diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index 428d573668fb4..5ff3d5f760204 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -510,10 +510,11 @@ static unsigned getTeeOpcode(const TargetRegisterClass *RC) { // Shrink LI to its uses, cleaning up LI. static void shrinkToUses(LiveInterval &LI, LiveIntervals &LIS) { - if (LIS.shrinkToUses(&LI)) { - SmallVector SplitLIs; - LIS.splitSeparateComponents(LI, SplitLIs); - } + LIS.shrinkToUses(&LI); + // In case the register's live interval now has multiple unconnected + // components, split them into multiple registers. + SmallVector SplitLIs; + LIS.splitSeparateComponents(LI, SplitLIs); } /// A single-use def in the same block with no intervening memory or register diff --git a/llvm/test/CodeGen/WebAssembly/tee-live-intervals.mir b/llvm/test/CodeGen/WebAssembly/tee-live-intervals.mir new file mode 100644 index 0000000000000..b137e990932b0 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/tee-live-intervals.mir @@ -0,0 +1,41 @@ +# RUN: llc -mtriple=wasm32-unknown-unknown -run-pass wasm-reg-stackify -verify-machineinstrs %s -o - + +# TEE generation in RegStackify can create virtual registers with LiveIntervals +# with multiple disconnected segments, which is invalid in MachineVerifier. In +# this test, '%0 = CALL @foo' will become a CALL and a TEE, which creates +# unconnected split segments. This should be later split into multiple +# registers. This test should not crash with -verify-machineinstrs, which checks +# whether all segments within a register is connected. See ??? for the detailed +# explanation. + +--- | + target triple = "wasm32-unknown-unknown" + + declare ptr @foo(ptr returned) + define void @tee_live_intervals_test() { + ret void + } +... +--- +name: tee_live_intervals_test +liveins: + - { reg: '$arguments' } +tracksRegLiveness: true +body: | + bb.0: + liveins: $arguments + successors: %bb.1, %bb.2 + %0:i32 = ARGUMENT_i32 0, implicit $arguments + %1:i32 = CONST_I32 0, implicit-def dead $arguments + BR_IF %bb.2, %1:i32, implicit-def dead $arguments + + bb.1: + ; predecessors: %bb.0 + %0:i32 = CALL @foo, %0:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64 + STORE8_I32_A32 0, 0, %0:i32, %1:i32, implicit-def dead $arguments + RETURN %0:i32, implicit-def dead $arguments + + bb.2: + ; predecessors: %bb.0 + %2:i32 = CONST_I32 0, implicit-def dead $arguments + RETURN %2:i32, implicit-def dead $arguments