2009-10-20 04:20:46 +08:00
|
|
|
//===-- ARMAsmPrinter.cpp - Print machine code to an ARM .s file ----------===//
|
|
|
|
//
|
2006-05-15 06:18:28 +08:00
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 04:36:04 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
2006-05-15 06:18:28 +08:00
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2006-12-20 06:59:26 +08:00
|
|
|
#define DEBUG_TYPE "asm-printer"
|
2006-05-15 06:18:28 +08:00
|
|
|
#include "ARM.h"
|
2009-05-24 03:51:20 +08:00
|
|
|
#include "ARMBuildAttrs.h"
|
2007-01-19 15:51:42 +08:00
|
|
|
#include "ARMAddressingModes.h"
|
|
|
|
#include "ARMConstantPoolValue.h"
|
2009-10-20 03:59:05 +08:00
|
|
|
#include "ARMInstPrinter.h"
|
2009-10-20 04:20:46 +08:00
|
|
|
#include "ARMMachineFunctionInfo.h"
|
|
|
|
#include "ARMMCInstLower.h"
|
|
|
|
#include "ARMTargetMachine.h"
|
2006-05-15 06:18:28 +08:00
|
|
|
#include "llvm/Constants.h"
|
|
|
|
#include "llvm/Module.h"
|
2009-12-28 20:27:56 +08:00
|
|
|
#include "llvm/Type.h"
|
2009-08-13 09:36:44 +08:00
|
|
|
#include "llvm/Assembly/Writer.h"
|
2006-05-15 06:18:28 +08:00
|
|
|
#include "llvm/CodeGen/AsmPrinter.h"
|
2007-01-19 15:51:42 +08:00
|
|
|
#include "llvm/CodeGen/DwarfWriter.h"
|
2009-10-20 02:38:33 +08:00
|
|
|
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
|
2006-05-15 06:18:28 +08:00
|
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
2007-01-19 15:51:42 +08:00
|
|
|
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
2009-10-20 02:38:33 +08:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
|
|
|
#include "llvm/MC/MCContext.h"
|
2009-10-20 04:20:46 +08:00
|
|
|
#include "llvm/MC/MCInst.h"
|
2009-08-11 02:15:01 +08:00
|
|
|
#include "llvm/MC/MCSectionMachO.h"
|
2009-08-19 13:49:37 +08:00
|
|
|
#include "llvm/MC/MCStreamer.h"
|
2009-09-14 01:14:04 +08:00
|
|
|
#include "llvm/MC/MCSymbol.h"
|
2006-07-27 19:38:51 +08:00
|
|
|
#include "llvm/Target/TargetData.h"
|
2009-07-28 11:13:23 +08:00
|
|
|
#include "llvm/Target/TargetLoweringObjectFile.h"
|
2006-05-15 06:18:28 +08:00
|
|
|
#include "llvm/Target/TargetMachine.h"
|
2007-01-20 03:25:36 +08:00
|
|
|
#include "llvm/Target/TargetOptions.h"
|
2009-07-16 04:24:03 +08:00
|
|
|
#include "llvm/Target/TargetRegistry.h"
|
2009-07-25 02:19:46 +08:00
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
2009-09-02 02:49:12 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2006-05-15 06:18:28 +08:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2009-11-07 07:33:28 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2008-12-05 09:06:39 +08:00
|
|
|
#include "llvm/ADT/StringSet.h"
|
2009-10-20 04:20:46 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2009-07-09 04:55:50 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2009-10-20 04:20:46 +08:00
|
|
|
#include "llvm/Support/FormattedStream.h"
|
2006-05-15 06:18:28 +08:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
|
|
|
#include <cctype>
|
|
|
|
using namespace llvm;
|
|
|
|
|
2006-12-20 06:59:26 +08:00
|
|
|
STATISTIC(EmittedInsts, "Number of machine instrs printed");
|
2006-05-15 06:18:28 +08:00
|
|
|
|
2009-10-20 04:20:46 +08:00
|
|
|
static cl::opt<bool>
|
|
|
|
EnableMCInst("enable-arm-mcinst-printer", cl::Hidden,
|
|
|
|
cl::desc("enable experimental asmprinter gunk in the arm backend"));
|
|
|
|
|
2006-12-20 06:59:26 +08:00
|
|
|
namespace {
|
2009-10-20 01:59:19 +08:00
|
|
|
class ARMAsmPrinter : public AsmPrinter {
|
2007-01-19 15:51:42 +08:00
|
|
|
|
|
|
|
/// Subtarget - Keep a pointer to the ARMSubtarget around so that we can
|
|
|
|
/// make the right decision when printing asm code for different targets.
|
|
|
|
const ARMSubtarget *Subtarget;
|
|
|
|
|
|
|
|
/// AFI - Keep a pointer to ARMFunctionInfo for the current
|
2008-09-18 15:27:23 +08:00
|
|
|
/// MachineFunction.
|
2007-01-19 15:51:42 +08:00
|
|
|
ARMFunctionInfo *AFI;
|
|
|
|
|
2008-09-18 15:27:23 +08:00
|
|
|
/// MCP - Keep a pointer to constantpool entries of the current
|
|
|
|
/// MachineFunction.
|
|
|
|
const MachineConstantPool *MCP;
|
|
|
|
|
2009-02-24 16:30:20 +08:00
|
|
|
public:
|
2009-07-15 04:18:05 +08:00
|
|
|
explicit ARMAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
|
2009-08-23 04:48:53 +08:00
|
|
|
const MCAsmInfo *T, bool V)
|
2009-10-20 02:08:02 +08:00
|
|
|
: AsmPrinter(O, TM, T, V), AFI(NULL), MCP(NULL) {
|
2009-02-24 16:30:20 +08:00
|
|
|
Subtarget = &TM.getSubtarget<ARMSubtarget>();
|
|
|
|
}
|
|
|
|
|
2006-05-15 06:18:28 +08:00
|
|
|
virtual const char *getPassName() const {
|
|
|
|
return "ARM Assembly Printer";
|
|
|
|
}
|
2009-10-20 03:59:05 +08:00
|
|
|
|
|
|
|
void printMCInst(const MCInst *MI) {
|
2009-10-20 05:21:39 +08:00
|
|
|
ARMInstPrinter(O, *MAI, VerboseAsm).printInstruction(MI);
|
2009-10-20 04:20:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void printInstructionThroughMCStreamer(const MachineInstr *MI);
|
|
|
|
|
2006-05-15 06:18:28 +08:00
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
void printOperand(const MachineInstr *MI, int OpNum,
|
2007-01-19 15:51:42 +08:00
|
|
|
const char *Modifier = 0);
|
2009-06-29 15:51:04 +08:00
|
|
|
void printSOImmOperand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printSOImm2PartOperand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printSORegOperand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printAddrMode2Operand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printAddrMode2OffsetOperand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printAddrMode3Operand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printAddrMode3OffsetOperand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printAddrMode4Operand(const MachineInstr *MI, int OpNum,
|
2007-01-19 15:51:42 +08:00
|
|
|
const char *Modifier = 0);
|
2009-06-29 15:51:04 +08:00
|
|
|
void printAddrMode5Operand(const MachineInstr *MI, int OpNum,
|
2007-01-19 15:51:42 +08:00
|
|
|
const char *Modifier = 0);
|
2009-07-02 07:16:05 +08:00
|
|
|
void printAddrMode6Operand(const MachineInstr *MI, int OpNum);
|
2009-06-29 15:51:04 +08:00
|
|
|
void printAddrModePCOperand(const MachineInstr *MI, int OpNum,
|
2007-01-19 15:51:42 +08:00
|
|
|
const char *Modifier = 0);
|
2009-06-29 15:51:04 +08:00
|
|
|
void printBitfieldInvMaskImmOperand (const MachineInstr *MI, int OpNum);
|
2009-06-27 10:26:13 +08:00
|
|
|
|
2009-11-19 14:57:41 +08:00
|
|
|
void printThumbS4ImmOperand(const MachineInstr *MI, int OpNum);
|
2009-07-10 07:43:36 +08:00
|
|
|
void printThumbITMask(const MachineInstr *MI, int OpNum);
|
2009-06-29 15:51:04 +08:00
|
|
|
void printThumbAddrModeRROperand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printThumbAddrModeRI5Operand(const MachineInstr *MI, int OpNum,
|
2007-01-19 15:51:42 +08:00
|
|
|
unsigned Scale);
|
2009-06-29 15:51:04 +08:00
|
|
|
void printThumbAddrModeS1Operand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printThumbAddrModeS2Operand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printThumbAddrModeS4Operand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printThumbAddrModeSPOperand(const MachineInstr *MI, int OpNum);
|
2009-06-27 10:26:13 +08:00
|
|
|
|
|
|
|
void printT2SOOperand(const MachineInstr *MI, int OpNum);
|
2009-06-29 15:51:04 +08:00
|
|
|
void printT2AddrModeImm12Operand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum);
|
2009-07-10 06:21:59 +08:00
|
|
|
void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum);
|
2009-07-02 15:28:31 +08:00
|
|
|
void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum);
|
2009-06-29 15:51:04 +08:00
|
|
|
void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum);
|
|
|
|
|
|
|
|
void printPredicateOperand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printSBitModifierOperand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printPCLabel(const MachineInstr *MI, int OpNum);
|
|
|
|
void printRegisterList(const MachineInstr *MI, int OpNum);
|
|
|
|
void printCPInstOperand(const MachineInstr *MI, int OpNum,
|
2007-01-19 15:51:42 +08:00
|
|
|
const char *Modifier);
|
2009-06-29 15:51:04 +08:00
|
|
|
void printJTBlockOperand(const MachineInstr *MI, int OpNum);
|
Change Thumb2 jumptable codegen to one that uses two level jumps:
Before:
adr r12, #LJTI3_0_0
ldr pc, [r12, +r0, lsl #2]
LJTI3_0_0:
.long LBB3_24
.long LBB3_30
.long LBB3_31
.long LBB3_32
After:
adr r12, #LJTI3_0_0
add pc, r12, +r0, lsl #2
LJTI3_0_0:
b.w LBB3_24
b.w LBB3_30
b.w LBB3_31
b.w LBB3_32
This has several advantages.
1. This will make it easier to optimize this to a TBB / TBH instruction +
(smaller) table.
2. This eliminate the need for ugly asm printer hack to force the address
into thumb addresses (bit 0 is one).
3. Same codegen for pic and non-pic.
4. This eliminate the need to align the table so constantpool island pass
won't have to over-estimate the size.
Based on my calculation, the later is probably slightly faster as well since
ldr pc with shifter address is very slow. That is, it should be a win as long
as the HW implementation can do a reasonable job of branch predict the second
branch.
llvm-svn: 77024
2009-07-25 08:33:29 +08:00
|
|
|
void printJT2BlockOperand(const MachineInstr *MI, int OpNum);
|
2009-07-29 10:18:14 +08:00
|
|
|
void printTBAddrMode(const MachineInstr *MI, int OpNum);
|
2009-08-22 05:58:55 +08:00
|
|
|
void printNoHashImmediate(const MachineInstr *MI, int OpNum);
|
2009-10-28 09:44:26 +08:00
|
|
|
void printVFPf32ImmOperand(const MachineInstr *MI, int OpNum);
|
|
|
|
void printVFPf64ImmOperand(const MachineInstr *MI, int OpNum);
|
2007-01-19 15:51:42 +08:00
|
|
|
|
2009-11-07 07:33:28 +08:00
|
|
|
void printHex8ImmOperand(const MachineInstr *MI, int OpNum) {
|
|
|
|
O << "#0x" << utohexstr(MI->getOperand(OpNum).getImm() & 0xff);
|
|
|
|
}
|
|
|
|
void printHex16ImmOperand(const MachineInstr *MI, int OpNum) {
|
|
|
|
O << "#0x" << utohexstr(MI->getOperand(OpNum).getImm() & 0xffff);
|
|
|
|
}
|
|
|
|
void printHex32ImmOperand(const MachineInstr *MI, int OpNum) {
|
|
|
|
O << "#0x" << utohexstr(MI->getOperand(OpNum).getImm() & 0xffffffff);
|
|
|
|
}
|
|
|
|
void printHex64ImmOperand(const MachineInstr *MI, int OpNum) {
|
|
|
|
O << "#0x" << utohexstr(MI->getOperand(OpNum).getImm());
|
|
|
|
}
|
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
|
2007-01-19 15:51:42 +08:00
|
|
|
unsigned AsmVariant, const char *ExtraCode);
|
2009-06-29 15:51:04 +08:00
|
|
|
virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
|
2009-05-19 13:53:42 +08:00
|
|
|
unsigned AsmVariant,
|
|
|
|
const char *ExtraCode);
|
2006-05-15 06:18:28 +08:00
|
|
|
|
2009-08-08 09:32:19 +08:00
|
|
|
void printInstruction(const MachineInstr *MI); // autogenerated.
|
2009-09-14 04:19:22 +08:00
|
|
|
static const char *getRegisterName(unsigned RegNo);
|
2009-09-14 04:08:00 +08:00
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
void printMachineInstruction(const MachineInstr *MI);
|
2006-05-15 06:18:28 +08:00
|
|
|
bool runOnMachineFunction(MachineFunction &F);
|
2009-10-01 06:06:26 +08:00
|
|
|
void EmitStartOfAsmFile(Module &M);
|
2009-10-20 01:59:19 +08:00
|
|
|
void EmitEndOfAsmFile(Module &M);
|
2007-01-19 15:51:42 +08:00
|
|
|
|
2008-08-08 14:56:16 +08:00
|
|
|
/// EmitMachineConstantPoolValue - Print a machine constantpool value to
|
|
|
|
/// the .s file.
|
2007-01-19 15:51:42 +08:00
|
|
|
virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) {
|
|
|
|
printDataDirective(MCPV->getType());
|
|
|
|
|
2008-08-08 14:56:16 +08:00
|
|
|
ARMConstantPoolValue *ACPV = static_cast<ARMConstantPoolValue*>(MCPV);
|
2010-01-13 14:38:18 +08:00
|
|
|
SmallString<128> TmpNameStr;
|
2009-09-01 09:57:56 +08:00
|
|
|
|
|
|
|
if (ACPV->isLSDA()) {
|
2010-01-13 14:38:18 +08:00
|
|
|
raw_svector_ostream(TmpNameStr) << MAI->getPrivateGlobalPrefix() <<
|
2009-09-02 02:49:12 +08:00
|
|
|
"_LSDA_" << getFunctionNumber();
|
2010-01-13 14:38:18 +08:00
|
|
|
O << TmpNameStr.str();
|
2009-11-03 00:59:06 +08:00
|
|
|
} else if (ACPV->isBlockAddress()) {
|
2010-01-13 14:38:18 +08:00
|
|
|
O << GetBlockAddressSymbol(ACPV->getBlockAddress())->getName();
|
2009-11-03 00:59:06 +08:00
|
|
|
} else if (ACPV->isGlobalValue()) {
|
|
|
|
GlobalValue *GV = ACPV->getGV();
|
2009-08-29 07:18:09 +08:00
|
|
|
bool isIndirect = Subtarget->isTargetDarwin() &&
|
2009-09-03 15:04:02 +08:00
|
|
|
Subtarget->GVIsIndirectSymbol(GV, TM.getRelocationModel());
|
2009-08-29 07:18:09 +08:00
|
|
|
if (!isIndirect)
|
2010-01-18 05:43:43 +08:00
|
|
|
O << *GetGlobalValueSymbol(GV);
|
2009-08-29 07:18:09 +08:00
|
|
|
else {
|
|
|
|
// FIXME: Remove this when Darwin transition to @GOT like syntax.
|
2010-01-17 02:37:32 +08:00
|
|
|
MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");
|
2010-01-18 05:43:43 +08:00
|
|
|
O << *Sym;
|
2009-10-20 02:49:14 +08:00
|
|
|
|
|
|
|
MachineModuleInfoMachO &MMIMachO =
|
|
|
|
MMI->getObjFileInfo<MachineModuleInfoMachO>();
|
|
|
|
const MCSymbol *&StubSym =
|
|
|
|
GV->hasHiddenVisibility() ? MMIMachO.getHiddenGVStubEntry(Sym) :
|
|
|
|
MMIMachO.getGVStubEntry(Sym);
|
2010-01-16 07:26:49 +08:00
|
|
|
if (StubSym == 0)
|
2010-01-16 07:18:17 +08:00
|
|
|
StubSym = GetGlobalValueSymbol(GV);
|
2009-08-29 07:18:09 +08:00
|
|
|
}
|
2009-11-03 00:59:06 +08:00
|
|
|
} else {
|
|
|
|
assert(ACPV->isExtSymbol() && "unrecognized constant pool value");
|
2010-01-18 05:43:43 +08:00
|
|
|
O << *GetExternalSymbolSymbol(ACPV->getSymbol());
|
2009-11-03 00:59:06 +08:00
|
|
|
}
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2007-04-22 08:04:12 +08:00
|
|
|
if (ACPV->hasModifier()) O << "(" << ACPV->getModifier() << ")";
|
2007-04-27 21:54:47 +08:00
|
|
|
if (ACPV->getPCAdjustment() != 0) {
|
2009-08-23 05:43:10 +08:00
|
|
|
O << "-(" << MAI->getPrivateGlobalPrefix() << "PC"
|
2009-11-07 06:24:13 +08:00
|
|
|
<< getFunctionNumber() << "_" << ACPV->getLabelId()
|
2007-04-27 21:54:47 +08:00
|
|
|
<< "+" << (unsigned)ACPV->getPCAdjustment();
|
|
|
|
if (ACPV->mustAddCurrentAddress())
|
|
|
|
O << "-.";
|
2010-01-16 07:26:49 +08:00
|
|
|
O << ')';
|
2007-04-27 21:54:47 +08:00
|
|
|
}
|
2010-01-16 07:26:49 +08:00
|
|
|
O << '\n';
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const {
|
2007-09-30 21:39:29 +08:00
|
|
|
AsmPrinter::getAnalysisUsage(AU);
|
2007-01-19 15:51:42 +08:00
|
|
|
AU.setPreservesAll();
|
2007-01-27 05:22:28 +08:00
|
|
|
AU.addRequired<MachineModuleInfo>();
|
2009-01-09 07:40:34 +08:00
|
|
|
AU.addRequired<DwarfWriter>();
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
2006-05-15 06:18:28 +08:00
|
|
|
};
|
|
|
|
} // end of anonymous namespace
|
|
|
|
|
|
|
|
#include "ARMGenAsmWriter.inc"
|
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
/// runOnMachineFunction - This uses the printInstruction()
|
2006-05-15 06:18:28 +08:00
|
|
|
/// method to print assembly for each instruction.
|
|
|
|
///
|
|
|
|
bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
|
2009-02-24 16:30:20 +08:00
|
|
|
this->MF = &MF;
|
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
AFI = MF.getInfo<ARMFunctionInfo>();
|
2008-09-18 15:27:23 +08:00
|
|
|
MCP = MF.getConstantPool();
|
2007-01-19 15:51:42 +08:00
|
|
|
|
|
|
|
SetupMachineFunction(MF);
|
|
|
|
O << "\n";
|
|
|
|
|
|
|
|
// NOTE: we don't print out constant pools here, they are handled as
|
|
|
|
// instructions.
|
2006-05-23 10:48:20 +08:00
|
|
|
|
2009-08-04 06:32:50 +08:00
|
|
|
O << '\n';
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2006-05-23 10:48:20 +08:00
|
|
|
// Print out labels for the function.
|
|
|
|
const Function *F = MF.getFunction();
|
2009-08-19 13:49:37 +08:00
|
|
|
OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
|
2009-08-04 06:32:50 +08:00
|
|
|
|
2006-05-23 10:48:20 +08:00
|
|
|
switch (F->getLinkage()) {
|
2009-07-15 00:55:14 +08:00
|
|
|
default: llvm_unreachable("Unknown linkage type!");
|
2009-01-16 04:18:42 +08:00
|
|
|
case Function::PrivateLinkage:
|
2006-05-23 10:48:20 +08:00
|
|
|
case Function::InternalLinkage:
|
|
|
|
break;
|
|
|
|
case Function::ExternalLinkage:
|
2010-01-18 05:43:43 +08:00
|
|
|
O << "\t.globl\t" << *CurrentFnSym << "\n";
|
2006-05-23 10:48:20 +08:00
|
|
|
break;
|
2009-08-24 09:03:42 +08:00
|
|
|
case Function::LinkerPrivateLinkage:
|
Introduce new linkage types linkonce_odr, weak_odr, common_odr
and extern_weak_odr. These are the same as the non-odr versions,
except that they indicate that the global will only be overridden
by an *equivalent* global. In C, a function with weak linkage can
be overridden by a function which behaves completely differently.
This means that IP passes have to skip weak functions, since any
deductions made from the function definition might be wrong, since
the definition could be replaced by something completely different
at link time. This is not allowed in C++, thanks to the ODR
(One-Definition-Rule): if a function is replaced by another at
link-time, then the new function must be the same as the original
function. If a language knows that a function or other global can
only be overridden by an equivalent global, it can give it the
weak_odr linkage type, and the optimizers will understand that it
is alright to make deductions based on the function body. The
code generators on the other hand map weak and weak_odr linkage
to the same thing.
llvm-svn: 66339
2009-03-07 23:45:40 +08:00
|
|
|
case Function::WeakAnyLinkage:
|
|
|
|
case Function::WeakODRLinkage:
|
|
|
|
case Function::LinkOnceAnyLinkage:
|
|
|
|
case Function::LinkOnceODRLinkage:
|
2007-01-20 03:25:36 +08:00
|
|
|
if (Subtarget->isTargetDarwin()) {
|
2010-01-18 05:43:43 +08:00
|
|
|
O << "\t.globl\t" << *CurrentFnSym << "\n";
|
|
|
|
O << "\t.weak_definition\t" << *CurrentFnSym << "\n";
|
2007-01-19 15:51:42 +08:00
|
|
|
} else {
|
2010-01-18 05:43:43 +08:00
|
|
|
O << MAI->getWeakRefDirective() << *CurrentFnSym << "\n";
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
2006-05-23 10:48:20 +08:00
|
|
|
break;
|
|
|
|
}
|
2007-01-19 15:51:42 +08:00
|
|
|
|
2010-01-16 08:21:18 +08:00
|
|
|
printVisibility(CurrentFnSym, F->getVisibility());
|
2007-03-29 15:49:34 +08:00
|
|
|
|
2009-10-02 14:57:25 +08:00
|
|
|
unsigned FnAlign = 1 << MF.getAlignment(); // MF alignment is log2.
|
2007-01-19 15:51:42 +08:00
|
|
|
if (AFI->isThumbFunction()) {
|
2009-10-02 14:57:25 +08:00
|
|
|
EmitAlignment(FnAlign, F, AFI->getAlign());
|
2007-01-19 15:51:42 +08:00
|
|
|
O << "\t.code\t16\n";
|
2007-02-02 02:25:34 +08:00
|
|
|
O << "\t.thumb_func";
|
2010-01-18 05:43:43 +08:00
|
|
|
if (Subtarget->isTargetDarwin())
|
|
|
|
O << "\t" << *CurrentFnSym;
|
2007-02-02 02:25:34 +08:00
|
|
|
O << "\n";
|
2009-07-01 06:38:32 +08:00
|
|
|
} else {
|
2009-10-02 14:57:25 +08:00
|
|
|
EmitAlignment(FnAlign, F);
|
2009-07-01 06:38:32 +08:00
|
|
|
}
|
2007-01-19 15:51:42 +08:00
|
|
|
|
2010-01-18 05:43:43 +08:00
|
|
|
O << *CurrentFnSym << ":\n";
|
2007-05-04 04:28:35 +08:00
|
|
|
// Emit pre-function debug information.
|
2009-01-09 07:40:34 +08:00
|
|
|
DW->BeginFunction(&MF);
|
2006-05-23 10:48:20 +08:00
|
|
|
|
2008-01-28 17:15:03 +08:00
|
|
|
if (Subtarget->isTargetDarwin()) {
|
|
|
|
// If the function is empty, then we need to emit *something*. Otherwise,
|
|
|
|
// the function's label might be associated with something that it wasn't
|
|
|
|
// meant to be associated with. We emit a noop in this situation.
|
|
|
|
MachineFunction::iterator I = MF.begin();
|
|
|
|
|
|
|
|
if (++I == MF.end() && MF.front().empty())
|
|
|
|
O << "\tnop\n";
|
|
|
|
}
|
|
|
|
|
2006-05-23 10:48:20 +08:00
|
|
|
// Print out code for the function.
|
|
|
|
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
// Print a label for the basic block.
|
2009-10-20 04:20:46 +08:00
|
|
|
if (I != MF.begin())
|
2009-09-14 02:25:37 +08:00
|
|
|
EmitBasicBlockStart(I);
|
2009-10-20 04:20:46 +08:00
|
|
|
|
|
|
|
// Print the assembly for the instruction.
|
2006-05-23 10:48:20 +08:00
|
|
|
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
|
2009-10-20 04:20:46 +08:00
|
|
|
II != E; ++II)
|
2007-01-19 15:51:42 +08:00
|
|
|
printMachineInstruction(II);
|
2006-09-12 01:25:40 +08:00
|
|
|
}
|
|
|
|
|
2010-01-18 05:43:43 +08:00
|
|
|
if (MAI->hasDotTypeDotSizeDirective())
|
|
|
|
O << "\t.size " << *CurrentFnSym << ", .-" << *CurrentFnSym << "\n";
|
2006-11-09 01:07:32 +08:00
|
|
|
|
2007-05-04 04:28:35 +08:00
|
|
|
// Emit post-function debug information.
|
2009-01-09 07:40:34 +08:00
|
|
|
DW->EndFunction(&MF);
|
2006-10-18 02:04:53 +08:00
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
return false;
|
2006-10-18 02:04:53 +08:00
|
|
|
}
|
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
|
2007-01-19 15:51:42 +08:00
|
|
|
const char *Modifier) {
|
2009-06-29 15:51:04 +08:00
|
|
|
const MachineOperand &MO = MI->getOperand(OpNum);
|
2009-11-24 08:44:37 +08:00
|
|
|
unsigned TF = MO.getTargetFlags();
|
|
|
|
|
2006-05-25 20:57:06 +08:00
|
|
|
switch (MO.getType()) {
|
2009-10-20 04:59:55 +08:00
|
|
|
default:
|
|
|
|
assert(0 && "<unknown operand type>");
|
2009-06-23 07:27:02 +08:00
|
|
|
case MachineOperand::MO_Register: {
|
|
|
|
unsigned Reg = MO.getReg();
|
2009-10-20 04:59:55 +08:00
|
|
|
assert(TargetRegisterInfo::isPhysicalRegister(Reg));
|
|
|
|
if (Modifier && strcmp(Modifier, "dregpair") == 0) {
|
|
|
|
unsigned DRegLo = TRI->getSubReg(Reg, 5); // arm_dsubreg_0
|
|
|
|
unsigned DRegHi = TRI->getSubReg(Reg, 6); // arm_dsubreg_1
|
|
|
|
O << '{'
|
|
|
|
<< getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi)
|
|
|
|
<< '}';
|
|
|
|
} else if (Modifier && strcmp(Modifier, "lane") == 0) {
|
|
|
|
unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg);
|
|
|
|
unsigned DReg = TRI->getMatchingSuperReg(Reg, RegNum & 1 ? 2 : 1,
|
|
|
|
&ARM::DPR_VFP2RegClass);
|
|
|
|
O << getRegisterName(DReg) << '[' << (RegNum & 1) << ']';
|
|
|
|
} else {
|
2009-11-07 23:20:32 +08:00
|
|
|
assert(!MO.getSubReg() && "Subregs should be eliminated!");
|
2009-10-20 04:59:55 +08:00
|
|
|
O << getRegisterName(Reg);
|
|
|
|
}
|
2006-05-25 20:57:06 +08:00
|
|
|
break;
|
2009-06-23 07:27:02 +08:00
|
|
|
}
|
2007-01-19 15:51:42 +08:00
|
|
|
case MachineOperand::MO_Immediate: {
|
2009-09-28 17:14:39 +08:00
|
|
|
int64_t Imm = MO.getImm();
|
2009-10-09 04:43:22 +08:00
|
|
|
O << '#';
|
2009-11-24 08:44:37 +08:00
|
|
|
if ((Modifier && strcmp(Modifier, "lo16") == 0) ||
|
|
|
|
(TF & ARMII::MO_LO16))
|
|
|
|
O << ":lower16:";
|
|
|
|
else if ((Modifier && strcmp(Modifier, "hi16") == 0) ||
|
|
|
|
(TF & ARMII::MO_HI16))
|
|
|
|
O << ":upper16:";
|
2009-10-09 04:43:22 +08:00
|
|
|
O << Imm;
|
2006-05-25 20:57:06 +08:00
|
|
|
break;
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
2006-05-25 20:57:06 +08:00
|
|
|
case MachineOperand::MO_MachineBasicBlock:
|
2010-01-18 05:43:43 +08:00
|
|
|
O << *GetMBBSymbol(MO.getMBB()->getNumber());
|
2006-05-25 20:57:06 +08:00
|
|
|
return;
|
2006-07-16 09:02:57 +08:00
|
|
|
case MachineOperand::MO_GlobalAddress: {
|
2007-01-19 15:51:42 +08:00
|
|
|
bool isCallOp = Modifier && !strcmp(Modifier, "call");
|
2006-07-16 09:02:57 +08:00
|
|
|
GlobalValue *GV = MO.getGlobal();
|
2009-11-24 08:44:37 +08:00
|
|
|
|
|
|
|
if ((Modifier && strcmp(Modifier, "lo16") == 0) ||
|
|
|
|
(TF & ARMII::MO_LO16))
|
|
|
|
O << ":lower16:";
|
|
|
|
else if ((Modifier && strcmp(Modifier, "hi16") == 0) ||
|
|
|
|
(TF & ARMII::MO_HI16))
|
|
|
|
O << ":upper16:";
|
2010-01-18 05:43:43 +08:00
|
|
|
O << *GetGlobalValueSymbol(GV);
|
2008-11-23 00:15:34 +08:00
|
|
|
|
|
|
|
printOffset(MO.getOffset());
|
|
|
|
|
2007-04-22 08:04:12 +08:00
|
|
|
if (isCallOp && Subtarget->isTargetELF() &&
|
|
|
|
TM.getRelocationModel() == Reloc::PIC_)
|
|
|
|
O << "(PLT)";
|
2006-05-25 20:57:06 +08:00
|
|
|
break;
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
|
|
|
case MachineOperand::MO_ExternalSymbol: {
|
|
|
|
bool isCallOp = Modifier && !strcmp(Modifier, "call");
|
2010-01-18 05:43:43 +08:00
|
|
|
O << *GetExternalSymbolSymbol(MO.getSymbolName());
|
2010-01-13 16:08:33 +08:00
|
|
|
|
2007-04-22 08:04:12 +08:00
|
|
|
if (isCallOp && Subtarget->isTargetELF() &&
|
|
|
|
TM.getRelocationModel() == Reloc::PIC_)
|
|
|
|
O << "(PLT)";
|
2006-05-25 20:57:06 +08:00
|
|
|
break;
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
2006-05-25 20:57:06 +08:00
|
|
|
case MachineOperand::MO_ConstantPoolIndex:
|
2009-08-23 05:43:10 +08:00
|
|
|
O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
|
2007-12-31 07:10:15 +08:00
|
|
|
<< '_' << MO.getIndex();
|
2006-05-25 20:57:06 +08:00
|
|
|
break;
|
2007-01-19 15:51:42 +08:00
|
|
|
case MachineOperand::MO_JumpTableIndex:
|
2009-08-23 05:43:10 +08:00
|
|
|
O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
|
2007-12-31 07:10:15 +08:00
|
|
|
<< '_' << MO.getIndex();
|
2007-01-19 15:51:42 +08:00
|
|
|
break;
|
2006-05-25 20:57:06 +08:00
|
|
|
}
|
2006-05-15 06:18:28 +08:00
|
|
|
}
|
|
|
|
|
2009-07-15 04:18:05 +08:00
|
|
|
static void printSOImm(formatted_raw_ostream &O, int64_t V, bool VerboseAsm,
|
2009-08-23 05:43:10 +08:00
|
|
|
const MCAsmInfo *MAI) {
|
2009-07-09 05:03:57 +08:00
|
|
|
// Break it up into two parts that make up a shifter immediate.
|
|
|
|
V = ARM_AM::getSOImmVal(V);
|
|
|
|
assert(V != -1 && "Not a valid so_imm value!");
|
|
|
|
|
2007-03-20 16:11:30 +08:00
|
|
|
unsigned Imm = ARM_AM::getSOImmValImm(V);
|
|
|
|
unsigned Rot = ARM_AM::getSOImmValRot(V);
|
2008-11-23 00:15:34 +08:00
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
// Print low-level immediate formation info, per
|
|
|
|
// A5.1.3: "Data-processing operands - Immediate".
|
|
|
|
if (Rot) {
|
|
|
|
O << "#" << Imm << ", " << Rot;
|
|
|
|
// Pretty printed version.
|
2009-10-28 09:44:26 +08:00
|
|
|
if (VerboseAsm) {
|
|
|
|
O.PadToColumn(MAI->getCommentColumn());
|
|
|
|
O << MAI->getCommentString() << ' ';
|
|
|
|
O << (int)ARM_AM::rotr32(Imm, Rot);
|
|
|
|
}
|
2007-01-19 15:51:42 +08:00
|
|
|
} else {
|
|
|
|
O << "#" << Imm;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-20 16:11:30 +08:00
|
|
|
/// printSOImmOperand - SOImm is 4-bit rotate amount in bits 8-11 with 8-bit
|
|
|
|
/// immediate in bits 0-7.
|
|
|
|
void ARMAsmPrinter::printSOImmOperand(const MachineInstr *MI, int OpNum) {
|
|
|
|
const MachineOperand &MO = MI->getOperand(OpNum);
|
2008-10-03 23:45:36 +08:00
|
|
|
assert(MO.isImm() && "Not a valid so_imm value!");
|
2009-08-23 05:43:10 +08:00
|
|
|
printSOImm(O, MO.getImm(), VerboseAsm, MAI);
|
2007-03-20 16:11:30 +08:00
|
|
|
}
|
|
|
|
|
2008-11-06 10:25:39 +08:00
|
|
|
/// printSOImm2PartOperand - SOImm is broken into two pieces using a 'mov'
|
|
|
|
/// followed by an 'orr' to materialize.
|
2007-03-20 16:11:30 +08:00
|
|
|
void ARMAsmPrinter::printSOImm2PartOperand(const MachineInstr *MI, int OpNum) {
|
|
|
|
const MachineOperand &MO = MI->getOperand(OpNum);
|
2008-10-03 23:45:36 +08:00
|
|
|
assert(MO.isImm() && "Not a valid so_imm value!");
|
2007-12-31 04:49:49 +08:00
|
|
|
unsigned V1 = ARM_AM::getSOImmTwoPartFirst(MO.getImm());
|
|
|
|
unsigned V2 = ARM_AM::getSOImmTwoPartSecond(MO.getImm());
|
2009-08-23 05:43:10 +08:00
|
|
|
printSOImm(O, V1, VerboseAsm, MAI);
|
2007-06-06 02:55:18 +08:00
|
|
|
O << "\n\torr";
|
|
|
|
printPredicateOperand(MI, 2);
|
2009-10-27 07:45:59 +08:00
|
|
|
O << "\t";
|
2009-09-04 09:38:51 +08:00
|
|
|
printOperand(MI, 0);
|
2007-03-20 16:11:30 +08:00
|
|
|
O << ", ";
|
2009-09-04 09:38:51 +08:00
|
|
|
printOperand(MI, 0);
|
2007-03-20 16:11:30 +08:00
|
|
|
O << ", ";
|
2009-08-23 05:43:10 +08:00
|
|
|
printSOImm(O, V2, VerboseAsm, MAI);
|
2007-03-20 16:11:30 +08:00
|
|
|
}
|
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
// so_reg is a 4-operand unit corresponding to register forms of the A5.1
|
|
|
|
// "Addressing Mode 1 - Data-processing operands" forms. This includes:
|
2009-06-27 10:26:13 +08:00
|
|
|
// REG 0 0 - e.g. R5
|
|
|
|
// REG REG 0,SH_OPC - e.g. R5, ROR R3
|
2007-01-19 15:51:42 +08:00
|
|
|
// REG 0 IMM,SH_OPC - e.g. R5, LSL #3
|
|
|
|
void ARMAsmPrinter::printSORegOperand(const MachineInstr *MI, int Op) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(Op);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(Op+1);
|
|
|
|
const MachineOperand &MO3 = MI->getOperand(Op+2);
|
|
|
|
|
2009-09-14 04:31:40 +08:00
|
|
|
O << getRegisterName(MO1.getReg());
|
2007-01-19 15:51:42 +08:00
|
|
|
|
|
|
|
// Print the shift opc.
|
|
|
|
O << ", "
|
2007-12-31 04:49:49 +08:00
|
|
|
<< ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm()))
|
2007-01-19 15:51:42 +08:00
|
|
|
<< " ";
|
|
|
|
|
|
|
|
if (MO2.getReg()) {
|
2009-09-14 04:31:40 +08:00
|
|
|
O << getRegisterName(MO2.getReg());
|
2007-01-19 15:51:42 +08:00
|
|
|
assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0);
|
|
|
|
} else {
|
|
|
|
O << "#" << ARM_AM::getSORegOffset(MO3.getImm());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ARMAsmPrinter::printAddrMode2Operand(const MachineInstr *MI, int Op) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(Op);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(Op+1);
|
|
|
|
const MachineOperand &MO3 = MI->getOperand(Op+2);
|
|
|
|
|
2008-10-03 23:45:36 +08:00
|
|
|
if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right.
|
2007-01-19 15:51:42 +08:00
|
|
|
printOperand(MI, Op);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-09-14 04:31:40 +08:00
|
|
|
O << "[" << getRegisterName(MO1.getReg());
|
2007-01-19 15:51:42 +08:00
|
|
|
|
|
|
|
if (!MO2.getReg()) {
|
|
|
|
if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0.
|
|
|
|
O << ", #"
|
|
|
|
<< (char)ARM_AM::getAM2Op(MO3.getImm())
|
|
|
|
<< ARM_AM::getAM2Offset(MO3.getImm());
|
|
|
|
O << "]";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
O << ", "
|
|
|
|
<< (char)ARM_AM::getAM2Op(MO3.getImm())
|
2009-09-14 04:31:40 +08:00
|
|
|
<< getRegisterName(MO2.getReg());
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm()))
|
|
|
|
O << ", "
|
2007-12-31 04:49:49 +08:00
|
|
|
<< ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO3.getImm()))
|
2007-01-19 15:51:42 +08:00
|
|
|
<< " #" << ShImm;
|
|
|
|
O << "]";
|
|
|
|
}
|
|
|
|
|
|
|
|
void ARMAsmPrinter::printAddrMode2OffsetOperand(const MachineInstr *MI, int Op){
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(Op);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(Op+1);
|
|
|
|
|
|
|
|
if (!MO1.getReg()) {
|
2007-05-04 07:30:36 +08:00
|
|
|
unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm());
|
|
|
|
assert(ImmOffs && "Malformed indexed load / store!");
|
|
|
|
O << "#"
|
|
|
|
<< (char)ARM_AM::getAM2Op(MO2.getImm())
|
|
|
|
<< ImmOffs;
|
2007-01-19 15:51:42 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
O << (char)ARM_AM::getAM2Op(MO2.getImm())
|
2009-09-14 04:31:40 +08:00
|
|
|
<< getRegisterName(MO1.getReg());
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm()))
|
|
|
|
O << ", "
|
2007-12-31 04:49:49 +08:00
|
|
|
<< ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO2.getImm()))
|
2007-01-19 15:51:42 +08:00
|
|
|
<< " #" << ShImm;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ARMAsmPrinter::printAddrMode3Operand(const MachineInstr *MI, int Op) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(Op);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(Op+1);
|
|
|
|
const MachineOperand &MO3 = MI->getOperand(Op+2);
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2008-02-11 02:45:23 +08:00
|
|
|
assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg()));
|
2009-09-14 04:31:40 +08:00
|
|
|
O << "[" << getRegisterName(MO1.getReg());
|
2007-01-19 15:51:42 +08:00
|
|
|
|
|
|
|
if (MO2.getReg()) {
|
|
|
|
O << ", "
|
|
|
|
<< (char)ARM_AM::getAM3Op(MO3.getImm())
|
2009-09-14 04:31:40 +08:00
|
|
|
<< getRegisterName(MO2.getReg())
|
2007-01-19 15:51:42 +08:00
|
|
|
<< "]";
|
|
|
|
return;
|
|
|
|
}
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm()))
|
|
|
|
O << ", #"
|
|
|
|
<< (char)ARM_AM::getAM3Op(MO3.getImm())
|
|
|
|
<< ImmOffs;
|
|
|
|
O << "]";
|
|
|
|
}
|
|
|
|
|
|
|
|
void ARMAsmPrinter::printAddrMode3OffsetOperand(const MachineInstr *MI, int Op){
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(Op);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(Op+1);
|
|
|
|
|
|
|
|
if (MO1.getReg()) {
|
|
|
|
O << (char)ARM_AM::getAM3Op(MO2.getImm())
|
2009-09-14 04:31:40 +08:00
|
|
|
<< getRegisterName(MO1.getReg());
|
2007-01-19 15:51:42 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm());
|
2007-05-04 07:30:36 +08:00
|
|
|
assert(ImmOffs && "Malformed indexed load / store!");
|
2007-01-19 15:51:42 +08:00
|
|
|
O << "#"
|
2007-05-04 07:30:36 +08:00
|
|
|
<< (char)ARM_AM::getAM3Op(MO2.getImm())
|
2007-01-19 15:51:42 +08:00
|
|
|
<< ImmOffs;
|
|
|
|
}
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
void ARMAsmPrinter::printAddrMode4Operand(const MachineInstr *MI, int Op,
|
|
|
|
const char *Modifier) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(Op);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(Op+1);
|
|
|
|
ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm());
|
|
|
|
if (Modifier && strcmp(Modifier, "submode") == 0) {
|
|
|
|
if (MO1.getReg() == ARM::SP) {
|
2009-08-04 09:43:45 +08:00
|
|
|
// FIXME
|
2007-01-19 15:51:42 +08:00
|
|
|
bool isLDM = (MI->getOpcode() == ARM::LDM ||
|
2009-08-04 09:43:45 +08:00
|
|
|
MI->getOpcode() == ARM::LDM_RET ||
|
2009-08-05 05:12:13 +08:00
|
|
|
MI->getOpcode() == ARM::t2LDM ||
|
2009-08-04 09:43:45 +08:00
|
|
|
MI->getOpcode() == ARM::t2LDM_RET);
|
2007-01-19 15:51:42 +08:00
|
|
|
O << ARM_AM::getAMSubModeAltStr(Mode, isLDM);
|
|
|
|
} else
|
|
|
|
O << ARM_AM::getAMSubModeStr(Mode);
|
2009-08-08 05:19:10 +08:00
|
|
|
} else if (Modifier && strcmp(Modifier, "wide") == 0) {
|
|
|
|
ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm());
|
|
|
|
if (Mode == ARM_AM::ia)
|
|
|
|
O << ".w";
|
2007-01-19 15:51:42 +08:00
|
|
|
} else {
|
|
|
|
printOperand(MI, Op);
|
|
|
|
if (ARM_AM::getAM4WBFlag(MO2.getImm()))
|
|
|
|
O << "!";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ARMAsmPrinter::printAddrMode5Operand(const MachineInstr *MI, int Op,
|
|
|
|
const char *Modifier) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(Op);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(Op+1);
|
|
|
|
|
2008-10-03 23:45:36 +08:00
|
|
|
if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right.
|
2007-01-19 15:51:42 +08:00
|
|
|
printOperand(MI, Op);
|
|
|
|
return;
|
|
|
|
}
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2008-02-11 02:45:23 +08:00
|
|
|
assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg()));
|
2007-01-19 15:51:42 +08:00
|
|
|
|
|
|
|
if (Modifier && strcmp(Modifier, "submode") == 0) {
|
|
|
|
ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MO2.getImm());
|
2009-11-09 08:11:35 +08:00
|
|
|
O << ARM_AM::getAMSubModeStr(Mode);
|
2007-01-19 15:51:42 +08:00
|
|
|
return;
|
|
|
|
} else if (Modifier && strcmp(Modifier, "base") == 0) {
|
|
|
|
// Used for FSTM{D|S} and LSTM{D|S} operations.
|
2009-09-14 04:31:40 +08:00
|
|
|
O << getRegisterName(MO1.getReg());
|
2007-01-19 15:51:42 +08:00
|
|
|
if (ARM_AM::getAM5WBFlag(MO2.getImm()))
|
|
|
|
O << "!";
|
|
|
|
return;
|
|
|
|
}
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2009-09-14 04:31:40 +08:00
|
|
|
O << "[" << getRegisterName(MO1.getReg());
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) {
|
|
|
|
O << ", #"
|
|
|
|
<< (char)ARM_AM::getAM5Op(MO2.getImm())
|
|
|
|
<< ImmOffs*4;
|
|
|
|
}
|
|
|
|
O << "]";
|
|
|
|
}
|
|
|
|
|
2009-07-02 07:16:05 +08:00
|
|
|
void ARMAsmPrinter::printAddrMode6Operand(const MachineInstr *MI, int Op) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(Op);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(Op+1);
|
|
|
|
const MachineOperand &MO3 = MI->getOperand(Op+2);
|
2009-11-08 05:25:39 +08:00
|
|
|
const MachineOperand &MO4 = MI->getOperand(Op+3);
|
2009-07-02 07:16:05 +08:00
|
|
|
|
2009-11-08 05:25:39 +08:00
|
|
|
O << "[" << getRegisterName(MO1.getReg());
|
|
|
|
if (MO4.getImm()) {
|
2009-11-18 04:04:59 +08:00
|
|
|
// FIXME: Both darwin as and GNU as violate ARM docs here.
|
|
|
|
O << ", :" << MO4.getImm();
|
2009-11-08 05:25:39 +08:00
|
|
|
}
|
|
|
|
O << "]";
|
2009-07-02 07:16:05 +08:00
|
|
|
|
|
|
|
if (ARM_AM::getAM6WBFlag(MO3.getImm())) {
|
|
|
|
if (MO2.getReg() == 0)
|
|
|
|
O << "!";
|
|
|
|
else
|
2009-09-14 04:31:40 +08:00
|
|
|
O << ", " << getRegisterName(MO2.getReg());
|
2009-07-02 07:16:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
void ARMAsmPrinter::printAddrModePCOperand(const MachineInstr *MI, int Op,
|
|
|
|
const char *Modifier) {
|
|
|
|
if (Modifier && strcmp(Modifier, "label") == 0) {
|
|
|
|
printPCLabel(MI, Op+1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(Op);
|
2008-02-11 02:45:23 +08:00
|
|
|
assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg()));
|
2009-09-14 04:31:40 +08:00
|
|
|
O << "[pc, +" << getRegisterName(MO1.getReg()) << "]";
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
|
|
|
|
2009-06-24 01:48:47 +08:00
|
|
|
void
|
|
|
|
ARMAsmPrinter::printBitfieldInvMaskImmOperand(const MachineInstr *MI, int Op) {
|
|
|
|
const MachineOperand &MO = MI->getOperand(Op);
|
|
|
|
uint32_t v = ~MO.getImm();
|
2009-06-26 06:04:44 +08:00
|
|
|
int32_t lsb = CountTrailingZeros_32(v);
|
2009-06-24 09:08:42 +08:00
|
|
|
int32_t width = (32 - CountLeadingZeros_32 (v)) - lsb;
|
2009-06-24 01:48:47 +08:00
|
|
|
assert(MO.isImm() && "Not a valid bf_inv_mask_imm value!");
|
|
|
|
O << "#" << lsb << ", #" << width;
|
|
|
|
}
|
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
|
2009-11-19 14:57:41 +08:00
|
|
|
void ARMAsmPrinter::printThumbS4ImmOperand(const MachineInstr *MI, int Op) {
|
|
|
|
O << "#" << MI->getOperand(Op).getImm() * 4;
|
|
|
|
}
|
|
|
|
|
2009-07-10 07:43:36 +08:00
|
|
|
void
|
|
|
|
ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op) {
|
|
|
|
// (3 - the number of trailing zeros) is the number of then / else.
|
|
|
|
unsigned Mask = MI->getOperand(Op).getImm();
|
|
|
|
unsigned NumTZ = CountTrailingZeros_32(Mask);
|
|
|
|
assert(NumTZ <= 3 && "Invalid IT mask!");
|
2009-07-10 09:54:42 +08:00
|
|
|
for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) {
|
2009-08-15 15:59:10 +08:00
|
|
|
bool T = (Mask & (1 << Pos)) == 0;
|
2009-07-10 07:43:36 +08:00
|
|
|
if (T)
|
|
|
|
O << 't';
|
|
|
|
else
|
|
|
|
O << 'e';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
void
|
|
|
|
ARMAsmPrinter::printThumbAddrModeRROperand(const MachineInstr *MI, int Op) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(Op);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(Op+1);
|
2009-09-14 04:31:40 +08:00
|
|
|
O << "[" << getRegisterName(MO1.getReg());
|
|
|
|
O << ", " << getRegisterName(MO2.getReg()) << "]";
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ARMAsmPrinter::printThumbAddrModeRI5Operand(const MachineInstr *MI, int Op,
|
|
|
|
unsigned Scale) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(Op);
|
2007-01-30 10:35:32 +08:00
|
|
|
const MachineOperand &MO2 = MI->getOperand(Op+1);
|
|
|
|
const MachineOperand &MO3 = MI->getOperand(Op+2);
|
2007-01-19 15:51:42 +08:00
|
|
|
|
2008-10-03 23:45:36 +08:00
|
|
|
if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right.
|
2007-01-19 15:51:42 +08:00
|
|
|
printOperand(MI, Op);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-09-14 04:31:40 +08:00
|
|
|
O << "[" << getRegisterName(MO1.getReg());
|
2007-01-30 10:35:32 +08:00
|
|
|
if (MO3.getReg())
|
2009-09-14 04:31:40 +08:00
|
|
|
O << ", " << getRegisterName(MO3.getReg());
|
2009-11-11 03:48:13 +08:00
|
|
|
else if (unsigned ImmOffs = MO2.getImm())
|
2009-11-19 14:31:26 +08:00
|
|
|
O << ", #+" << ImmOffs * Scale;
|
2007-01-19 15:51:42 +08:00
|
|
|
O << "]";
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-01-24 06:59:13 +08:00
|
|
|
ARMAsmPrinter::printThumbAddrModeS1Operand(const MachineInstr *MI, int Op) {
|
2007-01-30 10:35:32 +08:00
|
|
|
printThumbAddrModeRI5Operand(MI, Op, 1);
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
|
|
|
void
|
2007-01-24 06:59:13 +08:00
|
|
|
ARMAsmPrinter::printThumbAddrModeS2Operand(const MachineInstr *MI, int Op) {
|
2007-01-30 10:35:32 +08:00
|
|
|
printThumbAddrModeRI5Operand(MI, Op, 2);
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
|
|
|
void
|
2007-01-24 06:59:13 +08:00
|
|
|
ARMAsmPrinter::printThumbAddrModeS4Operand(const MachineInstr *MI, int Op) {
|
2007-01-30 10:35:32 +08:00
|
|
|
printThumbAddrModeRI5Operand(MI, Op, 4);
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ARMAsmPrinter::printThumbAddrModeSPOperand(const MachineInstr *MI,int Op) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(Op);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(Op+1);
|
2009-09-14 04:31:40 +08:00
|
|
|
O << "[" << getRegisterName(MO1.getReg());
|
2007-01-19 15:51:42 +08:00
|
|
|
if (unsigned ImmOffs = MO2.getImm())
|
2009-11-19 14:31:26 +08:00
|
|
|
O << ", #+" << ImmOffs*4;
|
2007-01-19 15:51:42 +08:00
|
|
|
O << "]";
|
2006-05-15 06:18:28 +08:00
|
|
|
}
|
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
|
2009-06-27 10:26:13 +08:00
|
|
|
// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2
|
|
|
|
// register with shift forms.
|
|
|
|
// REG 0 0 - e.g. R5
|
|
|
|
// REG IMM, SH_OPC - e.g. R5, LSL #3
|
|
|
|
void ARMAsmPrinter::printT2SOOperand(const MachineInstr *MI, int OpNum) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(OpNum);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(OpNum+1);
|
|
|
|
|
|
|
|
unsigned Reg = MO1.getReg();
|
|
|
|
assert(TargetRegisterInfo::isPhysicalRegister(Reg));
|
2009-09-14 04:31:40 +08:00
|
|
|
O << getRegisterName(Reg);
|
2009-06-27 10:26:13 +08:00
|
|
|
|
|
|
|
// Print the shift opc.
|
|
|
|
O << ", "
|
|
|
|
<< ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO2.getImm()))
|
|
|
|
<< " ";
|
|
|
|
|
|
|
|
assert(MO2.isImm() && "Not a valid t2_so_reg value!");
|
|
|
|
O << "#" << ARM_AM::getSORegOffset(MO2.getImm());
|
|
|
|
}
|
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
void ARMAsmPrinter::printT2AddrModeImm12Operand(const MachineInstr *MI,
|
|
|
|
int OpNum) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(OpNum);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(OpNum+1);
|
|
|
|
|
2009-09-14 04:31:40 +08:00
|
|
|
O << "[" << getRegisterName(MO1.getReg());
|
2009-06-29 15:51:04 +08:00
|
|
|
|
|
|
|
unsigned OffImm = MO2.getImm();
|
|
|
|
if (OffImm) // Don't print +0.
|
|
|
|
O << ", #+" << OffImm;
|
|
|
|
O << "]";
|
|
|
|
}
|
|
|
|
|
|
|
|
void ARMAsmPrinter::printT2AddrModeImm8Operand(const MachineInstr *MI,
|
|
|
|
int OpNum) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(OpNum);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(OpNum+1);
|
|
|
|
|
2009-09-14 04:31:40 +08:00
|
|
|
O << "[" << getRegisterName(MO1.getReg());
|
2009-06-29 15:51:04 +08:00
|
|
|
|
|
|
|
int32_t OffImm = (int32_t)MO2.getImm();
|
|
|
|
// Don't print +0.
|
|
|
|
if (OffImm < 0)
|
|
|
|
O << ", #-" << -OffImm;
|
|
|
|
else if (OffImm > 0)
|
|
|
|
O << ", #+" << OffImm;
|
|
|
|
O << "]";
|
|
|
|
}
|
|
|
|
|
2009-07-10 06:21:59 +08:00
|
|
|
void ARMAsmPrinter::printT2AddrModeImm8s4Operand(const MachineInstr *MI,
|
|
|
|
int OpNum) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(OpNum);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(OpNum+1);
|
|
|
|
|
2009-09-14 04:31:40 +08:00
|
|
|
O << "[" << getRegisterName(MO1.getReg());
|
2009-07-10 06:21:59 +08:00
|
|
|
|
|
|
|
int32_t OffImm = (int32_t)MO2.getImm() / 4;
|
|
|
|
// Don't print +0.
|
|
|
|
if (OffImm < 0)
|
2009-11-19 14:31:26 +08:00
|
|
|
O << ", #-" << -OffImm * 4;
|
2009-07-10 06:21:59 +08:00
|
|
|
else if (OffImm > 0)
|
2009-11-19 14:31:26 +08:00
|
|
|
O << ", #+" << OffImm * 4;
|
2009-07-10 06:21:59 +08:00
|
|
|
O << "]";
|
|
|
|
}
|
|
|
|
|
2009-07-02 15:28:31 +08:00
|
|
|
void ARMAsmPrinter::printT2AddrModeImm8OffsetOperand(const MachineInstr *MI,
|
|
|
|
int OpNum) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(OpNum);
|
|
|
|
int32_t OffImm = (int32_t)MO1.getImm();
|
|
|
|
// Don't print +0.
|
|
|
|
if (OffImm < 0)
|
|
|
|
O << "#-" << -OffImm;
|
|
|
|
else if (OffImm > 0)
|
|
|
|
O << "#+" << OffImm;
|
|
|
|
}
|
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI,
|
|
|
|
int OpNum) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(OpNum);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(OpNum+1);
|
|
|
|
const MachineOperand &MO3 = MI->getOperand(OpNum+2);
|
|
|
|
|
2009-09-14 04:31:40 +08:00
|
|
|
O << "[" << getRegisterName(MO1.getReg());
|
2009-06-29 15:51:04 +08:00
|
|
|
|
2009-08-11 16:52:18 +08:00
|
|
|
assert(MO2.getReg() && "Invalid so_reg load / store address!");
|
2009-09-14 04:31:40 +08:00
|
|
|
O << ", " << getRegisterName(MO2.getReg());
|
2009-06-27 10:26:13 +08:00
|
|
|
|
2009-08-11 16:52:18 +08:00
|
|
|
unsigned ShAmt = MO3.getImm();
|
|
|
|
if (ShAmt) {
|
|
|
|
assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!");
|
|
|
|
O << ", lsl #" << ShAmt;
|
2009-06-29 15:51:04 +08:00
|
|
|
}
|
|
|
|
O << "]";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
void ARMAsmPrinter::printPredicateOperand(const MachineInstr *MI, int OpNum) {
|
|
|
|
ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm();
|
2007-05-15 09:29:07 +08:00
|
|
|
if (CC != ARMCC::AL)
|
|
|
|
O << ARMCondCodeToString(CC);
|
2006-05-15 06:18:28 +08:00
|
|
|
}
|
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
void ARMAsmPrinter::printSBitModifierOperand(const MachineInstr *MI, int OpNum){
|
|
|
|
unsigned Reg = MI->getOperand(OpNum).getReg();
|
2007-07-06 09:01:34 +08:00
|
|
|
if (Reg) {
|
|
|
|
assert(Reg == ARM::CPSR && "Expect ARM CPSR register!");
|
|
|
|
O << 's';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
void ARMAsmPrinter::printPCLabel(const MachineInstr *MI, int OpNum) {
|
|
|
|
int Id = (int)MI->getOperand(OpNum).getImm();
|
2009-11-07 06:24:13 +08:00
|
|
|
O << MAI->getPrivateGlobalPrefix()
|
|
|
|
<< "PC" << getFunctionNumber() << "_" << Id;
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
void ARMAsmPrinter::printRegisterList(const MachineInstr *MI, int OpNum) {
|
2007-01-19 15:51:42 +08:00
|
|
|
O << "{";
|
2009-10-01 09:33:39 +08:00
|
|
|
// Always skip the first operand, it's the optional (and implicit writeback).
|
|
|
|
for (unsigned i = OpNum+1, e = MI->getNumOperands(); i != e; ++i) {
|
2009-08-12 05:11:32 +08:00
|
|
|
if (MI->getOperand(i).isImplicit())
|
|
|
|
continue;
|
2009-10-01 09:33:39 +08:00
|
|
|
if ((int)i != OpNum+1) O << ", ";
|
2007-01-19 15:51:42 +08:00
|
|
|
printOperand(MI, i);
|
|
|
|
}
|
|
|
|
O << "}";
|
|
|
|
}
|
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
void ARMAsmPrinter::printCPInstOperand(const MachineInstr *MI, int OpNum,
|
2007-01-19 15:51:42 +08:00
|
|
|
const char *Modifier) {
|
|
|
|
assert(Modifier && "This operand only works with a modifier!");
|
|
|
|
// There are two aspects to a CONSTANTPOOL_ENTRY operand, the label and the
|
|
|
|
// data itself.
|
|
|
|
if (!strcmp(Modifier, "label")) {
|
2009-06-29 15:51:04 +08:00
|
|
|
unsigned ID = MI->getOperand(OpNum).getImm();
|
2009-08-23 05:43:10 +08:00
|
|
|
O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
|
2007-10-14 13:57:21 +08:00
|
|
|
<< '_' << ID << ":\n";
|
2007-01-19 15:51:42 +08:00
|
|
|
} else {
|
|
|
|
assert(!strcmp(Modifier, "cpentry") && "Unknown modifier for CPE");
|
2009-06-29 15:51:04 +08:00
|
|
|
unsigned CPI = MI->getOperand(OpNum).getIndex();
|
2007-01-19 15:51:42 +08:00
|
|
|
|
2008-09-18 15:27:23 +08:00
|
|
|
const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPI];
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2008-08-08 14:56:16 +08:00
|
|
|
if (MCPE.isMachineConstantPoolEntry()) {
|
2007-01-19 15:51:42 +08:00
|
|
|
EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
|
2008-08-08 14:56:16 +08:00
|
|
|
} else {
|
2007-01-19 15:51:42 +08:00
|
|
|
EmitGlobalConstant(MCPE.Val.ConstVal);
|
2007-04-25 22:50:40 +08:00
|
|
|
}
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
void ARMAsmPrinter::printJTBlockOperand(const MachineInstr *MI, int OpNum) {
|
Change Thumb2 jumptable codegen to one that uses two level jumps:
Before:
adr r12, #LJTI3_0_0
ldr pc, [r12, +r0, lsl #2]
LJTI3_0_0:
.long LBB3_24
.long LBB3_30
.long LBB3_31
.long LBB3_32
After:
adr r12, #LJTI3_0_0
add pc, r12, +r0, lsl #2
LJTI3_0_0:
b.w LBB3_24
b.w LBB3_30
b.w LBB3_31
b.w LBB3_32
This has several advantages.
1. This will make it easier to optimize this to a TBB / TBH instruction +
(smaller) table.
2. This eliminate the need for ugly asm printer hack to force the address
into thumb addresses (bit 0 is one).
3. Same codegen for pic and non-pic.
4. This eliminate the need to align the table so constantpool island pass
won't have to over-estimate the size.
Based on my calculation, the later is probably slightly faster as well since
ldr pc with shifter address is very slow. That is, it should be a win as long
as the HW implementation can do a reasonable job of branch predict the second
branch.
llvm-svn: 77024
2009-07-25 08:33:29 +08:00
|
|
|
assert(!Subtarget->isThumb2() && "Thumb2 should use double-jump jumptables!");
|
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
const MachineOperand &MO1 = MI->getOperand(OpNum);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id
|
2007-12-31 07:10:15 +08:00
|
|
|
unsigned JTI = MO1.getIndex();
|
2009-08-23 05:43:10 +08:00
|
|
|
O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
|
2007-12-31 04:49:49 +08:00
|
|
|
<< '_' << JTI << '_' << MO2.getImm() << ":\n";
|
2007-01-19 15:51:42 +08:00
|
|
|
|
2009-08-23 05:43:10 +08:00
|
|
|
const char *JTEntryDirective = MAI->getData32bitsDirective();
|
2007-01-19 15:51:42 +08:00
|
|
|
|
|
|
|
const MachineFunction *MF = MI->getParent()->getParent();
|
2008-07-08 04:06:06 +08:00
|
|
|
const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
|
2007-01-19 15:51:42 +08:00
|
|
|
const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
|
|
|
|
const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
|
2009-08-23 05:43:10 +08:00
|
|
|
bool UseSet= MAI->getSetDirective() && TM.getRelocationModel() == Reloc::PIC_;
|
2009-07-25 02:19:46 +08:00
|
|
|
SmallPtrSet<MachineBasicBlock*, 8> JTSets;
|
2007-01-19 15:51:42 +08:00
|
|
|
for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
|
|
|
|
MachineBasicBlock *MBB = JTBBs[i];
|
Change Thumb2 jumptable codegen to one that uses two level jumps:
Before:
adr r12, #LJTI3_0_0
ldr pc, [r12, +r0, lsl #2]
LJTI3_0_0:
.long LBB3_24
.long LBB3_30
.long LBB3_31
.long LBB3_32
After:
adr r12, #LJTI3_0_0
add pc, r12, +r0, lsl #2
LJTI3_0_0:
b.w LBB3_24
b.w LBB3_30
b.w LBB3_31
b.w LBB3_32
This has several advantages.
1. This will make it easier to optimize this to a TBB / TBH instruction +
(smaller) table.
2. This eliminate the need for ugly asm printer hack to force the address
into thumb addresses (bit 0 is one).
3. Same codegen for pic and non-pic.
4. This eliminate the need to align the table so constantpool island pass
won't have to over-estimate the size.
Based on my calculation, the later is probably slightly faster as well since
ldr pc with shifter address is very slow. That is, it should be a win as long
as the HW implementation can do a reasonable job of branch predict the second
branch.
llvm-svn: 77024
2009-07-25 08:33:29 +08:00
|
|
|
bool isNew = JTSets.insert(MBB);
|
|
|
|
|
|
|
|
if (UseSet && isNew)
|
|
|
|
printPICJumpTableSetLabel(JTI, MO2.getImm(), MBB);
|
2007-01-19 15:51:42 +08:00
|
|
|
|
|
|
|
O << JTEntryDirective << ' ';
|
|
|
|
if (UseSet)
|
2009-08-23 05:43:10 +08:00
|
|
|
O << MAI->getPrivateGlobalPrefix() << getFunctionNumber()
|
2007-12-31 04:49:49 +08:00
|
|
|
<< '_' << JTI << '_' << MO2.getImm()
|
2007-10-14 13:57:21 +08:00
|
|
|
<< "_set_" << MBB->getNumber();
|
2007-01-19 15:51:42 +08:00
|
|
|
else if (TM.getRelocationModel() == Reloc::PIC_) {
|
2010-01-18 05:43:43 +08:00
|
|
|
O << *GetMBBSymbol(MBB->getNumber())
|
|
|
|
<< '-' << MAI->getPrivateGlobalPrefix() << "JTI"
|
2009-08-12 04:30:58 +08:00
|
|
|
<< getFunctionNumber() << '_' << JTI << '_' << MO2.getImm();
|
2009-07-25 02:19:46 +08:00
|
|
|
} else {
|
2010-01-18 05:43:43 +08:00
|
|
|
O << *GetMBBSymbol(MBB->getNumber());
|
2009-07-25 02:19:46 +08:00
|
|
|
}
|
2007-01-27 10:29:45 +08:00
|
|
|
if (i != e-1)
|
|
|
|
O << '\n';
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Change Thumb2 jumptable codegen to one that uses two level jumps:
Before:
adr r12, #LJTI3_0_0
ldr pc, [r12, +r0, lsl #2]
LJTI3_0_0:
.long LBB3_24
.long LBB3_30
.long LBB3_31
.long LBB3_32
After:
adr r12, #LJTI3_0_0
add pc, r12, +r0, lsl #2
LJTI3_0_0:
b.w LBB3_24
b.w LBB3_30
b.w LBB3_31
b.w LBB3_32
This has several advantages.
1. This will make it easier to optimize this to a TBB / TBH instruction +
(smaller) table.
2. This eliminate the need for ugly asm printer hack to force the address
into thumb addresses (bit 0 is one).
3. Same codegen for pic and non-pic.
4. This eliminate the need to align the table so constantpool island pass
won't have to over-estimate the size.
Based on my calculation, the later is probably slightly faster as well since
ldr pc with shifter address is very slow. That is, it should be a win as long
as the HW implementation can do a reasonable job of branch predict the second
branch.
llvm-svn: 77024
2009-07-25 08:33:29 +08:00
|
|
|
void ARMAsmPrinter::printJT2BlockOperand(const MachineInstr *MI, int OpNum) {
|
|
|
|
const MachineOperand &MO1 = MI->getOperand(OpNum);
|
|
|
|
const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id
|
|
|
|
unsigned JTI = MO1.getIndex();
|
2009-08-23 05:43:10 +08:00
|
|
|
O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
|
Change Thumb2 jumptable codegen to one that uses two level jumps:
Before:
adr r12, #LJTI3_0_0
ldr pc, [r12, +r0, lsl #2]
LJTI3_0_0:
.long LBB3_24
.long LBB3_30
.long LBB3_31
.long LBB3_32
After:
adr r12, #LJTI3_0_0
add pc, r12, +r0, lsl #2
LJTI3_0_0:
b.w LBB3_24
b.w LBB3_30
b.w LBB3_31
b.w LBB3_32
This has several advantages.
1. This will make it easier to optimize this to a TBB / TBH instruction +
(smaller) table.
2. This eliminate the need for ugly asm printer hack to force the address
into thumb addresses (bit 0 is one).
3. Same codegen for pic and non-pic.
4. This eliminate the need to align the table so constantpool island pass
won't have to over-estimate the size.
Based on my calculation, the later is probably slightly faster as well since
ldr pc with shifter address is very slow. That is, it should be a win as long
as the HW implementation can do a reasonable job of branch predict the second
branch.
llvm-svn: 77024
2009-07-25 08:33:29 +08:00
|
|
|
<< '_' << JTI << '_' << MO2.getImm() << ":\n";
|
|
|
|
|
|
|
|
const MachineFunction *MF = MI->getParent()->getParent();
|
|
|
|
const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
|
|
|
|
const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
|
|
|
|
const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
|
2009-07-29 10:18:14 +08:00
|
|
|
bool ByteOffset = false, HalfWordOffset = false;
|
|
|
|
if (MI->getOpcode() == ARM::t2TBB)
|
|
|
|
ByteOffset = true;
|
|
|
|
else if (MI->getOpcode() == ARM::t2TBH)
|
|
|
|
HalfWordOffset = true;
|
|
|
|
|
Change Thumb2 jumptable codegen to one that uses two level jumps:
Before:
adr r12, #LJTI3_0_0
ldr pc, [r12, +r0, lsl #2]
LJTI3_0_0:
.long LBB3_24
.long LBB3_30
.long LBB3_31
.long LBB3_32
After:
adr r12, #LJTI3_0_0
add pc, r12, +r0, lsl #2
LJTI3_0_0:
b.w LBB3_24
b.w LBB3_30
b.w LBB3_31
b.w LBB3_32
This has several advantages.
1. This will make it easier to optimize this to a TBB / TBH instruction +
(smaller) table.
2. This eliminate the need for ugly asm printer hack to force the address
into thumb addresses (bit 0 is one).
3. Same codegen for pic and non-pic.
4. This eliminate the need to align the table so constantpool island pass
won't have to over-estimate the size.
Based on my calculation, the later is probably slightly faster as well since
ldr pc with shifter address is very slow. That is, it should be a win as long
as the HW implementation can do a reasonable job of branch predict the second
branch.
llvm-svn: 77024
2009-07-25 08:33:29 +08:00
|
|
|
for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
|
|
|
|
MachineBasicBlock *MBB = JTBBs[i];
|
2009-07-29 10:18:14 +08:00
|
|
|
if (ByteOffset)
|
2009-08-23 05:43:10 +08:00
|
|
|
O << MAI->getData8bitsDirective();
|
2009-07-29 10:18:14 +08:00
|
|
|
else if (HalfWordOffset)
|
2009-08-23 05:43:10 +08:00
|
|
|
O << MAI->getData16bitsDirective();
|
2009-07-29 10:18:14 +08:00
|
|
|
if (ByteOffset || HalfWordOffset) {
|
2010-01-19 06:01:39 +08:00
|
|
|
O << '(' << *GetMBBSymbol(MBB->getNumber());
|
2009-08-23 05:43:10 +08:00
|
|
|
O << "-" << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
|
2009-07-29 10:18:14 +08:00
|
|
|
<< '_' << JTI << '_' << MO2.getImm() << ")/2";
|
|
|
|
} else {
|
2010-01-18 05:43:43 +08:00
|
|
|
O << "\tb.w " << *GetMBBSymbol(MBB->getNumber());
|
2009-07-29 10:18:14 +08:00
|
|
|
}
|
Change Thumb2 jumptable codegen to one that uses two level jumps:
Before:
adr r12, #LJTI3_0_0
ldr pc, [r12, +r0, lsl #2]
LJTI3_0_0:
.long LBB3_24
.long LBB3_30
.long LBB3_31
.long LBB3_32
After:
adr r12, #LJTI3_0_0
add pc, r12, +r0, lsl #2
LJTI3_0_0:
b.w LBB3_24
b.w LBB3_30
b.w LBB3_31
b.w LBB3_32
This has several advantages.
1. This will make it easier to optimize this to a TBB / TBH instruction +
(smaller) table.
2. This eliminate the need for ugly asm printer hack to force the address
into thumb addresses (bit 0 is one).
3. Same codegen for pic and non-pic.
4. This eliminate the need to align the table so constantpool island pass
won't have to over-estimate the size.
Based on my calculation, the later is probably slightly faster as well since
ldr pc with shifter address is very slow. That is, it should be a win as long
as the HW implementation can do a reasonable job of branch predict the second
branch.
llvm-svn: 77024
2009-07-25 08:33:29 +08:00
|
|
|
if (i != e-1)
|
|
|
|
O << '\n';
|
|
|
|
}
|
2009-08-01 02:35:56 +08:00
|
|
|
|
|
|
|
// Make sure the instruction that follows TBB is 2-byte aligned.
|
|
|
|
// FIXME: Constant island pass should insert an "ALIGN" instruction instead.
|
|
|
|
if (ByteOffset && (JTBBs.size() & 1)) {
|
|
|
|
O << '\n';
|
|
|
|
EmitAlignment(1);
|
|
|
|
}
|
Change Thumb2 jumptable codegen to one that uses two level jumps:
Before:
adr r12, #LJTI3_0_0
ldr pc, [r12, +r0, lsl #2]
LJTI3_0_0:
.long LBB3_24
.long LBB3_30
.long LBB3_31
.long LBB3_32
After:
adr r12, #LJTI3_0_0
add pc, r12, +r0, lsl #2
LJTI3_0_0:
b.w LBB3_24
b.w LBB3_30
b.w LBB3_31
b.w LBB3_32
This has several advantages.
1. This will make it easier to optimize this to a TBB / TBH instruction +
(smaller) table.
2. This eliminate the need for ugly asm printer hack to force the address
into thumb addresses (bit 0 is one).
3. Same codegen for pic and non-pic.
4. This eliminate the need to align the table so constantpool island pass
won't have to over-estimate the size.
Based on my calculation, the later is probably slightly faster as well since
ldr pc with shifter address is very slow. That is, it should be a win as long
as the HW implementation can do a reasonable job of branch predict the second
branch.
llvm-svn: 77024
2009-07-25 08:33:29 +08:00
|
|
|
}
|
|
|
|
|
2009-07-29 10:18:14 +08:00
|
|
|
void ARMAsmPrinter::printTBAddrMode(const MachineInstr *MI, int OpNum) {
|
2009-09-14 04:31:40 +08:00
|
|
|
O << "[pc, " << getRegisterName(MI->getOperand(OpNum).getReg());
|
2009-07-29 10:18:14 +08:00
|
|
|
if (MI->getOpcode() == ARM::t2TBH)
|
|
|
|
O << ", lsl #1";
|
|
|
|
O << ']';
|
|
|
|
}
|
|
|
|
|
2009-08-22 05:58:55 +08:00
|
|
|
void ARMAsmPrinter::printNoHashImmediate(const MachineInstr *MI, int OpNum) {
|
2009-08-09 07:10:41 +08:00
|
|
|
O << MI->getOperand(OpNum).getImm();
|
|
|
|
}
|
2007-01-19 15:51:42 +08:00
|
|
|
|
2009-10-28 09:44:26 +08:00
|
|
|
void ARMAsmPrinter::printVFPf32ImmOperand(const MachineInstr *MI, int OpNum) {
|
|
|
|
const ConstantFP *FP = MI->getOperand(OpNum).getFPImm();
|
2009-11-24 05:08:25 +08:00
|
|
|
O << '#' << FP->getValueAPF().convertToFloat();
|
2009-10-28 09:44:26 +08:00
|
|
|
if (VerboseAsm) {
|
|
|
|
O.PadToColumn(MAI->getCommentColumn());
|
|
|
|
O << MAI->getCommentString() << ' ';
|
|
|
|
WriteAsOperand(O, FP, /*PrintType=*/false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ARMAsmPrinter::printVFPf64ImmOperand(const MachineInstr *MI, int OpNum) {
|
|
|
|
const ConstantFP *FP = MI->getOperand(OpNum).getFPImm();
|
2009-11-24 05:08:25 +08:00
|
|
|
O << '#' << FP->getValueAPF().convertToDouble();
|
2009-10-28 09:44:26 +08:00
|
|
|
if (VerboseAsm) {
|
|
|
|
O.PadToColumn(MAI->getCommentColumn());
|
|
|
|
O << MAI->getCommentString() << ' ';
|
|
|
|
WriteAsOperand(O, FP, /*PrintType=*/false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
|
2007-01-19 15:51:42 +08:00
|
|
|
unsigned AsmVariant, const char *ExtraCode){
|
|
|
|
// Does this asm operand have a single letter operand modifier?
|
|
|
|
if (ExtraCode && ExtraCode[0]) {
|
|
|
|
if (ExtraCode[1] != 0) return true; // Unknown modifier.
|
2009-08-09 07:10:41 +08:00
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
switch (ExtraCode[0]) {
|
|
|
|
default: return true; // Unknown modifier.
|
2009-07-10 07:54:51 +08:00
|
|
|
case 'a': // Print as a memory address.
|
|
|
|
if (MI->getOperand(OpNum).isReg()) {
|
2009-09-14 04:31:40 +08:00
|
|
|
O << "[" << getRegisterName(MI->getOperand(OpNum).getReg()) << "]";
|
2009-07-10 07:54:51 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Fallthrough
|
|
|
|
case 'c': // Don't print "#" before an immediate operand.
|
2009-08-22 05:58:55 +08:00
|
|
|
if (!MI->getOperand(OpNum).isImm())
|
|
|
|
return true;
|
|
|
|
printNoHashImmediate(MI, OpNum);
|
2009-04-07 05:46:51 +08:00
|
|
|
return false;
|
2007-04-04 08:13:29 +08:00
|
|
|
case 'P': // Print a VFP double precision register.
|
2009-12-09 07:06:22 +08:00
|
|
|
case 'q': // Print a NEON quad precision register.
|
2009-06-29 15:51:04 +08:00
|
|
|
printOperand(MI, OpNum);
|
2007-03-09 06:42:46 +08:00
|
|
|
return false;
|
2007-01-19 15:51:42 +08:00
|
|
|
case 'Q':
|
|
|
|
if (TM.getTargetData()->isLittleEndian())
|
|
|
|
break;
|
|
|
|
// Fallthrough
|
|
|
|
case 'R':
|
|
|
|
if (TM.getTargetData()->isBigEndian())
|
|
|
|
break;
|
|
|
|
// Fallthrough
|
2009-09-04 09:38:51 +08:00
|
|
|
case 'H': // Write second word of DI / DF reference.
|
2007-01-19 15:51:42 +08:00
|
|
|
// Verify that this operand has two consecutive registers.
|
2009-06-29 15:51:04 +08:00
|
|
|
if (!MI->getOperand(OpNum).isReg() ||
|
|
|
|
OpNum+1 == MI->getNumOperands() ||
|
|
|
|
!MI->getOperand(OpNum+1).isReg())
|
2007-01-19 15:51:42 +08:00
|
|
|
return true;
|
2009-06-29 15:51:04 +08:00
|
|
|
++OpNum; // Return the high-part.
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
|
|
|
}
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2009-06-29 15:51:04 +08:00
|
|
|
printOperand(MI, OpNum);
|
2007-01-19 15:51:42 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-05-19 13:53:42 +08:00
|
|
|
bool ARMAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
|
2009-06-29 15:51:04 +08:00
|
|
|
unsigned OpNum, unsigned AsmVariant,
|
2009-05-19 13:53:42 +08:00
|
|
|
const char *ExtraCode) {
|
|
|
|
if (ExtraCode && ExtraCode[0])
|
|
|
|
return true; // Unknown modifier.
|
2009-10-14 04:50:28 +08:00
|
|
|
|
|
|
|
const MachineOperand &MO = MI->getOperand(OpNum);
|
|
|
|
assert(MO.isReg() && "unexpected inline asm memory operand");
|
|
|
|
O << "[" << getRegisterName(MO.getReg()) << "]";
|
2009-05-19 13:53:42 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
void ARMAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
|
|
|
|
++EmittedInsts;
|
|
|
|
|
|
|
|
// Call the autogenerated instruction printer routines.
|
2009-10-06 10:19:11 +08:00
|
|
|
processDebugLoc(MI, true);
|
2009-10-20 04:20:46 +08:00
|
|
|
|
|
|
|
if (EnableMCInst) {
|
|
|
|
printInstructionThroughMCStreamer(MI);
|
|
|
|
} else {
|
2009-10-20 06:33:05 +08:00
|
|
|
int Opc = MI->getOpcode();
|
|
|
|
if (Opc == ARM::CONSTPOOL_ENTRY)
|
|
|
|
EmitAlignment(2);
|
|
|
|
|
2009-10-20 04:20:46 +08:00
|
|
|
printInstruction(MI);
|
|
|
|
}
|
|
|
|
|
2009-11-14 05:34:57 +08:00
|
|
|
if (VerboseAsm)
|
2009-09-10 07:14:36 +08:00
|
|
|
EmitComments(*MI);
|
|
|
|
O << '\n';
|
2009-10-06 10:19:11 +08:00
|
|
|
processDebugLoc(MI, false);
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
|
|
|
|
2009-10-01 06:06:26 +08:00
|
|
|
void ARMAsmPrinter::EmitStartOfAsmFile(Module &M) {
|
2009-09-30 08:23:42 +08:00
|
|
|
if (Subtarget->isTargetDarwin()) {
|
|
|
|
Reloc::Model RelocM = TM.getRelocationModel();
|
|
|
|
if (RelocM == Reloc::PIC_ || RelocM == Reloc::DynamicNoPIC) {
|
|
|
|
// Declare all the text sections up front (before the DWARF sections
|
|
|
|
// emitted by AsmPrinter::doInitialization) so the assembler will keep
|
|
|
|
// them together at the beginning of the object file. This helps
|
|
|
|
// avoid out-of-range branches that are due a fundamental limitation of
|
|
|
|
// the way symbol offsets are encoded with the current Darwin ARM
|
|
|
|
// relocations.
|
2009-10-01 06:25:37 +08:00
|
|
|
TargetLoweringObjectFileMachO &TLOFMacho =
|
|
|
|
static_cast<TargetLoweringObjectFileMachO &>(getObjFileLowering());
|
|
|
|
OutStreamer.SwitchSection(TLOFMacho.getTextSection());
|
|
|
|
OutStreamer.SwitchSection(TLOFMacho.getTextCoalSection());
|
|
|
|
OutStreamer.SwitchSection(TLOFMacho.getConstTextCoalSection());
|
|
|
|
if (RelocM == Reloc::DynamicNoPIC) {
|
|
|
|
const MCSection *sect =
|
|
|
|
TLOFMacho.getMachOSection("__TEXT", "__symbol_stub4",
|
|
|
|
MCSectionMachO::S_SYMBOL_STUBS,
|
|
|
|
12, SectionKind::getText());
|
|
|
|
OutStreamer.SwitchSection(sect);
|
|
|
|
} else {
|
|
|
|
const MCSection *sect =
|
|
|
|
TLOFMacho.getMachOSection("__TEXT", "__picsymbolstub4",
|
|
|
|
MCSectionMachO::S_SYMBOL_STUBS,
|
|
|
|
16, SectionKind::getText());
|
|
|
|
OutStreamer.SwitchSection(sect);
|
|
|
|
}
|
2009-09-30 08:23:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-09 08:11:35 +08:00
|
|
|
// Use unified assembler syntax.
|
|
|
|
O << "\t.syntax unified\n";
|
2009-06-18 07:43:18 +08:00
|
|
|
|
2009-05-24 03:51:20 +08:00
|
|
|
// Emit ARM Build Attributes
|
|
|
|
if (Subtarget->isTargetELF()) {
|
|
|
|
// CPU Type
|
2009-06-02 03:03:17 +08:00
|
|
|
std::string CPUString = Subtarget->getCPUString();
|
|
|
|
if (CPUString != "generic")
|
|
|
|
O << "\t.cpu " << CPUString << '\n';
|
2009-05-24 03:51:20 +08:00
|
|
|
|
|
|
|
// FIXME: Emit FPU type
|
|
|
|
if (Subtarget->hasVFP2())
|
|
|
|
O << "\t.eabi_attribute " << ARMBuildAttrs::VFP_arch << ", 2\n";
|
|
|
|
|
|
|
|
// Signal various FP modes.
|
|
|
|
if (!UnsafeFPMath)
|
|
|
|
O << "\t.eabi_attribute " << ARMBuildAttrs::ABI_FP_denormal << ", 1\n"
|
|
|
|
<< "\t.eabi_attribute " << ARMBuildAttrs::ABI_FP_exceptions << ", 1\n";
|
|
|
|
|
|
|
|
if (FiniteOnlyFPMath())
|
|
|
|
O << "\t.eabi_attribute " << ARMBuildAttrs::ABI_FP_number_model << ", 1\n";
|
|
|
|
else
|
|
|
|
O << "\t.eabi_attribute " << ARMBuildAttrs::ABI_FP_number_model << ", 3\n";
|
|
|
|
|
|
|
|
// 8-bytes alignment stuff.
|
|
|
|
O << "\t.eabi_attribute " << ARMBuildAttrs::ABI_align8_needed << ", 1\n"
|
|
|
|
<< "\t.eabi_attribute " << ARMBuildAttrs::ABI_align8_preserved << ", 1\n";
|
|
|
|
|
2009-08-06 03:04:42 +08:00
|
|
|
// Hard float. Use both S and D registers and conform to AAPCS-VFP.
|
|
|
|
if (Subtarget->isAAPCS_ABI() && FloatABIType == FloatABI::Hard)
|
|
|
|
O << "\t.eabi_attribute " << ARMBuildAttrs::ABI_HardFP_use << ", 3\n"
|
|
|
|
<< "\t.eabi_attribute " << ARMBuildAttrs::ABI_VFP_args << ", 1\n";
|
|
|
|
|
2009-05-24 03:51:20 +08:00
|
|
|
// FIXME: Should we signal R9 usage?
|
|
|
|
}
|
2006-05-15 06:18:28 +08:00
|
|
|
}
|
|
|
|
|
2008-08-07 17:54:23 +08:00
|
|
|
|
2009-10-20 01:59:19 +08:00
|
|
|
void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) {
|
2007-01-20 03:25:36 +08:00
|
|
|
if (Subtarget->isTargetDarwin()) {
|
2009-08-04 06:18:15 +08:00
|
|
|
// All darwin targets use mach-o.
|
2009-09-04 09:38:51 +08:00
|
|
|
TargetLoweringObjectFileMachO &TLOFMacho =
|
2009-08-04 06:18:15 +08:00
|
|
|
static_cast<TargetLoweringObjectFileMachO &>(getObjFileLowering());
|
2009-10-20 02:38:33 +08:00
|
|
|
MachineModuleInfoMachO &MMIMacho =
|
|
|
|
MMI->getObjFileInfo<MachineModuleInfoMachO>();
|
2009-09-04 09:38:51 +08:00
|
|
|
|
2009-07-15 12:12:33 +08:00
|
|
|
O << '\n';
|
2007-01-19 15:51:42 +08:00
|
|
|
|
|
|
|
// Output non-lazy-pointers for external and common global variables.
|
2009-10-20 02:38:33 +08:00
|
|
|
MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetGVStubList();
|
|
|
|
|
|
|
|
if (!Stubs.empty()) {
|
2009-08-10 09:39:42 +08:00
|
|
|
// Switch with ".non_lazy_symbol_pointer" directive.
|
2009-08-19 13:49:37 +08:00
|
|
|
OutStreamer.SwitchSection(TLOFMacho.getNonLazySymbolPointerSection());
|
2009-08-11 02:01:34 +08:00
|
|
|
EmitAlignment(2);
|
2009-10-20 02:38:33 +08:00
|
|
|
for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
|
2010-01-18 05:43:43 +08:00
|
|
|
O << *Stubs[i].first << ":\n\t.indirect_symbol ";
|
|
|
|
O << *Stubs[i].second << "\n\t.long\t0\n";
|
2008-12-05 09:06:39 +08:00
|
|
|
}
|
2007-01-19 15:51:42 +08:00
|
|
|
}
|
|
|
|
|
2009-10-20 02:44:38 +08:00
|
|
|
Stubs = MMIMacho.GetHiddenGVStubList();
|
|
|
|
if (!Stubs.empty()) {
|
2009-08-19 13:49:37 +08:00
|
|
|
OutStreamer.SwitchSection(getObjFileLowering().getDataSection());
|
2009-08-11 02:02:16 +08:00
|
|
|
EmitAlignment(2);
|
2010-01-18 05:43:43 +08:00
|
|
|
for (unsigned i = 0, e = Stubs.size(); i != e; ++i)
|
|
|
|
O << *Stubs[i].first << ":\n\t.long " << *Stubs[i].second << "\n";
|
2008-12-05 09:06:39 +08:00
|
|
|
}
|
|
|
|
|
2007-01-19 15:51:42 +08:00
|
|
|
// 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.
|
2009-10-20 02:03:08 +08:00
|
|
|
OutStreamer.EmitAssemblerFlag(MCStreamer::SubsectionsViaSymbols);
|
2006-07-27 19:38:51 +08:00
|
|
|
}
|
2006-05-15 06:18:28 +08:00
|
|
|
}
|
2008-08-17 21:55:10 +08:00
|
|
|
|
2009-10-20 04:20:46 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
void ARMAsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) {
|
2009-10-20 08:52:47 +08:00
|
|
|
ARMMCInstLower MCInstLowering(OutContext, *Mang, *this);
|
2009-10-20 04:20:46 +08:00
|
|
|
switch (MI->getOpcode()) {
|
2009-10-20 13:58:02 +08:00
|
|
|
case ARM::t2MOVi32imm:
|
|
|
|
assert(0 && "Should be lowered by thumb2it pass");
|
2009-10-20 06:23:04 +08:00
|
|
|
default: break;
|
2009-10-20 04:20:46 +08:00
|
|
|
case TargetInstrInfo::DBG_LABEL:
|
|
|
|
case TargetInstrInfo::EH_LABEL:
|
|
|
|
case TargetInstrInfo::GC_LABEL:
|
|
|
|
printLabel(MI);
|
|
|
|
return;
|
|
|
|
case TargetInstrInfo::KILL:
|
2009-11-05 03:24:37 +08:00
|
|
|
printKill(MI);
|
2009-10-20 04:20:46 +08:00
|
|
|
return;
|
|
|
|
case TargetInstrInfo::INLINEASM:
|
|
|
|
printInlineAsm(MI);
|
|
|
|
return;
|
|
|
|
case TargetInstrInfo::IMPLICIT_DEF:
|
|
|
|
printImplicitDef(MI);
|
|
|
|
return;
|
2009-10-20 06:23:04 +08:00
|
|
|
case ARM::PICADD: { // FIXME: Remove asm string from td file.
|
|
|
|
// 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.
|
|
|
|
// FIXME: MOVE TO SHARED PLACE.
|
2009-10-20 06:33:05 +08:00
|
|
|
unsigned Id = (unsigned)MI->getOperand(2).getImm();
|
2009-10-20 06:49:00 +08:00
|
|
|
const char *Prefix = MAI->getPrivateGlobalPrefix();
|
2009-11-07 06:24:13 +08:00
|
|
|
MCSymbol *Label =OutContext.GetOrCreateSymbol(Twine(Prefix)
|
|
|
|
+ "PC" + Twine(getFunctionNumber()) + "_" + Twine(Id));
|
2009-10-20 06:49:00 +08:00
|
|
|
OutStreamer.EmitLabel(Label);
|
2009-10-20 06:23:04 +08:00
|
|
|
|
|
|
|
|
|
|
|
// Form and emit tha dd.
|
|
|
|
MCInst AddInst;
|
|
|
|
AddInst.setOpcode(ARM::ADDrr);
|
|
|
|
AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
|
|
|
|
AddInst.addOperand(MCOperand::CreateReg(ARM::PC));
|
|
|
|
AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg()));
|
|
|
|
printMCInst(&AddInst);
|
|
|
|
return;
|
|
|
|
}
|
2009-10-20 06:33:05 +08:00
|
|
|
case ARM::CONSTPOOL_ENTRY: { // FIXME: Remove asm string from td file.
|
|
|
|
/// 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.
|
|
|
|
unsigned LabelId = (unsigned)MI->getOperand(0).getImm();
|
|
|
|
unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();
|
|
|
|
|
|
|
|
EmitAlignment(2);
|
|
|
|
|
2009-10-20 06:51:16 +08:00
|
|
|
const char *Prefix = MAI->getPrivateGlobalPrefix();
|
|
|
|
MCSymbol *Label = OutContext.GetOrCreateSymbol(Twine(Prefix)+"CPI"+
|
|
|
|
Twine(getFunctionNumber())+
|
|
|
|
"_"+ Twine(LabelId));
|
|
|
|
OutStreamer.EmitLabel(Label);
|
2009-10-20 06:33:05 +08:00
|
|
|
|
|
|
|
const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx];
|
|
|
|
if (MCPE.isMachineConstantPoolEntry())
|
|
|
|
EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
|
|
|
|
else
|
|
|
|
EmitGlobalConstant(MCPE.Val.ConstVal);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2009-10-20 08:40:56 +08:00
|
|
|
case ARM::MOVi2pieces: { // FIXME: Remove asmstring from td file.
|
|
|
|
// This is a hack that lowers as a two instruction sequence.
|
|
|
|
unsigned DstReg = MI->getOperand(0).getReg();
|
|
|
|
unsigned ImmVal = (unsigned)MI->getOperand(1).getImm();
|
|
|
|
|
|
|
|
unsigned SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(ImmVal);
|
|
|
|
unsigned SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(ImmVal);
|
|
|
|
|
|
|
|
{
|
|
|
|
MCInst TmpInst;
|
|
|
|
TmpInst.setOpcode(ARM::MOVi);
|
|
|
|
TmpInst.addOperand(MCOperand::CreateReg(DstReg));
|
|
|
|
TmpInst.addOperand(MCOperand::CreateImm(SOImmValV1));
|
|
|
|
|
|
|
|
// Predicate.
|
|
|
|
TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm()));
|
|
|
|
TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg()));
|
2009-10-20 08:46:11 +08:00
|
|
|
|
|
|
|
TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out
|
2009-10-20 08:40:56 +08:00
|
|
|
printMCInst(&TmpInst);
|
|
|
|
O << '\n';
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
MCInst TmpInst;
|
|
|
|
TmpInst.setOpcode(ARM::ORRri);
|
|
|
|
TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg
|
|
|
|
TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // inreg
|
|
|
|
TmpInst.addOperand(MCOperand::CreateImm(SOImmValV2)); // so_imm
|
|
|
|
// Predicate.
|
|
|
|
TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm()));
|
|
|
|
TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg()));
|
|
|
|
|
|
|
|
TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out
|
|
|
|
printMCInst(&TmpInst);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2009-10-20 09:11:37 +08:00
|
|
|
case ARM::MOVi32imm: { // FIXME: Remove asmstring from td file.
|
|
|
|
// This is a hack that lowers as a two instruction sequence.
|
|
|
|
unsigned DstReg = MI->getOperand(0).getReg();
|
|
|
|
unsigned ImmVal = (unsigned)MI->getOperand(1).getImm();
|
|
|
|
|
|
|
|
{
|
|
|
|
MCInst TmpInst;
|
|
|
|
TmpInst.setOpcode(ARM::MOVi16);
|
|
|
|
TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg
|
|
|
|
TmpInst.addOperand(MCOperand::CreateImm(ImmVal & 65535)); // lower16(imm)
|
|
|
|
|
|
|
|
// Predicate.
|
|
|
|
TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm()));
|
|
|
|
TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg()));
|
|
|
|
|
|
|
|
printMCInst(&TmpInst);
|
|
|
|
O << '\n';
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
MCInst TmpInst;
|
|
|
|
TmpInst.setOpcode(ARM::MOVTi16);
|
|
|
|
TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg
|
|
|
|
TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // srcreg
|
|
|
|
TmpInst.addOperand(MCOperand::CreateImm(ImmVal >> 16)); // upper16(imm)
|
|
|
|
|
|
|
|
// Predicate.
|
|
|
|
TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm()));
|
|
|
|
TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg()));
|
|
|
|
|
|
|
|
printMCInst(&TmpInst);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2009-10-20 04:20:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
MCInst TmpInst;
|
|
|
|
MCInstLowering.Lower(MI, TmpInst);
|
|
|
|
|
|
|
|
printMCInst(&TmpInst);
|
|
|
|
}
|
2009-10-20 13:15:36 +08:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Target Registry Stuff
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
static MCInstPrinter *createARMMCInstPrinter(const Target &T,
|
|
|
|
unsigned SyntaxVariant,
|
|
|
|
const MCAsmInfo &MAI,
|
|
|
|
raw_ostream &O) {
|
|
|
|
if (SyntaxVariant == 0)
|
|
|
|
return new ARMInstPrinter(O, MAI, false);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Force static initialization.
|
|
|
|
extern "C" void LLVMInitializeARMAsmPrinter() {
|
|
|
|
RegisterAsmPrinter<ARMAsmPrinter> X(TheARMTarget);
|
|
|
|
RegisterAsmPrinter<ARMAsmPrinter> Y(TheThumbTarget);
|
|
|
|
|
|
|
|
TargetRegistry::RegisterMCInstPrinter(TheARMTarget, createARMMCInstPrinter);
|
|
|
|
TargetRegistry::RegisterMCInstPrinter(TheThumbTarget, createARMMCInstPrinter);
|
|
|
|
}
|
|
|
|
|