llvm.org GIT mirror llvm / 8e0d3d4
[WebAssembly] Revise the strategy for inline asm. Previously, an "r" constraint would mean the compiler provides a value on WebAssembly's operand stack. This was tricky to use properly, particularly since it isn't possible to declare a new local from within an inline asm string. With this patch, "r" provides the value in a WebAssembly local, and the local index is provided to the inline asm string. This requires inline asm to use get_local and set_local to read the register. This does potentially result in larger code size, however inline asm should hopefully be quite rare in WebAssembly. This also means that the "m" constraint can no longer be supported, as WebAssembly has nothing like a "memory operand" that includes an implicit get_local. This fixes PR34599 for the wasm32-unknown-unknown-wasm target (though not for the ELF target). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@317707 91177308-0d34-0410-b5e6-96231b3b80d8 Dan Gohman 1 year, 11 months ago
3 changed file(s) with 58 addition(s) and 29 deletion(s). Raw diff Collapse all Expand all
266266 if (AsmVariant != 0)
267267 report_fatal_error("There are no defined alternate asm variants");
268268
269 if (!ExtraCode) {
270 // TODO: For now, we just hard-code 0 as the constant offset; teach
271 // SelectInlineAsmMemoryOperand how to do address mode matching.
272 OS << "0(" + regToString(MI->getOperand(OpNo)) + ')';
273 return false;
274 }
269 // The current approach to inline asm is that "r" constraints are expressed
270 // as local indices, rather than values on the operand stack. This simplifies
271 // using "r" as it eliminates the need to push and pop the values in a
272 // particular order, however it also makes it impossible to have an "m"
273 // constraint. So we don't support it.
275274
276275 return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, AsmVariant, ExtraCode, OS);
277276 }
293293
294294 unsigned OldReg = MO.getReg();
295295
296 // Inline asm may have a def in the middle of the operands. Our contract
297 // with inline asm register operands is to provide local indices as
298 // immediates.
299 if (MO.isDef()) {
300 assert(MI.getOpcode() == TargetOpcode::INLINEASM);
301 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
302 MRI.removeRegOperandFromUseList(&MO);
303 MO = MachineOperand::CreateImm(LocalId);
304 continue;
305 }
306
296307 // If we see a stackified register, prepare to insert subsequent
297308 // get_locals before the start of its tree.
298309 if (MFI.isVRegStackified(OldReg)) {
299310 InsertPt = FindStartOfTree(MO, MRI, MFI);
311 continue;
312 }
313
314 // Our contract with inline asm register operands is to provide local
315 // indices as immediates.
316 if (MI.getOpcode() == TargetOpcode::INLINEASM) {
317 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
318 MRI.removeRegOperandFromUseList(&MO);
319 MO = MachineOperand::CreateImm(LocalId);
300320 continue;
301321 }
302322
None ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -no-integrated-as | FileCheck %s
0 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -no-integrated-as | FileCheck %s
11
22 ; Test basic inline assembly. Pass -no-integrated-as since these aren't
33 ; actually valid assembly syntax.
99 ; CHECK-NEXT: .param i32{{$}}
1010 ; CHECK-NEXT: .result i32{{$}}
1111 ; CHECK-NEXT: #APP{{$}}
12 ; CHECK-NEXT: # $0 = aaa($0){{$}}
12 ; CHECK-NEXT: # 0 = aaa(0){{$}}
1313 ; CHECK-NEXT: #NO_APP{{$}}
14 ; CHECK-NEXT: return $0{{$}}
14 ; CHECK-NEXT: get_local $push0=, 0{{$}}
15 ; CHECK-NEXT: return $pop0{{$}}
1516 define i32 @foo(i32 %r) {
1617 entry:
1718 %0 = tail call i32 asm sideeffect "# $0 = aaa($1)", "=r,r"(i32 %r) #0, !srcloc !0
1819 ret i32 %0
1920 }
2021
21 ; CHECK-LABEL: bar:
22 ; CHECK-NEXT: .param i32, i32{{$}}
23 ; CHECK-NEXT: #APP{{$}}
24 ; CHECK-NEXT: # 0($1) = bbb(0($0)){{$}}
25 ; CHECK-NEXT: #NO_APP{{$}}
26 ; CHECK-NEXT: return{{$}}
27 define void @bar(i32* %r, i32* %s) {
28 entry:
29 tail call void asm sideeffect "# $0 = bbb($1)", "=*m,*m"(i32* %s, i32* %r) #0, !srcloc !1
30 ret void
31 }
32
3322 ; CHECK-LABEL: imm:
3423 ; CHECK-NEXT: .result i32{{$}}
24 ; CHECK-NEXT: .local i32{{$}}
3525 ; CHECK-NEXT: #APP{{$}}
36 ; CHECK-NEXT: # $0 = ccc(42){{$}}
26 ; CHECK-NEXT: # 0 = ccc(42){{$}}
3727 ; CHECK-NEXT: #NO_APP{{$}}
38 ; CHECK-NEXT: return $0{{$}}
28 ; CHECK-NEXT: get_local $push0=, 0{{$}}
29 ; CHECK-NEXT: return $pop0{{$}}
3930 define i32 @imm() {
4031 entry:
4132 %0 = tail call i32 asm sideeffect "# $0 = ccc($1)", "=r,i"(i32 42) #0, !srcloc !2
4637 ; CHECK-NEXT: .param i64{{$}}
4738 ; CHECK-NEXT: .result i64{{$}}
4839 ; CHECK-NEXT: #APP{{$}}
49 ; CHECK-NEXT: # $0 = aaa($0){{$}}
40 ; CHECK-NEXT: # 0 = aaa(0){{$}}
5041 ; CHECK-NEXT: #NO_APP{{$}}
51 ; CHECK-NEXT: return $0{{$}}
42 ; CHECK-NEXT: get_local $push0=, 0{{$}}
43 ; CHECK-NEXT: return $pop0{{$}}
5244 define i64 @foo_i64(i64 %r) {
5345 entry:
5446 %0 = tail call i64 asm sideeffect "# $0 = aaa($1)", "=r,r"(i64 %r) #0, !srcloc !0
5648 }
5749
5850 ; CHECK-LABEL: X_i16:
59 ; CHECK: foo $1{{$}}
60 ; CHECK: i32.store16 0($0), $1{{$}}
51 ; CHECK: foo 1{{$}}
52 ; CHECK: get_local $push[[S0:[0-9]+]]=, 0{{$}}
53 ; CHECK-NEXT: get_local $push[[S1:[0-9]+]]=, 1{{$}}
54 ; CHECK-NEXT: i32.store16 0($pop[[S0]]), $pop[[S1]]{{$}}
6155 define void @X_i16(i16 * %t) {
6256 call void asm sideeffect "foo $0", "=*X,~{dirflag},~{fpsr},~{flags},~{memory}"(i16* %t)
6357 ret void
6458 }
6559
6660 ; CHECK-LABEL: X_ptr:
67 ; CHECK: foo $1{{$}}
68 ; CHECK: i32.store 0($0), $1{{$}}
61 ; CHECK: foo 1{{$}}
62 ; CHECK: get_local $push[[S0:[0-9]+]]=, 0{{$}}
63 ; CHECK-NEXT: get_local $push[[S1:[0-9]+]]=, 1{{$}}
64 ; CHECK-NEXT: i32.store 0($pop[[S0]]), $pop[[S1]]{{$}}
6965 define void @X_ptr(i16 ** %t) {
7066 call void asm sideeffect "foo $0", "=*X,~{dirflag},~{fpsr},~{flags},~{memory}"(i16** %t)
7167 ret void
8682 ret void
8783 }
8884
85 ; CHECK-LABEL: r_constraint
86 ; CHECK: i32.const $push[[S0:[0-9]+]]=, 0{{$}}
87 ; CHECK-NEXT: set_local [[L0:[0-9]+]], $pop[[S0]]{{$}}
88 ; CHECK-NEXT: i32.const $push[[S1:[0-9]+]]=, 37{{$}}
89 ; CHECK-NEXT: set_local [[L1:[0-9]+]], $pop[[S1]]{{$}}
90 ; CHECK: foo [[L2:[0-9]+]], 1, [[L0]], [[L1]]{{$}}
91 ; CHECK: get_local $push{{[0-9]+}}=, [[L2]]{{$}}
92 define hidden i32 @r_constraint(i32 %a, i32 %y) {
93 entry:
94 %z = bitcast i32 0 to i32
95 %t0 = tail call i32 asm "foo $0, $1, $2, $3", "=r,r,r,r"(i32 %y, i32 %z, i32 37) #0, !srcloc !0
96 ret i32 %t0
97 }
98
8999 attributes #0 = { nounwind }
90100
91101 !0 = !{i32 47}