blob: 882d0e8b8c7f6552718c204f9cf5b9d23969fc25 [file] [log] [blame]
; 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
; RUN: opt -passes=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
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; Test cases specifically designed for "align" attribute.
; We use FIXME's to indicate problems and missing attributes.
; TEST 1
; ATTRIBUTOR: define align 8 i32* @test1(i32* nofree readnone returned align 8 "no-capture-maybe-returned" %0)
define i32* @test1(i32* align 8 %0) #0 {
ret i32* %0
}
; TEST 2
; ATTRIBUTOR: define i32* @test2(i32* nofree readnone returned "no-capture-maybe-returned" %0)
define i32* @test2(i32* %0) #0 {
ret i32* %0
}
; TEST 3
; ATTRIBUTOR: define align 4 i32* @test3(i32* nofree readnone align 8 "no-capture-maybe-returned" %0, i32* nofree readnone align 4 "no-capture-maybe-returned" %1, i1 %2)
define i32* @test3(i32* align 8 %0, i32* align 4 %1, i1 %2) #0 {
%ret = select i1 %2, i32* %0, i32* %1
ret i32* %ret
}
; TEST 4
; ATTRIBUTOR: define align 32 i32* @test4(i32* nofree readnone align 32 "no-capture-maybe-returned" %0, i32* nofree readnone align 32 "no-capture-maybe-returned" %1, i1 %2)
define i32* @test4(i32* align 32 %0, i32* align 32 %1, i1 %2) #0 {
%ret = select i1 %2, i32* %0, i32* %1
ret i32* %ret
}
; TEST 5
declare i32* @unknown()
declare align 8 i32* @align8()
; ATTRIBUTOR: define align 8 i32* @test5_1()
define i32* @test5_1() {
%ret = tail call align 8 i32* @unknown()
ret i32* %ret
}
; ATTRIBUTOR: define align 8 i32* @test5_2()
define i32* @test5_2() {
%ret = tail call i32* @align8()
ret i32* %ret
}
; TEST 6
; SCC
; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @test6_1()
define i32* @test6_1() #0 {
%ret = tail call i32* @test6_2()
ret i32* %ret
}
; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @test6_2()
define i32* @test6_2() #0 {
%ret = tail call i32* @test6_1()
ret i32* %ret
}
; char a1 __attribute__((aligned(8)));
; char a2 __attribute__((aligned(16)));
;
; char* f1(char* a ){
; return a?a:f2(&a1);
; }
; char* f2(char* a){
; return a?f1(a):f3(&a2);
; }
;
; char* f3(char* a){
; return a?&a1: f1(&a2);
; }
@a1 = common global i8 0, align 8
@a2 = common global i8 0, align 16
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 {
%2 = icmp eq i8* %0, null
br i1 %2, label %3, label %5
; <label>:3: ; preds = %1
%4 = tail call i8* @f2(i8* nonnull @a1)
%l = load i8, i8* %4
br label %5
; <label>:5: ; preds = %1, %3
%6 = phi i8* [ %4, %3 ], [ %0, %1 ]
ret i8* %6
}
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 {
%2 = icmp eq i8* %0, null
br i1 %2, label %5, label %3
; <label>:3: ; preds = %1
%4 = tail call i8* @f1(i8* nonnull %0)
br label %7
; <label>:5: ; preds = %1
%6 = tail call i8* @f3(i8* nonnull @a2)
br label %7
; <label>:7: ; preds = %5, %3
%8 = phi i8* [ %4, %3 ], [ %6, %5 ]
ret i8* %8
}
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 {
%2 = icmp eq i8* %0, null
br i1 %2, label %3, label %5
; <label>:3: ; preds = %1
%4 = tail call i8* @f1(i8* nonnull @a2)
br label %5
; <label>:5: ; preds = %1, %3
%6 = phi i8* [ %4, %3 ], [ @a1, %1 ]
ret i8* %6
}
; UTC_ARGS: --enable
; TEST 7
; Better than IR information
define align 4 i8* @test7() #0 {
; 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-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]]
;
%c = tail call i8* @f1(i8* align 8 dereferenceable(1) @a1)
ret i8* %c
}
; TEST 7b
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 {
; ATTRIBUTOR_MODULE-LABEL: define {{[^@]+}}@f1b
; ATTRIBUTOR_MODULE-SAME: (i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; 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()
; 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]]
; ATTRIBUTOR_MODULE: 5:
; ATTRIBUTOR_MODULE-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ]
; ATTRIBUTOR_MODULE-NEXT: ret i8* [[TMP6]]
;
; ATTRIBUTOR_CGSCC-LABEL: define {{[^@]+}}@f1b
; ATTRIBUTOR_CGSCC-SAME: (i8* nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; 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()
; 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]]
; ATTRIBUTOR_CGSCC: 5:
; ATTRIBUTOR_CGSCC-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ]
; ATTRIBUTOR_CGSCC-NEXT: ret i8* [[TMP6]]
;
%2 = icmp eq i8* %0, null
br i1 %2, label %3, label %5
; <label>:3: ; preds = %1
%4 = tail call i8* @f2b(i8* nonnull @a1)
%l = load i8, i8* %4
store i8 %l, i8* @a1
br label %5
; <label>:5: ; preds = %1, %3
%6 = phi i8* [ %4, %3 ], [ %0, %1 ]
ret i8* %6
}
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f2b(i8* readnone %0) local_unnamed_addr #0 {
;
; 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
; <label>:3: ; preds = %1
%4 = tail call i8* @f1b(i8* nonnull %0)
br label %7
; <label>:5: ; preds = %1
%6 = tail call i8* @f3b(i8* nonnull @a2)
br label %7
; <label>:7: ; preds = %5, %3
%8 = phi i8* [ %4, %3 ], [ %6, %5 ]
ret i8* %8
}
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f3b(i8* readnone %0) local_unnamed_addr #0 {
;
; 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
; <label>:3: ; preds = %1
%4 = tail call i8* @f1b(i8* nonnull @a2)
br label %5
; <label>:5: ; preds = %1, %3
%6 = phi i8* [ %4, %3 ], [ @a1, %1 ]
ret i8* %6
}
define align 4 i32* @test7b(i32* align 32 %p) #0 {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test7b
; ATTRIBUTOR-SAME: (i32* nofree readnone returned align 32 "no-capture-maybe-returned" [[P:%.*]])
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
; ATTRIBUTOR-NEXT: ret i32* [[P]]
;
tail call i8* @f1b(i8* align 8 dereferenceable(1) @a1)
ret i32* %p
}
; UTC_ARGS: --disable
; TEST 8
define void @test8_helper() {
%ptr0 = tail call i32* @unknown()
%ptr1 = tail call align 4 i32* @unknown()
%ptr2 = tail call align 8 i32* @unknown()
tail call void @test8(i32* %ptr1, i32* %ptr1, i32* %ptr0)
; ATTRIBUTOR: tail call void @test8(i32* noalias readnone align 4 %ptr1, i32* noalias readnone align 4 %ptr1, i32* noalias readnone %ptr0)
tail call void @test8(i32* %ptr2, i32* %ptr1, i32* %ptr1)
; ATTRIBUTOR: tail call void @test8(i32* noalias readnone align 8 %ptr2, i32* noalias readnone align 4 %ptr1, i32* noalias readnone align 4 %ptr1)
tail call void @test8(i32* %ptr2, i32* %ptr1, i32* %ptr1)
; ATTRIBUTOR: tail call void @test8(i32* noalias readnone align 8 %ptr2, i32* noalias readnone align 4 %ptr1, i32* noalias readnone align 4 %ptr1)
ret void
}
declare void @user_i32_ptr(i32* nocapture readnone) nounwind
define internal void @test8(i32* %a, i32* %b, i32* %c) {
; ATTRIBUTOR_MODULE: define internal void @test8(i32* noalias nocapture readnone align 4 %a, i32* noalias nocapture readnone align 4 %b, i32* noalias nocapture readnone %c)
; ATTRIBUTOR_CGSCC: define internal void @test8(i32* nocapture readnone align 4 %a, i32* nocapture readnone align 4 %b, i32* nocapture readnone %c)
call void @user_i32_ptr(i32* %a)
call void @user_i32_ptr(i32* %b)
call void @user_i32_ptr(i32* %c)
ret void
}
declare void @test9_helper(i32* %A)
define void @test9_traversal(i1 %c, i32* align 4 %B, i32* align 8 %C) {
%sel = select i1 %c, i32* %B, i32* %C
call void @test9_helper(i32* %sel)
ret void
}
; FIXME: This will work with an upcoming patch (D66618 or similar)
; define align 32 i32* @test10a(i32* align 32 "no-capture-maybe-returned" %p)
; ATTRIBUTOR: define i32* @test10a(i32* nofree nonnull align 32 dereferenceable(4) "no-capture-maybe-returned" %p)
define i32* @test10a(i32* align 32 %p) {
; ATTRIBUTOR: %l = load i32, i32* %p, align 32
%l = load i32, i32* %p
%c = icmp eq i32 %l, 0
br i1 %c, label %t, label %f
t:
%r = call i32* @test10a(i32* %p)
; FIXME: This will work with an upcoming patch (D66618 or similar)
; store i32 1, i32* %r, align 32
; ATTRIBUTOR: store i32 1, i32* %r
store i32 1, i32* %r
%g0 = getelementptr i32, i32* %p, i32 8
br label %e
f:
%g1 = getelementptr i32, i32* %p, i32 8
; FIXME: This will work with an upcoming patch (D66618 or similar)
; store i32 -1, i32* %g1, align 32
; ATTRIBUTOR: store i32 -1, i32* %g1
store i32 -1, i32* %g1
br label %e
e:
%phi = phi i32* [%g0, %t], [%g1, %f]
ret i32* %phi
}
; FIXME: This will work with an upcoming patch (D66618 or similar)
; define align 32 i32* @test10b(i32* align 32 "no-capture-maybe-returned" %p)
; ATTRIBUTOR: define i32* @test10b(i32* nofree nonnull align 32 dereferenceable(4) "no-capture-maybe-returned" %p)
define i32* @test10b(i32* align 32 %p) {
; ATTRIBUTOR: %l = load i32, i32* %p, align 32
%l = load i32, i32* %p
%c = icmp eq i32 %l, 0
br i1 %c, label %t, label %f
t:
%r = call i32* @test10b(i32* %p)
; FIXME: This will work with an upcoming patch (D66618 or similar)
; store i32 1, i32* %r, align 32
; ATTRIBUTOR: store i32 1, i32* %r
store i32 1, i32* %r
%g0 = getelementptr i32, i32* %p, i32 8
br label %e
f:
%g1 = getelementptr i32, i32* %p, i32 -8
; FIXME: This will work with an upcoming patch (D66618 or similar)
; store i32 -1, i32* %g1, align 32
; ATTRIBUTOR: store i32 -1, i32* %g1
store i32 -1, i32* %g1
br label %e
e:
%phi = phi i32* [%g0, %t], [%g1, %f]
ret i32* %phi
}
; ATTRIBUTOR: define i64 @test11(i32* nocapture nofree nonnull readonly align 8 dereferenceable(8) %p)
define i64 @test11(i32* %p) {
%p-cast = bitcast i32* %p to i64*
%ret = load i64, i64* %p-cast, align 8
ret i64 %ret
}
; TEST 12
; Test for deduction using must-be-executed-context and GEP instruction
; FXIME: %p should have nonnull
; ATTRIBUTOR: define i64 @test12-1(i32* nocapture nofree readonly align 16 %p)
define i64 @test12-1(i32* align 4 %p) {
%p-cast = bitcast i32* %p to i64*
%arrayidx0 = getelementptr i64, i64* %p-cast, i64 1
%arrayidx1 = getelementptr i64, i64* %arrayidx0, i64 3
%ret = load i64, i64* %arrayidx1, align 16
ret i64 %ret
}
; ATTRIBUTOR: define i64 @test12-2(i32* nocapture nofree nonnull readonly align 16 dereferenceable(8) %p)
define i64 @test12-2(i32* align 4 %p) {
%p-cast = bitcast i32* %p to i64*
%arrayidx0 = getelementptr i64, i64* %p-cast, i64 0
%ret = load i64, i64* %arrayidx0, align 16
ret i64 %ret
}
; FXIME: %p should have nonnull
; ATTRIBUTOR: define void @test12-3(i32* nocapture nofree writeonly align 16 %p)
define void @test12-3(i32* align 4 %p) {
%p-cast = bitcast i32* %p to i64*
%arrayidx0 = getelementptr i64, i64* %p-cast, i64 1
%arrayidx1 = getelementptr i64, i64* %arrayidx0, i64 3
store i64 0, i64* %arrayidx1, align 16
ret void
}
; ATTRIBUTOR: define void @test12-4(i32* nocapture nofree nonnull writeonly align 16 dereferenceable(8) %p)
define void @test12-4(i32* align 4 %p) {
%p-cast = bitcast i32* %p to i64*
%arrayidx0 = getelementptr i64, i64* %p-cast, i64 0
store i64 0, i64* %arrayidx0, align 16
ret void
}
declare void @use(i64*) willreturn nounwind
; ATTRIBUTOR: define void @test12-5(i32* align 16 %p)
define void @test12-5(i32* align 4 %p) {
%p-cast = bitcast i32* %p to i64*
%arrayidx0 = getelementptr i64, i64* %p-cast, i64 1
%arrayidx1 = getelementptr i64, i64* %arrayidx0, i64 3
tail call void @use(i64* align 16 %arrayidx1)
ret void
}
; ATTRIBUTOR: define void @test12-6(i32* align 16 %p)
define void @test12-6(i32* align 4 %p) {
%p-cast = bitcast i32* %p to i64*
%arrayidx0 = getelementptr i64, i64* %p-cast, i64 0
tail call void @use(i64* align 16 %arrayidx0)
ret void
}
define void @test13(i1 %c, i32* align 32 %dst) #0 {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test13
; ATTRIBUTOR-SAME: (i1 [[C:%.*]], i32* nocapture nofree writeonly align 32 [[DST:%.*]])
; ATTRIBUTOR-NEXT: br i1 [[C]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; ATTRIBUTOR: truebb:
; ATTRIBUTOR-NEXT: br label [[END:%.*]]
; ATTRIBUTOR: falsebb:
; ATTRIBUTOR-NEXT: br label [[END]]
; ATTRIBUTOR: end:
; ATTRIBUTOR-NEXT: [[PTR:%.*]] = phi i32* [ [[DST]], [[TRUEBB]] ], [ null, [[FALSEBB]] ]
; ATTRIBUTOR-NEXT: store i32 0, i32* [[PTR]], align 32
; ATTRIBUTOR-NEXT: ret void
;
br i1 %c, label %truebb, label %falsebb
truebb:
br label %end
falsebb:
br label %end
end:
%ptr = phi i32* [ %dst, %truebb ], [ null, %falsebb ]
store i32 0, i32* %ptr
ret void
}
define void @test13-1(i1 %c, i32* align 32 %dst) {
; ATTRIBUTOR-LABEL: @test13-1(
; ATTRIBUTOR-NEXT: br i1 [[C:%.*]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; ATTRIBUTOR: truebb:
; ATTRIBUTOR-NEXT: br label [[END:%.*]]
; ATTRIBUTOR: falsebb:
; ATTRIBUTOR-NEXT: br label [[END]]
; ATTRIBUTOR: end:
; ATTRIBUTOR-NEXT: [[PTR:%.*]] = phi i32* [ [[DST:%.*]], [[TRUEBB]] ], [ inttoptr (i64 48 to i32*), [[FALSEBB]] ]
; ATTRIBUTOR-NEXT: store i32 0, i32* [[PTR]], align 16
; ATTRIBUTOR-NEXT: ret void
;
br i1 %c, label %truebb, label %falsebb
truebb:
br label %end
falsebb:
br label %end
end:
%ptr = phi i32* [ %dst, %truebb ], [ inttoptr (i64 48 to i32*), %falsebb ]
store i32 0, i32* %ptr
ret void
}
define void @test13-2(i1 %c, i32* align 32 %dst) {
; ATTRIBUTOR-LABEL: @test13-2(
; ATTRIBUTOR-NEXT: br i1 [[C:%.*]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; ATTRIBUTOR: truebb:
; ATTRIBUTOR-NEXT: br label [[END:%.*]]
; ATTRIBUTOR: falsebb:
; ATTRIBUTOR-NEXT: br label [[END]]
; ATTRIBUTOR: end:
; ATTRIBUTOR-NEXT: [[PTR:%.*]] = phi i32* [ [[DST:%.*]], [[TRUEBB]] ], [ inttoptr (i64 160 to i32*), [[FALSEBB]] ]
; ATTRIBUTOR-NEXT: store i32 0, i32* [[PTR]], align 32
; ATTRIBUTOR-NEXT: ret void
;
br i1 %c, label %truebb, label %falsebb
truebb:
br label %end
falsebb:
br label %end
end:
%ptr = phi i32* [ %dst, %truebb ], [ inttoptr (i64 160 to i32*), %falsebb ]
store i32 0, i32* %ptr
ret void
}
define void @test13-3(i1 %c, i32* align 32 %dst) {
; ATTRIBUTOR-LABEL: @test13-3(
; ATTRIBUTOR-NEXT: br i1 [[C:%.*]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; ATTRIBUTOR: truebb:
; ATTRIBUTOR-NEXT: br label [[END:%.*]]
; ATTRIBUTOR: falsebb:
; ATTRIBUTOR-NEXT: br label [[END]]
; ATTRIBUTOR: end:
; ATTRIBUTOR-NEXT: [[PTR:%.*]] = phi i32* [ [[DST:%.*]], [[TRUEBB]] ], [ inttoptr (i64 128 to i32*), [[FALSEBB]] ]
; ATTRIBUTOR-NEXT: store i32 0, i32* [[PTR]], align 32
; ATTRIBUTOR-NEXT: ret void
;
br i1 %c, label %truebb, label %falsebb
truebb:
br label %end
falsebb:
br label %end
end:
%ptr = phi i32* [ %dst, %truebb ], [ inttoptr (i64 128 to i32*), %falsebb ]
store i32 0, i32* %ptr
ret void
}
; Don't crash on ptr2int/int2ptr uses.
define i64 @ptr2int(i32* %p) {
%p2i = ptrtoint i32* %p to i64
ret i64 %p2i
}
define i64* @int2ptr(i64 %i) {
%i2p = inttoptr i64 %i to i64*
ret i64* %i2p
}
; Use the store alignment only for the pointer operand.
define void @aligned_store(i8* %Value, i8** %Ptr) {
; ATTRIBUTOR: define void @aligned_store(i8* nofree writeonly %Value, i8** nocapture nofree nonnull writeonly align 32 dereferenceable(8) %Ptr)
store i8* %Value, i8** %Ptr, align 32
ret void
}
; UTC_ARGS: --enable
declare i8* @some_func(i8*)
define void @align_call_op_not_store(i8* align 2048 %arg) {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@align_call_op_not_store
; ATTRIBUTOR-SAME: (i8* align 2048 [[ARG:%.*]])
; ATTRIBUTOR-NEXT: [[UNKNOWN:%.*]] = call i8* @some_func(i8* align 2048 [[ARG]])
; ATTRIBUTOR-NEXT: store i8 0, i8* [[UNKNOWN]]
; ATTRIBUTOR-NEXT: ret void
;
%unknown = call i8* @some_func(i8* %arg)
store i8 0, i8* %unknown
ret void
}
define void @align_store_after_bc(i32* align 2048 %arg) {
;
; ATTRIBUTOR-LABEL: define {{[^@]+}}@align_store_after_bc
; ATTRIBUTOR-SAME: (i32* nocapture nofree nonnull writeonly align 2048 dereferenceable(1) [[ARG:%.*]])
; ATTRIBUTOR-NEXT: [[BC:%.*]] = bitcast i32* [[ARG]] to i8*
; ATTRIBUTOR-NEXT: store i8 0, i8* [[BC]], align 2048
; ATTRIBUTOR-NEXT: ret void
;
%bc = bitcast i32* %arg to i8*
store i8 0, i8* %bc
ret void
}
; Make sure we do not annotate the callee of a must-tail call with an alignment
; we cannot also put on the caller.
@cnd = external global i1
define i32 @musttail_callee_1(i32* %p) {
%v = load i32, i32* %p, align 32
ret i32 %v
}
define i32 @musttail_caller_1(i32* %p) {
%c = load i1, i1* @cnd
br i1 %c, label %mt, label %exit
mt:
%v = musttail call i32 @musttail_callee_1(i32* %p)
ret i32 %v
exit:
ret i32 0
}
; UTC_ARGS: --disable
attributes #0 = { nounwind uwtable noinline }
attributes #1 = { uwtable noinline }
attributes #2 = { "null-pointer-is-valid"="true" }