LLVM 23.0.0git
LoongArchAsmPrinter.cpp
Go to the documentation of this file.
1//===- LoongArchAsmPrinter.cpp - LoongArch LLVM Assembly Printer -*- 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// This file contains a printer that converts from our internal representation
10// of machine-dependent LLVM code to GAS-format LoongArch assembly language.
11//
12//===----------------------------------------------------------------------===//
13
14#include "LoongArchAsmPrinter.h"
15#include "LoongArch.h"
24#include "llvm/MC/MCAsmInfo.h"
25#include "llvm/MC/MCContext.h"
30
31using namespace llvm;
32
33#define DEBUG_TYPE "loongarch-asm-printer"
34
36 "loongarch-annotate-tablejump", cl::Hidden,
38 "Annotate table jump instruction to correlate it with the jump table."),
39 cl::init(false));
40
41// Simple pseudo-instructions have their lowering (with expansion to real
42// instructions) auto-generated.
43#include "LoongArchGenMCPseudoLowering.inc"
44
45LoongArchTargetStreamer &LoongArchAsmPrinter::getTargetStreamer() const {
46 return static_cast<LoongArchTargetStreamer &>(
47 *OutStreamer->getTargetStreamer());
48}
49
51 LoongArch_MC::verifyInstructionPredicates(
52 MI->getOpcode(), getSubtargetInfo().getFeatureBits());
53
54 // Do any auto-generated pseudo lowerings.
55 if (MCInst OutInst; lowerPseudoInstExpansion(MI, OutInst)) {
56 EmitToStreamer(*OutStreamer, OutInst);
57 return;
58 }
59
60 switch (MI->getOpcode()) {
61 case TargetOpcode::STATEPOINT:
63 return;
64 case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
66 return;
67 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
69 return;
70 case TargetOpcode::PATCHABLE_TAIL_CALL:
72 return;
73 }
74
75 MCInst TmpInst;
76 if (!lowerLoongArchMachineInstrToMCInst(MI, TmpInst, *this))
77 EmitToStreamer(*OutStreamer, TmpInst);
78}
79
81 const char *ExtraCode,
82 raw_ostream &OS) {
83 // First try the generic code, which knows about modifiers like 'c' and 'n'.
84 if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
85 return false;
86
87 const MachineOperand &MO = MI->getOperand(OpNo);
88 if (ExtraCode && ExtraCode[0]) {
89 if (ExtraCode[1] != 0)
90 return true; // Unknown modifier.
91
92 switch (ExtraCode[0]) {
93 default:
94 return true; // Unknown modifier.
95 case 'z': // Print $zero register if zero, regular printing otherwise.
96 if (MO.isImm() && MO.getImm() == 0) {
97 OS << '$' << LoongArchInstPrinter::getRegisterName(LoongArch::R0);
98 return false;
99 }
100 break;
101 case 'u': // Print LASX registers.
102 case 'w': // Print LSX registers.
103 {
104 // If the operand is an LASX, LSX or floating point register, print the
105 // name of LASX or LSX register with the same index in that register
106 // class.
107 unsigned RegID = MO.getReg().id(), FirstReg;
108 if (RegID >= LoongArch::XR0 && RegID <= LoongArch::XR31)
109 FirstReg = LoongArch::XR0;
110 else if (RegID >= LoongArch::VR0 && RegID <= LoongArch::VR31)
111 FirstReg = LoongArch::VR0;
112 else if (RegID >= LoongArch::F0_64 && RegID <= LoongArch::F31_64)
113 FirstReg = LoongArch::F0_64;
114 else if (RegID >= LoongArch::F0 && RegID <= LoongArch::F31)
115 FirstReg = LoongArch::F0;
116 else
117 return true;
118 OS << '$'
120 RegID - FirstReg +
121 (ExtraCode[0] == 'u' ? LoongArch::XR0 : LoongArch::VR0));
122 return false;
123 }
124 // TODO: handle other extra codes if any.
125 }
126 }
127
128 switch (MO.getType()) {
130 OS << MO.getImm();
131 return false;
134 return false;
136 PrintSymbolOperand(MO, OS);
137 return false;
138 default:
139 llvm_unreachable("not implemented");
140 }
141
142 return true;
143}
144
146 unsigned OpNo,
147 const char *ExtraCode,
148 raw_ostream &OS) {
149 // TODO: handle extra code.
150 if (ExtraCode)
151 return true;
152
153 // We only support memory operands like "Base + Offset", where base must be a
154 // register, and offset can be a register or an immediate value.
155 const MachineOperand &BaseMO = MI->getOperand(OpNo);
156 // Base address must be a register.
157 if (!BaseMO.isReg())
158 return true;
159 // Print the base address register.
160 OS << "$" << LoongArchInstPrinter::getRegisterName(BaseMO.getReg());
161 // Print the offset operand.
162 const MachineOperand &OffsetMO = MI->getOperand(OpNo + 1);
163 MCOperand MCO;
164 if (!lowerOperand(OffsetMO, MCO))
165 return true;
166 if (OffsetMO.isReg())
167 OS << ", $" << LoongArchInstPrinter::getRegisterName(OffsetMO.getReg());
168 else if (OffsetMO.isImm())
169 OS << ", " << OffsetMO.getImm();
170 else if (OffsetMO.isGlobal() || OffsetMO.isBlockAddress() ||
171 OffsetMO.isMCSymbol() || OffsetMO.isCPI()) {
172 OS << ", ";
173 MAI.printExpr(OS, *MCO.getExpr());
174 } else
175 return true;
176
177 return false;
178}
179
181 StatepointOpers SOpers(&MI);
182 if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
183 assert(PatchBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
184 emitNops(PatchBytes / 4);
185 } else {
186 // Lower call target and choose correct opcode.
187 const MachineOperand &CallTarget = SOpers.getCallTarget();
188 MCOperand CallTargetMCOp;
189 switch (CallTarget.getType()) {
192 lowerOperand(CallTarget, CallTargetMCOp);
194 MCInstBuilder(LoongArch::BL).addOperand(CallTargetMCOp));
195 break;
197 CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());
199 MCInstBuilder(LoongArch::BL).addOperand(CallTargetMCOp));
200 break;
202 CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());
203 EmitToStreamer(*OutStreamer, MCInstBuilder(LoongArch::JIRL)
204 .addReg(LoongArch::R1)
205 .addOperand(CallTargetMCOp)
206 .addImm(0));
207 break;
208 default:
209 llvm_unreachable("Unsupported operand type in statepoint call target");
210 break;
211 }
212 }
213
214 auto &Ctx = OutStreamer->getContext();
215 MCSymbol *MILabel = Ctx.createTempSymbol();
216 OutStreamer->emitLabel(MILabel);
217 SM.recordStatepoint(*MILabel, MI);
218}
219
221 const MachineInstr &MI) {
222 const Function &F = MF->getFunction();
223 if (F.hasFnAttribute("patchable-function-entry")) {
224 unsigned Num = F.getFnAttributeAsParsedInteger("patchable-function-entry");
225 emitNops(Num);
226 return;
227 }
228
230}
231
235
239
241 // For loongarch64 we want to emit the following pattern:
242 //
243 // .Lxray_sled_beginN:
244 // B .Lxray_sled_endN
245 // 11 NOPs (44 bytes)
246 // .Lxray_sled_endN:
247 //
248 // We need the extra bytes because at runtime they may be used for the
249 // actual pattern defined at compiler-rt/lib/xray/xray_loongarch64.cpp.
250 // The count here should be adjusted accordingly if the implementation
251 // changes.
252 const int8_t NoopsInSledCount = 11;
253 OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());
254 MCSymbol *BeginOfSled = OutContext.createTempSymbol("xray_sled_begin");
255 MCSymbol *EndOfSled = OutContext.createTempSymbol("xray_sled_end");
256 OutStreamer->emitLabel(BeginOfSled);
258 MCInstBuilder(LoongArch::B)
259 .addExpr(MCSymbolRefExpr::create(EndOfSled, OutContext)));
260 emitNops(NoopsInSledCount);
261 OutStreamer->emitLabel(EndOfSled);
262 recordSled(BeginOfSled, MI, Kind, 2);
263}
264
267
269 return;
270
271 assert(TM.getTargetTriple().isOSBinFormatELF());
272
273 auto *LAFI = MF->getInfo<LoongArchMachineFunctionInfo>();
274 unsigned EntrySize = LAFI->getJumpInfoSize();
275 auto JTI = MF->getJumpTableInfo();
276
277 if (!JTI || 0 == EntrySize)
278 return;
279
280 unsigned Size = getDataLayout().getPointerSize();
281 const auto &JT = JTI->getJumpTables();
282
283 // Emit an additional section to store the correlation info as pairs of
284 // addresses, each pair contains the address of a jump instruction (jr) and
285 // the address of the jump table.
286 OutStreamer->switchSection(MMI->getContext().getELFSection(
287 ".discard.tablejump_annotate", ELF::SHT_PROGBITS, 0));
288
289 for (unsigned Idx = 0; Idx < EntrySize; ++Idx) {
290 int JTIIdx = LAFI->getJumpInfoJTIIndex(Idx);
291 if (JT[JTIIdx].MBBs.empty())
292 continue;
293 OutStreamer->emitValue(
294 MCSymbolRefExpr::create(LAFI->getJumpInfoJrMI(Idx)->getPreInstrSymbol(),
295 OutContext),
296 Size);
297 OutStreamer->emitValue(
299 }
300}
301
302// Emit .dtprelword or .dtpreldword directive
303// and value for debug thread local expression.
305 unsigned Size) const {
306 if (auto *Expr = dyn_cast<MCSpecifierExpr>(Value)) {
307 if (Expr->getSpecifier() == LoongArchMCExpr::VK_DTPREL) {
308 switch (Size) {
309 case 4:
310 getTargetStreamer().emitDTPRel32Value(Expr->getSubExpr());
311 break;
312 case 8:
313 getTargetStreamer().emitDTPRel64Value(Expr->getSubExpr());
314 break;
315 default:
316 llvm_unreachable("Unexpected size of expression value.");
317 }
318 return;
319 }
320 }
322}
323
326 // Emit the XRay table for this function.
328 return true;
329}
330
332
333INITIALIZE_PASS(LoongArchAsmPrinter, "loongarch-asm-printer",
334 "LoongArch Assembly Printer", false, false)
335
336// Force static initialization.
338LLVMInitializeLoongArchAsmPrinter() {
341}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static MCDisassembler::DecodeStatus addOperand(MCInst &Inst, const MCOperand &Opnd)
#define X(NUM, ENUM, NAME)
Definition ELF.h:853
#define LLVM_ABI
Definition Compiler.h:213
#define LLVM_EXTERNAL_VISIBILITY
Definition Compiler.h:132
IRTranslator LLVM IR MI
cl::opt< bool > LArchAnnotateTableJump("loongarch-annotate-tablejump", cl::Hidden, cl::desc("Annotate table jump instruction to correlate it with the jump table."), cl::init(false))
#define F(x, y, z)
Definition MD5.cpp:54
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
void emitNops(unsigned N)
Emit N NOP instructions.
virtual void emitDebugValue(const MCExpr *Value, unsigned Size) const
Emit the directive and value for debug thread local expression.
void EmitToStreamer(MCStreamer &S, const MCInst &Inst)
TargetMachine & TM
Target machine description.
Definition AsmPrinter.h:94
void emitXRayTable()
Emit a table with all XRay instrumentation points.
virtual void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &OS)
Print the MachineOperand as a symbol.
MachineFunction * MF
The current machine function.
Definition AsmPrinter.h:109
virtual void emitJumpTableInfo()
Print assembly representations of the jump tables used by the current function to the current output ...
MCSymbol * GetJTISymbol(unsigned JTID, bool isLinkerPrivate=false) const
Return the symbol for the specified jump table entry.
void recordSled(MCSymbol *Sled, const MachineInstr &MI, SledKind Kind, uint8_t Version=0)
MachineModuleInfo * MMI
This is a pointer to the current MachineModuleInfo.
Definition AsmPrinter.h:112
MCContext & OutContext
This is the context for the output file that we are streaming.
Definition AsmPrinter.h:101
bool runOnMachineFunction(MachineFunction &MF) override
Emit the specified function out to the OutStreamer.
Definition AsmPrinter.h:453
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition AsmPrinter.h:106
const MCAsmInfo & MAI
Target Asm Printer information.
Definition AsmPrinter.h:97
const DataLayout & getDataLayout() const
Return information about data layout.
const MCSubtargetInfo & getSubtargetInfo() const
Return information about subtarget.
virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant.
LLVM_ABI unsigned getPointerSize(unsigned AS=0) const
The pointer representation size in bytes, rounded up to a whole number of bytes.
void emitSled(const MachineInstr &MI, SledKind Kind)
void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI)
bool runOnMachineFunction(MachineFunction &MF) override
Emit the specified function out to the OutStreamer.
void emitDebugValue(const MCExpr *Value, unsigned Size) const override
Emit the directive and value for debug thread local expression.
void LowerSTATEPOINT(const MachineInstr &MI)
void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
void emitInstruction(const MachineInstr *MI) override
Targets should implement this to emit instructions.
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS) override
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant as...
bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const
bool lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst)
void emitJumpTableInfo() override
Print assembly representations of the jump tables used by the current function to the current output ...
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS) override
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant.
void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI)
static const char * getRegisterName(MCRegister Reg)
LoongArchMachineFunctionInfo - This class is derived from MachineFunctionInfo and contains private Lo...
Base class for the full range of assembler expressions which are needed for parsing.
Definition MCExpr.h:34
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
Instances of this class represent operands of the MCInst class.
Definition MCInst.h:40
static MCOperand createReg(MCRegister Reg)
Definition MCInst.h:138
static MCOperand createImm(int64_t Val)
Definition MCInst.h:145
const MCExpr * getExpr() const
Definition MCInst.h:118
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:214
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isCPI() const
isCPI - Tests if this is a MO_ConstantPoolIndex operand.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
bool isBlockAddress() const
isBlockAddress - Tests if this is a MO_BlockAddress operand.
Register getReg() const
getReg - Returns the register number.
@ MO_Immediate
Immediate operand.
@ MO_GlobalAddress
Address of a global value.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
constexpr unsigned id() const
Definition Register.h:100
MI-level Statepoint operands.
Definition StackMaps.h:159
uint32_t getNumPatchBytes() const
Return the number of patchable bytes the given statepoint should emit.
Definition StackMaps.h:208
const MachineOperand & getCallTarget() const
Return the target of the underlying call.
Definition StackMaps.h:213
LLVM Value Representation.
Definition Value.h:75
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ SHT_PROGBITS
Definition ELF.h:1150
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
Target & getTheLoongArch64Target()
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
bool lowerLoongArchMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, AsmPrinter &AP)
Target & getTheLoongArch32Target()
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
RegisterAsmPrinter - Helper template for registering a target specific assembly printer,...