diff --git a/CMakeLists.txt b/CMakeLists.txt index 3bbb287f..eb4468ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,6 +149,7 @@ file(GLOB IR_HDR ir/*.h) set(DRV_SRC driver/cl_options.cpp driver/configfile.cpp + driver/target.cpp driver/toobj.cpp driver/tool.cpp driver/linker.cpp @@ -158,6 +159,7 @@ set(DRV_HDR driver/linker.h driver/cl_options.h driver/configfile.h + driver/target.h driver/toobj.h driver/tool.h ) diff --git a/driver/main.cpp b/driver/main.cpp index 2dcf1af8..3ed1d247 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -17,23 +17,21 @@ #include "driver/cl_options.h" #include "driver/configfile.h" #include "driver/linker.h" +#include "driver/target.h" #include "driver/toobj.h" #include "gen/cl_helpers.h" #include "gen/irstate.h" #include "gen/linkage.h" #include "gen/llvm.h" -#include "gen/llvmcompat.h" #include "gen/logger.h" #include "gen/metadata.h" #include "gen/optimizer.h" #include "gen/passes/Passes.h" #include "llvm/Linker.h" -#include "llvm/MC/SubtargetFeature.h" #include "llvm/Support/Host.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" #if LDC_LLVM_VER >= 303 #include "llvm/LinkAllIR.h" #include "llvm/IR/LLVMContext.h" @@ -338,19 +336,10 @@ int main(int argc, char** argv) return EXIT_FAILURE; } -#if LDC_LLVM_VER >= 301 - llvm::TargetOptions targetOptions; -#endif - Array* libs; if (global.params.symdebug) { libs = global.params.debuglibnames; -#if LDC_LLVM_VER == 300 - llvm::NoFramePointerElim = true; -#else - targetOptions.NoFramePointerElim = true; -#endif } else libs = global.params.defaultlibnames; @@ -452,120 +441,32 @@ int main(int argc, char** argv) // create a proper target Ir ir; - // check -m32/64 sanity - if (m32bits && m64bits) - error("cannot use both -m32 and -m64 options"); - else if ((m32bits || m64bits) && (!mArch.empty() || !mTargetTriple.empty())) + // Set up the TargetMachine. + ExplicitBitness::Type bitness = ExplicitBitness::None; + if ((m32bits || m64bits) && (!mArch.empty() || !mTargetTriple.empty())) error("-m32 and -m64 switches cannot be used together with -march and -mtriple switches"); + + if (m32bits) + bitness = ExplicitBitness::M32; + if (m64bits) + { + if (bitness != ExplicitBitness::None) + { + error("cannot use both -m32 and -m64 options"); + } + } + if (global.errors) fatal(); - // override triple if needed - std::string defaultTriple = llvm::sys::getDefaultTargetTriple(); - if (sizeof(void*) == 4 && m64bits) - { -#if LDC_LLVM_VER >= 301 - defaultTriple = llvm::Triple(defaultTriple).get64BitArchVariant().str(); -#else - defaultTriple = llvm::Triple__get64BitArchVariant(defaultTriple).str(); -#endif - } - else if (sizeof(void*) == 8 && m32bits) - { -#if LDC_LLVM_VER >= 301 - defaultTriple = llvm::Triple(defaultTriple).get32BitArchVariant().str(); -#else - defaultTriple = llvm::Triple__get32BitArchVariant(defaultTriple).str(); -#endif - } - - std::string triple; - - // did the user override the target triple? - if (mTargetTriple.empty()) - { - if (!mArch.empty()) - { - error("you must specify a target triple as well with -mtriple when using the -march option"); - fatal(); - } - triple = defaultTriple; - } - else - { - triple = llvm::Triple::normalize(mTargetTriple); - } - - global.params.targetTriple = llvm::Triple(triple); - - // Allocate target machine. - const llvm::Target *theTarget = NULL; - // Check whether the user has explicitly specified an architecture to compile for. - if (mArch.empty()) - { - std::string Err; - theTarget = llvm::TargetRegistry::lookupTarget(triple, Err); - if (theTarget == 0) - { - error("%s Please use the -march option.", Err.c_str()); - fatal(); - } - } - else - { - for (llvm::TargetRegistry::iterator it = llvm::TargetRegistry::begin(), - ie = llvm::TargetRegistry::end(); it != ie; ++it) - { - if (mArch == it->getName()) - { - theTarget = &*it; - break; - } - } - - if (!theTarget) - { - error("invalid target '%s'", mArch.c_str()); - fatal(); - } - } - - // Package up features to be passed to target/subtarget - std::string FeaturesStr; - if (mCPU.size() || mAttrs.size()) - { - llvm::SubtargetFeatures Features; - for (unsigned i = 0; i != mAttrs.size(); ++i) - Features.AddFeature(mAttrs[i]); - FeaturesStr = Features.getString(); - } - - // FIXME - //std::auto_ptr target(theTarget->createTargetMachine(triple, FeaturesStr)); - //assert(target.get() && "Could not allocate target machine!"); - //gTargetMachine = target.get(); - -#if LDC_LLVM_VER == 300 - llvm::TargetMachine* target = theTarget->createTargetMachine(triple, mCPU, FeaturesStr, - mRelocModel, mCodeModel); -#else - llvm::TargetMachine * target = theTarget->createTargetMachine( - llvm::StringRef(triple), - llvm::StringRef(mCPU), - llvm::StringRef(FeaturesStr), - targetOptions, - mRelocModel, - mCodeModel, - codeGenOptLevel() - ); -#endif - - gTargetMachine = target; + gTargetMachine = createTargetMachine(mTargetTriple, mArch, mCPU, mAttrs, bitness, + mRelocModel, mCodeModel, codeGenOptLevel(), global.params.symdebug); + global.params.targetTriple = llvm::Triple(gTargetMachine->getTargetTriple()); #if LDC_LLVM_VER >= 302 - gDataLayout = target->getDataLayout(); + gDataLayout = gTargetMachine->getDataLayout(); #else - gDataLayout = target->getTargetData(); + gDataLayout = gTargetMachine->getTargetData(); #endif // Starting with LLVM 3.1 we could also use global.params.targetTriple.isArch64Bit(); diff --git a/driver/target.cpp b/driver/target.cpp new file mode 100644 index 00000000..f01d9089 --- /dev/null +++ b/driver/target.cpp @@ -0,0 +1,198 @@ +//===-- target.cpp --------------------------------------------------------===// +// +// LDC – the LLVM D compiler +// +// This file is distributed under the BSD-style LDC license. See the LICENSE +// file for details. +// +//===----------------------------------------------------------------------===// +// +// Note: The target CPU detection logic has been adapted from Clang +// (lib/Driver/Tools.cpp). +// +//===----------------------------------------------------------------------===// + +#include "driver/target.h" +#include "gen/llvmcompat.h" +#include "llvm/ADT/Triple.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "mars.h" + + +static std::string getX86TargetCPU(std::string arch, + const llvm::Triple &triple) +{ + if (!arch.empty()) { + if (arch != "native") + return arch; + + // FIXME: Reject attempts to use -march=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; + } + + // Select the default CPU if none was given (or detection failed). + + bool is64Bit = triple.getArch() == llvm::Triple::x86_64; + + if (triple.isOSDarwin()) + return is64Bit ? "core2" : "yonah"; + + // Everything else goes to x86-64 in 64-bit mode. + if (is64Bit) + return "x86-64"; + + if (triple.getOSName().startswith("haiku")) + return "i586"; + if (triple.getOSName().startswith("openbsd")) + return "i486"; + if (triple.getOSName().startswith("bitrig")) + return "i686"; + if (triple.getOSName().startswith("freebsd")) + return "i486"; + if (triple.getOSName().startswith("netbsd")) + return "i486"; +#if LDC_LLVM_VER >= 302 + // All x86 devices running Android have core2 as their common + // denominator. This makes a better choice than pentium4. + if (triple.getEnvironment() == llvm::Triple::Android) + return "core2"; +#endif + + // Fallback to p4. + return "pentium4"; +} + + +llvm::TargetMachine* createTargetMachine( + std::string targetTriple, + std::string arch, + std::string cpu, + std::vector attrs, + ExplicitBitness::Type bitness, + llvm::Reloc::Model relocModel, + llvm::CodeModel::Model codeModel, + llvm::CodeGenOpt::Level codeGenOptLevel, + bool genDebugInfo) +{ + // override triple if needed + std::string defaultTriple = llvm::sys::getDefaultTargetTriple(); + if (sizeof(void*) == 4 && bitness == ExplicitBitness::M64) + { +#if LDC_LLVM_VER >= 301 + defaultTriple = llvm::Triple(defaultTriple).get64BitArchVariant().str(); +#else + defaultTriple = llvm::Triple__get64BitArchVariant(defaultTriple).str(); +#endif + } + else if (sizeof(void*) == 8 && bitness == ExplicitBitness::M32) + { +#if LDC_LLVM_VER >= 301 + defaultTriple = llvm::Triple(defaultTriple).get32BitArchVariant().str(); +#else + defaultTriple = llvm::Triple__get32BitArchVariant(defaultTriple).str(); +#endif + } + + llvm::Triple triple; + + // did the user override the target triple? + if (targetTriple.empty()) + { + if (!arch.empty()) + { + error("you must specify a target triple as well with -mtriple when using the -arch option"); + fatal(); + } + 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()) + { + std::string Err; + theTarget = llvm::TargetRegistry::lookupTarget(triple.str(), Err); + if (theTarget == 0) + { + error("%s Please use the -march option.", Err.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 + // to default to "generic"). + if (cpu.empty()) + { + if (triple.getArch() == llvm::Triple::x86_64 || + triple.getArch() == llvm::Triple::x86) + { + cpu = getX86TargetCPU(arch, triple); + } + } + + // Package up features to be passed to target/subtarget + std::string FeaturesStr; + if (cpu.size() || attrs.size()) + { + llvm::SubtargetFeatures Features; + for (unsigned i = 0; i != attrs.size(); ++i) + Features.AddFeature(attrs[i]); + FeaturesStr = Features.getString(); + } + +#if LDC_LLVM_VER == 300 + llvm::NoFramePointerElim = genDebugInfo; + + return theTarget->createTargetMachine(triple.str(), cpu, FeaturesStr, + relocModel, codeModel); +#else + llvm::TargetOptions targetOptions; + targetOptions.NoFramePointerElim = genDebugInfo; + + return theTarget->createTargetMachine( + triple.str(), + cpu, + FeaturesStr, + targetOptions, + relocModel, + codeModel, + codeGenOptLevel + ); +#endif +} diff --git a/driver/target.h b/driver/target.h new file mode 100644 index 00000000..4eb4c635 --- /dev/null +++ b/driver/target.h @@ -0,0 +1,52 @@ +//===-- driver/target.h - LLVM target setup ---------------------*- C++ -*-===// +// +// LDC – the LLVM D compiler +// +// This file is distributed under the BSD-style LDC license. See the LICENSE +// file for details. +// +//===----------------------------------------------------------------------===// +// +// Handles setting up an LLVM TargetMachine from the ugiven command-line +// arguments. +// +//===----------------------------------------------------------------------===// + +#ifndef LDC_DRIVER_TARGET_H +#define LDC_DRIVER_TARGET_H + +#include "llvm/Support/CodeGen.h" +#if LDC_LLVM_VER == 300 +#include "llvm/Target/TargetMachine.h" // For llvm::CodeGenOpt::Level. +#endif +#include +#include + +namespace ExplicitBitness { + enum Type { + None, + M32, + M64 + }; +} + +namespace llvm { class TargetMachine; } + +/** + * Creates an LLVM TargetMachine suitable for the given (usually command-line) + * parameters and the host platform defaults. + * + * Does not depend on any global state. + */ +llvm::TargetMachine* createTargetMachine( + std::string targetTriple, + std::string arch, + std::string cpu, + std::vector attrs, + ExplicitBitness::Type bitness, + llvm::Reloc::Model relocModel, + llvm::CodeModel::Model codeModel, + llvm::CodeGenOpt::Level codeGenOptLevel, + bool genDebugInfo); + +#endif // LDC_DRIVER_TARGET_H