You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.167
Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
parent
e19d552987
commit
b084638f15
File diff suppressed because it is too large
Load Diff
@ -1,82 +0,0 @@
|
||||
; RUN: opt -S -codegenprepare -mtriple=aarch64-linux %s | FileCheck -enable-var-scope %s
|
||||
|
||||
; Test for CodeGenPrepare::optimizeLoadExt(): simple case: two loads
|
||||
; feeding a phi that zext's each loaded value.
|
||||
define i32 @test_free_zext(i32* %ptr, i32* %ptr2, i32 %c) {
|
||||
; CHECK-LABEL: @test_free_zext(
|
||||
bb1:
|
||||
; CHECK: bb1:
|
||||
; CHECK: %[[T1:.*]] = load
|
||||
; CHECK: %[[A1:.*]] = and i32 %[[T1]], 65535
|
||||
%load1 = load i32, i32* %ptr, align 4
|
||||
%cmp = icmp ne i32 %c, 0
|
||||
br i1 %cmp, label %bb2, label %bb3
|
||||
bb2:
|
||||
; CHECK: bb2:
|
||||
; CHECK: %[[T2:.*]] = load
|
||||
; CHECK: %[[A2:.*]] = and i32 %[[T2]], 65535
|
||||
%load2 = load i32, i32* %ptr2, align 4
|
||||
br label %bb3
|
||||
bb3:
|
||||
; CHECK: bb3:
|
||||
; CHECK: phi i32 [ %[[A1]], %bb1 ], [ %[[A2]], %bb2 ]
|
||||
%phi = phi i32 [ %load1, %bb1 ], [ %load2, %bb2 ]
|
||||
%and = and i32 %phi, 65535
|
||||
ret i32 %and
|
||||
}
|
||||
|
||||
; Test for CodeGenPrepare::optimizeLoadExt(): exercise all opcode
|
||||
; cases of active bit calculation.
|
||||
define i32 @test_free_zext2(i32* %ptr, i16* %dst16, i32* %dst32, i32 %c) {
|
||||
; CHECK-LABEL: @test_free_zext2(
|
||||
bb1:
|
||||
; CHECK: bb1:
|
||||
; CHECK: %[[T1:.*]] = load
|
||||
; CHECK: %[[A1:.*]] = and i32 %[[T1]], 65535
|
||||
%load1 = load i32, i32* %ptr, align 4
|
||||
%cmp = icmp ne i32 %c, 0
|
||||
br i1 %cmp, label %bb2, label %bb4
|
||||
bb2:
|
||||
; CHECK: bb2:
|
||||
%trunc = trunc i32 %load1 to i16
|
||||
store i16 %trunc, i16* %dst16, align 2
|
||||
br i1 %cmp, label %bb3, label %bb4
|
||||
bb3:
|
||||
; CHECK: bb3:
|
||||
%shl = shl i32 %load1, 16
|
||||
store i32 %shl, i32* %dst32, align 4
|
||||
br label %bb4
|
||||
bb4:
|
||||
; CHECK: bb4:
|
||||
; CHECK-NOT: and
|
||||
; CHECK: ret i32 %[[A1]]
|
||||
%and = and i32 %load1, 65535
|
||||
ret i32 %and
|
||||
}
|
||||
|
||||
; Test for CodeGenPrepare::optimizeLoadExt(): check case of zext-able
|
||||
; load feeding a phi in the same block.
|
||||
define void @test_free_zext3(i32* %ptr, i32* %ptr2, i32* %dst, i64* %c) {
|
||||
; CHECK-LABEL: @test_free_zext3(
|
||||
bb1:
|
||||
; CHECK: bb1:
|
||||
; CHECK: %[[T1:.*]] = load
|
||||
; CHECK: %[[A1:.*]] = and i32 %[[T1]], 65535
|
||||
%load1 = load i32, i32* %ptr, align 4
|
||||
br label %loop
|
||||
loop:
|
||||
; CHECK: loop:
|
||||
; CHECK: phi i32 [ %[[A1]], %bb1 ], [ %[[A2:.*]], %loop ]
|
||||
%phi = phi i32 [ %load1, %bb1 ], [ %load2, %loop ]
|
||||
%and = and i32 %phi, 65535
|
||||
store i32 %and, i32* %dst, align 4
|
||||
%idx = load volatile i64, i64* %c, align 4
|
||||
%addr = getelementptr inbounds i32, i32* %ptr2, i64 %idx
|
||||
; CHECK: %[[T2:.*]] = load i32
|
||||
; CHECK: %[[A2]] = and i32 %[[T2]], 65535
|
||||
%load2 = load i32, i32* %addr, align 4
|
||||
%cmp = icmp ne i64 %idx, 0
|
||||
br i1 %cmp, label %loop, label %end
|
||||
end:
|
||||
ret void
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
if not 'AArch64' in config.root.targets:
|
||||
config.unsupported = True
|
||||
|
@ -1,36 +0,0 @@
|
||||
; RUN: opt -S -codegenprepare -mtriple=arm64-apple-ios7.0 %s | FileCheck %s
|
||||
|
||||
%foo = type { i8 }
|
||||
|
||||
define %foo @test_merge(i32 %in) {
|
||||
; CHECK-LABEL: @test_merge
|
||||
|
||||
; CodeGenPrepare was requesting the EVT for { i8 } to determine
|
||||
; whether the insertvalue user of the trunc was legal. This
|
||||
; asserted.
|
||||
|
||||
; CHECK: insertvalue %foo undef, i8 %byte, 0
|
||||
%lobit = lshr i32 %in, 31
|
||||
%byte = trunc i32 %lobit to i8
|
||||
%struct = insertvalue %foo undef, i8 %byte, 0
|
||||
ret %"foo" %struct
|
||||
}
|
||||
|
||||
define i64* @test_merge_PR21548(i32 %a, i64* %p1, i64* %p2, i64* %p3) {
|
||||
; CHECK-LABEL: @test_merge_PR21548
|
||||
%as = lshr i32 %a, 3
|
||||
%Tr = trunc i32 %as to i1
|
||||
br i1 %Tr, label %BB2, label %BB3
|
||||
|
||||
BB2:
|
||||
; Similarly to above:
|
||||
; CodeGenPrepare was requesting the EVT for i8* to determine
|
||||
; whether the select user of the trunc was legal. This asserted.
|
||||
|
||||
; CHECK: select i1 {{%.*}}, i64* %p1, i64* %p2
|
||||
%p = select i1 %Tr, i64* %p1, i64* %p2
|
||||
ret i64* %p
|
||||
|
||||
BB3:
|
||||
ret i64* %p3
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
;; AArch64 is arbitralily chosen as a 32/64-bit RISC representative to show the transform in all tests.
|
||||
|
||||
; RUN: opt < %s -codegenprepare -S -mtriple=aarch64-unknown-unknown | FileCheck %s --check-prefix=ARM64
|
||||
|
||||
; AArch64 widens to 32-bit.
|
||||
|
||||
define i32 @widen_switch_i16(i32 %a) {
|
||||
entry:
|
||||
%trunc = trunc i32 %a to i16
|
||||
switch i16 %trunc, label %sw.default [
|
||||
i16 1, label %sw.bb0
|
||||
i16 -1, label %sw.bb1
|
||||
]
|
||||
|
||||
sw.bb0:
|
||||
br label %return
|
||||
|
||||
sw.bb1:
|
||||
br label %return
|
||||
|
||||
sw.default:
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi i32 [ -1, %sw.default ], [ 0, %sw.bb0 ], [ 1, %sw.bb1 ]
|
||||
ret i32 %retval
|
||||
|
||||
; ARM64-LABEL: @widen_switch_i16(
|
||||
; ARM64: %0 = zext i16 %trunc to i32
|
||||
; ARM64-NEXT: switch i32 %0, label %sw.default [
|
||||
; ARM64-NEXT: i32 1, label %sw.bb0
|
||||
; ARM64-NEXT: i32 65535, label %sw.bb1
|
||||
}
|
||||
|
||||
; Widen to 32-bit from a smaller, non-native type.
|
||||
|
||||
define i32 @widen_switch_i17(i32 %a) {
|
||||
entry:
|
||||
%trunc = trunc i32 %a to i17
|
||||
switch i17 %trunc, label %sw.default [
|
||||
i17 10, label %sw.bb0
|
||||
i17 -1, label %sw.bb1
|
||||
]
|
||||
|
||||
sw.bb0:
|
||||
br label %return
|
||||
|
||||
sw.bb1:
|
||||
br label %return
|
||||
|
||||
sw.default:
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi i32 [ -1, %sw.default ], [ 0, %sw.bb0 ], [ 1, %sw.bb1 ]
|
||||
ret i32 %retval
|
||||
|
||||
; ARM64-LABEL: @widen_switch_i17(
|
||||
; ARM64: %0 = zext i17 %trunc to i32
|
||||
; ARM64-NEXT: switch i32 %0, label %sw.default [
|
||||
; ARM64-NEXT: i32 10, label %sw.bb0
|
||||
; ARM64-NEXT: i32 131071, label %sw.bb1
|
||||
}
|
||||
|
||||
; If the switch condition is a sign-extended function argument, then the
|
||||
; condition and cases should be sign-extended rather than zero-extended
|
||||
; because the sign-extension can be optimized away.
|
||||
|
||||
define i32 @widen_switch_i16_sext(i2 signext %a) {
|
||||
entry:
|
||||
switch i2 %a, label %sw.default [
|
||||
i2 1, label %sw.bb0
|
||||
i2 -1, label %sw.bb1
|
||||
]
|
||||
|
||||
sw.bb0:
|
||||
br label %return
|
||||
|
||||
sw.bb1:
|
||||
br label %return
|
||||
|
||||
sw.default:
|
||||
br label %return
|
||||
|
||||
return:
|
||||
%retval = phi i32 [ -1, %sw.default ], [ 0, %sw.bb0 ], [ 1, %sw.bb1 ]
|
||||
ret i32 %retval
|
||||
|
||||
; ARM64-LABEL: @widen_switch_i16_sext(
|
||||
; ARM64: %0 = sext i2 %a to i32
|
||||
; ARM64-NEXT: switch i32 %0, label %sw.default [
|
||||
; ARM64-NEXT: i32 1, label %sw.bb0
|
||||
; ARM64-NEXT: i32 -1, label %sw.bb1
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
if not 'AMDGPU' in config.root.targets:
|
||||
config.unsupported = True
|
||||
|
@ -1,49 +0,0 @@
|
||||
; RUN: opt -S -codegenprepare -mtriple=amdgcn-unknown-unknown < %s | FileCheck -check-prefix=ASC -check-prefix=COMMON %s
|
||||
|
||||
; COMMON-LABEL: @test_sink_ptrtoint_asc(
|
||||
; ASC: addrspacecast
|
||||
; ASC-NOT: ptrtoint
|
||||
; ASC-NOT: inttoptr
|
||||
|
||||
define amdgpu_kernel void @test_sink_ptrtoint_asc(float addrspace(1)* nocapture %arg, float addrspace(1)* nocapture readonly %arg1, float addrspace(3)* %arg2) #0 {
|
||||
bb:
|
||||
%tmp = getelementptr inbounds float, float addrspace(3)* %arg2, i32 16
|
||||
%tmp2 = tail call i32 @llvm.amdgcn.workitem.id.x() #1
|
||||
%tmp3 = sext i32 %tmp2 to i64
|
||||
%tmp4 = getelementptr inbounds float, float addrspace(1)* %arg1, i64 %tmp3
|
||||
%tmp5 = load float, float addrspace(1)* %tmp4, align 4
|
||||
%tmp6 = addrspacecast float addrspace(3)* %tmp to float addrspace(4)*
|
||||
%tmp7 = fcmp olt float %tmp5, 8.388608e+06
|
||||
br i1 %tmp7, label %bb8, label %bb14
|
||||
|
||||
bb8: ; preds = %bb
|
||||
%tmp9 = tail call float @llvm.fma.f32(float %tmp5, float 0x3FE45F3060000000, float 5.000000e-01) #1
|
||||
%tmp10 = fmul float %tmp9, 0x3E74442D00000000
|
||||
%tmp11 = fsub float -0.000000e+00, %tmp10
|
||||
%tmp12 = tail call float @llvm.fma.f32(float %tmp9, float 0x3E74442D00000000, float %tmp11) #1
|
||||
store float %tmp12, float addrspace(4)* %tmp6, align 4
|
||||
%tmp13 = fsub float -0.000000e+00, %tmp12
|
||||
br label %bb15
|
||||
|
||||
bb14: ; preds = %bb
|
||||
store float 2.000000e+00, float addrspace(4)* %tmp6, align 4
|
||||
br label %bb15
|
||||
|
||||
bb15: ; preds = %bb14, %bb8
|
||||
%tmp16 = phi float [ 0.000000e+00, %bb14 ], [ %tmp13, %bb8 ]
|
||||
%tmp17 = fsub float -0.000000e+00, %tmp16
|
||||
%tmp18 = tail call float @llvm.fma.f32(float 1.000000e+00, float 0x3FF0AAAAA0000000, float %tmp17) #1
|
||||
%tmp19 = fsub float 2.187500e-01, %tmp18
|
||||
%tmp20 = fsub float 7.187500e-01, %tmp19
|
||||
%tmp21 = fcmp ogt float %tmp5, 1.600000e+01
|
||||
%tmp22 = select i1 %tmp21, float 0x7FF8000000000000, float %tmp20
|
||||
%tmp23 = getelementptr inbounds float, float addrspace(1)* %arg, i64 %tmp3
|
||||
store float %tmp22, float addrspace(1)* %tmp23, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
declare float @llvm.fma.f32(float, float, float) #1
|
||||
declare i32 @llvm.amdgcn.workitem.id.x() #1
|
||||
|
||||
attributes #0 = { nounwind }
|
||||
attributes #1 = { nounwind readnone }
|
@ -1,121 +0,0 @@
|
||||
; RUN: opt -S -codegenprepare -mtriple=amdgcn--amdhsa < %s | FileCheck %s
|
||||
|
||||
; CHECK-LABEL: @no_sink_local_to_flat(
|
||||
; CHECK: addrspacecast
|
||||
; CHECK: br
|
||||
; CHECK-NOT: addrspacecast
|
||||
define i64 @no_sink_local_to_flat(i1 %pred, i64 addrspace(3)* %ptr) {
|
||||
%ptr_cast = addrspacecast i64 addrspace(3)* %ptr to i64 addrspace(4)*
|
||||
br i1 %pred, label %l1, label %l2
|
||||
|
||||
l1:
|
||||
%v1 = load i64, i64 addrspace(3)* %ptr
|
||||
ret i64 %v1
|
||||
|
||||
l2:
|
||||
%v2 = load i64, i64 addrspace(4)* %ptr_cast
|
||||
ret i64 %v2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @no_sink_private_to_flat(
|
||||
; CHECK: addrspacecast
|
||||
; CHECK: br
|
||||
; CHECK-NOT: addrspacecast
|
||||
define i64 @no_sink_private_to_flat(i1 %pred, i64* %ptr) {
|
||||
%ptr_cast = addrspacecast i64* %ptr to i64 addrspace(4)*
|
||||
br i1 %pred, label %l1, label %l2
|
||||
|
||||
l1:
|
||||
%v1 = load i64, i64* %ptr
|
||||
ret i64 %v1
|
||||
|
||||
l2:
|
||||
%v2 = load i64, i64 addrspace(4)* %ptr_cast
|
||||
ret i64 %v2
|
||||
}
|
||||
|
||||
|
||||
; CHECK-LABEL: @sink_global_to_flat(
|
||||
; CHECK-NOT: addrspacecast
|
||||
; CHECK: br
|
||||
; CHECK: addrspacecast
|
||||
define i64 @sink_global_to_flat(i1 %pred, i64 addrspace(1)* %ptr) {
|
||||
%ptr_cast = addrspacecast i64 addrspace(1)* %ptr to i64 addrspace(4)*
|
||||
br i1 %pred, label %l1, label %l2
|
||||
|
||||
l1:
|
||||
%v1 = load i64, i64 addrspace(1)* %ptr
|
||||
ret i64 %v1
|
||||
|
||||
l2:
|
||||
%v2 = load i64, i64 addrspace(4)* %ptr_cast
|
||||
ret i64 %v2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @sink_flat_to_global(
|
||||
; CHECK-NOT: addrspacecast
|
||||
; CHECK: br
|
||||
; CHECK: addrspacecast
|
||||
define i64 @sink_flat_to_global(i1 %pred, i64 addrspace(4)* %ptr) {
|
||||
%ptr_cast = addrspacecast i64 addrspace(4)* %ptr to i64 addrspace(1)*
|
||||
br i1 %pred, label %l1, label %l2
|
||||
|
||||
l1:
|
||||
%v1 = load i64, i64 addrspace(4)* %ptr
|
||||
ret i64 %v1
|
||||
|
||||
l2:
|
||||
%v2 = load i64, i64 addrspace(1)* %ptr_cast
|
||||
ret i64 %v2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @sink_flat_to_constant(
|
||||
; CHECK-NOT: addrspacecast
|
||||
; CHECK: br
|
||||
; CHECK: addrspacecast
|
||||
define i64 @sink_flat_to_constant(i1 %pred, i64 addrspace(4)* %ptr) {
|
||||
%ptr_cast = addrspacecast i64 addrspace(4)* %ptr to i64 addrspace(2)*
|
||||
br i1 %pred, label %l1, label %l2
|
||||
|
||||
l1:
|
||||
%v1 = load i64, i64 addrspace(4)* %ptr
|
||||
ret i64 %v1
|
||||
|
||||
l2:
|
||||
%v2 = load i64, i64 addrspace(2)* %ptr_cast
|
||||
ret i64 %v2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @sink_flat_to_local(
|
||||
; CHECK-NOT: addrspacecast
|
||||
; CHECK: br
|
||||
; CHECK: addrspacecast
|
||||
define i64 @sink_flat_to_local(i1 %pred, i64 addrspace(4)* %ptr) {
|
||||
%ptr_cast = addrspacecast i64 addrspace(4)* %ptr to i64 addrspace(3)*
|
||||
br i1 %pred, label %l1, label %l2
|
||||
|
||||
l1:
|
||||
%v1 = load i64, i64 addrspace(4)* %ptr
|
||||
ret i64 %v1
|
||||
|
||||
l2:
|
||||
%v2 = load i64, i64 addrspace(3)* %ptr_cast
|
||||
ret i64 %v2
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @sink_flat_to_private(
|
||||
; CHECK-NOT: addrspacecast
|
||||
; CHECK: br
|
||||
; CHECK: addrspacecast
|
||||
define i64 @sink_flat_to_private(i1 %pred, i64 addrspace(4)* %ptr) {
|
||||
%ptr_cast = addrspacecast i64 addrspace(4)* %ptr to i64*
|
||||
br i1 %pred, label %l1, label %l2
|
||||
|
||||
l1:
|
||||
%v1 = load i64, i64 addrspace(4)* %ptr
|
||||
ret i64 %v1
|
||||
|
||||
l2:
|
||||
%v2 = load i64, i64* %ptr_cast
|
||||
ret i64 %v2
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
; RUN: opt -S -loop-unroll -codegenprepare < %s | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
target triple = "armv7--linux-gnueabihf"
|
||||
|
||||
; CHECK-LABEL: @f
|
||||
define i32 @f(i32 %a) #0 {
|
||||
; CHECK: call i32 @llvm.bitreverse.i32
|
||||
entry:
|
||||
br label %for.body
|
||||
|
||||
for.cond.cleanup: ; preds = %for.body
|
||||
ret i32 %or
|
||||
|
||||
for.body: ; preds = %for.body, %entry
|
||||
%i.08 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
|
||||
%b.07 = phi i32 [ 0, %entry ], [ %or, %for.body ]
|
||||
%shr = lshr i32 %a, %i.08
|
||||
%and = and i32 %shr, 1
|
||||
%sub = sub nuw nsw i32 31, %i.08
|
||||
%shl = shl i32 %and, %sub
|
||||
%or = or i32 %shl, %b.07
|
||||
%inc = add nuw nsw i32 %i.08, 1
|
||||
%exitcond = icmp eq i32 %inc, 32
|
||||
br i1 %exitcond, label %for.cond.cleanup, label %for.body, !llvm.loop !3
|
||||
}
|
||||
|
||||
attributes #0 = { norecurse nounwind readnone "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a8" "target-features"="+dsp,+neon,+vfp3" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
|
||||
!llvm.module.flags = !{!0, !1}
|
||||
!llvm.ident = !{!2}
|
||||
|
||||
!0 = !{i32 1, !"wchar_size", i32 4}
|
||||
!1 = !{i32 1, !"min_enum_size", i32 4}
|
||||
!2 = !{!"clang version 3.8.0 (http://llvm.org/git/clang.git b7441a0f42c43a8eea9e3e706be187252db747fa)"}
|
||||
!3 = distinct !{!3, !4}
|
||||
!4 = !{!"llvm.loop.unroll.full"}
|
@ -1,3 +0,0 @@
|
||||
if not 'ARM' in config.root.targets:
|
||||
config.unsupported = True
|
||||
|
@ -1,420 +0,0 @@
|
||||
; RUN: opt -S -codegenprepare -mtriple=thumbv7m -disable-complex-addr-modes=false -addr-sink-new-select=true -addr-sink-new-phis=true < %s | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
|
||||
@gv1 = common global i32 0, align 4
|
||||
@gv2 = common global i32 0, align 4
|
||||
|
||||
; Phi selects between ptr and gep with ptr as base and constant offset
|
||||
define void @test_phi_onegep_offset(i32* %ptr, i32 %value) {
|
||||
; CHECK-LABEL: @test_phi_onegep_offset
|
||||
; CHECK-NOT: phi i32* [ %ptr, %entry ], [ %gep, %if.then ]
|
||||
; CHECK: phi i32 [ 4, %if.then ], [ 0, %entry ]
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then:
|
||||
%gep = getelementptr inbounds i32, i32* %ptr, i32 1
|
||||
br label %if.end
|
||||
|
||||
if.end:
|
||||
%phi = phi i32* [ %ptr, %entry ], [ %gep, %if.then ]
|
||||
store i32 %value, i32* %phi, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Phi selects between two geps with same base, different constant offsets
|
||||
define void @test_phi_twogep_offset(i32* %ptr, i32 %value) {
|
||||
; CHECK-LABEL: @test_phi_twogep_offset
|
||||
; CHECK-NOT: phi i32* [ %gep1, %if.then ], [ %gep2, %if.else ]
|
||||
; CHECK: phi i32 [ 8, %if.else ], [ 4, %if.then ]
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
br i1 %cmp, label %if.then, label %if.else
|
||||
|
||||
if.then:
|
||||
%gep1 = getelementptr inbounds i32, i32* %ptr, i32 1
|
||||
br label %if.end
|
||||
|
||||
if.else:
|
||||
%gep2 = getelementptr inbounds i32, i32* %ptr, i32 2
|
||||
br label %if.end
|
||||
|
||||
if.end:
|
||||
%phi = phi i32* [ %gep1, %if.then ], [ %gep2, %if.else ]
|
||||
store i32 %value, i32* %phi, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Phi selects between ptr and gep with ptr as base and nonconstant offset
|
||||
define void @test_phi_onegep_nonconst_offset(i32* %ptr, i32 %value, i32 %off) {
|
||||
; CHECK-LABEL: @test_phi_onegep_nonconst_offset
|
||||
; CHECK-NOT: phi i32* [ %ptr, %entry ], [ %gep, %if.then ]
|
||||
; CHECK: phi i32 [ %off, %if.then ], [ 0, %entry ]
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then:
|
||||
%gep = getelementptr inbounds i32, i32* %ptr, i32 %off
|
||||
br label %if.end
|
||||
|
||||
if.end:
|
||||
%phi = phi i32* [ %ptr, %entry ], [ %gep, %if.then ]
|
||||
store i32 %value, i32* %phi, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Phi selects between two geps with same base, different nonconstant offsets
|
||||
define void @test_phi_twogep_nonconst_offset(i32* %ptr, i32 %value, i32 %off1, i32 %off2) {
|
||||
; CHECK-LABEL: @test_phi_twogep_nonconst_offset
|
||||
; CHECK-NOT: phi i32* [ %gep1, %if.then ], [ %gep2, %if.else ]
|
||||
; CHECK: phi i32 [ %off2, %if.else ], [ %off1, %if.then ]
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
br i1 %cmp, label %if.then, label %if.else
|
||||
|
||||
if.then:
|
||||
%gep1 = getelementptr inbounds i32, i32* %ptr, i32 %off1
|
||||
br label %if.end
|
||||
|
||||
if.else:
|
||||
%gep2 = getelementptr inbounds i32, i32* %ptr, i32 %off2
|
||||
br label %if.end
|
||||
|
||||
if.end:
|
||||
%phi = phi i32* [ %gep1, %if.then ], [ %gep2, %if.else ]
|
||||
store i32 %value, i32* %phi, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Phi selects between two geps with different base, same constant offset
|
||||
define void @test_phi_twogep_base(i32* %ptr1, i32* %ptr2, i32 %value) {
|
||||
; CHECK-LABEL: @test_phi_twogep_base
|
||||
; CHECK-NOT: phi i32* [ %gep1, %if.then ], [ %gep2, %if.else ]
|
||||
; CHECK: phi i32* [ %ptr2, %if.else ], [ %ptr1, %if.then ]
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
br i1 %cmp, label %if.then, label %if.else
|
||||
|
||||
if.then:
|
||||
%gep1 = getelementptr inbounds i32, i32* %ptr1, i32 1
|
||||
br label %if.end
|
||||
|
||||
if.else:
|
||||
%gep2 = getelementptr inbounds i32, i32* %ptr2, i32 1
|
||||
br label %if.end
|
||||
|
||||
if.end:
|
||||
%phi = phi i32* [ %gep1, %if.then ], [ %gep2, %if.else ]
|
||||
store i32 %value, i32* %phi, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Phi selects between two geps with different base global variables, same constant offset
|
||||
define void @test_phi_twogep_base_gv(i32 %value) {
|
||||
; CHECK-LABEL: @test_phi_twogep_base_gv
|
||||
; CHECK-NOT: phi i32* [ %gep1, %if.then ], [ %gep2, %if.else ]
|
||||
; CHECK: phi i32* [ @gv2, %if.else ], [ @gv1, %if.then ]
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
br i1 %cmp, label %if.then, label %if.else
|
||||
|
||||
if.then:
|
||||
%gep1 = getelementptr inbounds i32, i32* @gv1, i32 1
|
||||
br label %if.end
|
||||
|
||||
if.else:
|
||||
%gep2 = getelementptr inbounds i32, i32* @gv2, i32 1
|
||||
br label %if.end
|
||||
|
||||
if.end:
|
||||
%phi = phi i32* [ %gep1, %if.then ], [ %gep2, %if.else ]
|
||||
store i32 %value, i32* %phi, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Phi selects between ptr and gep with ptr as base and constant offset
|
||||
define void @test_select_onegep_offset(i32* %ptr, i32 %value) {
|
||||
; CHECK-LABEL: @test_select_onegep_offset
|
||||
; CHECK-NOT: select i1 %cmp, i32* %ptr, i32* %gep
|
||||
; CHECK: select i1 %cmp, i32 0, i32 4
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
%gep = getelementptr inbounds i32, i32* %ptr, i32 1
|
||||
%select = select i1 %cmp, i32* %ptr, i32* %gep
|
||||
store i32 %value, i32* %select, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Select between two geps with same base, different constant offsets
|
||||
define void @test_select_twogep_offset(i32* %ptr, i32 %value) {
|
||||
; CHECK-LABEL: @test_select_twogep_offset
|
||||
; CHECK-NOT: select i1 %cmp, i32* %gep1, i32* %gep2
|
||||
; CHECK: select i1 %cmp, i32 4, i32 8
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
%gep1 = getelementptr inbounds i32, i32* %ptr, i32 1
|
||||
%gep2 = getelementptr inbounds i32, i32* %ptr, i32 2
|
||||
%select = select i1 %cmp, i32* %gep1, i32* %gep2
|
||||
store i32 %value, i32* %select, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Select between ptr and gep with ptr as base and nonconstant offset
|
||||
define void @test_select_onegep_nonconst_offset(i32* %ptr, i32 %value, i32 %off) {
|
||||
; CHECK-LABEL: @test_select_onegep_nonconst_offset
|
||||
; CHECK-NOT: select i1 %cmp, i32* %ptr, i32* %gep
|
||||
; CHECK: select i1 %cmp, i32 0, i32 %off
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
%gep = getelementptr inbounds i32, i32* %ptr, i32 %off
|
||||
%select = select i1 %cmp, i32* %ptr, i32* %gep
|
||||
store i32 %value, i32* %select, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Select between two geps with same base, different nonconstant offsets
|
||||
define void @test_select_twogep_nonconst_offset(i32* %ptr, i32 %value, i32 %off1, i32 %off2) {
|
||||
; CHECK-LABEL: @test_select_twogep_nonconst_offset
|
||||
; CHECK-NOT: select i1 %cmp, i32* %gep1, i32* %gep2
|
||||
; CHECK: select i1 %cmp, i32 %off1, i32 %off2
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
%gep1 = getelementptr inbounds i32, i32* %ptr, i32 %off1
|
||||
%gep2 = getelementptr inbounds i32, i32* %ptr, i32 %off2
|
||||
%select = select i1 %cmp, i32* %gep1, i32* %gep2
|
||||
store i32 %value, i32* %select, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Select between two geps with different base, same constant offset
|
||||
define void @test_select_twogep_base(i32* %ptr1, i32* %ptr2, i32 %value) {
|
||||
; CHECK-LABEL: @test_select_twogep_base
|
||||
; CHECK-NOT: select i1 %cmp, i32* %gep1, i32* %gep2
|
||||
; CHECK: select i1 %cmp, i32* %ptr1, i32* %ptr2
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
%gep1 = getelementptr inbounds i32, i32* %ptr1, i32 1
|
||||
%gep2 = getelementptr inbounds i32, i32* %ptr2, i32 1
|
||||
%select = select i1 %cmp, i32* %gep1, i32* %gep2
|
||||
store i32 %value, i32* %select, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Select between two geps with different base global variables, same constant offset
|
||||
define void @test_select_twogep_base_gv(i32 %value) {
|
||||
; CHECK-LABEL: @test_select_twogep_base_gv
|
||||
; CHECK-NOT: select i1 %cmp, i32* %gep1, i32* %gep2
|
||||
; CHECK: select i1 %cmp, i32* @gv1, i32* @gv2
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
%gep1 = getelementptr inbounds i32, i32* @gv1, i32 1
|
||||
%gep2 = getelementptr inbounds i32, i32* @gv2, i32 1
|
||||
%select = select i1 %cmp, i32* %gep1, i32* %gep2
|
||||
store i32 %value, i32* %select, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; If the phi is in a different block to where the gep will be, the phi goes where
|
||||
; the original phi was not where the gep is.
|
||||
; CHECK-LABEL: @test_phi_different_block
|
||||
; CHECK-LABEL: if1.end
|
||||
; CHECK-NOT: phi i32* [ %ptr, %entry ], [ %gep, %if1.then ]
|
||||
; CHECK: phi i32 [ 4, %if1.then ], [ 0, %entry ]
|
||||
define void @test_phi_different_block(i32* %ptr, i32 %value1, i32 %value2) {
|
||||
entry:
|
||||
%cmp1 = icmp sgt i32 %value1, 0
|
||||
br i1 %cmp1, label %if1.then, label %if1.end
|
||||
|
||||
if1.then:
|
||||
%gep = getelementptr inbounds i32, i32* %ptr, i32 1
|
||||
br label %if1.end
|
||||
|
||||
if1.end:
|
||||
%phi = phi i32* [ %ptr, %entry ], [ %gep, %if1.then ]
|
||||
%cmp2 = icmp sgt i32 %value2, 0
|
||||
br i1 %cmp2, label %if2.then, label %if2.end
|
||||
|
||||
if2.then:
|
||||
store i32 %value1, i32* %ptr, align 4
|
||||
br label %if2.end
|
||||
|
||||
if2.end:
|
||||
store i32 %value2, i32* %phi, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; A phi with three incoming values should be optimised
|
||||
; CHECK-LABEL: @test_phi_threegep
|
||||
; CHECK-NOT: phi i32* [ %gep1, %if.then ], [ %gep2, %if.else.then ], [ %gep3, %if.else.else ]
|
||||
; CHECK: phi i32 [ 12, %if.else.else ], [ 8, %if.else.then ], [ 4, %if.then ]
|
||||
define void @test_phi_threegep(i32* %ptr, i32 %value1, i32 %value2) {
|
||||
entry:
|
||||
%cmp1 = icmp sgt i32 %value1, 0
|
||||
br i1 %cmp1, label %if.then, label %if.else
|
||||
|
||||
if.then:
|
||||
%gep1 = getelementptr inbounds i32, i32* %ptr, i32 1
|
||||
br label %if.end
|
||||
|
||||
if.else:
|
||||
%cmp2 = icmp sgt i32 %value2, 0
|
||||
br i1 %cmp2, label %if.else.then, label %if.else.else
|
||||
|
||||
if.else.then:
|
||||
%gep2 = getelementptr inbounds i32, i32* %ptr, i32 2
|
||||
br label %if.end
|
||||
|
||||
if.else.else:
|
||||
%gep3 = getelementptr inbounds i32, i32* %ptr, i32 3
|
||||
br label %if.end
|
||||
|
||||
if.end:
|
||||
%phi = phi i32* [ %gep1, %if.then ], [ %gep2, %if.else.then ], [ %gep3, %if.else.else ]
|
||||
store i32 %value1, i32* %phi, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; A phi with two incoming values but three geps due to nesting should be
|
||||
; optimised
|
||||
; CHECK-LABEL: @test_phi_threegep_nested
|
||||
; CHECK: %[[PHI:[a-z0-9_]+]] = phi i32 [ 12, %if.else.else ], [ 8, %if.else.then ]
|
||||
; CHECK: phi i32 [ %[[PHI]], %if.else.end ], [ 4, %if.then ]
|
||||
define void @test_phi_threegep_nested(i32* %ptr, i32 %value1, i32 %value2) {
|
||||
entry:
|
||||
%cmp1 = icmp sgt i32 %value1, 0
|
||||
br i1 %cmp1, label %if.then, label %if.else
|
||||
|
||||
if.then:
|
||||
%gep1 = getelementptr inbounds i32, i32* %ptr, i32 1
|
||||
br label %if.end
|
||||
|
||||
if.else:
|
||||
%cmp2 = icmp sgt i32 %value2, 0
|
||||
br i1 %cmp2, label %if.else.then, label %if.else.else
|
||||
|
||||
if.else.then:
|
||||
%gep2 = getelementptr inbounds i32, i32* %ptr, i32 2
|
||||
br label %if.else.end
|
||||
|
||||
if.else.else:
|
||||
%gep3 = getelementptr inbounds i32, i32* %ptr, i32 3
|
||||
br label %if.else.end
|
||||
|
||||
if.else.end:
|
||||
%gep4 = phi i32* [ %gep2, %if.else.then ], [ %gep3, %if.else.else ]
|
||||
store i32 %value2, i32* %ptr, align 4
|
||||
br label %if.end
|
||||
|
||||
if.end:
|
||||
%phi = phi i32* [ %gep1, %if.then ], [ %gep4, %if.else.end ]
|
||||
store i32 %value1, i32* %phi, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; A nested select is expected to be optimised
|
||||
; CHECK-LABEL: @test_nested_select
|
||||
; CHECK: %[[SELECT:[a-z0-9_]+]] = select i1 %cmp2, i32 4, i32 8
|
||||
; CHECK: select i1 %cmp1, i32 4, i32 %[[SELECT]]
|
||||
define void @test_nested_select(i32* %ptr, i32 %value1, i32 %value2) {
|
||||
entry:
|
||||
%gep1 = getelementptr inbounds i32, i32* %ptr, i32 1
|
||||
%gep2 = getelementptr inbounds i32, i32* %ptr, i32 2
|
||||
%cmp1 = icmp sgt i32 %value1, 0
|
||||
%cmp2 = icmp sgt i32 %value2, 0
|
||||
%select1 = select i1 %cmp2, i32* %gep1, i32* %gep2
|
||||
%select2 = select i1 %cmp1, i32* %gep1, i32* %select1
|
||||
store i32 %value1, i32* %select2, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Scaling the offset by a different amount is expected not to be optimised
|
||||
; CHECK-LABEL: @test_select_different_scale
|
||||
; CHECK: select i1 %cmp, i32* %gep1, i32* %castgep
|
||||
define void @test_select_different_scale(i32* %ptr, i32 %value, i32 %off) {
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
%castptr = bitcast i32* %ptr to i16*
|
||||
%gep1 = getelementptr inbounds i32, i32* %ptr, i32 %off
|
||||
%gep2 = getelementptr inbounds i16, i16* %castptr, i32 %off
|
||||
%castgep = bitcast i16* %gep2 to i32*
|
||||
%select = select i1 %cmp, i32* %gep1, i32* %castgep
|
||||
store i32 %value, i32* %select, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; A select between two values is already the best we can do
|
||||
; CHECK-LABEL: @test_select_trivial
|
||||
; CHECK: select i1 %cmp, i32* %ptr1, i32* %ptr2
|
||||
define void @test_select_trivial(i32* %ptr1, i32* %ptr2, i32 %value) {
|
||||
entey:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
%select = select i1 %cmp, i32* %ptr1, i32* %ptr2
|
||||
store i32 %value, i32* %select, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; A select between two global variables is already the best we can do
|
||||
; CHECK-LABEL: @test_select_trivial_gv
|
||||
; CHECK: select i1 %cmp, i32* @gv1, i32* @gv2
|
||||
define void @test_select_trivial_gv(i32 %value) {
|
||||
entey:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
%select = select i1 %cmp, i32* @gv1, i32* @gv2
|
||||
store i32 %value, i32* %select, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Same for a select between a value and global variable
|
||||
; CHECK-LABEL: @test_select_trivial_ptr_gv
|
||||
; CHECK: select i1 %cmp, i32* %ptr, i32* @gv2
|
||||
define void @test_select_trivial_ptr_gv(i32* %ptr, i32 %value) {
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %value, 0
|
||||
%select = select i1 %cmp, i32* %ptr, i32* @gv2
|
||||
store i32 %value, i32* %select, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Same for a select between a global variable and null, though the test needs to
|
||||
; be a little more complicated to avoid dereferencing a potential null pointer
|
||||
; CHECK-LABEL: @test_select_trivial_gv_null
|
||||
; CHECK: select i1 %cmp.i, i32* @gv1, i32* null
|
||||
define void @test_select_trivial_gv_null(){
|
||||
entry:
|
||||
%gv1_val = load i32, i32* @gv1, align 4
|
||||
%cmp.i = icmp eq i32 %gv1_val, 0
|
||||
%spec.select.i = select i1 %cmp.i, i32* @gv1, i32* null
|
||||
br i1 %cmp.i, label %if.then, label %if.end
|
||||
|
||||
if.then:
|
||||
%val = load i32, i32* %spec.select.i, align 4
|
||||
%inc = add nsw i32 %val, 1
|
||||
store i32 %inc, i32* %spec.select.i, align 4
|
||||
br label %if.end
|
||||
|
||||
if.end:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Same for a select between a value and null
|
||||
; CHECK-LABEL: @test_select_trivial_ptr_null
|
||||
; CHECK: select i1 %cmp.i, i32* %ptr, i32* null
|
||||
define void @test_select_trivial_ptr_null(i32* %ptr){
|
||||
entry:
|
||||
%gv1_val = load i32, i32* %ptr, align 4
|
||||
%cmp.i = icmp eq i32 %gv1_val, 0
|
||||
%spec.select.i = select i1 %cmp.i, i32* %ptr, i32* null
|
||||
br i1 %cmp.i, label %if.then, label %if.end
|
||||
|
||||
if.then:
|
||||
%val = load i32, i32* %spec.select.i, align 4
|
||||
%inc = add nsw i32 %val, 1
|
||||
store i32 %inc, i32* %spec.select.i, align 4
|
||||
br label %if.end
|
||||
|
||||
if.end:
|
||||
ret void
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
if not 'Mips' in config.root.targets:
|
||||
config.unsupported = True
|
@ -1,64 +0,0 @@
|
||||
; RUN: opt -S -mtriple=mips64-mti-linux-gnu -codegenprepare < %s | FileCheck %s
|
||||
|
||||
; Test that if an address that was sunk from a dominating bb, used in a
|
||||
; select that is erased along with its' trivally dead operand, that the
|
||||
; sunken address is not reused if the same address computation occurs
|
||||
; after the select. Previously, this caused a ICE.
|
||||
|
||||
%struct.az = type { i32, %struct.bt* }
|
||||
%struct.bt = type { i32 }
|
||||
%struct.f = type { %struct.ax, %union.anon }
|
||||
%struct.ax = type { %struct.az* }
|
||||
%union.anon = type { %struct.bd }
|
||||
%struct.bd = type { i64 }
|
||||
%struct.bg = type { i32, i32 }
|
||||
%struct.ap = type { i32, i32 }
|
||||
|
||||
@ch = common global %struct.f zeroinitializer, align 8
|
||||
@j = common global %struct.az* null, align 8
|
||||
@ck = common global i32 0, align 4
|
||||
@h = common global i32 0, align 4
|
||||
@.str = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
|
||||
|
||||
define internal void @probestart() {
|
||||
entry:
|
||||
%0 = load %struct.az*, %struct.az** @j, align 8
|
||||
%bw = getelementptr inbounds %struct.az, %struct.az* %0, i64 0, i32 1
|
||||
%1 = load i32, i32* @h, align 4
|
||||
%cond = icmp eq i32 %1, 0
|
||||
br i1 %cond, label %sw.bb, label %cl
|
||||
|
||||
sw.bb: ; preds = %entry
|
||||
%call = tail call inreg { i64, i64 } @ba(i32* bitcast (%struct.f* @ch to i32*))
|
||||
br label %cl
|
||||
|
||||
cl: ; preds = %sw.bb, %entry
|
||||
%2 = load %struct.bt*, %struct.bt** %bw, align 8
|
||||
%tobool = icmp eq %struct.bt* %2, null
|
||||
%3 = load i32, i32* @ck, align 4
|
||||
%.sink5 = select i1 %tobool, i32* getelementptr (%struct.bg, %struct.bg* bitcast (%union.anon* getelementptr inbounds (%struct.f, %struct.f* @ch, i64 0, i32 1) to %struct.bg*), i64 0, i32 1), i32* getelementptr (%struct.ap, %struct.ap* bitcast (%union.anon* getelementptr inbounds (%struct.f, %struct.f* @ch, i64 0, i32 1) to %struct.ap*), i64 0, i32 1)
|
||||
store i32 %3, i32* %.sink5, align 4
|
||||
store i32 1, i32* bitcast (i64* getelementptr inbounds (%struct.f, %struct.f* @ch, i64 0, i32 1, i32 0, i32 0) to i32*), align 8
|
||||
%4 = load %struct.bt*, %struct.bt** %bw, align 8
|
||||
tail call void (i8*, ...) @a(i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str, i64 0, i64 0), %struct.bt* %4)
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @probestart()
|
||||
; CHECK-LABEL: entry:
|
||||
; CHECK: %[[I0:[0-9]+]] = load %struct.az*, %struct.az** @j
|
||||
; CHECK-LABEL: cl:
|
||||
|
||||
; CHECK-NOT: %{{[0-9]+}} = load %struct.bt*, %struct.bt** %bw
|
||||
; CHECK-NOT: %{{[.a-z0-9]}} = select
|
||||
; CHECK-NOT: %{{[0-9]+}} = load %struct.bt*, %struct.bt** %bw
|
||||
|
||||
; CHECK: %[[I1:[0-9]+]] = bitcast %struct.az* %[[I0]] to i8*
|
||||
; CHECK-NEXT: %sunkaddr = getelementptr i8, i8* %[[I1]], i64 8
|
||||
; CHECK-NEXT: %[[I2:[0-9]+]] = bitcast i8* %sunkaddr to %struct.bt**
|
||||
; CHECK-NEXT: %{{[0-9]+}} = load %struct.bt*, %struct.bt** %[[I2]]
|
||||
; CHECK-NEXT: tail call void (i8*, ...) @a
|
||||
|
||||
declare inreg { i64, i64 } @ba(i32*)
|
||||
|
||||
declare void @a(i8*, ...)
|
@ -1,35 +0,0 @@
|
||||
; RUN: opt -S -codegenprepare < %s | FileCheck %s
|
||||
|
||||
target datalayout = "e-i64:64-v16:16-v32:32-n16:32:64"
|
||||
target triple = "nvptx64-nvidia-cuda"
|
||||
|
||||
; When we bypass slow div with a constant numerator which fits into the bypass
|
||||
; width, we still emit the bypass code, but we don't 'or' the numerator with
|
||||
; the denominator.
|
||||
; CHECK-LABEL: @small_constant_numer
|
||||
define i64 @small_constant_numer(i64 %a) {
|
||||
; CHECK: [[AND:%[0-9]+]] = and i64 %a, -4294967296
|
||||
; CHECK: icmp eq i64 [[AND]], 0
|
||||
|
||||
; CHECK: [[TRUNC:%[0-9]+]] = trunc i64 %a to i32
|
||||
; CHECK: udiv i32 -1, [[TRUNC]]
|
||||
%d = sdiv i64 4294967295, %a ; 0xffff'ffff
|
||||
ret i64 %d
|
||||
}
|
||||
|
||||
; When we try to bypass slow div with a constant numerator which *doesn't* fit
|
||||
; into the bypass width, leave it as a plain 64-bit div with no bypass.
|
||||
; CHECK-LABEL: @large_constant_numer
|
||||
define i64 @large_constant_numer(i64 %a) {
|
||||
; CHECK-NOT: udiv i32
|
||||
%d = sdiv i64 4294967296, %a ; 0x1'0000'0000
|
||||
ret i64 %d
|
||||
}
|
||||
|
||||
; For good measure, try a value larger than 2^32.
|
||||
; CHECK-LABEL: @larger_constant_numer
|
||||
define i64 @larger_constant_numer(i64 %a) {
|
||||
; CHECK-NOT: udiv i32
|
||||
%d = sdiv i64 5000000000, %a
|
||||
ret i64 %d
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
; RUN: opt -S -codegenprepare < %s | FileCheck %s
|
||||
|
||||
target datalayout = "e-i64:64-v16:16-v32:32-n16:32:64"
|
||||
target triple = "nvptx64-nvidia-cuda"
|
||||
|
||||
; Check that the smaller-width division that the BypassSlowDivision pass
|
||||
; creates is not marked as "exact" (that is, it doesn't claim that the
|
||||
; numerator is a multiple of the denominator).
|
||||
;
|
||||
; CHECK-LABEL: @test
|
||||
define void @test(i64 %a, i64 %b, i64* %retptr) {
|
||||
; CHECK: udiv i32
|
||||
%d = sdiv i64 %a, %b
|
||||
store i64 %d, i64* %retptr
|
||||
ret void
|
||||
}
|
@ -1,216 +0,0 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -S -codegenprepare < %s | FileCheck %s
|
||||
|
||||
target datalayout = "e-i64:64-v16:16-v32:32-n16:32:64"
|
||||
target triple = "nvptx64-nvidia-cuda"
|
||||
|
||||
; No bypassing should be done in apparently unsuitable cases.
|
||||
define void @Test_no_bypassing(i32 %a, i64 %b, i64* %retptr) {
|
||||
; CHECK-LABEL: @Test_no_bypassing(
|
||||
; CHECK-NEXT: [[A_1:%.*]] = zext i32 [[A:%.*]] to i64
|
||||
; CHECK-NEXT: [[A_2:%.*]] = sub i64 -1, [[A_1]]
|
||||
; CHECK-NEXT: [[RES:%.*]] = srem i64 [[A_2]], [[B:%.*]]
|
||||
; CHECK-NEXT: store i64 [[RES]], i64* [[RETPTR:%.*]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%a.1 = zext i32 %a to i64
|
||||
; %a.2 is always negative so the division cannot be bypassed.
|
||||
%a.2 = sub i64 -1, %a.1
|
||||
%res = srem i64 %a.2, %b
|
||||
store i64 %res, i64* %retptr
|
||||
ret void
|
||||
}
|
||||
|
||||
; No OR instruction is needed if one of the operands (divisor) is known
|
||||
; to fit into 32 bits.
|
||||
define void @Test_check_one_operand(i64 %a, i32 %b, i64* %retptr) {
|
||||
; CHECK-LABEL: @Test_check_one_operand(
|
||||
; CHECK-NEXT: [[B_1:%.*]] = zext i32 [[B:%.*]] to i64
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[A:%.*]], -4294967296
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 0
|
||||
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP8:%.*]]
|
||||
; CHECK: [[TMP4:%.*]] = trunc i64 [[B_1]] to i32
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = trunc i64 [[A]] to i32
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = udiv i32 [[TMP5]], [[TMP4]]
|
||||
; CHECK-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i64
|
||||
; CHECK-NEXT: br label [[TMP10:%.*]]
|
||||
; CHECK: [[TMP9:%.*]] = sdiv i64 [[A]], [[B_1]]
|
||||
; CHECK-NEXT: br label [[TMP10]]
|
||||
; CHECK: [[TMP11:%.*]] = phi i64 [ [[TMP7]], [[TMP3]] ], [ [[TMP9]], [[TMP8]] ]
|
||||
; CHECK-NEXT: store i64 [[TMP11]], i64* [[RETPTR:%.*]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%b.1 = zext i32 %b to i64
|
||||
%res = sdiv i64 %a, %b.1
|
||||
store i64 %res, i64* %retptr
|
||||
ret void
|
||||
}
|
||||
|
||||
; If both operands are known to fit into 32 bits, then replace the division
|
||||
; in-place without CFG modification.
|
||||
define void @Test_check_none(i64 %a, i32 %b, i64* %retptr) {
|
||||
; CHECK-LABEL: @Test_check_none(
|
||||
; CHECK-NEXT: [[A_1:%.*]] = and i64 [[A:%.*]], 4294967295
|
||||
; CHECK-NEXT: [[B_1:%.*]] = zext i32 [[B:%.*]] to i64
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[A_1]] to i32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[B_1]] to i32
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = udiv i32 [[TMP1]], [[TMP2]]
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[TMP3]] to i64
|
||||
; CHECK-NEXT: store i64 [[TMP4]], i64* [[RETPTR:%.*]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%a.1 = and i64 %a, 4294967295
|
||||
%b.1 = zext i32 %b to i64
|
||||
%res = udiv i64 %a.1, %b.1
|
||||
store i64 %res, i64* %retptr
|
||||
ret void
|
||||
}
|
||||
|
||||
; In case of unsigned long division with a short dividend,
|
||||
; the long division is not needed any more.
|
||||
define void @Test_special_case(i32 %a, i64 %b, i64* %retptr) {
|
||||
; CHECK-LABEL: @Test_special_case(
|
||||
; CHECK-NEXT: [[A_1:%.*]] = zext i32 [[A:%.*]] to i64
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i64 [[A_1]], [[B:%.*]]
|
||||
; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP9:%.*]]
|
||||
; CHECK: [[TMP3:%.*]] = trunc i64 [[B]] to i32
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = trunc i64 [[A_1]] to i32
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = udiv i32 [[TMP4]], [[TMP3]]
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = urem i32 [[TMP4]], [[TMP3]]
|
||||
; CHECK-NEXT: [[TMP7:%.*]] = zext i32 [[TMP5]] to i64
|
||||
; CHECK-NEXT: [[TMP8:%.*]] = zext i32 [[TMP6]] to i64
|
||||
; CHECK-NEXT: br label [[TMP9]]
|
||||
; CHECK: [[TMP10:%.*]] = phi i64 [ [[TMP7]], [[TMP2]] ], [ 0, [[TMP0:%.*]] ]
|
||||
; CHECK-NEXT: [[TMP11:%.*]] = phi i64 [ [[TMP8]], [[TMP2]] ], [ [[A_1]], [[TMP0]] ]
|
||||
; CHECK-NEXT: [[RES:%.*]] = add i64 [[TMP10]], [[TMP11]]
|
||||
; CHECK-NEXT: store i64 [[RES]], i64* [[RETPTR:%.*]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%a.1 = zext i32 %a to i64
|
||||
%div = udiv i64 %a.1, %b
|
||||
%rem = urem i64 %a.1, %b
|
||||
%res = add i64 %div, %rem
|
||||
store i64 %res, i64* %retptr
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
; Do not bypass a division if one of the operands looks like a hash value.
|
||||
define void @Test_dont_bypass_xor(i64 %a, i64 %b, i64 %l, i64* %retptr) {
|
||||
; CHECK-LABEL: @Test_dont_bypass_xor(
|
||||
; CHECK-NEXT: [[C:%.*]] = xor i64 [[A:%.*]], [[B:%.*]]
|
||||
; CHECK-NEXT: [[RES:%.*]] = udiv i64 [[C]], [[L:%.*]]
|
||||
; CHECK-NEXT: store i64 [[RES]], i64* [[RETPTR:%.*]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%c = xor i64 %a, %b
|
||||
%res = udiv i64 %c, %l
|
||||
store i64 %res, i64* %retptr
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @Test_dont_bypass_phi_xor(i64 %a, i64 %b, i64 %l, i64* %retptr) {
|
||||
; CHECK-LABEL: @Test_dont_bypass_phi_xor(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[B:%.*]], 0
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[MERGE:%.*]], label [[XORPATH:%.*]]
|
||||
; CHECK: xorpath:
|
||||
; CHECK-NEXT: [[C:%.*]] = xor i64 [[A:%.*]], [[B]]
|
||||
; CHECK-NEXT: br label [[MERGE]]
|
||||
; CHECK: merge:
|
||||
; CHECK-NEXT: [[E:%.*]] = phi i64 [ undef, [[ENTRY:%.*]] ], [ [[C]], [[XORPATH]] ]
|
||||
; CHECK-NEXT: [[RES:%.*]] = sdiv i64 [[E]], [[L:%.*]]
|
||||
; CHECK-NEXT: store i64 [[RES]], i64* [[RETPTR:%.*]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
%cmp = icmp eq i64 %b, 0
|
||||
br i1 %cmp, label %merge, label %xorpath
|
||||
|
||||
xorpath:
|
||||
%c = xor i64 %a, %b
|
||||
br label %merge
|
||||
|
||||
merge:
|
||||
%e = phi i64 [ undef, %entry ], [ %c, %xorpath ]
|
||||
%res = sdiv i64 %e, %l
|
||||
store i64 %res, i64* %retptr
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @Test_dont_bypass_mul_long_const(i64 %a, i64 %l, i64* %retptr) {
|
||||
; CHECK-LABEL: @Test_dont_bypass_mul_long_const(
|
||||
; CHECK-NEXT: [[C:%.*]] = mul i64 [[A:%.*]], 5229553307
|
||||
; CHECK-NEXT: [[RES:%.*]] = urem i64 [[C]], [[L:%.*]]
|
||||
; CHECK-NEXT: store i64 [[RES]], i64* [[RETPTR:%.*]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%c = mul i64 %a, 5229553307 ; the constant doesn't fit 32 bits
|
||||
%res = urem i64 %c, %l
|
||||
store i64 %res, i64* %retptr
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @Test_bypass_phi_mul_const(i64 %a, i64 %b, i64* %retptr) {
|
||||
; CHECK-LABEL: @Test_bypass_phi_mul_const(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[A_MUL:%.*]] = mul nsw i64 [[A:%.*]], 34806414968801
|
||||
; CHECK-NEXT: [[P:%.*]] = icmp sgt i64 [[A]], [[B:%.*]]
|
||||
; CHECK-NEXT: br i1 [[P]], label [[BRANCH:%.*]], label [[MERGE:%.*]]
|
||||
; CHECK: branch:
|
||||
; CHECK-NEXT: br label [[MERGE]]
|
||||
; CHECK: merge:
|
||||
; CHECK-NEXT: [[LHS:%.*]] = phi i64 [ 42, [[BRANCH]] ], [ [[A_MUL]], [[ENTRY:%.*]] ]
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = or i64 [[LHS]], [[B]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], -4294967296
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 0
|
||||
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP8:%.*]]
|
||||
; CHECK: [[TMP4:%.*]] = trunc i64 [[B]] to i32
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = trunc i64 [[LHS]] to i32
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = udiv i32 [[TMP5]], [[TMP4]]
|
||||
; CHECK-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i64
|
||||
; CHECK-NEXT: br label [[TMP10:%.*]]
|
||||
; CHECK: [[TMP9:%.*]] = sdiv i64 [[LHS]], [[B]]
|
||||
; CHECK-NEXT: br label [[TMP10]]
|
||||
; CHECK: [[TMP11:%.*]] = phi i64 [ [[TMP7]], [[TMP3]] ], [ [[TMP9]], [[TMP8]] ]
|
||||
; CHECK-NEXT: store i64 [[TMP11]], i64* [[RETPTR:%.*]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
%a.mul = mul nsw i64 %a, 34806414968801
|
||||
%p = icmp sgt i64 %a, %b
|
||||
br i1 %p, label %branch, label %merge
|
||||
|
||||
branch:
|
||||
br label %merge
|
||||
|
||||
merge:
|
||||
%lhs = phi i64 [ 42, %branch ], [ %a.mul, %entry ]
|
||||
%res = sdiv i64 %lhs, %b
|
||||
store i64 %res, i64* %retptr
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @Test_bypass_mul_short_const(i64 %a, i64 %l, i64* %retptr) {
|
||||
; CHECK-LABEL: @Test_bypass_mul_short_const(
|
||||
; CHECK-NEXT: [[C:%.*]] = mul i64 [[A:%.*]], -42
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = or i64 [[C]], [[L:%.*]]
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], -4294967296
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], 0
|
||||
; CHECK-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP9:%.*]]
|
||||
; CHECK: [[TMP5:%.*]] = trunc i64 [[L]] to i32
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = trunc i64 [[C]] to i32
|
||||
; CHECK-NEXT: [[TMP7:%.*]] = urem i32 [[TMP6]], [[TMP5]]
|
||||
; CHECK-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
|
||||
; CHECK-NEXT: br label [[TMP11:%.*]]
|
||||
; CHECK: [[TMP10:%.*]] = urem i64 [[C]], [[L]]
|
||||
; CHECK-NEXT: br label [[TMP11]]
|
||||
; CHECK: [[TMP12:%.*]] = phi i64 [ [[TMP8]], [[TMP4]] ], [ [[TMP10]], [[TMP9]] ]
|
||||
; CHECK-NEXT: store i64 [[TMP12]], i64* [[RETPTR:%.*]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%c = mul i64 %a, -42
|
||||
%res = urem i64 %c, %l
|
||||
store i64 %res, i64* %retptr
|
||||
ret void
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
; RUN: opt -S -codegenprepare < %s | FileCheck %s
|
||||
|
||||
target datalayout = "e-i64:64-v16:16-v32:32-n16:32:64"
|
||||
target triple = "nvptx64-nvidia-cuda"
|
||||
|
||||
; We only use the div instruction -- the rem should be DCE'ed.
|
||||
; CHECK-LABEL: @div_only
|
||||
define void @div_only(i64 %a, i64 %b, i64* %retptr) {
|
||||
; CHECK: udiv i32
|
||||
; CHECK-NOT: urem
|
||||
; CHECK: sdiv i64
|
||||
; CHECK-NOT: rem
|
||||
%d = sdiv i64 %a, %b
|
||||
store i64 %d, i64* %retptr
|
||||
ret void
|
||||
}
|
||||
|
||||
; We only use the rem instruction -- the div should be DCE'ed.
|
||||
; CHECK-LABEL: @rem_only
|
||||
define void @rem_only(i64 %a, i64 %b, i64* %retptr) {
|
||||
; CHECK-NOT: div
|
||||
; CHECK: urem i32
|
||||
; CHECK-NOT: div
|
||||
; CHECK: rem i64
|
||||
; CHECK-NOT: div
|
||||
%d = srem i64 %a, %b
|
||||
store i64 %d, i64* %retptr
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @udiv_by_constant(
|
||||
define i64 @udiv_by_constant(i32 %a) {
|
||||
; CHECK-NEXT: [[A_ZEXT:%.*]] = zext i32 [[A:%.*]] to i64
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[A_ZEXT]] to i32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = udiv i32 [[TMP1]], 50
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = zext i32 [[TMP2]] to i64
|
||||
; CHECK-NEXT: ret i64 [[TMP3]]
|
||||
|
||||
%a.zext = zext i32 %a to i64
|
||||
%wide.div = udiv i64 %a.zext, 50
|
||||
ret i64 %wide.div
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @urem_by_constant(
|
||||
define i64 @urem_by_constant(i32 %a) {
|
||||
; CHECK-NEXT: [[A_ZEXT:%.*]] = zext i32 [[A:%.*]] to i64
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[A_ZEXT]] to i32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = urem i32 [[TMP1]], 50
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = zext i32 [[TMP2]] to i64
|
||||
; CHECK-NEXT: ret i64 [[TMP3]]
|
||||
|
||||
%a.zext = zext i32 %a to i64
|
||||
%wide.div = urem i64 %a.zext, 50
|
||||
ret i64 %wide.div
|
||||
}
|
||||
|
||||
; Negative test: instead of emitting a runtime check on %a, we prefer to let the
|
||||
; DAGCombiner transform this division by constant into a multiplication (with a
|
||||
; "magic constant").
|
||||
;
|
||||
; CHECK-LABEL: @udiv_by_constant_negative_0(
|
||||
define i64 @udiv_by_constant_negative_0(i64 %a) {
|
||||
; CHECK-NEXT: [[WIDE_DIV:%.*]] = udiv i64 [[A:%.*]], 50
|
||||
; CHECK-NEXT: ret i64 [[WIDE_DIV]]
|
||||
|
||||
%wide.div = udiv i64 %a, 50
|
||||
ret i64 %wide.div
|
||||
}
|
||||
|
||||
; Negative test: while we know the dividend is short, the divisor isn't. This
|
||||
; test is here for completeness, but instcombine will optimize this to return 0.
|
||||
;
|
||||
; CHECK-LABEL: @udiv_by_constant_negative_1(
|
||||
define i64 @udiv_by_constant_negative_1(i32 %a) {
|
||||
; CHECK-NEXT: [[A_ZEXT:%.*]] = zext i32 [[A:%.*]] to i64
|
||||
; CHECK-NEXT: [[WIDE_DIV:%.*]] = udiv i64 [[A_ZEXT]], 8589934592
|
||||
; CHECK-NEXT: ret i64 [[WIDE_DIV]]
|
||||
|
||||
%a.zext = zext i32 %a to i64
|
||||
%wide.div = udiv i64 %a.zext, 8589934592 ;; == 1 << 33
|
||||
ret i64 %wide.div
|
||||
}
|
||||
|
||||
; URem version of udiv_by_constant_negative_0
|
||||
;
|
||||
; CHECK-LABEL: @urem_by_constant_negative_0(
|
||||
define i64 @urem_by_constant_negative_0(i64 %a) {
|
||||
; CHECK-NEXT: [[WIDE_DIV:%.*]] = urem i64 [[A:%.*]], 50
|
||||
; CHECK-NEXT: ret i64 [[WIDE_DIV]]
|
||||
|
||||
%wide.div = urem i64 %a, 50
|
||||
ret i64 %wide.div
|
||||
}
|
||||
|
||||
; URem version of udiv_by_constant_negative_1
|
||||
;
|
||||
; CHECK-LABEL: @urem_by_constant_negative_1(
|
||||
define i64 @urem_by_constant_negative_1(i32 %a) {
|
||||
; CHECK-NEXT: [[A_ZEXT:%.*]] = zext i32 [[A:%.*]] to i64
|
||||
; CHECK-NEXT: [[WIDE_DIV:%.*]] = urem i64 [[A_ZEXT]], 8589934592
|
||||
; CHECK-NEXT: ret i64 [[WIDE_DIV]]
|
||||
|
||||
%a.zext = zext i32 %a to i64
|
||||
%wide.div = urem i64 %a.zext, 8589934592 ;; == 1 << 33
|
||||
ret i64 %wide.div
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
; RUN: opt -S -codegenprepare < %s | FileCheck %s
|
||||
|
||||
target datalayout = "e-i64:64-v16:16-v32:32-n16:32:64"
|
||||
target triple = "nvptx64-nvidia-cuda"
|
||||
|
||||
; CHECK-LABEL: @test
|
||||
define i64 @test(i1 %pred, i64* %ptr) {
|
||||
; CHECK: addrspacecast
|
||||
%ptr_as1 = addrspacecast i64* %ptr to i64 addrspace(1)*
|
||||
br i1 %pred, label %l1, label %l2
|
||||
l1:
|
||||
; CHECK-LABEL: l1:
|
||||
; CHECK-NOT: addrspacecast
|
||||
%v1 = load i64, i64* %ptr
|
||||
ret i64 %v1
|
||||
l2:
|
||||
; CHECK-LABEL: l2:
|
||||
; CHECK-NOT: addrspacecast
|
||||
%v2 = load i64, i64 addrspace(1)* %ptr_as1
|
||||
ret i64 %v2
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
if not 'NVPTX' in config.root.targets:
|
||||
config.unsupported = True
|
@ -1,117 +0,0 @@
|
||||
; RUN: opt -codegenprepare -S < %s | FileCheck %s
|
||||
|
||||
; The following target lines are needed for the test to exercise what it should.
|
||||
; Without these lines, CodeGenPrepare does not try to sink the bitcasts.
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc"
|
||||
|
||||
declare i32 @__CxxFrameHandler3(...)
|
||||
|
||||
declare void @f()
|
||||
|
||||
declare void @g(i8*)
|
||||
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #2
|
||||
|
||||
; CodeGenPrepare will want to sink these bitcasts, but it selects the catchpad
|
||||
; blocks as the place to which the bitcast should be sunk. Since catchpads
|
||||
; do not allow non-phi instructions before the terminator, this isn't possible.
|
||||
|
||||
; CHECK-LABEL: @test(
|
||||
define void @test(i32* %addr) personality i32 (...)* @__CxxFrameHandler3 {
|
||||
entry:
|
||||
%x = getelementptr i32, i32* %addr, i32 1
|
||||
%p1 = bitcast i32* %x to i8*
|
||||
invoke void @f()
|
||||
to label %invoke.cont unwind label %catch1
|
||||
|
||||
; CHECK: invoke.cont:
|
||||
; CHECK-NEXT: %y = getelementptr i32, i32* %addr, i32 2
|
||||
invoke.cont:
|
||||
%y = getelementptr i32, i32* %addr, i32 2
|
||||
%p2 = bitcast i32* %y to i8*
|
||||
invoke void @f()
|
||||
to label %done unwind label %catch2
|
||||
|
||||
done:
|
||||
ret void
|
||||
|
||||
catch1:
|
||||
%cs1 = catchswitch within none [label %handler1] unwind to caller
|
||||
|
||||
handler1:
|
||||
%cp1 = catchpad within %cs1 []
|
||||
br label %catch.shared
|
||||
; CHECK: handler1:
|
||||
; CHECK-NEXT: catchpad within %cs1
|
||||
; CHECK: %[[p1:[0-9]+]] = bitcast i32* %x to i8*
|
||||
|
||||
catch2:
|
||||
%cs2 = catchswitch within none [label %handler2] unwind to caller
|
||||
|
||||
handler2:
|
||||
%cp2 = catchpad within %cs2 []
|
||||
br label %catch.shared
|
||||
; CHECK: handler2:
|
||||
; CHECK: catchpad within %cs2
|
||||
; CHECK: %[[p2:[0-9]+]] = bitcast i32* %y to i8*
|
||||
|
||||
; CHECK: catch.shared:
|
||||
; CHECK-NEXT: %p = phi i8* [ %[[p1]], %handler1 ], [ %[[p2]], %handler2 ]
|
||||
catch.shared:
|
||||
%p = phi i8* [ %p1, %handler1 ], [ %p2, %handler2 ]
|
||||
call void @g(i8* %p)
|
||||
unreachable
|
||||
}
|
||||
|
||||
; CodeGenPrepare will want to hoist these llvm.dbg.value calls to the phi, but
|
||||
; there is no insertion point in a catchpad block.
|
||||
|
||||
; CHECK-LABEL: @test_dbg_value(
|
||||
define void @test_dbg_value() personality i32 (...)* @__CxxFrameHandler3 {
|
||||
entry:
|
||||
%a = alloca i8
|
||||
%b = alloca i8
|
||||
invoke void @f() to label %next unwind label %catch.dispatch
|
||||
next:
|
||||
invoke void @f() to label %ret unwind label %catch.dispatch
|
||||
ret:
|
||||
ret void
|
||||
|
||||
catch.dispatch:
|
||||
%p = phi i8* [%a, %entry], [%b, %next]
|
||||
%cs1 = catchswitch within none [label %catch] unwind to caller
|
||||
|
||||
catch:
|
||||
%cp1 = catchpad within %cs1 []
|
||||
tail call void @llvm.dbg.value(metadata i8* %p, i64 0, metadata !11, metadata !13), !dbg !14
|
||||
call void @g(i8* %p)
|
||||
catchret from %cp1 to label %ret
|
||||
|
||||
; CHECK: catch.dispatch:
|
||||
; CHECK-NEXT: phi i8
|
||||
; CHECK-NEXT: catchswitch
|
||||
; CHECK-NOT: llvm.dbg.value
|
||||
|
||||
; CHECK: catch:
|
||||
; CHECK-NEXT: catchpad
|
||||
; CHECK-NEXT: call void @llvm.dbg.value
|
||||
}
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!7, !8, !9}
|
||||
!llvm.ident = !{!10}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (trunk 254906) (llvm/trunk 254917)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: null)
|
||||
!1 = !DIFile(filename: "t.c", directory: "D:\5Csrc\5Cllvm\5Cbuild")
|
||||
!4 = distinct !DISubprogram(name: "test_dbg_value", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, variables: null)
|
||||
!5 = !DISubroutineType(types: !6)
|
||||
!6 = !{null}
|
||||
!7 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!8 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!9 = !{i32 1, !"PIC Level", i32 2}
|
||||
!10 = !{!"clang version 3.8.0 (trunk 254906) (llvm/trunk 254917)"}
|
||||
!11 = !DILocalVariable(name: "p", scope: !4, file: !1, line: 2, type: !12)
|
||||
!12 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char)
|
||||
!13 = !DIExpression(DW_OP_deref)
|
||||
!14 = !DILocation(line: 2, column: 8, scope: !4)
|
||||
!15 = !DILocation(line: 3, column: 1, scope: !4)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user