Path: blob/main/contrib/llvm-project/llvm/lib/Target/ARM/ARMMCInstLower.cpp
35266 views
//===-- ARMMCInstLower.cpp - Convert ARM MachineInstr to an MCInst --------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains code to lower ARM MachineInstrs to their corresponding9// MCInst records.10//11//===----------------------------------------------------------------------===//1213#include "ARM.h"14#include "ARMAsmPrinter.h"15#include "ARMBaseInstrInfo.h"16#include "ARMMachineFunctionInfo.h"17#include "ARMSubtarget.h"18#include "MCTargetDesc/ARMAddressingModes.h"19#include "MCTargetDesc/ARMBaseInfo.h"20#include "MCTargetDesc/ARMMCExpr.h"21#include "llvm/ADT/APFloat.h"22#include "llvm/CodeGen/MachineBasicBlock.h"23#include "llvm/CodeGen/MachineInstr.h"24#include "llvm/CodeGen/MachineOperand.h"25#include "llvm/IR/Constants.h"26#include "llvm/MC/MCContext.h"27#include "llvm/MC/MCExpr.h"28#include "llvm/MC/MCInst.h"29#include "llvm/MC/MCInstBuilder.h"30#include "llvm/MC/MCStreamer.h"31#include "llvm/Support/ErrorHandling.h"32#include <cassert>33#include <cstdint>3435using namespace llvm;3637MCOperand ARMAsmPrinter::GetSymbolRef(const MachineOperand &MO,38const MCSymbol *Symbol) {39MCSymbolRefExpr::VariantKind SymbolVariant = MCSymbolRefExpr::VK_None;40if (MO.getTargetFlags() & ARMII::MO_SBREL)41SymbolVariant = MCSymbolRefExpr::VK_ARM_SBREL;4243const MCExpr *Expr =44MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);45switch (MO.getTargetFlags() & ARMII::MO_OPTION_MASK) {46default:47llvm_unreachable("Unknown target flag on symbol operand");48case ARMII::MO_NO_FLAG:49break;50case ARMII::MO_LO16:51Expr =52MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);53Expr = ARMMCExpr::createLower16(Expr, OutContext);54break;55case ARMII::MO_HI16:56Expr =57MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);58Expr = ARMMCExpr::createUpper16(Expr, OutContext);59break;60case ARMII::MO_LO_0_7:61Expr = MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);62Expr = ARMMCExpr::createLower0_7(Expr, OutContext);63break;64case ARMII::MO_LO_8_15:65Expr = MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);66Expr = ARMMCExpr::createLower8_15(Expr, OutContext);67break;68case ARMII::MO_HI_0_7:69Expr = MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);70Expr = ARMMCExpr::createUpper0_7(Expr, OutContext);71break;72case ARMII::MO_HI_8_15:73Expr = MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);74Expr = ARMMCExpr::createUpper8_15(Expr, OutContext);75break;76}7778if (!MO.isJTI() && MO.getOffset())79Expr = MCBinaryExpr::createAdd(Expr,80MCConstantExpr::create(MO.getOffset(),81OutContext),82OutContext);83return MCOperand::createExpr(Expr);8485}8687bool ARMAsmPrinter::lowerOperand(const MachineOperand &MO,88MCOperand &MCOp) {89switch (MO.getType()) {90default: llvm_unreachable("unknown operand type");91case MachineOperand::MO_Register:92// Ignore all implicit register operands.93if (MO.isImplicit())94return false;95assert(!MO.getSubReg() && "Subregs should be eliminated!");96MCOp = MCOperand::createReg(MO.getReg());97break;98case MachineOperand::MO_Immediate:99MCOp = MCOperand::createImm(MO.getImm());100break;101case MachineOperand::MO_MachineBasicBlock:102MCOp = MCOperand::createExpr(MCSymbolRefExpr::create(103MO.getMBB()->getSymbol(), OutContext));104break;105case MachineOperand::MO_GlobalAddress:106MCOp = GetSymbolRef(MO,107GetARMGVSymbol(MO.getGlobal(), MO.getTargetFlags()));108break;109case MachineOperand::MO_ExternalSymbol:110MCOp = GetSymbolRef(MO,111GetExternalSymbolSymbol(MO.getSymbolName()));112break;113case MachineOperand::MO_JumpTableIndex:114MCOp = GetSymbolRef(MO, GetJTISymbol(MO.getIndex()));115break;116case MachineOperand::MO_ConstantPoolIndex:117if (Subtarget->genExecuteOnly())118llvm_unreachable("execute-only should not generate constant pools");119MCOp = GetSymbolRef(MO, GetCPISymbol(MO.getIndex()));120break;121case MachineOperand::MO_BlockAddress:122MCOp = GetSymbolRef(MO, GetBlockAddressSymbol(MO.getBlockAddress()));123break;124case MachineOperand::MO_FPImmediate: {125APFloat Val = MO.getFPImm()->getValueAPF();126bool ignored;127Val.convert(APFloat::IEEEdouble(), APFloat::rmTowardZero, &ignored);128MCOp = MCOperand::createDFPImm(bit_cast<uint64_t>(Val.convertToDouble()));129break;130}131case MachineOperand::MO_RegisterMask:132// Ignore call clobbers.133return false;134}135return true;136}137138void llvm::LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,139ARMAsmPrinter &AP) {140OutMI.setOpcode(MI->getOpcode());141142// In the MC layer, we keep modified immediates in their encoded form143bool EncodeImms = false;144switch (MI->getOpcode()) {145default: break;146case ARM::MOVi:147case ARM::MVNi:148case ARM::CMPri:149case ARM::CMNri:150case ARM::TSTri:151case ARM::TEQri:152case ARM::MSRi:153case ARM::ADCri:154case ARM::ADDri:155case ARM::ADDSri:156case ARM::SBCri:157case ARM::SUBri:158case ARM::SUBSri:159case ARM::ANDri:160case ARM::ORRri:161case ARM::EORri:162case ARM::BICri:163case ARM::RSBri:164case ARM::RSBSri:165case ARM::RSCri:166EncodeImms = true;167break;168}169170for (const MachineOperand &MO : MI->operands()) {171MCOperand MCOp;172if (AP.lowerOperand(MO, MCOp)) {173if (MCOp.isImm() && EncodeImms) {174int32_t Enc = ARM_AM::getSOImmVal(MCOp.getImm());175if (Enc != -1)176MCOp.setImm(Enc);177}178OutMI.addOperand(MCOp);179}180}181}182183void ARMAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind)184{185if (MI.getParent()->getParent()->getInfo<ARMFunctionInfo>()186->isThumbFunction())187{188MI.emitError("An attempt to perform XRay instrumentation for a"189" Thumb function (not supported). Detected when emitting a sled.");190return;191}192static const int8_t NoopsInSledCount = 6;193// We want to emit the following pattern:194//195// .Lxray_sled_N:196// ALIGN197// B #20198// ; 6 NOP instructions (24 bytes)199// .tmpN200//201// We need the 24 bytes (6 instructions) because at runtime, we'd be patching202// over the full 28 bytes (7 instructions) with the following pattern:203//204// PUSH{ r0, lr }205// MOVW r0, #<lower 16 bits of function ID>206// MOVT r0, #<higher 16 bits of function ID>207// MOVW ip, #<lower 16 bits of address of __xray_FunctionEntry/Exit>208// MOVT ip, #<higher 16 bits of address of __xray_FunctionEntry/Exit>209// BLX ip210// POP{ r0, lr }211//212OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());213auto CurSled = OutContext.createTempSymbol("xray_sled_", true);214OutStreamer->emitLabel(CurSled);215auto Target = OutContext.createTempSymbol();216217// Emit "B #20" instruction, which jumps over the next 24 bytes (because218// register pc is 8 bytes ahead of the jump instruction by the moment CPU219// is executing it).220// By analogy to ARMAsmPrinter::emitPseudoExpansionLowering() |case ARM::B|.221// It is not clear why |addReg(0)| is needed (the last operand).222EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::Bcc).addImm(20)223.addImm(ARMCC::AL).addReg(0));224225emitNops(NoopsInSledCount);226227OutStreamer->emitLabel(Target);228recordSled(CurSled, MI, Kind, 2);229}230231void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)232{233EmitSled(MI, SledKind::FUNCTION_ENTER);234}235236void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI)237{238EmitSled(MI, SledKind::FUNCTION_EXIT);239}240241void ARMAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI)242{243EmitSled(MI, SledKind::TAIL_CALL);244}245246247