//===-- WebAssemblyCallIndirectFixup.cpp - Fix call_indirects -------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief This file converts pseudo call_indirect instructions into real /// call_indirects. /// /// The order of arguments for a call_indirect is the arguments to the function /// call, followed by the function pointer. There's no natural way to express /// a machineinstr with varargs followed by one more arg, so we express it as /// the function pointer followed by varargs, then rewrite it here. /// /// We need to rewrite the order of the arguments on the machineinstrs /// themselves so that register stackification knows the order they'll be /// executed in. /// //===----------------------------------------------------------------------===// #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_* #include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/CodeGen/LiveIntervals.h" #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; #define DEBUG_TYPE "wasm-call-indirect-fixup" namespace { class WebAssemblyCallIndirectFixup final : public MachineFunctionPass { StringRef getPassName() const override { return "WebAssembly CallIndirect Fixup"; } bool runOnMachineFunction(MachineFunction &MF) override; public: static char ID; // Pass identification, replacement for typeid WebAssemblyCallIndirectFixup() : MachineFunctionPass(ID) {} }; } // end anonymous namespace char WebAssemblyCallIndirectFixup::ID = 0; FunctionPass *llvm::createWebAssemblyCallIndirectFixup() { return new WebAssemblyCallIndirectFixup(); } static unsigned GetNonPseudoCallIndirectOpcode(const MachineInstr &MI) { switch (MI.getOpcode()) { using namespace WebAssembly; case PCALL_INDIRECT_VOID: return CALL_INDIRECT_VOID; case PCALL_INDIRECT_I32: return CALL_INDIRECT_I32; case PCALL_INDIRECT_I64: return CALL_INDIRECT_I64; case PCALL_INDIRECT_F32: return CALL_INDIRECT_F32; case PCALL_INDIRECT_F64: return CALL_INDIRECT_F64; case PCALL_INDIRECT_v16i8: return CALL_INDIRECT_v16i8; case PCALL_INDIRECT_v8i16: return CALL_INDIRECT_v8i16; case PCALL_INDIRECT_v4i32: return CALL_INDIRECT_v4i32; case PCALL_INDIRECT_v4f32: return CALL_INDIRECT_v4f32; default: return INSTRUCTION_LIST_END; } } static bool IsPseudoCallIndirect(const MachineInstr &MI) { return GetNonPseudoCallIndirectOpcode(MI) != WebAssembly::INSTRUCTION_LIST_END; } bool WebAssemblyCallIndirectFixup::runOnMachineFunction(MachineFunction &MF) { DEBUG(dbgs() << "********** Fixing up CALL_INDIRECTs **********\n" << MF.getName() << '\n'); bool Changed = false; const WebAssemblyInstrInfo *TII = MF.getSubtarget().getInstrInfo(); for (MachineBasicBlock &MBB : MF) { for (MachineInstr &MI : MBB) { if (IsPseudoCallIndirect(MI)) { DEBUG(dbgs() << "Found call_indirect: " << MI << '\n'); // Rewrite pseudo to non-pseudo const MCInstrDesc &Desc = TII->get(GetNonPseudoCallIndirectOpcode(MI)); MI.setDesc(Desc); // Rewrite argument order SmallVector Ops; // Set up a placeholder for the type signature immediate. Ops.push_back(MachineOperand::CreateImm(0)); // Set up the flags immediate, which currently has no defined flags // so it's always zero. Ops.push_back(MachineOperand::CreateImm(0)); for (const MachineOperand &MO : make_range(MI.operands_begin() + MI.getDesc().getNumDefs() + 1, MI.operands_begin() + MI.getNumExplicitOperands())) Ops.push_back(MO); Ops.push_back(MI.getOperand(MI.getDesc().getNumDefs())); // Replace the instructions operands. while (MI.getNumOperands() > MI.getDesc().getNumDefs()) MI.RemoveOperand(MI.getNumOperands() - 1); for (const MachineOperand &MO : Ops) MI.addOperand(MO); DEBUG(dbgs() << " After transform: " << MI); Changed = true; } } } DEBUG(dbgs() << "\nDone fixing up CALL_INDIRECTs\n\n"); return Changed; }