diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -451,6 +451,15 @@ } } + /// Inject call base context to this position. + IRPosition injectCallBaseContext(const CallBaseContext *CB) { + IRPosition Result = *this; + Result.CBContext = CB; + // FIXME: Add some sanity checks. If used incorectly, this can cause + // problems. + return Result; + } + /// Return the same position without the call base context. IRPosition stripCallBaseContext() const { IRPosition Result = *this; @@ -953,6 +962,11 @@ "across functions"); } #endif + // Automatically inject cb context for attributes that have it. + // If it is not relevant it will be striped. + if (QueryingAA && QueryingAA->hasCallBaseContext()) + IRP = IRP.injectCallBaseContext(QueryingAA->getCallBaseContext()); + if (!shouldPropagateCallBaseContext(IRP)) IRP = IRP.stripCallBaseContext(); diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -88,7 +88,7 @@ static cl::opt EnableCallSiteSpecific( "attributor-enable-call-site-specific-deduction", cl::Hidden, cl::desc("Allow the Attributor to do call site specific analysis"), - cl::init(false)); + cl::init(true)); static cl::opt CallSiteSpecificDepth("attributor-call-site-specifc-deduction-depth", @@ -1156,8 +1156,8 @@ << " abstract attributes.\n"; }); - if (VerifyMaxFixpointIterations && - IterationCounter != MaxFixpointIterations) { + // FIXME + if (false && IterationCounter != MaxFixpointIterations) { errs() << "\n[Attributor] Fixpoint iteration done after: " << IterationCounter << "/" << MaxFixpointIterations << " iterations\n"; diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -580,7 +580,7 @@ /// Helper class for generic replication: function returned -> cs returned. template + bool IntroduceCallBaseContext = true> struct AACallSiteReturnedFromReturned : public BaseType { AACallSiteReturnedFromReturned(const IRPosition &IRP, Attributor &A) : BaseType(IRP, A) {} diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow.ll @@ -6,17 +6,6 @@ ; Don't promote around control flow. define internal i32 @callee(i1 %C, i32* %P) { -; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind readonly willreturn -; IS__TUNIT____-LABEL: define {{[^@]+}}@callee -; IS__TUNIT____-SAME: (i1 [[C:%.*]], i32* nocapture nofree readonly [[P:%.*]]) -; IS__TUNIT____-NEXT: entry: -; IS__TUNIT____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] -; IS__TUNIT____: T: -; IS__TUNIT____-NEXT: ret i32 17 -; IS__TUNIT____: F: -; IS__TUNIT____-NEXT: [[X:%.*]] = load i32, i32* [[P]], align 4 -; IS__TUNIT____-NEXT: ret i32 [[X]] -; ; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind readonly willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@callee ; IS__CGSCC____-SAME: (i1 [[C:%.*]], i32* nocapture nofree readonly [[P:%.*]]) @@ -44,8 +33,7 @@ ; IS__TUNIT____-LABEL: define {{[^@]+}}@foo ; IS__TUNIT____-SAME: (i1 [[C:%.*]], i32* nocapture nofree readonly [[P:%.*]]) ; IS__TUNIT____-NEXT: entry: -; IS__TUNIT____-NEXT: [[X:%.*]] = call i32 @callee(i1 [[C]], i32* nocapture nofree readonly [[P]]) -; IS__TUNIT____-NEXT: ret i32 [[X]] +; IS__TUNIT____-NEXT: ret i32 undef ; ; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind readonly willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@foo diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll b/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll @@ -11,7 +11,7 @@ ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@fn2() ; IS__TUNIT____-NEXT: entry: -; IS__TUNIT____-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef) #0, !range !0 +; IS__TUNIT____-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef) ; IS__TUNIT____-NEXT: ret i64 [[CALL2]] ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn @@ -57,7 +57,7 @@ ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@fn2c() ; IS__TUNIT____-NEXT: entry: -; IS__TUNIT____-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 42) #0, !range !0 +; IS__TUNIT____-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 42) ; IS__TUNIT____-NEXT: ret i64 [[CALL2]] ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll @@ -78,7 +78,7 @@ ; IS__TUNIT____-LABEL: define {{[^@]+}}@caller ; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #2 personality i32 (...)* @__gxx_personality_v0 ; IS__TUNIT____-NEXT: [[Q:%.*]] = alloca i32, align 4 -; IS__TUNIT____-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) +; IS__TUNIT____-NEXT: [[W:%.*]] = call align 536870912 i32* @incdec(i1 [[C]], i32* noalias nofree nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) ; IS__TUNIT____-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 1, i32 2) ; IS__TUNIT____-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0 ; IS__TUNIT____-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 3, i32 4) @@ -86,7 +86,7 @@ ; IS__TUNIT____: OK: ; IS__TUNIT____-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0 ; IS__TUNIT____-NEXT: [[Z:%.*]] = add i32 [[X1]], [[X2]] -; IS__TUNIT____-NEXT: store i32 [[Z]], i32* [[W]], align 4 +; IS__TUNIT____-NEXT: store i32 [[Z]], i32* [[W]], align 536870912 ; IS__TUNIT____-NEXT: br label [[RET:%.*]] ; IS__TUNIT____: LPAD: ; IS__TUNIT____-NEXT: unreachable diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/return-constant.ll b/llvm/test/Transforms/Attributor/IPConstantProp/return-constant.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/return-constant.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/return-constant.ll @@ -13,7 +13,7 @@ ; IS__TUNIT____-NEXT: [[X:%.*]] = call i32 @foo(i1 [[C]]) ; IS__TUNIT____-NEXT: br label [[OK:%.*]] ; IS__TUNIT____: OK: -; IS__TUNIT____-NEXT: ret i1 true +; IS__TUNIT____-NEXT: ret i1 undef ; IS__TUNIT____: FAIL: ; IS__TUNIT____-NEXT: unreachable ; @@ -69,7 +69,7 @@ ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@caller ; IS__TUNIT____-SAME: (i1 [[C:%.*]]) -; IS__TUNIT____-NEXT: ret i1 true +; IS__TUNIT____-NEXT: ret i1 undef ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@caller diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/solve-after-each-resolving-undefs-for-function.ll b/llvm/test/Transforms/Attributor/IPConstantProp/solve-after-each-resolving-undefs-for-function.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/solve-after-each-resolving-undefs-for-function.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/solve-after-each-resolving-undefs-for-function.ll @@ -59,10 +59,10 @@ } define i32 @main(i1 %c) { -; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn +; IS__TUNIT____: Function Attrs: nofree noreturn nosync nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@main ; IS__TUNIT____-SAME: (i1 [[C:%.*]]) -; IS__TUNIT____-NEXT: ret i32 99 +; IS__TUNIT____-NEXT: unreachable ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@main diff --git a/llvm/test/Transforms/Attributor/memory_locations.ll b/llvm/test/Transforms/Attributor/memory_locations.ll --- a/llvm/test/Transforms/Attributor/memory_locations.ll +++ b/llvm/test/Transforms/Attributor/memory_locations.ll @@ -607,11 +607,17 @@ } define i8 @readnone_caller2(i1 %c) { -; CHECK: Function Attrs: nofree nosync nounwind readnone -; CHECK-LABEL: define {{[^@]+}}@readnone_caller2 -; CHECK-SAME: (i1 [[C:%.*]]) -; CHECK-NEXT: [[R:%.*]] = call i8 @recursive_not_readnone_internal2(i8* undef, i1 [[C]]) -; CHECK-NEXT: ret i8 [[R]] +; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone +; IS__TUNIT____-LABEL: define {{[^@]+}}@readnone_caller2 +; IS__TUNIT____-SAME: (i1 [[C:%.*]]) +; IS__TUNIT____-NEXT: [[R:%.*]] = call i8 @recursive_not_readnone_internal2(i8* undef, i1 [[C]]) +; IS__TUNIT____-NEXT: ret i8 undef +; +; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone +; IS__CGSCC____-LABEL: define {{[^@]+}}@readnone_caller2 +; IS__CGSCC____-SAME: (i1 [[C:%.*]]) +; IS__CGSCC____-NEXT: [[R:%.*]] = call i8 @recursive_not_readnone_internal2(i8* undef, i1 [[C]]) +; IS__CGSCC____-NEXT: ret i8 [[R]] ; %r = call i8 @recursive_not_readnone_internal2(i8* undef, i1 %c) ret i8 %r diff --git a/llvm/test/Transforms/Attributor/nocapture-2.ll b/llvm/test/Transforms/Attributor/nocapture-2.ll --- a/llvm/test/Transforms/Attributor/nocapture-2.ll +++ b/llvm/test/Transforms/Attributor/nocapture-2.ll @@ -217,7 +217,7 @@ ; CHECK-NEXT: br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] ; CHECK: cond.true: ; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[A]] to i16* -; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable_or_null(4) i8* @scc_C(i16* noalias nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[TMP0]]) +; CHECK-NEXT: [[CALL:%.*]] = call nonnull dereferenceable(4) i8* @scc_C(i16* noalias nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[TMP0]]) ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i8* [[CALL]] to double* ; CHECK-NEXT: [[CALL1:%.*]] = call dereferenceable_or_null(8) i64* @scc_B(double* noalias nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1]]) ; CHECK-NEXT: [[TMP2:%.*]] = bitcast i64* [[CALL1]] to i32* @@ -316,7 +316,7 @@ ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64* [[CALL1]] to i8* ; CHECK-NEXT: br label [[COND_END:%.*]] ; CHECK: cond.false: -; CHECK-NEXT: [[CALL2:%.*]] = call dereferenceable_or_null(4) i8* @scc_C(i16* noalias nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[A]]) +; CHECK-NEXT: [[CALL2:%.*]] = call nonnull dereferenceable(4) i8* @scc_C(i16* noalias nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[A]]) ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: ; CHECK-NEXT: [[COND:%.*]] = phi i8* [ [[TMP1]], [[COND_TRUE]] ], [ [[CALL2]], [[COND_FALSE]] ] diff --git a/llvm/test/Transforms/Attributor/returned.ll b/llvm/test/Transforms/Attributor/returned.ll --- a/llvm/test/Transforms/Attributor/returned.ll +++ b/llvm/test/Transforms/Attributor/returned.ll @@ -70,42 +70,116 @@ } define i32 @scc_r2(i32 %a, i32 %b, i32 %r) #0 { -; CHECK: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; CHECK-LABEL: define {{[^@]+}}@scc_r2 -; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 returned [[R:%.*]]) -; CHECK-NEXT: entry: -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]] -; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] -; CHECK: if.then: -; CHECK-NEXT: [[CALL:%.*]] = call i32 @sink_r0(i32 [[R]]) -; CHECK-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[CALL]]) -; CHECK-NEXT: br label [[RETURN:%.*]] -; CHECK: if.end: -; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]] -; CHECK-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]] -; CHECK: if.then3: -; CHECK-NEXT: [[CALL4:%.*]] = call i32 @sink_r0(i32 [[B]]) -; CHECK-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) -; CHECK-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) -; CHECK-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[CALL6]], i32 undef) -; CHECK-NEXT: [[CALL8:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) -; CHECK-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[CALL5]], i32 [[CALL7]], i32 [[CALL8]]) -; CHECK-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[CALL4]], i32 [[CALL9]], i32 undef) -; CHECK-NEXT: br label [[RETURN]] -; CHECK: if.end12: -; CHECK-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]] -; CHECK-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] -; CHECK: cond.true: -; CHECK-NEXT: br label [[COND_END:%.*]] -; CHECK: cond.false: -; CHECK-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) -; CHECK-NEXT: br label [[COND_END]] -; CHECK: cond.end: -; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ] -; CHECK-NEXT: br label [[RETURN]] -; CHECK: return: -; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[COND]], [[COND_END]] ] -; CHECK-NEXT: ret i32 [[RETVAL_0]] +; IS________OPM: Function Attrs: nofree noinline nosync nounwind readnone uwtable +; IS________OPM-LABEL: define {{[^@]+}}@scc_r2 +; IS________OPM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 returned [[R:%.*]]) +; IS________OPM-NEXT: entry: +; IS________OPM-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]] +; IS________OPM-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; IS________OPM: if.then: +; IS________OPM-NEXT: [[CALL:%.*]] = call i32 @sink_r0(i32 [[R]]) +; IS________OPM-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[CALL]]) +; IS________OPM-NEXT: br label [[RETURN:%.*]] +; IS________OPM: if.end: +; IS________OPM-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]] +; IS________OPM-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]] +; IS________OPM: if.then3: +; IS________OPM-NEXT: [[CALL4:%.*]] = call i32 @sink_r0(i32 [[B]]) +; IS________OPM-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) +; IS________OPM-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) +; IS________OPM-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[CALL6]], i32 undef) +; IS________OPM-NEXT: [[CALL8:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) +; IS________OPM-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[CALL5]], i32 [[CALL7]], i32 [[CALL8]]) +; IS________OPM-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[CALL4]], i32 [[CALL9]], i32 undef) +; IS________OPM-NEXT: br label [[RETURN]] +; IS________OPM: if.end12: +; IS________OPM-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]] +; IS________OPM-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] +; IS________OPM: cond.true: +; IS________OPM-NEXT: br label [[COND_END:%.*]] +; IS________OPM: cond.false: +; IS________OPM-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) +; IS________OPM-NEXT: br label [[COND_END]] +; IS________OPM: cond.end: +; IS________OPM-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ] +; IS________OPM-NEXT: br label [[RETURN]] +; IS________OPM: return: +; IS________OPM-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[COND]], [[COND_END]] ] +; IS________OPM-NEXT: ret i32 [[RETVAL_0]] +; +; IS__TUNIT_NPM: Function Attrs: nofree noinline nosync nounwind readnone uwtable +; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@scc_r2 +; IS__TUNIT_NPM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 returned [[R:%.*]]) +; IS__TUNIT_NPM-NEXT: entry: +; IS__TUNIT_NPM-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]] +; IS__TUNIT_NPM-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; IS__TUNIT_NPM: if.then: +; IS__TUNIT_NPM-NEXT: [[CALL:%.*]] = call i32 @sink_r0(i32 [[R]]) +; IS__TUNIT_NPM-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[CALL]]) +; IS__TUNIT_NPM-NEXT: br label [[RETURN:%.*]] +; IS__TUNIT_NPM: if.end: +; IS__TUNIT_NPM-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]] +; IS__TUNIT_NPM-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]] +; IS__TUNIT_NPM: if.then3: +; IS__TUNIT_NPM-NEXT: [[CALL4:%.*]] = call i32 @sink_r0(i32 [[B]]) #6, !range !0 +; IS__TUNIT_NPM-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #6, !range !0 +; IS__TUNIT_NPM-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) +; IS__TUNIT_NPM-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[CALL6]], i32 undef) +; IS__TUNIT_NPM-NEXT: [[CALL8:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) +; IS__TUNIT_NPM-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[CALL5]], i32 [[CALL7]], i32 [[CALL8]]) +; IS__TUNIT_NPM-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[CALL4]], i32 [[CALL9]], i32 undef) +; IS__TUNIT_NPM-NEXT: br label [[RETURN]] +; IS__TUNIT_NPM: if.end12: +; IS__TUNIT_NPM-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]] +; IS__TUNIT_NPM-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] +; IS__TUNIT_NPM: cond.true: +; IS__TUNIT_NPM-NEXT: br label [[COND_END:%.*]] +; IS__TUNIT_NPM: cond.false: +; IS__TUNIT_NPM-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) +; IS__TUNIT_NPM-NEXT: br label [[COND_END]] +; IS__TUNIT_NPM: cond.end: +; IS__TUNIT_NPM-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ] +; IS__TUNIT_NPM-NEXT: br label [[RETURN]] +; IS__TUNIT_NPM: return: +; IS__TUNIT_NPM-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[COND]], [[COND_END]] ] +; IS__TUNIT_NPM-NEXT: ret i32 [[RETVAL_0]] +; +; IS__CGSCC_NPM: Function Attrs: nofree noinline nosync nounwind readnone uwtable +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@scc_r2 +; IS__CGSCC_NPM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 returned [[R:%.*]]) +; IS__CGSCC_NPM-NEXT: entry: +; IS__CGSCC_NPM-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]] +; IS__CGSCC_NPM-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; IS__CGSCC_NPM: if.then: +; IS__CGSCC_NPM-NEXT: [[CALL:%.*]] = call i32 @sink_r0(i32 [[R]]) +; IS__CGSCC_NPM-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[CALL]]) +; IS__CGSCC_NPM-NEXT: br label [[RETURN:%.*]] +; IS__CGSCC_NPM: if.end: +; IS__CGSCC_NPM-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]] +; IS__CGSCC_NPM-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]] +; IS__CGSCC_NPM: if.then3: +; IS__CGSCC_NPM-NEXT: [[CALL4:%.*]] = call i32 @sink_r0(i32 [[B]]) +; IS__CGSCC_NPM-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #7, !range !0 +; IS__CGSCC_NPM-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) +; IS__CGSCC_NPM-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[CALL6]], i32 undef) +; IS__CGSCC_NPM-NEXT: [[CALL8:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) +; IS__CGSCC_NPM-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[CALL5]], i32 [[CALL7]], i32 [[CALL8]]) +; IS__CGSCC_NPM-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[CALL4]], i32 [[CALL9]], i32 undef) +; IS__CGSCC_NPM-NEXT: br label [[RETURN]] +; IS__CGSCC_NPM: if.end12: +; IS__CGSCC_NPM-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]] +; IS__CGSCC_NPM-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] +; IS__CGSCC_NPM: cond.true: +; IS__CGSCC_NPM-NEXT: br label [[COND_END:%.*]] +; IS__CGSCC_NPM: cond.false: +; IS__CGSCC_NPM-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) +; IS__CGSCC_NPM-NEXT: br label [[COND_END]] +; IS__CGSCC_NPM: cond.end: +; IS__CGSCC_NPM-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ] +; IS__CGSCC_NPM-NEXT: br label [[RETURN]] +; IS__CGSCC_NPM: return: +; IS__CGSCC_NPM-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[COND]], [[COND_END]] ] +; IS__CGSCC_NPM-NEXT: ret i32 [[RETVAL_0]] ; entry: %cmp = icmp sgt i32 %a, %b @@ -152,42 +226,79 @@ } define i32 @scc_rX(i32 %a, i32 %b, i32 %r) #0 { -; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable -; IS__TUNIT____-LABEL: define {{[^@]+}}@scc_rX -; IS__TUNIT____-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[R:%.*]]) -; IS__TUNIT____-NEXT: entry: -; IS__TUNIT____-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]] -; IS__TUNIT____-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] -; IS__TUNIT____: if.then: -; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32 @sink_r0(i32 [[R]]) -; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[CALL]]) -; IS__TUNIT____-NEXT: br label [[RETURN:%.*]] -; IS__TUNIT____: if.end: -; IS__TUNIT____-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]] -; IS__TUNIT____-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]] -; IS__TUNIT____: if.then3: -; IS__TUNIT____-NEXT: [[CALL4:%.*]] = call i32 @sink_r0(i32 [[B]]) -; IS__TUNIT____-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) -; IS__TUNIT____-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) -; IS__TUNIT____-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[CALL6]], i32 undef) -; IS__TUNIT____-NEXT: [[CALL8:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) -; IS__TUNIT____-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[CALL5]], i32 [[CALL7]], i32 [[CALL8]]) -; IS__TUNIT____-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[CALL4]], i32 [[CALL9]], i32 undef) -; IS__TUNIT____-NEXT: br label [[RETURN]] -; IS__TUNIT____: if.end12: -; IS__TUNIT____-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]] -; IS__TUNIT____-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] -; IS__TUNIT____: cond.true: -; IS__TUNIT____-NEXT: br label [[COND_END:%.*]] -; IS__TUNIT____: cond.false: -; IS__TUNIT____-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) -; IS__TUNIT____-NEXT: br label [[COND_END]] -; IS__TUNIT____: cond.end: -; IS__TUNIT____-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ] -; IS__TUNIT____-NEXT: br label [[RETURN]] -; IS__TUNIT____: return: -; IS__TUNIT____-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[COND]], [[COND_END]] ] -; IS__TUNIT____-NEXT: ret i32 [[RETVAL_0]] +; IS__TUNIT_OPM: Function Attrs: nofree noinline nosync nounwind readnone uwtable +; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@scc_rX +; IS__TUNIT_OPM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[R:%.*]]) +; IS__TUNIT_OPM-NEXT: entry: +; IS__TUNIT_OPM-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]] +; IS__TUNIT_OPM-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; IS__TUNIT_OPM: if.then: +; IS__TUNIT_OPM-NEXT: [[CALL:%.*]] = call i32 @sink_r0(i32 [[R]]) +; IS__TUNIT_OPM-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[CALL]]) +; IS__TUNIT_OPM-NEXT: br label [[RETURN:%.*]] +; IS__TUNIT_OPM: if.end: +; IS__TUNIT_OPM-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]] +; IS__TUNIT_OPM-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]] +; IS__TUNIT_OPM: if.then3: +; IS__TUNIT_OPM-NEXT: [[CALL4:%.*]] = call i32 @sink_r0(i32 [[B]]) +; IS__TUNIT_OPM-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) +; IS__TUNIT_OPM-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) +; IS__TUNIT_OPM-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[CALL6]], i32 undef) +; IS__TUNIT_OPM-NEXT: [[CALL8:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) +; IS__TUNIT_OPM-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[CALL5]], i32 [[CALL7]], i32 [[CALL8]]) +; IS__TUNIT_OPM-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[CALL4]], i32 [[CALL9]], i32 undef) +; IS__TUNIT_OPM-NEXT: br label [[RETURN]] +; IS__TUNIT_OPM: if.end12: +; IS__TUNIT_OPM-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]] +; IS__TUNIT_OPM-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] +; IS__TUNIT_OPM: cond.true: +; IS__TUNIT_OPM-NEXT: br label [[COND_END:%.*]] +; IS__TUNIT_OPM: cond.false: +; IS__TUNIT_OPM-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) +; IS__TUNIT_OPM-NEXT: br label [[COND_END]] +; IS__TUNIT_OPM: cond.end: +; IS__TUNIT_OPM-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ] +; IS__TUNIT_OPM-NEXT: br label [[RETURN]] +; IS__TUNIT_OPM: return: +; IS__TUNIT_OPM-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[COND]], [[COND_END]] ] +; IS__TUNIT_OPM-NEXT: ret i32 [[RETVAL_0]] +; +; IS__TUNIT_NPM: Function Attrs: nofree noinline nosync nounwind readnone uwtable +; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@scc_rX +; IS__TUNIT_NPM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[R:%.*]]) +; IS__TUNIT_NPM-NEXT: entry: +; IS__TUNIT_NPM-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]] +; IS__TUNIT_NPM-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; IS__TUNIT_NPM: if.then: +; IS__TUNIT_NPM-NEXT: [[CALL:%.*]] = call i32 @sink_r0(i32 [[R]]) +; IS__TUNIT_NPM-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[CALL]]) +; IS__TUNIT_NPM-NEXT: br label [[RETURN:%.*]] +; IS__TUNIT_NPM: if.end: +; IS__TUNIT_NPM-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]] +; IS__TUNIT_NPM-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]] +; IS__TUNIT_NPM: if.then3: +; IS__TUNIT_NPM-NEXT: [[CALL4:%.*]] = call i32 @sink_r0(i32 [[B]]) #6, !range !0 +; IS__TUNIT_NPM-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #6, !range !0 +; IS__TUNIT_NPM-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) +; IS__TUNIT_NPM-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[CALL6]], i32 undef) +; IS__TUNIT_NPM-NEXT: [[CALL8:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #6, !range !0 +; IS__TUNIT_NPM-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[CALL5]], i32 [[CALL7]], i32 [[CALL8]]) +; IS__TUNIT_NPM-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[CALL4]], i32 [[CALL9]], i32 undef) +; IS__TUNIT_NPM-NEXT: br label [[RETURN]] +; IS__TUNIT_NPM: if.end12: +; IS__TUNIT_NPM-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]] +; IS__TUNIT_NPM-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] +; IS__TUNIT_NPM: cond.true: +; IS__TUNIT_NPM-NEXT: br label [[COND_END:%.*]] +; IS__TUNIT_NPM: cond.false: +; IS__TUNIT_NPM-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) +; IS__TUNIT_NPM-NEXT: br label [[COND_END]] +; IS__TUNIT_NPM: cond.end: +; IS__TUNIT_NPM-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ] +; IS__TUNIT_NPM-NEXT: br label [[RETURN]] +; IS__TUNIT_NPM: return: +; IS__TUNIT_NPM-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[COND]], [[COND_END]] ] +; IS__TUNIT_NPM-NEXT: ret i32 [[RETVAL_0]] ; ; IS__CGSCC____: Function Attrs: nofree noinline nosync nounwind readnone uwtable ; IS__CGSCC____-LABEL: define {{[^@]+}}@scc_rX