mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 07:30:43 +03:00
Added -float-abi and auto-detection logic for ARM.
Even though this argument design conflates two separate concepts (ABI and hardware/software implementation), I chose to go with it since users are liekly know it from GCC and the combination of softloat operations with hardfloat ABI makes no sense. I didn't implement it for old LLVM versions, as ARM EABI exception handling requires LLVM 3.3+ anyway, without which LDC would be useless anyway.
This commit is contained in:
parent
2fb8d6d51b
commit
6a1bc70bd7
5 changed files with 189 additions and 7 deletions
|
@ -310,6 +310,16 @@ cl::opt<llvm::CodeModel::Model> mCodeModel("code-model",
|
|||
clEnumValN(llvm::CodeModel::Large, "large", "Large code model"),
|
||||
clEnumValEnd));
|
||||
|
||||
cl::opt<FloatABI::Type> mFloatABI("float-abi",
|
||||
cl::desc("ABI/operations to use for floating-point types:"),
|
||||
cl::init(FloatABI::Default),
|
||||
cl::values(
|
||||
clEnumValN(FloatABI::Default, "default", "Target default floating-point ABI"),
|
||||
clEnumValN(FloatABI::Soft, "soft", "Software floating-point ABI and operations"),
|
||||
clEnumValN(FloatABI::SoftFP, "softfp", "Soft-float ABI, but hardware floating-point instructions"),
|
||||
clEnumValN(FloatABI::Hard, "hard", "Hardware floating-point ABI and instructions"),
|
||||
clEnumValEnd));
|
||||
|
||||
static cl::opt<bool, true, FlagParser> asserts("asserts",
|
||||
cl::desc("(*) Enable assertions"),
|
||||
cl::value_desc("bool"),
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define LDC_DRIVER_CL_OPTIONS_H
|
||||
|
||||
#include "mars.h"
|
||||
#include "driver/target.h"
|
||||
#include "llvm/Support/CodeGen.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include <deque>
|
||||
|
@ -60,6 +61,7 @@ namespace opts {
|
|||
extern cl::opt<std::string> mTargetTriple;
|
||||
extern cl::opt<llvm::Reloc::Model> mRelocModel;
|
||||
extern cl::opt<llvm::CodeModel::Model> mCodeModel;
|
||||
extern cl::opt<FloatABI::Type> mFloatABI;
|
||||
extern cl::opt<bool, true> singleObj;
|
||||
extern cl::opt<bool> linkonceTemplates;
|
||||
|
||||
|
|
|
@ -459,8 +459,9 @@ int main(int argc, char** argv)
|
|||
if (global.errors)
|
||||
fatal();
|
||||
|
||||
gTargetMachine = createTargetMachine(mTargetTriple, mArch, mCPU, mAttrs, bitness,
|
||||
mRelocModel, mCodeModel, codeGenOptLevel(), global.params.symdebug);
|
||||
gTargetMachine = createTargetMachine(mTargetTriple, mArch, mCPU, mAttrs,
|
||||
bitness, mFloatABI, mRelocModel, mCodeModel, codeGenOptLevel(),
|
||||
global.params.symdebug);
|
||||
global.params.targetTriple = llvm::Triple(gTargetMachine->getTargetTriple());
|
||||
|
||||
#if LDC_LLVM_VER >= 302
|
||||
|
|
|
@ -7,13 +7,15 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Note: The target CPU detection logic has been adapted from Clang
|
||||
// (lib/Driver/Tools.cpp).
|
||||
// Note: The target CPU and FP ABI detection logic has been adapted from Clang
|
||||
// (Tools.cpp and ToolChain.cpp in lib/Driver, the latter seems to have the
|
||||
// more up-to-date version).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "driver/target.h"
|
||||
#include "gen/llvmcompat.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/MC/SubtargetFeature.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
|
@ -23,7 +25,6 @@
|
|||
#include "llvm/Target/TargetOptions.h"
|
||||
#include "mars.h"
|
||||
|
||||
|
||||
static std::string getX86TargetCPU(std::string arch,
|
||||
const llvm::Triple &triple)
|
||||
{
|
||||
|
@ -74,12 +75,130 @@ static std::string getX86TargetCPU(std::string arch,
|
|||
}
|
||||
|
||||
|
||||
static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU)
|
||||
{
|
||||
return llvm::StringSwitch<const char *>(CPU)
|
||||
.Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t")
|
||||
.Cases("arm720t", "arm9", "arm9tdmi", "v4t")
|
||||
.Cases("arm920", "arm920t", "arm922t", "v4t")
|
||||
.Cases("arm940t", "ep9312","v4t")
|
||||
.Cases("arm10tdmi", "arm1020t", "v5")
|
||||
.Cases("arm9e", "arm926ej-s", "arm946e-s", "v5e")
|
||||
.Cases("arm966e-s", "arm968e-s", "arm10e", "v5e")
|
||||
.Cases("arm1020e", "arm1022e", "xscale", "iwmmxt", "v5e")
|
||||
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
|
||||
.Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
|
||||
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
|
||||
.Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
|
||||
.Cases("cortex-a9", "cortex-a15", "v7")
|
||||
.Case("cortex-r5", "v7r")
|
||||
.Case("cortex-m0", "v6m")
|
||||
.Case("cortex-m3", "v7m")
|
||||
.Case("cortex-m4", "v7em")
|
||||
.Case("cortex-a9-mp", "v7f")
|
||||
.Case("swift", "v7s")
|
||||
.Default("");
|
||||
}
|
||||
|
||||
static std::string getARMTargetCPU(std::string arch, const llvm::Triple &triple)
|
||||
{
|
||||
// FIXME: Warn on inconsistent use of -mcpu and -march.
|
||||
|
||||
llvm::StringRef MArch;
|
||||
if (!arch.empty()) {
|
||||
// Otherwise, if we have -march= choose the base CPU for that arch.
|
||||
MArch = arch;
|
||||
} else {
|
||||
// Otherwise, use the Arch from the triple.
|
||||
MArch = triple.getArchName();
|
||||
}
|
||||
|
||||
// Handle -march=native.
|
||||
std::string NativeMArch;
|
||||
if (MArch == "native") {
|
||||
std::string CPU = llvm::sys::getHostCPUName();
|
||||
if (CPU != "generic") {
|
||||
// Translate the native cpu into the architecture. The switch below will
|
||||
// then chose the minimum cpu for that arch.
|
||||
NativeMArch = std::string("arm") + getLLVMArchSuffixForARM(CPU);
|
||||
MArch = NativeMArch;
|
||||
}
|
||||
}
|
||||
|
||||
return llvm::StringSwitch<const char *>(MArch)
|
||||
.Cases("armv2", "armv2a","arm2")
|
||||
.Case("armv3", "arm6")
|
||||
.Case("armv3m", "arm7m")
|
||||
.Cases("armv4", "armv4t", "arm7tdmi")
|
||||
.Cases("armv5", "armv5t", "arm10tdmi")
|
||||
.Cases("armv5e", "armv5te", "arm1026ejs")
|
||||
.Case("armv5tej", "arm926ej-s")
|
||||
.Cases("armv6", "armv6k", "arm1136jf-s")
|
||||
.Case("armv6j", "arm1136j-s")
|
||||
.Cases("armv6z", "armv6zk", "arm1176jzf-s")
|
||||
.Case("armv6t2", "arm1156t2-s")
|
||||
.Cases("armv6m", "armv6-m", "cortex-m0")
|
||||
.Cases("armv7", "armv7a", "armv7-a", "cortex-a8")
|
||||
.Cases("armv7l", "armv7-l", "cortex-a8")
|
||||
.Cases("armv7f", "armv7-f", "cortex-a9-mp")
|
||||
.Cases("armv7s", "armv7-s", "swift")
|
||||
.Cases("armv7r", "armv7-r", "cortex-r4")
|
||||
.Cases("armv7m", "armv7-m", "cortex-m3")
|
||||
.Cases("armv7em", "armv7e-m", "cortex-m4")
|
||||
.Case("ep9312", "ep9312")
|
||||
.Case("iwmmxt", "iwmmxt")
|
||||
.Case("xscale", "xscale")
|
||||
// If all else failed, return the most base CPU LLVM supports.
|
||||
.Default("arm7tdmi");
|
||||
}
|
||||
|
||||
static FloatABI::Type getARMFloatABI(const llvm::Triple &triple,
|
||||
const char* llvmArchSuffix)
|
||||
{
|
||||
switch (triple.getOS()) {
|
||||
case llvm::Triple::Darwin:
|
||||
case llvm::Triple::MacOSX:
|
||||
case llvm::Triple::IOS: {
|
||||
// Darwin defaults to "softfp" for v6 and v7.
|
||||
if (llvm::StringRef(llvmArchSuffix).startswith("v6") ||
|
||||
llvm::StringRef(llvmArchSuffix).startswith("v7"))
|
||||
return FloatABI::SoftFP;
|
||||
return FloatABI::Soft;
|
||||
}
|
||||
|
||||
case llvm::Triple::FreeBSD:
|
||||
// FreeBSD defaults to soft float
|
||||
return FloatABI::Soft;
|
||||
|
||||
default:
|
||||
switch(triple.getEnvironment()) {
|
||||
case llvm::Triple::GNUEABIHF:
|
||||
return FloatABI::Hard;
|
||||
case llvm::Triple::GNUEABI:
|
||||
return FloatABI::SoftFP;
|
||||
case llvm::Triple::EABI:
|
||||
// EABI is always AAPCS, and if it was not marked 'hard', it's softfp
|
||||
return FloatABI::SoftFP;
|
||||
case llvm::Triple::Android: {
|
||||
if (llvm::StringRef(llvmArchSuffix).startswith("v7"))
|
||||
return FloatABI::SoftFP;
|
||||
return FloatABI::Soft;
|
||||
}
|
||||
default:
|
||||
// Assume "soft", but warn the user we are guessing.
|
||||
return FloatABI::SoftFP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
llvm::TargetMachine* createTargetMachine(
|
||||
std::string targetTriple,
|
||||
std::string arch,
|
||||
std::string cpu,
|
||||
std::vector<std::string> attrs,
|
||||
ExplicitBitness::Type bitness,
|
||||
FloatABI::Type floatABI,
|
||||
llvm::Reloc::Model relocModel,
|
||||
llvm::CodeModel::Model codeModel,
|
||||
llvm::CodeGenOpt::Level codeGenOptLevel,
|
||||
|
@ -159,10 +278,16 @@ llvm::TargetMachine* createTargetMachine(
|
|||
// to default to "generic").
|
||||
if (cpu.empty())
|
||||
{
|
||||
if (triple.getArch() == llvm::Triple::x86_64 ||
|
||||
triple.getArch() == llvm::Triple::x86)
|
||||
switch (triple.getArch())
|
||||
{
|
||||
default: break;
|
||||
case llvm::Triple::x86:
|
||||
case llvm::Triple::x86_64:
|
||||
cpu = getX86TargetCPU(arch, triple);
|
||||
break;
|
||||
case llvm::Triple::arm:
|
||||
cpu = getARMTargetCPU(arch, triple);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,8 +301,25 @@ llvm::TargetMachine* createTargetMachine(
|
|||
FeaturesStr = Features.getString();
|
||||
}
|
||||
|
||||
if (floatABI == FloatABI::Default)
|
||||
{
|
||||
switch (triple.getArch())
|
||||
{
|
||||
default: // X86, ...
|
||||
floatABI = FloatABI::Hard;
|
||||
break;
|
||||
case llvm::Triple::arm:
|
||||
floatABI = getARMFloatABI(triple, getLLVMArchSuffixForARM(cpu));
|
||||
break;
|
||||
case llvm::Triple::thumb:
|
||||
floatABI = FloatABI::Soft;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if LDC_LLVM_VER == 300
|
||||
llvm::NoFramePointerElim = genDebugInfo;
|
||||
// FIXME: Handle floating-point ABI.
|
||||
|
||||
return theTarget->createTargetMachine(triple.str(), cpu, FeaturesStr,
|
||||
relocModel, codeModel);
|
||||
|
@ -185,6 +327,23 @@ llvm::TargetMachine* createTargetMachine(
|
|||
llvm::TargetOptions targetOptions;
|
||||
targetOptions.NoFramePointerElim = genDebugInfo;
|
||||
|
||||
switch (floatABI)
|
||||
{
|
||||
default: llvm_unreachable("Floating point ABI type unknown.");
|
||||
case FloatABI::Soft:
|
||||
targetOptions.UseSoftFloat = true;
|
||||
targetOptions.FloatABIType = llvm::FloatABI::Soft;
|
||||
break;
|
||||
case FloatABI::SoftFP:
|
||||
targetOptions.UseSoftFloat = false;
|
||||
targetOptions.FloatABIType = llvm::FloatABI::Soft;
|
||||
break;
|
||||
case FloatABI::Hard:
|
||||
targetOptions.UseSoftFloat = false;
|
||||
targetOptions.FloatABIType = llvm::FloatABI::Hard;
|
||||
break;
|
||||
}
|
||||
|
||||
return theTarget->createTargetMachine(
|
||||
triple.str(),
|
||||
cpu,
|
||||
|
|
|
@ -30,6 +30,15 @@ namespace ExplicitBitness {
|
|||
};
|
||||
}
|
||||
|
||||
namespace FloatABI {
|
||||
enum Type {
|
||||
Default,
|
||||
Soft,
|
||||
SoftFP,
|
||||
Hard
|
||||
};
|
||||
}
|
||||
|
||||
namespace llvm { class TargetMachine; }
|
||||
|
||||
/**
|
||||
|
@ -44,6 +53,7 @@ llvm::TargetMachine* createTargetMachine(
|
|||
std::string cpu,
|
||||
std::vector<std::string> attrs,
|
||||
ExplicitBitness::Type bitness,
|
||||
FloatABI::Type floatABI,
|
||||
llvm::Reloc::Model relocModel,
|
||||
llvm::CodeModel::Model codeModel,
|
||||
llvm::CodeGenOpt::Level codeGenOptLevel,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue