246 lines · cpp
1//===-- ARMMCInstLower.cpp - Convert ARM MachineInstr to an MCInst --------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains code to lower ARM MachineInstrs to their corresponding10// MCInst records.11//12//===----------------------------------------------------------------------===//13 14#include "ARM.h"15#include "ARMAsmPrinter.h"16#include "ARMBaseInstrInfo.h"17#include "ARMMachineFunctionInfo.h"18#include "ARMSubtarget.h"19#include "MCTargetDesc/ARMAddressingModes.h"20#include "MCTargetDesc/ARMBaseInfo.h"21#include "MCTargetDesc/ARMMCAsmInfo.h"22#include "llvm/ADT/APFloat.h"23#include "llvm/CodeGen/MachineBasicBlock.h"24#include "llvm/CodeGen/MachineInstr.h"25#include "llvm/CodeGen/MachineOperand.h"26#include "llvm/IR/Constants.h"27#include "llvm/MC/MCContext.h"28#include "llvm/MC/MCExpr.h"29#include "llvm/MC/MCInst.h"30#include "llvm/MC/MCInstBuilder.h"31#include "llvm/MC/MCStreamer.h"32#include "llvm/Support/ErrorHandling.h"33#include <cassert>34#include <cstdint>35 36using namespace llvm;37 38MCOperand ARMAsmPrinter::GetSymbolRef(const MachineOperand &MO,39 const MCSymbol *Symbol) {40 auto Specifier = ARM::S_None;41 if (MO.getTargetFlags() & ARMII::MO_SBREL)42 Specifier = ARM::S_SBREL;43 44 const MCExpr *Expr = MCSymbolRefExpr::create(Symbol, Specifier, OutContext);45 switch (MO.getTargetFlags() & ARMII::MO_OPTION_MASK) {46 default:47 llvm_unreachable("Unknown target flag on symbol operand");48 case ARMII::MO_NO_FLAG:49 break;50 case ARMII::MO_LO16:51 Expr = MCSymbolRefExpr::create(Symbol, Specifier, OutContext);52 Expr = ARM::createLower16(Expr, OutContext);53 break;54 case ARMII::MO_HI16:55 Expr = MCSymbolRefExpr::create(Symbol, Specifier, OutContext);56 Expr = ARM::createUpper16(Expr, OutContext);57 break;58 case ARMII::MO_LO_0_7:59 Expr = MCSymbolRefExpr::create(Symbol, Specifier, OutContext);60 Expr = ARM::createLower0_7(Expr, OutContext);61 break;62 case ARMII::MO_LO_8_15:63 Expr = MCSymbolRefExpr::create(Symbol, Specifier, OutContext);64 Expr = ARM::createLower8_15(Expr, OutContext);65 break;66 case ARMII::MO_HI_0_7:67 Expr = MCSymbolRefExpr::create(Symbol, Specifier, OutContext);68 Expr = ARM::createUpper0_7(Expr, OutContext);69 break;70 case ARMII::MO_HI_8_15:71 Expr = MCSymbolRefExpr::create(Symbol, Specifier, OutContext);72 Expr = ARM::createUpper8_15(Expr, OutContext);73 break;74 }75 76 if (!MO.isJTI() && MO.getOffset())77 Expr = MCBinaryExpr::createAdd(Expr,78 MCConstantExpr::create(MO.getOffset(),79 OutContext),80 OutContext);81 return MCOperand::createExpr(Expr);82 83}84 85bool ARMAsmPrinter::lowerOperand(const MachineOperand &MO,86 MCOperand &MCOp) {87 switch (MO.getType()) {88 default: llvm_unreachable("unknown operand type");89 case MachineOperand::MO_Register:90 // Ignore all implicit register operands.91 if (MO.isImplicit())92 return false;93 assert(!MO.getSubReg() && "Subregs should be eliminated!");94 MCOp = MCOperand::createReg(MO.getReg());95 break;96 case MachineOperand::MO_Immediate:97 MCOp = MCOperand::createImm(MO.getImm());98 break;99 case MachineOperand::MO_MachineBasicBlock:100 MCOp = MCOperand::createExpr(MCSymbolRefExpr::create(101 MO.getMBB()->getSymbol(), OutContext));102 break;103 case MachineOperand::MO_GlobalAddress:104 MCOp = GetSymbolRef(MO,105 GetARMGVSymbol(MO.getGlobal(), MO.getTargetFlags()));106 break;107 case MachineOperand::MO_ExternalSymbol:108 MCOp = GetSymbolRef(MO,109 GetExternalSymbolSymbol(MO.getSymbolName()));110 break;111 case MachineOperand::MO_JumpTableIndex:112 MCOp = GetSymbolRef(MO, GetJTISymbol(MO.getIndex()));113 break;114 case MachineOperand::MO_ConstantPoolIndex:115 assert(!MF->getSubtarget<ARMSubtarget>().genExecuteOnly() &&116 "execute-only should not generate constant pools");117 MCOp = GetSymbolRef(MO, GetCPISymbol(MO.getIndex()));118 break;119 case MachineOperand::MO_BlockAddress:120 MCOp = GetSymbolRef(MO, GetBlockAddressSymbol(MO.getBlockAddress()));121 break;122 case MachineOperand::MO_FPImmediate: {123 APFloat Val = MO.getFPImm()->getValueAPF();124 bool ignored;125 Val.convert(APFloat::IEEEdouble(), APFloat::rmTowardZero, &ignored);126 MCOp = MCOperand::createDFPImm(bit_cast<uint64_t>(Val.convertToDouble()));127 break;128 }129 case MachineOperand::MO_RegisterMask:130 // Ignore call clobbers.131 return false;132 }133 return true;134}135 136void llvm::LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,137 ARMAsmPrinter &AP) {138 OutMI.setOpcode(MI->getOpcode());139 140 // In the MC layer, we keep modified immediates in their encoded form141 bool EncodeImms = false;142 switch (MI->getOpcode()) {143 default: break;144 case ARM::MOVi:145 case ARM::MVNi:146 case ARM::CMPri:147 case ARM::CMNri:148 case ARM::TSTri:149 case ARM::TEQri:150 case ARM::MSRi:151 case ARM::ADCri:152 case ARM::ADDri:153 case ARM::ADDSri:154 case ARM::SBCri:155 case ARM::SUBri:156 case ARM::SUBSri:157 case ARM::ANDri:158 case ARM::ORRri:159 case ARM::EORri:160 case ARM::BICri:161 case ARM::RSBri:162 case ARM::RSBSri:163 case ARM::RSCri:164 EncodeImms = true;165 break;166 }167 168 for (const MachineOperand &MO : MI->operands()) {169 MCOperand MCOp;170 if (AP.lowerOperand(MO, MCOp)) {171 if (MCOp.isImm() && EncodeImms) {172 int32_t Enc = ARM_AM::getSOImmVal(MCOp.getImm());173 if (Enc != -1)174 MCOp.setImm(Enc);175 }176 OutMI.addOperand(MCOp);177 }178 }179}180 181void ARMAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind)182{183 const MachineFunction *MF = MI.getParent()->getParent();184 if (MF->getInfo<ARMFunctionInfo>()->isThumbFunction()) {185 const Function &Fn = MF->getFunction();186 Fn.getContext().diagnose(DiagnosticInfoUnsupported(187 Fn,188 "An attempt to perform XRay instrumentation for a Thumb function (not "189 "supported). Detected when emitting a sled.",190 MI.getDebugLoc()));191 return;192 }193 static const int8_t NoopsInSledCount = 6;194 // We want to emit the following pattern:195 //196 // .Lxray_sled_N:197 // ALIGN198 // B #20199 // ; 6 NOP instructions (24 bytes)200 // .tmpN201 //202 // We need the 24 bytes (6 instructions) because at runtime, we'd be patching203 // over the full 28 bytes (7 instructions) with the following pattern:204 //205 // PUSH{ r0, lr }206 // MOVW r0, #<lower 16 bits of function ID>207 // MOVT r0, #<higher 16 bits of function ID>208 // MOVW ip, #<lower 16 bits of address of __xray_FunctionEntry/Exit>209 // MOVT ip, #<higher 16 bits of address of __xray_FunctionEntry/Exit>210 // BLX ip211 // POP{ r0, lr }212 //213 OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());214 auto CurSled = OutContext.createTempSymbol("xray_sled_", true);215 OutStreamer->emitLabel(CurSled);216 auto Target = OutContext.createTempSymbol();217 218 // Emit "B #20" instruction, which jumps over the next 24 bytes (because219 // register pc is 8 bytes ahead of the jump instruction by the moment CPU220 // is executing it).221 // By analogy to ARMAsmPrinter::lowerPseudoInstExpansion() |case ARM::B|.222 // It is not clear why |addReg(0)| is needed (the last operand).223 EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::Bcc).addImm(20)224 .addImm(ARMCC::AL).addReg(0));225 226 emitNops(NoopsInSledCount);227 228 OutStreamer->emitLabel(Target);229 recordSled(CurSled, MI, Kind, 2);230}231 232void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)233{234 EmitSled(MI, SledKind::FUNCTION_ENTER);235}236 237void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI)238{239 EmitSled(MI, SledKind::FUNCTION_EXIT);240}241 242void ARMAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI)243{244 EmitSled(MI, SledKind::TAIL_CALL);245}246