mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-15 04:08:07 +00:00
dc024674ff
the function type, instead they belong to functions and function calls. This is an updated and slightly corrected version of Reid Spencer's original patch. The only known problem is that auto-upgrading of bitcode files doesn't seem to work properly (see test/Bitcode/AutoUpgradeIntrinsics.ll). Hopefully a bitcode guru (who might that be? :) ) will fix it. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@44359 91177308-0d34-0410-b5e6-96231b3b80d8
418 lines
15 KiB
C++
418 lines
15 KiB
C++
//===-- X86AsmPrinter.cpp - Convert X86 LLVM IR to X86 assembly -----------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file was developed by the LLVM research group and 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/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;
|
|
}
|
|
|
|
for (Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end();
|
|
AI != AE; ++AI)
|
|
// Size should be aligned to DWORD boundary
|
|
Size += ((TD->getABITypeSize(AI->getType()) + 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->isStructReturn()))
|
|
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->isStructReturn()))
|
|
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;
|
|
}
|
|
|
|
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\t" << 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;
|
|
} 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() << " " << I->getName() << "\n";
|
|
continue;
|
|
}
|
|
}
|
|
|
|
switch (I->getLinkage()) {
|
|
case GlobalValue::LinkOnceLinkage:
|
|
case GlobalValue::WeakLinkage:
|
|
if (Subtarget->isTargetDarwin()) {
|
|
O << "\t.globl\t" << name << "\n"
|
|
<< TAI->getWeakDefDirective() << name << "\n";
|
|
SwitchToDataSection(".section __DATA,__const_coal,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\t" << 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 (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() << " " << I->getName()
|
|
<< "\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(".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 (ExceptionHandling && TAI->doesSupportExceptionHandling() && MMI) {
|
|
// Add the (possibly multiple) personalities to the set of global values.
|
|
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(
|
|
".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());
|
|
}
|
|
}
|