1311116Sdim//===-- WebAssemblyCallIndirectFixup.cpp - Fix call_indirects -------------===// 2311116Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6311116Sdim// 7311116Sdim//===----------------------------------------------------------------------===// 8311116Sdim/// 9311116Sdim/// \file 10341825Sdim/// This file converts pseudo call_indirect instructions into real 11311116Sdim/// call_indirects. 12311116Sdim/// 13311116Sdim/// The order of arguments for a call_indirect is the arguments to the function 14311116Sdim/// call, followed by the function pointer. There's no natural way to express 15311116Sdim/// a machineinstr with varargs followed by one more arg, so we express it as 16311116Sdim/// the function pointer followed by varargs, then rewrite it here. 17311116Sdim/// 18311116Sdim/// We need to rewrite the order of the arguments on the machineinstrs 19311116Sdim/// themselves so that register stackification knows the order they'll be 20311116Sdim/// executed in. 21311116Sdim/// 22311116Sdim//===----------------------------------------------------------------------===// 23311116Sdim 24321369Sdim#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_* 25311116Sdim#include "WebAssembly.h" 26311116Sdim#include "WebAssemblyMachineFunctionInfo.h" 27311116Sdim#include "WebAssemblySubtarget.h" 28311116Sdim#include "llvm/Analysis/AliasAnalysis.h" 29327952Sdim#include "llvm/CodeGen/LiveIntervals.h" 30311116Sdim#include "llvm/CodeGen/MachineBlockFrequencyInfo.h" 31311116Sdim#include "llvm/CodeGen/MachineDominators.h" 32311116Sdim#include "llvm/CodeGen/MachineInstrBuilder.h" 33311116Sdim#include "llvm/CodeGen/MachineRegisterInfo.h" 34311116Sdim#include "llvm/CodeGen/Passes.h" 35311116Sdim#include "llvm/Support/Debug.h" 36311116Sdim#include "llvm/Support/raw_ostream.h" 37311116Sdimusing namespace llvm; 38311116Sdim 39311116Sdim#define DEBUG_TYPE "wasm-call-indirect-fixup" 40311116Sdim 41311116Sdimnamespace { 42311116Sdimclass WebAssemblyCallIndirectFixup final : public MachineFunctionPass { 43311116Sdim StringRef getPassName() const override { 44311116Sdim return "WebAssembly CallIndirect Fixup"; 45311116Sdim } 46311116Sdim 47311116Sdim bool runOnMachineFunction(MachineFunction &MF) override; 48311116Sdim 49311116Sdimpublic: 50311116Sdim static char ID; // Pass identification, replacement for typeid 51311116Sdim WebAssemblyCallIndirectFixup() : MachineFunctionPass(ID) {} 52311116Sdim}; 53311116Sdim} // end anonymous namespace 54311116Sdim 55311116Sdimchar WebAssemblyCallIndirectFixup::ID = 0; 56341825SdimINITIALIZE_PASS(WebAssemblyCallIndirectFixup, DEBUG_TYPE, 57341825Sdim "Rewrite call_indirect argument orderings", false, false) 58341825Sdim 59311116SdimFunctionPass *llvm::createWebAssemblyCallIndirectFixup() { 60311116Sdim return new WebAssemblyCallIndirectFixup(); 61311116Sdim} 62311116Sdim 63353358Sdimstatic unsigned getNonPseudoCallIndirectOpcode(const MachineInstr &MI) { 64311116Sdim switch (MI.getOpcode()) { 65311116Sdim using namespace WebAssembly; 66344779Sdim case PCALL_INDIRECT_VOID: 67344779Sdim return CALL_INDIRECT_VOID; 68353358Sdim case PCALL_INDIRECT_i32: 69353358Sdim return CALL_INDIRECT_i32; 70353358Sdim case PCALL_INDIRECT_i64: 71353358Sdim return CALL_INDIRECT_i64; 72353358Sdim case PCALL_INDIRECT_f32: 73353358Sdim return CALL_INDIRECT_f32; 74353358Sdim case PCALL_INDIRECT_f64: 75353358Sdim return CALL_INDIRECT_f64; 76344779Sdim case PCALL_INDIRECT_v16i8: 77344779Sdim return CALL_INDIRECT_v16i8; 78344779Sdim case PCALL_INDIRECT_v8i16: 79344779Sdim return CALL_INDIRECT_v8i16; 80344779Sdim case PCALL_INDIRECT_v4i32: 81344779Sdim return CALL_INDIRECT_v4i32; 82344779Sdim case PCALL_INDIRECT_v2i64: 83344779Sdim return CALL_INDIRECT_v2i64; 84344779Sdim case PCALL_INDIRECT_v4f32: 85344779Sdim return CALL_INDIRECT_v4f32; 86344779Sdim case PCALL_INDIRECT_v2f64: 87344779Sdim return CALL_INDIRECT_v2f64; 88353358Sdim case PCALL_INDIRECT_exnref: 89353358Sdim return CALL_INDIRECT_exnref; 90353358Sdim case PRET_CALL_INDIRECT: 91353358Sdim return RET_CALL_INDIRECT; 92344779Sdim default: 93344779Sdim return INSTRUCTION_LIST_END; 94311116Sdim } 95311116Sdim} 96311116Sdim 97353358Sdimstatic bool isPseudoCallIndirect(const MachineInstr &MI) { 98353358Sdim return getNonPseudoCallIndirectOpcode(MI) != 99311116Sdim WebAssembly::INSTRUCTION_LIST_END; 100311116Sdim} 101311116Sdim 102311116Sdimbool WebAssemblyCallIndirectFixup::runOnMachineFunction(MachineFunction &MF) { 103341825Sdim LLVM_DEBUG(dbgs() << "********** Fixing up CALL_INDIRECTs **********\n" 104344779Sdim << "********** Function: " << MF.getName() << '\n'); 105311116Sdim 106311116Sdim bool Changed = false; 107311116Sdim const WebAssemblyInstrInfo *TII = 108311116Sdim MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 109311116Sdim 110311116Sdim for (MachineBasicBlock &MBB : MF) { 111311116Sdim for (MachineInstr &MI : MBB) { 112353358Sdim if (isPseudoCallIndirect(MI)) { 113341825Sdim LLVM_DEBUG(dbgs() << "Found call_indirect: " << MI << '\n'); 114311116Sdim 115311116Sdim // Rewrite pseudo to non-pseudo 116353358Sdim const MCInstrDesc &Desc = TII->get(getNonPseudoCallIndirectOpcode(MI)); 117311116Sdim MI.setDesc(Desc); 118311116Sdim 119311116Sdim // Rewrite argument order 120321369Sdim SmallVector<MachineOperand, 8> Ops; 121311116Sdim 122321369Sdim // Set up a placeholder for the type signature immediate. 123321369Sdim Ops.push_back(MachineOperand::CreateImm(0)); 124321369Sdim 125311116Sdim // Set up the flags immediate, which currently has no defined flags 126311116Sdim // so it's always zero. 127321369Sdim Ops.push_back(MachineOperand::CreateImm(0)); 128311116Sdim 129321369Sdim for (const MachineOperand &MO : 130344779Sdim make_range(MI.operands_begin() + MI.getDesc().getNumDefs() + 1, 131344779Sdim MI.operands_begin() + MI.getNumExplicitOperands())) 132321369Sdim Ops.push_back(MO); 133321369Sdim Ops.push_back(MI.getOperand(MI.getDesc().getNumDefs())); 134311116Sdim 135321369Sdim // Replace the instructions operands. 136321369Sdim while (MI.getNumOperands() > MI.getDesc().getNumDefs()) 137321369Sdim MI.RemoveOperand(MI.getNumOperands() - 1); 138321369Sdim for (const MachineOperand &MO : Ops) 139321369Sdim MI.addOperand(MO); 140321369Sdim 141341825Sdim LLVM_DEBUG(dbgs() << " After transform: " << MI); 142311116Sdim Changed = true; 143311116Sdim } 144311116Sdim } 145311116Sdim } 146311116Sdim 147341825Sdim LLVM_DEBUG(dbgs() << "\nDone fixing up CALL_INDIRECTs\n\n"); 148311116Sdim 149311116Sdim return Changed; 150311116Sdim} 151