1//===-- PPCMCInstLower.cpp - Convert PPC MachineInstr to an MCInst --------===//
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// This file contains code to lower PPC MachineInstrs to their corresponding
10// MCInst records.
11//
12//===----------------------------------------------------------------------===//
13
14#include "MCTargetDesc/PPCMCAsmInfo.h"
15#include "PPC.h"
16#include "PPCMachineFunctionInfo.h"
17#include "PPCSubtarget.h"
18#include "llvm/ADT/SmallString.h"
19#include "llvm/ADT/Twine.h"
20#include "llvm/CodeGen/AsmPrinter.h"
21#include "llvm/CodeGen/MachineFunction.h"
22#include "llvm/CodeGen/MachineModuleInfoImpls.h"
23#include "llvm/CodeGen/TargetLowering.h"
24#include "llvm/IR/DataLayout.h"
25#include "llvm/IR/GlobalValue.h"
26#include "llvm/IR/Mangler.h"
27#include "llvm/IR/Module.h"
28#include "llvm/MC/MCAsmInfo.h"
29#include "llvm/MC/MCExpr.h"
30#include "llvm/MC/MCInst.h"
31#include "llvm/Target/TargetLoweringObjectFile.h"
32using namespace llvm;
33
34static MCSymbol *GetSymbolFromOperand(const MachineOperand &MO,
35 AsmPrinter &AP) {
36 if (MO.isGlobal()) {
37 // Get the symbol from the global, accounting for XCOFF-specific
38 // intricacies (see TargetLoweringObjectFileXCOFF::getTargetSymbol).
39 const GlobalValue *GV = MO.getGlobal();
40 return AP.getSymbol(GV);
41 }
42
43 assert(MO.isSymbol() && "Isn't a symbol reference");
44
45 SmallString<128> Name;
46 const DataLayout &DL = AP.getDataLayout();
47 Mangler::getNameWithPrefix(OutName&: Name, GVName: MO.getSymbolName(), DL);
48
49 MCContext &Ctx = AP.OutContext;
50 MCSymbol *Sym = Ctx.getOrCreateSymbol(Name);
51 return Sym;
52}
53
54static MCOperand GetSymbolRef(unsigned MIOpcode, const MachineOperand &MO,
55 const MCSymbol *Symbol, AsmPrinter &Printer) {
56 MCContext &Ctx = Printer.OutContext;
57 PPCMCExpr::Specifier RefKind = PPC::S_None;
58
59 unsigned access = MO.getTargetFlags();
60
61 switch (access) {
62 case PPCII::MO_TPREL_LO:
63 RefKind = PPC::S_TPREL_LO;
64 break;
65 case PPCII::MO_TPREL_HA:
66 RefKind = PPC::S_TPREL_HA;
67 break;
68 case PPCII::MO_DTPREL_LO:
69 RefKind = PPC::S_DTPREL_LO;
70 break;
71 case PPCII::MO_TLSLD_LO:
72 RefKind = PPC::S_GOT_TLSLD_LO;
73 break;
74 case PPCII::MO_TOC_LO:
75 RefKind = PPC::S_TOC_LO;
76 break;
77 case PPCII::MO_TLS:
78 RefKind = PPC::S_TLS;
79 break;
80 case PPCII::MO_TLS_PCREL_FLAG:
81 RefKind = PPC::S_TLS_PCREL;
82 break;
83 }
84
85 const TargetMachine &TM = Printer.TM;
86 const MachineFunction *MF = Printer.MF;
87
88 if (MO.getTargetFlags() == PPCII::MO_PLT)
89 RefKind = PPC::S_PLT;
90 else if (MO.getTargetFlags() == PPCII::MO_PCREL_FLAG)
91 RefKind = PPC::S_PCREL;
92 else if (MO.getTargetFlags() == PPCII::MO_GOT_PCREL_FLAG)
93 RefKind = PPC::S_GOT_PCREL;
94 else if (MO.getTargetFlags() == PPCII::MO_TPREL_PCREL_FLAG)
95 RefKind = PPC::S_TPREL;
96 else if (MO.getTargetFlags() == PPCII::MO_GOT_TLSGD_PCREL_FLAG)
97 RefKind = PPC::S_GOT_TLSGD_PCREL;
98 else if (MO.getTargetFlags() == PPCII::MO_GOT_TLSLD_PCREL_FLAG)
99 RefKind = PPC::S_GOT_TLSLD_PCREL;
100 else if (MO.getTargetFlags() == PPCII::MO_GOT_TPREL_PCREL_FLAG)
101 RefKind = PPC::S_GOT_TPREL_PCREL;
102 else if (MO.getTargetFlags() == PPCII::MO_TPREL_FLAG ||
103 MO.getTargetFlags() == PPCII::MO_TLSLD_FLAG) {
104 assert(MO.isGlobal() && "Only expecting a global MachineOperand here!");
105 TLSModel::Model Model = TM.getTLSModel(GV: MO.getGlobal());
106 const PPCFunctionInfo *FuncInfo = MF->getInfo<PPCFunctionInfo>();
107 // For the local-[exec|dynamic] TLS model, we may generate the offset from
108 // the TLS base as an immediate operand (instead of using a TOC entry). Set
109 // the relocation type in case the result is used for purposes other than a
110 // TOC reference. In TOC reference cases, this result is discarded.
111 if (Model == TLSModel::LocalExec)
112 RefKind = PPC::S_AIX_TLSLE;
113 else if (Model == TLSModel::LocalDynamic &&
114 FuncInfo->isAIXFuncUseTLSIEForLD())
115 // On AIX, TLS model opt may have turned local-dynamic accesses into
116 // initial-exec accesses.
117 RefKind = PPC::S_AIX_TLSIE;
118 else if (Model == TLSModel::LocalDynamic)
119 RefKind = PPC::S_AIX_TLSLD;
120 }
121
122 const Module *M = MF->getFunction().getParent();
123 const PPCSubtarget *Subtarget = &(MF->getSubtarget<PPCSubtarget>());
124
125 assert((Subtarget->isUsingPCRelativeCalls() || MIOpcode != PPC::BL8_NOTOC) &&
126 "BL8_NOTOC is only valid when using PC Relative Calls.");
127 if (Subtarget->isUsingPCRelativeCalls()) {
128 if (MIOpcode == PPC::TAILB || MIOpcode == PPC::TAILB8 ||
129 MIOpcode == PPC::TCRETURNdi || MIOpcode == PPC::TCRETURNdi8 ||
130 MIOpcode == PPC::BL8_NOTOC || MIOpcode == PPC::BL8_NOTOC_RM) {
131 RefKind = PPC::S_NOTOC;
132 }
133 if (MO.getTargetFlags() == PPCII::MO_PCREL_OPT_FLAG)
134 RefKind = PPC::S_PCREL_OPT;
135 }
136
137 const MCExpr *Expr = MCSymbolRefExpr::create(Symbol, specifier: RefKind, Ctx);
138 // If -msecure-plt -fPIC, add 32768 to symbol.
139 if (Subtarget->isSecurePlt() && TM.isPositionIndependent() &&
140 M->getPICLevel() == PICLevel::BigPIC &&
141 MO.getTargetFlags() == PPCII::MO_PLT)
142 Expr =
143 MCBinaryExpr::createAdd(LHS: Expr, RHS: MCConstantExpr::create(Value: 32768, Ctx), Ctx);
144
145 if (!MO.isJTI() && MO.getOffset())
146 Expr = MCBinaryExpr::createAdd(LHS: Expr,
147 RHS: MCConstantExpr::create(Value: MO.getOffset(), Ctx),
148 Ctx);
149
150 // Subtract off the PIC base if required.
151 if (MO.getTargetFlags() == PPCII::MO_PIC_FLAG ||
152 MO.getTargetFlags() == PPCII::MO_PIC_HA_FLAG ||
153 MO.getTargetFlags() == PPCII::MO_PIC_LO_FLAG) {
154 const MCExpr *PB = MCSymbolRefExpr::create(Symbol: MF->getPICBaseSymbol(), Ctx);
155 Expr = MCBinaryExpr::createSub(LHS: Expr, RHS: PB, Ctx);
156 }
157
158 // Add ha16() / lo16() markers if required.
159 switch (access) {
160 case PPCII::MO_LO:
161 case PPCII::MO_PIC_LO_FLAG:
162 Expr = MCSpecifierExpr::create(Expr, S: PPC::S_LO, Ctx);
163 break;
164 case PPCII::MO_HA:
165 case PPCII::MO_PIC_HA_FLAG:
166 Expr = MCSpecifierExpr::create(Expr, S: PPC::S_HA, Ctx);
167 break;
168 }
169
170 return MCOperand::createExpr(Val: Expr);
171}
172
173void llvm::LowerPPCMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
174 AsmPrinter &AP) {
175 OutMI.setOpcode(MI->getOpcode());
176
177 for (const MachineOperand &MO : MI->operands()) {
178 MCOperand MCOp;
179 if (LowerPPCMachineOperandToMCOperand(MIOpcode: MI->getOpcode(), MO, OutMO&: MCOp, AP))
180 OutMI.addOperand(Op: MCOp);
181 }
182}
183
184bool llvm::LowerPPCMachineOperandToMCOperand(unsigned MIOpcode,
185 const MachineOperand &MO,
186 MCOperand &OutMO, AsmPrinter &AP) {
187 switch (MO.getType()) {
188 default:
189 llvm_unreachable("unknown operand type");
190 case MachineOperand::MO_Register:
191 assert(!MO.getSubReg() && "Subregs should be eliminated!");
192 assert(MO.getReg() > PPC::NoRegister &&
193 MO.getReg() < PPC::NUM_TARGET_REGS &&
194 "Invalid register for this target!");
195 // ISA instructions refer to the containing dmr reg.
196 if (PPC::isDMRROWpRegister(Reg: MO.getReg())) {
197 OutMO =
198 MCOperand::createReg(Reg: PPC::DMR0 + (MO.getReg() - PPC::DMRROWp0) / 4);
199 return true;
200 }
201 // Ignore all implicit register operands.
202 if (MO.isImplicit())
203 return false;
204 OutMO = MCOperand::createReg(Reg: MO.getReg());
205 return true;
206 case MachineOperand::MO_Immediate:
207 OutMO = MCOperand::createImm(Val: MO.getImm());
208 return true;
209 case MachineOperand::MO_MachineBasicBlock:
210 OutMO = MCOperand::createExpr(
211 Val: MCSymbolRefExpr::create(Symbol: MO.getMBB()->getSymbol(), Ctx&: AP.OutContext));
212 return true;
213 case MachineOperand::MO_GlobalAddress:
214 case MachineOperand::MO_ExternalSymbol:
215 OutMO = GetSymbolRef(MIOpcode, MO, Symbol: GetSymbolFromOperand(MO, AP), Printer&: AP);
216 return true;
217 case MachineOperand::MO_JumpTableIndex:
218 OutMO = GetSymbolRef(MIOpcode, MO, Symbol: AP.GetJTISymbol(JTID: MO.getIndex()), Printer&: AP);
219 return true;
220 case MachineOperand::MO_ConstantPoolIndex:
221 OutMO = GetSymbolRef(MIOpcode, MO, Symbol: AP.GetCPISymbol(CPID: MO.getIndex()), Printer&: AP);
222 return true;
223 case MachineOperand::MO_BlockAddress:
224 OutMO = GetSymbolRef(MIOpcode, MO,
225 Symbol: AP.GetBlockAddressSymbol(BA: MO.getBlockAddress()), Printer&: AP);
226 return true;
227 case MachineOperand::MO_MCSymbol:
228 OutMO = GetSymbolRef(MIOpcode, MO, Symbol: MO.getMCSymbol(), Printer&: AP);
229 return true;
230 case MachineOperand::MO_RegisterMask:
231 return false;
232 }
233}
234