WebAssemblyMCInstLower.cpp revision 294024
1292915Sdim// WebAssemblyMCInstLower.cpp - Convert WebAssembly MachineInstr to an MCInst //
2292915Sdim//
3292915Sdim//                     The LLVM Compiler Infrastructure
4292915Sdim//
5292915Sdim// This file is distributed under the University of Illinois Open Source
6292915Sdim// License. See LICENSE.TXT for details.
7292915Sdim//
8292915Sdim//===----------------------------------------------------------------------===//
9292915Sdim///
10292915Sdim/// \file
11292915Sdim/// \brief This file contains code to lower WebAssembly MachineInstrs to their
12292915Sdim/// corresponding MCInst records.
13292915Sdim///
14292915Sdim//===----------------------------------------------------------------------===//
15292915Sdim
16292915Sdim#include "WebAssemblyMCInstLower.h"
17292915Sdim#include "WebAssemblyMachineFunctionInfo.h"
18292915Sdim#include "llvm/CodeGen/AsmPrinter.h"
19292915Sdim#include "llvm/CodeGen/MachineFunction.h"
20292915Sdim#include "llvm/IR/Constants.h"
21292915Sdim#include "llvm/MC/MCAsmInfo.h"
22292915Sdim#include "llvm/MC/MCContext.h"
23292915Sdim#include "llvm/MC/MCExpr.h"
24292915Sdim#include "llvm/MC/MCInst.h"
25292915Sdim#include "llvm/Support/ErrorHandling.h"
26292915Sdim#include "llvm/Support/raw_ostream.h"
27292915Sdimusing namespace llvm;
28292915Sdim
29292915SdimMCSymbol *
30292915SdimWebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
31292915Sdim  return Printer.getSymbol(MO.getGlobal());
32292915Sdim}
33292915Sdim
34292915SdimMCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
35292915Sdim    const MachineOperand &MO) const {
36292915Sdim  return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
37292915Sdim}
38292915Sdim
39294024SdimMCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym,
40294024Sdim                                                     int64_t Offset,
41294024Sdim                                                     bool IsFunc) const {
42294024Sdim  MCSymbolRefExpr::VariantKind VK =
43294024Sdim      IsFunc ? MCSymbolRefExpr::VK_WebAssembly_FUNCTION
44294024Sdim             : MCSymbolRefExpr::VK_None;
45294024Sdim  const MCExpr *Expr = MCSymbolRefExpr::create(Sym, VK, Ctx);
46292915Sdim
47292915Sdim  if (Offset != 0) {
48294024Sdim    if (IsFunc)
49294024Sdim      report_fatal_error("Function addresses with offsets not supported");
50292915Sdim    Expr =
51292915Sdim        MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, Ctx), Ctx);
52292915Sdim  }
53292915Sdim
54292915Sdim  return MCOperand::createExpr(Expr);
55292915Sdim}
56292915Sdim
57292915Sdimvoid WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
58292915Sdim                                   MCInst &OutMI) const {
59292915Sdim  OutMI.setOpcode(MI->getOpcode());
60292915Sdim
61292915Sdim  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
62292915Sdim    const MachineOperand &MO = MI->getOperand(i);
63292915Sdim
64292915Sdim    MCOperand MCOp;
65292915Sdim    switch (MO.getType()) {
66292915Sdim    default:
67292915Sdim      MI->dump();
68292915Sdim      llvm_unreachable("unknown operand type");
69294024Sdim    case MachineOperand::MO_MachineBasicBlock:
70294024Sdim      MI->dump();
71294024Sdim      llvm_unreachable("MachineBasicBlock operand should have been rewritten");
72292915Sdim    case MachineOperand::MO_Register: {
73292915Sdim      // Ignore all implicit register operands.
74292915Sdim      if (MO.isImplicit())
75292915Sdim        continue;
76292915Sdim      const WebAssemblyFunctionInfo &MFI =
77292915Sdim          *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
78292915Sdim      unsigned WAReg = MFI.getWAReg(MO.getReg());
79292915Sdim      MCOp = MCOperand::createReg(WAReg);
80292915Sdim      break;
81292915Sdim    }
82292915Sdim    case MachineOperand::MO_Immediate:
83292915Sdim      MCOp = MCOperand::createImm(MO.getImm());
84292915Sdim      break;
85292915Sdim    case MachineOperand::MO_FPImmediate: {
86292915Sdim      // TODO: MC converts all floating point immediate operands to double.
87292915Sdim      // This is fine for numeric values, but may cause NaNs to change bits.
88292915Sdim      const ConstantFP *Imm = MO.getFPImm();
89292915Sdim      if (Imm->getType()->isFloatTy())
90292915Sdim        MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToFloat());
91292915Sdim      else if (Imm->getType()->isDoubleTy())
92292915Sdim        MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToDouble());
93292915Sdim      else
94292915Sdim        llvm_unreachable("unknown floating point immediate type");
95292915Sdim      break;
96292915Sdim    }
97292915Sdim    case MachineOperand::MO_GlobalAddress:
98294024Sdim      assert(MO.getTargetFlags() == 0 &&
99294024Sdim             "WebAssembly does not use target flags on GlobalAddresses");
100294024Sdim      MCOp = LowerSymbolOperand(GetGlobalAddressSymbol(MO), MO.getOffset(),
101294024Sdim                                MO.getGlobal()->getValueType()->isFunctionTy());
102292915Sdim      break;
103292915Sdim    case MachineOperand::MO_ExternalSymbol:
104294024Sdim      // The target flag indicates whether this is a symbol for a
105294024Sdim      // variable or a function.
106294024Sdim      assert((MO.getTargetFlags() & -2) == 0 &&
107294024Sdim             "WebAssembly uses only one target flag bit on ExternalSymbols");
108294024Sdim      MCOp = LowerSymbolOperand(GetExternalSymbolSymbol(MO), /*Offset=*/0,
109294024Sdim                                MO.getTargetFlags() & 1);
110292915Sdim      break;
111292915Sdim    }
112292915Sdim
113292915Sdim    OutMI.addOperand(MCOp);
114292915Sdim  }
115292915Sdim}
116