1303231Sdim//===-- LanaiMCCodeEmitter.cpp - Convert Lanai code to machine code -------===//
2303231Sdim//
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
6303231Sdim//
7303231Sdim//===----------------------------------------------------------------------===//
8303231Sdim//
9303231Sdim// This file implements the LanaiMCCodeEmitter class.
10303231Sdim//
11303231Sdim//===----------------------------------------------------------------------===//
12303231Sdim
13353358Sdim#include "LanaiAluCode.h"
14303231Sdim#include "MCTargetDesc/LanaiBaseInfo.h"
15303231Sdim#include "MCTargetDesc/LanaiFixupKinds.h"
16303231Sdim#include "MCTargetDesc/LanaiMCExpr.h"
17314564Sdim#include "llvm/ADT/SmallVector.h"
18303231Sdim#include "llvm/ADT/Statistic.h"
19303231Sdim#include "llvm/MC/MCCodeEmitter.h"
20321369Sdim#include "llvm/MC/MCExpr.h"
21303231Sdim#include "llvm/MC/MCFixup.h"
22303231Sdim#include "llvm/MC/MCInst.h"
23303231Sdim#include "llvm/MC/MCInstrInfo.h"
24303231Sdim#include "llvm/MC/MCRegisterInfo.h"
25303231Sdim#include "llvm/MC/MCSubtargetInfo.h"
26314564Sdim#include "llvm/Support/Casting.h"
27303231Sdim#include "llvm/Support/raw_ostream.h"
28314564Sdim#include <cassert>
29314564Sdim#include <cstdint>
30303231Sdim
31303231Sdim#define DEBUG_TYPE "mccodeemitter"
32303231Sdim
33303231SdimSTATISTIC(MCNumEmitted, "Number of MC instructions emitted");
34303231Sdim
35303231Sdimnamespace llvm {
36314564Sdim
37303231Sdimnamespace {
38314564Sdim
39303231Sdimclass LanaiMCCodeEmitter : public MCCodeEmitter {
40303231Sdimpublic:
41314564Sdim  LanaiMCCodeEmitter(const MCInstrInfo &MCII, MCContext &C) {}
42314564Sdim  LanaiMCCodeEmitter(const LanaiMCCodeEmitter &) = delete;
43314564Sdim  void operator=(const LanaiMCCodeEmitter &) = delete;
44314564Sdim  ~LanaiMCCodeEmitter() override = default;
45303231Sdim
46303231Sdim  // The functions below are called by TableGen generated functions for getting
47303231Sdim  // the binary encoding of instructions/opereands.
48303231Sdim
49303231Sdim  // getBinaryCodeForInstr - TableGen'erated function for getting the
50303231Sdim  // binary encoding for an instruction.
51303231Sdim  uint64_t getBinaryCodeForInstr(const MCInst &Inst,
52303231Sdim                                 SmallVectorImpl<MCFixup> &Fixups,
53303231Sdim                                 const MCSubtargetInfo &SubtargetInfo) const;
54303231Sdim
55303231Sdim  // getMachineOpValue - Return binary encoding of operand. If the machine
56303231Sdim  // operand requires relocation, record the relocation and return zero.
57303231Sdim  unsigned getMachineOpValue(const MCInst &Inst, const MCOperand &MCOp,
58303231Sdim                             SmallVectorImpl<MCFixup> &Fixups,
59303231Sdim                             const MCSubtargetInfo &SubtargetInfo) const;
60303231Sdim
61303231Sdim  unsigned getRiMemoryOpValue(const MCInst &Inst, unsigned OpNo,
62303231Sdim                              SmallVectorImpl<MCFixup> &Fixups,
63303231Sdim                              const MCSubtargetInfo &SubtargetInfo) const;
64303231Sdim
65303231Sdim  unsigned getRrMemoryOpValue(const MCInst &Inst, unsigned OpNo,
66303231Sdim                              SmallVectorImpl<MCFixup> &Fixups,
67303231Sdim                              const MCSubtargetInfo &SubtargetInfo) const;
68303231Sdim
69303231Sdim  unsigned getSplsOpValue(const MCInst &Inst, unsigned OpNo,
70303231Sdim                          SmallVectorImpl<MCFixup> &Fixups,
71303231Sdim                          const MCSubtargetInfo &SubtargetInfo) const;
72303231Sdim
73303231Sdim  unsigned getBranchTargetOpValue(const MCInst &Inst, unsigned OpNo,
74303231Sdim                                  SmallVectorImpl<MCFixup> &Fixups,
75303231Sdim                                  const MCSubtargetInfo &SubtargetInfo) const;
76303231Sdim
77303231Sdim  void encodeInstruction(const MCInst &Inst, raw_ostream &Ostream,
78303231Sdim                         SmallVectorImpl<MCFixup> &Fixups,
79303231Sdim                         const MCSubtargetInfo &SubtargetInfo) const override;
80303231Sdim
81303231Sdim  unsigned adjustPqBitsRmAndRrm(const MCInst &Inst, unsigned Value,
82303231Sdim                                const MCSubtargetInfo &STI) const;
83303231Sdim
84303231Sdim  unsigned adjustPqBitsSpls(const MCInst &Inst, unsigned Value,
85303231Sdim                            const MCSubtargetInfo &STI) const;
86303231Sdim};
87303231Sdim
88314564Sdim} // end anonymous namespace
89314564Sdim
90321369Sdimstatic Lanai::Fixups FixupKind(const MCExpr *Expr) {
91303231Sdim  if (isa<MCSymbolRefExpr>(Expr))
92303231Sdim    return Lanai::FIXUP_LANAI_21;
93303231Sdim  if (const LanaiMCExpr *McExpr = dyn_cast<LanaiMCExpr>(Expr)) {
94303231Sdim    LanaiMCExpr::VariantKind ExprKind = McExpr->getKind();
95303231Sdim    switch (ExprKind) {
96303231Sdim    case LanaiMCExpr::VK_Lanai_None:
97303231Sdim      return Lanai::FIXUP_LANAI_21;
98303231Sdim    case LanaiMCExpr::VK_Lanai_ABS_HI:
99303231Sdim      return Lanai::FIXUP_LANAI_HI16;
100303231Sdim    case LanaiMCExpr::VK_Lanai_ABS_LO:
101303231Sdim      return Lanai::FIXUP_LANAI_LO16;
102303231Sdim    }
103303231Sdim  }
104303231Sdim  return Lanai::Fixups(0);
105303231Sdim}
106303231Sdim
107303231Sdim// getMachineOpValue - Return binary encoding of operand. If the machine
108303231Sdim// operand requires relocation, record the relocation and return zero.
109303231Sdimunsigned LanaiMCCodeEmitter::getMachineOpValue(
110303231Sdim    const MCInst &Inst, const MCOperand &MCOp, SmallVectorImpl<MCFixup> &Fixups,
111303231Sdim    const MCSubtargetInfo &SubtargetInfo) const {
112303231Sdim  if (MCOp.isReg())
113303231Sdim    return getLanaiRegisterNumbering(MCOp.getReg());
114303231Sdim  if (MCOp.isImm())
115303231Sdim    return static_cast<unsigned>(MCOp.getImm());
116303231Sdim
117303231Sdim  // MCOp must be an expression
118303231Sdim  assert(MCOp.isExpr());
119303231Sdim  const MCExpr *Expr = MCOp.getExpr();
120303231Sdim
121303231Sdim  // Extract the symbolic reference side of a binary expression.
122303231Sdim  if (Expr->getKind() == MCExpr::Binary) {
123303231Sdim    const MCBinaryExpr *BinaryExpr = static_cast<const MCBinaryExpr *>(Expr);
124303231Sdim    Expr = BinaryExpr->getLHS();
125303231Sdim  }
126303231Sdim
127303231Sdim  assert(isa<LanaiMCExpr>(Expr) || Expr->getKind() == MCExpr::SymbolRef);
128303231Sdim  // Push fixup (all info is contained within)
129303231Sdim  Fixups.push_back(
130303231Sdim      MCFixup::create(0, MCOp.getExpr(), MCFixupKind(FixupKind(Expr))));
131303231Sdim  return 0;
132303231Sdim}
133303231Sdim
134303231Sdim// Helper function to adjust P and Q bits on load and store instructions.
135321369Sdimstatic unsigned adjustPqBits(const MCInst &Inst, unsigned Value,
136321369Sdim                             unsigned PBitShift, unsigned QBitShift) {
137303231Sdim  const MCOperand AluOp = Inst.getOperand(3);
138303231Sdim  unsigned AluCode = AluOp.getImm();
139303231Sdim
140303231Sdim  // Set the P bit to one iff the immediate is nonzero and not a post-op
141303231Sdim  // instruction.
142303231Sdim  const MCOperand Op2 = Inst.getOperand(2);
143303231Sdim  Value &= ~(1 << PBitShift);
144303231Sdim  if (!LPAC::isPostOp(AluCode) &&
145303231Sdim      ((Op2.isImm() && Op2.getImm() != 0) ||
146303231Sdim       (Op2.isReg() && Op2.getReg() != Lanai::R0) || (Op2.isExpr())))
147303231Sdim    Value |= (1 << PBitShift);
148303231Sdim
149303231Sdim  // Set the Q bit to one iff it is a post- or pre-op instruction.
150303231Sdim  assert(Inst.getOperand(0).isReg() && Inst.getOperand(1).isReg() &&
151303231Sdim         "Expected register operand.");
152303231Sdim  Value &= ~(1 << QBitShift);
153303231Sdim  if (LPAC::modifiesOp(AluCode) && ((Op2.isImm() && Op2.getImm() != 0) ||
154303231Sdim                                    (Op2.isReg() && Op2.getReg() != Lanai::R0)))
155303231Sdim    Value |= (1 << QBitShift);
156303231Sdim
157303231Sdim  return Value;
158303231Sdim}
159303231Sdim
160303231Sdimunsigned
161303231SdimLanaiMCCodeEmitter::adjustPqBitsRmAndRrm(const MCInst &Inst, unsigned Value,
162303231Sdim                                         const MCSubtargetInfo &STI) const {
163303231Sdim  return adjustPqBits(Inst, Value, 17, 16);
164303231Sdim}
165303231Sdim
166303231Sdimunsigned
167303231SdimLanaiMCCodeEmitter::adjustPqBitsSpls(const MCInst &Inst, unsigned Value,
168303231Sdim                                     const MCSubtargetInfo &STI) const {
169303231Sdim  return adjustPqBits(Inst, Value, 11, 10);
170303231Sdim}
171303231Sdim
172303231Sdimvoid LanaiMCCodeEmitter::encodeInstruction(
173303231Sdim    const MCInst &Inst, raw_ostream &Ostream, SmallVectorImpl<MCFixup> &Fixups,
174303231Sdim    const MCSubtargetInfo &SubtargetInfo) const {
175303231Sdim  // Get instruction encoding and emit it
176303231Sdim  unsigned Value = getBinaryCodeForInstr(Inst, Fixups, SubtargetInfo);
177303231Sdim  ++MCNumEmitted; // Keep track of the number of emitted insns.
178303231Sdim
179303231Sdim  // Emit bytes in big-endian
180303231Sdim  for (int i = (4 - 1) * 8; i >= 0; i -= 8)
181303231Sdim    Ostream << static_cast<char>((Value >> i) & 0xff);
182303231Sdim}
183303231Sdim
184303231Sdim// Encode Lanai Memory Operand
185303231Sdimunsigned LanaiMCCodeEmitter::getRiMemoryOpValue(
186303231Sdim    const MCInst &Inst, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
187303231Sdim    const MCSubtargetInfo &SubtargetInfo) const {
188303231Sdim  unsigned Encoding;
189303231Sdim  const MCOperand Op1 = Inst.getOperand(OpNo + 0);
190303231Sdim  const MCOperand Op2 = Inst.getOperand(OpNo + 1);
191303231Sdim  const MCOperand AluOp = Inst.getOperand(OpNo + 2);
192303231Sdim
193303231Sdim  assert(Op1.isReg() && "First operand is not register.");
194303231Sdim  assert((Op2.isImm() || Op2.isExpr()) &&
195303231Sdim         "Second operand is neither an immediate nor an expression.");
196303231Sdim  assert((LPAC::getAluOp(AluOp.getImm()) == LPAC::ADD) &&
197303231Sdim         "Register immediate only supports addition operator");
198303231Sdim
199303231Sdim  Encoding = (getLanaiRegisterNumbering(Op1.getReg()) << 18);
200303231Sdim  if (Op2.isImm()) {
201303231Sdim    assert(isInt<16>(Op2.getImm()) &&
202303231Sdim           "Constant value truncated (limited to 16-bit)");
203303231Sdim
204303231Sdim    Encoding |= (Op2.getImm() & 0xffff);
205303231Sdim    if (Op2.getImm() != 0) {
206303231Sdim      if (LPAC::isPreOp(AluOp.getImm()))
207303231Sdim        Encoding |= (0x3 << 16);
208303231Sdim      if (LPAC::isPostOp(AluOp.getImm()))
209303231Sdim        Encoding |= (0x1 << 16);
210303231Sdim    }
211303231Sdim  } else
212303231Sdim    getMachineOpValue(Inst, Op2, Fixups, SubtargetInfo);
213303231Sdim
214303231Sdim  return Encoding;
215303231Sdim}
216303231Sdim
217303231Sdimunsigned LanaiMCCodeEmitter::getRrMemoryOpValue(
218303231Sdim    const MCInst &Inst, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
219303231Sdim    const MCSubtargetInfo &SubtargetInfo) const {
220303231Sdim  unsigned Encoding;
221303231Sdim  const MCOperand Op1 = Inst.getOperand(OpNo + 0);
222303231Sdim  const MCOperand Op2 = Inst.getOperand(OpNo + 1);
223303231Sdim  const MCOperand AluMCOp = Inst.getOperand(OpNo + 2);
224303231Sdim
225303231Sdim  assert(Op1.isReg() && "First operand is not register.");
226303231Sdim  Encoding = (getLanaiRegisterNumbering(Op1.getReg()) << 15);
227303231Sdim  assert(Op2.isReg() && "Second operand is not register.");
228303231Sdim  Encoding |= (getLanaiRegisterNumbering(Op2.getReg()) << 10);
229303231Sdim
230303231Sdim  assert(AluMCOp.isImm() && "Third operator is not immediate.");
231303231Sdim  // Set BBB
232303231Sdim  unsigned AluOp = AluMCOp.getImm();
233303231Sdim  Encoding |= LPAC::encodeLanaiAluCode(AluOp) << 5;
234303231Sdim  // Set P and Q
235303231Sdim  if (LPAC::isPreOp(AluOp))
236303231Sdim    Encoding |= (0x3 << 8);
237303231Sdim  if (LPAC::isPostOp(AluOp))
238303231Sdim    Encoding |= (0x1 << 8);
239303231Sdim  // Set JJJJ
240303231Sdim  switch (LPAC::getAluOp(AluOp)) {
241303231Sdim  case LPAC::SHL:
242303231Sdim  case LPAC::SRL:
243303231Sdim    Encoding |= 0x10;
244303231Sdim    break;
245303231Sdim  case LPAC::SRA:
246303231Sdim    Encoding |= 0x18;
247303231Sdim    break;
248303231Sdim  default:
249303231Sdim    break;
250303231Sdim  }
251303231Sdim
252303231Sdim  return Encoding;
253303231Sdim}
254303231Sdim
255303231Sdimunsigned
256303231SdimLanaiMCCodeEmitter::getSplsOpValue(const MCInst &Inst, unsigned OpNo,
257303231Sdim                                   SmallVectorImpl<MCFixup> &Fixups,
258303231Sdim                                   const MCSubtargetInfo &SubtargetInfo) const {
259303231Sdim  unsigned Encoding;
260303231Sdim  const MCOperand Op1 = Inst.getOperand(OpNo + 0);
261303231Sdim  const MCOperand Op2 = Inst.getOperand(OpNo + 1);
262303231Sdim  const MCOperand AluOp = Inst.getOperand(OpNo + 2);
263303231Sdim
264303231Sdim  assert(Op1.isReg() && "First operand is not register.");
265303231Sdim  assert((Op2.isImm() || Op2.isExpr()) &&
266303231Sdim         "Second operand is neither an immediate nor an expression.");
267303231Sdim  assert((LPAC::getAluOp(AluOp.getImm()) == LPAC::ADD) &&
268303231Sdim         "Register immediate only supports addition operator");
269303231Sdim
270303231Sdim  Encoding = (getLanaiRegisterNumbering(Op1.getReg()) << 12);
271303231Sdim  if (Op2.isImm()) {
272303231Sdim    assert(isInt<10>(Op2.getImm()) &&
273303231Sdim           "Constant value truncated (limited to 10-bit)");
274303231Sdim
275303231Sdim    Encoding |= (Op2.getImm() & 0x3ff);
276303231Sdim    if (Op2.getImm() != 0) {
277303231Sdim      if (LPAC::isPreOp(AluOp.getImm()))
278303231Sdim        Encoding |= (0x3 << 10);
279303231Sdim      if (LPAC::isPostOp(AluOp.getImm()))
280303231Sdim        Encoding |= (0x1 << 10);
281303231Sdim    }
282303231Sdim  } else
283303231Sdim    getMachineOpValue(Inst, Op2, Fixups, SubtargetInfo);
284303231Sdim
285303231Sdim  return Encoding;
286303231Sdim}
287303231Sdim
288303231Sdimunsigned LanaiMCCodeEmitter::getBranchTargetOpValue(
289303231Sdim    const MCInst &Inst, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
290303231Sdim    const MCSubtargetInfo &SubtargetInfo) const {
291303231Sdim  const MCOperand &MCOp = Inst.getOperand(OpNo);
292303231Sdim  if (MCOp.isReg() || MCOp.isImm())
293303231Sdim    return getMachineOpValue(Inst, MCOp, Fixups, SubtargetInfo);
294303231Sdim
295303231Sdim  Fixups.push_back(MCFixup::create(
296303231Sdim      0, MCOp.getExpr(), static_cast<MCFixupKind>(Lanai::FIXUP_LANAI_25)));
297303231Sdim
298303231Sdim  return 0;
299303231Sdim}
300303231Sdim
301303231Sdim#include "LanaiGenMCCodeEmitter.inc"
302303231Sdim
303314564Sdim} // end namespace llvm
304314564Sdim
305303231Sdimllvm::MCCodeEmitter *
306303231Sdimllvm::createLanaiMCCodeEmitter(const MCInstrInfo &InstrInfo,
307303231Sdim                               const MCRegisterInfo & /*MRI*/,
308303231Sdim                               MCContext &context) {
309303231Sdim  return new LanaiMCCodeEmitter(InstrInfo, context);
310303231Sdim}
311