mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-09 13:33:17 +00:00
1532f3ddd7
review feedback. -enable-eh is still accepted but doesn't do anything. EH intrinsics use Dwarf EH if the target supports that, and are handled by LowerInvoke otherwise. The separation of the EH table and frame move data is, I think, logically figured out, but either one still causes full EH info to be generated (not sure how to split the metadata correctly). MachineModuleInfo::needsFrameInfo is no longer used and is removed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@49064 91177308-0d34-0410-b5e6-96231b3b80d8
648 lines
21 KiB
C++
648 lines
21 KiB
C++
//===-- X86ATTAsmPrinter.cpp - Convert X86 LLVM code to AT&T assembly -----===//
|
|
//
|
|
// 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 AT&T format assembly
|
|
// language. This printer is the output mechanism used by `llc'.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "asm-printer"
|
|
#include "X86ATTAsmPrinter.h"
|
|
#include "X86.h"
|
|
#include "X86COFF.h"
|
|
#include "X86MachineFunctionInfo.h"
|
|
#include "X86TargetMachine.h"
|
|
#include "X86TargetAsmInfo.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/CallingConv.h"
|
|
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
|
#include "llvm/Module.h"
|
|
#include "llvm/Support/Mangler.h"
|
|
#include "llvm/Target/TargetAsmInfo.h"
|
|
#include "llvm/Target/TargetOptions.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
using namespace llvm;
|
|
|
|
STATISTIC(EmittedInsts, "Number of machine instrs printed");
|
|
|
|
static std::string getPICLabelString(unsigned FnNum,
|
|
const TargetAsmInfo *TAI,
|
|
const X86Subtarget* Subtarget) {
|
|
std::string label;
|
|
if (Subtarget->isTargetDarwin())
|
|
label = "\"L" + utostr_32(FnNum) + "$pb\"";
|
|
else if (Subtarget->isTargetELF())
|
|
label = ".Lllvm$" + utostr_32(FnNum) + "." + "$piclabel";
|
|
else
|
|
assert(0 && "Don't know how to print PIC label!\n");
|
|
|
|
return label;
|
|
}
|
|
|
|
/// getSectionForFunction - Return the section that we should emit the
|
|
/// specified function body into.
|
|
std::string X86ATTAsmPrinter::getSectionForFunction(const Function &F) const {
|
|
switch (F.getLinkage()) {
|
|
default: assert(0 && "Unknown linkage type!");
|
|
case Function::InternalLinkage:
|
|
case Function::DLLExportLinkage:
|
|
case Function::ExternalLinkage:
|
|
return TAI->getTextSection();
|
|
case Function::WeakLinkage:
|
|
case Function::LinkOnceLinkage:
|
|
if (Subtarget->isTargetDarwin()) {
|
|
return ".section __TEXT,__textcoal_nt,coalesced,pure_instructions";
|
|
} else if (Subtarget->isTargetCygMing()) {
|
|
return "\t.section\t.text$linkonce." + CurrentFnName + ",\"ax\"";
|
|
} else {
|
|
return "\t.section\t.llvm.linkonce.t." + CurrentFnName +
|
|
",\"ax\",@progbits";
|
|
}
|
|
}
|
|
}
|
|
|
|
/// runOnMachineFunction - This uses the printMachineInstruction()
|
|
/// method to print assembly for each instruction.
|
|
///
|
|
bool X86ATTAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
|
|
if (TAI->doesSupportDebugInformation()) {
|
|
// Let PassManager know we need debug information and relay
|
|
// the MachineModuleInfo address on to DwarfWriter.
|
|
MMI = &getAnalysis<MachineModuleInfo>();
|
|
DW.SetModuleInfo(MMI);
|
|
}
|
|
|
|
SetupMachineFunction(MF);
|
|
O << "\n\n";
|
|
|
|
// Print out constants referenced by the function
|
|
EmitConstantPool(MF.getConstantPool());
|
|
|
|
// Print out labels for the function.
|
|
const Function *F = MF.getFunction();
|
|
unsigned CC = F->getCallingConv();
|
|
|
|
// Populate function information map. Actually, We don't want to populate
|
|
// non-stdcall or non-fastcall functions' information right now.
|
|
if (CC == CallingConv::X86_StdCall || CC == CallingConv::X86_FastCall)
|
|
FunctionInfoMap[F] = *MF.getInfo<X86MachineFunctionInfo>();
|
|
|
|
X86SharedAsmPrinter::decorateName(CurrentFnName, F);
|
|
|
|
SwitchToTextSection(getSectionForFunction(*F).c_str(), F);
|
|
|
|
unsigned FnAlign = OptimizeForSize ? 1 : 4;
|
|
switch (F->getLinkage()) {
|
|
default: assert(0 && "Unknown linkage type!");
|
|
case Function::InternalLinkage: // Symbols default to internal.
|
|
EmitAlignment(FnAlign, F);
|
|
break;
|
|
case Function::DLLExportLinkage:
|
|
DLLExportedFns.insert(Mang->makeNameProper(F->getName(), ""));
|
|
//FALLS THROUGH
|
|
case Function::ExternalLinkage:
|
|
EmitAlignment(FnAlign, F);
|
|
O << "\t.globl\t" << CurrentFnName << "\n";
|
|
break;
|
|
case Function::LinkOnceLinkage:
|
|
case Function::WeakLinkage:
|
|
EmitAlignment(FnAlign, F);
|
|
if (Subtarget->isTargetDarwin()) {
|
|
O << "\t.globl\t" << CurrentFnName << "\n";
|
|
O << TAI->getWeakDefDirective() << CurrentFnName << "\n";
|
|
} else if (Subtarget->isTargetCygMing()) {
|
|
O << "\t.globl\t" << CurrentFnName << "\n";
|
|
O << "\t.linkonce discard\n";
|
|
} else {
|
|
O << "\t.weak\t" << CurrentFnName << "\n";
|
|
}
|
|
break;
|
|
}
|
|
if (F->hasHiddenVisibility()) {
|
|
if (const char *Directive = TAI->getHiddenDirective())
|
|
O << Directive << CurrentFnName << "\n";
|
|
} else if (F->hasProtectedVisibility()) {
|
|
if (const char *Directive = TAI->getProtectedDirective())
|
|
O << Directive << CurrentFnName << "\n";
|
|
}
|
|
|
|
if (Subtarget->isTargetELF())
|
|
O << "\t.type\t" << CurrentFnName << ",@function\n";
|
|
else if (Subtarget->isTargetCygMing()) {
|
|
O << "\t.def\t " << CurrentFnName
|
|
<< ";\t.scl\t" <<
|
|
(F->getLinkage() == Function::InternalLinkage ? COFF::C_STAT : COFF::C_EXT)
|
|
<< ";\t.type\t" << (COFF::DT_FCN << COFF::N_BTSHFT)
|
|
<< ";\t.endef\n";
|
|
}
|
|
|
|
O << CurrentFnName << ":\n";
|
|
// Add some workaround for linkonce linkage on Cygwin\MinGW
|
|
if (Subtarget->isTargetCygMing() &&
|
|
(F->getLinkage() == Function::LinkOnceLinkage ||
|
|
F->getLinkage() == Function::WeakLinkage))
|
|
O << "Lllvm$workaround$fake$stub$" << CurrentFnName << ":\n";
|
|
|
|
if (TAI->doesSupportDebugInformation() ||
|
|
TAI->doesSupportExceptionHandling()) {
|
|
// Emit pre-function debug and/or EH information.
|
|
DW.BeginFunction(&MF);
|
|
}
|
|
|
|
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";
|
|
}
|
|
|
|
// 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.
|
|
if (!I->pred_empty()) {
|
|
printBasicBlockLabel(I, true, true);
|
|
O << '\n';
|
|
}
|
|
for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end();
|
|
II != IE; ++II) {
|
|
// Print the assembly for the instruction.
|
|
printMachineInstruction(II);
|
|
}
|
|
}
|
|
|
|
if (TAI->hasDotTypeDotSizeDirective())
|
|
O << "\t.size\t" << CurrentFnName << ", .-" << CurrentFnName << "\n";
|
|
|
|
if (TAI->doesSupportDebugInformation()) {
|
|
// Emit post-function debug information.
|
|
DW.EndFunction();
|
|
}
|
|
|
|
// Print out jump tables referenced by the function.
|
|
EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
|
|
|
|
// We didn't modify anything.
|
|
return false;
|
|
}
|
|
|
|
static inline bool printGOT(TargetMachine &TM, const X86Subtarget* ST) {
|
|
return ST->isPICStyleGOT() && TM.getRelocationModel() == Reloc::PIC_;
|
|
}
|
|
|
|
static inline bool printStub(TargetMachine &TM, const X86Subtarget* ST) {
|
|
return ST->isPICStyleStub() && TM.getRelocationModel() != Reloc::Static;
|
|
}
|
|
|
|
void X86ATTAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
|
|
const char *Modifier, bool NotRIPRel) {
|
|
const MachineOperand &MO = MI->getOperand(OpNo);
|
|
switch (MO.getType()) {
|
|
case MachineOperand::MO_Register: {
|
|
assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
|
|
"Virtual registers should not make it this far!");
|
|
O << '%';
|
|
unsigned Reg = MO.getReg();
|
|
if (Modifier && strncmp(Modifier, "subreg", strlen("subreg")) == 0) {
|
|
MVT::ValueType VT = (strcmp(Modifier+6,"64") == 0) ?
|
|
MVT::i64 : ((strcmp(Modifier+6, "32") == 0) ? MVT::i32 :
|
|
((strcmp(Modifier+6,"16") == 0) ? MVT::i16 : MVT::i8));
|
|
Reg = getX86SubSuperRegister(Reg, VT);
|
|
}
|
|
for (const char *Name = TRI->getAsmName(Reg); *Name; ++Name)
|
|
O << (char)tolower(*Name);
|
|
return;
|
|
}
|
|
|
|
case MachineOperand::MO_Immediate:
|
|
if (!Modifier ||
|
|
(strcmp(Modifier, "debug") && strcmp(Modifier, "mem")))
|
|
O << '$';
|
|
O << MO.getImm();
|
|
return;
|
|
case MachineOperand::MO_MachineBasicBlock:
|
|
printBasicBlockLabel(MO.getMBB());
|
|
return;
|
|
case MachineOperand::MO_JumpTableIndex: {
|
|
bool isMemOp = Modifier && !strcmp(Modifier, "mem");
|
|
if (!isMemOp) O << '$';
|
|
O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() << "_"
|
|
<< MO.getIndex();
|
|
|
|
if (TM.getRelocationModel() == Reloc::PIC_) {
|
|
if (Subtarget->isPICStyleStub())
|
|
O << "-\"" << TAI->getPrivateGlobalPrefix() << getFunctionNumber()
|
|
<< "$pb\"";
|
|
else if (Subtarget->isPICStyleGOT())
|
|
O << "@GOTOFF";
|
|
}
|
|
|
|
if (isMemOp && Subtarget->isPICStyleRIPRel() && !NotRIPRel)
|
|
O << "(%rip)";
|
|
return;
|
|
}
|
|
case MachineOperand::MO_ConstantPoolIndex: {
|
|
bool isMemOp = Modifier && !strcmp(Modifier, "mem");
|
|
if (!isMemOp) O << '$';
|
|
O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
|
|
<< MO.getIndex();
|
|
|
|
if (TM.getRelocationModel() == Reloc::PIC_) {
|
|
if (Subtarget->isPICStyleStub())
|
|
O << "-\"" << TAI->getPrivateGlobalPrefix() << getFunctionNumber()
|
|
<< "$pb\"";
|
|
else if (Subtarget->isPICStyleGOT())
|
|
O << "@GOTOFF";
|
|
}
|
|
|
|
int Offset = MO.getOffset();
|
|
if (Offset > 0)
|
|
O << "+" << Offset;
|
|
else if (Offset < 0)
|
|
O << Offset;
|
|
|
|
if (isMemOp && Subtarget->isPICStyleRIPRel() && !NotRIPRel)
|
|
O << "(%rip)";
|
|
return;
|
|
}
|
|
case MachineOperand::MO_GlobalAddress: {
|
|
bool isCallOp = Modifier && !strcmp(Modifier, "call");
|
|
bool isMemOp = Modifier && !strcmp(Modifier, "mem");
|
|
bool needCloseParen = false;
|
|
|
|
const GlobalValue *GV = MO.getGlobal();
|
|
const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
|
|
if (!GVar) {
|
|
// If GV is an alias then use the aliasee for determining
|
|
// thread-localness.
|
|
if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(GV))
|
|
GVar = dyn_cast_or_null<GlobalVariable>(GA->resolveAliasedGlobal());
|
|
}
|
|
|
|
bool isThreadLocal = GVar && GVar->isThreadLocal();
|
|
|
|
std::string Name = Mang->getValueName(GV);
|
|
X86SharedAsmPrinter::decorateName(Name, GV);
|
|
|
|
if (!isMemOp && !isCallOp)
|
|
O << '$';
|
|
else if (Name[0] == '$') {
|
|
// The name begins with a dollar-sign. In order to avoid having it look
|
|
// like an integer immediate to the assembler, enclose it in parens.
|
|
O << '(';
|
|
needCloseParen = true;
|
|
}
|
|
|
|
if (printStub(TM, Subtarget)) {
|
|
// Link-once, declaration, or Weakly-linked global variables need
|
|
// non-lazily-resolved stubs
|
|
if (GV->isDeclaration() ||
|
|
GV->hasWeakLinkage() ||
|
|
GV->hasLinkOnceLinkage()) {
|
|
// Dynamically-resolved functions need a stub for the function.
|
|
if (isCallOp && isa<Function>(GV)) {
|
|
FnStubs.insert(Name);
|
|
O << TAI->getPrivateGlobalPrefix() << Name << "$stub";
|
|
} else {
|
|
GVStubs.insert(Name);
|
|
O << TAI->getPrivateGlobalPrefix() << Name << "$non_lazy_ptr";
|
|
}
|
|
} else {
|
|
if (GV->hasDLLImportLinkage())
|
|
O << "__imp_";
|
|
O << Name;
|
|
}
|
|
|
|
if (!isCallOp && TM.getRelocationModel() == Reloc::PIC_)
|
|
O << '-' << getPICLabelString(getFunctionNumber(), TAI, Subtarget);
|
|
} else {
|
|
if (GV->hasDLLImportLinkage()) {
|
|
O << "__imp_";
|
|
}
|
|
O << Name;
|
|
|
|
if (isCallOp && isa<Function>(GV)) {
|
|
if (printGOT(TM, Subtarget)) {
|
|
// Assemble call via PLT for non-local symbols
|
|
if (!(GV->hasHiddenVisibility() || GV->hasProtectedVisibility()) ||
|
|
GV->isDeclaration())
|
|
O << "@PLT";
|
|
}
|
|
if (Subtarget->isTargetCygMing() && GV->isDeclaration())
|
|
// Save function name for later type emission
|
|
FnStubs.insert(Name);
|
|
}
|
|
}
|
|
|
|
if (GV->hasExternalWeakLinkage())
|
|
ExtWeakSymbols.insert(GV);
|
|
|
|
int Offset = MO.getOffset();
|
|
if (Offset > 0)
|
|
O << "+" << Offset;
|
|
else if (Offset < 0)
|
|
O << Offset;
|
|
|
|
if (isThreadLocal) {
|
|
if (TM.getRelocationModel() == Reloc::PIC_)
|
|
O << "@TLSGD"; // general dynamic TLS model
|
|
else
|
|
if (GV->isDeclaration())
|
|
O << "@INDNTPOFF"; // initial exec TLS model
|
|
else
|
|
O << "@NTPOFF"; // local exec TLS model
|
|
} else if (isMemOp) {
|
|
if (printGOT(TM, Subtarget)) {
|
|
if (Subtarget->GVRequiresExtraLoad(GV, TM, false))
|
|
O << "@GOT";
|
|
else
|
|
O << "@GOTOFF";
|
|
} else if (Subtarget->isPICStyleRIPRel() && !NotRIPRel &&
|
|
TM.getRelocationModel() != Reloc::Static) {
|
|
if (Subtarget->GVRequiresExtraLoad(GV, TM, false))
|
|
O << "@GOTPCREL";
|
|
|
|
if (needCloseParen) {
|
|
needCloseParen = false;
|
|
O << ')';
|
|
}
|
|
|
|
// Use rip when possible to reduce code size, except when
|
|
// index or base register are also part of the address. e.g.
|
|
// foo(%rip)(%rcx,%rax,4) is not legal
|
|
O << "(%rip)";
|
|
}
|
|
}
|
|
|
|
if (needCloseParen)
|
|
O << ')';
|
|
|
|
return;
|
|
}
|
|
case MachineOperand::MO_ExternalSymbol: {
|
|
bool isCallOp = Modifier && !strcmp(Modifier, "call");
|
|
bool needCloseParen = false;
|
|
std::string Name(TAI->getGlobalPrefix());
|
|
Name += MO.getSymbolName();
|
|
if (isCallOp && printStub(TM, Subtarget)) {
|
|
FnStubs.insert(Name);
|
|
O << TAI->getPrivateGlobalPrefix() << Name << "$stub";
|
|
return;
|
|
}
|
|
if (!isCallOp)
|
|
O << '$';
|
|
else if (Name[0] == '$') {
|
|
// The name begins with a dollar-sign. In order to avoid having it look
|
|
// like an integer immediate to the assembler, enclose it in parens.
|
|
O << '(';
|
|
needCloseParen = true;
|
|
}
|
|
|
|
O << Name;
|
|
|
|
if (printGOT(TM, Subtarget)) {
|
|
std::string GOTName(TAI->getGlobalPrefix());
|
|
GOTName+="_GLOBAL_OFFSET_TABLE_";
|
|
if (Name == GOTName)
|
|
// HACK! Emit extra offset to PC during printing GOT offset to
|
|
// compensate for the size of popl instruction. The resulting code
|
|
// should look like:
|
|
// call .piclabel
|
|
// piclabel:
|
|
// popl %some_register
|
|
// addl $_GLOBAL_ADDRESS_TABLE_ + [.-piclabel], %some_register
|
|
O << " + [.-"
|
|
<< getPICLabelString(getFunctionNumber(), TAI, Subtarget) << "]";
|
|
|
|
if (isCallOp)
|
|
O << "@PLT";
|
|
}
|
|
|
|
if (needCloseParen)
|
|
O << ')';
|
|
|
|
if (!isCallOp && Subtarget->isPICStyleRIPRel())
|
|
O << "(%rip)";
|
|
|
|
return;
|
|
}
|
|
default:
|
|
O << "<unknown operand type>"; return;
|
|
}
|
|
}
|
|
|
|
void X86ATTAsmPrinter::printSSECC(const MachineInstr *MI, unsigned Op) {
|
|
unsigned char value = MI->getOperand(Op).getImm();
|
|
assert(value <= 7 && "Invalid ssecc argument!");
|
|
switch (value) {
|
|
case 0: O << "eq"; break;
|
|
case 1: O << "lt"; break;
|
|
case 2: O << "le"; break;
|
|
case 3: O << "unord"; break;
|
|
case 4: O << "neq"; break;
|
|
case 5: O << "nlt"; break;
|
|
case 6: O << "nle"; break;
|
|
case 7: O << "ord"; break;
|
|
}
|
|
}
|
|
|
|
void X86ATTAsmPrinter::printMemReference(const MachineInstr *MI, unsigned Op,
|
|
const char *Modifier){
|
|
assert(isMem(MI, Op) && "Invalid memory reference!");
|
|
MachineOperand BaseReg = MI->getOperand(Op);
|
|
MachineOperand IndexReg = MI->getOperand(Op+2);
|
|
const MachineOperand &DispSpec = MI->getOperand(Op+3);
|
|
|
|
bool NotRIPRel = IndexReg.getReg() || BaseReg.getReg();
|
|
if (DispSpec.isGlobalAddress() ||
|
|
DispSpec.isConstantPoolIndex() ||
|
|
DispSpec.isJumpTableIndex()) {
|
|
printOperand(MI, Op+3, "mem", NotRIPRel);
|
|
} else {
|
|
int DispVal = DispSpec.getImm();
|
|
if (DispVal || (!IndexReg.getReg() && !BaseReg.getReg()))
|
|
O << DispVal;
|
|
}
|
|
|
|
if (IndexReg.getReg() || BaseReg.getReg()) {
|
|
unsigned ScaleVal = MI->getOperand(Op+1).getImm();
|
|
unsigned BaseRegOperand = 0, IndexRegOperand = 2;
|
|
|
|
// There are cases where we can end up with ESP/RSP in the indexreg slot.
|
|
// If this happens, swap the base/index register to support assemblers that
|
|
// don't work when the index is *SP.
|
|
if (IndexReg.getReg() == X86::ESP || IndexReg.getReg() == X86::RSP) {
|
|
assert(ScaleVal == 1 && "Scale not supported for stack pointer!");
|
|
std::swap(BaseReg, IndexReg);
|
|
std::swap(BaseRegOperand, IndexRegOperand);
|
|
}
|
|
|
|
O << "(";
|
|
if (BaseReg.getReg())
|
|
printOperand(MI, Op+BaseRegOperand, Modifier);
|
|
|
|
if (IndexReg.getReg()) {
|
|
O << ",";
|
|
printOperand(MI, Op+IndexRegOperand, Modifier);
|
|
if (ScaleVal != 1)
|
|
O << "," << ScaleVal;
|
|
}
|
|
O << ")";
|
|
}
|
|
}
|
|
|
|
void X86ATTAsmPrinter::printPICJumpTableSetLabel(unsigned uid,
|
|
const MachineBasicBlock *MBB) const {
|
|
if (!TAI->getSetDirective())
|
|
return;
|
|
|
|
// We don't need .set machinery if we have GOT-style relocations
|
|
if (Subtarget->isPICStyleGOT())
|
|
return;
|
|
|
|
O << TAI->getSetDirective() << ' ' << TAI->getPrivateGlobalPrefix()
|
|
<< getFunctionNumber() << '_' << uid << "_set_" << MBB->getNumber() << ',';
|
|
printBasicBlockLabel(MBB, false, false, false);
|
|
if (Subtarget->isPICStyleRIPRel())
|
|
O << '-' << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
|
|
<< '_' << uid << '\n';
|
|
else
|
|
O << '-' << getPICLabelString(getFunctionNumber(), TAI, Subtarget) << '\n';
|
|
}
|
|
|
|
void X86ATTAsmPrinter::printPICLabel(const MachineInstr *MI, unsigned Op) {
|
|
std::string label = getPICLabelString(getFunctionNumber(), TAI, Subtarget);
|
|
O << label << "\n" << label << ":";
|
|
}
|
|
|
|
|
|
void X86ATTAsmPrinter::printPICJumpTableEntry(const MachineJumpTableInfo *MJTI,
|
|
const MachineBasicBlock *MBB,
|
|
unsigned uid) const
|
|
{
|
|
const char *JTEntryDirective = MJTI->getEntrySize() == 4 ?
|
|
TAI->getData32bitsDirective() : TAI->getData64bitsDirective();
|
|
|
|
O << JTEntryDirective << ' ';
|
|
|
|
if (TM.getRelocationModel() == Reloc::PIC_) {
|
|
if (Subtarget->isPICStyleRIPRel() || Subtarget->isPICStyleStub()) {
|
|
O << TAI->getPrivateGlobalPrefix() << getFunctionNumber()
|
|
<< '_' << uid << "_set_" << MBB->getNumber();
|
|
} else if (Subtarget->isPICStyleGOT()) {
|
|
printBasicBlockLabel(MBB, false, false, false);
|
|
O << "@GOTOFF";
|
|
} else
|
|
assert(0 && "Don't know how to print MBB label for this PIC mode");
|
|
} else
|
|
printBasicBlockLabel(MBB, false, false, false);
|
|
}
|
|
|
|
bool X86ATTAsmPrinter::printAsmMRegister(const MachineOperand &MO,
|
|
const char Mode) {
|
|
unsigned Reg = MO.getReg();
|
|
switch (Mode) {
|
|
default: return true; // Unknown mode.
|
|
case 'b': // Print QImode register
|
|
Reg = getX86SubSuperRegister(Reg, MVT::i8);
|
|
break;
|
|
case 'h': // Print QImode high register
|
|
Reg = getX86SubSuperRegister(Reg, MVT::i8, true);
|
|
break;
|
|
case 'w': // Print HImode register
|
|
Reg = getX86SubSuperRegister(Reg, MVT::i16);
|
|
break;
|
|
case 'k': // Print SImode register
|
|
Reg = getX86SubSuperRegister(Reg, MVT::i32);
|
|
break;
|
|
case 'q': // Print DImode register
|
|
Reg = getX86SubSuperRegister(Reg, MVT::i64);
|
|
break;
|
|
}
|
|
|
|
O << '%';
|
|
for (const char *Name = TRI->getAsmName(Reg); *Name; ++Name)
|
|
O << (char)tolower(*Name);
|
|
return false;
|
|
}
|
|
|
|
/// PrintAsmOperand - Print out an operand for an inline asm expression.
|
|
///
|
|
bool X86ATTAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
|
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.
|
|
|
|
switch (ExtraCode[0]) {
|
|
default: return true; // Unknown modifier.
|
|
case 'c': // Don't print "$" before a global var name or constant.
|
|
printOperand(MI, OpNo, "mem");
|
|
return false;
|
|
case 'b': // Print QImode register
|
|
case 'h': // Print QImode high register
|
|
case 'w': // Print HImode register
|
|
case 'k': // Print SImode register
|
|
case 'q': // Print DImode register
|
|
if (MI->getOperand(OpNo).isRegister())
|
|
return printAsmMRegister(MI->getOperand(OpNo), ExtraCode[0]);
|
|
printOperand(MI, OpNo);
|
|
return false;
|
|
|
|
case 'P': // Don't print @PLT, but do print as memory.
|
|
printOperand(MI, OpNo, "mem");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
printOperand(MI, OpNo);
|
|
return false;
|
|
}
|
|
|
|
bool X86ATTAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
|
|
unsigned OpNo,
|
|
unsigned AsmVariant,
|
|
const char *ExtraCode) {
|
|
if (ExtraCode && ExtraCode[0]) {
|
|
if (ExtraCode[1] != 0) return true; // Unknown modifier.
|
|
|
|
switch (ExtraCode[0]) {
|
|
default: return true; // Unknown modifier.
|
|
case 'b': // Print QImode register
|
|
case 'h': // Print QImode high register
|
|
case 'w': // Print HImode register
|
|
case 'k': // Print SImode register
|
|
case 'q': // Print SImode register
|
|
// These only apply to registers, ignore on mem.
|
|
break;
|
|
}
|
|
}
|
|
printMemReference(MI, OpNo);
|
|
return false;
|
|
}
|
|
|
|
/// printMachineInstruction -- Print out a single X86 LLVM instruction
|
|
/// MI in AT&T syntax to the current output stream.
|
|
///
|
|
void X86ATTAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
|
|
++EmittedInsts;
|
|
|
|
// Call the autogenerated instruction printer routines.
|
|
printInstruction(MI);
|
|
}
|
|
|
|
// Include the auto-generated portion of the assembly writer.
|
|
#include "X86GenAsmWriter.inc"
|
|
|