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 @@ -485,7 +485,8 @@ Attributor::getAssumedConstant(const Value &V, const AbstractAttribute &AA, bool &UsedAssumedInformation) { const auto &ValueSimplifyAA = getAAFor( - AA, IRPosition::value(V), /* TrackDependence */ false); + AA, IRPosition::value(V, AA.getCallBaseContext()), + /* TrackDependence */ false); Optional SimplifiedV = ValueSimplifyAA.getAssumedSimplifiedValue(*this); bool IsKnown = ValueSimplifyAA.isKnown(); @@ -524,6 +525,12 @@ return isAssumedDead(IRP, &AA, FnLivenessAA, CheckBBLivenessOnly, DepClass); } +const IRPosition::CallBaseContext *getCBContext(const AbstractAttribute *AA) { + if (!AA) + return nullptr; + return AA->getCallBaseContext(); +} + bool Attributor::isAssumedDead(const Use &U, const AbstractAttribute *QueryingAA, const AAIsDead *FnLivenessAA, @@ -561,9 +568,10 @@ const AAIsDead *FnLivenessAA, bool CheckBBLivenessOnly, DepClassTy DepClass) { if (!FnLivenessAA) - FnLivenessAA = lookupAAFor(IRPosition::function(*I.getFunction()), - QueryingAA, - /* TrackDependence */ false); + FnLivenessAA = lookupAAFor( + IRPosition::function(*I.getFunction(), getCBContext(QueryingAA)), + QueryingAA, + /* TrackDependence */ false); // If we have a context instruction and a liveness AA we use it. if (FnLivenessAA && @@ -577,8 +585,9 @@ if (CheckBBLivenessOnly) return false; - const AAIsDead &IsDeadAA = getOrCreateAAFor( - IRPosition::value(I), QueryingAA, /* TrackDependence */ false); + const AAIsDead &IsDeadAA = + getOrCreateAAFor(IRPosition::value(I, getCBContext(QueryingAA)), + QueryingAA, /* TrackDependence */ false); // Don't check liveness for AAIsDead. if (QueryingAA == &IsDeadAA) return false; @@ -836,7 +845,8 @@ return false; // TODO: use the function scope once we have call site AAReturnedValues. - const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction); + const IRPosition &QueryIRP = IRPosition::function( + *AssociatedFunction, QueryingAA.getCallBaseContext()); const auto &AARetVal = getAAFor(QueryingAA, QueryIRP); if (!AARetVal.getState().isValidState()) return false; 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 @@ -254,7 +254,8 @@ const AAIsDead *LivenessAA = nullptr; if (IRP.getAnchorScope()) LivenessAA = &A.getAAFor( - QueryingAA, IRPosition::function(*IRP.getAnchorScope()), + QueryingAA, + IRPosition::function(*IRP.getAnchorScope(), IRP.getCallBaseContext()), /* TrackDependence */ false); bool AnyDead = false; @@ -1078,7 +1079,7 @@ // Helper method to invoke the generic value traversal. auto VisitReturnedValue = [&](Value &RV, RVState &RVS, const Instruction *CtxI) { - IRPosition RetValPos = IRPosition::value(RV); + IRPosition RetValPos = IRPosition::value(RV, getCallBaseContext()); return genericValueTraversal( A, RetValPos, *this, RVS, VisitValueCB, CtxI, /* UseValueSimplify */ false); @@ -4387,7 +4388,8 @@ // FIXME: Add a typecast support. auto &ValueSimplifyAA = A.getAAFor( - QueryingAA, IRPosition::value(QueryingValue)); + QueryingAA, + IRPosition::value(QueryingValue, QueryingAA.getCallBaseContext())); Optional QueryingValueSimplified = ValueSimplifyAA.getAssumedSimplifiedValue(A); @@ -4421,6 +4423,7 @@ if (!getAssociatedValue().getType()->isIntegerTy()) return false; + // This will also pass the call base context. const auto &ValueConstantRangeAA = A.getAAFor(*this, getIRPosition()); @@ -4538,9 +4541,18 @@ return checkAndUpdate(A, *this, ArgOp, SimplifiedAssociatedValue); }; + // Generate a answer specific to a call site context. + bool Success; bool AllCallSitesKnown; - if (!A.checkForAllCallSites(PredForCallSite, *this, true, - AllCallSitesKnown)) + if (hasCallBaseContext()) { + AbstractCallSite ACS(&getCallBaseContext()->getCalledOperandUse()); + Success = PredForCallSite(ACS); + } else { + Success = A.checkForAllCallSites(PredForCallSite, *this, true, + AllCallSitesKnown); + } + + if (!Success) if (!askSimplifiedValueForAAValueConstantRange(A)) return indicatePessimisticFixpoint(); @@ -4644,7 +4656,8 @@ auto VisitValueCB = [&](Value &V, const Instruction *CtxI, bool &, bool Stripped) -> bool { - auto &AA = A.getAAFor(*this, IRPosition::value(V)); + auto &AA = A.getAAFor( + *this, IRPosition::value(V, getCallBaseContext())); if (!Stripped && this == &AA) { // TODO: Look the instruction and check recursively. @@ -7020,8 +7033,8 @@ if (!I || isa(I)) { // If the value is not instruction, we query AA to Attributor. - const auto &AA = - A.getAAFor(*this, IRPosition::value(V)); + const auto &AA = A.getAAFor( + *this, IRPosition::value(V, getCallBaseContext())); // Clamp operator is not used to utilize a program point CtxI. T.unionAssumed(AA.getAssumedConstantRange(A, CtxI)); diff --git a/llvm/test/Transforms/Attributor/cb_liveness.ll b/llvm/test/Transforms/Attributor/cb_liveness.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Attributor/cb_liveness.ll @@ -0,0 +1,196 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes + +; call site specific analysis is disabled + +; RUN: opt -attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -attributor-enable-call-site-specific-deduction=false -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=1 -attributor-enable-call-site-specific-deduction=false -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 -attributor-manifest-internal -attributor-annotate-decl-cs -attributor-enable-call-site-specific-deduction=false -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 -attributor-enable-call-site-specific-deduction=false -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM + +; call site specific-deduction analysis is enabled + +; RUN: opt -attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -attributor-enable-call-site-specific-deduction=true -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM,CHECK_ENABLED,NOT_CGSCC_NPM_ENABLED,NOT_CGSCC_OPM_ENABLED,NOT_TUNIT_NPM_ENABLED,IS__TUNIT_____ENABLED,IS________OPM_ENABLED,IS__TUNIT_OPM_ENABLED +; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -attributor-enable-call-site-specific-deduction=true -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM,CHECK_ENABLED,NOT_CGSCC_OPM_ENABLED,NOT_CGSCC_NPM_ENABLED,NOT_TUNIT_OPM_ENABLED,IS__TUNIT_____ENABLED,IS________NPM_ENABLED,IS__TUNIT_NPM_ENABLED +; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -attributor-enable-call-site-specific-deduction=true -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM,CHECK_ENABLED,NOT_TUNIT_NPM_ENABLED,NOT_TUNIT_OPM_ENABLED,NOT_CGSCC_NPM_ENABLED,IS__CGSCC_____ENABLED,IS________OPM_ENABLED,IS__CGSCC_OPM_ENABLED +; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -attributor-enable-call-site-specific-deduction=true -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM,CHECK_ENABLED,NOT_TUNIT_NPM_ENABLED,NOT_TUNIT_OPM_ENABLED,NOT_CGSCC_OPM_ENABLED,IS__CGSCC_____ENABLED,IS________NPM_ENABLED,IS__CGSCC_NPM_ENABLED + +define dso_local i32 @test_range1(i32 %0) #0 { +; CHECK-LABEL: define {{[^@]+}}@test_range1 +; CHECK-SAME: (i32 [[TMP0:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i32 [[TMP0]], 0 +; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP4:%.*]] +; CHECK: 3: +; CHECK-NEXT: br label [[TMP5:%.*]] +; CHECK: 4: +; CHECK-NEXT: br label [[TMP5]] +; CHECK: 5: +; CHECK-NEXT: [[DOT0:%.*]] = phi i32 [ 100, [[TMP3]] ], [ 0, [[TMP4]] ] +; CHECK-NEXT: ret i32 [[DOT0]] +; + %2 = icmp ne i32 %0, 0 + br i1 %2, label %3, label %4 + +3: ; preds = %1 + br label %5 + +4: ; preds = %1 + br label %5 + +5: ; preds = %4, %3 + %.0 = phi i32 [ 100, %3 ], [ 0, %4 ] + ret i32 %.0 +} + +define i32 @test_range2(i32 %0) #0 { +; CHECK-LABEL: define {{[^@]+}}@test_range2 +; CHECK-SAME: (i32 [[TMP0:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i32 [[TMP0]], 0 +; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP4:%.*]] +; CHECK: 3: +; CHECK-NEXT: br label [[TMP5:%.*]] +; CHECK: 4: +; CHECK-NEXT: br label [[TMP5]] +; CHECK: 5: +; CHECK-NEXT: [[DOT0:%.*]] = phi i32 [ 100, [[TMP3]] ], [ 200, [[TMP4]] ] +; CHECK-NEXT: ret i32 [[DOT0]] +; + %2 = icmp ne i32 %0, 0 + br i1 %2, label %3, label %4 + +3: ; preds = %1 + br label %5 + +4: ; preds = %1 + br label %5 + +5: ; preds = %4, %3 + %.0 = phi i32 [ 100, %3 ], [ 200, %4 ] + ret i32 %.0 +} +define i32 @test(i32 %0, i32 %1) #0 { +; IS__TUNIT____-LABEL: define {{[^@]+}}@test +; IS__TUNIT____-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) +; IS__TUNIT____-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1]], 0 +; IS__TUNIT____-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP6:%.*]] +; IS__TUNIT____: 4: +; IS__TUNIT____-NEXT: [[TMP5:%.*]] = call i32 @test_range1(i32 [[TMP0]]) #1, !range !0 +; IS__TUNIT____-NEXT: br label [[TMP8:%.*]] +; IS__TUNIT____: 6: +; IS__TUNIT____-NEXT: [[TMP7:%.*]] = call i32 @test_range2(i32 [[TMP0]]) #1, !range !1 +; IS__TUNIT____-NEXT: br label [[TMP8]] +; IS__TUNIT____: 8: +; IS__TUNIT____-NEXT: [[DOT0:%.*]] = phi i32 [ [[TMP5]], [[TMP4]] ], [ [[TMP7]], [[TMP6]] ] +; IS__TUNIT____-NEXT: ret i32 [[DOT0]] +; +; IS__CGSCC____-LABEL: define {{[^@]+}}@test +; IS__CGSCC____-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) +; IS__CGSCC____-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1]], 0 +; IS__CGSCC____-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP6:%.*]] +; IS__CGSCC____: 4: +; IS__CGSCC____-NEXT: [[TMP5:%.*]] = call i32 @test_range1(i32 [[TMP0]]) +; IS__CGSCC____-NEXT: br label [[TMP8:%.*]] +; IS__CGSCC____: 6: +; IS__CGSCC____-NEXT: [[TMP7:%.*]] = call i32 @test_range2(i32 [[TMP0]]) +; IS__CGSCC____-NEXT: br label [[TMP8]] +; IS__CGSCC____: 8: +; IS__CGSCC____-NEXT: [[DOT0:%.*]] = phi i32 [ [[TMP5]], [[TMP4]] ], [ [[TMP7]], [[TMP6]] ] +; IS__CGSCC____-NEXT: ret i32 [[DOT0]] +; + %3 = icmp ne i32 %1, 0 + br i1 %3, label %4, label %6 + +4: ; preds = %2 + %5 = call i32 @test_range1(i32 %0) + br label %8 + +6: ; preds = %2 + %7 = call i32 @test_range2(i32 %0) + br label %8 + +8: ; preds = %6, %4 + %.0 = phi i32 [ %5, %4 ], [ %7, %6 ] + ret i32 %.0 +} + +define i32 @test_pcheck1(i32 %0) #0 { +; IS__CGSCC____-LABEL: define {{[^@]+}}@test_pcheck1 +; IS__CGSCC____-SAME: (i32 [[TMP0:%.*]]) +; IS__CGSCC____-NEXT: [[TMP2:%.*]] = call i32 @test(i32 [[TMP0]], i32 1) +; IS__CGSCC____-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP2]], 101 +; IS__CGSCC____-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32 +; IS__CGSCC____-NEXT: ret i32 [[TMP4]] +; +; IS__TUNIT_____ENABLED-LABEL: define {{[^@]+}}@test_pcheck1 +; IS__TUNIT_____ENABLED-SAME: (i32 [[TMP0:%.*]]) +; IS__TUNIT_____ENABLED-NEXT: ret i32 1 +; + %2 = call i32 @test(i32 %0, i32 1) + %3 = icmp slt i32 %2, 101 + %4 = zext i1 %3 to i32 + ret i32 %4 +} + +define i32 @test_pcheck2(i32 %0) #0 { +; IS__CGSCC____-LABEL: define {{[^@]+}}@test_pcheck2 +; IS__CGSCC____-SAME: (i32 [[TMP0:%.*]]) +; IS__CGSCC____-NEXT: [[TMP2:%.*]] = call i32 @test(i32 [[TMP0]], i32 0) +; IS__CGSCC____-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], 99 +; IS__CGSCC____-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32 +; IS__CGSCC____-NEXT: ret i32 [[TMP4]] +; +; IS__TUNIT_____ENABLED-LABEL: define {{[^@]+}}@test_pcheck2 +; IS__TUNIT_____ENABLED-SAME: (i32 [[TMP0:%.*]]) +; IS__TUNIT_____ENABLED-NEXT: ret i32 1 +; + %2 = call i32 @test(i32 %0, i32 0) + %3 = icmp sgt i32 %2, 99 + %4 = zext i1 %3 to i32 + ret i32 %4 +} + +define i32 @test_ncheck1(i32 %0) #0 { +; IS__CGSCC____-LABEL: define {{[^@]+}}@test_ncheck1 +; IS__CGSCC____-SAME: (i32 [[TMP0:%.*]]) +; IS__CGSCC____-NEXT: [[TMP2:%.*]] = call i32 @test(i32 [[TMP0]], i32 1) +; IS__CGSCC____-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], 50 +; IS__CGSCC____-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32 +; IS__CGSCC____-NEXT: ret i32 [[TMP4]] +; +; IS__TUNIT_____ENABLED-LABEL: define {{[^@]+}}@test_ncheck1 +; IS__TUNIT_____ENABLED-SAME: (i32 [[TMP0:%.*]]) +; IS__TUNIT_____ENABLED-NEXT: [[TMP2:%.*]] = call i32 @test(i32 [[TMP0]], i32 1) #1, !range !0 +; IS__TUNIT_____ENABLED-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], 50 +; IS__TUNIT_____ENABLED-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32 +; IS__TUNIT_____ENABLED-NEXT: ret i32 [[TMP4]] +; + %2 = call i32 @test(i32 %0, i32 1) + %3 = icmp sgt i32 %2, 50 + %4 = zext i1 %3 to i32 + ret i32 %4 +} + +define i32 @test_ncheck2(i32 %0) #0 { +; IS__CGSCC____-LABEL: define {{[^@]+}}@test_ncheck2 +; IS__CGSCC____-SAME: (i32 [[TMP0:%.*]]) +; IS__CGSCC____-NEXT: [[TMP2:%.*]] = call i32 @test(i32 [[TMP0]], i32 0) +; IS__CGSCC____-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], 150 +; IS__CGSCC____-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32 +; IS__CGSCC____-NEXT: ret i32 [[TMP4]] +; +; IS__TUNIT_____ENABLED-LABEL: define {{[^@]+}}@test_ncheck2 +; IS__TUNIT_____ENABLED-SAME: (i32 [[TMP0:%.*]]) +; IS__TUNIT_____ENABLED-NEXT: [[TMP2:%.*]] = call i32 @test(i32 [[TMP0]], i32 0) #1, !range !1 +; IS__TUNIT_____ENABLED-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], 150 +; IS__TUNIT_____ENABLED-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32 +; IS__TUNIT_____ENABLED-NEXT: ret i32 [[TMP4]] +; + %2 = call i32 @test(i32 %0, i32 0) + %3 = icmp sgt i32 %2, 150 + %4 = zext i1 %3 to i32 + ret i32 %4 +} + +attributes #0 = { noinline nounwind sspstrong uwtable} + +; IS__TUNIT_____: !0 = !{i32 0, i32 101} +; IS__TUNIT_____: !1 = !{i32 100, i32 201}