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/// \brief This file contains code to lower WebAssembly MachineInstrs to their
12/// corresponding MCInst records.
13///
14//===----------------------------------------------------------------------===//
15
16#include "WebAssemblyMCInstLower.h"
17#include "WebAssemblyMachineFunctionInfo.h"
18#include "llvm/CodeGen/AsmPrinter.h"
19#include "llvm/CodeGen/MachineFunction.h"
20#include "llvm/IR/Constants.h"
21#include "llvm/MC/MCAsmInfo.h"
22#include "llvm/MC/MCContext.h"
23#include "llvm/MC/MCExpr.h"
24#include "llvm/MC/MCInst.h"
25#include "llvm/Support/ErrorHandling.h"
26#include "llvm/Support/raw_ostream.h"
27using namespace llvm;
28
29MCSymbol *
30WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
31  return Printer.getSymbol(MO.getGlobal());
32}
33
34MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
35    const MachineOperand &MO) const {
36  return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
37}
38
39MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym,
40                                                     int64_t Offset,
41                                                     bool IsFunc) const {
42  MCSymbolRefExpr::VariantKind VK =
43      IsFunc ? MCSymbolRefExpr::VK_WebAssembly_FUNCTION
44             : MCSymbolRefExpr::VK_None;
45  const MCExpr *Expr = MCSymbolRefExpr::create(Sym, VK, Ctx);
46
47  if (Offset != 0) {
48    if (IsFunc)
49      report_fatal_error("Function addresses with offsets not supported");
50    Expr =
51        MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, Ctx), Ctx);
52  }
53
54  return MCOperand::createExpr(Expr);
55}
56
57void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
58                                   MCInst &OutMI) const {
59  OutMI.setOpcode(MI->getOpcode());
60
61  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
62    const MachineOperand &MO = MI->getOperand(i);
63
64    MCOperand MCOp;
65    switch (MO.getType()) {
66    default:
67      MI->dump();
68      llvm_unreachable("unknown operand type");
69    case MachineOperand::MO_MachineBasicBlock:
70      MI->dump();
71      llvm_unreachable("MachineBasicBlock operand should have been rewritten");
72    case MachineOperand::MO_Register: {
73      // Ignore all implicit register operands.
74      if (MO.isImplicit())
75        continue;
76      const WebAssemblyFunctionInfo &MFI =
77          *MI->getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
78      unsigned WAReg = MFI.getWAReg(MO.getReg());
79      MCOp = MCOperand::createReg(WAReg);
80      break;
81    }
82    case MachineOperand::MO_Immediate:
83      MCOp = MCOperand::createImm(MO.getImm());
84      break;
85    case MachineOperand::MO_FPImmediate: {
86      // TODO: MC converts all floating point immediate operands to double.
87      // This is fine for numeric values, but may cause NaNs to change bits.
88      const ConstantFP *Imm = MO.getFPImm();
89      if (Imm->getType()->isFloatTy())
90        MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToFloat());
91      else if (Imm->getType()->isDoubleTy())
92        MCOp = MCOperand::createFPImm(Imm->getValueAPF().convertToDouble());
93      else
94        llvm_unreachable("unknown floating point immediate type");
95      break;
96    }
97    case MachineOperand::MO_GlobalAddress:
98      assert(MO.getTargetFlags() == 0 &&
99             "WebAssembly does not use target flags on GlobalAddresses");
100      MCOp = LowerSymbolOperand(GetGlobalAddressSymbol(MO), MO.getOffset(),
101                                MO.getGlobal()->getValueType()->isFunctionTy());
102      break;
103    case MachineOperand::MO_ExternalSymbol:
104      // The target flag indicates whether this is a symbol for a
105      // variable or a function.
106      assert((MO.getTargetFlags() & -2) == 0 &&
107             "WebAssembly uses only one target flag bit on ExternalSymbols");
108      MCOp = LowerSymbolOperand(GetExternalSymbolSymbol(MO), /*Offset=*/0,
109                                MO.getTargetFlags() & 1);
110      break;
111    }
112
113    OutMI.addOperand(MCOp);
114  }
115}
116