Index: lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -42,11 +42,12 @@ class WebAssemblyAsmPrinter final : public AsmPrinter { const WebAssemblyInstrInfo *TII; + const MachineRegisterInfo *MRI; unsigned NumArgs; public: WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) - : AsmPrinter(TM, std::move(Streamer)), TII(nullptr) {} + : AsmPrinter(TM, std::move(Streamer)), TII(nullptr), MRI(nullptr) {} private: const char *getPassName() const override { @@ -64,6 +65,7 @@ bool runOnMachineFunction(MachineFunction &MF) override { const auto &Subtarget = MF.getSubtarget(); TII = Subtarget.getInstrInfo(); + MRI = &MF.getRegInfo(); NumArgs = MF.getInfo()->getNumArguments(); return AsmPrinter::runOnMachineFunction(MF); } @@ -78,10 +80,11 @@ void EmitInstruction(const MachineInstr *MI) override; + std::string getRegTypeName(unsigned RegNo) const; static std::string toString(const APFloat &APF); const char *toString(Type *Ty) const; - std::string regToString(unsigned RegNo); - std::string argToString(unsigned ArgNo); + std::string regToString(const MachineOperand &MO); + std::string argToString(const MachineOperand &MO); }; } // end anonymous namespace @@ -90,19 +93,33 @@ // Helpers. //===----------------------------------------------------------------------===// -// Untyped, lower-case version of the opcode's name matching the names -// WebAssembly opcodes are expected to have. The tablegen names are uppercase -// and suffixed with their type (after an underscore). -static SmallString<32> OpcodeName(const WebAssemblyInstrInfo *TII, - const MachineInstr *MI) { +// Operand type (if any), followed by the lower-case version of the opcode's +// name matching the names WebAssembly opcodes are expected to have. The +// tablegen names are uppercase and suffixed with their type (after an +// underscore). +static std::string OpcodeName(const WebAssemblyInstrInfo *TII, + const MachineInstr *MI) { std::string N(StringRef(TII->getName(MI->getOpcode())).lower()); - std::string::size_type End = N.rfind('_'); - End = std::string::npos == End ? N.length() : End; - return SmallString<32>(&N[0], &N[End]); + std::string::size_type Len = N.length(); + std::string::size_type Under = N.rfind('_'); + bool HasType = std::string::npos != Under; + std::string::size_type NameEnd = HasType ? Under : Len; + std::string Name(&N[0], &N[NameEnd]); + return HasType ? (std::string(&N[NameEnd + 1], &N[Len]) + '.' + Name) : Name; } static std::string toSymbol(StringRef S) { return ("$" + S).str(); } +std::string WebAssemblyAsmPrinter::getRegTypeName(unsigned RegNo) const { + const TargetRegisterClass *TRC = MRI->getRegClass(RegNo); + for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) + if (TRC->hasType(T)) + return EVT(T).getEVTString(); + DEBUG(errs() << "Unknown type for register number: " << RegNo); + llvm_unreachable("Unknown register type"); + return "?"; +} + std::string WebAssemblyAsmPrinter::toString(const APFloat &FP) { static const size_t BufBytes = 128; char buf[BufBytes]; @@ -120,19 +137,21 @@ return buf; } -std::string WebAssemblyAsmPrinter::regToString(unsigned RegNo) { +std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) { + unsigned RegNo = MO.getReg(); if (TargetRegisterInfo::isPhysicalRegister(RegNo)) return WebAssemblyInstPrinter::getRegisterName(RegNo); // WebAssembly arguments and local variables are in the same index space, and // there are no explicit varargs, so we just add the number of arguments to // the virtual register number to get the local variable number. - return '@' + utostr(TargetRegisterInfo::virtReg2Index(RegNo) + NumArgs); + return utostr(TargetRegisterInfo::virtReg2Index(RegNo) + NumArgs); } -std::string WebAssemblyAsmPrinter::argToString(unsigned ArgNo) { +std::string WebAssemblyAsmPrinter::argToString(const MachineOperand &MO) { + unsigned ArgNo = MO.getImm(); // Same as above, but we don't need to add NumArgs here. - return '@' + utostr(ArgNo); + return utostr(ArgNo); } const char *WebAssemblyAsmPrinter::toString(Type *Ty) const { @@ -189,26 +208,35 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() { const Function *F = MF->getFunction(); Type *Rt = F->getReturnType(); + SmallString<128> Str; + raw_svector_ostream OS(Str); + bool First = true; if (!Rt->isVoidTy() || !F->arg_empty()) { - SmallString<128> Str; - raw_svector_ostream OS(Str); - bool First = true; for (const Argument &A : F->args()) { - OS << (First ? "" : "\n") << "\t" - ".param " - << toString(A.getType()); + OS << (First ? "" : "\n") << "\t.param " << toString(A.getType()); First = false; } if (!Rt->isVoidTy()) { - OS << (First ? "" : "\n") << "\t" - ".result " - << toString(Rt); + OS << (First ? "" : "\n") << "\t.result " << toString(Rt); First = false; } - OutStreamer->EmitRawText(OS.str()); } + bool FirstVReg = true; + for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) { + unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx); + if (!MRI->use_empty(VReg)) { + if (FirstVReg) { + OS << (First ? "" : "\n") << "\t.local "; + First = false; + } + OS << (FirstVReg ? "" : ", ") << getRegTypeName(VReg); + FirstVReg = false; + } + } + + OutStreamer->EmitRawText(OS.str()); AsmPrinter::EmitFunctionBodyStart(); } @@ -225,7 +253,7 @@ switch (MI->getOpcode()) { case TargetOpcode::COPY: - OS << regToString(MI->getOperand(1).getReg()); + OS << "get_local " << regToString(MI->getOperand(1)); break; case WebAssembly::GLOBAL: // TODO: wasm64 @@ -235,7 +263,7 @@ case WebAssembly::ARGUMENT_I64: case WebAssembly::ARGUMENT_F32: case WebAssembly::ARGUMENT_F64: - OS << argToString(MI->getOperand(1).getImm()); + OS << "get_local " << argToString(MI->getOperand(1)); break; case WebAssembly::Immediate_I32: OS << "i32.const " << MI->getOperand(1).getImm(); @@ -263,7 +291,7 @@ default: llvm_unreachable("unexpected machine operand type"); case MachineOperand::MO_Register: - OS << regToString(MO.getReg()); + OS << "get_local " << regToString(MO); break; case MachineOperand::MO_Immediate: OS << MO.getImm(); @@ -288,9 +316,8 @@ if (NumDefs != 0) { SmallString<128> Str; raw_svector_ostream OS(Str); - OS << "\t" "set_local " - << regToString(MI->getOperand(0).getReg()) << ", " - "pop"; + const MachineOperand &Operand = MI->getOperand(0); + OS << "\tset_local " << regToString(Operand) << ", pop"; OutStreamer->EmitRawText(OS.str()); } } Index: test/CodeGen/WebAssembly/func.ll =================================================================== --- test/CodeGen/WebAssembly/func.ll +++ test/CodeGen/WebAssembly/func.ll @@ -14,9 +14,10 @@ ; CHECK-LABEL: f1: ; CHECK-NEXT: .result i32{{$}} +; CHECK-NEXT: .local i32{{$}} ; CHECK-NEXT: i32.const 0{{$}} -; CHECK-NEXT: set_local @0, pop{{$}} -; CHECK-NEXT: return @0{{$}} +; CHECK-NEXT: set_local 0, pop{{$}} +; CHECK-NEXT: i32.return get_local 0{{$}} ; CHECK: .size f1, define i32 @f1() { ret i32 0 @@ -26,9 +27,10 @@ ; CHECK-NEXT: .param i32{{$}} ; CHECK-NEXT: .param f32{{$}} ; CHECK-NEXT: .result i32{{$}} +; CHECK-NEXT: .local i32{{$}} ; CHECK-NEXT: i32.const 0{{$}} -; CHECK-NEXT: set_local @2, pop{{$}} -; CHECK-NEXT: return @2{{$}} +; CHECK-NEXT: set_local 2, pop{{$}} +; CHECK-NEXT: i32.return get_local 2{{$}} ; CHECK: .size f2, define i32 @f2(i32 %p1, float %p2) { ret i32 0 @@ -37,7 +39,8 @@ ; CHECK-LABEL: f3: ; CHECK-NEXT: .param i32{{$}} ; CHECK-NEXT: .param f32{{$}} -; CHECK-NEXT: return{{$}} +; CHECK-NOT: .local +; CHECK-NEXT: void.return{{$}} ; CHECK: .size f3, define void @f3(i32 %p1, float %p2) { ret void