llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.05k stars 11.98k forks source link

[WebAssembly] `stacksave` leads machine code verification failure after `wasm-replace-phys-regs` #62235

Closed kateinoigakukun closed 1 year ago

kateinoigakukun commented 1 year ago

LLVM version: llvmorg-16.0.0

Minimum reproducible code:

target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-wasi"

define weak_odr swiftcc { i32, i8 } @x(i1 %0) {
entry:
  br i1 %0, label %.thread51, label %.lr.ph.i30

.thread51:                                        ; preds = %entry
  %spsave253 = tail call i8* @llvm.stacksave()
  br label %.loopexit

.lr.ph.i30:                                       ; preds = %.lr.ph.i30, %entry
  br i1 %0, label %.loopexit, label %.lr.ph.i30

.loopexit:                                        ; preds = %.lr.ph.i30, %.thread51
  %spsave254.ph = phi i8* [ %spsave253, %.thread51 ], [ null, %.lr.ph.i30 ]
  tail call void @llvm.stackrestore(i8* %spsave254.ph)
  unreachable
}

; Function Attrs: nocallback nofree nosync nounwind willreturn
declare i8* @llvm.stacksave() #0

; Function Attrs: nocallback nofree nosync nounwind willreturn
declare void @llvm.stackrestore(i8*) #0

attributes #0 = { nocallback nofree nosync nounwind willreturn }
$ llc test.ll -stop-after wasm-replace-phys-regs -o - -verify-machineinstrs
# Machine code for function x: NoPHIs, TracksLiveness, TiedOpsRewritten
Function Live Ins: $arguments

bb.0.entry:
  successors: %bb.1(0x00000000), %bb.2(0x80000000); %bb.1(0.00%), %bb.2(100.00%)
  liveins: $arguments
  %3:i32 = ARGUMENT_i32 1, implicit $arguments
  dead %2:i32 = ARGUMENT_i32 0, implicit $arguments
  %4:i32 = CONST_I32 1, implicit-def dead $arguments
  %5:i32 = AND_I32 %3:i32, %4:i32, implicit-def dead $arguments
  BR_UNLESS %bb.2, %5:i32, implicit-def $arguments

bb.1..thread51:
; predecessors: %bb.0

  %10:i32 = COPY_I32 %11:i32, implicit-def $arguments
  %11:i32 = COPY_I32 %10:i32, implicit-def $arguments
  UNREACHABLE implicit-def dead $arguments

bb.2..lr.ph.i30:
; predecessors: %bb.2, %bb.0
  successors: %bb.3(0x00000000), %bb.2(0x80000000); %bb.3(0.00%), %bb.2(100.00%)

  BR_UNLESS %bb.2, %5:i32, implicit-def dead $arguments

bb.3:
; predecessors: %bb.2

  %10:i32 = CONST_I32 0, implicit-def dead $arguments
  %11:i32 = COPY_I32 %10:i32, implicit-def $arguments
  UNREACHABLE implicit-def dead $arguments

# End machine code for function x.

