From b2b56203a96ba191f57e37e3c3d32d5278ae9f6c Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 01:01:19 +0200 Subject: [PATCH 01/14] Use llvm::Triple::isArch64Bit (LLVM 3.1+). --- driver/main.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/driver/main.cpp b/driver/main.cpp index eb8901c8..c218474a 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -637,15 +637,18 @@ int main(int argc, char **argv) gTargetMachine = createTargetMachine(mTargetTriple, mArch, mCPU, mAttrs, bitness, mRelocModel, mCodeModel, codeGenOptLevel(), global.params.symdebug); - llvm::Triple targetTriple = llvm::Triple(gTargetMachine->getTargetTriple()); - global.params.targetTriple = targetTriple; - global.params.trace = false; - global.params.isLinux = targetTriple.getOS() == llvm::Triple::Linux; - global.params.isOSX = targetTriple.isMacOSX(); - global.params.isWindows = targetTriple.isOSWindows(); - global.params.isFreeBSD = targetTriple.getOS() == llvm::Triple::FreeBSD; - global.params.isOpenBSD = targetTriple.getOS() == llvm::Triple::OpenBSD; - global.params.isSolaris = targetTriple.getOS() == llvm::Triple::Solaris; + + { + llvm::Triple triple = llvm::Triple(gTargetMachine->getTargetTriple()); + global.params.targetTriple = triple; + global.params.isLinux = triple.getOS() == llvm::Triple::Linux; + global.params.isOSX = triple.isMacOSX(); + global.params.isWindows = triple.isOSWindows(); + global.params.isFreeBSD = triple.getOS() == llvm::Triple::FreeBSD; + global.params.isOpenBSD = triple.getOS() == llvm::Triple::OpenBSD; + global.params.isSolaris = triple.getOS() == llvm::Triple::Solaris; + global.params.is64bit = triple.isArch64Bit(); + } #if LDC_LLVM_VER >= 302 gDataLayout = gTargetMachine->getDataLayout(); @@ -653,9 +656,6 @@ int main(int argc, char **argv) gDataLayout = gTargetMachine->getTargetData(); #endif - // Starting with LLVM 3.1 we could also use global.params.targetTriple.isArch64Bit(); - global.params.is64bit = gDataLayout->getPointerSizeInBits(ADDRESS_SPACE) == 64; - // Set predefined version identifiers. registerPredefinedVersions(); From 02abf028f8dcf1c6beb96ddfb1f4241b198c10f7 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 01:10:26 +0200 Subject: [PATCH 02/14] Don't require -triple when using -march. There is really no reason we should, and I couldn't find out why that check was added back in 2009. Also cleaned up the code a bit now that the LLVM 3.0 branches are gone. --- driver/targetmachine.cpp | 67 ++++++++++++---------------------------- 1 file changed, 19 insertions(+), 48 deletions(-) diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index 20b3ba29..830eeafb 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -83,66 +83,37 @@ llvm::TargetMachine* createTargetMachine( llvm::CodeGenOpt::Level codeGenOptLevel, bool genDebugInfo) { - // override triple if needed - std::string defaultTriple = llvm::sys::getDefaultTargetTriple(); - if (sizeof(void*) == 4 && bitness == ExplicitBitness::M64) - { - defaultTriple = llvm::Triple(defaultTriple).get64BitArchVariant().str(); - } - else if (sizeof(void*) == 8 && bitness == ExplicitBitness::M32) - { - defaultTriple = llvm::Triple(defaultTriple).get32BitArchVariant().str(); - } - + // Determine target triple. If the user didn't explicitly specify one, use + // the one set at LLVM configure time. llvm::Triple triple; - - // did the user override the target triple? if (targetTriple.empty()) { - if (!arch.empty()) + triple = llvm::Triple(llvm::sys::getDefaultTargetTriple()); + + // Handle -m32/-m64. + if (sizeof(void*) == 4 && bitness == ExplicitBitness::M64) { - error("you must specify a target triple as well with -mtriple when using the -arch option"); - fatal(); + triple = triple.get64BitArchVariant(); + } + else if (sizeof(void*) == 8 && bitness == ExplicitBitness::M32) + { + triple = triple.get32BitArchVariant(); } - triple = llvm::Triple(defaultTriple); } else { triple = llvm::Triple(llvm::Triple::normalize(targetTriple)); } - // Allocate target machine. - const llvm::Target *theTarget = NULL; - // Check whether the user has explicitly specified an architecture to compile for. - if (arch.empty()) + // Look up the LLVM backend to use. + std::string errMsg; + const llvm::Target *target = + llvm::TargetRegistry::lookupTarget(arch, triple, errMsg); + if (target == 0) { - std::string Err; - theTarget = llvm::TargetRegistry::lookupTarget(triple.str(), Err); - if (theTarget == 0) - { - error("%s Please use the -march option.", Err.c_str()); - fatal(); - } + error("%s", errMsg.c_str()); + fatal(); } - else - { - for (llvm::TargetRegistry::iterator it = llvm::TargetRegistry::begin(), - ie = llvm::TargetRegistry::end(); it != ie; ++it) - { - if (arch == it->getName()) - { - theTarget = &*it; - break; - } - } - - if (!theTarget) - { - error("invalid target '%s'", arch.c_str()); - fatal(); - } - } - // With an empty CPU string, LLVM will default to the host CPU, which is // usually not what we want (expected behavior from other compilers is @@ -176,7 +147,7 @@ llvm::TargetMachine* createTargetMachine( llvm::TargetOptions targetOptions; targetOptions.NoFramePointerElim = genDebugInfo; - return theTarget->createTargetMachine( + return target->createTargetMachine( triple.str(), cpu, FeaturesStr, From d17aa2aaaccc1af444e0f7c97cecf712cc1919ad Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 01:41:13 +0200 Subject: [PATCH 03/14] Disentangle -march and -mcpu. -mcpu=native now actually works. GitHub: Fixes #414. --- driver/targetmachine.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index 830eeafb..dfb339c5 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -23,14 +23,14 @@ #include "mars.h" -static std::string getX86TargetCPU(std::string arch, +static std::string getX86TargetCPU(const std::string &cpu, const llvm::Triple &triple) { - if (!arch.empty()) { - if (arch != "native") - return arch; + if (!cpu.empty()) { + if (cpu != "native") + return cpu; - // FIXME: Reject attempts to use -march=native unless the target matches + // FIXME: Reject attempts to use -mcpu=native unless the target matches // the host. // // FIXME: We should also incorporate the detected target features for use @@ -118,13 +118,10 @@ llvm::TargetMachine* createTargetMachine( // With an empty CPU string, LLVM will default to the host CPU, which is // usually not what we want (expected behavior from other compilers is // to default to "generic"). - if (cpu.empty()) + if (triple.getArch() == llvm::Triple::x86_64 || + triple.getArch() == llvm::Triple::x86) { - if (triple.getArch() == llvm::Triple::x86_64 || - triple.getArch() == llvm::Triple::x86) - { - cpu = getX86TargetCPU(arch, triple); - } + cpu = getX86TargetCPU(cpu, triple); } // Package up features to be passed to target/subtarget From e57d0458fb7de1f9ef723e3b3d6454875ed41879 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 01:41:46 +0200 Subject: [PATCH 04/14] getX86TargetCPU cleanup. --- driver/targetmachine.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index dfb339c5..a950c15e 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -28,7 +28,7 @@ static std::string getX86TargetCPU(const std::string &cpu, { if (!cpu.empty()) { if (cpu != "native") - return cpu; + return cpu; // FIXME: Reject attempts to use -mcpu=native unless the target matches // the host. @@ -37,18 +37,17 @@ static std::string getX86TargetCPU(const std::string &cpu, // with -native. std::string cpu = llvm::sys::getHostCPUName(); if (!cpu.empty() && cpu != "generic") - return cpu; + return cpu; } // Select the default CPU if none was given (or detection failed). - bool is64Bit = triple.getArch() == llvm::Triple::x86_64; - + // Intel Macs are relatively recent, take advantage of that. if (triple.isOSDarwin()) - return is64Bit ? "core2" : "yonah"; + return triple.isArch64Bit() ? "core2" : "yonah"; // Everything else goes to x86-64 in 64-bit mode. - if (is64Bit) + if (triple.isArch64Bit()) return "x86-64"; if (triple.getOSName().startswith("haiku")) From e9e4e100853b4b5e6405885c13dd23a292c7bdb9 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 02:37:31 +0200 Subject: [PATCH 05/14] Auto-detect target attributes for -mcpu=native. This is currently only implemented for ARM in LLVM. --- driver/targetmachine.cpp | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index a950c15e..770dbfcf 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -21,6 +21,7 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "mars.h" +#include "gen/logger.h" static std::string getX86TargetCPU(const std::string &cpu, @@ -32,9 +33,6 @@ static std::string getX86TargetCPU(const std::string &cpu, // FIXME: Reject attempts to use -mcpu=native unless the target matches // the host. - // - // FIXME: We should also incorporate the detected target features for use - // with -native. std::string cpu = llvm::sys::getHostCPUName(); if (!cpu.empty() && cpu != "generic") return cpu; @@ -114,6 +112,23 @@ llvm::TargetMachine* createTargetMachine( fatal(); } + // Package up features to be passed to target/subtarget. + llvm::SubtargetFeatures features; + features.getDefaultSubtargetFeatures(triple); + if (cpu == "native") + { + llvm::StringMap hostFeatures; + if (llvm::sys::getHostCPUFeatures(hostFeatures)) + { + llvm::StringMapConstIterator i = hostFeatures.begin(), + end = hostFeatures.end(); + for (; i != end; ++i) + features.AddFeature(i->first(), i->second); + } + } + for (unsigned i = 0; i < attrs.size(); ++i) + features.AddFeature(attrs[i]); + // With an empty CPU string, LLVM will default to the host CPU, which is // usually not what we want (expected behavior from other compilers is // to default to "generic"). @@ -123,14 +138,10 @@ llvm::TargetMachine* createTargetMachine( cpu = getX86TargetCPU(cpu, triple); } - // Package up features to be passed to target/subtarget - std::string FeaturesStr; - if (cpu.size() || attrs.size()) + if (Logger::enabled()) { - llvm::SubtargetFeatures Features; - for (unsigned i = 0; i != attrs.size(); ++i) - Features.AddFeature(attrs[i]); - FeaturesStr = Features.getString(); + Logger::cout() << "Targeting CPU '" << cpu << "' with features '" << + features.getString() << "'.\n"; } if (triple.isMacOSX() && relocModel == llvm::Reloc::Default) @@ -146,7 +157,7 @@ llvm::TargetMachine* createTargetMachine( return target->createTargetMachine( triple.str(), cpu, - FeaturesStr, + features.getString(), targetOptions, relocModel, codeModel, From 359f6c585abb04ad9e7df481fb1fd003e47a0670 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 03:07:04 +0200 Subject: [PATCH 06/14] CPU detection for ARM. This is not perfect yet, as lookupTarget wipes out any more specific arch info (e.g. armv8) the triple might have. --- driver/targetmachine.cpp | 90 ++++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 18 deletions(-) diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index 770dbfcf..3ff2baa2 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "driver/targetmachine.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Support/Host.h" @@ -24,20 +25,8 @@ #include "gen/logger.h" -static std::string getX86TargetCPU(const std::string &cpu, - const llvm::Triple &triple) +static std::string getX86TargetCPU(const llvm::Triple &triple) { - if (!cpu.empty()) { - if (cpu != "native") - return cpu; - - // FIXME: Reject attempts to use -mcpu=native unless the target matches - // the host. - std::string cpu = llvm::sys::getHostCPUName(); - if (!cpu.empty() && cpu != "generic") - return cpu; - } - // Select the default CPU if none was given (or detection failed). // Intel Macs are relatively recent, take advantage of that. @@ -69,6 +58,75 @@ static std::string getX86TargetCPU(const std::string &cpu, return "pentium4"; } +static std::string getARMTargetCPU(const llvm::Triple &triple) +{ + const char *result = llvm::StringSwitch(triple.getArchName()) + .Cases("armv2", "armv2a","arm2") + .Case("armv3", "arm6") + .Case("armv3m", "arm7m") + .Case("armv4", "strongarm") + .Case("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") + .Cases("armv8", "armv8a", "armv8-a", "cortex-a53") + .Case("ep9312", "ep9312") + .Case("iwmmxt", "iwmmxt") + .Case("xscale", "xscale") + // If all else failed, return the most base CPU with thumb interworking + // supported by LLVM. + .Default(0); + + if (result) + return result; + + return (triple.getEnvironment() == llvm::Triple::GNUEABIHF) ? + "arm1176jzf-s" : "arm7tdmi"; +} + +/// Returns the LLVM name of the target CPU to use given the provided +/// -mcpu argument and target triple. +static std::string getTargetCPU(const std::string &cpu, + const llvm::Triple &triple) +{ + if (!cpu.empty()) + { + if (cpu != "native") + return cpu; + + // FIXME: Reject attempts to use -mcpu=native unless the target matches + // the host. + std::string hostCPU = llvm::sys::getHostCPUName(); + if (!hostCPU.empty() && hostCPU != "generic") + return hostCPU; + } + + if (triple.getArch() == llvm::Triple::x86_64 || + triple.getArch() == llvm::Triple::x86) + { + return getX86TargetCPU(triple); + } + else if (triple.getArch() == llvm::Triple::arm) + { + return getARMTargetCPU(triple); + } + + return cpu; +} + + llvm::TargetMachine* createTargetMachine( std::string targetTriple, std::string arch, @@ -132,11 +190,7 @@ llvm::TargetMachine* createTargetMachine( // With an empty CPU string, LLVM will default to the host CPU, which is // usually not what we want (expected behavior from other compilers is // to default to "generic"). - if (triple.getArch() == llvm::Triple::x86_64 || - triple.getArch() == llvm::Triple::x86) - { - cpu = getX86TargetCPU(cpu, triple); - } + cpu = getTargetCPU(cpu, triple); if (Logger::enabled()) { From 1335e26c4508aae207c215f8b82a71fc3785a6d6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 03:07:51 +0200 Subject: [PATCH 07/14] Log/error message prettification. --- driver/targetmachine.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index 3ff2baa2..1873946f 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -160,13 +160,14 @@ llvm::TargetMachine* createTargetMachine( triple = llvm::Triple(llvm::Triple::normalize(targetTriple)); } - // Look up the LLVM backend to use. + // Look up the LLVM backend to use. This also updates triple with the + // user-specified arch, if any. std::string errMsg; const llvm::Target *target = llvm::TargetRegistry::lookupTarget(arch, triple, errMsg); if (target == 0) { - error("%s", errMsg.c_str()); + error("Could not determine target platform: %s", errMsg.c_str()); fatal(); } @@ -194,8 +195,8 @@ llvm::TargetMachine* createTargetMachine( if (Logger::enabled()) { - Logger::cout() << "Targeting CPU '" << cpu << "' with features '" << - features.getString() << "'.\n"; + Logger::cout() << "Targeting '" << triple.str() << "' (CPU '" << cpu + << "' with features '" << features.getString() << "').\n"; } if (triple.isMacOSX() && relocModel == llvm::Reloc::Default) From 49697a8bc2d90c709fe976dbd7926e752038a9ee Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 03:25:18 +0200 Subject: [PATCH 08/14] if chain -> switch. --- driver/targetmachine.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index 1873946f..5c52d31a 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -113,17 +113,18 @@ static std::string getTargetCPU(const std::string &cpu, return hostCPU; } - if (triple.getArch() == llvm::Triple::x86_64 || - triple.getArch() == llvm::Triple::x86) + switch (triple.getArch()) { + default: + // We don't know about the specifics of this platform, just return the + // empty string and let LLVM decide. + return cpu; + case llvm::Triple::x86: + case llvm::Triple::x86_64: return getX86TargetCPU(triple); - } - else if (triple.getArch() == llvm::Triple::arm) - { + case llvm::Triple::arm: return getARMTargetCPU(triple); } - - return cpu; } From 422715fc8908a4ce3c96bcb2d3d1271c33b2de6f Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 03:27:47 +0200 Subject: [PATCH 09/14] Add -float-abi switch and auto-detection for ARM. This is based on the implementation that was reverted in fc8e0c4c20f12f0f727063f0d63dae6d318999df. --- driver/cl_options.cpp | 10 ++++ driver/cl_options.h | 2 + driver/main.cpp | 5 +- driver/targetmachine.cpp | 106 ++++++++++++++++++++++++++++++++++++++- driver/targetmachine.h | 10 ++++ 5 files changed, 130 insertions(+), 3 deletions(-) diff --git a/driver/cl_options.cpp b/driver/cl_options.cpp index 8b688953..643b901c 100644 --- a/driver/cl_options.cpp +++ b/driver/cl_options.cpp @@ -315,6 +315,16 @@ cl::opt mCodeModel("code-model", clEnumValN(llvm::CodeModel::Large, "large", "Large code model"), clEnumValEnd)); +cl::opt 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 asserts("asserts", cl::desc("(*) Enable assertions"), cl::value_desc("bool"), diff --git a/driver/cl_options.h b/driver/cl_options.h index 25afb5a6..4cc67c68 100644 --- a/driver/cl_options.h +++ b/driver/cl_options.h @@ -15,6 +15,7 @@ #ifndef LDC_DRIVER_CL_OPTIONS_H #define LDC_DRIVER_CL_OPTIONS_H +#include "driver/targetmachine.h" #include "gen/cl_helpers.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/CommandLine.h" @@ -60,6 +61,7 @@ namespace opts { extern cl::opt mTargetTriple; extern cl::opt mRelocModel; extern cl::opt mCodeModel; + extern cl::opt mFloatABI; extern cl::opt singleObj; extern cl::opt linkonceTemplates; diff --git a/driver/main.cpp b/driver/main.cpp index c218474a..3346fe34 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -635,8 +635,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); { llvm::Triple triple = llvm::Triple(gTargetMachine->getTargetTriple()); diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index 5c52d31a..3de7c3d9 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -8,7 +8,8 @@ //===----------------------------------------------------------------------===// // // Note: The target CPU detection logic has been adapted from Clang -// (lib/Driver/Tools.cpp). +// (Tools.cpp and ToolChain.cpp in lib/Driver, the latter seems to have the +// more up-to-date version). // //===----------------------------------------------------------------------===// @@ -127,6 +128,74 @@ static std::string getTargetCPU(const std::string &cpu, } } +static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) +{ + return llvm::StringSwitch(CPU) + .Case("strongarm", "v4") + .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-a12", "cortex-a15", "v7") + .Cases("cortex-r4", "cortex-r5", "v7r") + .Case("cortex-m0", "v6m") + .Case("cortex-m3", "v7m") + .Case("cortex-m4", "v7em") + .Case("cortex-a9-mp", "v7f") + .Case("swift", "v7s") + .Case("cortex-a53", "v8") + .Default(""); +} + +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; +#if LDC_LLVM_VER >= 302 + case llvm::Triple::Android: { + if (llvm::StringRef(llvmArchSuffix).startswith("v7")) + return FloatABI::SoftFP; + return FloatABI::Soft; + } +#endif + default: + // Assume "soft". + // TODO: Warn the user we are guessing. + return FloatABI::Soft; + } + } +} llvm::TargetMachine* createTargetMachine( std::string targetTriple, @@ -134,6 +203,7 @@ llvm::TargetMachine* createTargetMachine( std::string cpu, std::vector attrs, ExplicitBitness::Type bitness, + FloatABI::Type floatABI, llvm::Reloc::Model relocModel, llvm::CodeModel::Model codeModel, llvm::CodeGenOpt::Level codeGenOptLevel, @@ -207,9 +277,43 @@ llvm::TargetMachine* createTargetMachine( relocModel = llvm::Reloc::PIC_; } + 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; + } + } + + 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 target->createTargetMachine( triple.str(), cpu, diff --git a/driver/targetmachine.h b/driver/targetmachine.h index 0dd8018f..83106bb3 100644 --- a/driver/targetmachine.h +++ b/driver/targetmachine.h @@ -27,6 +27,15 @@ namespace ExplicitBitness { }; } +namespace FloatABI { + enum Type { + Default, + Soft, + SoftFP, + Hard + }; +} + namespace llvm { class TargetMachine; } /** @@ -41,6 +50,7 @@ llvm::TargetMachine* createTargetMachine( std::string cpu, std::vector attrs, ExplicitBitness::Type bitness, + FloatABI::Type floatABI, llvm::Reloc::Model relocModel, llvm::CodeModel::Model codeModel, llvm::CodeGenOpt::Level codeGenOptLevel, From 1d7943bc7e131b983169a932598160bb0313a179 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 04:21:37 +0200 Subject: [PATCH 10/14] Simplify FindLibconfig++ using find_package_handle_standard_args features. --- cmake/Modules/FindLibConfig++.cmake | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/cmake/Modules/FindLibConfig++.cmake b/cmake/Modules/FindLibConfig++.cmake index 28c9712e..265dd7ba 100644 --- a/cmake/Modules/FindLibConfig++.cmake +++ b/cmake/Modules/FindLibConfig++.cmake @@ -1,21 +1,15 @@ -# Find the libconfig++ includes and library +# - Find the libconfig++ includes and library # # This module defines # LIBCONFIG++_INCLUDE_DIR, where to find libconfig++ include files, etc. # LIBCONFIG++_LIBRARY, the library to link against to use libconfig++. # LIBCONFIG++_FOUND, If false, do not try to use libconfig++. -set(LIBCONFIG++_FOUND FALSE) - find_path(LIBCONFIG++_INCLUDE_DIR libconfig.h++) find_library(LIBCONFIG++_LIBRARY config++) -if (LIBCONFIG++_INCLUDE_DIR AND LIBCONFIG++_LIBRARY) - set(LIBCONFIG++_FOUND TRUE) -endif (LIBCONFIG++_INCLUDE_DIR AND LIBCONFIG++_LIBRARY) - # Use the default CMake facilities for handling QUIET/REQUIRED. include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(LIBCONFIG++ +find_package_handle_standard_args(LibConfig++ REQUIRED_VARS LIBCONFIG++_INCLUDE_DIR LIBCONFIG++_LIBRARY) From 250f7fab274cc0485c732e0886ba402ed75340d2 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 08:30:58 +0200 Subject: [PATCH 11/14] ARM: Fold in druntime fixes. --- runtime/CMakeLists.txt | 5 +++++ runtime/druntime | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index d6f8fff8..f5fd158f 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -108,6 +108,11 @@ if(UNIX) endif() list(REMOVE_ITEM LDC_D ${RUNTIME_DIR}/src/ldc/eh2.d) list(REMOVE_ITEM DCRT_C ${RUNTIME_DC_DIR}/msvc.c) + + # Using CMAKE_SYSTEM_PROCESSOR might be inacurrate when somebody is + # cross-compiling by just setting the tool executbles to a cross toolchain, + # so just always include the file. + list(APPEND DCRT_C ${RUNTIME_DIR}/src/ldc/arm_unwind.c) elseif(WIN32) list(APPEND CORE_D_SYS ${CORE_D_WIN}) if (MSVC) diff --git a/runtime/druntime b/runtime/druntime index a116bff2..822720b8 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit a116bff228fb1b722d0e615364a22fc20cfde160 +Subproject commit 822720b8637bf5ad0d2301aa00807216a9d334bd From 445b743ba5762d341c2fce71b5d569ffb0fb3151 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 19:12:36 +0200 Subject: [PATCH 12/14] Implement lookupTarget() with arch override for LLVM 3.1. To be removed again once we drop 3.1 support. --- driver/targetmachine.cpp | 59 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index 3de7c3d9..19735e9b 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -197,6 +197,60 @@ static FloatABI::Type getARMFloatABI(const llvm::Triple &triple, } } +/// Looks up a target based on an arch name and a target triple. +/// +/// If the arch name is non-empty, then the lookup is done by arch. Otherwise, +/// the target triple is used. +/// +/// This has been adapted from the corresponding LLVM 3.2+ overload of +/// llvm::TargetRegistry::lookupTarget. Once support for LLVM 3.1 is dropped, +/// the registry method can be used instead. +const llvm::Target *lookupTarget(const std::string &arch, llvm::Triple &triple, + std::string &errorMsg) +{ + // Allocate target machine. First, check whether the user has explicitly + // specified an architecture to compile for. If so we have to look it up by + // name, because it might be a backend that has no mapping to a target triple. + const llvm::Target *target = 0; + if (!arch.empty()) + { + for (llvm::TargetRegistry::iterator it = llvm::TargetRegistry::begin(), + ie = llvm::TargetRegistry::end(); it != ie; ++it) + { + if (arch == it->getName()) + { + target = &*it; + break; + } + } + + if (!target) + { + errorMsg = "invalid target architecture '" + arch + "', see " + "-version for a list of supported targets."; + return 0; + } + + // Adjust the triple to match (if known), otherwise stick with the + // given triple. + llvm::Triple::ArchType Type = llvm::Triple::getArchTypeForLLVMName(arch); + if (Type != llvm::Triple::UnknownArch) + triple.setArch(Type); + } + else + { + std::string tempError; + target = llvm::TargetRegistry::lookupTarget(triple.getTriple(), tempError); + if (!target) + { + errorMsg = "unable to get target for '" + triple.getTriple() + + "', see -version and -mtriple."; + } + } + + return target; +} + llvm::TargetMachine* createTargetMachine( std::string targetTriple, std::string arch, @@ -234,11 +288,10 @@ llvm::TargetMachine* createTargetMachine( // Look up the LLVM backend to use. This also updates triple with the // user-specified arch, if any. std::string errMsg; - const llvm::Target *target = - llvm::TargetRegistry::lookupTarget(arch, triple, errMsg); + const llvm::Target *target = lookupTarget(arch, triple, errMsg); if (target == 0) { - error("Could not determine target platform: %s", errMsg.c_str()); + error("%s", errMsg.c_str()); fatal(); } From aba1b82539106ef8511423393fd41e3c43d5eb9c Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 19:26:58 +0200 Subject: [PATCH 13/14] Finally fix LLVM 3.1 compilation. --- driver/targetmachine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index 19735e9b..e6b46c1a 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -319,8 +319,8 @@ llvm::TargetMachine* createTargetMachine( if (Logger::enabled()) { - Logger::cout() << "Targeting '" << triple.str() << "' (CPU '" << cpu - << "' with features '" << features.getString() << "').\n"; + Logger::println("Targeting '%s' (CPU '%s' with features '%s')", + triple.str().c_str(), cpu.c_str(), features.getString().c_str()); } if (triple.isMacOSX() && relocModel == llvm::Reloc::Default) From e4fee1116af225c63935a2216d9b27453fa3897c Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 20:15:28 +0200 Subject: [PATCH 14/14] ARM: Use -arm-enable-ehabi(-descriptors). D exception handling does not work at all yet, but with these flags it does for C++/Clang, at least in simple cases. --- driver/targetmachine.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index e6b46c1a..4be79b08 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Support/Host.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Target/TargetMachine.h" @@ -346,6 +347,19 @@ llvm::TargetMachine* createTargetMachine( } } + if (triple.getArch() == llvm::Triple::arm) + { + // On ARM, we want to use EHABI exception handling, as we don't support + // SJLJ EH in druntime. Unfortunately, it is still in a partly + // experimental state, and the -arm-enable-ehabi-descriptors command + // line option is not exposed via an internal API at all. + const char *backendArgs[3] = { + "ldc2", // Fake name, irrelevant. + "-arm-enable-ehabi", + "-arm-enable-ehabi-descriptors" + }; + llvm::cl::ParseCommandLineOptions(3, backendArgs); + } llvm::TargetOptions targetOptions; targetOptions.NoFramePointerElim = genDebugInfo;