#include "llvm/Support/Debug.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
-
using namespace llvm;
#define DEBUG_TYPE "asm-printer"
// MachineFunctionPass Implementation.
//===------------------------------------------------------------------===//
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AsmPrinter::getAnalysisUsage(AU);
- }
-
bool runOnMachineFunction(MachineFunction &MF) override {
MRI = &MF.getRegInfo();
MFI = MF.getInfo<WebAssemblyFunctionInfo>();
void EmitConstantPool() override;
void EmitFunctionBodyStart() override;
void EmitInstruction(const MachineInstr *MI) override;
- void EmitEndOfAsmFile(Module &M) override;
-
- std::string getRegTypeName(unsigned RegNo) const;
+ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &OS) override;
+ bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &OS) override;
+
+ MVT getRegType(unsigned RegNo) const;
const char *toString(MVT VT) const;
std::string regToString(const MachineOperand &MO);
};
// Helpers.
//===----------------------------------------------------------------------===//
-std::string WebAssemblyAsmPrinter::getRegTypeName(unsigned RegNo) const {
+MVT WebAssemblyAsmPrinter::getRegType(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();
+ return T;
DEBUG(errs() << "Unknown type for register number: " << RegNo);
llvm_unreachable("Unknown register type");
- return "?";
+ return MVT::Other;
}
std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) {
unsigned RegNo = MO.getReg();
- if (TargetRegisterInfo::isPhysicalRegister(RegNo))
- return WebAssemblyInstPrinter::getRegisterName(RegNo);
-
- return utostr(MFI->getWAReg(RegNo));
+ assert(TargetRegisterInfo::isVirtualRegister(RegNo) &&
+ "Unlowered physical register encountered during assembly printing");
+ assert(!MFI->isVRegStackified(RegNo));
+ unsigned WAReg = MFI->getWAReg(RegNo);
+ assert(WAReg != WebAssemblyFunctionInfo::UnusedReg);
+ return '$' + utostr(WAReg);
}
const char *WebAssemblyAsmPrinter::toString(MVT VT) const {
- switch (VT.SimpleTy) {
- default:
- break;
- case MVT::f32:
- return "f32";
- case MVT::f64:
- return "f64";
- case MVT::i32:
- return "i32";
- case MVT::i64:
- return "i64";
- }
- DEBUG(dbgs() << "Invalid type " << EVT(VT).getEVTString() << '\n');
- llvm_unreachable("invalid type");
- return "<invalid>";
+ return WebAssembly::TypeToString(VT);
}
//===----------------------------------------------------------------------===//
// Nothing to do; jump tables are incorporated into the instruction stream.
}
+static void ComputeLegalValueVTs(const Function &F, const TargetMachine &TM,
+ Type *Ty, SmallVectorImpl<MVT> &ValueVTs) {
+ const DataLayout &DL(F.getParent()->getDataLayout());
+ const WebAssemblyTargetLowering &TLI =
+ *TM.getSubtarget<WebAssemblySubtarget>(F).getTargetLowering();
+ SmallVector<EVT, 4> VTs;
+ ComputeValueVTs(TLI, DL, Ty, VTs);
+
+ for (EVT VT : VTs) {
+ unsigned NumRegs = TLI.getNumRegisters(F.getContext(), VT);
+ MVT RegisterVT = TLI.getRegisterType(F.getContext(), VT);
+ for (unsigned i = 0; i != NumRegs; ++i)
+ ValueVTs.push_back(RegisterVT);
+ }
+}
+
void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
- SmallString<128> Str;
- raw_svector_ostream OS(Str);
+ if (!MFI->getParams().empty()) {
+ MCInst Param;
+ Param.setOpcode(WebAssembly::PARAM);
+ for (MVT VT : MFI->getParams())
+ Param.addOperand(MCOperand::createImm(VT.SimpleTy));
+ EmitToStreamer(*OutStreamer, Param);
+ }
- for (MVT VT : MFI->getParams())
- OS << "\t" ".param " << toString(VT) << '\n';
- for (MVT VT : MFI->getResults())
- OS << "\t" ".result " << toString(VT) << '\n';
+ SmallVector<MVT, 4> ResultVTs;
+ const Function &F(*MF->getFunction());
+ ComputeLegalValueVTs(F, TM, F.getReturnType(), ResultVTs);
+ // If the return type needs to be legalized it will get converted into
+ // passing a pointer.
+ if (ResultVTs.size() == 1) {
+ MCInst Result;
+ Result.setOpcode(WebAssembly::RESULT);
+ Result.addOperand(MCOperand::createImm(ResultVTs.front().SimpleTy));
+ EmitToStreamer(*OutStreamer, Result);
+ }
- bool FirstVReg = true;
+ bool AnyWARegs = false;
+ MCInst Local;
+ Local.setOpcode(WebAssembly::LOCAL);
for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) {
unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx);
- if (!MRI->use_empty(VReg)) {
- if (FirstVReg)
- OS << "\t" ".local ";
- else
- OS << ", ";
- OS << getRegTypeName(VReg);
- FirstVReg = false;
- }
+ unsigned WAReg = MFI->getWAReg(VReg);
+ // Don't declare unused registers.
+ if (WAReg == WebAssemblyFunctionInfo::UnusedReg)
+ continue;
+ // Don't redeclare parameters.
+ if (WAReg < MFI->getParams().size())
+ continue;
+ // Don't declare stackified registers.
+ if (int(WAReg) < 0)
+ continue;
+ Local.addOperand(MCOperand::createImm(getRegType(VReg).SimpleTy));
+ AnyWARegs = true;
}
- if (!FirstVReg)
- OS << '\n';
+ if (AnyWARegs)
+ EmitToStreamer(*OutStreamer, Local);
- // EmitRawText appends a newline, so strip off the last newline.
- StringRef Text = OS.str();
- if (!Text.empty())
- OutStreamer->EmitRawText(Text.substr(0, Text.size() - 1));
AsmPrinter::EmitFunctionBodyStart();
}
void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n');
- assert(MI->getDesc().getNumDefs() <= 1 &&
- "Instructions with multiple result values not implemented");
-
switch (MI->getOpcode()) {
- case TargetOpcode::COPY: {
- // TODO: Figure out a way to lower COPY instructions to MCInst form.
- SmallString<128> Str;
- raw_svector_ostream OS(Str);
- OS << "\t" "set_local " << regToString(MI->getOperand(0)) << ", "
- "(get_local " << regToString(MI->getOperand(1)) << ")";
- OutStreamer->EmitRawText(OS.str());
- break;
- }
case WebAssembly::ARGUMENT_I32:
case WebAssembly::ARGUMENT_I64:
case WebAssembly::ARGUMENT_F32:
// These represent values which are live into the function entry, so there's
// no instruction to emit.
break;
+ case WebAssembly::LOOP_END:
+ // This is a no-op which just exists to tell AsmPrinter.cpp that there's a
+ // fallthrough which nevertheless requires a label for the destination here.
+ break;
default: {
WebAssemblyMCInstLower MCInstLowering(OutContext, *this);
MCInst TmpInst;
}
}
-static void ComputeLegalValueVTs(LLVMContext &Context,
- const WebAssemblyTargetLowering &TLI,
- const DataLayout &DL, Type *Ty,
- SmallVectorImpl<MVT> &ValueVTs) {
- SmallVector<EVT, 4> VTs;
- ComputeValueVTs(TLI, DL, Ty, VTs);
-
- for (EVT VT : VTs) {
- unsigned NumRegs = TLI.getNumRegisters(Context, VT);
- MVT RegisterVT = TLI.getRegisterType(Context, VT);
- for (unsigned i = 0; i != NumRegs; ++i)
- ValueVTs.push_back(RegisterVT);
+bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI,
+ unsigned OpNo, unsigned AsmVariant,
+ const char *ExtraCode,
+ raw_ostream &OS) {
+ if (AsmVariant != 0)
+ report_fatal_error("There are no defined alternate asm variants");
+
+ // First try the generic code, which knows about modifiers like 'c' and 'n'.
+ if (!AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, OS))
+ return false;
+
+ if (!ExtraCode) {
+ const MachineOperand &MO = MI->getOperand(OpNo);
+ switch (MO.getType()) {
+ case MachineOperand::MO_Immediate:
+ OS << MO.getImm();
+ return false;
+ case MachineOperand::MO_Register:
+ OS << regToString(MO);
+ return false;
+ case MachineOperand::MO_GlobalAddress:
+ getSymbol(MO.getGlobal())->print(OS, MAI);
+ printOffset(MO.getOffset(), OS);
+ return false;
+ case MachineOperand::MO_ExternalSymbol:
+ GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI);
+ printOffset(MO.getOffset(), OS);
+ return false;
+ case MachineOperand::MO_MachineBasicBlock:
+ MO.getMBB()->getSymbol()->print(OS, MAI);
+ return false;
+ default:
+ break;
+ }
}
+
+ return true;
}
-void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
- const DataLayout &DL = M.getDataLayout();
-
- 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.isIntrinsic())
- continue;
- if (Str.empty())
- OS << "\t.imports\n";
-
- MCSymbol *Sym = OutStreamer->getContext().getOrCreateSymbol(F.getName());
- OS << "\t.import " << *Sym << " \"\" " << *Sym;
-
- const WebAssemblyTargetLowering &TLI =
- *TM.getSubtarget<WebAssemblySubtarget>(F).getTargetLowering();
-
- // If we need to legalize the return type, it'll get converted into
- // passing a pointer.
- bool SawParam = false;
- SmallVector<MVT, 4> ResultVTs;
- ComputeLegalValueVTs(M.getContext(), TLI, DL, F.getReturnType(),
- ResultVTs);
- if (ResultVTs.size() > 1) {
- ResultVTs.clear();
- OS << " (param " << toString(TLI.getPointerTy(DL));
- SawParam = true;
- }
-
- for (const Argument &A : F.args()) {
- SmallVector<MVT, 4> ParamVTs;
- ComputeLegalValueVTs(M.getContext(), TLI, DL, A.getType(), ParamVTs);
- for (EVT VT : ParamVTs) {
- if (!SawParam) {
- OS << " (param";
- SawParam = true;
- }
- OS << ' ' << toString(VT.getSimpleVT());
- }
- }
- if (SawParam)
- OS << ')';
-
- for (EVT VT : ResultVTs)
- OS << " (result " << toString(VT.getSimpleVT()) << ')';
-
- OS << '\n';
- }
+bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
+ unsigned OpNo,
+ unsigned AsmVariant,
+ const char *ExtraCode,
+ raw_ostream &OS) {
+ if (AsmVariant != 0)
+ report_fatal_error("There are no defined alternate asm variants");
+
+ if (!ExtraCode) {
+ // TODO: For now, we just hard-code 0 as the constant offset; teach
+ // SelectInlineAsmMemoryOperand how to do address mode matching.
+ OS << "0(" + regToString(MI->getOperand(OpNo)) + ')';
+ return false;
+ }
- StringRef Text = OS.str();
- if (!Text.empty())
- OutStreamer->EmitRawText(Text.substr(0, Text.size() - 1));
+ return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, AsmVariant, ExtraCode, OS);
}
// Force static initialization.