Dan Gohman | 05ac43f | 2015-12-17 01:39:00 +0000 | [diff] [blame] | 1 | //=- WebAssemblyMCCodeEmitter.cpp - Convert WebAssembly code to machine code -// |
| 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 implements the WebAssemblyMCCodeEmitter class. |
| 12 | /// |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 16 | #include "llvm/ADT/STLExtras.h" |
Dan Gohman | 05ac43f | 2015-12-17 01:39:00 +0000 | [diff] [blame] | 17 | #include "llvm/ADT/Statistic.h" |
| 18 | #include "llvm/MC/MCCodeEmitter.h" |
| 19 | #include "llvm/MC/MCFixup.h" |
| 20 | #include "llvm/MC/MCInst.h" |
| 21 | #include "llvm/MC/MCInstrInfo.h" |
| 22 | #include "llvm/MC/MCRegisterInfo.h" |
| 23 | #include "llvm/MC/MCSubtargetInfo.h" |
| 24 | #include "llvm/MC/MCSymbol.h" |
Reid Kleckner | 8f4bd1f | 2016-06-23 18:12:31 +0000 | [diff] [blame] | 25 | #include "llvm/Support/EndianStream.h" |
Dan Gohman | 4fc4e42 | 2016-10-24 19:49:43 +0000 | [diff] [blame] | 26 | #include "llvm/Support/LEB128.h" |
Dan Gohman | 05ac43f | 2015-12-17 01:39:00 +0000 | [diff] [blame] | 27 | #include "llvm/Support/raw_ostream.h" |
| 28 | using namespace llvm; |
| 29 | |
| 30 | #define DEBUG_TYPE "mccodeemitter" |
| 31 | |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 32 | STATISTIC(MCNumEmitted, "Number of MC instructions emitted."); |
| 33 | STATISTIC(MCNumFixups, "Number of MC fixups created."); |
| 34 | |
Dan Gohman | 05ac43f | 2015-12-17 01:39:00 +0000 | [diff] [blame] | 35 | namespace { |
| 36 | class WebAssemblyMCCodeEmitter final : public MCCodeEmitter { |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 37 | const MCInstrInfo &MCII; |
Dan Gohman | 05ac43f | 2015-12-17 01:39:00 +0000 | [diff] [blame] | 38 | |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 39 | // Implementation generated by tablegen. |
Dan Gohman | 05ac43f | 2015-12-17 01:39:00 +0000 | [diff] [blame] | 40 | uint64_t getBinaryCodeForInstr(const MCInst &MI, |
| 41 | SmallVectorImpl<MCFixup> &Fixups, |
| 42 | const MCSubtargetInfo &STI) const; |
| 43 | |
Dan Gohman | 05ac43f | 2015-12-17 01:39:00 +0000 | [diff] [blame] | 44 | void encodeInstruction(const MCInst &MI, raw_ostream &OS, |
| 45 | SmallVectorImpl<MCFixup> &Fixups, |
| 46 | const MCSubtargetInfo &STI) const override; |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 47 | |
| 48 | public: |
Dan Gohman | 8394756 | 2016-01-20 05:54:22 +0000 | [diff] [blame] | 49 | WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {} |
Dan Gohman | 05ac43f | 2015-12-17 01:39:00 +0000 | [diff] [blame] | 50 | }; |
| 51 | } // end anonymous namespace |
| 52 | |
Dan Gohman | cff7983 | 2016-01-19 21:31:41 +0000 | [diff] [blame] | 53 | MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII) { |
| 54 | return new WebAssemblyMCCodeEmitter(MCII); |
Dan Gohman | 05ac43f | 2015-12-17 01:39:00 +0000 | [diff] [blame] | 55 | } |
| 56 | |
| 57 | void WebAssemblyMCCodeEmitter::encodeInstruction( |
| 58 | const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups, |
| 59 | const MCSubtargetInfo &STI) const { |
Dan Gohman | 4fc4e42 | 2016-10-24 19:49:43 +0000 | [diff] [blame] | 60 | uint64_t Start = OS.tell(); |
| 61 | |
| 62 | uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI); |
Dan Gohman | 3acb187 | 2016-10-24 23:27:49 +0000 | [diff] [blame] | 63 | assert(Binary < UINT8_MAX && "Multi-byte opcodes not supported yet"); |
| 64 | OS << uint8_t(Binary); |
Dan Gohman | 4fc4e42 | 2016-10-24 19:49:43 +0000 | [diff] [blame] | 65 | |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 66 | const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 67 | for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) { |
| 68 | const MCOperand &MO = MI.getOperand(i); |
| 69 | if (MO.isReg()) { |
Dan Gohman | 4fc4e42 | 2016-10-24 19:49:43 +0000 | [diff] [blame] | 70 | /* nothing to encode */ |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 71 | } else if (MO.isImm()) { |
Dan Gohman | 3acb187 | 2016-10-24 23:27:49 +0000 | [diff] [blame] | 72 | if (i < Desc.getNumOperands()) { |
| 73 | assert(Desc.TSFlags == 0 && |
| 74 | "WebAssembly non-variable_ops don't use TSFlags"); |
| 75 | const MCOperandInfo &Info = Desc.OpInfo[i]; |
| 76 | if (Info.OperandType == WebAssembly::OPERAND_I32IMM) { |
| 77 | encodeSLEB128(int32_t(MO.getImm()), OS); |
| 78 | } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) { |
| 79 | encodeSLEB128(int64_t(MO.getImm()), OS); |
| 80 | } else { |
| 81 | encodeULEB128(uint64_t(MO.getImm()), OS); |
| 82 | } |
Dan Gohman | 4fc4e42 | 2016-10-24 19:49:43 +0000 | [diff] [blame] | 83 | } else { |
Dan Gohman | 3acb187 | 2016-10-24 23:27:49 +0000 | [diff] [blame] | 84 | assert(Desc.TSFlags == (WebAssemblyII::VariableOpIsImmediate | |
| 85 | WebAssemblyII::VariableOpImmediateIsLabel)); |
Dan Gohman | 4fc4e42 | 2016-10-24 19:49:43 +0000 | [diff] [blame] | 86 | encodeULEB128(uint64_t(MO.getImm()), OS); |
| 87 | } |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 88 | } else if (MO.isFPImm()) { |
Dan Gohman | 4fc4e42 | 2016-10-24 19:49:43 +0000 | [diff] [blame] | 89 | assert(i < Desc.getNumOperands() && |
| 90 | "Unexpected floating-point immediate as a non-fixed operand"); |
| 91 | assert(Desc.TSFlags == 0 && |
| 92 | "WebAssembly variable_ops floating point ops don't use TSFlags"); |
| 93 | const MCOperandInfo &Info = Desc.OpInfo[i]; |
| 94 | if (Info.OperandType == WebAssembly::OPERAND_F32IMM) { |
| 95 | // TODO: MC converts all floating point immediate operands to double. |
| 96 | // This is fine for numeric values, but may cause NaNs to change bits. |
| 97 | float f = float(MO.getFPImm()); |
| 98 | support::endian::Writer<support::little>(OS).write<float>(f); |
| 99 | } else { |
| 100 | assert(Info.OperandType == WebAssembly::OPERAND_F64IMM); |
| 101 | double d = MO.getFPImm(); |
| 102 | support::endian::Writer<support::little>(OS).write<double>(d); |
| 103 | } |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 104 | } else if (MO.isExpr()) { |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 105 | Fixups.push_back(MCFixup::create( |
Dan Gohman | 4fc4e42 | 2016-10-24 19:49:43 +0000 | [diff] [blame] | 106 | OS.tell() - Start, MO.getExpr(), |
Dan Gohman | 8394756 | 2016-01-20 05:54:22 +0000 | [diff] [blame] | 107 | STI.getTargetTriple().isArch64Bit() ? FK_Data_8 : FK_Data_4, |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 108 | MI.getLoc())); |
| 109 | ++MCNumFixups; |
Dan Gohman | 4fc4e42 | 2016-10-24 19:49:43 +0000 | [diff] [blame] | 110 | encodeULEB128(STI.getTargetTriple().isArch64Bit() ? UINT64_MAX |
| 111 | : uint64_t(UINT32_MAX), |
| 112 | OS); |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 113 | } else { |
| 114 | llvm_unreachable("unexpected operand kind"); |
| 115 | } |
| 116 | } |
Dan Gohman | 05ac43f | 2015-12-17 01:39:00 +0000 | [diff] [blame] | 117 | |
Dan Gohman | 1a42728 | 2016-01-12 03:32:29 +0000 | [diff] [blame] | 118 | ++MCNumEmitted; // Keep track of the # of mi's emitted. |
Dan Gohman | 05ac43f | 2015-12-17 01:39:00 +0000 | [diff] [blame] | 119 | } |
| 120 | |
| 121 | #include "WebAssemblyGenMCCodeEmitter.inc" |