mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[Attributor][FIX] Do not introduce multiple instances of SSA values
If we have a recursive function we could create multiple instantiations of an SSA value, one per recursive invocation of the function. This is a problem as we use SSA value equality in various places. The basic idea follows from this test: ``` static int r(int c, int *a) { int X; return c ? r(false, &X) : a == &X; } int test(int c) { return r(c, undef); } ``` If we look through the argument `a` we will end up with `X`. Using SSA value equality we will fold `a == &X` to true and return true even though it should have been false because `a` and `&X` are from different instantiations of the function. Various tests for this have been placed in value-simplify-instances.ll and this commit fixes them all by avoiding to produce simplified values that could be non-unique at runtime. Thus, the result of a simplify value call will always be unique at runtime or the original value, both do not allow to accidentally compare two instances of a value with each other and conclude they are equal statically (pointer equivalence) while they are unequal at runtime.
This commit is contained in:
parent
b93c50b86a
commit
54c73c71f7
@ -138,6 +138,12 @@ class Function;
|
||||
|
||||
/// Abstract Attribute helper functions.
|
||||
namespace AA {
|
||||
|
||||
/// Return true if \p V is dynamically unique, that is, there are no two
|
||||
/// "instances" of \p V at runtime with different values.
|
||||
bool isDynamicallyUnique(Attributor &A, const AbstractAttribute &QueryingAA,
|
||||
const Value &V);
|
||||
|
||||
/// Return true if \p V is a valid value in \p Scope, that is a constant or an
|
||||
/// instruction/argument of \p Scope.
|
||||
bool isValidInScope(const Value &V, const Function *Scope);
|
||||
|
@ -179,6 +179,26 @@ ChangeStatus &llvm::operator&=(ChangeStatus &L, ChangeStatus R) {
|
||||
}
|
||||
///}
|
||||
|
||||
bool AA::isDynamicallyUnique(Attributor &A, const AbstractAttribute &QueryingAA,
|
||||
const Value &V) {
|
||||
if (auto *C = dyn_cast<Constant>(&V))
|
||||
return !C->isThreadDependent();
|
||||
// TODO: Inspect and cache more complex instructions.
|
||||
if (auto *CB = dyn_cast<CallBase>(&V))
|
||||
return CB->getNumOperands() == 0 && !CB->mayHaveSideEffects() &&
|
||||
!CB->mayReadFromMemory();
|
||||
const Function *Scope = nullptr;
|
||||
if (auto *I = dyn_cast<Instruction>(&V))
|
||||
Scope = I->getFunction();
|
||||
if (auto *A = dyn_cast<Argument>(&V))
|
||||
Scope = A->getParent();
|
||||
if (!Scope)
|
||||
return false;
|
||||
auto &NoRecurseAA = A.getAAFor<AANoRecurse>(
|
||||
QueryingAA, IRPosition::function(*Scope), DepClassTy::OPTIONAL);
|
||||
return NoRecurseAA.isAssumedNoRecurse();
|
||||
}
|
||||
|
||||
Constant *AA::getInitialValueForObj(Value &Obj, Type &Ty) {
|
||||
if (isa<AllocaInst>(Obj))
|
||||
return UndefValue::get(&Ty);
|
||||
|
@ -5131,6 +5131,15 @@ struct AAValueSimplifyImpl : AAValueSimplify {
|
||||
|
||||
static bool handleLoad(Attributor &A, const AbstractAttribute &AA,
|
||||
LoadInst &L, function_ref<bool(Value &)> Union) {
|
||||
auto UnionWrapper = [&](Value &V, Value &Obj) {
|
||||
if (isa<AllocaInst>(Obj))
|
||||
return Union(V);
|
||||
if (!AA::isDynamicallyUnique(A, AA, V))
|
||||
return false;
|
||||
if (!AA::isValidAtPosition(V, L, A.getInfoCache()))
|
||||
return false;
|
||||
return Union(V);
|
||||
};
|
||||
|
||||
Value &Ptr = *L.getPointerOperand();
|
||||
SmallVector<Value *, 8> Objects;
|
||||
@ -5174,10 +5183,10 @@ struct AAValueSimplifyImpl : AAValueSimplify {
|
||||
if (!CastedContent)
|
||||
return false;
|
||||
if (IsExact)
|
||||
return Union(*CastedContent);
|
||||
return UnionWrapper(*CastedContent, *Obj);
|
||||
if (auto *C = dyn_cast<Constant>(CastedContent))
|
||||
if (C->isNullValue() || C->isAllOnesValue() || isa<UndefValue>(C))
|
||||
return Union(*CastedContent);
|
||||
return UnionWrapper(*CastedContent, *Obj);
|
||||
return false;
|
||||
};
|
||||
|
||||
@ -5241,32 +5250,23 @@ struct AAValueSimplifyArgument final : AAValueSimplifyImpl {
|
||||
// valid in the current scope. This avoids refering to simplified values
|
||||
// in other functions, e.g., we don't want to say a an argument in a
|
||||
// static function is actually an argument in a different function.
|
||||
Value &ArgOp = ACSArgPos.getAssociatedValue();
|
||||
bool UsedAssumedInformation = false;
|
||||
Optional<Value *> SimpleArgOp =
|
||||
A.getAssumedSimplified(ACSArgPos, *this, UsedAssumedInformation);
|
||||
Optional<Constant *> SimpleArgOp =
|
||||
A.getAssumedConstant(ACSArgPos, *this, UsedAssumedInformation);
|
||||
if (!SimpleArgOp.hasValue())
|
||||
return true;
|
||||
Value *SimpleArgOpVal = *SimpleArgOp ? *SimpleArgOp : &ArgOp;
|
||||
if (!AA::isValidInScope(*SimpleArgOpVal, getAnchorScope()))
|
||||
if (!SimpleArgOp.getValue())
|
||||
return false;
|
||||
|
||||
// We can only propagate thread independent values through callbacks.
|
||||
// This is different to direct/indirect call sites because for them we
|
||||
// know the thread executing the caller and callee is the same. For
|
||||
// callbacks this is not guaranteed, thus a thread dependent value could
|
||||
// be different for the caller and callee, making it invalid to propagate.
|
||||
if (ACS.isCallbackCall())
|
||||
if (auto *C = dyn_cast<Constant>(SimpleArgOpVal))
|
||||
if (C->isThreadDependent())
|
||||
return false;
|
||||
return checkAndUpdate(A, *this, ACSArgPos);
|
||||
if (!AA::isDynamicallyUnique(A, *this, **SimpleArgOp))
|
||||
return false;
|
||||
return unionAssumed(*SimpleArgOp);
|
||||
};
|
||||
|
||||
// Generate a answer specific to a call site context.
|
||||
bool Success;
|
||||
bool AllCallSitesKnown;
|
||||
if (hasCallBaseContext())
|
||||
if (hasCallBaseContext() &&
|
||||
getCallBaseContext()->getCalledFunction() == Arg->getParent())
|
||||
Success = PredForCallSite(
|
||||
AbstractCallSite(&getCallBaseContext()->getCalledOperandUse()));
|
||||
else
|
||||
|
@ -491,7 +491,7 @@ define void @writeonly_global() {
|
||||
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@writeonly_global
|
||||
; IS__CGSCC____-SAME: () #[[ATTR6]] {
|
||||
; IS__CGSCC____-NEXT: call void @write_global() #[[ATTR11:[0-9]+]]
|
||||
; IS__CGSCC____-NEXT: call void @write_global() #[[ATTR10:[0-9]+]]
|
||||
; IS__CGSCC____-NEXT: ret void
|
||||
;
|
||||
call void @write_global()
|
||||
@ -507,7 +507,7 @@ define void @writeonly_global_via_arg() {
|
||||
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@writeonly_global_via_arg
|
||||
; IS__CGSCC____-SAME: () #[[ATTR6]] {
|
||||
; IS__CGSCC____-NEXT: call void @write_global_via_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) @G) #[[ATTR11]]
|
||||
; IS__CGSCC____-NEXT: call void @write_global_via_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) @G) #[[ATTR10]]
|
||||
; IS__CGSCC____-NEXT: ret void
|
||||
;
|
||||
call void @write_global_via_arg(i32* @G)
|
||||
@ -525,7 +525,7 @@ define void @writeonly_global_via_arg_internal() {
|
||||
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@writeonly_global_via_arg_internal
|
||||
; IS__CGSCC____-SAME: () #[[ATTR6]] {
|
||||
; IS__CGSCC____-NEXT: call void @write_global_via_arg_internal() #[[ATTR11]]
|
||||
; IS__CGSCC____-NEXT: call void @write_global_via_arg_internal() #[[ATTR10]]
|
||||
; IS__CGSCC____-NEXT: ret void
|
||||
;
|
||||
call void @write_global_via_arg_internal(i32* @G)
|
||||
@ -551,7 +551,7 @@ define i8 @recursive_not_readnone(i8* %ptr, i1 %c) {
|
||||
; IS__CGSCC____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1
|
||||
; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__CGSCC____: t:
|
||||
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR12:[0-9]+]], !range [[RNG0:![0-9]+]]
|
||||
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR11:[0-9]+]], !range [[RNG0:![0-9]+]]
|
||||
; IS__CGSCC____-NEXT: ret i8 1
|
||||
; IS__CGSCC____: f:
|
||||
; IS__CGSCC____-NEXT: store i8 1, i8* [[PTR]], align 1
|
||||
@ -587,7 +587,7 @@ define internal i8 @recursive_not_readnone_internal(i8* %ptr, i1 %c) {
|
||||
; IS__CGSCC____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1
|
||||
; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__CGSCC____: t:
|
||||
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR12]], !range [[RNG0]]
|
||||
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR11]], !range [[RNG0]]
|
||||
; IS__CGSCC____-NEXT: ret i8 1
|
||||
; IS__CGSCC____: f:
|
||||
; IS__CGSCC____-NEXT: store i8 1, i8* [[PTR]], align 1
|
||||
@ -616,7 +616,7 @@ define i8 @readnone_caller(i1 %c) {
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@readnone_caller
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR9:[0-9]+]] {
|
||||
; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i8, align 1
|
||||
; IS__CGSCC____-NEXT: [[R:%.*]] = call noundef i8 @recursive_not_readnone_internal(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[A]], i1 [[C]]) #[[ATTR13:[0-9]+]], !range [[RNG0]]
|
||||
; IS__CGSCC____-NEXT: [[R:%.*]] = call noundef i8 @recursive_not_readnone_internal(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[A]], i1 [[C]]) #[[ATTR12:[0-9]+]], !range [[RNG0]]
|
||||
; IS__CGSCC____-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%a = alloca i8
|
||||
@ -625,25 +625,25 @@ define i8 @readnone_caller(i1 %c) {
|
||||
}
|
||||
|
||||
define internal i8 @recursive_readnone_internal2(i8* %ptr, i1 %c) {
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone
|
||||
; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind writeonly
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@recursive_readnone_internal2
|
||||
; IS__TUNIT____-SAME: (i8* nocapture nofree nonnull writeonly [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR9]] {
|
||||
; IS__TUNIT____-SAME: (i8* nocapture nofree nonnull writeonly [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR8]] {
|
||||
; IS__TUNIT____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1
|
||||
; IS__TUNIT____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__TUNIT____: t:
|
||||
; IS__TUNIT____-NEXT: [[TMP1:%.*]] = call i8 @recursive_readnone_internal2(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR9]], !range [[RNG0]]
|
||||
; IS__TUNIT____-NEXT: [[TMP1:%.*]] = call i8 @recursive_readnone_internal2(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR10]], !range [[RNG0]]
|
||||
; IS__TUNIT____-NEXT: ret i8 1
|
||||
; IS__TUNIT____: f:
|
||||
; IS__TUNIT____-NEXT: store i8 1, i8* [[PTR]], align 1
|
||||
; IS__TUNIT____-NEXT: ret i8 0
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone willreturn
|
||||
; IS__CGSCC____: Function Attrs: argmemonly nofree nosync nounwind writeonly
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_readnone_internal2
|
||||
; IS__CGSCC____-SAME: (i8* noalias nocapture nofree nonnull readnone [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR10:[0-9]+]] {
|
||||
; IS__CGSCC____-SAME: (i8* nocapture nofree nonnull writeonly [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR8]] {
|
||||
; IS__CGSCC____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1
|
||||
; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__CGSCC____: t:
|
||||
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_readnone_internal2(i8* noalias nocapture nofree noundef nonnull readnone dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR9]], !range [[RNG0]]
|
||||
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_readnone_internal2(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR11]], !range [[RNG0]]
|
||||
; IS__CGSCC____-NEXT: ret i8 1
|
||||
; IS__CGSCC____: f:
|
||||
; IS__CGSCC____-NEXT: store i8 1, i8* [[PTR]], align 1
|
||||
@ -664,13 +664,13 @@ define i8 @readnone_caller2(i1 %c) {
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@readnone_caller2
|
||||
; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR9]] {
|
||||
; IS__TUNIT____-NEXT: [[R:%.*]] = call noundef i8 @recursive_readnone_internal2(i8* undef, i1 [[C]]) #[[ATTR9]], !range [[RNG0]]
|
||||
; IS__TUNIT____-NEXT: [[R:%.*]] = call noundef i8 @recursive_readnone_internal2(i8* undef, i1 [[C]]) #[[ATTR10]], !range [[RNG0]]
|
||||
; IS__TUNIT____-NEXT: ret i8 [[R]]
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone willreturn
|
||||
; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@readnone_caller2
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR10]] {
|
||||
; IS__CGSCC____-NEXT: [[R:%.*]] = call noundef i8 @recursive_readnone_internal2(i8* undef, i1 [[C]]) #[[ATTR14:[0-9]+]], !range [[RNG0]]
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR9]] {
|
||||
; IS__CGSCC____-NEXT: [[R:%.*]] = call noundef i8 @recursive_readnone_internal2(i8* undef, i1 [[C]]) #[[ATTR12]], !range [[RNG0]]
|
||||
; IS__CGSCC____-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%r = call i8 @recursive_readnone_internal2(i8* undef, i1 %c)
|
||||
@ -696,7 +696,7 @@ define internal i8 @recursive_not_readnone_internal3(i8* %ptr, i1 %c) {
|
||||
; IS__CGSCC____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1
|
||||
; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__CGSCC____: t:
|
||||
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal3(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR12]], !range [[RNG0]]
|
||||
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal3(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR11]], !range [[RNG0]]
|
||||
; IS__CGSCC____-NEXT: ret i8 1
|
||||
; IS__CGSCC____: f:
|
||||
; IS__CGSCC____-NEXT: store i8 1, i8* [[PTR]], align 1
|
||||
@ -725,7 +725,7 @@ define i8 @readnone_caller3(i1 %c) {
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@readnone_caller3
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR9]] {
|
||||
; IS__CGSCC____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1
|
||||
; IS__CGSCC____-NEXT: [[R:%.*]] = call noundef i8 @recursive_not_readnone_internal3(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 [[C]]) #[[ATTR13]], !range [[RNG0]]
|
||||
; IS__CGSCC____-NEXT: [[R:%.*]] = call noundef i8 @recursive_not_readnone_internal3(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 [[C]]) #[[ATTR12]], !range [[RNG0]]
|
||||
; IS__CGSCC____-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%alloc = alloca i8
|
||||
@ -760,7 +760,7 @@ define void @argmemonky_caller() {
|
||||
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@argmemonky_caller
|
||||
; IS__CGSCC____-SAME: () #[[ATTR6]] {
|
||||
; IS__CGSCC____-NEXT: call void @argmemonly_before_ipconstprop() #[[ATTR11]]
|
||||
; IS__CGSCC____-NEXT: call void @argmemonly_before_ipconstprop() #[[ATTR10]]
|
||||
; IS__CGSCC____-NEXT: ret void
|
||||
;
|
||||
call void @argmemonly_before_ipconstprop(i32* @G)
|
||||
@ -789,11 +789,9 @@ define void @argmemonky_caller() {
|
||||
; IS__CGSCC____: attributes #[[ATTR7]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly }
|
||||
; IS__CGSCC____: attributes #[[ATTR8]] = { argmemonly nofree nosync nounwind writeonly }
|
||||
; IS__CGSCC____: attributes #[[ATTR9]] = { nofree nosync nounwind readnone }
|
||||
; IS__CGSCC____: attributes #[[ATTR10]] = { nofree nosync nounwind readnone willreturn }
|
||||
; IS__CGSCC____: attributes #[[ATTR11]] = { nounwind willreturn writeonly }
|
||||
; IS__CGSCC____: attributes #[[ATTR12]] = { nofree nosync nounwind writeonly }
|
||||
; IS__CGSCC____: attributes #[[ATTR13]] = { nounwind writeonly }
|
||||
; IS__CGSCC____: attributes #[[ATTR14]] = { nounwind readnone willreturn }
|
||||
; IS__CGSCC____: attributes #[[ATTR10]] = { nounwind willreturn writeonly }
|
||||
; IS__CGSCC____: attributes #[[ATTR11]] = { nofree nosync nounwind writeonly }
|
||||
; IS__CGSCC____: attributes #[[ATTR12]] = { nounwind writeonly }
|
||||
;.
|
||||
; CHECK: [[META0:![0-9]+]] = !{i8 0, i8 2}
|
||||
;.
|
||||
|
@ -1,6 +1,6 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
|
||||
; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
|
||||
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
|
||||
; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
|
||||
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
|
||||
; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
|
||||
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
|
||||
|
||||
@ -32,49 +32,27 @@ define internal i1 @recursive_inst_comparator(i1* %a, i1* %b) {
|
||||
}
|
||||
|
||||
define internal i1 @recursive_inst_generator(i1 %c, i1* %p) {
|
||||
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@recursive_inst_generator
|
||||
; IS__TUNIT_OPM-SAME: (i1 [[C:%.*]], i1* nofree [[P:%.*]]) {
|
||||
; IS__TUNIT_OPM-NEXT: [[A:%.*]] = call i1* @geti1Ptr()
|
||||
; IS__TUNIT_OPM-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__TUNIT_OPM: t:
|
||||
; IS__TUNIT_OPM-NEXT: [[R1:%.*]] = call i1 @recursive_inst_comparator(i1* noalias nofree readnone [[A]], i1* noalias nofree readnone [[P]]) #[[ATTR3:[0-9]+]]
|
||||
; IS__TUNIT_OPM-NEXT: ret i1 [[R1]]
|
||||
; IS__TUNIT_OPM: f:
|
||||
; IS__TUNIT_OPM-NEXT: [[R2:%.*]] = call i1 @recursive_inst_generator(i1 noundef true, i1* nofree [[A]])
|
||||
; IS__TUNIT_OPM-NEXT: ret i1 [[R2]]
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@recursive_inst_generator
|
||||
; IS__TUNIT____-SAME: (i1 [[C:%.*]], i1* nofree [[P:%.*]]) {
|
||||
; IS__TUNIT____-NEXT: [[A:%.*]] = call i1* @geti1Ptr()
|
||||
; IS__TUNIT____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__TUNIT____: t:
|
||||
; IS__TUNIT____-NEXT: [[R1:%.*]] = call i1 @recursive_inst_comparator(i1* noalias nofree readnone [[A]], i1* noalias nofree readnone [[P]]) #[[ATTR4:[0-9]+]]
|
||||
; IS__TUNIT____-NEXT: ret i1 [[R1]]
|
||||
; IS__TUNIT____: f:
|
||||
; IS__TUNIT____-NEXT: [[R2:%.*]] = call i1 @recursive_inst_generator(i1 noundef true, i1* nofree [[A]])
|
||||
; IS__TUNIT____-NEXT: ret i1 [[R2]]
|
||||
;
|
||||
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@recursive_inst_generator
|
||||
; IS__TUNIT_NPM-SAME: (i1 [[C:%.*]], i1* nofree [[P:%.*]]) {
|
||||
; IS__TUNIT_NPM-NEXT: [[A:%.*]] = call i1* @geti1Ptr()
|
||||
; IS__TUNIT_NPM-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__TUNIT_NPM: t:
|
||||
; IS__TUNIT_NPM-NEXT: [[R1:%.*]] = call i1 @recursive_inst_comparator(i1* noalias nofree readnone [[A]], i1* noalias nofree readnone [[A]]) #[[ATTR3:[0-9]+]]
|
||||
; IS__TUNIT_NPM-NEXT: ret i1 [[R1]]
|
||||
; IS__TUNIT_NPM: f:
|
||||
; IS__TUNIT_NPM-NEXT: [[R2:%.*]] = call i1 @recursive_inst_generator(i1 noundef true, i1* nofree [[A]])
|
||||
; IS__TUNIT_NPM-NEXT: ret i1 [[R2]]
|
||||
;
|
||||
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@recursive_inst_generator
|
||||
; IS__CGSCC_OPM-SAME: (i1 [[C:%.*]], i1* nofree [[P:%.*]]) {
|
||||
; IS__CGSCC_OPM-NEXT: [[A:%.*]] = call i1* @geti1Ptr()
|
||||
; IS__CGSCC_OPM-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__CGSCC_OPM: t:
|
||||
; IS__CGSCC_OPM-NEXT: [[R1:%.*]] = call i1 @recursive_inst_comparator(i1* noalias nofree readnone [[A]], i1* noalias nofree readnone [[P]])
|
||||
; IS__CGSCC_OPM-NEXT: ret i1 [[R1]]
|
||||
; IS__CGSCC_OPM: f:
|
||||
; IS__CGSCC_OPM-NEXT: [[R2:%.*]] = call i1 @recursive_inst_generator(i1 noundef true, i1* nofree [[A]])
|
||||
; IS__CGSCC_OPM-NEXT: ret i1 [[R2]]
|
||||
;
|
||||
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@recursive_inst_generator
|
||||
; IS__CGSCC_NPM-SAME: (i1 [[C:%.*]]) {
|
||||
; IS__CGSCC_NPM-NEXT: [[A:%.*]] = call i1* @geti1Ptr()
|
||||
; IS__CGSCC_NPM-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__CGSCC_NPM: t:
|
||||
; IS__CGSCC_NPM-NEXT: [[R1:%.*]] = call i1 @recursive_inst_comparator(i1* noalias nofree readnone [[A]], i1* noalias nofree readnone [[A]])
|
||||
; IS__CGSCC_NPM-NEXT: ret i1 [[R1]]
|
||||
; IS__CGSCC_NPM: f:
|
||||
; IS__CGSCC_NPM-NEXT: [[R2:%.*]] = call i1 @recursive_inst_generator(i1 noundef true)
|
||||
; IS__CGSCC_NPM-NEXT: ret i1 [[R2]]
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_inst_generator
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]], i1* nofree [[P:%.*]]) {
|
||||
; IS__CGSCC____-NEXT: [[A:%.*]] = call i1* @geti1Ptr()
|
||||
; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__CGSCC____: t:
|
||||
; IS__CGSCC____-NEXT: [[R1:%.*]] = call i1 @recursive_inst_comparator(i1* noalias nofree readnone [[A]], i1* noalias nofree readnone [[P]])
|
||||
; IS__CGSCC____-NEXT: ret i1 [[R1]]
|
||||
; IS__CGSCC____: f:
|
||||
; IS__CGSCC____-NEXT: [[R2:%.*]] = call i1 @recursive_inst_generator(i1 noundef true, i1* nofree [[A]])
|
||||
; IS__CGSCC____-NEXT: ret i1 [[R2]]
|
||||
;
|
||||
%a = call i1* @geti1Ptr()
|
||||
br i1 %c, label %t, label %f
|
||||
@ -88,15 +66,10 @@ f:
|
||||
|
||||
; FIXME: This should *not* return true.
|
||||
define i1 @recursive_inst_generator_caller(i1 %c) {
|
||||
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@recursive_inst_generator_caller
|
||||
; NOT_CGSCC_NPM-SAME: (i1 [[C:%.*]]) {
|
||||
; NOT_CGSCC_NPM-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_generator(i1 [[C]], i1* undef)
|
||||
; NOT_CGSCC_NPM-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@recursive_inst_generator_caller
|
||||
; IS__CGSCC_NPM-SAME: (i1 [[C:%.*]]) {
|
||||
; IS__CGSCC_NPM-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_generator(i1 [[C]])
|
||||
; IS__CGSCC_NPM-NEXT: ret i1 [[CALL]]
|
||||
; CHECK-LABEL: define {{[^@]+}}@recursive_inst_generator_caller
|
||||
; CHECK-SAME: (i1 [[C:%.*]]) {
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_generator(i1 [[C]], i1* undef)
|
||||
; CHECK-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
%call = call i1 @recursive_inst_generator(i1 %c, i1* undef)
|
||||
ret i1 %call
|
||||
@ -105,14 +78,15 @@ define i1 @recursive_inst_generator_caller(i1 %c) {
|
||||
; Make sure we do *not* return true.
|
||||
define internal i1 @recursive_inst_compare(i1 %c, i1* %p) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@recursive_inst_compare
|
||||
; CHECK-SAME: (i1 [[C:%.*]]) {
|
||||
; CHECK-SAME: (i1 [[C:%.*]], i1* [[P:%.*]]) {
|
||||
; CHECK-NEXT: [[A:%.*]] = call i1* @geti1Ptr()
|
||||
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; CHECK: t:
|
||||
; CHECK-NEXT: ret i1 undef
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i1* [[A]], [[P]]
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
; CHECK: f:
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare(i1 noundef true)
|
||||
; CHECK-NEXT: ret i1 undef
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare(i1 noundef true, i1* [[A]])
|
||||
; CHECK-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
%a = call i1* @geti1Ptr()
|
||||
br i1 %c, label %t, label %f
|
||||
@ -128,8 +102,8 @@ f:
|
||||
define i1 @recursive_inst_compare_caller(i1 %c) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@recursive_inst_compare_caller
|
||||
; CHECK-SAME: (i1 [[C:%.*]]) {
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare(i1 [[C]])
|
||||
; CHECK-NEXT: ret i1 true
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare(i1 [[C]], i1* undef)
|
||||
; CHECK-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
%call = call i1 @recursive_inst_compare(i1 %c, i1* undef)
|
||||
ret i1 %call
|
||||
@ -137,14 +111,17 @@ define i1 @recursive_inst_compare_caller(i1 %c) {
|
||||
|
||||
; Make sure we do *not* return true.
|
||||
define internal i1 @recursive_alloca_compare(i1 %c, i1* %p) {
|
||||
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_alloca_compare
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR0]] {
|
||||
; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__CGSCC____: t:
|
||||
; IS__CGSCC____-NEXT: ret i1 undef
|
||||
; IS__CGSCC____: f:
|
||||
; IS__CGSCC____-NEXT: ret i1 undef
|
||||
; CHECK: Function Attrs: nofree nosync nounwind readnone
|
||||
; CHECK-LABEL: define {{[^@]+}}@recursive_alloca_compare
|
||||
; CHECK-SAME: (i1 [[C:%.*]], i1* noalias nofree nonnull readnone [[P:%.*]]) #[[ATTR1:[0-9]+]] {
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i1, align 1
|
||||
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; CHECK: t:
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i1* [[A]], [[P]]
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
; CHECK: f:
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare(i1 noundef true, i1* noalias nofree noundef nonnull readnone dereferenceable(1) [[A]]) #[[ATTR1]]
|
||||
; CHECK-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
%a = alloca i1
|
||||
br i1 %c, label %t, label %f
|
||||
@ -158,15 +135,17 @@ f:
|
||||
|
||||
; FIXME: This should *not* return true.
|
||||
define i1 @recursive_alloca_compare_caller(i1 %c) {
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@recursive_alloca_compare_caller
|
||||
; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR0]] {
|
||||
; IS__TUNIT____-NEXT: ret i1 true
|
||||
; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
|
||||
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare(i1 [[C]], i1* undef) #[[ATTR1]]
|
||||
; IS__TUNIT____-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
||||
; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_alloca_compare_caller
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR0]] {
|
||||
; IS__CGSCC____-NEXT: ret i1 true
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
|
||||
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare(i1 [[C]], i1* undef) #[[ATTR4:[0-9]+]]
|
||||
; IS__CGSCC____-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
%call = call i1 @recursive_alloca_compare(i1 %c, i1* undef)
|
||||
ret i1 %call
|
||||
@ -174,33 +153,19 @@ define i1 @recursive_alloca_compare_caller(i1 %c) {
|
||||
|
||||
; Make sure we do *not* simplify this to return 0 or 1, return 42 is ok though.
|
||||
define internal i8 @recursive_alloca_load_return(i1 %c, i8* %p, i8 %v) {
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@recursive_alloca_load_return
|
||||
; IS__TUNIT____-SAME: (i1 [[C:%.*]], i8* nocapture nofree nonnull readonly [[P:%.*]], i8 noundef [[V:%.*]]) #[[ATTR1:[0-9]+]] {
|
||||
; IS__TUNIT____-NEXT: [[A:%.*]] = alloca i8, align 1
|
||||
; IS__TUNIT____-NEXT: store i8 [[V]], i8* [[A]], align 1
|
||||
; IS__TUNIT____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__TUNIT____: t:
|
||||
; IS__TUNIT____-NEXT: store i8 0, i8* [[A]], align 1
|
||||
; IS__TUNIT____-NEXT: [[L:%.*]] = load i8, i8* [[P]], align 1
|
||||
; IS__TUNIT____-NEXT: ret i8 [[L]]
|
||||
; IS__TUNIT____: f:
|
||||
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i8 @recursive_alloca_load_return(i1 noundef true, i8* noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[A]], i8 noundef 1) #[[ATTR1]]
|
||||
; IS__TUNIT____-NEXT: ret i8 [[CALL]]
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_alloca_load_return
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]], i8* noalias nocapture nofree nonnull readnone [[P:%.*]], i8 noundef [[V:%.*]]) #[[ATTR1:[0-9]+]] {
|
||||
; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i8, align 1
|
||||
; IS__CGSCC____-NEXT: store i8 [[V]], i8* [[A]], align 1
|
||||
; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; IS__CGSCC____: t:
|
||||
; IS__CGSCC____-NEXT: store i8 0, i8* [[A]], align 1
|
||||
; IS__CGSCC____-NEXT: [[L:%.*]] = load i8, i8* [[P]], align 1
|
||||
; IS__CGSCC____-NEXT: ret i8 [[L]]
|
||||
; IS__CGSCC____: f:
|
||||
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i8 @recursive_alloca_load_return(i1 noundef true, i8* noalias nocapture nofree noundef nonnull readnone dereferenceable(1) [[A]], i8 noundef 1) #[[ATTR1]]
|
||||
; IS__CGSCC____-NEXT: ret i8 [[CALL]]
|
||||
; CHECK: Function Attrs: argmemonly nofree nosync nounwind
|
||||
; CHECK-LABEL: define {{[^@]+}}@recursive_alloca_load_return
|
||||
; CHECK-SAME: (i1 [[C:%.*]], i8* nocapture nofree nonnull readonly [[P:%.*]], i8 noundef [[V:%.*]]) #[[ATTR2:[0-9]+]] {
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1
|
||||
; CHECK-NEXT: store i8 [[V]], i8* [[A]], align 1
|
||||
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; CHECK: t:
|
||||
; CHECK-NEXT: store i8 0, i8* [[A]], align 1
|
||||
; CHECK-NEXT: [[L:%.*]] = load i8, i8* [[P]], align 1
|
||||
; CHECK-NEXT: ret i8 [[L]]
|
||||
; CHECK: f:
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i8 @recursive_alloca_load_return(i1 noundef true, i8* noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[A]], i8 noundef 1) #[[ATTR3:[0-9]+]]
|
||||
; CHECK-NEXT: ret i8 [[CALL]]
|
||||
;
|
||||
%a = alloca i8
|
||||
store i8 %v, i8* %a
|
||||
@ -218,13 +183,13 @@ define i8 @recursive_alloca_load_return_caller(i1 %c) {
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@recursive_alloca_load_return_caller
|
||||
; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
|
||||
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i8 @recursive_alloca_load_return(i1 [[C]], i8* undef, i8 noundef 42) #[[ATTR1]]
|
||||
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i8 @recursive_alloca_load_return(i1 [[C]], i8* undef, i8 noundef 42) #[[ATTR3]]
|
||||
; IS__TUNIT____-NEXT: ret i8 [[CALL]]
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_alloca_load_return_caller
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
|
||||
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i8 @recursive_alloca_load_return(i1 [[C]], i8* undef, i8 noundef 42) #[[ATTR3:[0-9]+]]
|
||||
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i8 @recursive_alloca_load_return(i1 [[C]], i8* undef, i8 noundef 42) #[[ATTR5:[0-9]+]]
|
||||
; IS__CGSCC____-NEXT: ret i8 [[CALL]]
|
||||
;
|
||||
%call = call i8 @recursive_alloca_load_return(i1 %c, i8* undef, i8 42)
|
||||
@ -237,17 +202,19 @@ define i8 @recursive_alloca_load_return_caller(i1 %c) {
|
||||
|
||||
; Make sure we do *not* return true.
|
||||
define internal i1 @recursive_alloca_compare_global1(i1 %c) {
|
||||
; CHECK: Function Attrs: nofree nosync nounwind writeonly
|
||||
; CHECK: Function Attrs: nofree nosync nounwind
|
||||
; CHECK-LABEL: define {{[^@]+}}@recursive_alloca_compare_global1
|
||||
; CHECK-SAME: (i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] {
|
||||
; CHECK-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i1, align 1
|
||||
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; CHECK: t:
|
||||
; CHECK-NEXT: ret i1 undef
|
||||
; CHECK-NEXT: [[P:%.*]] = load i1*, i1** @G1, align 8
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i1* [[A]], [[P]]
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
; CHECK: f:
|
||||
; CHECK-NEXT: store i1* [[A]], i1** @G1, align 8
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global1(i1 noundef true) #[[ATTR2]]
|
||||
; CHECK-NEXT: ret i1 undef
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global1(i1 noundef true) #[[ATTR3]]
|
||||
; CHECK-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
%a = alloca i1
|
||||
br i1 %c, label %t, label %f
|
||||
@ -263,34 +230,36 @@ f:
|
||||
|
||||
; FIXME: This should *not* return true.
|
||||
define i1 @recursive_alloca_compare_caller_global1(i1 %c) {
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind writeonly
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@recursive_alloca_compare_caller_global1
|
||||
; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
||||
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global1(i1 [[C]]) #[[ATTR2]]
|
||||
; IS__TUNIT____-NEXT: ret i1 true
|
||||
; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
|
||||
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global1(i1 [[C]]) #[[ATTR3]]
|
||||
; IS__TUNIT____-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: nofree nosync nounwind writeonly
|
||||
; IS__CGSCC____: Function Attrs: nofree nosync nounwind
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_alloca_compare_caller_global1
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
||||
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global1(i1 [[C]]) #[[ATTR4:[0-9]+]]
|
||||
; IS__CGSCC____-NEXT: ret i1 true
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
|
||||
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global1(i1 [[C]]) #[[ATTR5]]
|
||||
; IS__CGSCC____-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
%call = call i1 @recursive_alloca_compare_global1(i1 %c)
|
||||
ret i1 %call
|
||||
}
|
||||
|
||||
define internal i1 @recursive_alloca_compare_global2(i1 %c) {
|
||||
; CHECK: Function Attrs: nofree nosync nounwind writeonly
|
||||
; CHECK: Function Attrs: nofree nosync nounwind
|
||||
; CHECK-LABEL: define {{[^@]+}}@recursive_alloca_compare_global2
|
||||
; CHECK-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
||||
; CHECK-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i1, align 1
|
||||
; CHECK-NEXT: [[P:%.*]] = load i1*, i1** @G2, align 8
|
||||
; CHECK-NEXT: store i1* [[A]], i1** @G2, align 8
|
||||
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; CHECK: t:
|
||||
; CHECK-NEXT: ret i1 undef
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i1* [[A]], [[P]]
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
; CHECK: f:
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global2(i1 noundef true) #[[ATTR2]]
|
||||
; CHECK-NEXT: ret i1 undef
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global2(i1 noundef true) #[[ATTR3]]
|
||||
; CHECK-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
%a = alloca i1
|
||||
%p = load i1*, i1** @G2
|
||||
@ -306,33 +275,35 @@ f:
|
||||
|
||||
; FIXME: This should *not* return true.
|
||||
define i1 @recursive_alloca_compare_caller_global2(i1 %c) {
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind writeonly
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@recursive_alloca_compare_caller_global2
|
||||
; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
||||
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global2(i1 [[C]]) #[[ATTR2]]
|
||||
; IS__TUNIT____-NEXT: ret i1 true
|
||||
; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
|
||||
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global2(i1 [[C]]) #[[ATTR3]]
|
||||
; IS__TUNIT____-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: nofree nosync nounwind writeonly
|
||||
; IS__CGSCC____: Function Attrs: nofree nosync nounwind
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_alloca_compare_caller_global2
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
||||
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global2(i1 [[C]]) #[[ATTR4]]
|
||||
; IS__CGSCC____-NEXT: ret i1 true
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
|
||||
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare_global2(i1 [[C]]) #[[ATTR5]]
|
||||
; IS__CGSCC____-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
%call = call i1 @recursive_alloca_compare_global2(i1 %c)
|
||||
ret i1 %call
|
||||
}
|
||||
define internal i1 @recursive_inst_compare_global3(i1 %c) {
|
||||
;
|
||||
; CHECK: Function Attrs: nofree nosync nounwind writeonly
|
||||
; CHECK: Function Attrs: nofree nosync nounwind
|
||||
; CHECK-LABEL: define {{[^@]+}}@recursive_inst_compare_global3
|
||||
; CHECK-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
||||
; CHECK-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
|
||||
; CHECK-NEXT: [[P:%.*]] = load i1, i1* @G3, align 1
|
||||
; CHECK-NEXT: store i1 [[C]], i1* @G3, align 1
|
||||
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; CHECK: t:
|
||||
; CHECK-NEXT: ret i1 undef
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i1 [[C]], [[P]]
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
; CHECK: f:
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare_global3(i1 noundef true) #[[ATTR2]]
|
||||
; CHECK-NEXT: ret i1 undef
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare_global3(i1 noundef true) #[[ATTR3]]
|
||||
; CHECK-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
%p = load i1, i1* @G3
|
||||
store i1 %c, i1* @G3
|
||||
@ -347,17 +318,17 @@ f:
|
||||
|
||||
; FIXME: This should *not* return true.
|
||||
define i1 @recursive_inst_compare_caller_global3(i1 %c) {
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind writeonly
|
||||
; IS__TUNIT____: Function Attrs: nofree nosync nounwind
|
||||
; IS__TUNIT____-LABEL: define {{[^@]+}}@recursive_inst_compare_caller_global3
|
||||
; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
||||
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare_global3(i1 [[C]]) #[[ATTR2]]
|
||||
; IS__TUNIT____-NEXT: ret i1 true
|
||||
; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
|
||||
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare_global3(i1 [[C]]) #[[ATTR3]]
|
||||
; IS__TUNIT____-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
; IS__CGSCC____: Function Attrs: nofree nosync nounwind writeonly
|
||||
; IS__CGSCC____: Function Attrs: nofree nosync nounwind
|
||||
; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_inst_compare_caller_global3
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
||||
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare_global3(i1 [[C]]) #[[ATTR4]]
|
||||
; IS__CGSCC____-NEXT: ret i1 true
|
||||
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR3]] {
|
||||
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i1 @recursive_inst_compare_global3(i1 [[C]]) #[[ATTR5]]
|
||||
; IS__CGSCC____-NEXT: ret i1 [[CALL]]
|
||||
;
|
||||
%call = call i1 @recursive_inst_compare_global3(i1 %c)
|
||||
ret i1 %call
|
||||
@ -365,12 +336,14 @@ define i1 @recursive_inst_compare_caller_global3(i1 %c) {
|
||||
;.
|
||||
; IS__TUNIT____: attributes #[[ATTR0]] = { nofree nosync nounwind readnone willreturn }
|
||||
; IS__TUNIT____: attributes #[[ATTR1]] = { nofree nosync nounwind readnone }
|
||||
; IS__TUNIT____: attributes #[[ATTR2]] = { nofree nosync nounwind writeonly }
|
||||
; IS__TUNIT____: attributes #[[ATTR3:[0-9]+]] = { nounwind readnone }
|
||||
; IS__TUNIT____: attributes #[[ATTR2]] = { argmemonly nofree nosync nounwind }
|
||||
; IS__TUNIT____: attributes #[[ATTR3]] = { nofree nosync nounwind }
|
||||
; IS__TUNIT____: attributes #[[ATTR4]] = { nounwind readnone }
|
||||
;.
|
||||
; IS__CGSCC____: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
|
||||
; IS__CGSCC____: attributes #[[ATTR1]] = { nofree nosync nounwind readnone }
|
||||
; IS__CGSCC____: attributes #[[ATTR2]] = { nofree nosync nounwind writeonly }
|
||||
; IS__CGSCC____: attributes #[[ATTR3]] = { nounwind readnone }
|
||||
; IS__CGSCC____: attributes #[[ATTR4]] = { nounwind writeonly }
|
||||
; IS__CGSCC____: attributes #[[ATTR2]] = { argmemonly nofree nosync nounwind }
|
||||
; IS__CGSCC____: attributes #[[ATTR3]] = { nofree nosync nounwind }
|
||||
; IS__CGSCC____: attributes #[[ATTR4]] = { nounwind readnone }
|
||||
; IS__CGSCC____: attributes #[[ATTR5]] = { nounwind }
|
||||
;.
|
||||
|
Loading…
Reference in New Issue
Block a user