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" 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" 23 24 using namespace llvm; 25 26 #define DEBUG_TYPE "loongarch-asm-printer" 27 28 // Simple pseudo-instructions have their lowering (with expansion to real 29 // instructions) auto-generated. 30 #include "LoongArchGenMCPseudoLowering.inc" 31 32 void LoongArchAsmPrinter::emitInstruction(const MachineInstr *MI) { 33 LoongArch_MC::verifyInstructionPredicates( 34 MI->getOpcode(), getSubtargetInfo().getFeatureBits()); 35 36 // Do any auto-generated pseudo lowerings. 37 if (emitPseudoExpansionLowering(*OutStreamer, MI)) 38 return; 39 40 switch (MI->getOpcode()) { 41 case TargetOpcode::PATCHABLE_FUNCTION_ENTER: 42 LowerPATCHABLE_FUNCTION_ENTER(*MI); 43 return; 44 case TargetOpcode::PATCHABLE_FUNCTION_EXIT: 45 LowerPATCHABLE_FUNCTION_EXIT(*MI); 46 return; 47 case TargetOpcode::PATCHABLE_TAIL_CALL: 48 LowerPATCHABLE_TAIL_CALL(*MI); 49 return; 50 } 51 52 MCInst TmpInst; 53 if (!lowerLoongArchMachineInstrToMCInst(MI, TmpInst, *this)) 54 EmitToStreamer(*OutStreamer, TmpInst); 55 } 56 57 bool LoongArchAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 58 const char *ExtraCode, 59 raw_ostream &OS) { 60 // First try the generic code, which knows about modifiers like 'c' and 'n'. 61 if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS)) 62 return false; 63 64 const MachineOperand &MO = MI->getOperand(OpNo); 65 if (ExtraCode && ExtraCode[0]) { 66 if (ExtraCode[1] != 0) 67 return true; // Unknown modifier. 68 69 switch (ExtraCode[0]) { 70 default: 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); 75 return false; 76 } 77 break; 78 case 'w': // Print LSX registers. 79 if (MO.getReg().id() >= LoongArch::VR0 && 80 MO.getReg().id() <= LoongArch::VR31) 81 break; 82 // The modifier is 'w' but the operand is not an LSX register; Report an 83 // unknown operand error. 84 return true; 85 case 'u': // Print LASX registers. 86 if (MO.getReg().id() >= LoongArch::XR0 && 87 MO.getReg().id() <= LoongArch::XR31) 88 break; 89 // The modifier is 'u' but the operand is not an LASX register; Report an 90 // unknown operand error. 91 return true; 92 // TODO: handle other extra codes if any. 93 } 94 } 95 96 switch (MO.getType()) { 97 case MachineOperand::MO_Immediate: 98 OS << MO.getImm(); 99 return false; 100 case MachineOperand::MO_Register: 101 OS << '$' << LoongArchInstPrinter::getRegisterName(MO.getReg()); 102 return false; 103 case MachineOperand::MO_GlobalAddress: 104 PrintSymbolOperand(MO, OS); 105 return false; 106 default: 107 llvm_unreachable("not implemented"); 108 } 109 110 return true; 111 } 112 113 bool LoongArchAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 114 unsigned OpNo, 115 const char *ExtraCode, 116 raw_ostream &OS) { 117 // TODO: handle extra code. 118 if (ExtraCode) 119 return true; 120 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. 125 if (!BaseMO.isReg()) 126 return true; 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(); 135 else 136 return true; 137 138 return false; 139 } 140 141 void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER( 142 const MachineInstr &MI) { 143 const Function &F = MF->getFunction(); 144 if (F.hasFnAttribute("patchable-function-entry")) { 145 unsigned Num; 146 if (F.getFnAttribute("patchable-function-entry") 147 .getValueAsString() 148 .getAsInteger(10, Num)) 149 return; 150 emitNops(Num); 151 return; 152 } 153 154 emitSled(MI, SledKind::FUNCTION_ENTER); 155 } 156 157 void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) { 158 emitSled(MI, SledKind::FUNCTION_EXIT); 159 } 160 161 void LoongArchAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) { 162 emitSled(MI, SledKind::TAIL_CALL); 163 } 164 165 void LoongArchAsmPrinter::emitSled(const MachineInstr &MI, SledKind Kind) { 166 // For loongarch64 we want to emit the following pattern: 167 // 168 // .Lxray_sled_beginN: 169 // B .Lxray_sled_endN 170 // 11 NOPs (44 bytes) 171 // .Lxray_sled_endN: 172 // 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 176 // changes. 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); 188 } 189 190 bool LoongArchAsmPrinter::runOnMachineFunction(MachineFunction &MF) { 191 AsmPrinter::runOnMachineFunction(MF); 192 // Emit the XRay table for this function. 193 emitXRayTable(); 194 return true; 195 } 196 197 // Force static initialization. 198 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmPrinter() { 199 RegisterAsmPrinter<LoongArchAsmPrinter> X(getTheLoongArch32Target()); 200 RegisterAsmPrinter<LoongArchAsmPrinter> Y(getTheLoongArch64Target()); 201 } 202