From 422715fc8908a4ce3c96bcb2d3d1271c33b2de6f Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 6 Oct 2013 03:27:47 +0200 Subject: [PATCH] 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,