Skip to content

Commit 477e728

Browse files
sparker-armnikic
authored andcommitted
[WebAssembly] multivalue stackify fix
Don't attempt to move a multivalue def past one of it's prior uses. Differential Revision: https://reviews.llvm.org/D137824
1 parent 6c0bab9 commit 477e728

File tree

2 files changed

+116
-5
lines changed

2 files changed

+116
-5
lines changed

llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -336,12 +336,17 @@ static bool isSafeToMove(const MachineOperand *Def, const MachineOperand *Use,
336336
// instruction in which the current value is used, we cannot
337337
// stackify. Stackifying in this case would require that def moving below the
338338
// current def in the stack, which cannot be achieved, even with locals.
339+
// Also ensure we don't sink the def past any other prior uses.
339340
for (const auto &SubsequentDef : drop_begin(DefI->defs())) {
340-
for (const auto &PriorUse : UseI->uses()) {
341-
if (&PriorUse == Use)
342-
break;
343-
if (PriorUse.isReg() && SubsequentDef.getReg() == PriorUse.getReg())
344-
return false;
341+
auto I = std::next(MachineBasicBlock::const_iterator(DefI));
342+
auto E = std::next(MachineBasicBlock::const_iterator(UseI));
343+
for (; I != E; ++I) {
344+
for (const auto &PriorUse : I->uses()) {
345+
if (&PriorUse == Use)
346+
break;
347+
if (PriorUse.isReg() && SubsequentDef.getReg() == PriorUse.getReg())
348+
return false;
349+
}
345350
}
346351
}
347352

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -mtriple=wasm32-unknown-unknown -mattr=+multivalue -run-pass=wasm-reg-stackify -verify-machineinstrs %s -o - | FileCheck %s
3+
4+
--- |
5+
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
6+
target triple = "wasm32-unknown-wasi"
7+
8+
declare { i32, i32 } @foo() #0
9+
10+
define i32 @dont_move_call_past_first_add() #0 {
11+
entry:
12+
%foo1 = call { i32, i32 } @foo()
13+
%foo2 = call { i32, i32 } @foo()
14+
%foo1_0 = extractvalue { i32, i32 } %foo2, 0
15+
%foo1_1 = extractvalue { i32, i32 } %foo2, 1
16+
%foo2_0 = extractvalue { i32, i32 } %foo1, 0
17+
%a = add i32 %foo2_0, %foo1_1
18+
%b = add i32 %a, %foo1_0
19+
ret i32 %b
20+
}
21+
22+
attributes #0 = { "target-features"="+multivalue,+mutable-globals,+sign-ext," }
23+
24+
!llvm.module.flags = !{!0, !1, !2}
25+
26+
!0 = !{i32 1, !"wasm-feature-multivalue", i32 43}
27+
!1 = !{i32 1, !"wasm-feature-mutable-globals", i32 43}
28+
!2 = !{i32 1, !"wasm-feature-sign-ext", i32 43}
29+
30+
...
31+
---
32+
name: dont_move_call_past_first_add
33+
alignment: 1
34+
exposesReturnsTwice: false
35+
legalized: false
36+
regBankSelected: false
37+
selected: false
38+
failedISel: false
39+
tracksRegLiveness: true
40+
hasWinCFI: false
41+
callsEHReturn: false
42+
callsUnwindInit: false
43+
hasEHCatchret: false
44+
hasEHScopes: false
45+
hasEHFunclets: false
46+
failsVerification: false
47+
tracksDebugUserValues: false
48+
registers:
49+
- { id: 0, class: i32, preferred-register: '' }
50+
- { id: 1, class: i32, preferred-register: '' }
51+
- { id: 2, class: i32, preferred-register: '' }
52+
- { id: 3, class: i32, preferred-register: '' }
53+
- { id: 4, class: i32, preferred-register: '' }
54+
- { id: 5, class: i32, preferred-register: '' }
55+
liveins:
56+
- { reg: '$arguments', virtual-reg: '' }
57+
frameInfo:
58+
isFrameAddressTaken: false
59+
isReturnAddressTaken: false
60+
hasStackMap: false
61+
hasPatchPoint: false
62+
stackSize: 0
63+
offsetAdjustment: 0
64+
maxAlignment: 1
65+
adjustsStack: false
66+
hasCalls: true
67+
stackProtector: ''
68+
functionContext: ''
69+
maxCallFrameSize: 0
70+
cvBytesOfCalleeSavedRegisters: 0
71+
hasOpaqueSPAdjustment: false
72+
hasVAStart: false
73+
hasMustTailInVarArgFunc: false
74+
hasTailCall: false
75+
localFrameSize: 0
76+
savePoint: ''
77+
restorePoint: ''
78+
fixedStack: []
79+
stack: []
80+
callSites: []
81+
debugValueSubstitutions: []
82+
constants: []
83+
machineFunctionInfo:
84+
params: [ ]
85+
results: [ i32 ]
86+
isCFGStackified: false
87+
wasmEHFuncInfo: {}
88+
body: |
89+
bb.0.entry:
90+
liveins: $arguments
91+
92+
; CHECK-LABEL: name: dont_move_call_past_first_add
93+
; CHECK: liveins: $arguments, $value_stack
94+
; CHECK-NEXT: {{ $}}
95+
; CHECK-NEXT: %0:i32, dead %1:i32 = CALL @foo, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def dead $arguments, implicit $sp32, implicit $sp64
96+
; CHECK-NEXT: [[CALL:%[0-9]+]]:i32, [[CALL1:%[0-9]+]]:i32 = CALL @foo, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def dead $arguments, implicit $sp32, implicit $sp64
97+
; CHECK-NEXT: [[ADD_I32_:%[0-9]+]]:i32 = ADD_I32 %0, [[CALL1]], implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
98+
; CHECK-NEXT: [[ADD_I32_1:%[0-9]+]]:i32 = ADD_I32 [[CALL]], [[ADD_I32_]], implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
99+
; CHECK-NEXT: RETURN [[ADD_I32_1]], implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
100+
%0:i32, dead %1:i32 = CALL @foo, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def dead $arguments, implicit $sp32, implicit $sp64
101+
%2:i32, %3:i32 = CALL @foo, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def dead $arguments, implicit $sp32, implicit $sp64
102+
%4:i32 = ADD_I32 %0, %3, implicit-def dead $arguments
103+
%5:i32 = ADD_I32 %4, %2, implicit-def dead $arguments
104+
RETURN %5, implicit-def dead $arguments
105+
106+
...

0 commit comments

Comments
 (0)