LCOV - code coverage report
Current view: top level - lib/Target/WebAssembly - WebAssemblyMCInstLower.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 90 102 88.2 %
Date: 2018-10-20 13:21:21 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // WebAssemblyMCInstLower.cpp - Convert WebAssembly MachineInstr to an MCInst //
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : ///
      10             : /// \file
      11             : /// This file contains code to lower WebAssembly MachineInstrs to their
      12             : /// corresponding MCInst records.
      13             : ///
      14             : //===----------------------------------------------------------------------===//
      15             : 
      16             : #include "WebAssemblyMCInstLower.h"
      17             : #include "WebAssemblyAsmPrinter.h"
      18             : #include "WebAssemblyMachineFunctionInfo.h"
      19             : #include "WebAssemblyRuntimeLibcallSignatures.h"
      20             : #include "WebAssemblyUtilities.h"
      21             : #include "llvm/CodeGen/AsmPrinter.h"
      22             : #include "llvm/CodeGen/MachineFunction.h"
      23             : #include "llvm/IR/Constants.h"
      24             : #include "llvm/MC/MCAsmInfo.h"
      25             : #include "llvm/MC/MCContext.h"
      26             : #include "llvm/MC/MCExpr.h"
      27             : #include "llvm/MC/MCInst.h"
      28             : #include "llvm/MC/MCSymbolWasm.h"
      29             : #include "llvm/Support/ErrorHandling.h"
      30             : #include "llvm/Support/raw_ostream.h"
      31             : using namespace llvm;
      32             : 
      33             : // This disables the removal of registers when lowering into MC, as required
      34             : // by some current tests.
      35             : static cl::opt<bool>
      36             :     WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
      37             :                       cl::desc("WebAssembly: output stack registers in"
      38             :                                " instruction output for test purposes only."),
      39             :                       cl::init(false));
      40             : 
      41             : static unsigned regInstructionToStackInstruction(unsigned OpCode);
      42             : static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
      43             : 
      44             : MCSymbol *
      45         810 : WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
      46         810 :   const GlobalValue *Global = MO.getGlobal();
      47         810 :   MCSymbolWasm *WasmSym = cast<MCSymbolWasm>(Printer.getSymbol(Global));
      48             : 
      49         810 :   if (const auto *FuncTy = dyn_cast<FunctionType>(Global->getValueType())) {
      50         461 :     const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
      51         461 :     const TargetMachine &TM = MF.getTarget();
      52         461 :     const Function &CurrentFunc = MF.getFunction();
      53             : 
      54             :     SmallVector<MVT, 1> ResultMVTs;
      55             :     SmallVector<MVT, 4> ParamMVTs;
      56         461 :     ComputeSignatureVTs(FuncTy, CurrentFunc, TM, ParamMVTs, ResultMVTs);
      57             : 
      58         922 :     auto Signature = SignatureFromMVTs(ResultMVTs, ParamMVTs);
      59             :     WasmSym->setSignature(Signature.get());
      60         461 :     Printer.addSignature(std::move(Signature));
      61             :     WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
      62             :   }
      63             : 
      64         810 :   return WasmSym;
      65             : }
      66             : 
      67         376 : MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
      68             :     const MachineOperand &MO) const {
      69         376 :   const char *Name = MO.getSymbolName();
      70             :   MCSymbolWasm *WasmSym =
      71         752 :       cast<MCSymbolWasm>(Printer.GetExternalSymbolSymbol(Name));
      72         376 :   const WebAssemblySubtarget &Subtarget = Printer.getSubtarget();
      73             : 
      74             :   // __stack_pointer is a global variable; all other external symbols used by
      75             :   // CodeGen are functions.  It's OK to hardcode knowledge of specific symbols
      76             :   // here; this method is precisely there for fetching the signatures of known
      77             :   // Clang-provided symbols.
      78         376 :   if (strcmp(Name, "__stack_pointer") == 0) {
      79             :     WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
      80         254 :     WasmSym->setGlobalType(wasm::WasmGlobalType{
      81             :         uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64
      82             :                                       : wasm::WASM_TYPE_I32),
      83             :         true});
      84         254 :     return WasmSym;
      85             :   }
      86             : 
      87             :   SmallVector<wasm::ValType, 4> Returns;
      88             :   SmallVector<wasm::ValType, 4> Params;
      89         122 :   GetLibcallSignature(Subtarget, Name, Returns, Params);
      90             :   auto Signature =
      91         244 :       make_unique<wasm::WasmSignature>(std::move(Returns), std::move(Params));
      92             :   WasmSym->setSignature(Signature.get());
      93         122 :   Printer.addSignature(std::move(Signature));
      94             :   WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
      95             : 
      96             :   return WasmSym;
      97             : }
      98             : 
      99        1186 : MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym,
     100             :                                                      int64_t Offset,
     101             :                                                      bool IsFunc,
     102             :                                                      bool IsGlob) const {
     103             :   MCSymbolRefExpr::VariantKind VK =
     104        1186 :       IsFunc ? MCSymbolRefExpr::VK_WebAssembly_FUNCTION
     105         603 :              : IsGlob ? MCSymbolRefExpr::VK_WebAssembly_GLOBAL
     106             :                       : MCSymbolRefExpr::VK_None;
     107             : 
     108        1186 :   const MCExpr *Expr = MCSymbolRefExpr::create(Sym, VK, Ctx);
     109             : 
     110        1186 :   if (Offset != 0) {
     111          78 :     if (IsFunc)
     112           0 :       report_fatal_error("Function addresses with offsets not supported");
     113          78 :     if (IsGlob)
     114           0 :       report_fatal_error("Global indexes with offsets not supported");
     115             :     Expr =
     116          78 :         MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, Ctx), Ctx);
     117             :   }
     118             : 
     119        1186 :   return MCOperand::createExpr(Expr);
     120             : }
     121             : 
     122             : // Return the WebAssembly type associated with the given register class.
     123             : static wasm::ValType getType(const TargetRegisterClass *RC) {
     124          75 :   if (RC == &WebAssembly::I32RegClass)
     125             :     return wasm::ValType::I32;
     126          17 :   if (RC == &WebAssembly::I64RegClass)
     127             :     return wasm::ValType::I64;
     128           8 :   if (RC == &WebAssembly::F32RegClass)
     129             :     return wasm::ValType::F32;
     130           5 :   if (RC == &WebAssembly::F64RegClass)
     131             :     return wasm::ValType::F64;
     132           2 :   if (RC == &WebAssembly::V128RegClass)
     133             :     return wasm::ValType::V128;
     134           0 :   llvm_unreachable("Unexpected register class");
     135             : }
     136             : 
     137       24888 : void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
     138             :                                    MCInst &OutMI) const {
     139       24888 :   OutMI.setOpcode(MI->getOpcode());
     140             : 
     141             :   const MCInstrDesc &Desc = MI->getDesc();
     142      141996 :   for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
     143      117108 :     const MachineOperand &MO = MI->getOperand(i);
     144             : 
     145             :     MCOperand MCOp;
     146      117108 :     switch (MO.getType()) {
     147           0 :     default:
     148           0 :       MI->print(errs());
     149           0 :       llvm_unreachable("unknown operand type");
     150           0 :     case MachineOperand::MO_MachineBasicBlock:
     151           0 :       MI->print(errs());
     152           0 :       llvm_unreachable("MachineBasicBlock operand should have been rewritten");
     153             :     case MachineOperand::MO_Register: {
     154             :       // Ignore all implicit register operands.
     155      101169 :       if (MO.isImplicit())
     156       62702 :         continue;
     157             :       const WebAssemblyFunctionInfo &MFI =
     158       38467 :           *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
     159       38467 :       unsigned WAReg = MFI.getWAReg(MO.getReg());
     160       38467 :       MCOp = MCOperand::createReg(WAReg);
     161       38467 :       break;
     162             :     }
     163       14546 :     case MachineOperand::MO_Immediate:
     164       14546 :       if (i < Desc.NumOperands) {
     165       14485 :         const MCOperandInfo &Info = Desc.OpInfo[i];
     166       14485 :         if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
     167          66 :           MCSymbol *Sym = Printer.createTempSymbol("typeindex");
     168             : 
     169             :           SmallVector<wasm::ValType, 4> Returns;
     170             :           SmallVector<wasm::ValType, 4> Params;
     171             : 
     172             :           const MachineRegisterInfo &MRI =
     173          33 :               MI->getParent()->getParent()->getRegInfo();
     174          59 :           for (const MachineOperand &MO : MI->defs())
     175          38 :             Returns.push_back(getType(MRI.getRegClass(MO.getReg())));
     176         148 :           for (const MachineOperand &MO : MI->explicit_uses())
     177         115 :             if (MO.isReg())
     178          54 :               Params.push_back(getType(MRI.getRegClass(MO.getReg())));
     179             : 
     180             :           // call_indirect instructions have a callee operand at the end which
     181             :           // doesn't count as a param.
     182          33 :           if (WebAssembly::isCallIndirect(*MI))
     183             :             Params.pop_back();
     184             : 
     185             :           MCSymbolWasm *WasmSym = cast<MCSymbolWasm>(Sym);
     186             :           auto Signature = make_unique<wasm::WasmSignature>(std::move(Returns),
     187          33 :                                                             std::move(Params));
     188             :           WasmSym->setSignature(Signature.get());
     189          33 :           Printer.addSignature(std::move(Signature));
     190             :           WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
     191             : 
     192          33 :           const MCExpr *Expr = MCSymbolRefExpr::create(
     193          33 :               WasmSym, MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX, Ctx);
     194          33 :           MCOp = MCOperand::createExpr(Expr);
     195             :           break;
     196             :         }
     197             :       }
     198       14513 :       MCOp = MCOperand::createImm(MO.getImm());
     199       14513 :       break;
     200         207 :     case MachineOperand::MO_FPImmediate: {
     201             :       // TODO: MC converts all floating point immediate operands to double.
     202             :       // This is fine for numeric values, but may cause NaNs to change bits.
     203         207 :       const ConstantFP *Imm = MO.getFPImm();
     204         414 :       if (Imm->getType()->isFloatTy())
     205         101 :         MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToFloat());
     206         106 :       else if (Imm->getType()->isDoubleTy())
     207         106 :         MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToDouble());
     208             :       else
     209           0 :         llvm_unreachable("unknown floating point immediate type");
     210             :       break;
     211             :     }
     212         810 :     case MachineOperand::MO_GlobalAddress:
     213             :       assert(MO.getTargetFlags() == WebAssemblyII::MO_NO_FLAG &&
     214             :              "WebAssembly does not use target flags on GlobalAddresses");
     215             :       MCOp = LowerSymbolOperand(GetGlobalAddressSymbol(MO), MO.getOffset(),
     216         810 :                                 MO.getGlobal()->getValueType()->isFunctionTy(),
     217        1620 :                                 false);
     218         810 :       break;
     219             :     case MachineOperand::MO_ExternalSymbol:
     220             :       // The target flag indicates whether this is a symbol for a
     221             :       // variable or a function.
     222             :       assert((MO.getTargetFlags() & ~WebAssemblyII::MO_SYMBOL_MASK) == 0 &&
     223             :              "WebAssembly uses only symbol flags on ExternalSymbols");
     224             :       MCOp = LowerSymbolOperand(
     225             :           GetExternalSymbolSymbol(MO), /*Offset=*/0,
     226         376 :           (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_FUNCTION) != 0,
     227         752 :           (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_GLOBAL) != 0);
     228         376 :       break;
     229             :     }
     230             : 
     231             :     OutMI.addOperand(MCOp);
     232             :   }
     233             : 
     234       24888 :   if (!WasmKeepRegisters)
     235        3156 :     removeRegisterOperands(MI, OutMI);
     236       24888 : }
     237             : 
     238        3156 : static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
     239             :   // Remove all uses of stackified registers to bring the instruction format
     240             :   // into its final stack form used thruout MC, and transition opcodes to
     241             :   // their _S variant.
     242             :   // We do this seperate from the above code that still may need these
     243             :   // registers for e.g. call_indirect signatures.
     244             :   // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
     245             :   // details.
     246             :   // TODO: the code above creates new registers which are then removed here.
     247             :   // That code could be slightly simplified by not doing that, though maybe
     248             :   // it is simpler conceptually to keep the code above in "register mode"
     249             :   // until this transition point.
     250             :   // FIXME: we are not processing inline assembly, which contains register
     251             :   // operands, because it is used by later target generic code.
     252        3156 :   if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm())
     253             :     return;
     254             : 
     255             :   // Transform to _S instruction.
     256        3156 :   auto RegOpcode = OutMI.getOpcode();
     257        3156 :   auto StackOpcode = regInstructionToStackInstruction(RegOpcode);
     258             :   OutMI.setOpcode(StackOpcode);
     259             : 
     260             :   // Remove register operands.
     261        8851 :   for (auto I = OutMI.getNumOperands(); I; --I) {
     262        5695 :     auto &MO = OutMI.getOperand(I - 1);
     263        5695 :     if (MO.isReg()) {
     264             :       OutMI.erase(&MO);
     265             :     }
     266             :   }
     267             : }
     268             : 
     269        3156 : static unsigned regInstructionToStackInstruction(unsigned OpCode) {
     270             :   // For most opcodes, this function could have been implemented as "return
     271             :   // OpCode + 1", but since table-gen alphabetically sorts them, this cannot be
     272             :   // guaranteed (see e.g. BR and BR_IF). Instead we use a giant switch statement
     273             :   // generated by a custom TableGen backend (WebAssemblyStackifierEmitter.cpp)
     274             :   // that emits switch cases of the form
     275             :   //
     276             :   //   case WebAssembly::RegisterInstr: return WebAssembly::StackInstr;
     277             :   //
     278             :   // for every pair of equivalent register and stack instructions.
     279        3156 :   switch (OpCode) {
     280           0 :   default:
     281           0 :     llvm_unreachable(
     282             :         "unknown WebAssembly instruction in WebAssemblyMCInstLower pass");
     283             : #include "WebAssemblyGenStackifier.inc"
     284             :   }
     285             : }

Generated by: LCOV version 1.13