[llvm] [WebAssembly] Don't fold non-nuw add/sub in FastISel (PR #111278)
Heejin Ahn via llvm-commits
llvm-commits at lists.llvm.org
Sat Oct 5 22:29:57 PDT 2024
================
@@ -0,0 +1,106 @@
+; RUN: llc < %s -asm-verbose=false -fast-isel -verify-machineinstrs | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+; FastISel should not fold one of the add/sub operands into a load/store's
+; offset when 'nuw' (no unsigned wrap) is not present, because the address
+; calculation does not wrap. When there is an add/sub and nuw is not present, we
+; bail out of FastISel.
+
+ at mylabel = external global ptr
+
+; CHECK-LABEL: dont_fold_non_nuw_add_load:
+; CHECK: local.get 0
+; CHECK-NEXT: i32.const 2147483644
+; CHECK-NEXT: i32.add
+; CHECK-NEXT: i32.load 0
+define i32 @dont_fold_non_nuw_add_load(ptr %p) {
+ %q = ptrtoint ptr %p to i32
+ %r = add i32 %q, 2147483644
+ %s = inttoptr i32 %r to ptr
+ %t = load i32, ptr %s
+ ret i32 %t
+}
+
+; CHECK-LABEL: dont_fold_non_nuw_add_store:
+; CHECK: local.get 0
+; CHECK-NEXT: i32.const 2147483644
+; CHECK-NEXT: i32.add
+; CHECK-NEXT: i32.const 5
+; CHECK-NEXT: i32.store 0
+define void @dont_fold_non_nuw_add_store(ptr %p) {
+ %q = ptrtoint ptr %p to i32
+ %r = add i32 %q, 2147483644
+ %s = inttoptr i32 %r to ptr
+ store i32 5, ptr %s
+ ret void
+}
+
+; CHECK-LABEL: dont_fold_non_nuw_add_load_2:
+; CHECK: i32.const mylabel
+; CHECK-NEXT: i32.const -4
+; CHECK-NEXT: i32.add
+; CHECK-NEXT: i32.load 0
+define i32 @dont_fold_non_nuw_add_load_2() {
+ %t = load i32, ptr inttoptr (i32 add (i32 ptrtoint (ptr @mylabel to i32), i32 -4) to ptr), align 4
+ ret i32 %t
+}
+
+; CHECK-LABEL: dont_fold_non_nuw_add_store_2:
+; CHECK: i32.const mylabel
+; CHECK-NEXT: i32.const -4
+; CHECK-NEXT: i32.add
+; CHECK-NEXT: i32.const 5
+; CHECK-NEXT: i32.store 0
+define void @dont_fold_non_nuw_add_store_2() {
+ store i32 5, ptr inttoptr (i32 add (i32 ptrtoint (ptr @mylabel to i32), i32 -4) to ptr), align 4
+ ret void
+}
+
+; CHECK-LABEL: dont_fold_non_nuw_sub_load:
+; CHECK: local.get 0
+; CHECK-NEXT: i32.const 2147483644
+; CHECK-NEXT: i32.add
+; CHECK-NEXT: i32.load 0
+define i32 @dont_fold_non_nuw_sub_load(ptr %p) {
+ %q = ptrtoint ptr %p to i32
+ %r = sub i32 %q, -2147483644
+ %s = inttoptr i32 %r to ptr
+ %t = load i32, ptr %s
+ ret i32 %t
+}
+
+; CHECK-LABEL: dont_fold_non_nuw_sub_store:
+; CHECK: local.get 0
+; CHECK-NEXT: i32.const 2147483644
+; CHECK-NEXT: i32.add
+; CHECK-NEXT: i32.const 5
+; CHECK-NEXT: i32.store 0
+define void @dont_fold_non_nuw_sub_store(ptr %p) {
+ %q = ptrtoint ptr %p to i32
+ %r = sub i32 %q, -2147483644
+ %s = inttoptr i32 %r to ptr
+ store i32 5, ptr %s
+ ret void
+}
+
+; CHECK-LABEL: dont_fold_non_nuw_sub_load_2:
+; CHECK: i32.const mylabel
+; CHECK-NEXT: i32.const -4
+; CHECK-NEXT: i32.add
+; CHECK-NEXT: i32.load 0
+define i32 @dont_fold_non_nuw_sub_load_2() {
+ %t = load i32, ptr inttoptr (i32 sub (i32 ptrtoint (ptr @mylabel to i32), i32 4) to ptr), align 4
+ ret i32 %t
+}
+
+; CHECK-LABEL: dont_fold_non_nuw_sub_store_2:
+; CHECK: i32.const mylabel
+; CHECK-NEXT: i32.const -4
+; CHECK-NEXT: i32.add
+; CHECK-NEXT: i32.const 5
+; CHECK-NEXT: i32.store 0
+define void @dont_fold_non_nuw_sub_store_2() {
+ store i32 5, ptr inttoptr (i32 sub (i32 ptrtoint (ptr @mylabel to i32), i32 4) to ptr), align 4
+ ret void
+}
----------------
aheejin wrote:
Actually these two are correctly compiled even in the current compiler, because in `ISD::ADD`, even if RHS is negative, we try to compute each of LHS and RHS separately to see if they can be combined:
https://github.com/llvm/llvm-project/blob/6de5305b3d7a4a19a29b35d481a8090e2a6d3a7e/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp#L355-L358
But `ISD::SUB` handling doesn't have this part. (Because offset calculation is addition)
But I added these tests for symmetry and ensure if these invariants are well maintained in future.
https://github.com/llvm/llvm-project/pull/111278
More information about the llvm-commits
mailing list