Skip to content

Commit 7aec58a

Browse files
[ConstantTime][RISCV] Add comprehensive tests for ct.select
Add comprehensive test suite for RISC-V fallback implementation: - Edge cases (zero conditions, large integers, sign extension) - Pattern matching (nested selects, chains) - Vector support with RVV extensions - Side effects and memory operations The basic fallback test is in the core infrastructure PR.
1 parent 6ac8221 commit 7aec58a

File tree

4 files changed

+1577
-0
lines changed

4 files changed

+1577
-0
lines changed
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc < %s -mtriple=riscv64 -O3 | FileCheck %s --check-prefix=RV64
3+
; RUN: llc < %s -mtriple=riscv32 -O3 | FileCheck %s --check-prefix=RV32
4+
5+
; Test with small integer types
6+
define i1 @test_ctselect_i1(i1 %cond, i1 %a, i1 %b) {
7+
; RV64-LABEL: test_ctselect_i1:
8+
; RV64: # %bb.0:
9+
; RV64-NEXT: and a1, a0, a1
10+
; RV64-NEXT: xori a0, a0, 1
11+
; RV64-NEXT: and a0, a0, a2
12+
; RV64-NEXT: or a0, a1, a0
13+
; RV64-NEXT: ret
14+
;
15+
; RV32-LABEL: test_ctselect_i1:
16+
; RV32: # %bb.0:
17+
; RV32-NEXT: and a1, a0, a1
18+
; RV32-NEXT: xori a0, a0, 1
19+
; RV32-NEXT: and a0, a0, a2
20+
; RV32-NEXT: or a0, a1, a0
21+
; RV32-NEXT: ret
22+
%result = call i1 @llvm.ct.select.i1(i1 %cond, i1 %a, i1 %b)
23+
ret i1 %result
24+
}
25+
26+
; Test with extremal values
27+
define i32 @test_ctselect_extremal_values(i1 %cond) {
28+
; RV64-LABEL: test_ctselect_extremal_values:
29+
; RV64: # %bb.0:
30+
; RV64-NEXT: andi a0, a0, 1
31+
; RV64-NEXT: lui a1, 524288
32+
; RV64-NEXT: subw a0, a1, a0
33+
; RV64-NEXT: ret
34+
;
35+
; RV32-LABEL: test_ctselect_extremal_values:
36+
; RV32: # %bb.0:
37+
; RV32-NEXT: andi a0, a0, 1
38+
; RV32-NEXT: lui a1, 524288
39+
; RV32-NEXT: addi a2, a0, -1
40+
; RV32-NEXT: neg a0, a0
41+
; RV32-NEXT: and a1, a2, a1
42+
; RV32-NEXT: slli a0, a0, 1
43+
; RV32-NEXT: srli a0, a0, 1
44+
; RV32-NEXT: or a0, a0, a1
45+
; RV32-NEXT: ret
46+
%result = call i32 @llvm.ct.select.i32(i1 %cond, i32 2147483647, i32 -2147483648)
47+
ret i32 %result
48+
}
49+
50+
; Test with null pointers
51+
define ptr @test_ctselect_null_ptr(i1 %cond, ptr %ptr) {
52+
; RV64-LABEL: test_ctselect_null_ptr:
53+
; RV64: # %bb.0:
54+
; RV64-NEXT: slli a0, a0, 63
55+
; RV64-NEXT: srai a0, a0, 63
56+
; RV64-NEXT: and a0, a0, a1
57+
; RV64-NEXT: ret
58+
;
59+
; RV32-LABEL: test_ctselect_null_ptr:
60+
; RV32: # %bb.0:
61+
; RV32-NEXT: slli a0, a0, 31
62+
; RV32-NEXT: srai a0, a0, 31
63+
; RV32-NEXT: and a0, a0, a1
64+
; RV32-NEXT: ret
65+
%result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %ptr, ptr null)
66+
ret ptr %result
67+
}
68+
69+
; Test with function pointers
70+
define ptr @test_ctselect_function_ptr(i1 %cond, ptr %func1, ptr %func2) {
71+
; RV64-LABEL: test_ctselect_function_ptr:
72+
; RV64: # %bb.0:
73+
; RV64-NEXT: andi a0, a0, 1
74+
; RV64-NEXT: neg a3, a0
75+
; RV64-NEXT: addi a0, a0, -1
76+
; RV64-NEXT: and a1, a3, a1
77+
; RV64-NEXT: and a0, a0, a2
78+
; RV64-NEXT: or a0, a1, a0
79+
; RV64-NEXT: ret
80+
;
81+
; RV32-LABEL: test_ctselect_function_ptr:
82+
; RV32: # %bb.0:
83+
; RV32-NEXT: andi a0, a0, 1
84+
; RV32-NEXT: neg a3, a0
85+
; RV32-NEXT: addi a0, a0, -1
86+
; RV32-NEXT: and a1, a3, a1
87+
; RV32-NEXT: and a0, a0, a2
88+
; RV32-NEXT: or a0, a1, a0
89+
; RV32-NEXT: ret
90+
%result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %func1, ptr %func2)
91+
ret ptr %result
92+
}
93+
94+
; Test with condition from icmp on pointers
95+
define ptr @test_ctselect_ptr_cmp(ptr %p1, ptr %p2, ptr %a, ptr %b) {
96+
; RV64-LABEL: test_ctselect_ptr_cmp:
97+
; RV64: # %bb.0:
98+
; RV64-NEXT: xor a0, a0, a1
99+
; RV64-NEXT: snez a0, a0
100+
; RV64-NEXT: addi a0, a0, -1
101+
; RV64-NEXT: and a2, a0, a2
102+
; RV64-NEXT: not a0, a0
103+
; RV64-NEXT: and a0, a0, a3
104+
; RV64-NEXT: or a0, a2, a0
105+
; RV64-NEXT: ret
106+
;
107+
; RV32-LABEL: test_ctselect_ptr_cmp:
108+
; RV32: # %bb.0:
109+
; RV32-NEXT: xor a0, a0, a1
110+
; RV32-NEXT: snez a0, a0
111+
; RV32-NEXT: addi a0, a0, -1
112+
; RV32-NEXT: and a2, a0, a2
113+
; RV32-NEXT: not a0, a0
114+
; RV32-NEXT: and a0, a0, a3
115+
; RV32-NEXT: or a0, a2, a0
116+
; RV32-NEXT: ret
117+
%cmp = icmp eq ptr %p1, %p2
118+
%result = call ptr @llvm.ct.select.p0(i1 %cmp, ptr %a, ptr %b)
119+
ret ptr %result
120+
}
121+
122+
; Test with struct pointer types
123+
%struct.pair = type { i32, i32 }
124+
125+
define ptr @test_ctselect_struct_ptr(i1 %cond, ptr %a, ptr %b) {
126+
; RV64-LABEL: test_ctselect_struct_ptr:
127+
; RV64: # %bb.0:
128+
; RV64-NEXT: andi a0, a0, 1
129+
; RV64-NEXT: neg a3, a0
130+
; RV64-NEXT: addi a0, a0, -1
131+
; RV64-NEXT: and a1, a3, a1
132+
; RV64-NEXT: and a0, a0, a2
133+
; RV64-NEXT: or a0, a1, a0
134+
; RV64-NEXT: ret
135+
;
136+
; RV32-LABEL: test_ctselect_struct_ptr:
137+
; RV32: # %bb.0:
138+
; RV32-NEXT: andi a0, a0, 1
139+
; RV32-NEXT: neg a3, a0
140+
; RV32-NEXT: addi a0, a0, -1
141+
; RV32-NEXT: and a1, a3, a1
142+
; RV32-NEXT: and a0, a0, a2
143+
; RV32-NEXT: or a0, a1, a0
144+
; RV32-NEXT: ret
145+
%result = call ptr @llvm.ct.select.p0(i1 %cond, ptr %a, ptr %b)
146+
ret ptr %result
147+
}
148+
149+
; Test with deeply nested conditions
150+
define i32 @test_ctselect_deeply_nested(i1 %c1, i1 %c2, i1 %c3, i1 %c4, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) {
151+
; RV64-LABEL: test_ctselect_deeply_nested:
152+
; RV64: # %bb.0:
153+
; RV64-NEXT: lw t0, 0(sp)
154+
; RV64-NEXT: xor a4, a4, a5
155+
; RV64-NEXT: slli a0, a0, 63
156+
; RV64-NEXT: xor a5, a5, a6
157+
; RV64-NEXT: slli a1, a1, 63
158+
; RV64-NEXT: xor a6, a6, a7
159+
; RV64-NEXT: slli a2, a2, 63
160+
; RV64-NEXT: slli a3, a3, 63
161+
; RV64-NEXT: srai a0, a0, 63
162+
; RV64-NEXT: srai a1, a1, 63
163+
; RV64-NEXT: srai a2, a2, 63
164+
; RV64-NEXT: and a0, a4, a0
165+
; RV64-NEXT: xor a0, a0, a5
166+
; RV64-NEXT: and a0, a0, a1
167+
; RV64-NEXT: xor a1, a7, t0
168+
; RV64-NEXT: xor a0, a0, a6
169+
; RV64-NEXT: and a0, a0, a2
170+
; RV64-NEXT: xor a0, a0, a1
171+
; RV64-NEXT: srai a3, a3, 63
172+
; RV64-NEXT: and a0, a0, a3
173+
; RV64-NEXT: xor a0, a0, t0
174+
; RV64-NEXT: ret
175+
;
176+
; RV32-LABEL: test_ctselect_deeply_nested:
177+
; RV32: # %bb.0:
178+
; RV32-NEXT: lw t0, 0(sp)
179+
; RV32-NEXT: andi a0, a0, 1
180+
; RV32-NEXT: andi a1, a1, 1
181+
; RV32-NEXT: andi a2, a2, 1
182+
; RV32-NEXT: andi a3, a3, 1
183+
; RV32-NEXT: neg t1, a0
184+
; RV32-NEXT: addi a0, a0, -1
185+
; RV32-NEXT: and a4, t1, a4
186+
; RV32-NEXT: neg t1, a1
187+
; RV32-NEXT: addi a1, a1, -1
188+
; RV32-NEXT: and a0, a0, a5
189+
; RV32-NEXT: neg a5, a2
190+
; RV32-NEXT: addi a2, a2, -1
191+
; RV32-NEXT: and a1, a1, a6
192+
; RV32-NEXT: neg a6, a3
193+
; RV32-NEXT: addi a3, a3, -1
194+
; RV32-NEXT: and a2, a2, a7
195+
; RV32-NEXT: or a0, a4, a0
196+
; RV32-NEXT: and a0, t1, a0
197+
; RV32-NEXT: or a0, a0, a1
198+
; RV32-NEXT: and a0, a5, a0
199+
; RV32-NEXT: or a0, a0, a2
200+
; RV32-NEXT: and a0, a6, a0
201+
; RV32-NEXT: and a1, a3, t0
202+
; RV32-NEXT: or a0, a0, a1
203+
; RV32-NEXT: ret
204+
%sel1 = call i32 @llvm.ct.select.i32(i1 %c1, i32 %a, i32 %b)
205+
%sel2 = call i32 @llvm.ct.select.i32(i1 %c2, i32 %sel1, i32 %c)
206+
%sel3 = call i32 @llvm.ct.select.i32(i1 %c3, i32 %sel2, i32 %d)
207+
%sel4 = call i32 @llvm.ct.select.i32(i1 %c4, i32 %sel3, i32 %e)
208+
ret i32 %sel4
209+
}
210+
211+
; Declare the intrinsics
212+
declare i1 @llvm.ct.select.i1(i1, i1, i1)
213+
declare i32 @llvm.ct.select.i32(i1, i32, i32)
214+
declare ptr @llvm.ct.select.p0(i1, ptr, ptr)

0 commit comments

Comments
 (0)