Index: test/NaCl/ARM/divrem-guards.ll |
diff --git a/test/NaCl/ARM/divrem-guards.ll b/test/NaCl/ARM/divrem-guards.ll |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1be08765c2ce6089cfecbae8cfae0a6c4a57396d |
--- /dev/null |
+++ b/test/NaCl/ARM/divrem-guards.ll |
@@ -0,0 +1,107 @@ |
+; RUN: llc -mtriple=armv7-unknown-nacl -sfi-branch -filetype=obj %s -o - \ |
eliben
2013/05/03 21:18:55
I wonder if there's a way to hook this pass to opt
sehr
2013/05/03 23:29:05
I have added an invocation under opt.
|
+; RUN: | llvm-objdump -disassemble -triple armv7 -mattr=+nacl-trap - \ |
+; RUN: | FileCheck %s |
+ |
+; Check for all four operators that need guards. |
+define i32 @mysdiv(i32 %x, i32 %y) #0 { |
+entry: |
+ %x.addr = alloca i32, align 4 |
eliben
2013/05/03 21:18:55
Could you minimize this repeating test case to som
sehr
2013/05/03 23:29:05
Done.
|
+ %y.addr = alloca i32, align 4 |
+ store i32 %x, i32* %x.addr, align 4 |
+ store i32 %y, i32* %y.addr, align 4 |
+ %0 = load i32* %x.addr, align 4 |
Mark Seaborn
2013/05/03 21:25:36
Remove the loads+stores. You're copying Clang's -
sehr
2013/05/03 23:29:05
Yes, removed.
|
+ %1 = load i32* %y.addr, align 4 |
+ %div1 = sdiv i32 %0, %1 |
+; CHECK: cmp r1, #0 |
Mark Seaborn
2013/05/03 21:25:36
It would be better to test at the IR level too. T
sehr
2013/05/03 23:29:05
I am now testing both ways.
sehr
2013/05/03 23:29:05
I am now checking both.
|
+; CHECK-NEXT: beq |
eliben
2013/05/03 21:18:55
I'd check that a trap exists too, before the next
sehr
2013/05/03 23:29:05
Done.
|
+ ret i32 %div1 |
+} |
+ |
+define i32 @myudiv(i32 %x, i32 %y) #0 { |
+entry: |
+ %x.addr = alloca i32, align 4 |
+ %y.addr = alloca i32, align 4 |
+ store i32 %x, i32* %x.addr, align 4 |
+ store i32 %y, i32* %y.addr, align 4 |
+ %0 = load i32* %x.addr, align 4 |
+ %1 = load i32* %y.addr, align 4 |
+ %div1 = udiv i32 %0, %1 |
+; CHECK: cmp r1, #0 |
+; CHECK-NEXT: beq |
+ ret i32 %div1 |
+} |
+ |
+define i32 @mysrem(i32 %x, i32 %y) #0 { |
+entry: |
+ %x.addr = alloca i32, align 4 |
+ %y.addr = alloca i32, align 4 |
+ store i32 %x, i32* %x.addr, align 4 |
+ store i32 %y, i32* %y.addr, align 4 |
+ %0 = load i32* %x.addr, align 4 |
+ %1 = load i32* %y.addr, align 4 |
+ %rem1 = srem i32 %0, %1 |
+; CHECK: cmp r1, #0 |
+; CHECK-NEXT: beq |
+ ret i32 %rem1 |
+} |
+ |
+define i32 @myurem(i32 %x, i32 %y) #0 { |
+entry: |
+ %x.addr = alloca i32, align 4 |
+ %y.addr = alloca i32, align 4 |
+ store i32 %x, i32* %x.addr, align 4 |
+ store i32 %y, i32* %y.addr, align 4 |
+ %0 = load i32* %x.addr, align 4 |
+ %1 = load i32* %y.addr, align 4 |
+ %rem1 = urem i32 %0, %1 |
+; CHECK: cmp r1, #0 |
+; CHECK-NEXT: beq |
+ ret i32 %rem1 |
+} |
+ |
+; Divides by non-zero constants should not be guarded. |
+define i32 @mysdiv_const(i32 %x, i32 %y) #0 { |
+entry: |
+ %x.addr = alloca i32, align 4 |
+ %y.addr = alloca i32, align 4 |
+ store i32 %x, i32* %x.addr, align 4 |
+ store i32 %y, i32* %y.addr, align 4 |
+ %0 = load i32* %x.addr, align 4 |
+ %div1 = sdiv i32 %0, 10 |
+; CHECK-NOT: cmp r1, #0 |
+; CHECK-NOT: f0 de fe e7 |
+ ret i32 %div1 |
+} |
+ |
+; Divides by explicit zero should prefixed by a trap. |
+define i32 @mysdiv_zero(i32 %x, i32 %y) #0 { |
+entry: |
+ %x.addr = alloca i32, align 4 |
+ %y.addr = alloca i32, align 4 |
+ store i32 %x, i32* %x.addr, align 4 |
+ store i32 %y, i32* %y.addr, align 4 |
+ %0 = load i32* %x.addr, align 4 |
+ %div1 = sdiv i32 %0, 0 |
+; CHECK-NOT: cmp r1, #0 |
+; CHECK: f0 de fe e7 |
+ ret i32 %div1 |
+} |
+ |
+; Divides at the start of block should be guarded correctly. |
+define i32 @mysdiv_loop(i32 %x, i32 %y) #0 { |
+entry: |
+ %x.addr = alloca i32, align 4 |
+ %y.addr = alloca i32, align 4 |
+ store i32 %x, i32* %x.addr, align 4 |
+ store i32 %y, i32* %y.addr, align 4 |
+ %0 = load i32* %x.addr, align 4 |
+ %1 = load i32* %y.addr, align 4 |
+ br label %header |
+header: |
+ %div1 = sdiv i32 %0, %1 |
+; CHECK: cmp r1, #0 |
+ br label %header |
+ ret i32 %div1 |
+} |
+ |
+attributes #0 = { nounwind } |