mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-28 19:31:58 +00:00
3e77df419d
This commit isn't using the correct context, and is transfoming calls that are operands to loads rather than calls that are operands to an icmp feeding into an assume. I've replied on the original review thread with a very reduced test case and some thoughts on how to rework this. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@228677 91177308-0d34-0410-b5e6-96231b3b80d8
266 lines
5.6 KiB
LLVM
266 lines
5.6 KiB
LLVM
; RUN: opt < %s -instcombine -S | FileCheck %s
|
|
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
|
target triple = "x86_64-unknown-linux-gnu"
|
|
|
|
; Function Attrs: nounwind uwtable
|
|
define i32 @foo1(i32* %a) #0 {
|
|
entry:
|
|
%0 = load i32* %a, align 4
|
|
|
|
; Check that the alignment has been upgraded and that the assume has not
|
|
; been removed:
|
|
; CHECK-LABEL: @foo1
|
|
; CHECK-DAG: load i32* %a, align 32
|
|
; CHECK-DAG: call void @llvm.assume
|
|
; CHECK: ret i32
|
|
|
|
%ptrint = ptrtoint i32* %a to i64
|
|
%maskedptr = and i64 %ptrint, 31
|
|
%maskcond = icmp eq i64 %maskedptr, 0
|
|
tail call void @llvm.assume(i1 %maskcond)
|
|
|
|
ret i32 %0
|
|
}
|
|
|
|
; Function Attrs: nounwind uwtable
|
|
define i32 @foo2(i32* %a) #0 {
|
|
entry:
|
|
; Same check as in @foo1, but make sure it works if the assume is first too.
|
|
; CHECK-LABEL: @foo2
|
|
; CHECK-DAG: load i32* %a, align 32
|
|
; CHECK-DAG: call void @llvm.assume
|
|
; CHECK: ret i32
|
|
|
|
%ptrint = ptrtoint i32* %a to i64
|
|
%maskedptr = and i64 %ptrint, 31
|
|
%maskcond = icmp eq i64 %maskedptr, 0
|
|
tail call void @llvm.assume(i1 %maskcond)
|
|
|
|
%0 = load i32* %a, align 4
|
|
ret i32 %0
|
|
}
|
|
|
|
; Function Attrs: nounwind
|
|
declare void @llvm.assume(i1) #1
|
|
|
|
define i32 @simple(i32 %a) #1 {
|
|
entry:
|
|
|
|
; CHECK-LABEL: @simple
|
|
; CHECK: call void @llvm.assume
|
|
; CHECK: ret i32 4
|
|
|
|
%cmp = icmp eq i32 %a, 4
|
|
tail call void @llvm.assume(i1 %cmp)
|
|
ret i32 %a
|
|
}
|
|
|
|
; Function Attrs: nounwind uwtable
|
|
define i32 @can1(i1 %a, i1 %b, i1 %c) {
|
|
entry:
|
|
%and1 = and i1 %a, %b
|
|
%and = and i1 %and1, %c
|
|
tail call void @llvm.assume(i1 %and)
|
|
|
|
; CHECK-LABEL: @can1
|
|
; CHECK: call void @llvm.assume(i1 %a)
|
|
; CHECK: call void @llvm.assume(i1 %b)
|
|
; CHECK: call void @llvm.assume(i1 %c)
|
|
; CHECK: ret i32
|
|
|
|
ret i32 5
|
|
}
|
|
|
|
; Function Attrs: nounwind uwtable
|
|
define i32 @can2(i1 %a, i1 %b, i1 %c) {
|
|
entry:
|
|
%v = or i1 %a, %b
|
|
%w = xor i1 %v, 1
|
|
tail call void @llvm.assume(i1 %w)
|
|
|
|
; CHECK-LABEL: @can2
|
|
; CHECK: %[[V1:[^ ]+]] = xor i1 %a, true
|
|
; CHECK: call void @llvm.assume(i1 %[[V1]])
|
|
; CHECK: %[[V2:[^ ]+]] = xor i1 %b, true
|
|
; CHECK: call void @llvm.assume(i1 %[[V2]])
|
|
; CHECK: ret i32
|
|
|
|
ret i32 5
|
|
}
|
|
|
|
define i32 @bar1(i32 %a) #0 {
|
|
entry:
|
|
%and1 = and i32 %a, 3
|
|
|
|
; CHECK-LABEL: @bar1
|
|
; CHECK: call void @llvm.assume
|
|
; CHECK: ret i32 1
|
|
|
|
%and = and i32 %a, 7
|
|
%cmp = icmp eq i32 %and, 1
|
|
tail call void @llvm.assume(i1 %cmp)
|
|
|
|
ret i32 %and1
|
|
}
|
|
|
|
; Function Attrs: nounwind uwtable
|
|
define i32 @bar2(i32 %a) #0 {
|
|
entry:
|
|
; CHECK-LABEL: @bar2
|
|
; CHECK: call void @llvm.assume
|
|
; CHECK: ret i32 1
|
|
|
|
%and = and i32 %a, 7
|
|
%cmp = icmp eq i32 %and, 1
|
|
tail call void @llvm.assume(i1 %cmp)
|
|
|
|
%and1 = and i32 %a, 3
|
|
ret i32 %and1
|
|
}
|
|
|
|
; Function Attrs: nounwind uwtable
|
|
define i32 @bar3(i32 %a, i1 %x, i1 %y) #0 {
|
|
entry:
|
|
%and1 = and i32 %a, 3
|
|
|
|
; Don't be fooled by other assumes around.
|
|
; CHECK-LABEL: @bar3
|
|
; CHECK: call void @llvm.assume
|
|
; CHECK: ret i32 1
|
|
|
|
tail call void @llvm.assume(i1 %x)
|
|
|
|
%and = and i32 %a, 7
|
|
%cmp = icmp eq i32 %and, 1
|
|
tail call void @llvm.assume(i1 %cmp)
|
|
|
|
tail call void @llvm.assume(i1 %y)
|
|
|
|
ret i32 %and1
|
|
}
|
|
|
|
; Function Attrs: nounwind uwtable
|
|
define i32 @bar4(i32 %a, i32 %b) {
|
|
entry:
|
|
%and1 = and i32 %b, 3
|
|
|
|
; CHECK-LABEL: @bar4
|
|
; CHECK: call void @llvm.assume
|
|
; CHECK: call void @llvm.assume
|
|
; CHECK: ret i32 1
|
|
|
|
%and = and i32 %a, 7
|
|
%cmp = icmp eq i32 %and, 1
|
|
tail call void @llvm.assume(i1 %cmp)
|
|
|
|
%cmp2 = icmp eq i32 %a, %b
|
|
tail call void @llvm.assume(i1 %cmp2)
|
|
|
|
ret i32 %and1
|
|
}
|
|
|
|
define i32 @icmp1(i32 %a) #0 {
|
|
entry:
|
|
%cmp = icmp sgt i32 %a, 5
|
|
tail call void @llvm.assume(i1 %cmp)
|
|
%conv = zext i1 %cmp to i32
|
|
ret i32 %conv
|
|
|
|
; CHECK-LABEL: @icmp1
|
|
; CHECK: call void @llvm.assume
|
|
; CHECK: ret i32 1
|
|
|
|
}
|
|
|
|
; Function Attrs: nounwind uwtable
|
|
define i32 @icmp2(i32 %a) #0 {
|
|
entry:
|
|
%cmp = icmp sgt i32 %a, 5
|
|
tail call void @llvm.assume(i1 %cmp)
|
|
%0 = zext i1 %cmp to i32
|
|
%lnot.ext = xor i32 %0, 1
|
|
ret i32 %lnot.ext
|
|
|
|
; CHECK-LABEL: @icmp2
|
|
; CHECK: call void @llvm.assume
|
|
; CHECK: ret i32 0
|
|
}
|
|
|
|
declare void @escape(i32* %a)
|
|
|
|
; Do we canonicalize a nonnull assumption on a load into
|
|
; metadata form?
|
|
define i1 @nonnull1(i32** %a) {
|
|
entry:
|
|
%load = load i32** %a
|
|
%cmp = icmp ne i32* %load, null
|
|
tail call void @llvm.assume(i1 %cmp)
|
|
tail call void @escape(i32* %load)
|
|
%rval = icmp eq i32* %load, null
|
|
ret i1 %rval
|
|
|
|
; CHECK-LABEL: @nonnull1
|
|
; CHECK: !nonnull
|
|
; CHECK-NOT: call void @llvm.assume
|
|
; CHECK: ret i1 false
|
|
}
|
|
|
|
; Make sure the above canonicalization applies only
|
|
; to pointer types. Doing otherwise would be illegal.
|
|
define i1 @nonnull2(i32* %a) {
|
|
entry:
|
|
%load = load i32* %a
|
|
%cmp = icmp ne i32 %load, 0
|
|
tail call void @llvm.assume(i1 %cmp)
|
|
%rval = icmp eq i32 %load, 0
|
|
ret i1 %rval
|
|
|
|
; CHECK-LABEL: @nonnull2
|
|
; CHECK-NOT: !nonnull
|
|
; CHECK: call void @llvm.assume
|
|
}
|
|
|
|
; Make sure the above canonicalization does not trigger
|
|
; if the assume is control dependent on something else
|
|
define i1 @nonnull3(i32** %a, i1 %control) {
|
|
entry:
|
|
%load = load i32** %a
|
|
%cmp = icmp ne i32* %load, null
|
|
br i1 %control, label %taken, label %not_taken
|
|
taken:
|
|
tail call void @llvm.assume(i1 %cmp)
|
|
%rval = icmp eq i32* %load, null
|
|
ret i1 %rval
|
|
not_taken:
|
|
ret i1 true
|
|
|
|
; CHECK-LABEL: @nonnull3
|
|
; CHECK-NOT: !nonnull
|
|
; CHECK: call void @llvm.assume
|
|
}
|
|
|
|
; Make sure the above canonicalization does not trigger
|
|
; if the path from the load to the assume is potentially
|
|
; interrupted by an exception being thrown
|
|
define i1 @nonnull4(i32** %a) {
|
|
entry:
|
|
%load = load i32** %a
|
|
;; This call may throw!
|
|
tail call void @escape(i32* %load)
|
|
%cmp = icmp ne i32* %load, null
|
|
tail call void @llvm.assume(i1 %cmp)
|
|
%rval = icmp eq i32* %load, null
|
|
ret i1 %rval
|
|
|
|
; CHECK-LABEL: @nonnull4
|
|
; CHECK-NOT: !nonnull
|
|
; CHECK: call void @llvm.assume
|
|
}
|
|
|
|
|
|
|
|
|
|
attributes #0 = { nounwind uwtable }
|
|
attributes #1 = { nounwind }
|
|
|