mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-17 18:31:04 +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
448 lines
16 KiB
C++
448 lines
16 KiB
C++
//===-- X86AsmPrinter.cpp - Convert X86 LLVM IR to X86 assembly -----------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file the shared super class printer that converts from our internal
|
|
// representation of machine-dependent LLVM code to Intel and AT&T format
|
|
// assembly language.
|
|
// This printer is the output mechanism used by `llc'.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "X86AsmPrinter.h"
|
|
#include "X86ATTAsmPrinter.h"
|
|
#include "X86COFF.h"
|
|
#include "X86IntelAsmPrinter.h"
|
|
#include "X86MachineFunctionInfo.h"
|
|
#include "X86Subtarget.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/CallingConv.h"
|
|
#include "llvm/Constants.h"
|
|
#include "llvm/Module.h"
|
|
#include "llvm/DerivedTypes.h"
|
|
#include "llvm/ParameterAttributes.h"
|
|
#include "llvm/Type.h"
|
|
#include "llvm/Assembly/Writer.h"
|
|
#include "llvm/Support/Mangler.h"
|
|
#include "llvm/Target/TargetAsmInfo.h"
|
|
#include "llvm/Target/TargetOptions.h"
|
|
using namespace llvm;
|
|
|
|
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
|
|
if (F->paramHasAttr(argNum, ParamAttr::ByVal))
|
|
Ty = cast<PointerType>(Ty)->getElementType();
|
|
|
|
// Size should be aligned to DWORD boundary
|
|
Size += ((TD->getABITypeSize(Ty) + 3)/4)*4;
|
|
}
|
|
|
|
// We're not supporting tooooo huge arguments :)
|
|
Info.setBytesToPopOnReturn((unsigned int)Size);
|
|
return Info;
|
|
}
|
|
|
|
|
|
/// decorateName - Query FunctionInfoMap and use this information for various
|
|
/// name decoration.
|
|
void X86SharedAsmPrinter::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");
|
|
}
|
|
}
|
|
|
|
/// doInitialization
|
|
bool X86SharedAsmPrinter::doInitialization(Module &M) {
|
|
if (TAI->doesSupportDebugInformation()) {
|
|
// Emit initial debug information.
|
|
DW.BeginModule(&M);
|
|
}
|
|
|
|
bool Result = AsmPrinter::doInitialization(M);
|
|
|
|
// Darwin wants symbols to be quoted if they have complex names.
|
|
if (Subtarget->isTargetDarwin())
|
|
Mang->setUseQuotes(true);
|
|
|
|
return Result;
|
|
}
|
|
|
|
/// PrintUnmangledNameSafely - Print out the printable characters in the name.
|
|
/// Don't print things like \n or \0.
|
|
static void PrintUnmangledNameSafely(const Value *V, std::ostream &OS) {
|
|
for (const char *Name = V->getNameStart(), *E = Name+V->getNameLen();
|
|
Name != E; ++Name)
|
|
if (isprint(*Name))
|
|
OS << *Name;
|
|
}
|
|
|
|
bool X86SharedAsmPrinter::doFinalization(Module &M) {
|
|
// Note: this code is not shared by the Intel printer as it is too different
|
|
// from how MASM does things. When making changes here don't forget to look
|
|
// at X86IntelAsmPrinter::doFinalization().
|
|
const TargetData *TD = TM.getTargetData();
|
|
|
|
// Print out module-level global variables here.
|
|
for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
|
|
I != E; ++I) {
|
|
if (!I->hasInitializer())
|
|
continue; // External global require no code
|
|
|
|
// Check to see if this is a special global used by LLVM, if so, emit it.
|
|
if (EmitSpecialLLVMGlobal(I)) {
|
|
if (Subtarget->isTargetDarwin() &&
|
|
TM.getRelocationModel() == Reloc::Static) {
|
|
if (I->getName() == "llvm.global_ctors")
|
|
O << ".reference .constructors_used\n";
|
|
else if (I->getName() == "llvm.global_dtors")
|
|
O << ".reference .destructors_used\n";
|
|
}
|
|
continue;
|
|
}
|
|
|
|
std::string name = Mang->getValueName(I);
|
|
Constant *C = I->getInitializer();
|
|
const Type *Type = C->getType();
|
|
unsigned Size = TD->getABITypeSize(Type);
|
|
unsigned Align = TD->getPreferredAlignmentLog(I);
|
|
|
|
if (I->hasHiddenVisibility()) {
|
|
if (const char *Directive = TAI->getHiddenDirective())
|
|
O << Directive << name << "\n";
|
|
} else if (I->hasProtectedVisibility()) {
|
|
if (const char *Directive = TAI->getProtectedDirective())
|
|
O << Directive << name << "\n";
|
|
}
|
|
|
|
if (Subtarget->isTargetELF())
|
|
O << "\t.type\t" << name << ",@object\n";
|
|
|
|
if (C->isNullValue() && !I->hasSection()) {
|
|
if (I->hasExternalLinkage()) {
|
|
if (const char *Directive = TAI->getZeroFillDirective()) {
|
|
O << "\t.globl " << name << "\n";
|
|
O << Directive << "__DATA, __common, " << name << ", "
|
|
<< Size << ", " << Align << "\n";
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!I->isThreadLocal() &&
|
|
(I->hasInternalLinkage() || I->hasWeakLinkage() ||
|
|
I->hasLinkOnceLinkage())) {
|
|
if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
|
|
if (!NoZerosInBSS && TAI->getBSSSection())
|
|
SwitchToDataSection(TAI->getBSSSection(), I);
|
|
else
|
|
SwitchToDataSection(TAI->getDataSection(), I);
|
|
if (TAI->getLCOMMDirective() != NULL) {
|
|
if (I->hasInternalLinkage()) {
|
|
O << TAI->getLCOMMDirective() << name << "," << Size;
|
|
if (Subtarget->isTargetDarwin())
|
|
O << "," << Align;
|
|
} else {
|
|
O << TAI->getCOMMDirective() << name << "," << Size;
|
|
|
|
// Leopard and above support aligned common symbols.
|
|
if (Subtarget->getDarwinVers() >= 9)
|
|
O << "," << Align;
|
|
}
|
|
} else {
|
|
if (!Subtarget->isTargetCygMing()) {
|
|
if (I->hasInternalLinkage())
|
|
O << "\t.local\t" << name << "\n";
|
|
}
|
|
O << TAI->getCOMMDirective() << name << "," << Size;
|
|
if (TAI->getCOMMDirectiveTakesAlignment())
|
|
O << "," << (TAI->getAlignmentIsInBytes() ? (1 << Align) : Align);
|
|
}
|
|
O << "\t\t" << TAI->getCommentString() << " ";
|
|
PrintUnmangledNameSafely(I, O);
|
|
O << "\n";
|
|
continue;
|
|
}
|
|
}
|
|
|
|
switch (I->getLinkage()) {
|
|
case GlobalValue::LinkOnceLinkage:
|
|
case GlobalValue::WeakLinkage:
|
|
if (Subtarget->isTargetDarwin()) {
|
|
O << "\t.globl " << name << "\n"
|
|
<< TAI->getWeakDefDirective() << name << "\n";
|
|
SwitchToDataSection("\t.section __DATA,__datacoal_nt,coalesced", I);
|
|
} else if (Subtarget->isTargetCygMing()) {
|
|
std::string SectionName(".section\t.data$linkonce." +
|
|
name +
|
|
",\"aw\"");
|
|
SwitchToDataSection(SectionName.c_str(), I);
|
|
O << "\t.globl\t" << name << "\n"
|
|
<< "\t.linkonce same_size\n";
|
|
} else {
|
|
std::string SectionName("\t.section\t.llvm.linkonce.d." +
|
|
name +
|
|
",\"aw\",@progbits");
|
|
SwitchToDataSection(SectionName.c_str(), I);
|
|
O << "\t.weak\t" << name << "\n";
|
|
}
|
|
break;
|
|
case GlobalValue::DLLExportLinkage:
|
|
DLLExportedGVs.insert(Mang->makeNameProper(I->getName(),""));
|
|
// FALL THROUGH
|
|
case GlobalValue::AppendingLinkage:
|
|
// FIXME: appending linkage variables should go into a section of
|
|
// their name or something. For now, just emit them as external.
|
|
case GlobalValue::ExternalLinkage:
|
|
// If external or appending, declare as a global symbol
|
|
O << "\t.globl " << name << "\n";
|
|
// FALL THROUGH
|
|
case GlobalValue::InternalLinkage: {
|
|
if (I->isConstant()) {
|
|
const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
|
|
if (TAI->getCStringSection() && CVA && CVA->isCString()) {
|
|
SwitchToDataSection(TAI->getCStringSection(), I);
|
|
break;
|
|
}
|
|
}
|
|
// FIXME: special handling for ".ctors" & ".dtors" sections
|
|
if (I->hasSection() &&
|
|
(I->getSection() == ".ctors" ||
|
|
I->getSection() == ".dtors")) {
|
|
std::string SectionName = ".section " + I->getSection();
|
|
|
|
if (Subtarget->isTargetCygMing()) {
|
|
SectionName += ",\"aw\"";
|
|
} else {
|
|
assert(!Subtarget->isTargetDarwin());
|
|
SectionName += ",\"aw\",@progbits";
|
|
}
|
|
SwitchToDataSection(SectionName.c_str());
|
|
} else if (I->hasSection() && Subtarget->isTargetDarwin()) {
|
|
// Honor all section names on Darwin; ObjC uses this
|
|
std::string SectionName = ".section " + I->getSection();
|
|
SwitchToDataSection(SectionName.c_str());
|
|
} else {
|
|
if (C->isNullValue() && !NoZerosInBSS && TAI->getBSSSection())
|
|
SwitchToDataSection(I->isThreadLocal() ? TAI->getTLSBSSSection() :
|
|
TAI->getBSSSection(), I);
|
|
else if (!I->isConstant())
|
|
SwitchToDataSection(I->isThreadLocal() ? TAI->getTLSDataSection() :
|
|
TAI->getDataSection(), I);
|
|
else if (I->isThreadLocal())
|
|
SwitchToDataSection(TAI->getTLSDataSection());
|
|
else {
|
|
// Read-only data.
|
|
bool HasReloc = C->ContainsRelocations();
|
|
if (HasReloc &&
|
|
Subtarget->isTargetDarwin() &&
|
|
TM.getRelocationModel() != Reloc::Static)
|
|
SwitchToDataSection("\t.const_data\n");
|
|
else if (!HasReloc && Size == 4 &&
|
|
TAI->getFourByteConstantSection())
|
|
SwitchToDataSection(TAI->getFourByteConstantSection(), I);
|
|
else if (!HasReloc && Size == 8 &&
|
|
TAI->getEightByteConstantSection())
|
|
SwitchToDataSection(TAI->getEightByteConstantSection(), I);
|
|
else if (!HasReloc && Size == 16 &&
|
|
TAI->getSixteenByteConstantSection())
|
|
SwitchToDataSection(TAI->getSixteenByteConstantSection(), I);
|
|
else if (TAI->getReadOnlySection())
|
|
SwitchToDataSection(TAI->getReadOnlySection(), I);
|
|
else
|
|
SwitchToDataSection(TAI->getDataSection(), I);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
assert(0 && "Unknown linkage type!");
|
|
}
|
|
|
|
EmitAlignment(Align, I);
|
|
O << name << ":\t\t\t\t" << TAI->getCommentString() << " ";
|
|
PrintUnmangledNameSafely(I, O);
|
|
O << "\n";
|
|
if (TAI->hasDotTypeDotSizeDirective())
|
|
O << "\t.size\t" << name << ", " << Size << "\n";
|
|
// If the initializer is a extern weak symbol, remember to emit the weak
|
|
// reference!
|
|
if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
|
|
if (GV->hasExternalWeakLinkage())
|
|
ExtWeakSymbols.insert(GV);
|
|
|
|
EmitGlobalConstant(C);
|
|
}
|
|
|
|
// Output linker support code for dllexported globals
|
|
if (!DLLExportedGVs.empty()) {
|
|
SwitchToDataSection(".section .drectve");
|
|
}
|
|
|
|
for (std::set<std::string>::iterator i = DLLExportedGVs.begin(),
|
|
e = DLLExportedGVs.end();
|
|
i != e; ++i) {
|
|
O << "\t.ascii \" -export:" << *i << ",data\"\n";
|
|
}
|
|
|
|
if (!DLLExportedFns.empty()) {
|
|
SwitchToDataSection(".section .drectve");
|
|
}
|
|
|
|
for (std::set<std::string>::iterator i = DLLExportedFns.begin(),
|
|
e = DLLExportedFns.end();
|
|
i != e; ++i) {
|
|
O << "\t.ascii \" -export:" << *i << "\"\n";
|
|
}
|
|
|
|
if (Subtarget->isTargetDarwin()) {
|
|
SwitchToDataSection("");
|
|
|
|
// Output stubs for dynamically-linked functions
|
|
unsigned j = 1;
|
|
for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
|
|
i != e; ++i, ++j) {
|
|
SwitchToDataSection("\t.section __IMPORT,__jump_table,symbol_stubs,"
|
|
"self_modifying_code+pure_instructions,5", 0);
|
|
O << "L" << *i << "$stub:\n";
|
|
O << "\t.indirect_symbol " << *i << "\n";
|
|
O << "\thlt ; hlt ; hlt ; hlt ; hlt\n";
|
|
}
|
|
|
|
O << "\n";
|
|
|
|
if (TAI->doesSupportExceptionHandling() && MMI && !Subtarget->is64Bit()) {
|
|
// Add the (possibly multiple) personalities to the set of global values.
|
|
// Only referenced functions get into the Personalities list.
|
|
const std::vector<Function *>& Personalities = MMI->getPersonalities();
|
|
|
|
for (std::vector<Function *>::const_iterator I = Personalities.begin(),
|
|
E = Personalities.end(); I != E; ++I)
|
|
if (*I) GVStubs.insert("_" + (*I)->getName());
|
|
}
|
|
|
|
// Output stubs for external and common global variables.
|
|
if (!GVStubs.empty())
|
|
SwitchToDataSection(
|
|
"\t.section __IMPORT,__pointers,non_lazy_symbol_pointers");
|
|
for (std::set<std::string>::iterator i = GVStubs.begin(), e = GVStubs.end();
|
|
i != e; ++i) {
|
|
O << "L" << *i << "$non_lazy_ptr:\n";
|
|
O << "\t.indirect_symbol " << *i << "\n";
|
|
O << "\t.long\t0\n";
|
|
}
|
|
|
|
// Emit final debug information.
|
|
DW.EndModule();
|
|
|
|
// 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.
|
|
O << "\t.subsections_via_symbols\n";
|
|
} else if (Subtarget->isTargetCygMing()) {
|
|
// Emit type information for external functions
|
|
for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
|
|
i != e; ++i) {
|
|
O << "\t.def\t " << *i
|
|
<< ";\t.scl\t" << COFF::C_EXT
|
|
<< ";\t.type\t" << (COFF::DT_FCN << COFF::N_BTSHFT)
|
|
<< ";\t.endef\n";
|
|
}
|
|
|
|
// Emit final debug information.
|
|
DW.EndModule();
|
|
} else if (Subtarget->isTargetELF()) {
|
|
// Emit final debug information.
|
|
DW.EndModule();
|
|
}
|
|
|
|
return AsmPrinter::doFinalization(M);
|
|
}
|
|
|
|
/// createX86CodePrinterPass - Returns a pass that prints the X86 assembly code
|
|
/// for a MachineFunction to the given output stream, using the given target
|
|
/// machine description.
|
|
///
|
|
FunctionPass *llvm::createX86CodePrinterPass(std::ostream &o,
|
|
X86TargetMachine &tm) {
|
|
const X86Subtarget *Subtarget = &tm.getSubtarget<X86Subtarget>();
|
|
|
|
if (Subtarget->isFlavorIntel()) {
|
|
return new X86IntelAsmPrinter(o, tm, tm.getTargetAsmInfo());
|
|
} else {
|
|
return new X86ATTAsmPrinter(o, tm, tm.getTargetAsmInfo());
|
|
}
|
|
}
|