*** Bad machine code: Virtual register defs don't dominate all uses. ***
- function:    x
- v. register: %11
LLVM ERROR: Found 1 machine code errors.
Stack trace ```console PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace. Stack dump: 0. Program arguments: /home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc Swift.x.wasm32-unknown-wasi.reduced.ll 1. Running pass 'Function Pass Manager' on module 'Swift.x.wasm32-unknown-wasi.reduced.ll'. 2. Running pass 'Live Interval Analysis' on function '@x' #0 0x0000000001e019d3 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x1e019d3) #1 0x0000000001dff6fe llvm::sys::RunSignalHandlers() (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x1dff6fe) #2 0x0000000001e01e9f SignalHandler(int) Signals.cpp:0:0 #3 0x00007f6a7e2c3420 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x14420) #4 0x00007f6a7dd5600b raise /build/glibc-SzIz7B/glibc-2.31/signal/../sysdeps/unix/sysv/linux/raise.c:51:1 #5 0x00007f6a7dd35859 abort /build/glibc-SzIz7B/glibc-2.31/stdlib/abort.c:81:7 #6 0x0000000001d7e6b0 llvm::report_fatal_error(llvm::Twine const&, bool) (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x1d7e6b0) #7 0x000000000127f7a6 (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x127f7a6) #8 0x00000000011004aa llvm::LiveRangeCalc::findReachingDefs(llvm::LiveRange&, llvm::MachineBasicBlock&, llvm::SlotIndex, unsigned int, llvm::ArrayRef) (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x11004aa) #9 0x00000000010ff7f7 llvm::LiveRangeCalc::extend(llvm::LiveRange&, llvm::SlotIndex, unsigned int, llvm::ArrayRef) (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x10ff7f7) #10 0x000000000110321a llvm::LiveIntervalCalc::extendToUses(llvm::LiveRange&, llvm::Register, llvm::LaneBitmask, llvm::LiveInterval*) (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x110321a) #11 0x0000000001102ec0 llvm::LiveIntervalCalc::calculate(llvm::LiveInterval&, bool) (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x1102ec0) #12 0x00000000010ead22 llvm::LiveIntervals::computeVirtRegInterval(llvm::LiveInterval&) (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x10ead22) #13 0x00000000010e9824 llvm::LiveIntervals::computeVirtRegs() (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x10e9824) #14 0x00000000010e95f2 llvm::LiveIntervals::runOnMachineFunction(llvm::MachineFunction&) (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x10e95f2) #15 0x00000000011a4641 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x11a4641) #16 0x000000000165c868 llvm::FPPassManager::runOnFunction(llvm::Function&) (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x165c868) #17 0x0000000001664f41 llvm::FPPassManager::runOnModule(llvm::Module&) (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x1664f41) #18 0x000000000165d034 llvm::legacy::PassManagerImpl::run(llvm::Module&) (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x165d034) #19 0x00000000006e3a7d compileModule(char**, llvm::LLVMContext&) llc.cpp:0:0 #20 0x00000000006e144d main (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x6e144d) #21 0x00007f6a7dd37083 __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:342:3 #22 0x00000000006e07ae _start (/home/katei/ghq/work.katei.dev/swiftwasm-source/host-build/Ninja-ReleaseAssert/llvm-linux-x86_64/bin/llc+0x6e07ae) ```

It looks like $sp32 read by stacksave is replaced with a virtual reg by wasm-replace-phys-regs, but it results in violating the domination principle for virtual registers.

Result of `-stop-before=wasm-replace-phys-regs` ``` bb.0.entry: successors: %bb.1(0x00000000), %bb.2(0x80000000) liveins: $arguments %3:i32 = ARGUMENT_i32 1, implicit $arguments dead %2:i32 = ARGUMENT_i32 0, implicit $arguments %4:i32 = CONST_I32 1, implicit-def dead $arguments %5:i32 = AND_I32 %3, %4, implicit-def dead $arguments BR_UNLESS %bb.2, %5, implicit-def $arguments bb.1..thread51: %10:i32 = COPY_I32 $sp32, implicit-def $arguments $sp32 = COPY_I32 %10, implicit-def $arguments UNREACHABLE implicit-def dead $arguments bb.2..lr.ph.i30: successors: %bb.3(0x00000000), %bb.2(0x80000000) BR_UNLESS %bb.2, %5, implicit-def dead $arguments bb.3: %10:i32 = CONST_I32 0, implicit-def dead $arguments $sp32 = COPY_I32 %10, implicit-def $arguments UNREACHABLE implicit-def dead $arguments ```

I'm not sure the stacksave / stackrestore are supported on WebAssembly target or not 🤷 But it seems that it somehow succeeds with LLVM 14: https://godbolt.org/z/7Mx45GqK6

llvmbot commented 1 year ago

@llvm/issue-subscribers-backend-webassembly