Skip to content

Commit

Permalink
[Attributor] Generalize getAssumedConstantInt interface
Browse files Browse the repository at this point in the history
We are often interested in an assumed constant and sometimes it has to
be an integer constant. Before we only looked for the latter, now we can
ask for either.
  • Loading branch information
jdoerfert committed Feb 20, 2020
1 parent 16188f9 commit e1eed6c
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 90 deletions.
38 changes: 26 additions & 12 deletions llvm/lib/Transforms/IPO/Attributor.cpp
Expand Up @@ -248,9 +248,9 @@ Argument *IRPosition::getAssociatedArgument() const {
return nullptr;
}

static Optional<ConstantInt *>
getAssumedConstant(Attributor &A, const Value &V, const AbstractAttribute &AA,
bool &UsedAssumedInformation) {
static Optional<Constant *> getAssumedConstant(Attributor &A, const Value &V,
const AbstractAttribute &AA,
bool &UsedAssumedInformation) {
const auto &ValueSimplifyAA = A.getAAFor<AAValueSimplify>(
AA, IRPosition::value(V), /* TrackDependence */ false);
Optional<Value *> SimplifiedV = ValueSimplifyAA.getAssumedSimplifiedValue(A);
Expand All @@ -264,12 +264,26 @@ getAssumedConstant(Attributor &A, const Value &V, const AbstractAttribute &AA,
A.recordDependence(ValueSimplifyAA, AA, DepClassTy::OPTIONAL);
return llvm::None;
}
ConstantInt *CI = dyn_cast_or_null<ConstantInt>(SimplifiedV.getValue());
Constant *CI = dyn_cast_or_null<Constant>(SimplifiedV.getValue());
if (CI && CI->getType() != V.getType()) {
// TODO: Check for a save conversion.
return nullptr;
}
if (CI)
A.recordDependence(ValueSimplifyAA, AA, DepClassTy::OPTIONAL);
return CI;
}

static Optional<ConstantInt *>
getAssumedConstantInt(Attributor &A, const Value &V,
const AbstractAttribute &AA,
bool &UsedAssumedInformation) {
Optional<Constant *> C = getAssumedConstant(A, V, AA, UsedAssumedInformation);
if (C.hasValue())
return dyn_cast_or_null<ConstantInt>(C.getValue());
return llvm::None;
}

/// Get pointer operand of memory accessing instruction. If \p I is
/// not a memory accessing instruction, return nullptr. If \p AllowVolatile,
/// is set to false and the instruction is volatile, return nullptr.
Expand Down Expand Up @@ -2919,9 +2933,9 @@ struct AAIsDeadFloating : public AAIsDeadValueImpl {
return ChangeStatus::UNCHANGED;

bool UsedAssumedInformation = false;
Optional<ConstantInt *> CI =
Optional<Constant *> C =
getAssumedConstant(A, V, *this, UsedAssumedInformation);
if (CI.hasValue() && CI.getValue())
if (C.hasValue() && C.getValue())
return ChangeStatus::UNCHANGED;

UndefValue &UV = *UndefValue::get(V.getType());
Expand Down Expand Up @@ -3307,8 +3321,8 @@ identifyAliveSuccessors(Attributor &A, const BranchInst &BI,
if (BI.getNumSuccessors() == 1) {
AliveSuccessors.push_back(&BI.getSuccessor(0)->front());
} else {
Optional<ConstantInt *> CI =
getAssumedConstant(A, *BI.getCondition(), AA, UsedAssumedInformation);
Optional<ConstantInt *> CI = getAssumedConstantInt(
A, *BI.getCondition(), AA, UsedAssumedInformation);
if (!CI.hasValue()) {
// No value yet, assume both edges are dead.
} else if (CI.getValue()) {
Expand All @@ -3330,7 +3344,7 @@ identifyAliveSuccessors(Attributor &A, const SwitchInst &SI,
SmallVectorImpl<const Instruction *> &AliveSuccessors) {
bool UsedAssumedInformation = false;
Optional<ConstantInt *> CI =
getAssumedConstant(A, *SI.getCondition(), AA, UsedAssumedInformation);
getAssumedConstantInt(A, *SI.getCondition(), AA, UsedAssumedInformation);
if (!CI.hasValue()) {
// No value yet, assume all edges are dead.
} else if (CI.getValue()) {
Expand Down Expand Up @@ -7220,11 +7234,11 @@ bool Attributor::checkForAllUses(
// instead use the `follow` callback argument to look at transitive users,
// however, that should be clear from the presence of the argument.
bool UsedAssumedInformation = false;
Optional<ConstantInt *> CI =
Optional<Constant *> C =
getAssumedConstant(*this, V, QueryingAA, UsedAssumedInformation);
if (CI.hasValue() && CI.getValue()) {
if (C.hasValue() && C.getValue()) {
LLVM_DEBUG(dbgs() << "[Attributor] Value is simplified, uses skipped: " << V
<< " -> " << *CI.getValue() << "\n");
<< " -> " << *C.getValue() << "\n");
return true;
}

Expand Down
Expand Up @@ -5,8 +5,7 @@
; This test tries to convince CHECK about promoting the load from %A + 2,
; because there is a load of %A in the entry block
define internal i32 @callee(i1 %C, i32* %A) {
; CHECK-LABEL: define {{[^@]+}}@callee
; CHECK-SAME: (i32* noalias nocapture nofree nonnull readonly align 536870912 dereferenceable(4) [[A:%.*]])
; CHECK-LABEL: define {{[^@]+}}@callee()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_0:%.*]] = load i32, i32* null, align 536870912
; CHECK-NEXT: br label [[F:%.*]]
Expand Down Expand Up @@ -34,7 +33,7 @@ F:

define i32 @foo() {
; CHECK-LABEL: define {{[^@]+}}@foo()
; CHECK-NEXT: [[X:%.*]] = call i32 @callee(i32* noalias nofree readonly align 536870912 null)
; CHECK-NEXT: [[X:%.*]] = call i32 @callee()
; CHECK-NEXT: ret i32 [[X]]
;
%X = call i32 @callee(i1 false, i32* null) ; <i32> [#uses=1]
Expand Down
5 changes: 2 additions & 3 deletions llvm/test/Transforms/Attributor/ArgumentPromotion/chained.ll
Expand Up @@ -5,8 +5,7 @@
@G2 = constant i32* @G1

define internal i32 @test(i32** %x) {
; CHECK-LABEL: define {{[^@]+}}@test
; CHECK-SAME: (i32** nocapture nofree nonnull readonly align 8 dereferenceable(8) [[X:%.*]])
; CHECK-LABEL: define {{[^@]+}}@test()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[Y:%.*]] = load i32*, i32** @G2, align 8
; CHECK-NEXT: [[Z:%.*]] = load i32, i32* [[Y]]
Expand All @@ -21,7 +20,7 @@ entry:
define i32 @caller() {
; CHECK-LABEL: define {{[^@]+}}@caller()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X:%.*]] = call i32 @test(i32** nofree nonnull readonly align 8 dereferenceable(8) @G2)
; CHECK-NEXT: [[X:%.*]] = call i32 @test()
; CHECK-NEXT: ret i32 [[X]]
;
entry:
Expand Down
@@ -1,7 +1,7 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -basicaa -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 < %s | FileCheck %s --check-prefixes=CHECK,OLDPM,OLDPM_MODULE
; RUN: opt -S -basicaa -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=7 < %s | FileCheck %s --check-prefixes=CHECK,OLDPM,OLDPM_MODULE
; RUN: opt -S -basicaa -attributor-cgscc -attributor-disable=false < %s | FileCheck %s --check-prefixes=CHECK,OLDPM,OLDPM_CGSCC
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 < %s | FileCheck %s --check-prefixes=CHECK,NEWPM,NEWPM_MODULE
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=7 < %s | FileCheck %s --check-prefixes=CHECK,NEWPM,NEWPM_MODULE
; RUN: opt -S -passes='attributor-cgscc' -aa-pipeline='basic-aa' -attributor-disable=false < %s | FileCheck %s --check-prefixes=CHECK,NEWPM,NEWPM_CGSCC

; OLDPM_MODULE-NOT: @dead
Expand Down
Expand Up @@ -30,6 +30,8 @@
; This test is just to verify that we do not crash/assert due to mismatch in
; argument count between the caller and callee.

; FIXME we should recognize this as UB and make it an unreachable.

define dso_local i16 @foo(i16 %a) {
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i16 [[A:%.*]])
Expand Down
Expand Up @@ -63,7 +63,7 @@ define internal i8* @side_effects(i8 %v) {
define internal i8* @no_side_effects(i8 %v) readonly nounwind {
; CHECK-LABEL: define {{[^@]+}}@no_side_effects
; CHECK-SAME: (i8 [[V:%.*]])
; CHECK-NEXT: ret i8* null
; CHECK-NEXT: ret i8* undef
;
ret i8* null
}
Expand All @@ -72,7 +72,7 @@ define internal i8* @dont_zap_me(i8 %v) {
; CHECK-LABEL: define {{[^@]+}}@dont_zap_me
; CHECK-SAME: (i8 [[V:%.*]])
; CHECK-NEXT: [[I1:%.*]] = call i32 @external()
; CHECK-NEXT: ret i8* null
; CHECK-NEXT: ret i8* undef
;
%i1 = call i32 @external()
ret i8* null
Expand Down
31 changes: 21 additions & 10 deletions llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll
Expand Up @@ -29,16 +29,27 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; FIXME: nocapture & noalias for %alloc2 in %call3

define dso_local i32 @main() {
; CHECK-LABEL: define {{[^@]+}}@main()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ALLOC1:%.*]] = alloca i8, align 8
; CHECK-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
; CHECK-NEXT: [[THREAD:%.*]] = alloca i64, align 8
; CHECK-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @foo, i8* noalias nofree readnone align 536870912 null)
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* noalias nofree nonnull readnone align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*))
; CHECK-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC1]])
; CHECK-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* noalias nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]])
; CHECK-NEXT: ret i32 0
; MODULE-LABEL: define {{[^@]+}}@main()
; MODULE-NEXT: entry:
; MODULE-NEXT: [[ALLOC1:%.*]] = alloca i8, align 8
; MODULE-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
; MODULE-NEXT: [[THREAD:%.*]] = alloca i64, align 8
; MODULE-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @foo, i8* noalias nofree readnone align 536870912 undef)
; MODULE-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* noalias nofree nonnull readnone align 8 dereferenceable(8) undef)
; MODULE-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC1]])
; MODULE-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* noalias nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]])
; MODULE-NEXT: ret i32 0
;
; CGSCC-LABEL: define {{[^@]+}}@main()
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[ALLOC1:%.*]] = alloca i8, align 8
; CGSCC-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
; CGSCC-NEXT: [[THREAD:%.*]] = alloca i64, align 8
; CGSCC-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @foo, i8* noalias nofree readnone align 536870912 null)
; CGSCC-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* noalias nofree nonnull readnone align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*))
; CGSCC-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC1]])
; CGSCC-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* noalias nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]])
; CGSCC-NEXT: ret i32 0
;
entry:
%alloc1 = alloca i8, align 8
Expand Down
Expand Up @@ -39,7 +39,7 @@ entry:
define dso_local void @caller() {
; CHECK-LABEL: define {{[^@]+}}@caller()
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @broker(i32* nofree nonnull readonly align 4 dereferenceable(4) @gtl, i32 (i32*, i32*)* nonnull @callee, i32* nofree nonnull readonly align 4 dereferenceable(4) @gsh)
; CHECK-NEXT: call void @broker(i32* nofree nonnull readonly align 4 dereferenceable(4) @gtl, i32 (i32*, i32*)* nonnull @callee, i32* nofree nonnull readonly align 4 dereferenceable(4) undef)
; CHECK-NEXT: ret void
;
entry:
Expand Down
55 changes: 26 additions & 29 deletions llvm/test/Transforms/Attributor/align.ll
@@ -1,4 +1,4 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes --turn off
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --disable --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_MODULE
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_CGSCC
; RUN: opt -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_MODULE
Expand Down Expand Up @@ -138,12 +138,11 @@ define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 {
; TEST 7
; Better than IR information
define align 4 i8* @test7() #0 {
; ATTRIBUTOR_MODULE-LABEL: define {{[^@]+}}@test7
; ATTRIBUTOR_MODULE-LABEL: define {{[^@]+}}@test7()
; ATTRIBUTOR_MODULE-NEXT: [[C:%.*]] = tail call i8* @f1(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
; ATTRIBUTOR_MODULE-NEXT: ret i8* [[C]]
;
; ATTRIBUTOR_CGSCC-LABEL: define {{[^@]+}}@test7
; ATTRIBUTOR_CGSCC-SAME: ()
; ATTRIBUTOR_CGSCC-LABEL: define {{[^@]+}}@test7()
; ATTRIBUTOR_CGSCC-NEXT: [[C:%.*]] = tail call nonnull align 8 dereferenceable(1) i8* @f1(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
; ATTRIBUTOR_CGSCC-NEXT: ret i8* [[C]]
;
Expand All @@ -159,7 +158,7 @@ define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 {
; ATTRIBUTOR_MODULE-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
; ATTRIBUTOR_MODULE-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; ATTRIBUTOR_MODULE: 3:
; ATTRIBUTOR_MODULE-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
; ATTRIBUTOR_MODULE-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2b()
; ATTRIBUTOR_MODULE-NEXT: [[L:%.*]] = load i8, i8* [[TMP4]], align 8
; ATTRIBUTOR_MODULE-NEXT: store i8 [[L]], i8* @a1, align 8
; ATTRIBUTOR_MODULE-NEXT: br label [[TMP5]]
Expand All @@ -172,7 +171,7 @@ define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 {
; ATTRIBUTOR_CGSCC-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
; ATTRIBUTOR_CGSCC-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; ATTRIBUTOR_CGSCC: 3:
; ATTRIBUTOR_CGSCC-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
; ATTRIBUTOR_CGSCC-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2b()
; ATTRIBUTOR_CGSCC-NEXT: [[L:%.*]] = load i8, i8* [[TMP4]], align 8
; ATTRIBUTOR_CGSCC-NEXT: store i8 [[L]], i8* @a1, align 8
; ATTRIBUTOR_CGSCC-NEXT: br label [[TMP5]]
Expand All @@ -197,19 +196,18 @@ define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 {
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f2b(i8* readnone %0) local_unnamed_addr #0 {
;
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f2b
; ATTRIBUTOR-SAME: (i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq i8* @a1, null
; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]]
; ATTRIBUTOR: 3:
; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" @a1)
; ATTRIBUTOR-NEXT: br label [[TMP7:%.*]]
; ATTRIBUTOR: 5:
; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = tail call i8* @f3b(i8* noalias nofree nonnull readnone align 16 dereferenceable(1) @a2)
; ATTRIBUTOR-NEXT: br label [[TMP7]]
; ATTRIBUTOR: 7:
; ATTRIBUTOR-NEXT: [[TMP8:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP6]], [[TMP5]] ]
; ATTRIBUTOR-NEXT: ret i8* [[TMP8]]
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f2b() local_unnamed_addr
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = icmp eq i8* @a1, null
; ATTRIBUTOR-NEXT: br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]]
; ATTRIBUTOR: 2:
; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" @a1)
; ATTRIBUTOR-NEXT: br label [[TMP6:%.*]]
; ATTRIBUTOR: 4:
; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i8* @f3b()
; ATTRIBUTOR-NEXT: br label [[TMP6]]
; ATTRIBUTOR: 6:
; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i8* [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ]
; ATTRIBUTOR-NEXT: ret i8* [[TMP7]]
;
%2 = icmp eq i8* %0, null
br i1 %2, label %5, label %3
Expand All @@ -231,16 +229,15 @@ define internal i8* @f2b(i8* readnone %0) local_unnamed_addr #0 {
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f3b(i8* readnone %0) local_unnamed_addr #0 {
;
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f3b
; ATTRIBUTOR-SAME: (i8* noalias nocapture nofree nonnull readnone align 16 dereferenceable(1) [[TMP0:%.*]]) local_unnamed_addr
; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq i8* @a2, null
; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; ATTRIBUTOR: 3:
; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 16 dereferenceable(1) @a2)
; ATTRIBUTOR-NEXT: br label [[TMP5]]
; ATTRIBUTOR: 5:
; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ @a1, [[TMP1:%.*]] ]
; ATTRIBUTOR-NEXT: ret i8* [[TMP6]]
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f3b() local_unnamed_addr
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = icmp eq i8* @a2, null
; ATTRIBUTOR-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP4:%.*]]
; ATTRIBUTOR: 2:
; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 16 dereferenceable(1) @a2)
; ATTRIBUTOR-NEXT: br label [[TMP4]]
; ATTRIBUTOR: 4:
; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = phi i8* [ [[TMP3]], [[TMP2]] ], [ @a1, [[TMP0:%.*]] ]
; ATTRIBUTOR-NEXT: ret i8* [[TMP5]]
;
%2 = icmp eq i8* %0, null
br i1 %2, label %3, label %5
Expand Down

0 comments on commit e1eed6c

Please sign in to comment.