LLVM 20.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"
23#include "llvm/MC/MCContext.h"
27
28using namespace llvm;
29
30#define DEBUG_TYPE "loongarch-asm-printer"
31
33 "loongarch-annotate-tablejump", cl::Hidden,
35 "Annotate table jump instruction to correlate it with the jump table."),
36 cl::init(false));
37
38// Simple pseudo-instructions have their lowering (with expansion to real
39// instructions) auto-generated.
40#include "LoongArchGenMCPseudoLowering.inc"
41
43 LoongArch_MC::verifyInstructionPredicates(
44 MI->getOpcode(), getSubtargetInfo().getFeatureBits());
45
46 // Do any auto-generated pseudo lowerings.
47 if (MCInst OutInst; lowerPseudoInstExpansion(MI, OutInst)) {
48 EmitToStreamer(*OutStreamer, OutInst);
49 return;
50 }
51
52 switch (MI->getOpcode()) {
53 case TargetOpcode::STATEPOINT:
55 return;
56 case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
58 return;
59 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
61 return;
62 case TargetOpcode::PATCHABLE_TAIL_CALL:
64 return;
65 }
66
67 MCInst TmpInst;
68 if (!lowerLoongArchMachineInstrToMCInst(MI, TmpInst, *this))
69 EmitToStreamer(*OutStreamer, TmpInst);
70}
71
73 const char *ExtraCode,
74 raw_ostream &OS) {
75 // First try the generic code, which knows about modifiers like 'c' and 'n'.
76 if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
77 return false;
78
79 const MachineOperand &MO = MI->getOperand(OpNo);
80 if (ExtraCode && ExtraCode[0]) {
81 if (ExtraCode[1] != 0)
82 return true; // Unknown modifier.
83
84 switch (ExtraCode[0]) {
85 default:
86 return true; // Unknown modifier.
87 case 'z': // Print $zero register if zero, regular printing otherwise.
88 if (MO.isImm() && MO.getImm() == 0) {
89 OS << '$' << LoongArchInstPrinter::getRegisterName(LoongArch::R0);
90 return false;
91 }
92 break;
93 case 'w': // Print LSX registers.
94 if (MO.getReg().id() >= LoongArch::VR0 &&
95 MO.getReg().id() <= LoongArch::VR31)
96 break;
97 // The modifier is 'w' but the operand is not an LSX register; Report an
98 // unknown operand error.
99 return true;
100 case 'u': // Print LASX registers.
101 if (MO.getReg().id() >= LoongArch::XR0 &&
102 MO.getReg().id() <= LoongArch::XR31)
103 break;
104 // The modifier is 'u' but the operand is not an LASX register; Report an
105 // unknown operand error.
106 return true;
107 // TODO: handle other extra codes if any.
108 }
109 }
110
111 switch (MO.getType()) {
113 OS << MO.getImm();
114 return false;
117 return false;
120 return false;
121 default:
122 llvm_unreachable("not implemented");
123 }
124
125 return true;
126}
127
129 unsigned OpNo,
130 const char *ExtraCode,
131 raw_ostream &OS) {
132 // TODO: handle extra code.
133 if (ExtraCode)
134 return true;
135
136 // We only support memory operands like "Base + Offset", where base must be a
137 // register, and offset can be a register or an immediate value.
138 const MachineOperand &BaseMO = MI->getOperand(OpNo);
139 // Base address must be a register.
140 if (!BaseMO.isReg())
141 return true;
142 // Print the base address register.
144 // Print the offset operand.
145 const MachineOperand &OffsetMO = MI->getOperand(OpNo + 1);
146 MCOperand MCO;
147 if (!lowerOperand(OffsetMO, MCO))
148 return true;
149 if (OffsetMO.isReg())
150 OS << ", $" << LoongArchInstPrinter::getRegisterName(OffsetMO.getReg());
151 else if (OffsetMO.isImm())
152 OS << ", " << OffsetMO.getImm();
153 else if (OffsetMO.isGlobal() || OffsetMO.isBlockAddress() ||
154 OffsetMO.isMCSymbol())
155 OS << ", " << *MCO.getExpr();
156 else
157 return true;
158
159 return false;
160}
161
163 StatepointOpers SOpers(&MI);
164 if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
165 assert(PatchBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
166 emitNops(PatchBytes / 4);
167 } else {
168 // Lower call target and choose correct opcode.
169 const MachineOperand &CallTarget = SOpers.getCallTarget();
170 MCOperand CallTargetMCOp;
171 switch (CallTarget.getType()) {
174 lowerOperand(CallTarget, CallTargetMCOp);
176 MCInstBuilder(LoongArch::BL).addOperand(CallTargetMCOp));
177 break;
179 CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());
181 MCInstBuilder(LoongArch::BL).addOperand(CallTargetMCOp));
182 break;
184 CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());
185 EmitToStreamer(*OutStreamer, MCInstBuilder(LoongArch::JIRL)
186 .addReg(LoongArch::R1)
187 .addOperand(CallTargetMCOp)
188 .addImm(0));
189 break;
190 default:
191 llvm_unreachable("Unsupported operand type in statepoint call target");
192 break;
193 }
194 }
195
196 auto &Ctx = OutStreamer->getContext();
197 MCSymbol *MILabel = Ctx.createTempSymbol();
198 OutStreamer->emitLabel(MILabel);
199 SM.recordStatepoint(*MILabel, MI);
200}
201
203 const MachineInstr &MI) {
204 const Function &F = MF->getFunction();
205 if (F.hasFnAttribute("patchable-function-entry")) {
206 unsigned Num;
207 if (F.getFnAttribute("patchable-function-entry")
208 .getValueAsString()
209 .getAsInteger(10, Num))
210 return;
211 emitNops(Num);
212 return;
213 }
214
216}
217
220}
221
224}
225
227 // For loongarch64 we want to emit the following pattern:
228 //
229 // .Lxray_sled_beginN:
230 // B .Lxray_sled_endN
231 // 11 NOPs (44 bytes)
232 // .Lxray_sled_endN:
233 //
234 // We need the extra bytes because at runtime they may be used for the
235 // actual pattern defined at compiler-rt/lib/xray/xray_loongarch64.cpp.
236 // The count here should be adjusted accordingly if the implementation
237 // changes.
238 const int8_t NoopsInSledCount = 11;
239 OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());
240 MCSymbol *BeginOfSled = OutContext.createTempSymbol("xray_sled_begin");
241 MCSymbol *EndOfSled = OutContext.createTempSymbol("xray_sled_end");
242 OutStreamer->emitLabel(BeginOfSled);
244 MCInstBuilder(LoongArch::B)
245 .addExpr(MCSymbolRefExpr::create(EndOfSled, OutContext)));
246 emitNops(NoopsInSledCount);
247 OutStreamer->emitLabel(EndOfSled);
248 recordSled(BeginOfSled, MI, Kind, 2);
249}
250
253
255 return;
256
258
259 unsigned Size = getDataLayout().getPointerSize();
260 auto *LAFI = MF->getInfo<LoongArchMachineFunctionInfo>();
261 unsigned EntrySize = LAFI->getJumpInfoSize();
262
263 if (0 == EntrySize)
264 return;
265
266 // Emit an additional section to store the correlation info as pairs of
267 // addresses, each pair contains the address of a jump instruction (jr) and
268 // the address of the jump table.
269 OutStreamer->switchSection(MMI->getContext().getELFSection(
270 ".discard.tablejump_annotate", ELF::SHT_PROGBITS, 0));
271
272 for (unsigned Idx = 0; Idx < EntrySize; ++Idx) {
273 OutStreamer->emitValue(
274 MCSymbolRefExpr::create(LAFI->getJumpInfoJrMI(Idx)->getPreInstrSymbol(),
275 OutContext),
276 Size);
277 OutStreamer->emitValue(
279 GetJTISymbol(LAFI->getJumpInfoJTIMO(Idx)->getIndex()), OutContext),
280 Size);
281 }
282}
283
286 // Emit the XRay table for this function.
288 return true;
289}
290
291// Force static initialization.
295}
static MCDisassembler::DecodeStatus addOperand(MCInst &Inst, const MCOperand &Opnd)
#define LLVM_EXTERNAL_VISIBILITY
Definition: Compiler.h:128
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
uint64_t Size
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
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))
LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmPrinter()
#define F(x, y, z)
Definition: MD5.cpp:55
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
void emitNops(unsigned N)
Emit N NOP instructions.
void EmitToStreamer(MCStreamer &S, const MCInst &Inst)
Definition: AsmPrinter.cpp:428
TargetMachine & TM
Target machine description.
Definition: AsmPrinter.h:89
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:104
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:107
MCContext & OutContext
This is the context for the output file that we are streaming.
Definition: AsmPrinter.h:96
bool runOnMachineFunction(MachineFunction &MF) override
Emit the specified function out to the OutStreamer.
Definition: AsmPrinter.h:387
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition: AsmPrinter.h:101
StackMaps SM
Definition: AsmPrinter.h:199
const DataLayout & getDataLayout() const
Return information about data layout.
Definition: AsmPrinter.cpp:412
const MCSubtargetInfo & getSubtargetInfo() const
Return information about subtarget.
Definition: AsmPrinter.cpp:423
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.
unsigned getPointerSize(unsigned AS=0) const
Layout pointer size in bytes, rounded up to a whole number of bytes.
Definition: DataLayout.cpp:739
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 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...
MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
Definition: MCContext.cpp:345
MCSectionELF * getELFSection(const Twine &Section, unsigned Type, unsigned Flags)
Definition: MCContext.h:551
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:185
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:37
static MCOperand createReg(MCRegister Reg)
Definition: MCInst.h:135
static MCOperand createImm(int64_t Val)
Definition: MCInst.h:142
const MCExpr * getExpr() const
Definition: MCInst.h:115
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
Definition: MCExpr.h:398
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Representation of each machine instruction.
Definition: MachineInstr.h:69
const MCContext & getContext() const
MachineOperand class - Representation of each machine instruction operand.
bool isMCSymbol() const
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register 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:103
void recordStatepoint(const MCSymbol &L, const MachineInstr &MI)
Generate a stackmap record for a statepoint instruction.
Definition: StackMaps.cpp:562
MI-level Statepoint operands.
Definition: StackMaps.h:158
uint32_t getNumPatchBytes() const
Return the number of patchable bytes the given statepoint should emit.
Definition: StackMaps.h:207
const MachineOperand & getCallTarget() const
Return the target of the underlying call.
Definition: StackMaps.h:212
const Triple & getTargetTriple() const
bool isOSBinFormatELF() const
Tests whether the OS uses the ELF binary format.
Definition: Triple.h:730
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ SHT_PROGBITS
Definition: ELF.h:1090
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
Target & getTheLoongArch64Target()
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,...