mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
289a0fd30f
When computing a range for a SCEVUnknown, today we use computeKnownBits for unsigned ranges, and computeNumSignBots for signed ranges. This means we miss opportunities to improve range results. One common missed pattern is that we have a signed range of a value which CKB can determine is positive, but CNSB doesn't convey that information. The current range includes the negative part, and is thus double the size. Per the removed comment, the original concern which delayed using both (after some code merging years back) was a compile time concern. CTMark results (provided by Nikita, thanks!) showed a geomean impact of about 0.1%. This doesn't seem large enough to avoid higher quality results. Differential Revision: https://reviews.llvm.org/D96534
615 lines
16 KiB
LLVM
615 lines
16 KiB
LLVM
; RUN: opt -S -analyze -stack-safety-local < %s -enable-new-pm=0 | FileCheck %s --check-prefixes=CHECK,LOCAL
|
|
; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL
|
|
; RUN: opt -S -analyze -stack-safety < %s -enable-new-pm=0 | FileCheck %s --check-prefixes=CHECK,GLOBAL
|
|
; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL
|
|
|
|
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
|
target triple = "x86_64-unknown-linux-gnu"
|
|
|
|
@sink = global i8* null, align 8
|
|
|
|
declare void @llvm.memset.p0i8.i32(i8* %dest, i8 %val, i32 %len, i1 %isvolatile)
|
|
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
|
|
declare void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
|
|
declare void @llvm.memset.p0i8.i64(i8* %dest, i8 %val, i64 %len, i1 %isvolatile)
|
|
|
|
; Address leaked.
|
|
define void @LeakAddress() {
|
|
; CHECK-LABEL: @LeakAddress dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[4]: full-set{{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, align 4
|
|
%x1 = bitcast i32* %x to i8*
|
|
store i8* %x1, i8** @sink, align 8
|
|
ret void
|
|
}
|
|
|
|
define void @StoreInBounds() {
|
|
; CHECK-LABEL: @StoreInBounds dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[4]: [0,1){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, align 4
|
|
%x1 = bitcast i32* %x to i8*
|
|
store i8 0, i8* %x1, align 1
|
|
ret void
|
|
}
|
|
|
|
define void @StoreInBounds2() {
|
|
; CHECK-LABEL: @StoreInBounds2 dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[4]: [0,4){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, align 4
|
|
store i32 0, i32* %x, align 4
|
|
ret void
|
|
}
|
|
|
|
define void @StoreInBounds3() {
|
|
; CHECK-LABEL: @StoreInBounds3 dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[4]: [2,3){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, align 4
|
|
%x1 = bitcast i32* %x to i8*
|
|
%x2 = getelementptr i8, i8* %x1, i64 2
|
|
store i8 0, i8* %x2, align 1
|
|
ret void
|
|
}
|
|
|
|
; FIXME: ScalarEvolution does not look through ptrtoint/inttoptr.
|
|
define void @StoreInBounds4() {
|
|
; CHECK-LABEL: @StoreInBounds4 dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[4]: [-9223372036854775808,9223372036854775807){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, align 4
|
|
%x1 = ptrtoint i32* %x to i64
|
|
%x2 = add i64 %x1, 2
|
|
%x3 = inttoptr i64 %x2 to i8*
|
|
store i8 0, i8* %x3, align 1
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @WriteMinMax(i8* %p) {
|
|
; CHECK-LABEL: @WriteMinMax{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: p[]: full-set
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%p1 = getelementptr i8, i8* %p, i64 9223372036854775805
|
|
store i8 0, i8* %p1, align 1
|
|
%p2 = getelementptr i8, i8* %p, i64 -9223372036854775805
|
|
store i8 0, i8* %p2, align 1
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @WriteMax(i8* %p) {
|
|
; CHECK-LABEL: @WriteMax{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: p[]: [-9223372036854775807,9223372036854775806)
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
call void @llvm.memset.p0i8.i64(i8* %p, i8 1, i64 9223372036854775806, i1 0)
|
|
%p2 = getelementptr i8, i8* %p, i64 -9223372036854775807
|
|
call void @llvm.memset.p0i8.i64(i8* %p2, i8 1, i64 9223372036854775806, i1 0)
|
|
ret void
|
|
}
|
|
|
|
define void @StoreOutOfBounds() {
|
|
; CHECK-LABEL: @StoreOutOfBounds dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[4]: [2,6){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, align 4
|
|
%x1 = bitcast i32* %x to i8*
|
|
%x2 = getelementptr i8, i8* %x1, i64 2
|
|
%x3 = bitcast i8* %x2 to i32*
|
|
store i32 0, i32* %x3, align 1
|
|
ret void
|
|
}
|
|
|
|
; There is no difference in load vs store handling.
|
|
define void @LoadInBounds() {
|
|
; CHECK-LABEL: @LoadInBounds dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[4]: [0,1){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, align 4
|
|
%x1 = bitcast i32* %x to i8*
|
|
%v = load i8, i8* %x1, align 1
|
|
ret void
|
|
}
|
|
|
|
define void @LoadOutOfBounds() {
|
|
; CHECK-LABEL: @LoadOutOfBounds dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[4]: [2,6){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, align 4
|
|
%x1 = bitcast i32* %x to i8*
|
|
%x2 = getelementptr i8, i8* %x1, i64 2
|
|
%x3 = bitcast i8* %x2 to i32*
|
|
%v = load i32, i32* %x3, align 1
|
|
ret void
|
|
}
|
|
|
|
; Leak through ret.
|
|
define i8* @Ret() {
|
|
; CHECK-LABEL: @Ret dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[4]: full-set{{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, align 4
|
|
%x1 = bitcast i32* %x to i8*
|
|
%x2 = getelementptr i8, i8* %x1, i64 2
|
|
ret i8* %x2
|
|
}
|
|
|
|
declare void @Foo(i16* %p)
|
|
|
|
define void @DirectCall() {
|
|
; CHECK-LABEL: @DirectCall dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; LOCAL-NEXT: x[8]: empty-set, @Foo(arg0, [2,3)){{$}}
|
|
; GLOBAL-NEXT: x[8]: full-set, @Foo(arg0, [2,3)){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i64, align 4
|
|
%x1 = bitcast i64* %x to i16*
|
|
%x2 = getelementptr i16, i16* %x1, i64 1
|
|
call void @Foo(i16* %x2);
|
|
ret void
|
|
}
|
|
|
|
; Indirect calls can not be analyzed (yet).
|
|
; FIXME: %p[]: full-set looks invalid
|
|
define void @IndirectCall(void (i8*)* %p) {
|
|
; CHECK-LABEL: @IndirectCall dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: p[]: full-set{{$}}
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[4]: full-set{{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, align 4
|
|
%x1 = bitcast i32* %x to i8*
|
|
call void %p(i8* %x1);
|
|
ret void
|
|
}
|
|
|
|
define void @NonConstantOffset(i1 zeroext %z) {
|
|
; CHECK-LABEL: @NonConstantOffset dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; FIXME: SCEV can't look through selects.
|
|
; CHECK-NEXT: x[4]: [0,4){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, align 4
|
|
%x1 = bitcast i32* %x to i8*
|
|
%idx = select i1 %z, i64 1, i64 2
|
|
%x2 = getelementptr i8, i8* %x1, i64 %idx
|
|
store i8 0, i8* %x2, align 1
|
|
ret void
|
|
}
|
|
|
|
define void @NegativeOffset() {
|
|
; CHECK-LABEL: @NegativeOffset dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[40]: [-1600000000000,-1599999999996){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, i32 10, align 4
|
|
%x2 = getelementptr i32, i32* %x, i64 -400000000000
|
|
store i32 0, i32* %x2, align 1
|
|
ret void
|
|
}
|
|
|
|
define void @PossiblyNegativeOffset(i16 %z) {
|
|
; CHECK-LABEL: @PossiblyNegativeOffset dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[40]: [-131072,131072){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, i32 10, align 4
|
|
%x2 = getelementptr i32, i32* %x, i16 %z
|
|
store i32 0, i32* %x2, align 1
|
|
ret void
|
|
}
|
|
|
|
define void @NonConstantOffsetOOB(i1 zeroext %z) {
|
|
; CHECK-LABEL: @NonConstantOffsetOOB dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[4]: [0,6){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, align 4
|
|
%x1 = bitcast i32* %x to i8*
|
|
%idx = select i1 %z, i64 1, i64 4
|
|
%x2 = getelementptr i8, i8* %x1, i64 %idx
|
|
store i8 0, i8* %x2, align 1
|
|
ret void
|
|
}
|
|
|
|
define void @ArrayAlloca() {
|
|
; CHECK-LABEL: @ArrayAlloca dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[40]: [36,40){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, i32 10, align 4
|
|
%x1 = bitcast i32* %x to i8*
|
|
%x2 = getelementptr i8, i8* %x1, i64 36
|
|
%x3 = bitcast i8* %x2 to i32*
|
|
store i32 0, i32* %x3, align 1
|
|
ret void
|
|
}
|
|
|
|
define void @ArrayAllocaOOB() {
|
|
; CHECK-LABEL: @ArrayAllocaOOB dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[40]: [37,41){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, i32 10, align 4
|
|
%x1 = bitcast i32* %x to i8*
|
|
%x2 = getelementptr i8, i8* %x1, i64 37
|
|
%x3 = bitcast i8* %x2 to i32*
|
|
store i32 0, i32* %x3, align 1
|
|
ret void
|
|
}
|
|
|
|
define void @DynamicAllocaUnused(i64 %size) {
|
|
; CHECK-LABEL: @DynamicAllocaUnused dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[0]: empty-set{{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, i64 %size, align 16
|
|
ret void
|
|
}
|
|
|
|
; Dynamic alloca with unknown size.
|
|
define void @DynamicAlloca(i64 %size) {
|
|
; CHECK-LABEL: @DynamicAlloca dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[0]: [0,4){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i32, i64 %size, align 16
|
|
store i32 0, i32* %x, align 1
|
|
ret void
|
|
}
|
|
|
|
; Dynamic alloca with limited size.
|
|
; FIXME: could be proved safe. Implement.
|
|
define void @DynamicAllocaFiniteSizeRange(i1 zeroext %z) {
|
|
; CHECK-LABEL: @DynamicAllocaFiniteSizeRange dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[0]: [0,4){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%size = select i1 %z, i64 3, i64 5
|
|
%x = alloca i32, i64 %size, align 16
|
|
store i32 0, i32* %x, align 1
|
|
ret void
|
|
}
|
|
|
|
define signext i8 @SimpleLoop() {
|
|
; CHECK-LABEL: @SimpleLoop dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[10]: [0,10){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca [10 x i8], align 1
|
|
%0 = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 0
|
|
%lftr.limit = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 10
|
|
br label %for.body
|
|
|
|
for.body:
|
|
%sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ]
|
|
%p.09 = phi i8* [ %0, %entry ], [ %incdec.ptr, %for.body ]
|
|
%incdec.ptr = getelementptr inbounds i8, i8* %p.09, i64 1
|
|
%1 = load volatile i8, i8* %p.09, align 1
|
|
%add = add i8 %1, %sum.010
|
|
%exitcond = icmp eq i8* %incdec.ptr, %lftr.limit
|
|
br i1 %exitcond, label %for.cond.cleanup, label %for.body
|
|
|
|
for.cond.cleanup:
|
|
ret i8 %add
|
|
}
|
|
|
|
; OOB in a loop.
|
|
define signext i8 @SimpleLoopOOB() {
|
|
; CHECK-LABEL: @SimpleLoopOOB dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[10]: [0,11){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca [10 x i8], align 1
|
|
%0 = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 0
|
|
; 11 iterations
|
|
%lftr.limit = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 11
|
|
br label %for.body
|
|
|
|
for.body:
|
|
%sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ]
|
|
%p.09 = phi i8* [ %0, %entry ], [ %incdec.ptr, %for.body ]
|
|
%incdec.ptr = getelementptr inbounds i8, i8* %p.09, i64 1
|
|
%1 = load volatile i8, i8* %p.09, align 1
|
|
%add = add i8 %1, %sum.010
|
|
%exitcond = icmp eq i8* %incdec.ptr, %lftr.limit
|
|
br i1 %exitcond, label %for.cond.cleanup, label %for.body
|
|
|
|
for.cond.cleanup:
|
|
ret i8 %add
|
|
}
|
|
|
|
define dso_local void @SizeCheck(i32 %sz) {
|
|
; CHECK-LABEL: @SizeCheck{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x1[128]: [0,4294967295){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x1 = alloca [128 x i8], align 16
|
|
%x1.sub = getelementptr inbounds [128 x i8], [128 x i8]* %x1, i64 0, i64 0
|
|
%cmp = icmp slt i32 %sz, 129
|
|
br i1 %cmp, label %if.then, label %if.end
|
|
|
|
if.then:
|
|
call void @llvm.memset.p0i8.i32(i8* nonnull align 16 %x1.sub, i8 0, i32 %sz, i1 false)
|
|
br label %if.end
|
|
|
|
if.end:
|
|
ret void
|
|
}
|
|
|
|
; FIXME: scalable allocas are considered to be of size zero, and scalable accesses to be full-range.
|
|
; This effectively disables safety analysis for scalable allocations.
|
|
define void @Scalable(<vscale x 4 x i32>* %p, <vscale x 4 x i32>* %unused, <vscale x 4 x i32> %v) {
|
|
; CHECK-LABEL: @Scalable dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: p[]: full-set
|
|
; CHECK-NEXT: unused[]: empty-set
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[0]: [0,1){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca <vscale x 4 x i32>, align 4
|
|
%x1 = bitcast <vscale x 4 x i32>* %x to i8*
|
|
store i8 0, i8* %x1, align 1
|
|
store <vscale x 4 x i32> %v, <vscale x 4 x i32>* %p, align 4
|
|
ret void
|
|
}
|
|
|
|
%zerosize_type = type {}
|
|
|
|
define void @ZeroSize(%zerosize_type *%p) {
|
|
; CHECK-LABEL: @ZeroSize dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: p[]: empty-set
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[0]: empty-set
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca %zerosize_type, align 4
|
|
store %zerosize_type undef, %zerosize_type* %x, align 4
|
|
store %zerosize_type undef, %zerosize_type* undef, align 4
|
|
%val = load %zerosize_type, %zerosize_type* %p, align 4
|
|
ret void
|
|
}
|
|
|
|
define void @OperandBundle() {
|
|
; CHECK-LABEL: @OperandBundle dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: a[4]: full-set
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%a = alloca i32, align 4
|
|
call void @LeakAddress() ["unknown"(i32* %a)]
|
|
ret void
|
|
}
|
|
|
|
define void @ByVal(i16* byval(i16) %p) {
|
|
; CHECK-LABEL: @ByVal dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
ret void
|
|
}
|
|
|
|
define void @TestByVal() {
|
|
; CHECK-LABEL: @TestByVal dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[2]: [0,2)
|
|
; CHECK-NEXT: y[8]: [0,2)
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i16, align 4
|
|
call void @ByVal(i16* byval(i16) %x)
|
|
|
|
%y = alloca i64, align 4
|
|
%y1 = bitcast i64* %y to i16*
|
|
call void @ByVal(i16* byval(i16) %y1)
|
|
|
|
ret void
|
|
}
|
|
|
|
declare void @ByValArray([100000 x i64]* byval([100000 x i64]) %p)
|
|
|
|
define void @TestByValArray() {
|
|
; CHECK-LABEL: @TestByValArray dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: z[800000]: [500000,1300000)
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%z = alloca [100000 x i64], align 4
|
|
%z1 = bitcast [100000 x i64]* %z to i8*
|
|
%z2 = getelementptr i8, i8* %z1, i64 500000
|
|
%z3 = bitcast i8* %z2 to [100000 x i64]*
|
|
call void @ByValArray([100000 x i64]* byval([100000 x i64]) %z3)
|
|
ret void
|
|
}
|
|
|
|
define dso_local i8 @LoadMinInt64(i8* %p) {
|
|
; CHECK-LABEL: @LoadMinInt64{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: p[]: [-9223372036854775808,-9223372036854775807){{$}}
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-EMPTY:
|
|
%p2 = getelementptr i8, i8* %p, i64 -9223372036854775808
|
|
%v = load i8, i8* %p2, align 1
|
|
ret i8 %v
|
|
}
|
|
|
|
define void @Overflow() {
|
|
; CHECK-LABEL: @Overflow dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; LOCAL-NEXT: x[1]: empty-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
|
|
; GLOBAL-NEXT: x[1]: full-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i8, align 4
|
|
%x2 = getelementptr i8, i8* %x, i64 -9223372036854775808
|
|
%v = call i8 @LoadMinInt64(i8* %x2)
|
|
ret void
|
|
}
|
|
|
|
define void @DeadBlock(i64* %p) {
|
|
; CHECK-LABEL: @DeadBlock dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: p[]: empty-set{{$}}
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK-NEXT: x[1]: empty-set{{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i8, align 4
|
|
br label %end
|
|
|
|
dead:
|
|
store i8 5, i8* %x
|
|
store i64 -5, i64* %p
|
|
br label %end
|
|
|
|
end:
|
|
ret void
|
|
}
|
|
|
|
define void @LifeNotStarted() {
|
|
; CHECK-LABEL: @LifeNotStarted dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK: x[1]: full-set{{$}}
|
|
; CHECK: y[1]: full-set{{$}}
|
|
; CHECK: z[1]: full-set{{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i8, align 4
|
|
%y = alloca i8, align 4
|
|
%z = alloca i8, align 4
|
|
|
|
store i8 5, i8* %x
|
|
%n = load i8, i8* %y
|
|
call void @llvm.memset.p0i8.i32(i8* nonnull %z, i8 0, i32 1, i1 false)
|
|
|
|
call void @llvm.lifetime.start.p0i8(i64 1, i8* %x)
|
|
call void @llvm.lifetime.start.p0i8(i64 1, i8* %y)
|
|
call void @llvm.lifetime.start.p0i8(i64 1, i8* %z)
|
|
|
|
ret void
|
|
}
|
|
|
|
define void @LifeOK() {
|
|
; CHECK-LABEL: @LifeOK dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK: x[1]: [0,1){{$}}
|
|
; CHECK: y[1]: [0,1){{$}}
|
|
; CHECK: z[1]: [0,1){{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i8, align 4
|
|
%y = alloca i8, align 4
|
|
%z = alloca i8, align 4
|
|
|
|
call void @llvm.lifetime.start.p0i8(i64 1, i8* %x)
|
|
call void @llvm.lifetime.start.p0i8(i64 1, i8* %y)
|
|
call void @llvm.lifetime.start.p0i8(i64 1, i8* %z)
|
|
|
|
store i8 5, i8* %x
|
|
%n = load i8, i8* %y
|
|
call void @llvm.memset.p0i8.i32(i8* nonnull %z, i8 0, i32 1, i1 false)
|
|
|
|
ret void
|
|
}
|
|
|
|
define void @LifeEnded() {
|
|
; CHECK-LABEL: @LifeEnded dso_preemptable{{$}}
|
|
; CHECK-NEXT: args uses:
|
|
; CHECK-NEXT: allocas uses:
|
|
; CHECK: x[1]: full-set{{$}}
|
|
; CHECK: y[1]: full-set{{$}}
|
|
; CHECK: z[1]: full-set{{$}}
|
|
; CHECK-EMPTY:
|
|
entry:
|
|
%x = alloca i8, align 4
|
|
%y = alloca i8, align 4
|
|
%z = alloca i8, align 4
|
|
|
|
call void @llvm.lifetime.start.p0i8(i64 1, i8* %x)
|
|
call void @llvm.lifetime.start.p0i8(i64 1, i8* %y)
|
|
call void @llvm.lifetime.start.p0i8(i64 1, i8* %z)
|
|
|
|
call void @llvm.lifetime.end.p0i8(i64 1, i8* %x)
|
|
call void @llvm.lifetime.end.p0i8(i64 1, i8* %y)
|
|
call void @llvm.lifetime.end.p0i8(i64 1, i8* %z)
|
|
|
|
store i8 5, i8* %x
|
|
%n = load i8, i8* %y
|
|
call void @llvm.memset.p0i8.i32(i8* nonnull %z, i8 0, i32 1, i1 false)
|
|
|
|
ret void
|
|
}
|
|
|
|
declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
|
|
declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
|