1 //===- LoongArchAsmPrinter.cpp - LoongArch LLVM Assembly Printer -*- C++ -*--=//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains a printer that converts from our internal representation
10 // of machine-dependent LLVM code to GAS-format LoongArch assembly language.
12 //===----------------------------------------------------------------------===//
14 #include "LoongArchAsmPrinter.h"
15 #include "LoongArch.h"
16 #include "LoongArchTargetMachine.h"
17 #include "MCTargetDesc/LoongArchInstPrinter.h"
18 #include "TargetInfo/LoongArchTargetInfo.h"
19 #include "llvm/CodeGen/AsmPrinter.h"
20 #include "llvm/MC/MCContext.h"
21 #include "llvm/MC/MCInstBuilder.h"
22 #include "llvm/MC/TargetRegistry.h"
26 #define DEBUG_TYPE "loongarch-asm-printer"
28 // Simple pseudo-instructions have their lowering (with expansion to real
29 // instructions) auto-generated.
30 #include "LoongArchGenMCPseudoLowering.inc"
32 void LoongArchAsmPrinter::emitInstruction(const MachineInstr
*MI
) {
33 LoongArch_MC::verifyInstructionPredicates(
34 MI
->getOpcode(), getSubtargetInfo().getFeatureBits());
36 // Do any auto-generated pseudo lowerings.
37 if (emitPseudoExpansionLowering(*OutStreamer
, MI
))
40 switch (MI
->getOpcode()) {
41 case TargetOpcode::PATCHABLE_FUNCTION_ENTER
:
42 LowerPATCHABLE_FUNCTION_ENTER(*MI
);
44 case TargetOpcode::PATCHABLE_FUNCTION_EXIT
:
45 LowerPATCHABLE_FUNCTION_EXIT(*MI
);
47 case TargetOpcode::PATCHABLE_TAIL_CALL
:
48 LowerPATCHABLE_TAIL_CALL(*MI
);
53 if (!lowerLoongArchMachineInstrToMCInst(MI
, TmpInst
, *this))
54 EmitToStreamer(*OutStreamer
, TmpInst
);
57 bool LoongArchAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
58 const char *ExtraCode
,
60 // First try the generic code, which knows about modifiers like 'c' and 'n'.
61 if (!AsmPrinter::PrintAsmOperand(MI
, OpNo
, ExtraCode
, OS
))
64 const MachineOperand
&MO
= MI
->getOperand(OpNo
);
65 if (ExtraCode
&& ExtraCode
[0]) {
66 if (ExtraCode
[1] != 0)
67 return true; // Unknown modifier.
69 switch (ExtraCode
[0]) {
71 return true; // Unknown modifier.
72 case 'z': // Print $zero register if zero, regular printing otherwise.
73 if (MO
.isImm() && MO
.getImm() == 0) {
74 OS
<< '$' << LoongArchInstPrinter::getRegisterName(LoongArch::R0
);
78 case 'w': // Print LSX registers.
79 if (MO
.getReg().id() >= LoongArch::VR0
&&
80 MO
.getReg().id() <= LoongArch::VR31
)
82 // The modifier is 'w' but the operand is not an LSX register; Report an
83 // unknown operand error.
85 case 'u': // Print LASX registers.
86 if (MO
.getReg().id() >= LoongArch::XR0
&&
87 MO
.getReg().id() <= LoongArch::XR31
)
89 // The modifier is 'u' but the operand is not an LASX register; Report an
90 // unknown operand error.
92 // TODO: handle other extra codes if any.
96 switch (MO
.getType()) {
97 case MachineOperand::MO_Immediate
:
100 case MachineOperand::MO_Register
:
101 OS
<< '$' << LoongArchInstPrinter::getRegisterName(MO
.getReg());
103 case MachineOperand::MO_GlobalAddress
:
104 PrintSymbolOperand(MO
, OS
);
107 llvm_unreachable("not implemented");
113 bool LoongArchAsmPrinter::PrintAsmMemoryOperand(const MachineInstr
*MI
,
115 const char *ExtraCode
,
117 // TODO: handle extra code.
121 // We only support memory operands like "Base + Offset", where base must be a
122 // register, and offset can be a register or an immediate value.
123 const MachineOperand
&BaseMO
= MI
->getOperand(OpNo
);
124 // Base address must be a register.
127 // Print the base address register.
128 OS
<< "$" << LoongArchInstPrinter::getRegisterName(BaseMO
.getReg());
129 // Print the offset operand.
130 const MachineOperand
&OffsetMO
= MI
->getOperand(OpNo
+ 1);
131 if (OffsetMO
.isReg())
132 OS
<< ", $" << LoongArchInstPrinter::getRegisterName(OffsetMO
.getReg());
133 else if (OffsetMO
.isImm())
134 OS
<< ", " << OffsetMO
.getImm();
141 void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
142 const MachineInstr
&MI
) {
143 const Function
&F
= MF
->getFunction();
144 if (F
.hasFnAttribute("patchable-function-entry")) {
146 if (F
.getFnAttribute("patchable-function-entry")
148 .getAsInteger(10, Num
))
154 emitSled(MI
, SledKind::FUNCTION_ENTER
);
157 void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr
&MI
) {
158 emitSled(MI
, SledKind::FUNCTION_EXIT
);
161 void LoongArchAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr
&MI
) {
162 emitSled(MI
, SledKind::TAIL_CALL
);
165 void LoongArchAsmPrinter::emitSled(const MachineInstr
&MI
, SledKind Kind
) {
166 // For loongarch64 we want to emit the following pattern:
168 // .Lxray_sled_beginN:
169 // B .Lxray_sled_endN
170 // 11 NOPs (44 bytes)
173 // We need the extra bytes because at runtime they may be used for the
174 // actual pattern defined at compiler-rt/lib/xray/xray_loongarch64.cpp.
175 // The count here should be adjusted accordingly if the implementation
177 const int8_t NoopsInSledCount
= 11;
178 OutStreamer
->emitCodeAlignment(Align(4), &getSubtargetInfo());
179 MCSymbol
*BeginOfSled
= OutContext
.createTempSymbol("xray_sled_begin");
180 MCSymbol
*EndOfSled
= OutContext
.createTempSymbol("xray_sled_end");
181 OutStreamer
->emitLabel(BeginOfSled
);
182 EmitToStreamer(*OutStreamer
,
183 MCInstBuilder(LoongArch::B
)
184 .addExpr(MCSymbolRefExpr::create(EndOfSled
, OutContext
)));
185 emitNops(NoopsInSledCount
);
186 OutStreamer
->emitLabel(EndOfSled
);
187 recordSled(BeginOfSled
, MI
, Kind
, 2);
190 bool LoongArchAsmPrinter::runOnMachineFunction(MachineFunction
&MF
) {
191 AsmPrinter::runOnMachineFunction(MF
);
192 // Emit the XRay table for this function.
197 // Force static initialization.
198 extern "C" LLVM_EXTERNAL_VISIBILITY
void LLVMInitializeLoongArchAsmPrinter() {
199 RegisterAsmPrinter
<LoongArchAsmPrinter
> X(getTheLoongArch32Target());
200 RegisterAsmPrinter
<LoongArchAsmPrinter
> Y(getTheLoongArch64Target());