1 //===-- M68kMCInstLower.cpp - M68k MachineInstr to MCInst -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file contains code to lower M68k MachineInstrs to their
11 /// corresponding MCInst records.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "M68kMCInstLower.h"
16 
17 #include "M68kAsmPrinter.h"
18 #include "M68kInstrInfo.h"
19 
20 #include "MCTargetDesc/M68kBaseInfo.h"
21 
22 #include "llvm/CodeGen/MachineFunction.h"
23 #include "llvm/CodeGen/MachineInstr.h"
24 #include "llvm/CodeGen/MachineOperand.h"
25 #include "llvm/IR/Mangler.h"
26 #include "llvm/MC/MCContext.h"
27 #include "llvm/MC/MCExpr.h"
28 #include "llvm/MC/MCInst.h"
29 
30 using namespace llvm;
31 
32 #define DEBUG_TYPE "m68k-mc-inst-lower"
33 
34 M68kMCInstLower::M68kMCInstLower(MachineFunction &MF, M68kAsmPrinter &AP)
35     : Ctx(MF.getContext()), MF(MF), TM(MF.getTarget()), MAI(*TM.getMCAsmInfo()),
36       AsmPrinter(AP) {}
37 
38 MCSymbol *
39 M68kMCInstLower::GetSymbolFromOperand(const MachineOperand &MO) const {
40   assert((MO.isGlobal() || MO.isSymbol() || MO.isMBB()) &&
41          "Isn't a symbol reference");
42 
43   const auto &TT = TM.getTargetTriple();
44   if (MO.isGlobal() && TT.isOSBinFormatELF())
45     return AsmPrinter.getSymbolPreferLocal(*MO.getGlobal());
46 
47   const DataLayout &DL = MF.getDataLayout();
48 
49   MCSymbol *Sym = nullptr;
50   SmallString<128> Name;
51   StringRef Suffix;
52 
53   if (!Suffix.empty())
54     Name += DL.getPrivateGlobalPrefix();
55 
56   if (MO.isGlobal()) {
57     const GlobalValue *GV = MO.getGlobal();
58     AsmPrinter.getNameWithPrefix(Name, GV);
59   } else if (MO.isSymbol()) {
60     Mangler::getNameWithPrefix(Name, MO.getSymbolName(), DL);
61   } else if (MO.isMBB()) {
62     assert(Suffix.empty());
63     Sym = MO.getMBB()->getSymbol();
64   }
65 
66   Name += Suffix;
67   if (!Sym)
68     Sym = Ctx.getOrCreateSymbol(Name);
69 
70   return Sym;
71 }
72 
73 MCOperand M68kMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
74                                               MCSymbol *Sym) const {
75   // FIXME We would like an efficient form for this, so we don't have to do a
76   // lot of extra uniquing. This fixme is originally from X86
77   const MCExpr *Expr = nullptr;
78   MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None;
79 
80   switch (MO.getTargetFlags()) {
81   default:
82     llvm_unreachable("Unknown target flag on GV operand");
83   case M68kII::MO_NO_FLAG:
84   case M68kII::MO_ABSOLUTE_ADDRESS:
85   case M68kII::MO_PC_RELATIVE_ADDRESS:
86     break;
87   case M68kII::MO_GOTPCREL:
88     RefKind = MCSymbolRefExpr::VK_GOTPCREL;
89     break;
90   case M68kII::MO_GOT:
91     RefKind = MCSymbolRefExpr::VK_GOT;
92     break;
93   case M68kII::MO_GOTOFF:
94     RefKind = MCSymbolRefExpr::VK_GOTOFF;
95     break;
96   case M68kII::MO_PLT:
97     RefKind = MCSymbolRefExpr::VK_PLT;
98     break;
99   case M68kII::MO_TLSGD:
100     RefKind = MCSymbolRefExpr::VK_TLSGD;
101     break;
102   case M68kII::MO_TLSLD:
103     RefKind = MCSymbolRefExpr::VK_TLSLD;
104     break;
105   case M68kII::MO_TLSLDM:
106     RefKind = MCSymbolRefExpr::VK_TLSLDM;
107     break;
108   case M68kII::MO_TLSIE:
109     RefKind = MCSymbolRefExpr::VK_GOTTPOFF;
110     break;
111   case M68kII::MO_TLSLE:
112     RefKind = MCSymbolRefExpr::VK_TPOFF;
113     break;
114   }
115 
116   if (!Expr) {
117     Expr = MCSymbolRefExpr::create(Sym, RefKind, Ctx);
118   }
119 
120   if (!MO.isJTI() && !MO.isMBB() && MO.getOffset()) {
121     Expr = MCBinaryExpr::createAdd(
122         Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
123   }
124 
125   return MCOperand::createExpr(Expr);
126 }
127 
128 std::optional<MCOperand>
129 M68kMCInstLower::LowerOperand(const MachineInstr *MI,
130                               const MachineOperand &MO) const {
131   switch (MO.getType()) {
132   default:
133     llvm_unreachable("unknown operand type");
134   case MachineOperand::MO_Register:
135     // Ignore all implicit register operands.
136     if (MO.isImplicit())
137       return std::nullopt;
138     return MCOperand::createReg(MO.getReg());
139   case MachineOperand::MO_Immediate:
140     return MCOperand::createImm(MO.getImm());
141   case MachineOperand::MO_MachineBasicBlock:
142   case MachineOperand::MO_GlobalAddress:
143   case MachineOperand::MO_ExternalSymbol:
144     return LowerSymbolOperand(MO, GetSymbolFromOperand(MO));
145   case MachineOperand::MO_MCSymbol:
146     return LowerSymbolOperand(MO, MO.getMCSymbol());
147   case MachineOperand::MO_JumpTableIndex:
148     return LowerSymbolOperand(MO, AsmPrinter.GetJTISymbol(MO.getIndex()));
149   case MachineOperand::MO_ConstantPoolIndex:
150     return LowerSymbolOperand(MO, AsmPrinter.GetCPISymbol(MO.getIndex()));
151   case MachineOperand::MO_BlockAddress:
152     return LowerSymbolOperand(
153         MO, AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress()));
154   case MachineOperand::MO_RegisterMask:
155     // Ignore call clobbers.
156     return std::nullopt;
157   }
158 }
159 
160 void M68kMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
161   unsigned Opcode = MI->getOpcode();
162   OutMI.setOpcode(Opcode);
163 
164   for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
165     const MachineOperand &MO = MI->getOperand(i);
166     std::optional<MCOperand> MCOp = LowerOperand(MI, MO);
167 
168     if (MCOp.has_value() && MCOp.value().isValid())
169       OutMI.addOperand(MCOp.value());
170   }
171 
172   // TAILJMPj, TAILJMPq - Lower to the correct jump instructions.
173   if (Opcode == M68k::TAILJMPj || Opcode == M68k::TAILJMPq) {
174     assert(OutMI.getNumOperands() == 1 && "Unexpected number of operands");
175     switch (Opcode) {
176     case M68k::TAILJMPj:
177       Opcode = M68k::JMP32j;
178       break;
179     case M68k::TAILJMPq:
180       Opcode = M68k::BRA8;
181       break;
182     }
183     OutMI.setOpcode(Opcode);
184   }
185 }
186