181ad6265SDimitry Andric //===- LoongArchAsmPrinter.cpp - LoongArch LLVM Assembly Printer -*- C++ -*--=//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This file contains a printer that converts from our internal representation
1081ad6265SDimitry Andric // of machine-dependent LLVM code to GAS-format LoongArch assembly language.
1181ad6265SDimitry Andric //
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric
1481ad6265SDimitry Andric #include "LoongArchAsmPrinter.h"
1581ad6265SDimitry Andric #include "LoongArch.h"
1681ad6265SDimitry Andric #include "LoongArchTargetMachine.h"
17bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchInstPrinter.h"
1881ad6265SDimitry Andric #include "TargetInfo/LoongArchTargetInfo.h"
1981ad6265SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
20*06c3fb27SDimitry Andric #include "llvm/MC/MCContext.h"
21*06c3fb27SDimitry Andric #include "llvm/MC/MCInstBuilder.h"
2281ad6265SDimitry Andric #include "llvm/MC/TargetRegistry.h"
2381ad6265SDimitry Andric
2481ad6265SDimitry Andric using namespace llvm;
2581ad6265SDimitry Andric
2681ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-asm-printer"
2781ad6265SDimitry Andric
2881ad6265SDimitry Andric // Simple pseudo-instructions have their lowering (with expansion to real
2981ad6265SDimitry Andric // instructions) auto-generated.
3081ad6265SDimitry Andric #include "LoongArchGenMCPseudoLowering.inc"
3181ad6265SDimitry Andric
emitInstruction(const MachineInstr * MI)3281ad6265SDimitry Andric void LoongArchAsmPrinter::emitInstruction(const MachineInstr *MI) {
33753f127fSDimitry Andric LoongArch_MC::verifyInstructionPredicates(
34753f127fSDimitry Andric MI->getOpcode(), getSubtargetInfo().getFeatureBits());
35753f127fSDimitry Andric
3681ad6265SDimitry Andric // Do any auto-generated pseudo lowerings.
3781ad6265SDimitry Andric if (emitPseudoExpansionLowering(*OutStreamer, MI))
3881ad6265SDimitry Andric return;
3981ad6265SDimitry Andric
40*06c3fb27SDimitry Andric switch (MI->getOpcode()) {
41*06c3fb27SDimitry Andric case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
42*06c3fb27SDimitry Andric LowerPATCHABLE_FUNCTION_ENTER(*MI);
43*06c3fb27SDimitry Andric return;
44*06c3fb27SDimitry Andric case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
45*06c3fb27SDimitry Andric LowerPATCHABLE_FUNCTION_EXIT(*MI);
46*06c3fb27SDimitry Andric return;
47*06c3fb27SDimitry Andric case TargetOpcode::PATCHABLE_TAIL_CALL:
48*06c3fb27SDimitry Andric LowerPATCHABLE_TAIL_CALL(*MI);
49*06c3fb27SDimitry Andric return;
50*06c3fb27SDimitry Andric }
51*06c3fb27SDimitry Andric
5281ad6265SDimitry Andric MCInst TmpInst;
5381ad6265SDimitry Andric if (!lowerLoongArchMachineInstrToMCInst(MI, TmpInst, *this))
5481ad6265SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst);
5581ad6265SDimitry Andric }
5681ad6265SDimitry Andric
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)57bdd1243dSDimitry Andric bool LoongArchAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
58bdd1243dSDimitry Andric const char *ExtraCode,
59bdd1243dSDimitry Andric raw_ostream &OS) {
60bdd1243dSDimitry Andric // First try the generic code, which knows about modifiers like 'c' and 'n'.
61bdd1243dSDimitry Andric if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
62bdd1243dSDimitry Andric return false;
63bdd1243dSDimitry Andric
64bdd1243dSDimitry Andric const MachineOperand &MO = MI->getOperand(OpNo);
65bdd1243dSDimitry Andric if (ExtraCode && ExtraCode[0]) {
66bdd1243dSDimitry Andric if (ExtraCode[1] != 0)
67bdd1243dSDimitry Andric return true; // Unknown modifier.
68bdd1243dSDimitry Andric
69bdd1243dSDimitry Andric switch (ExtraCode[0]) {
70bdd1243dSDimitry Andric default:
71bdd1243dSDimitry Andric return true; // Unknown modifier.
72bdd1243dSDimitry Andric case 'z': // Print $zero register if zero, regular printing otherwise.
73bdd1243dSDimitry Andric if (MO.isImm() && MO.getImm() == 0) {
74bdd1243dSDimitry Andric OS << '$' << LoongArchInstPrinter::getRegisterName(LoongArch::R0);
75bdd1243dSDimitry Andric return false;
76bdd1243dSDimitry Andric }
77bdd1243dSDimitry Andric break;
78*06c3fb27SDimitry Andric case 'w': // Print LSX registers.
79*06c3fb27SDimitry Andric if (MO.getReg().id() >= LoongArch::VR0 &&
80*06c3fb27SDimitry Andric MO.getReg().id() <= LoongArch::VR31)
81*06c3fb27SDimitry Andric break;
82*06c3fb27SDimitry Andric // The modifier is 'w' but the operand is not an LSX register; Report an
83*06c3fb27SDimitry Andric // unknown operand error.
84*06c3fb27SDimitry Andric return true;
85*06c3fb27SDimitry Andric case 'u': // Print LASX registers.
86*06c3fb27SDimitry Andric if (MO.getReg().id() >= LoongArch::XR0 &&
87*06c3fb27SDimitry Andric MO.getReg().id() <= LoongArch::XR31)
88*06c3fb27SDimitry Andric break;
89*06c3fb27SDimitry Andric // The modifier is 'u' but the operand is not an LASX register; Report an
90*06c3fb27SDimitry Andric // unknown operand error.
91*06c3fb27SDimitry Andric return true;
92bdd1243dSDimitry Andric // TODO: handle other extra codes if any.
93bdd1243dSDimitry Andric }
94bdd1243dSDimitry Andric }
95bdd1243dSDimitry Andric
96bdd1243dSDimitry Andric switch (MO.getType()) {
97bdd1243dSDimitry Andric case MachineOperand::MO_Immediate:
98bdd1243dSDimitry Andric OS << MO.getImm();
99bdd1243dSDimitry Andric return false;
100bdd1243dSDimitry Andric case MachineOperand::MO_Register:
101bdd1243dSDimitry Andric OS << '$' << LoongArchInstPrinter::getRegisterName(MO.getReg());
102bdd1243dSDimitry Andric return false;
103bdd1243dSDimitry Andric case MachineOperand::MO_GlobalAddress:
104bdd1243dSDimitry Andric PrintSymbolOperand(MO, OS);
105bdd1243dSDimitry Andric return false;
106bdd1243dSDimitry Andric default:
107bdd1243dSDimitry Andric llvm_unreachable("not implemented");
108bdd1243dSDimitry Andric }
109bdd1243dSDimitry Andric
110bdd1243dSDimitry Andric return true;
111bdd1243dSDimitry Andric }
112bdd1243dSDimitry Andric
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)113bdd1243dSDimitry Andric bool LoongArchAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
114bdd1243dSDimitry Andric unsigned OpNo,
115bdd1243dSDimitry Andric const char *ExtraCode,
116bdd1243dSDimitry Andric raw_ostream &OS) {
117bdd1243dSDimitry Andric // TODO: handle extra code.
118bdd1243dSDimitry Andric if (ExtraCode)
119bdd1243dSDimitry Andric return true;
120bdd1243dSDimitry Andric
121bdd1243dSDimitry Andric // We only support memory operands like "Base + Offset", where base must be a
122bdd1243dSDimitry Andric // register, and offset can be a register or an immediate value.
123bdd1243dSDimitry Andric const MachineOperand &BaseMO = MI->getOperand(OpNo);
124bdd1243dSDimitry Andric // Base address must be a register.
125bdd1243dSDimitry Andric if (!BaseMO.isReg())
126bdd1243dSDimitry Andric return true;
127bdd1243dSDimitry Andric // Print the base address register.
128bdd1243dSDimitry Andric OS << "$" << LoongArchInstPrinter::getRegisterName(BaseMO.getReg());
129bdd1243dSDimitry Andric // Print the offset operand.
130bdd1243dSDimitry Andric const MachineOperand &OffsetMO = MI->getOperand(OpNo + 1);
131bdd1243dSDimitry Andric if (OffsetMO.isReg())
132bdd1243dSDimitry Andric OS << ", $" << LoongArchInstPrinter::getRegisterName(OffsetMO.getReg());
133bdd1243dSDimitry Andric else if (OffsetMO.isImm())
134bdd1243dSDimitry Andric OS << ", " << OffsetMO.getImm();
135bdd1243dSDimitry Andric else
136bdd1243dSDimitry Andric return true;
137bdd1243dSDimitry Andric
138bdd1243dSDimitry Andric return false;
139bdd1243dSDimitry Andric }
140bdd1243dSDimitry Andric
LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr & MI)141*06c3fb27SDimitry Andric void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
142*06c3fb27SDimitry Andric const MachineInstr &MI) {
143*06c3fb27SDimitry Andric const Function &F = MF->getFunction();
144*06c3fb27SDimitry Andric if (F.hasFnAttribute("patchable-function-entry")) {
145*06c3fb27SDimitry Andric unsigned Num;
146*06c3fb27SDimitry Andric if (F.getFnAttribute("patchable-function-entry")
147*06c3fb27SDimitry Andric .getValueAsString()
148*06c3fb27SDimitry Andric .getAsInteger(10, Num))
149*06c3fb27SDimitry Andric return;
150*06c3fb27SDimitry Andric emitNops(Num);
151*06c3fb27SDimitry Andric return;
152*06c3fb27SDimitry Andric }
153*06c3fb27SDimitry Andric
154*06c3fb27SDimitry Andric emitSled(MI, SledKind::FUNCTION_ENTER);
155*06c3fb27SDimitry Andric }
156*06c3fb27SDimitry Andric
LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr & MI)157*06c3fb27SDimitry Andric void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {
158*06c3fb27SDimitry Andric emitSled(MI, SledKind::FUNCTION_EXIT);
159*06c3fb27SDimitry Andric }
160*06c3fb27SDimitry Andric
LowerPATCHABLE_TAIL_CALL(const MachineInstr & MI)161*06c3fb27SDimitry Andric void LoongArchAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {
162*06c3fb27SDimitry Andric emitSled(MI, SledKind::TAIL_CALL);
163*06c3fb27SDimitry Andric }
164*06c3fb27SDimitry Andric
emitSled(const MachineInstr & MI,SledKind Kind)165*06c3fb27SDimitry Andric void LoongArchAsmPrinter::emitSled(const MachineInstr &MI, SledKind Kind) {
166*06c3fb27SDimitry Andric // For loongarch64 we want to emit the following pattern:
167*06c3fb27SDimitry Andric //
168*06c3fb27SDimitry Andric // .Lxray_sled_beginN:
169*06c3fb27SDimitry Andric // B .Lxray_sled_endN
170*06c3fb27SDimitry Andric // 11 NOPs (44 bytes)
171*06c3fb27SDimitry Andric // .Lxray_sled_endN:
172*06c3fb27SDimitry Andric //
173*06c3fb27SDimitry Andric // We need the extra bytes because at runtime they may be used for the
174*06c3fb27SDimitry Andric // actual pattern defined at compiler-rt/lib/xray/xray_loongarch64.cpp.
175*06c3fb27SDimitry Andric // The count here should be adjusted accordingly if the implementation
176*06c3fb27SDimitry Andric // changes.
177*06c3fb27SDimitry Andric const int8_t NoopsInSledCount = 11;
178*06c3fb27SDimitry Andric OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());
179*06c3fb27SDimitry Andric MCSymbol *BeginOfSled = OutContext.createTempSymbol("xray_sled_begin");
180*06c3fb27SDimitry Andric MCSymbol *EndOfSled = OutContext.createTempSymbol("xray_sled_end");
181*06c3fb27SDimitry Andric OutStreamer->emitLabel(BeginOfSled);
182*06c3fb27SDimitry Andric EmitToStreamer(*OutStreamer,
183*06c3fb27SDimitry Andric MCInstBuilder(LoongArch::B)
184*06c3fb27SDimitry Andric .addExpr(MCSymbolRefExpr::create(EndOfSled, OutContext)));
185*06c3fb27SDimitry Andric emitNops(NoopsInSledCount);
186*06c3fb27SDimitry Andric OutStreamer->emitLabel(EndOfSled);
187*06c3fb27SDimitry Andric recordSled(BeginOfSled, MI, Kind, 2);
188*06c3fb27SDimitry Andric }
189*06c3fb27SDimitry Andric
runOnMachineFunction(MachineFunction & MF)19081ad6265SDimitry Andric bool LoongArchAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
19181ad6265SDimitry Andric AsmPrinter::runOnMachineFunction(MF);
192*06c3fb27SDimitry Andric // Emit the XRay table for this function.
193*06c3fb27SDimitry Andric emitXRayTable();
19481ad6265SDimitry Andric return true;
19581ad6265SDimitry Andric }
19681ad6265SDimitry Andric
19781ad6265SDimitry Andric // Force static initialization.
LLVMInitializeLoongArchAsmPrinter()19881ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmPrinter() {
19981ad6265SDimitry Andric RegisterAsmPrinter<LoongArchAsmPrinter> X(getTheLoongArch32Target());
20081ad6265SDimitry Andric RegisterAsmPrinter<LoongArchAsmPrinter> Y(getTheLoongArch64Target());
20181ad6265SDimitry Andric }
202