summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 15:06:44 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 15:06:44 +0000
commitb64793999546ed8adebaeebd9d8345d18db8927d (patch)
tree4357c27b561d73b0e089727c6ed659f2ceff5f47 /gnu/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
parentAdd support for UTF-8 DISPLAY-HINTs with octet length. For now only (diff)
downloadwireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.tar.xz
wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.zip
Remove LLVM 8.0.1 files.
Diffstat (limited to 'gnu/llvm/lib/Target/ARM/ARMAsmPrinter.cpp')
-rw-r--r--gnu/llvm/lib/Target/ARM/ARMAsmPrinter.cpp2085
1 files changed, 0 insertions, 2085 deletions
diff --git a/gnu/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/gnu/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
deleted file mode 100644
index b7cd3a0c2da..00000000000
--- a/gnu/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
+++ /dev/null
@@ -1,2085 +0,0 @@
-//===-- ARMAsmPrinter.cpp - Print machine code to an ARM .s file ----------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains a printer that converts from our internal representation
-// of machine-dependent LLVM code to GAS-format ARM assembly language.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ARMAsmPrinter.h"
-#include "ARM.h"
-#include "ARMConstantPoolValue.h"
-#include "ARMMachineFunctionInfo.h"
-#include "ARMTargetMachine.h"
-#include "ARMTargetObjectFile.h"
-#include "InstPrinter/ARMInstPrinter.h"
-#include "MCTargetDesc/ARMAddressingModes.h"
-#include "MCTargetDesc/ARMMCExpr.h"
-#include "llvm/ADT/SetVector.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/BinaryFormat/COFF.h"
-#include "llvm/CodeGen/MachineFunctionPass.h"
-#include "llvm/CodeGen/MachineJumpTableInfo.h"
-#include "llvm/CodeGen/MachineModuleInfoImpls.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/Mangler.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Type.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCAssembler.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCELFStreamer.h"
-#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCInstBuilder.h"
-#include "llvm/MC/MCObjectStreamer.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSymbol.h"
-#include "llvm/Support/ARMBuildAttributes.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/TargetParser.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetMachine.h"
-using namespace llvm;
-
-#define DEBUG_TYPE "asm-printer"
-
-ARMAsmPrinter::ARMAsmPrinter(TargetMachine &TM,
- std::unique_ptr<MCStreamer> Streamer)
- : AsmPrinter(TM, std::move(Streamer)), AFI(nullptr), MCP(nullptr),
- InConstantPool(false), OptimizationGoals(-1) {}
-
-void ARMAsmPrinter::EmitFunctionBodyEnd() {
- // Make sure to terminate any constant pools that were at the end
- // of the function.
- if (!InConstantPool)
- return;
- InConstantPool = false;
- OutStreamer->EmitDataRegion(MCDR_DataRegionEnd);
-}
-
-void ARMAsmPrinter::EmitFunctionEntryLabel() {
- if (AFI->isThumbFunction()) {
- OutStreamer->EmitAssemblerFlag(MCAF_Code16);
- OutStreamer->EmitThumbFunc(CurrentFnSym);
- } else {
- OutStreamer->EmitAssemblerFlag(MCAF_Code32);
- }
- OutStreamer->EmitLabel(CurrentFnSym);
-}
-
-void ARMAsmPrinter::EmitXXStructor(const DataLayout &DL, const Constant *CV) {
- uint64_t Size = getDataLayout().getTypeAllocSize(CV->getType());
- assert(Size && "C++ constructor pointer had zero size!");
-
- const GlobalValue *GV = dyn_cast<GlobalValue>(CV->stripPointerCasts());
- assert(GV && "C++ constructor pointer was not a GlobalValue!");
-
- const MCExpr *E = MCSymbolRefExpr::create(GetARMGVSymbol(GV,
- ARMII::MO_NO_FLAG),
- (Subtarget->isTargetELF()
- ? MCSymbolRefExpr::VK_ARM_TARGET1
- : MCSymbolRefExpr::VK_None),
- OutContext);
-
- OutStreamer->EmitValue(E, Size);
-}
-
-void ARMAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
- if (PromotedGlobals.count(GV))
- // The global was promoted into a constant pool. It should not be emitted.
- return;
- AsmPrinter::EmitGlobalVariable(GV);
-}
-
-/// runOnMachineFunction - This uses the EmitInstruction()
-/// method to print assembly for each instruction.
-///
-bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
- AFI = MF.getInfo<ARMFunctionInfo>();
- MCP = MF.getConstantPool();
- Subtarget = &MF.getSubtarget<ARMSubtarget>();
-
- SetupMachineFunction(MF);
- const Function &F = MF.getFunction();
- const TargetMachine& TM = MF.getTarget();
-
- // Collect all globals that had their storage promoted to a constant pool.
- // Functions are emitted before variables, so this accumulates promoted
- // globals from all functions in PromotedGlobals.
- for (auto *GV : AFI->getGlobalsPromotedToConstantPool())
- PromotedGlobals.insert(GV);
-
- // Calculate this function's optimization goal.
- unsigned OptimizationGoal;
- if (F.hasFnAttribute(Attribute::OptimizeNone))
- // For best debugging illusion, speed and small size sacrificed
- OptimizationGoal = 6;
- else if (F.optForMinSize())
- // Aggressively for small size, speed and debug illusion sacrificed
- OptimizationGoal = 4;
- else if (F.optForSize())
- // For small size, but speed and debugging illusion preserved
- OptimizationGoal = 3;
- else if (TM.getOptLevel() == CodeGenOpt::Aggressive)
- // Aggressively for speed, small size and debug illusion sacrificed
- OptimizationGoal = 2;
- else if (TM.getOptLevel() > CodeGenOpt::None)
- // For speed, but small size and good debug illusion preserved
- OptimizationGoal = 1;
- else // TM.getOptLevel() == CodeGenOpt::None
- // For good debugging, but speed and small size preserved
- OptimizationGoal = 5;
-
- // Combine a new optimization goal with existing ones.
- if (OptimizationGoals == -1) // uninitialized goals
- OptimizationGoals = OptimizationGoal;
- else if (OptimizationGoals != (int)OptimizationGoal) // conflicting goals
- OptimizationGoals = 0;
-
- if (Subtarget->isTargetCOFF()) {
- bool Internal = F.hasInternalLinkage();
- COFF::SymbolStorageClass Scl = Internal ? COFF::IMAGE_SYM_CLASS_STATIC
- : COFF::IMAGE_SYM_CLASS_EXTERNAL;
- int Type = COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT;
-
- OutStreamer->BeginCOFFSymbolDef(CurrentFnSym);
- OutStreamer->EmitCOFFSymbolStorageClass(Scl);
- OutStreamer->EmitCOFFSymbolType(Type);
- OutStreamer->EndCOFFSymbolDef();
- }
-
- // Emit the rest of the function body.
- EmitFunctionBody();
-
- // Emit the XRay table for this function.
- emitXRayTable();
-
- // If we need V4T thumb mode Register Indirect Jump pads, emit them.
- // These are created per function, rather than per TU, since it's
- // relatively easy to exceed the thumb branch range within a TU.
- if (! ThumbIndirectPads.empty()) {
- OutStreamer->EmitAssemblerFlag(MCAF_Code16);
- EmitAlignment(1);
- for (std::pair<unsigned, MCSymbol *> &TIP : ThumbIndirectPads) {
- OutStreamer->EmitLabel(TIP.second);
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tBX)
- .addReg(TIP.first)
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0));
- }
- ThumbIndirectPads.clear();
- }
-
- // We didn't modify anything.
- return false;
-}
-
-void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
- raw_ostream &O) {
- const MachineOperand &MO = MI->getOperand(OpNum);
- unsigned TF = MO.getTargetFlags();
-
- switch (MO.getType()) {
- default: llvm_unreachable("<unknown operand type>");
- case MachineOperand::MO_Register: {
- unsigned Reg = MO.getReg();
- assert(TargetRegisterInfo::isPhysicalRegister(Reg));
- assert(!MO.getSubReg() && "Subregs should be eliminated!");
- if(ARM::GPRPairRegClass.contains(Reg)) {
- const MachineFunction &MF = *MI->getParent()->getParent();
- const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
- Reg = TRI->getSubReg(Reg, ARM::gsub_0);
- }
- O << ARMInstPrinter::getRegisterName(Reg);
- break;
- }
- case MachineOperand::MO_Immediate: {
- int64_t Imm = MO.getImm();
- O << '#';
- if (TF == ARMII::MO_LO16)
- O << ":lower16:";
- else if (TF == ARMII::MO_HI16)
- O << ":upper16:";
- O << Imm;
- break;
- }
- case MachineOperand::MO_MachineBasicBlock:
- MO.getMBB()->getSymbol()->print(O, MAI);
- return;
- case MachineOperand::MO_GlobalAddress: {
- const GlobalValue *GV = MO.getGlobal();
- if (TF & ARMII::MO_LO16)
- O << ":lower16:";
- else if (TF & ARMII::MO_HI16)
- O << ":upper16:";
- GetARMGVSymbol(GV, TF)->print(O, MAI);
-
- printOffset(MO.getOffset(), O);
- break;
- }
- case MachineOperand::MO_ConstantPoolIndex:
- if (Subtarget->genExecuteOnly())
- llvm_unreachable("execute-only should not generate constant pools");
- GetCPISymbol(MO.getIndex())->print(O, MAI);
- break;
- }
-}
-
-MCSymbol *ARMAsmPrinter::GetCPISymbol(unsigned CPID) const {
- // The AsmPrinter::GetCPISymbol superclass method tries to use CPID as
- // indexes in MachineConstantPool, which isn't in sync with indexes used here.
- const DataLayout &DL = getDataLayout();
- return OutContext.getOrCreateSymbol(Twine(DL.getPrivateGlobalPrefix()) +
- "CPI" + Twine(getFunctionNumber()) + "_" +
- Twine(CPID));
-}
-
-//===--------------------------------------------------------------------===//
-
-MCSymbol *ARMAsmPrinter::
-GetARMJTIPICJumpTableLabel(unsigned uid) const {
- const DataLayout &DL = getDataLayout();
- SmallString<60> Name;
- raw_svector_ostream(Name) << DL.getPrivateGlobalPrefix() << "JTI"
- << getFunctionNumber() << '_' << uid;
- return OutContext.getOrCreateSymbol(Name);
-}
-
-bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
- unsigned AsmVariant, const char *ExtraCode,
- raw_ostream &O) {
- // Does this asm operand have a single letter operand modifier?
- if (ExtraCode && ExtraCode[0]) {
- if (ExtraCode[1] != 0) return true; // Unknown modifier.
-
- switch (ExtraCode[0]) {
- default:
- // See if this is a generic print operand
- return AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O);
- case 'a': // Print as a memory address.
- if (MI->getOperand(OpNum).isReg()) {
- O << "["
- << ARMInstPrinter::getRegisterName(MI->getOperand(OpNum).getReg())
- << "]";
- return false;
- }
- LLVM_FALLTHROUGH;
- case 'c': // Don't print "#" before an immediate operand.
- if (!MI->getOperand(OpNum).isImm())
- return true;
- O << MI->getOperand(OpNum).getImm();
- return false;
- case 'P': // Print a VFP double precision register.
- case 'q': // Print a NEON quad precision register.
- printOperand(MI, OpNum, O);
- return false;
- case 'y': // Print a VFP single precision register as indexed double.
- if (MI->getOperand(OpNum).isReg()) {
- unsigned Reg = MI->getOperand(OpNum).getReg();
- const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
- // Find the 'd' register that has this 's' register as a sub-register,
- // and determine the lane number.
- for (MCSuperRegIterator SR(Reg, TRI); SR.isValid(); ++SR) {
- if (!ARM::DPRRegClass.contains(*SR))
- continue;
- bool Lane0 = TRI->getSubReg(*SR, ARM::ssub_0) == Reg;
- O << ARMInstPrinter::getRegisterName(*SR) << (Lane0 ? "[0]" : "[1]");
- return false;
- }
- }
- return true;
- case 'B': // Bitwise inverse of integer or symbol without a preceding #.
- if (!MI->getOperand(OpNum).isImm())
- return true;
- O << ~(MI->getOperand(OpNum).getImm());
- return false;
- case 'L': // The low 16 bits of an immediate constant.
- if (!MI->getOperand(OpNum).isImm())
- return true;
- O << (MI->getOperand(OpNum).getImm() & 0xffff);
- return false;
- case 'M': { // A register range suitable for LDM/STM.
- if (!MI->getOperand(OpNum).isReg())
- return true;
- const MachineOperand &MO = MI->getOperand(OpNum);
- unsigned RegBegin = MO.getReg();
- // This takes advantage of the 2 operand-ness of ldm/stm and that we've
- // already got the operands in registers that are operands to the
- // inline asm statement.
- O << "{";
- if (ARM::GPRPairRegClass.contains(RegBegin)) {
- const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
- unsigned Reg0 = TRI->getSubReg(RegBegin, ARM::gsub_0);
- O << ARMInstPrinter::getRegisterName(Reg0) << ", ";
- RegBegin = TRI->getSubReg(RegBegin, ARM::gsub_1);
- }
- O << ARMInstPrinter::getRegisterName(RegBegin);
-
- // FIXME: The register allocator not only may not have given us the
- // registers in sequence, but may not be in ascending registers. This
- // will require changes in the register allocator that'll need to be
- // propagated down here if the operands change.
- unsigned RegOps = OpNum + 1;
- while (MI->getOperand(RegOps).isReg()) {
- O << ", "
- << ARMInstPrinter::getRegisterName(MI->getOperand(RegOps).getReg());
- RegOps++;
- }
-
- O << "}";
-
- return false;
- }
- case 'R': // The most significant register of a pair.
- case 'Q': { // The least significant register of a pair.
- if (OpNum == 0)
- return true;
- const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1);
- if (!FlagsOP.isImm())
- return true;
- unsigned Flags = FlagsOP.getImm();
-
- // This operand may not be the one that actually provides the register. If
- // it's tied to a previous one then we should refer instead to that one
- // for registers and their classes.
- unsigned TiedIdx;
- if (InlineAsm::isUseOperandTiedToDef(Flags, TiedIdx)) {
- for (OpNum = InlineAsm::MIOp_FirstOperand; TiedIdx; --TiedIdx) {
- unsigned OpFlags = MI->getOperand(OpNum).getImm();
- OpNum += InlineAsm::getNumOperandRegisters(OpFlags) + 1;
- }
- Flags = MI->getOperand(OpNum).getImm();
-
- // Later code expects OpNum to be pointing at the register rather than
- // the flags.
- OpNum += 1;
- }
-
- unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags);
- unsigned RC;
- bool FirstHalf;
- const ARMBaseTargetMachine &ATM =
- static_cast<const ARMBaseTargetMachine &>(TM);
-
- // 'Q' should correspond to the low order register and 'R' to the high
- // order register. Whether this corresponds to the upper or lower half
- // depends on the endianess mode.
- if (ExtraCode[0] == 'Q')
- FirstHalf = ATM.isLittleEndian();
- else
- // ExtraCode[0] == 'R'.
- FirstHalf = !ATM.isLittleEndian();
- const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
- if (InlineAsm::hasRegClassConstraint(Flags, RC) &&
- ARM::GPRPairRegClass.hasSubClassEq(TRI->getRegClass(RC))) {
- if (NumVals != 1)
- return true;
- const MachineOperand &MO = MI->getOperand(OpNum);
- if (!MO.isReg())
- return true;
- const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
- unsigned Reg = TRI->getSubReg(MO.getReg(), FirstHalf ?
- ARM::gsub_0 : ARM::gsub_1);
- O << ARMInstPrinter::getRegisterName(Reg);
- return false;
- }
- if (NumVals != 2)
- return true;
- unsigned RegOp = FirstHalf ? OpNum : OpNum + 1;
- if (RegOp >= MI->getNumOperands())
- return true;
- const MachineOperand &MO = MI->getOperand(RegOp);
- if (!MO.isReg())
- return true;
- unsigned Reg = MO.getReg();
- O << ARMInstPrinter::getRegisterName(Reg);
- return false;
- }
-
- case 'e': // The low doubleword register of a NEON quad register.
- case 'f': { // The high doubleword register of a NEON quad register.
- if (!MI->getOperand(OpNum).isReg())
- return true;
- unsigned Reg = MI->getOperand(OpNum).getReg();
- if (!ARM::QPRRegClass.contains(Reg))
- return true;
- const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
- unsigned SubReg = TRI->getSubReg(Reg, ExtraCode[0] == 'e' ?
- ARM::dsub_0 : ARM::dsub_1);
- O << ARMInstPrinter::getRegisterName(SubReg);
- return false;
- }
-
- // This modifier is not yet supported.
- case 'h': // A range of VFP/NEON registers suitable for VLD1/VST1.
- return true;
- case 'H': { // The highest-numbered register of a pair.
- const MachineOperand &MO = MI->getOperand(OpNum);
- if (!MO.isReg())
- return true;
- const MachineFunction &MF = *MI->getParent()->getParent();
- const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
- unsigned Reg = MO.getReg();
- if(!ARM::GPRPairRegClass.contains(Reg))
- return false;
- Reg = TRI->getSubReg(Reg, ARM::gsub_1);
- O << ARMInstPrinter::getRegisterName(Reg);
- return false;
- }
- }
- }
-
- printOperand(MI, OpNum, O);
- return false;
-}
-
-bool ARMAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
- unsigned OpNum, unsigned AsmVariant,
- const char *ExtraCode,
- raw_ostream &O) {
- // Does this asm operand have a single letter operand modifier?
- if (ExtraCode && ExtraCode[0]) {
- if (ExtraCode[1] != 0) return true; // Unknown modifier.
-
- switch (ExtraCode[0]) {
- case 'A': // A memory operand for a VLD1/VST1 instruction.
- default: return true; // Unknown modifier.
- case 'm': // The base register of a memory operand.
- if (!MI->getOperand(OpNum).isReg())
- return true;
- O << ARMInstPrinter::getRegisterName(MI->getOperand(OpNum).getReg());
- return false;
- }
- }
-
- const MachineOperand &MO = MI->getOperand(OpNum);
- assert(MO.isReg() && "unexpected inline asm memory operand");
- O << "[" << ARMInstPrinter::getRegisterName(MO.getReg()) << "]";
- return false;
-}
-
-static bool isThumb(const MCSubtargetInfo& STI) {
- return STI.getFeatureBits()[ARM::ModeThumb];
-}
-
-void ARMAsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
- const MCSubtargetInfo *EndInfo) const {
- // If either end mode is unknown (EndInfo == NULL) or different than
- // the start mode, then restore the start mode.
- const bool WasThumb = isThumb(StartInfo);
- if (!EndInfo || WasThumb != isThumb(*EndInfo)) {
- OutStreamer->EmitAssemblerFlag(WasThumb ? MCAF_Code16 : MCAF_Code32);
- }
-}
-
-void ARMAsmPrinter::EmitStartOfAsmFile(Module &M) {
- const Triple &TT = TM.getTargetTriple();
- // Use unified assembler syntax.
- OutStreamer->EmitAssemblerFlag(MCAF_SyntaxUnified);
-
- // Emit ARM Build Attributes
- if (TT.isOSBinFormatELF())
- emitAttributes();
-
- // Use the triple's architecture and subarchitecture to determine
- // if we're thumb for the purposes of the top level code16 assembler
- // flag.
- if (!M.getModuleInlineAsm().empty() && TT.isThumb())
- OutStreamer->EmitAssemblerFlag(MCAF_Code16);
-}
-
-static void
-emitNonLazySymbolPointer(MCStreamer &OutStreamer, MCSymbol *StubLabel,
- MachineModuleInfoImpl::StubValueTy &MCSym) {
- // L_foo$stub:
- OutStreamer.EmitLabel(StubLabel);
- // .indirect_symbol _foo
- OutStreamer.EmitSymbolAttribute(MCSym.getPointer(), MCSA_IndirectSymbol);
-
- if (MCSym.getInt())
- // External to current translation unit.
- OutStreamer.EmitIntValue(0, 4/*size*/);
- else
- // Internal to current translation unit.
- //
- // When we place the LSDA into the TEXT section, the type info
- // pointers need to be indirect and pc-rel. We accomplish this by
- // using NLPs; however, sometimes the types are local to the file.
- // We need to fill in the value for the NLP in those cases.
- OutStreamer.EmitValue(
- MCSymbolRefExpr::create(MCSym.getPointer(), OutStreamer.getContext()),
- 4 /*size*/);
-}
-
-
-void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) {
- const Triple &TT = TM.getTargetTriple();
- if (TT.isOSBinFormatMachO()) {
- // All darwin targets use mach-o.
- const TargetLoweringObjectFileMachO &TLOFMacho =
- static_cast<const TargetLoweringObjectFileMachO &>(getObjFileLowering());
- MachineModuleInfoMachO &MMIMacho =
- MMI->getObjFileInfo<MachineModuleInfoMachO>();
-
- // Output non-lazy-pointers for external and common global variables.
- MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetGVStubList();
-
- if (!Stubs.empty()) {
- // Switch with ".non_lazy_symbol_pointer" directive.
- OutStreamer->SwitchSection(TLOFMacho.getNonLazySymbolPointerSection());
- EmitAlignment(2);
-
- for (auto &Stub : Stubs)
- emitNonLazySymbolPointer(*OutStreamer, Stub.first, Stub.second);
-
- Stubs.clear();
- OutStreamer->AddBlankLine();
- }
-
- Stubs = MMIMacho.GetThreadLocalGVStubList();
- if (!Stubs.empty()) {
- // Switch with ".non_lazy_symbol_pointer" directive.
- OutStreamer->SwitchSection(TLOFMacho.getThreadLocalPointerSection());
- EmitAlignment(2);
-
- for (auto &Stub : Stubs)
- emitNonLazySymbolPointer(*OutStreamer, Stub.first, Stub.second);
-
- Stubs.clear();
- OutStreamer->AddBlankLine();
- }
-
- // Funny Darwin hack: This flag tells the linker that no global symbols
- // contain code that falls through to other global symbols (e.g. the obvious
- // implementation of multiple entry points). If this doesn't occur, the
- // linker can safely perform dead code stripping. Since LLVM never
- // generates code that does this, it is always safe to set.
- OutStreamer->EmitAssemblerFlag(MCAF_SubsectionsViaSymbols);
- }
-
- // The last attribute to be emitted is ABI_optimization_goals
- MCTargetStreamer &TS = *OutStreamer->getTargetStreamer();
- ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS);
-
- if (OptimizationGoals > 0 &&
- (Subtarget->isTargetAEABI() || Subtarget->isTargetGNUAEABI() ||
- Subtarget->isTargetMuslAEABI()))
- ATS.emitAttribute(ARMBuildAttrs::ABI_optimization_goals, OptimizationGoals);
- OptimizationGoals = -1;
-
- ATS.finishAttributeSection();
-}
-
-//===----------------------------------------------------------------------===//
-// Helper routines for EmitStartOfAsmFile() and EmitEndOfAsmFile()
-// FIXME:
-// The following seem like one-off assembler flags, but they actually need
-// to appear in the .ARM.attributes section in ELF.
-// Instead of subclassing the MCELFStreamer, we do the work here.
-
-// Returns true if all functions have the same function attribute value.
-// It also returns true when the module has no functions.
-static bool checkFunctionsAttributeConsistency(const Module &M, StringRef Attr,
- StringRef Value) {
- return !any_of(M, [&](const Function &F) {
- return F.getFnAttribute(Attr).getValueAsString() != Value;
- });
-}
-
-void ARMAsmPrinter::emitAttributes() {
- MCTargetStreamer &TS = *OutStreamer->getTargetStreamer();
- ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS);
-
- ATS.emitTextAttribute(ARMBuildAttrs::conformance, "2.09");
-
- ATS.switchVendor("aeabi");
-
- // Compute ARM ELF Attributes based on the default subtarget that
- // we'd have constructed. The existing ARM behavior isn't LTO clean
- // anyhow.
- // FIXME: For ifunc related functions we could iterate over and look
- // for a feature string that doesn't match the default one.
- const Triple &TT = TM.getTargetTriple();
- StringRef CPU = TM.getTargetCPU();
- StringRef FS = TM.getTargetFeatureString();
- std::string ArchFS = ARM_MC::ParseARMTriple(TT, CPU);
- if (!FS.empty()) {
- if (!ArchFS.empty())
- ArchFS = (Twine(ArchFS) + "," + FS).str();
- else
- ArchFS = FS;
- }
- const ARMBaseTargetMachine &ATM =
- static_cast<const ARMBaseTargetMachine &>(TM);
- const ARMSubtarget STI(TT, CPU, ArchFS, ATM, ATM.isLittleEndian());
-
- // Emit build attributes for the available hardware.
- ATS.emitTargetAttributes(STI);
-
- // RW data addressing.
- if (isPositionIndependent()) {
- ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RW_data,
- ARMBuildAttrs::AddressRWPCRel);
- } else if (STI.isRWPI()) {
- // RWPI specific attributes.
- ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RW_data,
- ARMBuildAttrs::AddressRWSBRel);
- }
-
- // RO data addressing.
- if (isPositionIndependent() || STI.isROPI()) {
- ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RO_data,
- ARMBuildAttrs::AddressROPCRel);
- }
-
- // GOT use.
- if (isPositionIndependent()) {
- ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_GOT_use,
- ARMBuildAttrs::AddressGOT);
- } else {
- ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_GOT_use,
- ARMBuildAttrs::AddressDirect);
- }
-
- // Set FP Denormals.
- if (checkFunctionsAttributeConsistency(*MMI->getModule(),
- "denormal-fp-math",
- "preserve-sign") ||
- TM.Options.FPDenormalMode == FPDenormal::PreserveSign)
- ATS.emitAttribute(ARMBuildAttrs::ABI_FP_denormal,
- ARMBuildAttrs::PreserveFPSign);
- else if (checkFunctionsAttributeConsistency(*MMI->getModule(),
- "denormal-fp-math",
- "positive-zero") ||
- TM.Options.FPDenormalMode == FPDenormal::PositiveZero)
- ATS.emitAttribute(ARMBuildAttrs::ABI_FP_denormal,
- ARMBuildAttrs::PositiveZero);
- else if (!TM.Options.UnsafeFPMath)
- ATS.emitAttribute(ARMBuildAttrs::ABI_FP_denormal,
- ARMBuildAttrs::IEEEDenormals);
- else {
- if (!STI.hasVFP2()) {
- // When the target doesn't have an FPU (by design or
- // intention), the assumptions made on the software support
- // mirror that of the equivalent hardware support *if it
- // existed*. For v7 and better we indicate that denormals are
- // flushed preserving sign, and for V6 we indicate that
- // denormals are flushed to positive zero.
- if (STI.hasV7Ops())
- ATS.emitAttribute(ARMBuildAttrs::ABI_FP_denormal,
- ARMBuildAttrs::PreserveFPSign);
- } else if (STI.hasVFP3()) {
- // In VFPv4, VFPv4U, VFPv3, or VFPv3U, it is preserved. That is,
- // the sign bit of the zero matches the sign bit of the input or
- // result that is being flushed to zero.
- ATS.emitAttribute(ARMBuildAttrs::ABI_FP_denormal,
- ARMBuildAttrs::PreserveFPSign);
- }
- // For VFPv2 implementations it is implementation defined as
- // to whether denormals are flushed to positive zero or to
- // whatever the sign of zero is (ARM v7AR ARM 2.7.5). Historically
- // LLVM has chosen to flush this to positive zero (most likely for
- // GCC compatibility), so that's the chosen value here (the
- // absence of its emission implies zero).
- }
-
- // Set FP exceptions and rounding
- if (checkFunctionsAttributeConsistency(*MMI->getModule(),
- "no-trapping-math", "true") ||
- TM.Options.NoTrappingFPMath)
- ATS.emitAttribute(ARMBuildAttrs::ABI_FP_exceptions,
- ARMBuildAttrs::Not_Allowed);
- else if (!TM.Options.UnsafeFPMath) {
- ATS.emitAttribute(ARMBuildAttrs::ABI_FP_exceptions, ARMBuildAttrs::Allowed);
-
- // If the user has permitted this code to choose the IEEE 754
- // rounding at run-time, emit the rounding attribute.
- if (TM.Options.HonorSignDependentRoundingFPMathOption)
- ATS.emitAttribute(ARMBuildAttrs::ABI_FP_rounding, ARMBuildAttrs::Allowed);
- }
-
- // TM.Options.NoInfsFPMath && TM.Options.NoNaNsFPMath is the
- // equivalent of GCC's -ffinite-math-only flag.
- if (TM.Options.NoInfsFPMath && TM.Options.NoNaNsFPMath)
- ATS.emitAttribute(ARMBuildAttrs::ABI_FP_number_model,
- ARMBuildAttrs::Allowed);
- else
- ATS.emitAttribute(ARMBuildAttrs::ABI_FP_number_model,
- ARMBuildAttrs::AllowIEEE754);
-
- // FIXME: add more flags to ARMBuildAttributes.h
- // 8-bytes alignment stuff.
- ATS.emitAttribute(ARMBuildAttrs::ABI_align_needed, 1);
- ATS.emitAttribute(ARMBuildAttrs::ABI_align_preserved, 1);
-
- // Hard float. Use both S and D registers and conform to AAPCS-VFP.
- if (STI.isAAPCS_ABI() && TM.Options.FloatABIType == FloatABI::Hard)
- ATS.emitAttribute(ARMBuildAttrs::ABI_VFP_args, ARMBuildAttrs::HardFPAAPCS);
-
- // FIXME: To support emitting this build attribute as GCC does, the
- // -mfp16-format option and associated plumbing must be
- // supported. For now the __fp16 type is exposed by default, so this
- // attribute should be emitted with value 1.
- ATS.emitAttribute(ARMBuildAttrs::ABI_FP_16bit_format,
- ARMBuildAttrs::FP16FormatIEEE);
-
- if (MMI) {
- if (const Module *SourceModule = MMI->getModule()) {
- // ABI_PCS_wchar_t to indicate wchar_t width
- // FIXME: There is no way to emit value 0 (wchar_t prohibited).
- if (auto WCharWidthValue = mdconst::extract_or_null<ConstantInt>(
- SourceModule->getModuleFlag("wchar_size"))) {
- int WCharWidth = WCharWidthValue->getZExtValue();
- assert((WCharWidth == 2 || WCharWidth == 4) &&
- "wchar_t width must be 2 or 4 bytes");
- ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_wchar_t, WCharWidth);
- }
-
- // ABI_enum_size to indicate enum width
- // FIXME: There is no way to emit value 0 (enums prohibited) or value 3
- // (all enums contain a value needing 32 bits to encode).
- if (auto EnumWidthValue = mdconst::extract_or_null<ConstantInt>(
- SourceModule->getModuleFlag("min_enum_size"))) {
- int EnumWidth = EnumWidthValue->getZExtValue();
- assert((EnumWidth == 1 || EnumWidth == 4) &&
- "Minimum enum width must be 1 or 4 bytes");
- int EnumBuildAttr = EnumWidth == 1 ? 1 : 2;
- ATS.emitAttribute(ARMBuildAttrs::ABI_enum_size, EnumBuildAttr);
- }
- }
- }
-
- // We currently do not support using R9 as the TLS pointer.
- if (STI.isRWPI())
- ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use,
- ARMBuildAttrs::R9IsSB);
- else if (STI.isR9Reserved())
- ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use,
- ARMBuildAttrs::R9Reserved);
- else
- ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use,
- ARMBuildAttrs::R9IsGPR);
-}
-
-//===----------------------------------------------------------------------===//
-
-static MCSymbol *getPICLabel(StringRef Prefix, unsigned FunctionNumber,
- unsigned LabelId, MCContext &Ctx) {
-
- MCSymbol *Label = Ctx.getOrCreateSymbol(Twine(Prefix)
- + "PC" + Twine(FunctionNumber) + "_" + Twine(LabelId));
- return Label;
-}
-
-static MCSymbolRefExpr::VariantKind
-getModifierVariantKind(ARMCP::ARMCPModifier Modifier) {
- switch (Modifier) {
- case ARMCP::no_modifier:
- return MCSymbolRefExpr::VK_None;
- case ARMCP::TLSGD:
- return MCSymbolRefExpr::VK_TLSGD;
- case ARMCP::TPOFF:
- return MCSymbolRefExpr::VK_TPOFF;
- case ARMCP::GOTTPOFF:
- return MCSymbolRefExpr::VK_GOTTPOFF;
- case ARMCP::SBREL:
- return MCSymbolRefExpr::VK_ARM_SBREL;
- case ARMCP::GOT_PREL:
- return MCSymbolRefExpr::VK_ARM_GOT_PREL;
- case ARMCP::SECREL:
- return MCSymbolRefExpr::VK_SECREL;
- }
- llvm_unreachable("Invalid ARMCPModifier!");
-}
-
-MCSymbol *ARMAsmPrinter::GetARMGVSymbol(const GlobalValue *GV,
- unsigned char TargetFlags) {
- if (Subtarget->isTargetMachO()) {
- bool IsIndirect =
- (TargetFlags & ARMII::MO_NONLAZY) && Subtarget->isGVIndirectSymbol(GV);
-
- if (!IsIndirect)
- return getSymbol(GV);
-
- // FIXME: Remove this when Darwin transition to @GOT like syntax.
- MCSymbol *MCSym = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");
- MachineModuleInfoMachO &MMIMachO =
- MMI->getObjFileInfo<MachineModuleInfoMachO>();
- MachineModuleInfoImpl::StubValueTy &StubSym =
- GV->isThreadLocal() ? MMIMachO.getThreadLocalGVStubEntry(MCSym)
- : MMIMachO.getGVStubEntry(MCSym);
-
- if (!StubSym.getPointer())
- StubSym = MachineModuleInfoImpl::StubValueTy(getSymbol(GV),
- !GV->hasInternalLinkage());
- return MCSym;
- } else if (Subtarget->isTargetCOFF()) {
- assert(Subtarget->isTargetWindows() &&
- "Windows is the only supported COFF target");
-
- bool IsIndirect =
- (TargetFlags & (ARMII::MO_DLLIMPORT | ARMII::MO_COFFSTUB));
- if (!IsIndirect)
- return getSymbol(GV);
-
- SmallString<128> Name;
- if (TargetFlags & ARMII::MO_DLLIMPORT)
- Name = "__imp_";
- else if (TargetFlags & ARMII::MO_COFFSTUB)
- Name = ".refptr.";
- getNameWithPrefix(Name, GV);
-
- MCSymbol *MCSym = OutContext.getOrCreateSymbol(Name);
-
- if (TargetFlags & ARMII::MO_COFFSTUB) {
- MachineModuleInfoCOFF &MMICOFF =
- MMI->getObjFileInfo<MachineModuleInfoCOFF>();
- MachineModuleInfoImpl::StubValueTy &StubSym =
- MMICOFF.getGVStubEntry(MCSym);
-
- if (!StubSym.getPointer())
- StubSym = MachineModuleInfoImpl::StubValueTy(getSymbol(GV), true);
- }
-
- return MCSym;
- } else if (Subtarget->isTargetELF()) {
- return getSymbol(GV);
- }
- llvm_unreachable("unexpected target");
-}
-
-void ARMAsmPrinter::
-EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) {
- const DataLayout &DL = getDataLayout();
- int Size = DL.getTypeAllocSize(MCPV->getType());
-
- ARMConstantPoolValue *ACPV = static_cast<ARMConstantPoolValue*>(MCPV);
-
- if (ACPV->isPromotedGlobal()) {
- // This constant pool entry is actually a global whose storage has been
- // promoted into the constant pool. This global may be referenced still
- // by debug information, and due to the way AsmPrinter is set up, the debug
- // info is immutable by the time we decide to promote globals to constant
- // pools. Because of this, we need to ensure we emit a symbol for the global
- // with private linkage (the default) so debug info can refer to it.
- //
- // However, if this global is promoted into several functions we must ensure
- // we don't try and emit duplicate symbols!
- auto *ACPC = cast<ARMConstantPoolConstant>(ACPV);
- for (const auto *GV : ACPC->promotedGlobals()) {
- if (!EmittedPromotedGlobalLabels.count(GV)) {
- MCSymbol *GVSym = getSymbol(GV);
- OutStreamer->EmitLabel(GVSym);
- EmittedPromotedGlobalLabels.insert(GV);
- }
- }
- return EmitGlobalConstant(DL, ACPC->getPromotedGlobalInit());
- }
-
- MCSymbol *MCSym;
- if (ACPV->isLSDA()) {
- MCSym = getCurExceptionSym();
- } else if (ACPV->isBlockAddress()) {
- const BlockAddress *BA =
- cast<ARMConstantPoolConstant>(ACPV)->getBlockAddress();
- MCSym = GetBlockAddressSymbol(BA);
- } else if (ACPV->isGlobalValue()) {
- const GlobalValue *GV = cast<ARMConstantPoolConstant>(ACPV)->getGV();
-
- // On Darwin, const-pool entries may get the "FOO$non_lazy_ptr" mangling, so
- // flag the global as MO_NONLAZY.
- unsigned char TF = Subtarget->isTargetMachO() ? ARMII::MO_NONLAZY : 0;
- MCSym = GetARMGVSymbol(GV, TF);
- } else if (ACPV->isMachineBasicBlock()) {
- const MachineBasicBlock *MBB = cast<ARMConstantPoolMBB>(ACPV)->getMBB();
- MCSym = MBB->getSymbol();
- } else {
- assert(ACPV->isExtSymbol() && "unrecognized constant pool value");
- auto Sym = cast<ARMConstantPoolSymbol>(ACPV)->getSymbol();
- MCSym = GetExternalSymbolSymbol(Sym);
- }
-
- // Create an MCSymbol for the reference.
- const MCExpr *Expr =
- MCSymbolRefExpr::create(MCSym, getModifierVariantKind(ACPV->getModifier()),
- OutContext);
-
- if (ACPV->getPCAdjustment()) {
- MCSymbol *PCLabel =
- getPICLabel(DL.getPrivateGlobalPrefix(), getFunctionNumber(),
- ACPV->getLabelId(), OutContext);
- const MCExpr *PCRelExpr = MCSymbolRefExpr::create(PCLabel, OutContext);
- PCRelExpr =
- MCBinaryExpr::createAdd(PCRelExpr,
- MCConstantExpr::create(ACPV->getPCAdjustment(),
- OutContext),
- OutContext);
- if (ACPV->mustAddCurrentAddress()) {
- // We want "(<expr> - .)", but MC doesn't have a concept of the '.'
- // label, so just emit a local label end reference that instead.
- MCSymbol *DotSym = OutContext.createTempSymbol();
- OutStreamer->EmitLabel(DotSym);
- const MCExpr *DotExpr = MCSymbolRefExpr::create(DotSym, OutContext);
- PCRelExpr = MCBinaryExpr::createSub(PCRelExpr, DotExpr, OutContext);
- }
- Expr = MCBinaryExpr::createSub(Expr, PCRelExpr, OutContext);
- }
- OutStreamer->EmitValue(Expr, Size);
-}
-
-void ARMAsmPrinter::EmitJumpTableAddrs(const MachineInstr *MI) {
- const MachineOperand &MO1 = MI->getOperand(1);
- unsigned JTI = MO1.getIndex();
-
- // Make sure the Thumb jump table is 4-byte aligned. This will be a nop for
- // ARM mode tables.
- EmitAlignment(2);
-
- // Emit a label for the jump table.
- MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel(JTI);
- OutStreamer->EmitLabel(JTISymbol);
-
- // Mark the jump table as data-in-code.
- OutStreamer->EmitDataRegion(MCDR_DataRegionJT32);
-
- // Emit each entry of the table.
- const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
- const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
- const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
-
- for (MachineBasicBlock *MBB : JTBBs) {
- // Construct an MCExpr for the entry. We want a value of the form:
- // (BasicBlockAddr - TableBeginAddr)
- //
- // For example, a table with entries jumping to basic blocks BB0 and BB1
- // would look like:
- // LJTI_0_0:
- // .word (LBB0 - LJTI_0_0)
- // .word (LBB1 - LJTI_0_0)
- const MCExpr *Expr = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext);
-
- if (isPositionIndependent() || Subtarget->isROPI())
- Expr = MCBinaryExpr::createSub(Expr, MCSymbolRefExpr::create(JTISymbol,
- OutContext),
- OutContext);
- // If we're generating a table of Thumb addresses in static relocation
- // model, we need to add one to keep interworking correctly.
- else if (AFI->isThumbFunction())
- Expr = MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(1,OutContext),
- OutContext);
- OutStreamer->EmitValue(Expr, 4);
- }
- // Mark the end of jump table data-in-code region.
- OutStreamer->EmitDataRegion(MCDR_DataRegionEnd);
-}
-
-void ARMAsmPrinter::EmitJumpTableInsts(const MachineInstr *MI) {
- const MachineOperand &MO1 = MI->getOperand(1);
- unsigned JTI = MO1.getIndex();
-
- // Make sure the Thumb jump table is 4-byte aligned. This will be a nop for
- // ARM mode tables.
- EmitAlignment(2);
-
- // Emit a label for the jump table.
- MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel(JTI);
- OutStreamer->EmitLabel(JTISymbol);
-
- // Emit each entry of the table.
- const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
- const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
- const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
-
- for (MachineBasicBlock *MBB : JTBBs) {
- const MCExpr *MBBSymbolExpr = MCSymbolRefExpr::create(MBB->getSymbol(),
- OutContext);
- // If this isn't a TBB or TBH, the entries are direct branch instructions.
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::t2B)
- .addExpr(MBBSymbolExpr)
- .addImm(ARMCC::AL)
- .addReg(0));
- }
-}
-
-void ARMAsmPrinter::EmitJumpTableTBInst(const MachineInstr *MI,
- unsigned OffsetWidth) {
- assert((OffsetWidth == 1 || OffsetWidth == 2) && "invalid tbb/tbh width");
- const MachineOperand &MO1 = MI->getOperand(1);
- unsigned JTI = MO1.getIndex();
-
- if (Subtarget->isThumb1Only())
- EmitAlignment(2);
-
- MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel(JTI);
- OutStreamer->EmitLabel(JTISymbol);
-
- // Emit each entry of the table.
- const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
- const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
- const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
-
- // Mark the jump table as data-in-code.
- OutStreamer->EmitDataRegion(OffsetWidth == 1 ? MCDR_DataRegionJT8
- : MCDR_DataRegionJT16);
-
- for (auto MBB : JTBBs) {
- const MCExpr *MBBSymbolExpr = MCSymbolRefExpr::create(MBB->getSymbol(),
- OutContext);
- // Otherwise it's an offset from the dispatch instruction. Construct an
- // MCExpr for the entry. We want a value of the form:
- // (BasicBlockAddr - TBBInstAddr + 4) / 2
- //
- // For example, a TBB table with entries jumping to basic blocks BB0 and BB1
- // would look like:
- // LJTI_0_0:
- // .byte (LBB0 - (LCPI0_0 + 4)) / 2
- // .byte (LBB1 - (LCPI0_0 + 4)) / 2
- // where LCPI0_0 is a label defined just before the TBB instruction using
- // this table.
- MCSymbol *TBInstPC = GetCPISymbol(MI->getOperand(0).getImm());
- const MCExpr *Expr = MCBinaryExpr::createAdd(
- MCSymbolRefExpr::create(TBInstPC, OutContext),
- MCConstantExpr::create(4, OutContext), OutContext);
- Expr = MCBinaryExpr::createSub(MBBSymbolExpr, Expr, OutContext);
- Expr = MCBinaryExpr::createDiv(Expr, MCConstantExpr::create(2, OutContext),
- OutContext);
- OutStreamer->EmitValue(Expr, OffsetWidth);
- }
- // Mark the end of jump table data-in-code region. 32-bit offsets use
- // actual branch instructions here, so we don't mark those as a data-region
- // at all.
- OutStreamer->EmitDataRegion(MCDR_DataRegionEnd);
-
- // Make sure the next instruction is 2-byte aligned.
- EmitAlignment(1);
-}
-
-void ARMAsmPrinter::EmitUnwindingInstruction(const MachineInstr *MI) {
- assert(MI->getFlag(MachineInstr::FrameSetup) &&
- "Only instruction which are involved into frame setup code are allowed");
-
- MCTargetStreamer &TS = *OutStreamer->getTargetStreamer();
- ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS);
- const MachineFunction &MF = *MI->getParent()->getParent();
- const TargetRegisterInfo *TargetRegInfo =
- MF.getSubtarget().getRegisterInfo();
- const MachineRegisterInfo &MachineRegInfo = MF.getRegInfo();
- const ARMFunctionInfo &AFI = *MF.getInfo<ARMFunctionInfo>();
-
- unsigned FramePtr = TargetRegInfo->getFrameRegister(MF);
- unsigned Opc = MI->getOpcode();
- unsigned SrcReg, DstReg;
-
- if (Opc == ARM::tPUSH || Opc == ARM::tLDRpci) {
- // Two special cases:
- // 1) tPUSH does not have src/dst regs.
- // 2) for Thumb1 code we sometimes materialize the constant via constpool
- // load. Yes, this is pretty fragile, but for now I don't see better
- // way... :(
- SrcReg = DstReg = ARM::SP;
- } else {
- SrcReg = MI->getOperand(1).getReg();
- DstReg = MI->getOperand(0).getReg();
- }
-
- // Try to figure out the unwinding opcode out of src / dst regs.
- if (MI->mayStore()) {
- // Register saves.
- assert(DstReg == ARM::SP &&
- "Only stack pointer as a destination reg is supported");
-
- SmallVector<unsigned, 4> RegList;
- // Skip src & dst reg, and pred ops.
- unsigned StartOp = 2 + 2;
- // Use all the operands.
- unsigned NumOffset = 0;
- // Amount of SP adjustment folded into a push.
- unsigned Pad = 0;
-
- switch (Opc) {
- default:
- MI->print(errs());
- llvm_unreachable("Unsupported opcode for unwinding information");
- case ARM::tPUSH:
- // Special case here: no src & dst reg, but two extra imp ops.
- StartOp = 2; NumOffset = 2;
- LLVM_FALLTHROUGH;
- case ARM::STMDB_UPD:
- case ARM::t2STMDB_UPD:
- case ARM::VSTMDDB_UPD:
- assert(SrcReg == ARM::SP &&
- "Only stack pointer as a source reg is supported");
- for (unsigned i = StartOp, NumOps = MI->getNumOperands() - NumOffset;
- i != NumOps; ++i) {
- const MachineOperand &MO = MI->getOperand(i);
- // Actually, there should never be any impdef stuff here. Skip it
- // temporary to workaround PR11902.
- if (MO.isImplicit())
- continue;
- // Registers, pushed as a part of folding an SP update into the
- // push instruction are marked as undef and should not be
- // restored when unwinding, because the function can modify the
- // corresponding stack slots.
- if (MO.isUndef()) {
- assert(RegList.empty() &&
- "Pad registers must come before restored ones");
- unsigned Width =
- TargetRegInfo->getRegSizeInBits(MO.getReg(), MachineRegInfo) / 8;
- Pad += Width;
- continue;
- }
- RegList.push_back(MO.getReg());
- }
- break;
- case ARM::STR_PRE_IMM:
- case ARM::STR_PRE_REG:
- case ARM::t2STR_PRE:
- assert(MI->getOperand(2).getReg() == ARM::SP &&
- "Only stack pointer as a source reg is supported");
- RegList.push_back(SrcReg);
- break;
- }
- if (MAI->getExceptionHandlingType() == ExceptionHandling::ARM) {
- ATS.emitRegSave(RegList, Opc == ARM::VSTMDDB_UPD);
- // Account for the SP adjustment, folded into the push.
- if (Pad)
- ATS.emitPad(Pad);
- }
- } else {
- // Changes of stack / frame pointer.
- if (SrcReg == ARM::SP) {
- int64_t Offset = 0;
- switch (Opc) {
- default:
- MI->print(errs());
- llvm_unreachable("Unsupported opcode for unwinding information");
- case ARM::MOVr:
- case ARM::tMOVr:
- Offset = 0;
- break;
- case ARM::ADDri:
- case ARM::t2ADDri:
- Offset = -MI->getOperand(2).getImm();
- break;
- case ARM::SUBri:
- case ARM::t2SUBri:
- Offset = MI->getOperand(2).getImm();
- break;
- case ARM::tSUBspi:
- Offset = MI->getOperand(2).getImm()*4;
- break;
- case ARM::tADDspi:
- case ARM::tADDrSPi:
- Offset = -MI->getOperand(2).getImm()*4;
- break;
- case ARM::tLDRpci: {
- // Grab the constpool index and check, whether it corresponds to
- // original or cloned constpool entry.
- unsigned CPI = MI->getOperand(1).getIndex();
- const MachineConstantPool *MCP = MF.getConstantPool();
- if (CPI >= MCP->getConstants().size())
- CPI = AFI.getOriginalCPIdx(CPI);
- assert(CPI != -1U && "Invalid constpool index");
-
- // Derive the actual offset.
- const MachineConstantPoolEntry &CPE = MCP->getConstants()[CPI];
- assert(!CPE.isMachineConstantPoolEntry() && "Invalid constpool entry");
- // FIXME: Check for user, it should be "add" instruction!
- Offset = -cast<ConstantInt>(CPE.Val.ConstVal)->getSExtValue();
- break;
- }
- }
-
- if (MAI->getExceptionHandlingType() == ExceptionHandling::ARM) {
- if (DstReg == FramePtr && FramePtr != ARM::SP)
- // Set-up of the frame pointer. Positive values correspond to "add"
- // instruction.
- ATS.emitSetFP(FramePtr, ARM::SP, -Offset);
- else if (DstReg == ARM::SP) {
- // Change of SP by an offset. Positive values correspond to "sub"
- // instruction.
- ATS.emitPad(Offset);
- } else {
- // Move of SP to a register. Positive values correspond to an "add"
- // instruction.
- ATS.emitMovSP(DstReg, -Offset);
- }
- }
- } else if (DstReg == ARM::SP) {
- MI->print(errs());
- llvm_unreachable("Unsupported opcode for unwinding information");
- }
- else {
- MI->print(errs());
- llvm_unreachable("Unsupported opcode for unwinding information");
- }
- }
-}
-
-// Simple pseudo-instructions have their lowering (with expansion to real
-// instructions) auto-generated.
-#include "ARMGenMCPseudoLowering.inc"
-
-void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
- const DataLayout &DL = getDataLayout();
- MCTargetStreamer &TS = *OutStreamer->getTargetStreamer();
- ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS);
-
- const MachineFunction &MF = *MI->getParent()->getParent();
- const ARMSubtarget &STI = MF.getSubtarget<ARMSubtarget>();
- unsigned FramePtr = STI.useR7AsFramePointer() ? ARM::R7 : ARM::R11;
-
- // If we just ended a constant pool, mark it as such.
- if (InConstantPool && MI->getOpcode() != ARM::CONSTPOOL_ENTRY) {
- OutStreamer->EmitDataRegion(MCDR_DataRegionEnd);
- InConstantPool = false;
- }
-
- // Emit unwinding stuff for frame-related instructions
- if (Subtarget->isTargetEHABICompatible() &&
- MI->getFlag(MachineInstr::FrameSetup))
- EmitUnwindingInstruction(MI);
-
- // Do any auto-generated pseudo lowerings.
- if (emitPseudoExpansionLowering(*OutStreamer, MI))
- return;
-
- assert(!convertAddSubFlagsOpcode(MI->getOpcode()) &&
- "Pseudo flag setting opcode should be expanded early");
-
- // Check for manual lowerings.
- unsigned Opc = MI->getOpcode();
- switch (Opc) {
- case ARM::t2MOVi32imm: llvm_unreachable("Should be lowered by thumb2it pass");
- case ARM::DBG_VALUE: llvm_unreachable("Should be handled by generic printing");
- case ARM::LEApcrel:
- case ARM::tLEApcrel:
- case ARM::t2LEApcrel: {
- // FIXME: Need to also handle globals and externals
- MCSymbol *CPISymbol = GetCPISymbol(MI->getOperand(1).getIndex());
- EmitToStreamer(*OutStreamer, MCInstBuilder(MI->getOpcode() ==
- ARM::t2LEApcrel ? ARM::t2ADR
- : (MI->getOpcode() == ARM::tLEApcrel ? ARM::tADR
- : ARM::ADR))
- .addReg(MI->getOperand(0).getReg())
- .addExpr(MCSymbolRefExpr::create(CPISymbol, OutContext))
- // Add predicate operands.
- .addImm(MI->getOperand(2).getImm())
- .addReg(MI->getOperand(3).getReg()));
- return;
- }
- case ARM::LEApcrelJT:
- case ARM::tLEApcrelJT:
- case ARM::t2LEApcrelJT: {
- MCSymbol *JTIPICSymbol =
- GetARMJTIPICJumpTableLabel(MI->getOperand(1).getIndex());
- EmitToStreamer(*OutStreamer, MCInstBuilder(MI->getOpcode() ==
- ARM::t2LEApcrelJT ? ARM::t2ADR
- : (MI->getOpcode() == ARM::tLEApcrelJT ? ARM::tADR
- : ARM::ADR))
- .addReg(MI->getOperand(0).getReg())
- .addExpr(MCSymbolRefExpr::create(JTIPICSymbol, OutContext))
- // Add predicate operands.
- .addImm(MI->getOperand(2).getImm())
- .addReg(MI->getOperand(3).getReg()));
- return;
- }
- // Darwin call instructions are just normal call instructions with different
- // clobber semantics (they clobber R9).
- case ARM::BX_CALL: {
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::MOVr)
- .addReg(ARM::LR)
- .addReg(ARM::PC)
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0)
- // Add 's' bit operand (always reg0 for this)
- .addReg(0));
-
- assert(Subtarget->hasV4TOps());
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::BX)
- .addReg(MI->getOperand(0).getReg()));
- return;
- }
- case ARM::tBX_CALL: {
- if (Subtarget->hasV5TOps())
- llvm_unreachable("Expected BLX to be selected for v5t+");
-
- // On ARM v4t, when doing a call from thumb mode, we need to ensure
- // that the saved lr has its LSB set correctly (the arch doesn't
- // have blx).
- // So here we generate a bl to a small jump pad that does bx rN.
- // The jump pads are emitted after the function body.
-
- unsigned TReg = MI->getOperand(0).getReg();
- MCSymbol *TRegSym = nullptr;
- for (std::pair<unsigned, MCSymbol *> &TIP : ThumbIndirectPads) {
- if (TIP.first == TReg) {
- TRegSym = TIP.second;
- break;
- }
- }
-
- if (!TRegSym) {
- TRegSym = OutContext.createTempSymbol();
- ThumbIndirectPads.push_back(std::make_pair(TReg, TRegSym));
- }
-
- // Create a link-saving branch to the Reg Indirect Jump Pad.
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tBL)
- // Predicate comes first here.
- .addImm(ARMCC::AL).addReg(0)
- .addExpr(MCSymbolRefExpr::create(TRegSym, OutContext)));
- return;
- }
- case ARM::BMOVPCRX_CALL: {
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::MOVr)
- .addReg(ARM::LR)
- .addReg(ARM::PC)
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0)
- // Add 's' bit operand (always reg0 for this)
- .addReg(0));
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::MOVr)
- .addReg(ARM::PC)
- .addReg(MI->getOperand(0).getReg())
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0)
- // Add 's' bit operand (always reg0 for this)
- .addReg(0));
- return;
- }
- case ARM::BMOVPCB_CALL: {
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::MOVr)
- .addReg(ARM::LR)
- .addReg(ARM::PC)
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0)
- // Add 's' bit operand (always reg0 for this)
- .addReg(0));
-
- const MachineOperand &Op = MI->getOperand(0);
- const GlobalValue *GV = Op.getGlobal();
- const unsigned TF = Op.getTargetFlags();
- MCSymbol *GVSym = GetARMGVSymbol(GV, TF);
- const MCExpr *GVSymExpr = MCSymbolRefExpr::create(GVSym, OutContext);
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::Bcc)
- .addExpr(GVSymExpr)
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0));
- return;
- }
- case ARM::MOVi16_ga_pcrel:
- case ARM::t2MOVi16_ga_pcrel: {
- MCInst TmpInst;
- TmpInst.setOpcode(Opc == ARM::MOVi16_ga_pcrel? ARM::MOVi16 : ARM::t2MOVi16);
- TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
-
- unsigned TF = MI->getOperand(1).getTargetFlags();
- const GlobalValue *GV = MI->getOperand(1).getGlobal();
- MCSymbol *GVSym = GetARMGVSymbol(GV, TF);
- const MCExpr *GVSymExpr = MCSymbolRefExpr::create(GVSym, OutContext);
-
- MCSymbol *LabelSym =
- getPICLabel(DL.getPrivateGlobalPrefix(), getFunctionNumber(),
- MI->getOperand(2).getImm(), OutContext);
- const MCExpr *LabelSymExpr= MCSymbolRefExpr::create(LabelSym, OutContext);
- unsigned PCAdj = (Opc == ARM::MOVi16_ga_pcrel) ? 8 : 4;
- const MCExpr *PCRelExpr =
- ARMMCExpr::createLower16(MCBinaryExpr::createSub(GVSymExpr,
- MCBinaryExpr::createAdd(LabelSymExpr,
- MCConstantExpr::create(PCAdj, OutContext),
- OutContext), OutContext), OutContext);
- TmpInst.addOperand(MCOperand::createExpr(PCRelExpr));
-
- // Add predicate operands.
- TmpInst.addOperand(MCOperand::createImm(ARMCC::AL));
- TmpInst.addOperand(MCOperand::createReg(0));
- // Add 's' bit operand (always reg0 for this)
- TmpInst.addOperand(MCOperand::createReg(0));
- EmitToStreamer(*OutStreamer, TmpInst);
- return;
- }
- case ARM::MOVTi16_ga_pcrel:
- case ARM::t2MOVTi16_ga_pcrel: {
- MCInst TmpInst;
- TmpInst.setOpcode(Opc == ARM::MOVTi16_ga_pcrel
- ? ARM::MOVTi16 : ARM::t2MOVTi16);
- TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
- TmpInst.addOperand(MCOperand::createReg(MI->getOperand(1).getReg()));
-
- unsigned TF = MI->getOperand(2).getTargetFlags();
- const GlobalValue *GV = MI->getOperand(2).getGlobal();
- MCSymbol *GVSym = GetARMGVSymbol(GV, TF);
- const MCExpr *GVSymExpr = MCSymbolRefExpr::create(GVSym, OutContext);
-
- MCSymbol *LabelSym =
- getPICLabel(DL.getPrivateGlobalPrefix(), getFunctionNumber(),
- MI->getOperand(3).getImm(), OutContext);
- const MCExpr *LabelSymExpr= MCSymbolRefExpr::create(LabelSym, OutContext);
- unsigned PCAdj = (Opc == ARM::MOVTi16_ga_pcrel) ? 8 : 4;
- const MCExpr *PCRelExpr =
- ARMMCExpr::createUpper16(MCBinaryExpr::createSub(GVSymExpr,
- MCBinaryExpr::createAdd(LabelSymExpr,
- MCConstantExpr::create(PCAdj, OutContext),
- OutContext), OutContext), OutContext);
- TmpInst.addOperand(MCOperand::createExpr(PCRelExpr));
- // Add predicate operands.
- TmpInst.addOperand(MCOperand::createImm(ARMCC::AL));
- TmpInst.addOperand(MCOperand::createReg(0));
- // Add 's' bit operand (always reg0 for this)
- TmpInst.addOperand(MCOperand::createReg(0));
- EmitToStreamer(*OutStreamer, TmpInst);
- return;
- }
- case ARM::tPICADD: {
- // This is a pseudo op for a label + instruction sequence, which looks like:
- // LPC0:
- // add r0, pc
- // This adds the address of LPC0 to r0.
-
- // Emit the label.
- OutStreamer->EmitLabel(getPICLabel(DL.getPrivateGlobalPrefix(),
- getFunctionNumber(),
- MI->getOperand(2).getImm(), OutContext));
-
- // Form and emit the add.
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tADDhirr)
- .addReg(MI->getOperand(0).getReg())
- .addReg(MI->getOperand(0).getReg())
- .addReg(ARM::PC)
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0));
- return;
- }
- case ARM::PICADD: {
- // This is a pseudo op for a label + instruction sequence, which looks like:
- // LPC0:
- // add r0, pc, r0
- // This adds the address of LPC0 to r0.
-
- // Emit the label.
- OutStreamer->EmitLabel(getPICLabel(DL.getPrivateGlobalPrefix(),
- getFunctionNumber(),
- MI->getOperand(2).getImm(), OutContext));
-
- // Form and emit the add.
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::ADDrr)
- .addReg(MI->getOperand(0).getReg())
- .addReg(ARM::PC)
- .addReg(MI->getOperand(1).getReg())
- // Add predicate operands.
- .addImm(MI->getOperand(3).getImm())
- .addReg(MI->getOperand(4).getReg())
- // Add 's' bit operand (always reg0 for this)
- .addReg(0));
- return;
- }
- case ARM::PICSTR:
- case ARM::PICSTRB:
- case ARM::PICSTRH:
- case ARM::PICLDR:
- case ARM::PICLDRB:
- case ARM::PICLDRH:
- case ARM::PICLDRSB:
- case ARM::PICLDRSH: {
- // This is a pseudo op for a label + instruction sequence, which looks like:
- // LPC0:
- // OP r0, [pc, r0]
- // The LCP0 label is referenced by a constant pool entry in order to get
- // a PC-relative address at the ldr instruction.
-
- // Emit the label.
- OutStreamer->EmitLabel(getPICLabel(DL.getPrivateGlobalPrefix(),
- getFunctionNumber(),
- MI->getOperand(2).getImm(), OutContext));
-
- // Form and emit the load
- unsigned Opcode;
- switch (MI->getOpcode()) {
- default:
- llvm_unreachable("Unexpected opcode!");
- case ARM::PICSTR: Opcode = ARM::STRrs; break;
- case ARM::PICSTRB: Opcode = ARM::STRBrs; break;
- case ARM::PICSTRH: Opcode = ARM::STRH; break;
- case ARM::PICLDR: Opcode = ARM::LDRrs; break;
- case ARM::PICLDRB: Opcode = ARM::LDRBrs; break;
- case ARM::PICLDRH: Opcode = ARM::LDRH; break;
- case ARM::PICLDRSB: Opcode = ARM::LDRSB; break;
- case ARM::PICLDRSH: Opcode = ARM::LDRSH; break;
- }
- EmitToStreamer(*OutStreamer, MCInstBuilder(Opcode)
- .addReg(MI->getOperand(0).getReg())
- .addReg(ARM::PC)
- .addReg(MI->getOperand(1).getReg())
- .addImm(0)
- // Add predicate operands.
- .addImm(MI->getOperand(3).getImm())
- .addReg(MI->getOperand(4).getReg()));
-
- return;
- }
- case ARM::CONSTPOOL_ENTRY: {
- if (Subtarget->genExecuteOnly())
- llvm_unreachable("execute-only should not generate constant pools");
-
- /// CONSTPOOL_ENTRY - This instruction represents a floating constant pool
- /// in the function. The first operand is the ID# for this instruction, the
- /// second is the index into the MachineConstantPool that this is, the third
- /// is the size in bytes of this constant pool entry.
- /// The required alignment is specified on the basic block holding this MI.
- unsigned LabelId = (unsigned)MI->getOperand(0).getImm();
- unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();
-
- // If this is the first entry of the pool, mark it.
- if (!InConstantPool) {
- OutStreamer->EmitDataRegion(MCDR_DataRegion);
- InConstantPool = true;
- }
-
- OutStreamer->EmitLabel(GetCPISymbol(LabelId));
-
- const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx];
- if (MCPE.isMachineConstantPoolEntry())
- EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
- else
- EmitGlobalConstant(DL, MCPE.Val.ConstVal);
- return;
- }
- case ARM::JUMPTABLE_ADDRS:
- EmitJumpTableAddrs(MI);
- return;
- case ARM::JUMPTABLE_INSTS:
- EmitJumpTableInsts(MI);
- return;
- case ARM::JUMPTABLE_TBB:
- case ARM::JUMPTABLE_TBH:
- EmitJumpTableTBInst(MI, MI->getOpcode() == ARM::JUMPTABLE_TBB ? 1 : 2);
- return;
- case ARM::t2BR_JT: {
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tMOVr)
- .addReg(ARM::PC)
- .addReg(MI->getOperand(0).getReg())
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0));
- return;
- }
- case ARM::t2TBB_JT:
- case ARM::t2TBH_JT: {
- unsigned Opc = MI->getOpcode() == ARM::t2TBB_JT ? ARM::t2TBB : ARM::t2TBH;
- // Lower and emit the PC label, then the instruction itself.
- OutStreamer->EmitLabel(GetCPISymbol(MI->getOperand(3).getImm()));
- EmitToStreamer(*OutStreamer, MCInstBuilder(Opc)
- .addReg(MI->getOperand(0).getReg())
- .addReg(MI->getOperand(1).getReg())
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0));
- return;
- }
- case ARM::tTBB_JT:
- case ARM::tTBH_JT: {
-
- bool Is8Bit = MI->getOpcode() == ARM::tTBB_JT;
- unsigned Base = MI->getOperand(0).getReg();
- unsigned Idx = MI->getOperand(1).getReg();
- assert(MI->getOperand(1).isKill() && "We need the index register as scratch!");
-
- // Multiply up idx if necessary.
- if (!Is8Bit)
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tLSLri)
- .addReg(Idx)
- .addReg(ARM::CPSR)
- .addReg(Idx)
- .addImm(1)
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- if (Base == ARM::PC) {
- // TBB [base, idx] =
- // ADDS idx, idx, base
- // LDRB idx, [idx, #4] ; or LDRH if TBH
- // LSLS idx, #1
- // ADDS pc, pc, idx
-
- // When using PC as the base, it's important that there is no padding
- // between the last ADDS and the start of the jump table. The jump table
- // is 4-byte aligned, so we ensure we're 4 byte aligned here too.
- //
- // FIXME: Ideally we could vary the LDRB index based on the padding
- // between the sequence and jump table, however that relies on MCExprs
- // for load indexes which are currently not supported.
- OutStreamer->EmitCodeAlignment(4);
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tADDhirr)
- .addReg(Idx)
- .addReg(Idx)
- .addReg(Base)
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- unsigned Opc = Is8Bit ? ARM::tLDRBi : ARM::tLDRHi;
- EmitToStreamer(*OutStreamer, MCInstBuilder(Opc)
- .addReg(Idx)
- .addReg(Idx)
- .addImm(Is8Bit ? 4 : 2)
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0));
- } else {
- // TBB [base, idx] =
- // LDRB idx, [base, idx] ; or LDRH if TBH
- // LSLS idx, #1
- // ADDS pc, pc, idx
-
- unsigned Opc = Is8Bit ? ARM::tLDRBr : ARM::tLDRHr;
- EmitToStreamer(*OutStreamer, MCInstBuilder(Opc)
- .addReg(Idx)
- .addReg(Base)
- .addReg(Idx)
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0));
- }
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tLSLri)
- .addReg(Idx)
- .addReg(ARM::CPSR)
- .addReg(Idx)
- .addImm(1)
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- OutStreamer->EmitLabel(GetCPISymbol(MI->getOperand(3).getImm()));
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tADDhirr)
- .addReg(ARM::PC)
- .addReg(ARM::PC)
- .addReg(Idx)
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0));
- return;
- }
- case ARM::tBR_JTr:
- case ARM::BR_JTr: {
- // mov pc, target
- MCInst TmpInst;
- unsigned Opc = MI->getOpcode() == ARM::BR_JTr ?
- ARM::MOVr : ARM::tMOVr;
- TmpInst.setOpcode(Opc);
- TmpInst.addOperand(MCOperand::createReg(ARM::PC));
- TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
- // Add predicate operands.
- TmpInst.addOperand(MCOperand::createImm(ARMCC::AL));
- TmpInst.addOperand(MCOperand::createReg(0));
- // Add 's' bit operand (always reg0 for this)
- if (Opc == ARM::MOVr)
- TmpInst.addOperand(MCOperand::createReg(0));
- EmitToStreamer(*OutStreamer, TmpInst);
- return;
- }
- case ARM::BR_JTm_i12: {
- // ldr pc, target
- MCInst TmpInst;
- TmpInst.setOpcode(ARM::LDRi12);
- TmpInst.addOperand(MCOperand::createReg(ARM::PC));
- TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
- TmpInst.addOperand(MCOperand::createImm(MI->getOperand(2).getImm()));
- // Add predicate operands.
- TmpInst.addOperand(MCOperand::createImm(ARMCC::AL));
- TmpInst.addOperand(MCOperand::createReg(0));
- EmitToStreamer(*OutStreamer, TmpInst);
- return;
- }
- case ARM::BR_JTm_rs: {
- // ldr pc, target
- MCInst TmpInst;
- TmpInst.setOpcode(ARM::LDRrs);
- TmpInst.addOperand(MCOperand::createReg(ARM::PC));
- TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
- TmpInst.addOperand(MCOperand::createReg(MI->getOperand(1).getReg()));
- TmpInst.addOperand(MCOperand::createImm(MI->getOperand(2).getImm()));
- // Add predicate operands.
- TmpInst.addOperand(MCOperand::createImm(ARMCC::AL));
- TmpInst.addOperand(MCOperand::createReg(0));
- EmitToStreamer(*OutStreamer, TmpInst);
- return;
- }
- case ARM::BR_JTadd: {
- // add pc, target, idx
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::ADDrr)
- .addReg(ARM::PC)
- .addReg(MI->getOperand(0).getReg())
- .addReg(MI->getOperand(1).getReg())
- // Add predicate operands.
- .addImm(ARMCC::AL)
- .addReg(0)
- // Add 's' bit operand (always reg0 for this)
- .addReg(0));
- return;
- }
- case ARM::SPACE:
- OutStreamer->EmitZeros(MI->getOperand(1).getImm());
- return;
- case ARM::TRAP: {
- // Non-Darwin binutils don't yet support the "trap" mnemonic.
- // FIXME: Remove this special case when they do.
- if (!Subtarget->isTargetMachO()) {
- uint32_t Val = 0xe7ffdefeUL;
- OutStreamer->AddComment("trap");
- ATS.emitInst(Val);
- return;
- }
- break;
- }
- case ARM::TRAPNaCl: {
- uint32_t Val = 0xe7fedef0UL;
- OutStreamer->AddComment("trap");
- ATS.emitInst(Val);
- return;
- }
- case ARM::tTRAP: {
- // Non-Darwin binutils don't yet support the "trap" mnemonic.
- // FIXME: Remove this special case when they do.
- if (!Subtarget->isTargetMachO()) {
- uint16_t Val = 0xdefe;
- OutStreamer->AddComment("trap");
- ATS.emitInst(Val, 'n');
- return;
- }
- break;
- }
- case ARM::t2Int_eh_sjlj_setjmp:
- case ARM::t2Int_eh_sjlj_setjmp_nofp:
- case ARM::tInt_eh_sjlj_setjmp: {
- // Two incoming args: GPR:$src, GPR:$val
- // mov $val, pc
- // adds $val, #7
- // str $val, [$src, #4]
- // movs r0, #0
- // b LSJLJEH
- // movs r0, #1
- // LSJLJEH:
- unsigned SrcReg = MI->getOperand(0).getReg();
- unsigned ValReg = MI->getOperand(1).getReg();
- MCSymbol *Label = OutContext.createTempSymbol("SJLJEH", false, true);
- OutStreamer->AddComment("eh_setjmp begin");
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tMOVr)
- .addReg(ValReg)
- .addReg(ARM::PC)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tADDi3)
- .addReg(ValReg)
- // 's' bit operand
- .addReg(ARM::CPSR)
- .addReg(ValReg)
- .addImm(7)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tSTRi)
- .addReg(ValReg)
- .addReg(SrcReg)
- // The offset immediate is #4. The operand value is scaled by 4 for the
- // tSTR instruction.
- .addImm(1)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tMOVi8)
- .addReg(ARM::R0)
- .addReg(ARM::CPSR)
- .addImm(0)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- const MCExpr *SymbolExpr = MCSymbolRefExpr::create(Label, OutContext);
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tB)
- .addExpr(SymbolExpr)
- .addImm(ARMCC::AL)
- .addReg(0));
-
- OutStreamer->AddComment("eh_setjmp end");
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tMOVi8)
- .addReg(ARM::R0)
- .addReg(ARM::CPSR)
- .addImm(1)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- OutStreamer->EmitLabel(Label);
- return;
- }
-
- case ARM::Int_eh_sjlj_setjmp_nofp:
- case ARM::Int_eh_sjlj_setjmp: {
- // Two incoming args: GPR:$src, GPR:$val
- // add $val, pc, #8
- // str $val, [$src, #+4]
- // mov r0, #0
- // add pc, pc, #0
- // mov r0, #1
- unsigned SrcReg = MI->getOperand(0).getReg();
- unsigned ValReg = MI->getOperand(1).getReg();
-
- OutStreamer->AddComment("eh_setjmp begin");
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::ADDri)
- .addReg(ValReg)
- .addReg(ARM::PC)
- .addImm(8)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0)
- // 's' bit operand (always reg0 for this).
- .addReg(0));
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::STRi12)
- .addReg(ValReg)
- .addReg(SrcReg)
- .addImm(4)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::MOVi)
- .addReg(ARM::R0)
- .addImm(0)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0)
- // 's' bit operand (always reg0 for this).
- .addReg(0));
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::ADDri)
- .addReg(ARM::PC)
- .addReg(ARM::PC)
- .addImm(0)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0)
- // 's' bit operand (always reg0 for this).
- .addReg(0));
-
- OutStreamer->AddComment("eh_setjmp end");
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::MOVi)
- .addReg(ARM::R0)
- .addImm(1)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0)
- // 's' bit operand (always reg0 for this).
- .addReg(0));
- return;
- }
- case ARM::Int_eh_sjlj_longjmp: {
- // ldr sp, [$src, #8]
- // ldr $scratch, [$src, #4]
- // ldr r7, [$src]
- // bx $scratch
- unsigned SrcReg = MI->getOperand(0).getReg();
- unsigned ScratchReg = MI->getOperand(1).getReg();
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::LDRi12)
- .addReg(ARM::SP)
- .addReg(SrcReg)
- .addImm(8)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::LDRi12)
- .addReg(ScratchReg)
- .addReg(SrcReg)
- .addImm(4)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- if (STI.isTargetDarwin() || STI.isTargetWindows()) {
- // These platforms always use the same frame register
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::LDRi12)
- .addReg(FramePtr)
- .addReg(SrcReg)
- .addImm(0)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
- } else {
- // If the calling code might use either R7 or R11 as
- // frame pointer register, restore it into both.
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::LDRi12)
- .addReg(ARM::R7)
- .addReg(SrcReg)
- .addImm(0)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::LDRi12)
- .addReg(ARM::R11)
- .addReg(SrcReg)
- .addImm(0)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
- }
-
- assert(Subtarget->hasV4TOps());
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::BX)
- .addReg(ScratchReg)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
- return;
- }
- case ARM::tInt_eh_sjlj_longjmp: {
- // ldr $scratch, [$src, #8]
- // mov sp, $scratch
- // ldr $scratch, [$src, #4]
- // ldr r7, [$src]
- // bx $scratch
- unsigned SrcReg = MI->getOperand(0).getReg();
- unsigned ScratchReg = MI->getOperand(1).getReg();
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tLDRi)
- .addReg(ScratchReg)
- .addReg(SrcReg)
- // The offset immediate is #8. The operand value is scaled by 4 for the
- // tLDR instruction.
- .addImm(2)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tMOVr)
- .addReg(ARM::SP)
- .addReg(ScratchReg)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tLDRi)
- .addReg(ScratchReg)
- .addReg(SrcReg)
- .addImm(1)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
-
- if (STI.isTargetDarwin() || STI.isTargetWindows()) {
- // These platforms always use the same frame register
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tLDRi)
- .addReg(FramePtr)
- .addReg(SrcReg)
- .addImm(0)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
- } else {
- // If the calling code might use either R7 or R11 as
- // frame pointer register, restore it into both.
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tLDRi)
- .addReg(ARM::R7)
- .addReg(SrcReg)
- .addImm(0)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tLDRi)
- .addReg(ARM::R11)
- .addReg(SrcReg)
- .addImm(0)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
- }
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tBX)
- .addReg(ScratchReg)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
- return;
- }
- case ARM::tInt_WIN_eh_sjlj_longjmp: {
- // ldr.w r11, [$src, #0]
- // ldr.w sp, [$src, #8]
- // ldr.w pc, [$src, #4]
-
- unsigned SrcReg = MI->getOperand(0).getReg();
-
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::t2LDRi12)
- .addReg(ARM::R11)
- .addReg(SrcReg)
- .addImm(0)
- // Predicate
- .addImm(ARMCC::AL)
- .addReg(0));
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::t2LDRi12)
- .addReg(ARM::SP)
- .addReg(SrcReg)
- .addImm(8)
- // Predicate
- .addImm(ARMCC::AL)
- .addReg(0));
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::t2LDRi12)
- .addReg(ARM::PC)
- .addReg(SrcReg)
- .addImm(4)
- // Predicate
- .addImm(ARMCC::AL)
- .addReg(0));
- return;
- }
- case ARM::PATCHABLE_FUNCTION_ENTER:
- LowerPATCHABLE_FUNCTION_ENTER(*MI);
- return;
- case ARM::PATCHABLE_FUNCTION_EXIT:
- LowerPATCHABLE_FUNCTION_EXIT(*MI);
- return;
- case ARM::PATCHABLE_TAIL_CALL:
- LowerPATCHABLE_TAIL_CALL(*MI);
- return;
- }
-
- MCInst TmpInst;
- LowerARMMachineInstrToMCInst(MI, TmpInst, *this);
-
- EmitToStreamer(*OutStreamer, TmpInst);
-}
-
-//===----------------------------------------------------------------------===//
-// Target Registry Stuff
-//===----------------------------------------------------------------------===//
-
-// Force static initialization.
-extern "C" void LLVMInitializeARMAsmPrinter() {
- RegisterAsmPrinter<ARMAsmPrinter> X(getTheARMLETarget());
- RegisterAsmPrinter<ARMAsmPrinter> Y(getTheARMBETarget());
- RegisterAsmPrinter<ARMAsmPrinter> A(getTheThumbLETarget());
- RegisterAsmPrinter<ARMAsmPrinter> B(getTheThumbBETarget());
-}