1 //===-- ARMMCInstLower.cpp - Convert ARM MachineInstr to an MCInst --------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains code to lower ARM MachineInstrs to their corresponding 11 // MCInst records. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "ARM.h" 16 #include "ARMAsmPrinter.h" 17 #include "MCTargetDesc/ARMBaseInfo.h" 18 #include "MCTargetDesc/ARMMCExpr.h" 19 #include "llvm/CodeGen/MachineBasicBlock.h" 20 #include "llvm/IR/Constants.h" 21 #include "llvm/IR/Mangler.h" 22 #include "llvm/MC/MCExpr.h" 23 #include "llvm/MC/MCInst.h" 24 #include "llvm/MC/MCContext.h" 25 #include "llvm/MC/MCSymbolELF.h" 26 #include "llvm/MC/MCSectionELF.h" 27 #include "llvm/MC/MCSectionMachO.h" 28 #include "llvm/MC/MCInstBuilder.h" 29 #include "llvm/MC/MCStreamer.h" 30 using namespace llvm; 31 32 33 MCOperand ARMAsmPrinter::GetSymbolRef(const MachineOperand &MO, 34 const MCSymbol *Symbol) { 35 const MCExpr *Expr = 36 MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext); 37 switch (MO.getTargetFlags() & ARMII::MO_OPTION_MASK) { 38 default: 39 llvm_unreachable("Unknown target flag on symbol operand"); 40 case ARMII::MO_NO_FLAG: 41 break; 42 case ARMII::MO_LO16: 43 Expr = 44 MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext); 45 Expr = ARMMCExpr::createLower16(Expr, OutContext); 46 break; 47 case ARMII::MO_HI16: 48 Expr = 49 MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext); 50 Expr = ARMMCExpr::createUpper16(Expr, OutContext); 51 break; 52 } 53 54 if (!MO.isJTI() && MO.getOffset()) 55 Expr = MCBinaryExpr::createAdd(Expr, 56 MCConstantExpr::create(MO.getOffset(), 57 OutContext), 58 OutContext); 59 return MCOperand::createExpr(Expr); 60 61 } 62 63 bool ARMAsmPrinter::lowerOperand(const MachineOperand &MO, 64 MCOperand &MCOp) { 65 switch (MO.getType()) { 66 default: llvm_unreachable("unknown operand type"); 67 case MachineOperand::MO_Register: 68 // Ignore all non-CPSR implicit register operands. 69 if (MO.isImplicit() && MO.getReg() != ARM::CPSR) 70 return false; 71 assert(!MO.getSubReg() && "Subregs should be eliminated!"); 72 MCOp = MCOperand::createReg(MO.getReg()); 73 break; 74 case MachineOperand::MO_Immediate: 75 MCOp = MCOperand::createImm(MO.getImm()); 76 break; 77 case MachineOperand::MO_MachineBasicBlock: 78 MCOp = MCOperand::createExpr(MCSymbolRefExpr::create( 79 MO.getMBB()->getSymbol(), OutContext)); 80 break; 81 case MachineOperand::MO_GlobalAddress: { 82 MCOp = GetSymbolRef(MO, 83 GetARMGVSymbol(MO.getGlobal(), MO.getTargetFlags())); 84 break; 85 } 86 case MachineOperand::MO_ExternalSymbol: 87 MCOp = GetSymbolRef(MO, 88 GetExternalSymbolSymbol(MO.getSymbolName())); 89 break; 90 case MachineOperand::MO_JumpTableIndex: 91 MCOp = GetSymbolRef(MO, GetJTISymbol(MO.getIndex())); 92 break; 93 case MachineOperand::MO_ConstantPoolIndex: 94 MCOp = GetSymbolRef(MO, GetCPISymbol(MO.getIndex())); 95 break; 96 case MachineOperand::MO_BlockAddress: 97 MCOp = GetSymbolRef(MO, GetBlockAddressSymbol(MO.getBlockAddress())); 98 break; 99 case MachineOperand::MO_FPImmediate: { 100 APFloat Val = MO.getFPImm()->getValueAPF(); 101 bool ignored; 102 Val.convert(APFloat::IEEEdouble, APFloat::rmTowardZero, &ignored); 103 MCOp = MCOperand::createFPImm(Val.convertToDouble()); 104 break; 105 } 106 case MachineOperand::MO_RegisterMask: 107 // Ignore call clobbers. 108 return false; 109 } 110 return true; 111 } 112 113 void llvm::LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, 114 ARMAsmPrinter &AP) { 115 OutMI.setOpcode(MI->getOpcode()); 116 117 // In the MC layer, we keep modified immediates in their encoded form 118 bool EncodeImms = false; 119 switch (MI->getOpcode()) { 120 default: break; 121 case ARM::MOVi: 122 case ARM::MVNi: 123 case ARM::CMPri: 124 case ARM::CMNri: 125 case ARM::TSTri: 126 case ARM::TEQri: 127 case ARM::MSRi: 128 case ARM::ADCri: 129 case ARM::ADDri: 130 case ARM::ADDSri: 131 case ARM::SBCri: 132 case ARM::SUBri: 133 case ARM::SUBSri: 134 case ARM::ANDri: 135 case ARM::ORRri: 136 case ARM::EORri: 137 case ARM::BICri: 138 case ARM::RSBri: 139 case ARM::RSBSri: 140 case ARM::RSCri: 141 EncodeImms = true; 142 break; 143 } 144 145 for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { 146 const MachineOperand &MO = MI->getOperand(i); 147 148 MCOperand MCOp; 149 if (AP.lowerOperand(MO, MCOp)) { 150 if (MCOp.isImm() && EncodeImms) { 151 int32_t Enc = ARM_AM::getSOImmVal(MCOp.getImm()); 152 if (Enc != -1) 153 MCOp.setImm(Enc); 154 } 155 OutMI.addOperand(MCOp); 156 } 157 } 158 } 159 160 void ARMAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) 161 { 162 if (MI.getParent()->getParent()->getInfo<ARMFunctionInfo>() 163 ->isThumbFunction()) 164 { 165 MI.emitError("An attempt to perform XRay instrumentation for a" 166 " Thumb function (not supported). Detected when emitting a sled."); 167 return; 168 } 169 static const int8_t NoopsInSledCount = 6; 170 // We want to emit the following pattern: 171 // 172 // .Lxray_sled_N: 173 // ALIGN 174 // B #20 175 // ; 6 NOP instructions (24 bytes) 176 // .tmpN 177 // 178 // We need the 24 bytes (6 instructions) because at runtime, we'd be patching 179 // over the full 28 bytes (7 instructions) with the following pattern: 180 // 181 // PUSH{ r0, lr } 182 // MOVW r0, #<lower 16 bits of function ID> 183 // MOVT r0, #<higher 16 bits of function ID> 184 // MOVW ip, #<lower 16 bits of address of __xray_FunctionEntry/Exit> 185 // MOVT ip, #<higher 16 bits of address of __xray_FunctionEntry/Exit> 186 // BLX ip 187 // POP{ r0, lr } 188 // 189 OutStreamer->EmitCodeAlignment(4); 190 auto CurSled = OutContext.createTempSymbol("xray_sled_", true); 191 OutStreamer->EmitLabel(CurSled); 192 auto Target = OutContext.createTempSymbol(); 193 194 // Emit "B #20" instruction, which jumps over the next 24 bytes (because 195 // register pc is 8 bytes ahead of the jump instruction by the moment CPU 196 // is executing it). 197 // By analogy to ARMAsmPrinter::emitPseudoExpansionLowering() |case ARM::B|. 198 // It is not clear why |addReg(0)| is needed (the last operand). 199 EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::Bcc).addImm(20) 200 .addImm(ARMCC::AL).addReg(0)); 201 202 MCInst Noop; 203 Subtarget->getInstrInfo()->getNoopForElfTarget(Noop); 204 for (int8_t I = 0; I < NoopsInSledCount; I++) 205 { 206 OutStreamer->EmitInstruction(Noop, getSubtargetInfo()); 207 } 208 209 OutStreamer->EmitLabel(Target); 210 recordSled(CurSled, MI, Kind); 211 } 212 213 void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI) 214 { 215 EmitSled(MI, SledKind::FUNCTION_ENTER); 216 } 217 218 void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) 219 { 220 EmitSled(MI, SledKind::FUNCTION_EXIT); 221 } 222 223 void ARMAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) 224 { 225 EmitSled(MI, SledKind::TAIL_CALL); 226 } 227 228 void ARMAsmPrinter::EmitXRayTable() 229 { 230 if (Sleds.empty()) 231 return; 232 233 MCSection *Section = nullptr; 234 if (Subtarget->isTargetELF()) { 235 Section = OutContext.getELFSection("xray_instr_map", ELF::SHT_PROGBITS, 236 ELF::SHF_ALLOC | ELF::SHF_GROUP | 237 ELF::SHF_MERGE, 238 0, CurrentFnSym->getName()); 239 } else if (Subtarget->isTargetMachO()) { 240 Section = OutContext.getMachOSection("__DATA", "xray_instr_map", 0, 241 SectionKind::getReadOnlyWithRel()); 242 } else { 243 llvm_unreachable("Unsupported target"); 244 } 245 246 auto PrevSection = OutStreamer->getCurrentSectionOnly(); 247 OutStreamer->SwitchSection(Section); 248 for (const auto &Sled : Sleds) { 249 OutStreamer->EmitSymbolValue(Sled.Sled, 4); 250 OutStreamer->EmitSymbolValue(CurrentFnSym, 4); 251 auto Kind = static_cast<uint8_t>(Sled.Kind); 252 OutStreamer->EmitBytes( 253 StringRef(reinterpret_cast<const char *>(&Kind), 1)); 254 OutStreamer->EmitBytes( 255 StringRef(reinterpret_cast<const char *>(&Sled.AlwaysInstrument), 1)); 256 OutStreamer->EmitZeros(6); 257 } 258 OutStreamer->SwitchSection(PrevSection); 259 260 Sleds.clear(); 261 } 262