void EmitJumpTableInfo() override;
void EmitConstantPool() override;
void EmitFunctionBodyStart() override;
-
void EmitInstruction(const MachineInstr *MI) override;
+ void EmitEndOfAsmFile(Module &M) override;
std::string getRegTypeName(unsigned RegNo) const;
static std::string toString(const APFloat &APF);
// 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).
+// underscore). Conversions are additionally prefixed with their input type
+// (before a double underscore).
static std::string OpcodeName(const WebAssemblyInstrInfo *TII,
const MachineInstr *MI) {
std::string N(StringRef(TII->getName(MI->getOpcode())).lower());
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;
+ if (!HasType)
+ return Name;
+ for (const char *typelessOpcode : { "return", "call", "br_if" })
+ if (Name == typelessOpcode)
+ return Name;
+ std::string Type(&N[NameEnd + 1], &N[Len]);
+ std::string::size_type DoubleUnder = Name.find("__");
+ bool IsConv = std::string::npos != DoubleUnder;
+ if (!IsConv)
+ return Type + '.' + Name;
+ std::string InType(&Name[0], &Name[DoubleUnder]);
+ return Type + '.' + std::string(&Name[DoubleUnder + 2], &Name[NameEnd]) +
+ '/' + InType;
}
static std::string toSymbol(StringRef S) { return ("$" + S).str(); }
bool FirstVReg = true;
for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) {
unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx);
- if (!MRI->use_empty(VReg)) {
+ // FIXME: Don't skip dead virtual registers for now: that would require
+ // remapping all locals' numbers.
+ //if (!MRI->use_empty(VReg)) {
if (FirstVReg) {
OS << (First ? "" : "\n") << "\t.local ";
First = false;
}
OS << (FirstVReg ? "" : ", ") << getRegTypeName(VReg);
FirstVReg = false;
- }
+ //}
}
if (!First)
switch (MI->getOpcode()) {
case TargetOpcode::COPY:
- OS << "get_local " << regToString(MI->getOperand(1));
- break;
- case WebAssembly::GLOBAL:
- // TODO: wasm64
- OS << "i32.const " << toSymbol(MI->getOperand(1).getGlobal()->getName());
+ OS << "get_local push, " << regToString(MI->getOperand(1));
break;
case WebAssembly::ARGUMENT_I32:
case WebAssembly::ARGUMENT_I64:
case WebAssembly::ARGUMENT_F32:
case WebAssembly::ARGUMENT_F64:
- OS << "get_local " << argToString(MI->getOperand(1));
- break;
- case WebAssembly::Immediate_I32:
- OS << "i32.const " << MI->getOperand(1).getImm();
- break;
- case WebAssembly::Immediate_I64:
- OS << "i64.const " << MI->getOperand(1).getImm();
- break;
- case WebAssembly::Immediate_F32:
- OS << "f32.const " << toString(MI->getOperand(1).getFPImm()->getValueAPF());
- break;
- case WebAssembly::Immediate_F64:
- OS << "f64.const " << toString(MI->getOperand(1).getFPImm()->getValueAPF());
+ OS << "get_local push, " << argToString(MI->getOperand(1));
break;
default: {
OS << OpcodeName(TII, MI);
bool NeedComma = false;
+ bool DefsPushed = false;
+ if (NumDefs != 0 && !MI->isCall()) {
+ OS << " push";
+ NeedComma = true;
+ DefsPushed = true;
+ }
for (const MachineOperand &MO : MI->uses()) {
if (MO.isReg() && MO.isImplicit())
continue;
OS << toSymbol(MO.getMBB()->getSymbol()->getName());
break;
}
+ if (NumDefs != 0 && !DefsPushed) {
+ // Special-case for calls; print the push after the callee.
+ assert(MI->isCall());
+ OS << ", push";
+ DefsPushed = true;
+ }
}
break;
}
}
}
+void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
+ SmallString<128> Str;
+ raw_svector_ostream OS(Str);
+ for (const Function &F : M)
+ if (F.isDeclarationForLinker()) {
+ assert(F.hasName() && "imported functions must have a name");
+ if (F.getName().startswith("llvm."))
+ continue;
+ if (Str.empty())
+ OS << "\t.imports\n";
+ Type *Rt = F.getReturnType();
+ OS << "\t.import " << toSymbol(F.getName()) << " \"\" \"" << F.getName()
+ << "\" (param";
+ for (const Argument &A : F.args())
+ OS << ' ' << toString(A.getType());
+ OS << ')';
+ if (!Rt->isVoidTy())
+ OS << " (result " << toString(Rt) << ')';
+ OS << '\n';
+ }
+ OutStreamer->EmitRawText(OS.str());
+}
+
// Force static initialization.
extern "C" void LLVMInitializeWebAssemblyAsmPrinter() {
RegisterAsmPrinter<WebAssemblyAsmPrinter> X(TheWebAssemblyTarget32);