Newer
Older
//===-- 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/CallingConv.h"
#include "llvm/Module.h"
#include "llvm/Type.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCStreamer.h"
Bill Wendling
committed
#include "llvm/CodeGen/DwarfWriter.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Mangler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetAsmInfo.h"
using namespace llvm;
STATISTIC(EmittedInsts, "Number of machine instrs printed");
static cl::opt<bool> NewAsmPrinter("experimental-asm-printer",
cl::Hidden);
Evan Cheng
committed
static std::string getPICLabelString(unsigned FnNum,
const TargetAsmInfo *TAI,
const X86Subtarget* Subtarget) {
label = ".Lllvm$" + utostr_32(FnNum) + "." "$piclabel";
assert(0 && "Don't know how to print PIC label!\n");
return label;
}
static X86MachineFunctionInfo calculateFunctionInfo(const Function *F,
const TargetData *TD) {
X86MachineFunctionInfo Info;
uint64_t Size = 0;
switch (F->getCallingConv()) {
case CallingConv::X86_StdCall:
Info.setDecorationStyle(StdCall);
break;
case CallingConv::X86_FastCall:
Info.setDecorationStyle(FastCall);
break;
default:
return Info;
}
unsigned argNum = 1;
for (Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end();
AI != AE; ++AI, ++argNum) {
const Type* Ty = AI->getType();
// 'Dereference' type in case of byval parameter attribute
Ty = cast<PointerType>(Ty)->getElementType();
// Size should be aligned to DWORD boundary
Size += ((TD->getTypeAllocSize(Ty) + 3)/4)*4;
}
// We're not supporting tooooo huge arguments :)
Info.setBytesToPopOnReturn((unsigned int)Size);
return Info;
}
/// PrintUnmangledNameSafely - Print out the printable characters in the name.
/// Don't print things like \\n or \\0.
static void PrintUnmangledNameSafely(const Value *V, raw_ostream &OS) {
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
for (const char *Name = V->getNameStart(), *E = Name+V->getNameLen();
Name != E; ++Name)
if (isprint(*Name))
OS << *Name;
}
/// decorateName - Query FunctionInfoMap and use this information for various
/// name decoration.
void X86ATTAsmPrinter::decorateName(std::string &Name,
const GlobalValue *GV) {
const Function *F = dyn_cast<Function>(GV);
if (!F) return;
// We don't want to decorate non-stdcall or non-fastcall functions right now
unsigned CC = F->getCallingConv();
if (CC != CallingConv::X86_StdCall && CC != CallingConv::X86_FastCall)
return;
// Decorate names only when we're targeting Cygwin/Mingw32 targets
if (!Subtarget->isTargetCygMing())
return;
FMFInfoMap::const_iterator info_item = FunctionInfoMap.find(F);
const X86MachineFunctionInfo *Info;
if (info_item == FunctionInfoMap.end()) {
// Calculate apropriate function info and populate map
FunctionInfoMap[F] = calculateFunctionInfo(F, TM.getTargetData());
Info = &FunctionInfoMap[F];
} else {
Info = &info_item->second;
}
const FunctionType *FT = F->getFunctionType();
switch (Info->getDecorationStyle()) {
case None:
break;
case StdCall:
// "Pure" variadic functions do not receive @0 suffix.
if (!FT->isVarArg() || (FT->getNumParams() == 0) ||
(FT->getNumParams() == 1 && F->hasStructRetAttr()))
Name += '@' + utostr_32(Info->getBytesToPopOnReturn());
break;
case FastCall:
// "Pure" variadic functions do not receive @0 suffix.
if (!FT->isVarArg() || (FT->getNumParams() == 0) ||
(FT->getNumParams() == 1 && F->hasStructRetAttr()))
Name += '@' + utostr_32(Info->getBytesToPopOnReturn());
if (Name[0] == '_') {
Name[0] = '@';
} else {
Name = '@' + Name;
}
break;
default:
assert(0 && "Unsupported DecorationStyle");
}
}
void X86ATTAsmPrinter::emitFunctionHeader(const MachineFunction &MF) {
const Function *F = MF.getFunction();
Anton Korobeynikov
committed
SwitchToSection(TAI->SectionForGlobal(F));
unsigned FnAlign = 4;
if (F->hasFnAttr(Attribute::OptimizeForSize))
FnAlign = 1;
switch (F->getLinkage()) {
default: assert(0 && "Unknown linkage type!");
case Function::InternalLinkage: // Symbols default to internal.
EmitAlignment(FnAlign, F);
break;
case Function::DLLExportLinkage:
case Function::ExternalLinkage:
EmitAlignment(FnAlign, F);
O << "\t.globl\t" << CurrentFnName << '\n';
break;
case Function::LinkOnceAnyLinkage:
case Function::LinkOnceODRLinkage:
case Function::WeakAnyLinkage:
case Function::WeakODRLinkage:
EmitAlignment(FnAlign, F);
O << "\t.globl\t" << CurrentFnName << '\n';
O << TAI->getWeakDefDirective() << CurrentFnName << '\n';
O << "\t.globl\t" << CurrentFnName << "\n"
"\t.linkonce discard\n";
} else {
O << "\t.weak\t" << CurrentFnName << '\n';
}
break;
}
Anton Korobeynikov
committed
printVisibility(CurrentFnName, F->getVisibility());
if (Subtarget->isTargetELF())
O << "\t.type\t" << CurrentFnName << ",@function\n";
else if (Subtarget->isTargetCygMing()) {
O << "\t.def\t " << CurrentFnName
<< ";\t.scl\t" <<
(F->hasInternalLinkage() ? 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
(F->hasLinkOnceLinkage() || F->hasWeakLinkage()))
O << "Lllvm$workaround$fake$stub$" << CurrentFnName << ":\n";
/// runOnMachineFunction - This uses the printMachineInstruction()
/// method to print assembly for each instruction.
///
bool X86ATTAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
const Function *F = MF.getFunction();
unsigned CC = F->getCallingConv();
SetupMachineFunction(MF);
O << "\n\n";
// 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>();
// Print out constants referenced by the function
EmitConstantPool(MF.getConstantPool());
if (F->hasDLLExportLinkage())
DLLExportedFns.insert(Mang->makeNameProper(F->getName(), ""));
// Print the 'header' of function
emitFunctionHeader(MF);
// Emit pre-function debug and/or EH information.
if (TAI->doesSupportDebugInformation() || TAI->doesSupportExceptionHandling())
// Print out code for the function.
bool hasAnyRealCode = false;
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
I != E; ++I) {
// Print a label for the basic block.
if (!VerboseAsm && (I->pred_empty() || I->isOnlyReachableByFallthrough())) {
// This is an entry block or a block that's only reachable via a
// fallthrough edge. In non-VerboseAsm mode, don't print the label.
} else {
printBasicBlockLabel(I, true, true, VerboseAsm);
O << '\n';
}
for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end();
II != IE; ++II) {
// Print the assembly for the instruction.
if (!II->isLabel())
hasAnyRealCode = true;
printMachineInstruction(II);
}
}
Evan Cheng
committed
if (Subtarget->isTargetDarwin() && !hasAnyRealCode) {
// 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.
// We are assuming inline asms are code.
O << "\tnop\n";
}
if (TAI->hasDotTypeDotSizeDirective())
O << "\t.size\t" << CurrentFnName << ", .-" << CurrentFnName << '\n';
// Emit post-function debug information.
if (TAI->doesSupportDebugInformation() || TAI->doesSupportExceptionHandling())
// Print out jump tables referenced by the function.
EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
O.flush();
// We didn't modify anything.
return false;
}
static inline bool shouldPrintGOT(TargetMachine &TM, const X86Subtarget* ST) {
return ST->isPICStyleGOT() && TM.getRelocationModel() == Reloc::PIC_;
}
static inline bool shouldPrintPLT(TargetMachine &TM, const X86Subtarget* ST) {
return ST->isTargetELF() && TM.getRelocationModel() == Reloc::PIC_ &&
(ST->isPICStyleRIPRel() || ST->isPICStyleGOT());
}
static inline bool shouldPrintStub(TargetMachine &TM, const X86Subtarget* ST) {
return ST->isPICStyleStub() && TM.getRelocationModel() != Reloc::Static;
}
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
/// print_pcrel_imm - This is used to print an immediate value that ends up
/// being encoded as a pc-relative value. These print slightly differently, for
/// example, a $ is not emitted.
void X86ATTAsmPrinter::print_pcrel_imm(const MachineInstr *MI, unsigned OpNo) {
const MachineOperand &MO = MI->getOperand(OpNo);
switch (MO.getType()) {
default: assert(0 && "Unknown pcrel immediate operand");
case MachineOperand::MO_Immediate:
O << MO.getImm();
return;
case MachineOperand::MO_MachineBasicBlock:
printBasicBlockLabel(MO.getMBB(), false, false, VerboseAsm);
return;
case MachineOperand::MO_GlobalAddress: {
const GlobalValue *GV = MO.getGlobal();
std::string Name = Mang->getValueName(GV);
decorateName(Name, GV);
bool needCloseParen = false;
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 (shouldPrintStub(TM, Subtarget)) {
// Link-once, declaration, or Weakly-linked global variables need
// non-lazily-resolved stubs
if (GV->isDeclaration() || GV->isWeakForLinker()) {
// Dynamically-resolved functions need a stub for the function.
if (isa<Function>(GV)) {
// Function stubs are no longer needed for Mac OS X 10.5 and up.
if (Subtarget->isTargetDarwin() && Subtarget->getDarwinVers() >= 9) {
O << Name;
} else {
FnStubs.insert(Name);
printSuffixedName(Name, "$stub");
}
} else if (GV->hasHiddenVisibility()) {
if (!GV->isDeclaration() && !GV->hasCommonLinkage())
// Definition is not definitely in the current translation unit.
O << Name;
else {
HiddenGVStubs.insert(Name);
printSuffixedName(Name, "$non_lazy_ptr");
}
} else {
GVStubs.insert(Name);
printSuffixedName(Name, "$non_lazy_ptr");
}
} else {
if (GV->hasDLLImportLinkage())
O << "__imp_";
O << Name;
}
} else {
if (GV->hasDLLImportLinkage()) {
O << "__imp_";
}
O << Name;
if (shouldPrintPLT(TM, Subtarget)) {
// Assemble call via PLT for externally visible symbols
if (!GV->hasHiddenVisibility() && !GV->hasProtectedVisibility() &&
!GV->hasLocalLinkage())
O << "@PLT";
}
if (Subtarget->isTargetCygMing() && GV->isDeclaration())
// Save function name for later type emission
FnStubs.insert(Name);
}
printOffset(MO.getOffset());
if (needCloseParen)
O << ')';
return;
}
case MachineOperand::MO_ExternalSymbol: {
bool needCloseParen = false;
std::string Name(TAI->getGlobalPrefix());
Name += MO.getSymbolName();
// Print function stub suffix unless it's Mac OS X 10.5 and up.
if (shouldPrintStub(TM, Subtarget) &&
!(Subtarget->isTargetDarwin() && Subtarget->getDarwinVers() >= 9)) {
FnStubs.insert(Name);
printSuffixedName(Name, "$stub");
return;
}
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 (shouldPrintPLT(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) << ']';
O << "@PLT";
}
if (needCloseParen)
O << ')';
return;
}
}
}
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 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);
}
O << TRI->getAsmName(Reg);
return;
}
case MachineOperand::MO_Immediate:
if (!Modifier || (strcmp(Modifier, "debug") &&
strcmp(Modifier, "mem")))
Chris Lattner
committed
O << MO.getImm();
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)
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";
}
printOffset(MO.getOffset());
if (isMemOp && Subtarget->isPICStyleRIPRel() && !NotRIPRel)
return;
}
case MachineOperand::MO_GlobalAddress: {
Anton Korobeynikov
committed
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.
Anton Korobeynikov
committed
if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(GV))
GVar =dyn_cast_or_null<GlobalVariable>(GA->resolveAliasedGlobal(false));
Anton Korobeynikov
committed
}
Lauro Ramos Venancio
committed
bool isThreadLocal = GVar && GVar->isThreadLocal();
if (!isMemOp)
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 (shouldPrintStub(TM, Subtarget)) {
// Link-once, declaration, or Weakly-linked global variables need
// non-lazily-resolved stubs
if (GV->isDeclaration() || GV->isWeakForLinker()) {
// Dynamically-resolved functions need a stub for the function.
if (GV->hasHiddenVisibility()) {
Evan Cheng
committed
if (!GV->isDeclaration() && !GV->hasCommonLinkage())
// Definition is not definitely in the current translation unit.
O << Name;
else {
HiddenGVStubs.insert(Name);
printSuffixedName(Name, "$non_lazy_ptr");
}
} else {
GVStubs.insert(Name);
printSuffixedName(Name, "$non_lazy_ptr");
}
} else {
if (GV->hasDLLImportLinkage())
if (TM.getRelocationModel() == Reloc::PIC_)
Evan Cheng
committed
O << '-' << getPICLabelString(getFunctionNumber(), TAI, Subtarget);
} else {
Anton Korobeynikov
committed
printOffset(MO.getOffset());
if (needCloseParen)
O << ')';
bool isRIPRelative = false;
Lauro Ramos Venancio
committed
if (isThreadLocal) {
Rafael Espindola
committed
TLSModel::Model model = getTLSModel(GVar, TM.getRelocationModel());
switch (model) {
case TLSModel::GeneralDynamic:
O << "@TLSGD";
break;
case TLSModel::LocalDynamic:
// O << "@TLSLD"; // local dynamic not implemented
Rafael Espindola
committed
break;
case TLSModel::InitialExec:
if (Subtarget->is64Bit()) {
assert (!NotRIPRel);
O << "@GOTTPOFF";
isRIPRelative = true;
Rafael Espindola
committed
O << "@INDNTPOFF";
Rafael Espindola
committed
break;
case TLSModel::LocalExec:
if (Subtarget->is64Bit())
Rafael Espindola
committed
else
Rafael Espindola
committed
break;
default:
assert (0 && "Unknown TLS model");
}
Lauro Ramos Venancio
committed
} else if (isMemOp) {
if (shouldPrintGOT(TM, Subtarget)) {
if (Subtarget->GVRequiresExtraLoad(GV, TM, false))
else
O << "@GOTOFF";
} else if (Subtarget->isPICStyleRIPRel() &&
!NotRIPRel) {
if (TM.getRelocationModel() != Reloc::Static) {
if (Subtarget->GVRequiresExtraLoad(GV, TM, false))
O << "@GOTPCREL";
// 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.
if (isRIPRelative)
O << "(%rip)";
return;
}
case MachineOperand::MO_ExternalSymbol: {
bool isMemOp = Modifier && !strcmp(Modifier, "mem");
std::string Name(TAI->getGlobalPrefix());
Name += MO.getSymbolName();
Evan Cheng
committed
// Print function stub suffix unless it's Mac OS X 10.5 and up.
if (!isMemOp)
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 (shouldPrintPLT(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
<< getPICLabelString(getFunctionNumber(), TAI, Subtarget) << ']';
if (needCloseParen)
O << ')';
if (Subtarget->isPICStyleRIPRel())
return;
default:
O << "<unknown operand type>"; return;
}
}
void X86ATTAsmPrinter::printSSECC(const MachineInstr *MI, unsigned Op) {
Chris Lattner
committed
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::printLeaMemReference(const MachineInstr *MI, unsigned Op,
const char *Modifier,
bool NotRIPRel) {
MachineOperand BaseReg = MI->getOperand(Op);
MachineOperand IndexReg = MI->getOperand(Op+2);
const MachineOperand &DispSpec = MI->getOperand(Op+3);
NotRIPRel |= IndexReg.getReg() || BaseReg.getReg();
if (DispSpec.isGlobal() ||
DispSpec.isCPI() ||
DispSpec.isJTI() ||
DispSpec.isSymbol()) {
printOperand(MI, Op+3, "mem", NotRIPRel);
} else {
Chris Lattner
committed
int DispVal = DispSpec.getImm();
if (DispVal || (!IndexReg.getReg() && !BaseReg.getReg()))
O << DispVal;
}
if (IndexReg.getReg() || BaseReg.getReg()) {
Chris Lattner
committed
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::printMemReference(const MachineInstr *MI, unsigned Op,
const char *Modifier, bool NotRIPRel){
assert(isMem(MI, Op) && "Invalid memory reference!");
MachineOperand Segment = MI->getOperand(Op+4);
if (Segment.getReg()) {
printOperand(MI, Op+4, Modifier);
O << ':';
}
printLeaMemReference(MI, Op, Modifier, NotRIPRel);
void X86ATTAsmPrinter::printPICJumpTableSetLabel(unsigned uid,
const MachineBasicBlock *MBB) const {
if (!TAI->getSetDirective())
return;
Anton Korobeynikov
committed
// 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() << ',';
Evan Cheng
committed
printBasicBlockLabel(MBB, false, false, false);
O << '-' << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
Evan Cheng
committed
O << '-' << getPICLabelString(getFunctionNumber(), TAI, Subtarget) << '\n';
void X86ATTAsmPrinter::printPICLabel(const MachineInstr *MI, unsigned Op) {
Evan Cheng
committed
std::string label = getPICLabelString(getFunctionNumber(), TAI, Subtarget);
O << label << '\n' << label << ':';
Anton Korobeynikov
committed
void X86ATTAsmPrinter::printPICJumpTableEntry(const MachineJumpTableInfo *MJTI,
const MachineBasicBlock *MBB,
Anton Korobeynikov
committed
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()) {
Evan Cheng
committed
printBasicBlockLabel(MBB, false, false, false);
Anton Korobeynikov
committed
O << "@GOTOFF";
} else
assert(0 && "Don't know how to print MBB label for this PIC mode");
} else
Evan Cheng
committed
printBasicBlockLabel(MBB, false, false, false);
Anton Korobeynikov
committed
}
bool X86ATTAsmPrinter::printAsmMRegister(const MachineOperand &MO, 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);
case 'q': // Print DImode register
Reg = getX86SubSuperRegister(Reg, MVT::i64);
break;
O << '%'<< TRI->getAsmName(Reg);
/// PrintAsmOperand - Print out an operand for an inline asm expression.
///
bool X86ATTAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
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", /*NotRIPRel=*/true);
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).isReg())
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", /*NotRIPRel=*/true);
printOperand(MI, OpNo);
return false;
}
bool X86ATTAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
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;
case 'P': // Don't print @PLT, but do print as memory.
printMemReference(MI, OpNo, "mem", /*NotRIPRel=*/true);
return false;
}
}
printMemReference(MI, OpNo);
return false;
}
static void lower_lea64_32mem(MCInst *MI, unsigned OpNo) {
// Convert registers in the addr mode according to subreg64.
for (unsigned i = 0; i != 4; ++i) {
if (!MI->getOperand(i).isReg()) continue;
unsigned Reg = MI->getOperand(i).getReg();
if (Reg == 0) continue;
MI->getOperand(i).setReg(getX86SubSuperRegister(Reg, MVT::i64));
}
}
/// 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;
if (NewAsmPrinter) {
if (MI->getOpcode() == TargetInstrInfo::INLINEASM) {
O << "\t";
printInlineAsm(MI);
return;
} else if (MI->isLabel()) {
printLabel(MI);
return;
} else if (MI->getOpcode() == TargetInstrInfo::DECLARE) {
printDeclare(MI);
return;
} else if (MI->getOpcode() == TargetInstrInfo::IMPLICIT_DEF) {
printImplicitDef(MI);
return;
}
O << "NEW: ";
TmpInst.setOpcode(MI->getOpcode());
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
MCOperand MCOp;
if (MO.isReg()) {
MCOp.MakeReg(MO.getReg());
} else if (MO.isImm()) {
MCOp.MakeImm(MO.getImm());
} else if (MO.isMBB()) {
MCOp.MakeMBBLabel(getFunctionNumber(), MO.getMBB()->getNumber());
} else {
assert(0 && "Unimp");
}
TmpInst.addOperand(MCOp);
}
switch (TmpInst.getOpcode()) {
case X86::LEA64_32r:
// Handle the 'subreg rewriting' for the lea64_32mem operand.
lower_lea64_32mem(&TmpInst, 1);
// FIXME: Convert TmpInst.
printInstruction(&TmpInst);
O << "OLD: ";
// Call the autogenerated instruction printer routines.
printInstruction(MI);
}
/// doInitialization
bool X86ATTAsmPrinter::doInitialization(Module &M) {
if (NewAsmPrinter) {
Context = new MCContext();
// FIXME: Send this to "O" instead of outs(). For now, we force it to
// stdout to make it easy to compare.
Streamer = createAsmStreamer(*Context, outs());
}
void X86ATTAsmPrinter::printModuleLevelGV(const GlobalVariable* GVar) {
const TargetData *TD = TM.getTargetData();
if (!GVar->hasInitializer())
return; // External global require no code
// Check to see if this is a special global used by LLVM, if so, emit it.
if (EmitSpecialLLVMGlobal(GVar)) {
if (Subtarget->isTargetDarwin() &&
TM.getRelocationModel() == Reloc::Static) {
if (GVar->getName() == "llvm.global_ctors")
O << ".reference .constructors_used\n";
else if (GVar->getName() == "llvm.global_dtors")
O << ".reference .destructors_used\n";
return;
}
std::string name = Mang->getValueName(GVar);
Constant *C = GVar->getInitializer();
const Type *Type = C->getType();
unsigned Size = TD->getTypeAllocSize(Type);
unsigned Align = TD->getPreferredAlignmentLog(GVar);
Anton Korobeynikov
committed
printVisibility(name, GVar->getVisibility());
if (Subtarget->isTargetELF())
O << "\t.type\t" << name << ",@object\n";
Anton Korobeynikov
committed
SwitchToSection(TAI->SectionForGlobal(GVar));
if (C->isNullValue() && !GVar->hasSection() &&
!(Subtarget->isTargetDarwin() &&
TAI->SectionKindForGlobal(GVar) == SectionKind::RODataMergeStr)) {
// FIXME: This seems to be pretty darwin-specific
if (GVar->hasExternalLinkage()) {
if (const char *Directive = TAI->getZeroFillDirective()) {
O << "\t.globl " << name << '\n';
O << Directive << "__DATA, __common, " << name << ", "
<< Size << ", " << Align << '\n';
if (!GVar->isThreadLocal() &&
(GVar->hasLocalLinkage() || GVar->isWeakForLinker())) {
if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
if (TAI->getLCOMMDirective() != NULL) {
O << TAI->getLCOMMDirective() << name << ',' << Size;
if (Subtarget->isTargetDarwin())
O << ',' << Align;
} else if (Subtarget->isTargetDarwin() && !GVar->hasCommonLinkage()) {
O << "\t.globl " << name << '\n'
<< TAI->getWeakDefDirective() << name << '\n';
EmitAlignment(Align, GVar);
O << name << ":";
if (VerboseAsm) {
O << "\t\t\t\t" << TAI->getCommentString() << ' ';
PrintUnmangledNameSafely(GVar, O);