llvm-project/llvm/test/CodeGen/WebAssembly/fast-isel-pr47040.ll
Heejin Ahn 115cb402d8
[WebAssembly] Don't fold non-nuw add/sub in FastISel (#111278)
We should not fold one of add/sub operands into a load/store's offset
when `nuw` (no unsigned wrap) is not present, because the address
calculation, which adds the offset with the operand, does not wrap.

This is handled correctly in the normal ISel:

6de5305b3d/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp (L328-L332)
but not in FastISel.

This positivity check in FastISel is not sufficient to avoid this case
fully:

6de5305b3d/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp (L348-L352)

because
1. Even if RHS is within signed int range, depending on the value of the
LHS, the resulting value can exceed uint32 max.
2. When one of the operands is a label, `Address` can contain a
`GlobalValue` and a `Reg` at the same time, so the `GlobalValue` becomes
incorrectly an offset:
6de5305b3d/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp (L53-L69)
6de5305b3d/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp (L409-L417)

Both cases are in the newly added test.

We should handle `SUB` too because `SUB` is the same as `ADD` when RHS's
sign changes. I checked why our current normal ISel only handles `ADD`,
and the reason it's OK for the normal ISel to handle only `ADD` seems
that DAGCombiner replaces `SUB` with `ADD` here:
6de5305b3d/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp (L3904-L3907)

Fixes #111018.
2024-10-09 14:31:16 -07:00

22 lines
842 B
LLVM

; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs
; Regression test for PR47040, in which an assertion was improperly
; triggered during FastISel's address computation. The issue was that
; an `Address` set to be relative to FrameIndex zero was incorrectly
; considered to have an unset base. When the left hand side of an add
; set the Address to have a FrameIndex base of 0, the right side would
; not detect that the Address base had already been set and could try
; to set the Address to be relative to a register instead, triggering
; an assertion.
target triple = "wasm32-unknown-unknown"
define i32 @foo() {
%stack_addr = alloca i32
%stack_i = ptrtoint ptr %stack_addr to i32
%added = add nuw i32 %stack_i, undef
%added_addr = inttoptr i32 %added to ptr
%ret = load i32, ptr %added_addr
ret i32 %ret
}