mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
d6d187a5b7
The current pattern matching for zext results in the following code snippet being produced, w1 = w0 r1 <<= 32 r1 >>= 32 Because BPF implementations require zero extension on 32bit loads this both adds a few extra unneeded instructions but also makes it a bit harder for the verifier to track the r1 register bounds. For example in this verifier trace we see at the end of the snippet R2 offset is unknown. However, if we track this correctly we see w1 should have the same bounds as r8. R8 smax is less than U32 max value so a zero extend load should keep the same value. Adding a max value of 800 (R8=inv(id=0,smax_value=800)) to an off=0, as seen in R7 should create a max offset of 800. However at the end of the snippet we note the R2 max offset is 0xffffFFFF. R0=inv(id=0,smax_value=800) R1_w=inv(id=0,umax_value=2147483647,var_off=(0x0; 0x7fffffff)) R6=ctx(id=0,off=0,imm=0) R7=map_value(id=0,off=0,ks=4,vs=1600,imm=0) R8_w=inv(id=0,smax_value=800,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R9=inv800 R10=fp0 fp-8=mmmm???? 58: (1c) w9 -= w8 59: (bc) w1 = w8 60: (67) r1 <<= 32 61: (77) r1 >>= 32 62: (bf) r2 = r7 63: (0f) r2 += r1 64: (bf) r1 = r6 65: (bc) w3 = w9 66: (b7) r4 = 0 67: (85) call bpf_get_stack#67 R0=inv(id=0,smax_value=800) R1_w=ctx(id=0,off=0,imm=0) R2_w=map_value(id=0,off=0,ks=4,vs=1600,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R3_w=inv(id=0,umax_value=800,var_off=(0x0; 0x3ff)) R4_w=inv0 R6=ctx(id=0,off=0,imm=0) R7=map_value(id=0,off=0,ks=4,vs=1600,imm=0) R8_w=inv(id=0,smax_value=800,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R9_w=inv(id=0,umax_value=800,var_off=(0x0; 0x3ff)) R10=fp0 fp-8=mmmm???? After this patch R1 bounds are not smashed by the <<=32 >>=32 shift and we get correct bounds on R2 umax_value=800. Further it reduces 3 insns to 1. Signed-off-by: John Fastabend <john.fastabend@gmail.com> Differential Revision: https://reviews.llvm.org/D73985
127 lines
3.3 KiB
LLVM
127 lines
3.3 KiB
LLVM
; RUN: llc -O2 -march=bpfel -mcpu=v2 -mattr=+alu32 < %s | FileCheck %s
|
|
;
|
|
; long long select_u(unsigned a, unsigned b, long long c, long long d)
|
|
; {
|
|
; if (a > b)
|
|
; return c;
|
|
; else
|
|
; return d;
|
|
; }
|
|
;
|
|
; long long select_u_2(unsigned a, unsigned long long b, long long c, long long d)
|
|
; {
|
|
; if (a > b)
|
|
; return c;
|
|
; else
|
|
; return d;
|
|
; }
|
|
;
|
|
; long long select_s(signed a, signed b, long long c, long long d)
|
|
; {
|
|
; if (a > b)
|
|
; return c;
|
|
; else
|
|
; return d;
|
|
; }
|
|
;
|
|
; long long bar ();
|
|
;
|
|
; int foo (int b, int c)
|
|
; {
|
|
; unsigned int i32_val = (unsigned int) bar();
|
|
;
|
|
; if (i32_val < 10)
|
|
; return b;
|
|
; else
|
|
; return c;
|
|
; }
|
|
;
|
|
; int *inc_p (int *p, unsigned a)
|
|
; {
|
|
; return p + a;
|
|
; }
|
|
|
|
; Function Attrs: norecurse nounwind readnone
|
|
define dso_local i64 @select_u(i32 %a, i32 %b, i64 %c, i64 %d) local_unnamed_addr #0 {
|
|
; CHECK-LABEL: select_u:
|
|
entry:
|
|
%cmp = icmp ugt i32 %a, %b
|
|
%c.d = select i1 %cmp, i64 %c, i64 %d
|
|
; CHECK: r{{[0-9]+}} = w{{[0-9]+}}
|
|
; CHECK-NOT: r{{[0-9]+}} <<= 32
|
|
; CHECK-NOT: r{{[0-9]+}} >>= 32
|
|
; CHECK: if r{{[0-9]+}} {{<|>}} r{{[0-9]+}} goto
|
|
ret i64 %c.d
|
|
}
|
|
|
|
; Function Attrs: norecurse nounwind readnone
|
|
define dso_local i64 @select_u_2(i32 %a, i64 %b, i64 %c, i64 %d) local_unnamed_addr #0 {
|
|
; CHECK-LABEL: select_u_2:
|
|
entry:
|
|
%conv = zext i32 %a to i64
|
|
; CHECK: r{{[0-9]+}} = w{{[0-9]+}}
|
|
; CHECK-NOT: r{{[0-9]+}} <<= 32
|
|
; CHECK-NOT: r{{[0-9]+}} >>= 32
|
|
%cmp = icmp ugt i64 %conv, %b
|
|
%c.d = select i1 %cmp, i64 %c, i64 %d
|
|
ret i64 %c.d
|
|
}
|
|
|
|
; Function Attrs: norecurse nounwind readnone
|
|
define dso_local i64 @select_s(i32 %a, i32 %b, i64 %c, i64 %d) local_unnamed_addr #0 {
|
|
; CHECK-LABEL: select_s:
|
|
entry:
|
|
%cmp = icmp sgt i32 %a, %b
|
|
%c.d = select i1 %cmp, i64 %c, i64 %d
|
|
; CHECK: r{{[0-9]+}} <<= 32
|
|
; CHECK-NEXT: r{{[0-9]+}} s>>= 32
|
|
; CHECK: if r{{[0-9]+}} s{{<|>}} r{{[0-9]+}} goto
|
|
ret i64 %c.d
|
|
}
|
|
|
|
; Function Attrs: nounwind
|
|
define dso_local i32 @foo(i32 %b, i32 %c) local_unnamed_addr #0 {
|
|
; CHECK-LABEL: foo:
|
|
entry:
|
|
%call = tail call i64 bitcast (i64 (...)* @bar to i64 ()*)() #2
|
|
%conv = trunc i64 %call to i32
|
|
%cmp = icmp ult i32 %conv, 10
|
|
; %call comes from function call returning i64 so the high bits will need
|
|
; to be cleared.
|
|
; CHECK: r{{[0-9]+}} = w{{[0-9]+}}
|
|
; CHECK-NOT: r{{[0-9]+}} <<= 32
|
|
; CHECK-NOT: r{{[0-9]+}} >>= 32
|
|
%b.c = select i1 %cmp, i32 %b, i32 %c
|
|
; CHECK: if r{{[0-9]+}} {{<|>}} {{[0-9]+}} goto
|
|
ret i32 %b.c
|
|
}
|
|
|
|
declare dso_local i64 @bar(...) local_unnamed_addr #1
|
|
|
|
; Function Attrs: norecurse nounwind readnone
|
|
define dso_local i32* @inc_p(i32* readnone %p, i32 %a) local_unnamed_addr #0 {
|
|
; CHECK-LABEL: inc_p:
|
|
entry:
|
|
%idx.ext = zext i32 %a to i64
|
|
; CHECK: r{{[0-9]+}} = w{{[0-9]+}}
|
|
; CHECK-NOT: r{{[0-9]+}} <<= 32
|
|
; CHECK-NOT: r{{[0-9]+}} >>= 32
|
|
%add.ptr = getelementptr inbounds i32, i32* %p, i64 %idx.ext
|
|
ret i32* %add.ptr
|
|
}
|
|
|
|
define dso_local i32 @test() local_unnamed_addr {
|
|
; CHECK-LABEL: test:
|
|
entry:
|
|
%call = tail call i32 bitcast (i32 (...)* @helper to i32 ()*)()
|
|
%cmp = icmp sgt i32 %call, 6
|
|
; The shifts can't be optimized out because %call comes from function call
|
|
; return i32 so the high bits might be invalid.
|
|
; CHECK: r{{[0-9]+}} <<= 32
|
|
; CHECK-NEXT: r{{[0-9]+}} s>>= 32
|
|
%cond = zext i1 %cmp to i32
|
|
; CHECK: if r{{[0-9]+}} s{{<|>}} {{[0-9]+}} goto
|
|
ret i32 %cond
|
|
}
|
|
declare dso_local i32 @helper(...) local_unnamed_addr
|