Index: lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp =================================================================== --- lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp +++ lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp @@ -44,6 +44,9 @@ OS << "$" << RegNo; } +// TODO: Include this correctly +bool IsCallIndirect(unsigned opcode); + void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS, StringRef Annot, const MCSubtargetInfo & /*STI*/) { @@ -52,12 +55,23 @@ // Print any additional variadic operands. const MCInstrDesc &Desc = MII.get(MI->getOpcode()); - if (Desc.isVariadic()) - for (auto i = Desc.getNumOperands(), e = MI->getNumOperands(); i < e; ++i) { + if (Desc.isVariadic()) { + auto start = Desc.getNumOperands(); + if (start > 0 && IsCallIndirect(MI->getOpcode())) { + --start; + } + for (auto i = start, end = MI->getNumOperands(); i < end; ++i) { if (i != 0) OS << ", "; - printOperand(MI, i, OS); + auto x = i; + if (IsCallIndirect(MI->getOpcode())) { + x = i + 1; + if (x >= end) + x = start; + } + printOperand(MI, x, OS); } + } // Print any added annotation. printAnnotation(OS, Annot); Index: lib/Target/WebAssembly/WebAssemblyInstrCall.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ lib/Target/WebAssembly/WebAssemblyInstrCall.td @@ -31,7 +31,7 @@ !strconcat(prefix, "call\t$dst, $callee")>; def CALL_INDIRECT_#vt : I<(outs vt:$dst), (ins I32:$callee, variable_ops), [(set vt:$dst, (WebAssemblycall1 I32:$callee))], - !strconcat(prefix, "call_indirect\t$dst, $callee")>; + !strconcat(prefix, "call_indirect\t$dst")>; } multiclass SIMD_CALL { @@ -44,7 +44,7 @@ [(set (vt V128:$dst), (WebAssemblycall1 I32:$callee))], !strconcat(prefix, - "call_indirect\t$dst, $callee")>; + "call_indirect\t$dst")>; } let Uses = [SP32, SP64], isCall = 1 in { @@ -62,7 +62,7 @@ "call \t$callee">; def CALL_INDIRECT_VOID : I<(outs), (ins I32:$callee, variable_ops), [(WebAssemblycall0 I32:$callee)], - "call_indirect\t$callee">; + "call_indirect\t">; } // Uses = [SP32,SP64], isCall = 1 } // Defs = [ARGUMENTS] Index: lib/Target/WebAssembly/WebAssemblyRegStackify.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -69,6 +69,20 @@ return new WebAssemblyRegStackify(); } +// TODO: Find a better place for this to live +bool IsCallIndirect(unsigned opcode) { + switch (opcode) { + case WebAssembly::CALL_INDIRECT_VOID: + case WebAssembly::CALL_INDIRECT_I32: + case WebAssembly::CALL_INDIRECT_I64: + case WebAssembly::CALL_INDIRECT_F32: + case WebAssembly::CALL_INDIRECT_F64: + return true; + default: + return false; + } +} + // Decorate the given instruction with implicit operands that enforce the // expression stack ordering constraints for an instruction which is on // the expression stack. @@ -585,11 +599,16 @@ typedef iterator_range RangeTy; SmallVector Worklist; + void addRange(const mop_iterator &Begin, const mop_iterator &End) { + if (Begin != End) { + const iterator_range Range(Begin, End); + Worklist.push_back(reverse(Range)); + } + } + public: explicit TreeWalkerState(MachineInstr *Insert) { - const iterator_range &Range = Insert->explicit_uses(); - if (Range.begin() != Range.end()) - Worklist.push_back(reverse(Range)); + PushOperands(Insert); } bool Done() const { return Worklist.empty(); } @@ -608,9 +627,13 @@ /// Push Instr's operands onto the stack to be visited. void PushOperands(MachineInstr *Instr) { - const iterator_range &Range(Instr->explicit_uses()); - if (Range.begin() != Range.end()) - Worklist.push_back(reverse(Range)); + auto Uses = Instr->explicit_uses(); + if (!IsCallIndirect(Instr->getOpcode())) { + addRange(Uses.begin(), Uses.end()); + } else { + addRange(Uses.begin() + 1, Uses.end()); + addRange(Uses.begin(), Uses.begin() + 1); + } } /// Some of Instr's operands are on the top of the stack; remove them and @@ -828,13 +851,41 @@ for (MachineInstr &MI : MBB) { if (MI.isDebugValue()) continue; - for (MachineOperand &MO : reverse(MI.explicit_operands())) { - if (!MO.isReg()) + + // TODO: Refactor this to be cleaner + SmallVector operands; + for (auto &MO : MI.explicit_operands()) + operands.push_back(&MO); + SmallVector actual_operands; + if (!IsCallIndirect(MI.getOpcode())) { + for (auto x : operands) + actual_operands.push_back(x); + } else { + MachineOperand* target = nullptr; + for (unsigned i = 0; i < operands.size(); ++i) { + auto op = operands[i]; + if (op->isDef()) { + actual_operands.push_back(op); + continue; + } + if (!target) { + target = op; + continue; + } + actual_operands.push_back(op); + } + if (target) { + actual_operands.push_back(target); + } + } + + for (MachineOperand *MO : reverse(actual_operands)) { + if (!MO->isReg()) continue; - unsigned Reg = MO.getReg(); + unsigned Reg = MO->getReg(); if (MFI.isVRegStackified(Reg)) { - if (MO.isDef()) + if (MO->isDef()) Stack.push_back(Reg); else assert(Stack.pop_back_val() == Reg && Index: test/CodeGen/WebAssembly/call.ll =================================================================== --- test/CodeGen/WebAssembly/call.ll +++ test/CodeGen/WebAssembly/call.ll @@ -97,6 +97,24 @@ ret i32 %t } +; CHECK-LABEL: call_indirect_arg: +; CHECK-NEXT: .param i32, i32{{$}} +; CHECK-NEXT: {{^}} call_indirect $1, $0{{$}} +; CHECK-NEXT: return{{$}} +define void @call_indirect_arg(void (i32)* %callee, i32 %arg) { + call void %callee(i32 %arg) + ret void +} + +; CHECK-LABEL: call_indirect_arg_2: +; CHECK-NEXT: .param i32, i32, i32{{$}} +; CHECK-NEXT: {{^}} i32.call_indirect $drop=, $1, $2, $0{{$}} +; CHECK-NEXT: return{{$}} +define void @call_indirect_arg_2(i32 (i32, i32)* %callee, i32 %arg, i32 %arg2) { + call i32 %callee(i32 %arg, i32 %arg2) + ret void +} + ; CHECK-LABEL: tail_call_void_nullary: ; CHECK-NEXT: {{^}} call void_nullary@FUNCTION{{$}} ; CHECK-NEXT: return{{$}}