Merge branch 'master' into merge-2.069

This commit is contained in:
Johan Engelen 2016-02-13 20:12:17 +01:00
commit acdcc4a8c1
28 changed files with 600 additions and 277 deletions

View file

@ -33,6 +33,8 @@ addons:
- llvm-3.7-dev
- llvm-3.8
- llvm-3.8-dev
- llvm-3.9
- llvm-3.9-dev
install:
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then export CC="gcc-4.9"; export CXX="g++-4.9"; fi
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew update; brew install llvm36; brew install libconfig; fi;
@ -45,14 +47,13 @@ env:
- LLVM_CONFIG="llvm-config-3.6" OPTS="-DBUILD_SHARED_LIBS=ON"
- LLVM_CONFIG="llvm-config-3.5" OPTS="-DTEST_COVERAGE=ON"
- LLVM_CONFIG="llvm-config-3.8"
- LLVM_CONFIG="llvm-config-3.9"
# OSX only (and the only ones for OSX):
- LLVM_CONFIG="llvm-config-3.6" TEST_CONFIG="Debug"
- LLVM_CONFIG="llvm-config-3.6" TEST_CONFIG="Release"
matrix:
allow_failures:
- env: LLVM_CONFIG="llvm-config-3.8"
- os: osx
env: LLVM_CONFIG="llvm-config-3.6" TEST_CONFIG="Release"
- env: LLVM_CONFIG="llvm-config-3.9"
exclude:
- os: linux
env: LLVM_CONFIG="llvm-config-3.6" TEST_CONFIG="Debug"
@ -66,6 +67,8 @@ matrix:
env: LLVM_CONFIG="llvm-config-3.5" OPTS="-DTEST_COVERAGE=ON"
- os: osx
env: LLVM_CONFIG="llvm-config-3.8"
- os: osx
env: LLVM_CONFIG="llvm-config-3.9"
script:
- cmake -DLLVM_CONFIG=$(which ${LLVM_CONFIG}) $OPTS .
- make -j3

View file

@ -17,7 +17,7 @@ include(CheckCXXCompilerFlag)
#
find_package(LLVM 3.5 REQUIRED
all-targets analysis asmparser asmprinter bitreader bitwriter codegen core debuginfodwarf instcombine ipa ipo instrumentation irreader linker lto mc mcdisassembler mcparser objcarcopts object option profiledata scalaropts selectiondag support tablegen target transformutils vectorize ${EXTRA_LLVM_MODULES})
all-targets analysis asmparser asmprinter bitreader bitwriter codegen core debuginfocodeview debuginfodwarf debuginfopdb instcombine ipa ipo instrumentation irreader linker lto mc mcdisassembler mcparser objcarcopts object option profiledata scalaropts selectiondag support tablegen target transformutils vectorize ${EXTRA_LLVM_MODULES})
math(EXPR LDC_LLVM_VER ${LLVM_VERSION_MAJOR}*100+${LLVM_VERSION_MINOR})
# Remove LLVMTableGen library from list of libraries
string(REGEX MATCH "^-.*LLVMTableGen[^;]*;|;-.*LLVMTableGen[^;]*" LLVM_TABLEGEN_LIBRARY "${LLVM_LIBRARIES}")
@ -252,6 +252,8 @@ string(REPLACE "-Werror " "" LLVM_CXXFLAGS ${LLVM_CXXFLAGS})
if (UNIX AND NOT "${LLVM_LDFLAGS}" STREQUAL "")
# LLVM_LDFLAGS may contain -l-lld which is a wrong library reference (AIX)
string(REPLACE "-l-lld " "-lld " LLVM_LDFLAGS ${LLVM_LDFLAGS})
# LLVM_LDFLAGS may have a space at the end
string(REGEX REPLACE " $" "" LLVM_LDFLAGS ${LLVM_LDFLAGS})
endif()
# LLVM_CXXFLAGS may contain -Wcovered-switch-default and -fcolor-diagnostics
# which are clang-only options

View file

@ -27,7 +27,8 @@
# We also want an user-specified LLVM_ROOT_DIR to take precedence over the
# system default locations such as /usr/local/bin. Executing find_program()
# multiples times is the approach recommended in the docs.
set(llvm_config_names llvm-config-3.8 llvm-config38
set(llvm_config_names llvm-config-3.9 llvm-config39
llvm-config-3.8 llvm-config38
llvm-config-3.7 llvm-config37
llvm-config-3.6 llvm-config36
llvm-config-3.5 llvm-config35
@ -67,23 +68,17 @@ if ((WIN32 AND NOT(MINGW OR CYGWIN)) OR NOT LLVM_CONFIG)
if(TARGET_AArch64 GREATER -1)
list(APPEND LLVM_FIND_COMPONENTS AArch64Utils)
endif()
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "backend" index)
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-2][\\.0-9A-Za-z]*")
# Versions below 3.3 do not support components objcarcopts, option
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "objcarcopts" index)
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "option" index)
endif()
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-4][\\.0-9A-Za-z]*")
# Versions below 3.5 do not support components lto, profiledata
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "lto" index)
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "profiledata" index)
endif()
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-6][\\.0-9A-Za-z]*")
# Versions below 3.7 do not support components debuginfodwarf
# Versions below 3.7 do not support components debuginfo[dwarf|pdb]
# Only debuginfo is available
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfodwarf" index)
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfopdb" index)
list(APPEND LLVM_FIND_COMPONENTS "debuginfo")
endif()
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-8][\\.0-9A-Za-z]*")
# Versions below 3.9 do not support components debuginfocodeview
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfocodeview" index)
endif()
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[8-9][\\.0-9A-Za-z]*")
# Versions beginning with 3.8 do not support component ipa
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "ipa" index)
@ -150,23 +145,19 @@ else()
llvm_set(HOST_TARGET host-target)
llvm_set(INCLUDE_DIRS includedir true)
llvm_set(ROOT_DIR prefix true)
llvm_set(ENABLE_ASSERTIONS assertion-mode)
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-2][\\.0-9A-Za-z]*")
# Versions below 3.3 do not support components objcarcopts, option
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "objcarcopts" index)
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "option" index)
endif()
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-4][\\.0-9A-Za-z]*")
# Versions below 3.5 do not support components lto, profiledata
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "lto" index)
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "profiledata" index)
endif()
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-6][\\.0-9A-Za-z]*")
# Versions below 3.7 do not support components debuginfodwarf
# Versions below 3.7 do not support components debuginfo[dwarf|pdb]
# Only debuginfo is available
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfodwarf" index)
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfopdb" index)
list(APPEND LLVM_FIND_COMPONENTS "debuginfo")
endif()
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-8][\\.0-9A-Za-z]*")
# Versions below 3.9 do not support components debuginfocodeview
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfocodeview" index)
endif()
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[8-9][\\.0-9A-Za-z]*")
# Versions beginning with 3.8 do not support component ipa
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "ipa" index)
@ -181,6 +172,8 @@ else()
endif()
llvm_set(LIBRARY_DIRS libdir true)
llvm_set_libs(LIBRARIES libs)
llvm_set(TARGETS_TO_BUILD targets-built)
string(REGEX MATCHALL "${pattern}[^ ]+" LLVM_TARGETS_TO_BUILD ${LLVM_TARGETS_TO_BUILD})
endif()
# On CMake builds of LLVM, the output of llvm-config --cxxflags does not

View file

@ -651,7 +651,7 @@ longdouble Port::strtold(const char *p, char **endp)
#endif
#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __DragonFly__ || __HAIKU__
#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__ || __HAIKU__
#include <math.h>
#if __linux__
@ -806,7 +806,7 @@ int Port::isNan(double r)
#else
return __inline_isnan(r);
#endif
#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __DragonFly__
#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__
return isnan(r);
#else
#undef isnan
@ -822,7 +822,7 @@ int Port::isNan(longdouble r)
#else
return __inline_isnan(r);
#endif
#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __DragonFly__
#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__
return isnan(r);
#else
#undef isnan
@ -850,7 +850,7 @@ int Port::isInfinity(double r)
{
#if __APPLE__
return fpclassify(r) == FP_INFINITE;
#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __DragonFly__
#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__
return isinf(r);
#else
#undef isinf
@ -865,7 +865,7 @@ longdouble Port::sqrt(longdouble x)
longdouble Port::fmodl(longdouble x, longdouble y)
{
#if __FreeBSD__ && __FreeBSD_version < 800000 || __OpenBSD__ || __DragonFly__
#if __FreeBSD__ && __FreeBSD_version < 800000 || __OpenBSD__ || __NetBSD__ || __DragonFly__
return ::fmod(x, y); // hack for now, fix later
#else
return ::fmodl(x, y);

View file

@ -37,10 +37,9 @@ static bool endsWith(const std::string &str, const std::string &end) {
//////////////////////////////////////////////////////////////////////////////
static void CreateDirectoryOnDisk(llvm::StringRef fileName) {
llvm::StringRef dir(llvm::sys::path::parent_path(fileName));
auto dir = llvm::sys::path::parent_path(fileName);
if (!dir.empty() && !llvm::sys::fs::exists(dir)) {
std::error_code ec = llvm::sys::fs::create_directory(dir);
if (ec) {
if (auto ec = llvm::sys::fs::create_directory(dir)) {
error(Loc(), "failed to create path to file: %s\n%s", dir.data(),
ec.message().c_str());
fatal();
@ -175,6 +174,9 @@ static int linkObjToBinaryGcc(bool sharedLib, bool fullyStatic) {
args.push_back("-ldl");
// fallthrough
case llvm::Triple::FreeBSD:
case llvm::Triple::NetBSD:
case llvm::Triple::OpenBSD:
case llvm::Triple::DragonFly:
addSoname = true;
args.push_back("-lpthread");
args.push_back("-lm");
@ -183,7 +185,8 @@ static int linkObjToBinaryGcc(bool sharedLib, bool fullyStatic) {
case llvm::Triple::Solaris:
args.push_back("-lm");
args.push_back("-lumem");
// solaris TODO
args.push_back("-lsocket");
args.push_back("-lnsl");
break;
default:

View file

@ -125,9 +125,8 @@ static std::string getX86TargetCPU(const llvm::Triple &triple) {
// Intel Macs are relatively recent, take advantage of that.
if (triple.isOSDarwin()) {
return triple.isArch64Bit() ? "core2" : "yonah";
// Everything else goes to x86-64 in 64-bit mode.
}
// Everything else goes to x86-64 in 64-bit mode.
if (triple.isArch64Bit()) {
return "x86-64";
}
@ -145,9 +144,15 @@ static std::string getX86TargetCPU(const llvm::Triple &triple) {
}
if (triple.getOSName().startswith("netbsd")) {
return "i486";
// All x86 devices running Android have core2 as their common
// denominator. This makes a better choice than pentium4.
}
if (triple.getOSName().startswith("openbsd")) {
return "i486";
}
if (triple.getOSName().startswith("dragonfly")) {
return "i486";
}
// 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";
@ -271,6 +276,11 @@ static FloatABI::Type getARMFloatABI(const llvm::Triple &triple,
return FloatABI::Soft;
default:
if (triple.getVendorName().startswith("hardfloat"))
return FloatABI::Hard;
if (triple.getVendorName().startswith("softfloat"))
return FloatABI::SoftFP;
switch (triple.getEnvironment()) {
case llvm::Triple::GNUEABIHF:
return FloatABI::Hard;
@ -495,10 +505,27 @@ llvm::TargetMachine *createTargetMachine(
features.getString().c_str());
}
if (triple.isMacOSX() && relocModel == llvm::Reloc::Default) {
// OS X defaults to PIC (and as of 10.7.5/LLVM 3.1-3.3, TLS use leads
// to crashes for non-PIC code). LLVM doesn't handle this.
relocModel = llvm::Reloc::PIC_;
// Handle cases where LLVM picks wrong default relocModel
if (relocModel == llvm::Reloc::Default) {
if (triple.isOSDarwin()) {
// Darwin defaults to PIC (and as of 10.7.5/LLVM 3.1-3.3, TLS use leads
// to crashes for non-PIC code). LLVM doesn't handle this.
relocModel = llvm::Reloc::PIC_;
} else if (triple.getEnvironment() == llvm::Triple::Android) {
relocModel = llvm::Reloc::PIC_;
} else {
// ARM for other than Darwin or Android defaults to static
switch (triple.getArch()) {
default:
break;
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
relocModel = llvm::Reloc::Static;
break;
}
}
}
if (floatABI == FloatABI::Default) {

View file

@ -346,27 +346,26 @@ void writeModule(llvm::Module *m, std::string filename) {
global.params.targetTriple->getOS() == llvm::Triple::AIX);
// eventually do our own path stuff, dmd's is a bit strange.
typedef llvm::SmallString<128> LLPath;
using LLPath = llvm::SmallString<128>;
#if LDC_LLVM_VER >= 306
using ErrorInfo = std::error_code;
#define ERRORINFO_STRING(errinfo) errinfo.message().c_str()
#else
using ErrorInfo = std::string;
#define ERRORINFO_STRING(errinfo) errinfo.c_str()
#endif
// write LLVM bitcode
if (global.params.output_bc) {
LLPath bcpath = LLPath(filename);
LLPath bcpath(filename);
llvm::sys::path::replace_extension(bcpath, global.bc_ext);
Logger::println("Writing LLVM bitcode to: %s\n", bcpath.c_str());
#if LDC_LLVM_VER >= 306
std::error_code errinfo;
#else
std::string errinfo;
#endif
ErrorInfo errinfo;
llvm::raw_fd_ostream bos(bcpath.c_str(), errinfo, llvm::sys::fs::F_None);
if (bos.has_error()) {
error(Loc(), "cannot write LLVM bitcode file '%s': %s", bcpath.c_str(),
#if LDC_LLVM_VER >= 306
errinfo
#else
errinfo.c_str()
#endif
);
ERRORINFO_STRING(errinfo));
fatal();
}
llvm::WriteBitcodeToFile(m, bos);
@ -374,23 +373,14 @@ void writeModule(llvm::Module *m, std::string filename) {
// write LLVM IR
if (global.params.output_ll) {
LLPath llpath = LLPath(filename);
LLPath llpath(filename);
llvm::sys::path::replace_extension(llpath, global.ll_ext);
Logger::println("Writing LLVM asm to: %s\n", llpath.c_str());
#if LDC_LLVM_VER >= 306
std::error_code errinfo;
#else
std::string errinfo;
#endif
ErrorInfo errinfo;
llvm::raw_fd_ostream aos(llpath.c_str(), errinfo, llvm::sys::fs::F_None);
if (aos.has_error()) {
error(Loc(), "cannot write LLVM asm file '%s': %s", llpath.c_str(),
#if LDC_LLVM_VER >= 306
errinfo
#else
errinfo.c_str()
#endif
);
ERRORINFO_STRING(errinfo));
fatal();
}
AssemblyAnnotator annotator;
@ -399,18 +389,14 @@ void writeModule(llvm::Module *m, std::string filename) {
// write native assembly
if (global.params.output_s || assembleExternally) {
LLPath spath = LLPath(filename);
LLPath spath(filename);
llvm::sys::path::replace_extension(spath, global.s_ext);
if (!global.params.output_s) {
llvm::sys::fs::createUniqueFile("ldc-%%%%%%%.s", spath);
}
Logger::println("Writing native asm to: %s\n", spath.c_str());
#if LDC_LLVM_VER >= 306
std::error_code errinfo;
#else
std::string errinfo;
#endif
ErrorInfo errinfo;
{
llvm::raw_fd_ostream out(spath.c_str(), errinfo, llvm::sys::fs::F_None);
#if LDC_LLVM_VER >= 306
@ -422,20 +408,13 @@ void writeModule(llvm::Module *m, std::string filename) {
codegenModule(*gTargetMachine, *m, out,
llvm::TargetMachine::CGFT_AssemblyFile);
} else {
error(Loc(), "cannot write native asm: %s",
#if LDC_LLVM_VER >= 306
errinfo
#else
errinfo.c_str()
#endif
);
error(Loc(), "cannot write native asm: %s", ERRORINFO_STRING(errinfo));
fatal();
}
}
if (assembleExternally) {
LLPath objpath(filename);
assemble(spath.str(), objpath.str());
assemble(spath.str(), filename);
}
if (!global.params.output_s) {
@ -444,15 +423,11 @@ void writeModule(llvm::Module *m, std::string filename) {
}
if (global.params.output_o && !assembleExternally) {
LLPath objpath = LLPath(filename);
Logger::println("Writing object file to: %s\n", objpath.c_str());
#if LDC_LLVM_VER >= 306
std::error_code errinfo;
#else
std::string errinfo;
#endif
Logger::println("Writing object file to: %s\n", filename.c_str());
ErrorInfo errinfo;
{
llvm::raw_fd_ostream out(objpath.c_str(), errinfo, llvm::sys::fs::F_None);
llvm::raw_fd_ostream out(filename.c_str(), errinfo,
llvm::sys::fs::F_None);
#if LDC_LLVM_VER >= 306
if (!errinfo)
#else
@ -462,15 +437,11 @@ void writeModule(llvm::Module *m, std::string filename) {
codegenModule(*gTargetMachine, *m, out,
llvm::TargetMachine::CGFT_ObjectFile);
} else {
error(Loc(), "cannot write object file: %s",
#if LDC_LLVM_VER >= 306
errinfo
#else
errinfo.c_str()
#endif
);
error(Loc(), "cannot write object file: %s", ERRORINFO_STRING(errinfo));
fatal();
}
}
}
#undef ERRORINFO_STRING
}

View file

@ -83,7 +83,7 @@ struct AArch64TargetABI : TargetABI {
// and set 'ap' to its address.
LLValue *valistmem = DtoRawAlloca(getValistType(), 0, "__va_list_mem");
valistmem = DtoBitCast(valistmem, getVoidPtrType());
DtoStore(valistmem, pAp); // ap = (void*)__va_list_mem
DtoStore(valistmem, DtoBitCast(pAp, getPtrToType(getVoidPtrType())));
// pass a void* pointer to the actual struct to LLVM's va_start intrinsic
return valistmem;

124
gen/abi-arm.cpp Normal file
View file

@ -0,0 +1,124 @@
//===-- abi-arm.cpp ---------------------------------------------------===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
/*
ARM ABI based on AAPCS (Procedure Call Standard for the ARM Architecture)
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf
*/
#include "gen/abi.h"
#include "gen/abi-generic.h"
#include "gen/abi-arm.h"
namespace {
struct CompositeToArray32 : ABIRewrite {
LLValue *get(Type *dty, LLValue *v) override {
Logger::println("rewriting i32 array -> as %s", dty->toChars());
LLValue *lval = DtoRawAlloca(v->getType(), 0);
DtoStore(v, lval);
LLType *pTy = getPtrToType(DtoType(dty));
return DtoLoad(DtoBitCast(lval, pTy), "get-result");
}
LLValue *put(DValue *dv) override {
Type *dty = dv->getType();
Logger::println("rewriting %s -> as i32 array", dty->toChars());
LLType *t = type(dty, nullptr);
return DtoLoad(DtoBitCast(dv->getRVal(), getPtrToType(t)));
}
LLType *type(Type *t, LLType *) override {
// An i32 array that will hold Type 't'
size_t sz = (t->size() + 3) / 4;
return LLArrayType::get(LLIntegerType::get(gIR->context(), 32), sz);
}
};
}
struct ArmTargetABI : TargetABI {
HFAToArray hfaToArray;
CompositeToArray32 compositeToArray32;
IntegerRewrite integerRewrite;
bool returnInArg(TypeFunction *tf) override {
// AAPCS 5.4 wants composites > 4-bytes returned by arg except for
// Homogeneous Aggregates of up-to 4 float types (6.1.2.1) - an HFA.
// TODO: see if Tsarray should be candidate for HFA.
if (tf->isref)
return false;
Type *rt = tf->next->toBasetype();
// For extern(D), always return structs by arg because of problem with
// non-POD structs (failure in std.algorithm.move when struct has a ctor).
// TODO: figure out what the problem is
if (tf->linkage == LINKd)
return rt->ty == Tsarray || rt->ty == Tstruct;
return rt->ty == Tsarray ||
(rt->ty == Tstruct && rt->size() > 4 && !isHFA((TypeStruct *)rt));
}
bool passByVal(Type *t) override {
// AAPCS does not pass byval
return false;
// Note: the codegen is horrible for Tsarrays passed this way - tries to do
// copy without a loop for huge arrays. Would be better if byval was used
// for arrays, but then there is an optimizer problem in the "top-down list
// latency scheduler" pass that reorders instructions incorrectly if byval
// used.
}
void rewriteFunctionType(TypeFunction *tf, IrFuncTy &fty) override {
Type *retTy = fty.ret->type->toBasetype();
if (!fty.ret->byref && retTy->ty == Tstruct) {
// Rewrite HFAs only because union HFAs are turned into IR types that are
// non-HFA and messes up register selection
if (isHFA((TypeStruct *)retTy, &fty.ret->ltype)) {
fty.ret->rewrite = &hfaToArray;
} else {
fty.ret->rewrite = &integerRewrite;
fty.ret->ltype = integerRewrite.type(fty.ret->type, fty.ret->ltype);
}
}
for (auto arg : fty.args) {
if (!arg->byref)
rewriteArgument(fty, *arg);
}
}
void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) override {
// structs and arrays need rewrite as i32 arrays. This keeps data layout
// unchanged when passed in registers r0-r3 and is necessary to match C ABI
// for struct passing. Without out this rewrite, each field or array
// element is passed in own register. For example: char[4] now all fits in
// r0, where before it consumed r0-r3.
Type *ty = arg.type->toBasetype();
// TODO: want to also rewrite Tsarray as i32 arrays, but sometimes
// llvm selects an aligned ldrd instruction even though the ptr is
// unaligned (e.g. walking through members of array char[5][]).
// if (ty->ty == Tstruct || ty->ty == Tsarray)
if (ty->ty == Tstruct) {
// Rewrite HFAs only because union HFAs are turned into IR types that are
// non-HFA and messes up register selection
if (isHFA((TypeStruct *)ty, &arg.ltype)) {
arg.rewrite = &hfaToArray;
} else {
arg.rewrite = &compositeToArray32;
arg.ltype = compositeToArray32.type(arg.type, arg.ltype);
}
}
}
};
TargetABI *getArmTargetABI() { return new ArmTargetABI; }

21
gen/abi-arm.h Normal file
View file

@ -0,0 +1,21 @@
//===-- gen/abi-arm.h - ARM ABI description -------------*- C++ -*-===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
//
// The ABI implementation used for ARM targets.
//
//===----------------------------------------------------------------------===//
#ifndef LDC_GEN_ABI_ARM_H
#define LDC_GEN_ABI_ARM_H
struct TargetABI;
TargetABI *getArmTargetABI();
#endif

View file

@ -227,4 +227,34 @@ struct ExplicitByvalRewrite : ABIRewrite {
}
};
/**
* Rewrite Homogeneous Homogeneous Floating-point Aggregate (HFA) as array of
* float type.
*/
struct HFAToArray : ABIRewrite {
LLValue *get(Type *dty, LLValue *v) override {
Logger::println("rewriting array -> as HFA %s", dty->toChars());
LLValue *lval = DtoRawAlloca(v->getType(), 0);
DtoStore(v, lval);
LLType *pTy = getPtrToType(DtoType(dty));
return DtoLoad(DtoBitCast(lval, pTy), "get-result");
}
LLValue *put(DValue *dv) override {
Type *dty = dv->getType();
Logger::println("rewriting HFA %s -> as array", dty->toChars());
LLType *t = type(dty, nullptr);
return DtoLoad(DtoBitCast(dv->getRVal(), getPtrToType(t)));
}
LLType *type(Type *dty, LLType *) override {
assert(dty->ty == Tstruct);
LLType *floatArrayType = nullptr;
if (TargetABI::isHFA((TypeStruct *)dty, &floatArrayType))
return floatArrayType;
llvm_unreachable("Type dty should be an HFA");
}
};
#endif

View file

@ -12,6 +12,7 @@
#include "id.h"
#include "gen/abi-generic.h"
#include "gen/abi-aarch64.h"
#include "gen/abi-arm.h"
#include "gen/abi-mips64.h"
#include "gen/abi-ppc64.h"
#include "gen/abi-win64.h"
@ -97,6 +98,113 @@ LLValue *ABIRewrite::loadFromMemory(LLValue *address, LLType *asType,
//////////////////////////////////////////////////////////////////////////////
// A Homogeneous Floating-point Aggregate (HFA) is an ARM/AArch64 concept that
// consists of up to 4 of same floating point type. D floats of same size are
// considered as same (e.g. ifloat and float are same). It is the aggregate
// final data layout that matters so nested structs, unions, and sarrays can
// result in an HFA.
//
// simple HFAs: struct F1 {float f;} struct D4 {double a,b,c,d;}
// interesting HFA: struct {F1[2] vals; float weight;}
namespace {
bool isNestedHFA(const TypeStruct *t, d_uns64 &floatSize, int &num,
uinteger_t adim) {
// Used internally by isHFA() to check struct recursively for HFA-ness.
// Return true if struct 't' is part of an HFA where 'floatSize' is sizeof
// the float and 'num' is number of these floats so far. On return, 'num'
// is updated to the total number of floats in the HFA. Set 'floatSize'
// to 0 discover the sizeof the float. When struct 't' is part of an
// sarray, 'adim' is the dimension of that array, otherwise it is 1.
VarDeclarations fields = t->sym->fields;
// HFA can't contains an empty struct
if (fields.dim == 0)
return false;
// Accumulate number of floats in HFA
int n;
// For unions, need to find field with most floats
int maxn = num;
for (size_t i = 0; i < fields.dim; ++i) {
Type *field = fields[i]->type;
// reset to initial num floats (all union fields are at offset 0)
if (fields[i]->offset == 0)
n = num;
// reset dim to dimension of sarray we are in (will be 1 if not)
uinteger_t dim = adim;
// Field is an array. Process the arrayof type and multiply dim by
// array dim. Note that empty arrays immediately exclude this struct
// from HFA status.
if (field->ty == Tsarray) {
TypeSArray *array = (TypeSArray *)field;
if (array->dim->toUInteger() == 0)
return false;
field = array->nextOf();
dim *= array->dim->toUInteger();
}
if (field->ty == Tstruct) {
if (!isNestedHFA((TypeStruct *)field, floatSize, n, dim))
return false;
} else if (field->isfloating()) {
d_uns64 sz = field->size();
n += dim;
if (field->iscomplex()) {
sz /= 2; // complex is 2 floats, adjust sz
n += dim;
}
if (floatSize == 0) // discovered floatSize
floatSize = sz;
else if (sz != floatSize) // different float size, reject
return false;
if (n > 4)
return false; // too many floats for HFA, reject
} else {
return false; // reject all other types
}
if (n > maxn)
maxn = n;
}
num = maxn;
return true;
}
}
bool TargetABI::isHFA(TypeStruct *t, llvm::Type **rewriteType) {
d_uns64 floatSize = 0;
int num = 0;
if (isNestedHFA(t, floatSize, num, 1)) {
if (rewriteType) {
llvm::Type *floatType = nullptr;
switch (floatSize) {
case 4:
floatType = llvm::Type::getFloatTy(gIR->context());
break;
case 8:
floatType = llvm::Type::getDoubleTy(gIR->context());
break;
default:
llvm_unreachable("Unexpected size for float type");
}
*rewriteType = LLArrayType::get(floatType, num);
}
return true;
}
return false;
}
bool TargetABI::isAggregate(Type *t) {
TY ty = t->toBasetype()->ty;
// FIXME: dynamic arrays can currently not be rewritten as they are used
@ -235,6 +343,11 @@ TargetABI *TargetABI::getTarget() {
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
return getAArch64TargetABI();
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
return getArmTargetABI();
default:
Logger::cout() << "WARNING: Unknown ABI, guessing...\n";
return new UnknownTargetABI;

View file

@ -23,6 +23,7 @@
class Type;
class TypeFunction;
class TypeStruct;
struct IrFuncTy;
struct IrFuncTyArg;
class DValue;
@ -148,9 +149,15 @@ struct TargetABI {
/// Must match the alias in druntime.
virtual Type *vaListType();
protected:
/***** Static Helpers *****/
/// Check if struct 't' is a Homogeneous Floating-point Aggregate (HFA)
/// consisting of up to 4 of same floating point type. If so, optionally
/// produce the rewriteType: an array of that floating point type
static bool isHFA(TypeStruct *t, llvm::Type **rewriteType = nullptr);
protected:
/// Returns true if the D type is an aggregate:
/// * struct
/// * static/dynamic array

View file

@ -151,9 +151,9 @@ ldc::DIType ldc::DIBuilder::CreateBasicType(Type *type) {
"Unsupported basic type for debug info in DIBuilder::CreateBasicType");
}
return DBuilder.createBasicType(type->toChars(), // name
getTypeBitSize(T), // size (bits)
getABITypeAlign(T) * 8, // align (bits)
return DBuilder.createBasicType(type->toChars(), // name
getTypeAllocSize(T) * 8, // size (bits)
getABITypeAlign(T) * 8, // align (bits)
Encoding);
}
@ -182,7 +182,7 @@ ldc::DIType ldc::DIBuilder::CreateEnumType(Type *type) {
return DBuilder.createEnumerationType(
GetCU(), Name, File, LineNumber,
getTypeBitSize(T), // size (bits)
getTypeAllocSize(T) * 8, // size (bits)
getABITypeAlign(T) * 8, // align (bits)
DBuilder.getOrCreateArray(subscripts), // subscripts
CreateTypeDescription(te->sym->memtype, false));
@ -201,9 +201,9 @@ ldc::DIType ldc::DIBuilder::CreatePointerType(Type *type) {
ldc::DIType basetype(CreateTypeDescription(nt, false));
return DBuilder.createPointerType(basetype,
getTypeBitSize(T), // size (bits)
getABITypeAlign(T) * 8, // align (bits)
type->toChars() // name
getTypeAllocSize(T) * 8, // size (bits)
getABITypeAlign(T) * 8, // align (bits)
type->toChars() // name
);
}
@ -225,7 +225,7 @@ ldc::DIType ldc::DIBuilder::CreateVectorType(Type *type) {
ldc::DIType basetype(CreateTypeDescription(te, false));
return DBuilder.createVectorType(
getTypeBitSize(T), // size (bits)
getTypeAllocSize(T) * 8, // size (bits)
getABITypeAlign(T) * 8, // align (bits)
basetype, // element type
DBuilder.getOrCreateArray(subscripts) // subscripts
@ -260,14 +260,14 @@ ldc::DIType ldc::DIBuilder::CreateMemberType(unsigned linnum, Type *type,
}
return DBuilder.createMemberType(GetCU(),
c_name, // name
file, // file
linnum, // line number
getTypeBitSize(T), // size (bits)
getABITypeAlign(T) * 8, // align (bits)
offset * 8, // offset (bits)
Flags, // flags
basetype // derived from
c_name, // name
file, // file
linnum, // line number
getTypeAllocSize(T) * 8, // size (bits)
getABITypeAlign(T) * 8, // align (bits)
offset * 8, // offset (bits)
Flags, // flags
basetype // derived from
);
}
@ -381,18 +381,18 @@ ldc::DIType ldc::DIBuilder::CreateCompositeType(Type *type) {
name, // name
file, // file where defined
linnum, // line number where defined
getTypeBitSize(T), // size in bits
getABITypeAlign(T) * 8, // alignment in bits
0, // offset in bits,
DIFlags::FlagFwdDecl, // flags
derivedFrom, // DerivedFrom
getTypeAllocSize(T) * 8, // size in bits
getABITypeAlign(T) * 8, // alignment in bits
0, // offset in bits,
DIFlags::FlagFwdDecl, // flags
derivedFrom, // DerivedFrom
elemsArray);
} else {
ret = DBuilder.createStructType(CU, // compile unit where defined
name, // name
file, // file where defined
linnum, // line number where defined
getTypeBitSize(T), // size in bits
getTypeAllocSize(T) * 8, // size in bits
getABITypeAlign(T) * 8, // alignment in bits
DIFlags::FlagFwdDecl, // flags
derivedFrom, // DerivedFrom
@ -434,9 +434,9 @@ ldc::DIType ldc::DIBuilder::CreateArrayType(Type *type) {
llvm::StringRef(), // Name TODO: Really no name for arrays? t->toChars()?
file, // File
0, // LineNo
getTypeBitSize(T), // size in bits
getABITypeAlign(T) * 8, // alignment in bits
0, // What here?
getTypeAllocSize(T) * 8, // size in bits
getABITypeAlign(T) * 8, // alignment in bits
0, // What here?
#if LDC_LLVM_VER >= 307
nullptr, // DerivedFrom
#else
@ -469,7 +469,7 @@ ldc::DIType ldc::DIBuilder::CreateSArrayType(Type *type) {
ldc::DIType basetype(CreateTypeDescription(t, false));
return DBuilder.createArrayType(
getTypeBitSize(T), // size (bits)
getTypeAllocSize(T) * 8, // size (bits)
getABITypeAlign(T) * 8, // align (bits)
basetype, // element type
DBuilder.getOrCreateArray(subscripts) // subscripts

View file

@ -75,8 +75,7 @@ bool isTargetWindowsMSVC() {
LLValue *DtoNew(Loc &loc, Type *newtype) {
// get runtime function
llvm::Function *fn =
getRuntimeFunction(loc, gIR->module, "_d_allocmemoryT");
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_allocmemoryT");
// get type info
LLConstant *ti = DtoTypeInfoOf(newtype);
assert(isaPointer(ti));
@ -96,16 +95,14 @@ LLValue *DtoNewStruct(Loc &loc, TypeStruct *newtype) {
}
void DtoDeleteMemory(Loc &loc, DValue *ptr) {
llvm::Function *fn =
getRuntimeFunction(loc, gIR->module, "_d_delmemory");
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_delmemory");
LLValue *lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
gIR->CreateCallOrInvoke(
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
}
void DtoDeleteStruct(Loc &loc, DValue *ptr) {
llvm::Function *fn =
getRuntimeFunction(loc, gIR->module, "_d_delstruct");
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_delstruct");
LLValue *lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
gIR->CreateCallOrInvoke(
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)),
@ -114,24 +111,21 @@ void DtoDeleteStruct(Loc &loc, DValue *ptr) {
}
void DtoDeleteClass(Loc &loc, DValue *inst) {
llvm::Function *fn =
getRuntimeFunction(loc, gIR->module, "_d_delclass");
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_delclass");
LLValue *lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
gIR->CreateCallOrInvoke(
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
}
void DtoDeleteInterface(Loc &loc, DValue *inst) {
llvm::Function *fn =
getRuntimeFunction(loc, gIR->module, "_d_delinterface");
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_delinterface");
LLValue *lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
gIR->CreateCallOrInvoke(
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
}
void DtoDeleteArray(Loc &loc, DValue *arr) {
llvm::Function *fn =
getRuntimeFunction(loc, gIR->module, "_d_delarray_t");
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_delarray_t");
llvm::FunctionType *fty = fn->getFunctionType();
// the TypeInfo argument must be null if the type has no dtor
@ -195,8 +189,7 @@ llvm::AllocaInst *DtoRawAlloca(LLType *lltype, size_t alignment,
LLValue *DtoGcMalloc(Loc &loc, LLType *lltype, const char *name) {
// get runtime function
llvm::Function *fn =
getRuntimeFunction(loc, gIR->module, "_d_allocmemory");
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_allocmemory");
// parameters
LLValue *size = DtoConstSize_t(getTypeAllocSize(lltype));
// call runtime allocator
@ -600,6 +593,23 @@ DValue *DtoCastVector(Loc &loc, DValue *val, Type *to) {
fatal();
}
DValue *DtoCastStruct(Loc &loc, DValue *val, Type *to) {
Type *const totype = to->toBasetype();
if (totype->ty == Tstruct) {
// This a cast to repaint a struct to another type, which the language
// allows for identical layouts (opCast() and so on have been lowered
// earlier by the frontend).
llvm::Value *rv = val->getRVal();
llvm::Value *result =
DtoBitCast(rv, DtoType(to)->getPointerTo(), rv->getName() + ".repaint");
return new DImValue(to, result);
}
error(loc, "Internal Compiler Error: Invalid struct cast from '%s' to '%s'",
val->getType()->toChars(), to->toChars());
fatal();
}
DValue *DtoCast(Loc &loc, DValue *val, Type *to) {
Type *fromtype = val->getType()->toBasetype();
Type *totype = to->toBasetype();
@ -629,6 +639,7 @@ DValue *DtoCast(Loc &loc, DValue *val, Type *to) {
LOG_SCOPE;
if (fromtype->ty == Tvector) {
// First, handle vector types (which can also be isintegral()).
return DtoCastVector(loc, val, to);
}
if (fromtype->isintegral()) {
@ -640,27 +651,33 @@ DValue *DtoCast(Loc &loc, DValue *val, Type *to) {
if (fromtype->isfloating()) {
return DtoCastFloat(loc, val, to);
}
if (fromtype->ty == Tclass) {
switch (fromtype->ty) {
case Tclass:
return DtoCastClass(loc, val, to);
}
if (fromtype->ty == Tarray || fromtype->ty == Tsarray) {
case Tarray:
case Tsarray:
return DtoCastArray(loc, val, to);
}
if (fromtype->ty == Tpointer || fromtype->ty == Tfunction) {
case Tpointer:
case Tfunction:
return DtoCastPtr(loc, val, to);
}
if (fromtype->ty == Tdelegate) {
case Tdelegate:
return DtoCastDelegate(loc, val, to);
}
if (fromtype->ty == Tnull) {
case Tstruct:
return DtoCastStruct(loc, val, to);
case Tnull:
return DtoNullValue(to, loc);
case Taarray:
if (totype->ty == Taarray) {
// Do nothing, the types will match up anyway.
return new DImValue(to, val->getRVal());
}
// fall-through
default:
error(loc, "invalid cast from '%s' to '%s'", val->getType()->toChars(),
to->toChars());
fatal();
}
if (fromtype->ty == totype->ty) {
return val;
}
error(loc, "invalid cast from '%s' to '%s'", val->getType()->toChars(),
to->toChars());
fatal();
}
////////////////////////////////////////////////////////////////////////////////
@ -1397,7 +1414,6 @@ LLValue *makeLValue(Loc &loc, DValue *value) {
////////////////////////////////////////////////////////////////////////////////
void callPostblit(Loc &loc, Expression *exp, LLValue *val) {
Type *tb = exp->type->toBasetype();
if ((exp->op == TOKvar || exp->op == TOKdotvar || exp->op == TOKstar ||
exp->op == TOKthis || exp->op == TOKindex) &&

View file

@ -178,8 +178,7 @@ void DtoDefineNakedFunction(FuncDeclaration *fd) {
// Windows is different
else if (isWin) {
std::string fullMangle;
if (global.params.targetTriple->isWindowsGNUEnvironment() &&
!global.params.targetTriple->isArch64Bit()) {
if (!global.params.targetTriple->isArch64Bit()) {
fullMangle = "_";
}
fullMangle += mangle;

View file

@ -42,8 +42,14 @@ RTTIBuilder::RTTIBuilder(AggregateDeclaration *base_class) {
void RTTIBuilder::push(llvm::Constant *C) {
// We need to explicitly zero any padding bytes as per TDPL §7.1.1 (and
// also match the struct type lowering code here).
const uint64_t fieldStart = llvm::RoundUpToAlignment(
prevFieldEnd, gDataLayout->getABITypeAlignment(C->getType()));
const uint64_t fieldStart =
#if LDC_LLVM_VER >= 309
llvm::alignTo
#else
llvm::RoundUpToAlignment
#endif
(prevFieldEnd, gDataLayout->getABITypeAlignment(C->getType()));
const uint64_t paddingBytes = fieldStart - prevFieldEnd;
if (paddingBytes) {
llvm::Type *const padding = llvm::ArrayType::get(

View file

@ -653,34 +653,23 @@ static void buildRuntimeModule() {
{objectTy});
// void _d_dso_registry(CompilerDSOData* data)
if (global.params.targetTriple->isOSLinux() || global.params.targetTriple->isOSFreeBSD() ||
#if LDC_LLVM_VER > 305
global.params.targetTriple->isOSNetBSD() || global.params.targetTriple->isOSOpenBSD() ||
global.params.targetTriple->isOSDragonFly()
#else
global.params.targetTriple->getOS() == llvm::Triple::NetBSD ||
global.params.targetTriple->getOS() == llvm::Triple::OpenBSD ||
global.params.targetTriple->getOS() == llvm::Triple::DragonFly
#endif
) {
llvm::StringRef fname("_d_dso_registry");
llvm::StringRef fname("_d_dso_registry");
LLType *LLvoidTy = LLType::getVoidTy(gIR->context());
LLType *LLvoidPtrPtrTy = getPtrToType(getPtrToType(LLvoidTy));
LLType *moduleInfoPtrPtrTy =
getPtrToType(getPtrToType(DtoType(Module::moduleinfo->type)));
LLType *LLvoidTy = LLType::getVoidTy(gIR->context());
LLType *LLvoidPtrPtrTy = getPtrToType(getPtrToType(LLvoidTy));
LLType *moduleInfoPtrPtrTy =
getPtrToType(getPtrToType(DtoType(Module::moduleinfo->type)));
llvm::StructType *dsoDataTy =
llvm::StructType::get(DtoSize_t(), // version
LLvoidPtrPtrTy, // slot
moduleInfoPtrPtrTy, // _minfo_beg
moduleInfoPtrPtrTy, // _minfo_end
NULL);
llvm::StructType *dsoDataTy =
llvm::StructType::get(DtoSize_t(), // version
LLvoidPtrPtrTy, // slot
moduleInfoPtrPtrTy, // _minfo_beg
moduleInfoPtrPtrTy, // _minfo_end
NULL);
llvm::Type *types[] = {getPtrToType(dsoDataTy)};
llvm::FunctionType *fty = llvm::FunctionType::get(LLvoidTy, types, false);
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
llvm::Type *types[] = {getPtrToType(dsoDataTy)};
llvm::FunctionType *fty = llvm::FunctionType::get(LLvoidTy, types, false);
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

View file

@ -71,7 +71,17 @@ unsigned Target::critsecsize() {
if (global.params.targetTriple->isOSWindows()) {
return global.params.is64bit ? 40 : 24;
}
if (global.params.targetTriple->getOS() == llvm::Triple::FreeBSD) {
if (global.params.targetTriple->isOSFreeBSD() ||
#if LDC_LLVM_VER > 305
global.params.targetTriple->isOSNetBSD() ||
global.params.targetTriple->isOSOpenBSD() ||
global.params.targetTriple->isOSDragonFly()
#else
global.params.targetTriple->getOS() == llvm::Triple::NetBSD ||
global.params.targetTriple->getOS() == llvm::Triple::OpenBSD ||
global.params.targetTriple->getOS() == llvm::Triple::DragonFly
#endif
) {
return sizeof(size_t);
}
return sizeof(pthread_mutex_t);

View file

@ -505,7 +505,7 @@ void DtoAlignedStore(LLValue *src, LLValue *dst) {
////////////////////////////////////////////////////////////////////////////////
LLValue *DtoBitCast(LLValue *v, LLType *t, const char *name) {
LLValue *DtoBitCast(LLValue *v, LLType *t, const llvm::Twine &name) {
if (v->getType() == t) {
return v;
}
@ -668,8 +668,18 @@ LLStructType *DtoMutexType() {
return mutex;
}
// FreeBSD
if (global.params.targetTriple->getOS() == llvm::Triple::FreeBSD) {
// FreeBSD, NetBSD, OpenBSD, DragonFly
if (global.params.targetTriple->isOSFreeBSD() ||
#if LDC_LLVM_VER > 305
global.params.targetTriple->isOSNetBSD() ||
global.params.targetTriple->isOSOpenBSD() ||
global.params.targetTriple->isOSDragonFly()
#else
global.params.targetTriple->getOS() == llvm::Triple::NetBSD ||
global.params.targetTriple->getOS() == llvm::Triple::OpenBSD ||
global.params.targetTriple->getOS() == llvm::Triple::DragonFly
#endif
) {
// Just a pointer
return LLStructType::get(gIR->context(), DtoSize_t());
}

View file

@ -100,7 +100,7 @@ void DtoStore(LLValue *src, LLValue *dst);
void DtoVolatileStore(LLValue *src, LLValue *dst);
void DtoStoreZextI8(LLValue *src, LLValue *dst);
void DtoAlignedStore(LLValue *src, LLValue *dst);
LLValue *DtoBitCast(LLValue *v, LLType *t, const char *name = "");
LLValue *DtoBitCast(LLValue *v, LLType *t, const llvm::Twine &name = "");
LLConstant *DtoBitCast(LLConstant *v, LLType *t);
LLValue *DtoInsertValue(LLValue *aggr, LLValue *v, unsigned idx,
const char *name = "");

View file

@ -16,11 +16,8 @@
#include "gen/tollvm.h"
#include "ir/irtype.h"
// This code uses llvm::getGlobalContext() as these functions are invoked before
// gIR is set.
// ... thus it segfaults on gIR==NULL
//////////////////////////////////////////////////////////////////////////////
// These functions use llvm::getGlobalContext() as they are invoked before gIR
// is set.
IrType::IrType(Type *dt, LLType *lt) : dtype(dt), type(lt) {
assert(dt && "null D Type");
@ -28,36 +25,27 @@ IrType::IrType(Type *dt, LLType *lt) : dtype(dt), type(lt) {
assert(!dt->ctype && "already has IrType");
}
//////////////////////////////////////////////////////////////////////////////
IrFuncTy &IrType::getIrFuncTy() {
llvm_unreachable("cannot get IrFuncTy from non lazy/function/delegate");
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
IrTypeBasic::IrTypeBasic(Type *dt) : IrType(dt, basic2llvm(dt)) {}
//////////////////////////////////////////////////////////////////////////////
IrTypeBasic *IrTypeBasic::get(Type *dt) {
auto t = new IrTypeBasic(dt);
dt->ctype = t;
return t;
}
//////////////////////////////////////////////////////////////////////////////
LLType *IrTypeBasic::getComplexType(llvm::LLVMContext &ctx, LLType *type) {
llvm::Type *types[] = {type, type};
return llvm::StructType::get(ctx, types, false);
}
//////////////////////////////////////////////////////////////////////////////
static inline llvm::Type *getReal80Type(llvm::LLVMContext &ctx) {
namespace {
llvm::Type *getReal80Type(llvm::LLVMContext &ctx) {
llvm::Triple::ArchType const a = global.params.targetTriple->getArch();
bool const anyX86 = (a == llvm::Triple::x86) || (a == llvm::Triple::x86_64);
@ -68,8 +56,7 @@ static inline llvm::Type *getReal80Type(llvm::LLVMContext &ctx) {
return llvm::Type::getDoubleTy(ctx);
}
//////////////////////////////////////////////////////////////////////////////
}
llvm::Type *IrTypeBasic::basic2llvm(Type *t) {
llvm::LLVMContext &ctx = llvm::getGlobalContext();
@ -129,14 +116,10 @@ llvm::Type *IrTypeBasic::basic2llvm(Type *t) {
}
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
IrTypePointer::IrTypePointer(Type *dt, LLType *lt) : IrType(dt, lt) {}
//////////////////////////////////////////////////////////////////////////////
IrTypePointer *IrTypePointer::get(Type *dt) {
assert(!dt->ctype);
assert((dt->ty == Tpointer || dt->ty == Tnull) && "not pointer/null type");
@ -159,38 +142,31 @@ IrTypePointer *IrTypePointer::get(Type *dt) {
return t;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
IrTypeSArray::IrTypeSArray(Type *dt) : IrType(dt, sarray2llvm(dt)) {}
//////////////////////////////////////////////////////////////////////////////
IrTypeSArray::IrTypeSArray(Type *dt, LLType *lt) : IrType(dt, lt) {}
IrTypeSArray *IrTypeSArray::get(Type *dt) {
auto t = new IrTypeSArray(dt);
dt->ctype = t;
return t;
assert(!dt->ctype);
assert(dt->ty == Tsarray && "not static array type");
LLType *elemType = DtoMemType(dt->nextOf());
// We might have already built the type during DtoMemType e.g. as part of a
// forward reference in a struct.
if (!dt->ctype) {
TypeSArray *tsa = static_cast<TypeSArray *>(dt);
uint64_t dim = static_cast<uint64_t>(tsa->dim->toUInteger());
dt->ctype = new IrTypeSArray(dt, llvm::ArrayType::get(elemType, dim));
}
return dt->ctype->isSArray();
}
//////////////////////////////////////////////////////////////////////////////
llvm::Type *IrTypeSArray::sarray2llvm(Type *t) {
assert(t->ty == Tsarray && "not static array type");
TypeSArray *tsa = static_cast<TypeSArray *>(t);
uint64_t dim = static_cast<uint64_t>(tsa->dim->toUInteger());
LLType *elemType = DtoMemType(t->nextOf());
return llvm::ArrayType::get(elemType, dim);
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
IrTypeArray::IrTypeArray(Type *dt, LLType *lt) : IrType(dt, lt) {}
//////////////////////////////////////////////////////////////////////////////
IrTypeArray *IrTypeArray::get(Type *dt) {
assert(!dt->ctype);
assert(dt->ty == Tarray && "not dynamic array type");
@ -208,22 +184,20 @@ IrTypeArray *IrTypeArray::get(Type *dt) {
return dt->ctype->isArray();
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
IrTypeVector::IrTypeVector(Type *dt) : IrType(dt, vector2llvm(dt)) {}
//////////////////////////////////////////////////////////////////////////////
IrTypeVector::IrTypeVector(Type *dt, llvm::Type *lt) : IrType(dt, lt) {}
IrTypeVector *IrTypeVector::get(Type *dt) {
auto t = new IrTypeVector(dt);
dt->ctype = t;
return t;
LLType *lt = vector2llvm(dt);
// Could have already built the type as part of a struct forward reference,
// just as for pointers and arrays.
if (!dt->ctype) {
dt->ctype = new IrTypeVector(dt, lt);
}
return dt->ctype->isVector();
}
//////////////////////////////////////////////////////////////////////////////
llvm::Type *IrTypeVector::vector2llvm(Type *dt) {
assert(dt->ty == Tvector && "not vector type");
TypeVector *tv = static_cast<TypeVector *>(dt);
@ -233,5 +207,3 @@ llvm::Type *IrTypeVector::vector2llvm(Type *dt) {
LLType *elemType = DtoMemType(tsa->next);
return llvm::VectorType::get(elemType, dim);
}
//////////////////////////////////////////////////////////////////////////////

View file

@ -46,17 +46,17 @@ class IrTypeVector;
///
/// Derived classes should be created using their static get() methods, which
/// makes sure that uniqueness is preserved in the face of forward references.
/// Note that the get() methods expect the IrType of the passed type/symbol to
/// be not yet set.
///
/// This could be altered to just return the existing IrType in order to bring
/// the API entirely in line with the LLVM type get() methods. It has not been
/// changed so far since currently all clients use the DtoType wrapper rather
/// than handling IrType instances directly, and keeping it this way allows to
/// easily check for uniqueness violations in the face of forward references.
/// TODO: Implement the described changes (now that the forward reference
/// handling logic seems to work correctly) and get rid of the "no-op" DtoType
/// calls in IrAggr, ... that only exist for their side effect.
/// Note that the get() methods expect the IrType of the passed type/symbol not
/// to be set yet. Another option would be to just return the existing IrType
/// in such cases. This would bring the API more in line with the llvm::Type
/// get() functions. Currently all clients use the DtoType() wrapper anyway
/// instead of directly handling IrType instances, so keeping the assertions
/// allows us to check for any uniqueness violations that might have slipped
/// through.
// TODO: Implement the described changes (now that the forward reference
// handling logic seems to work correctly) and get rid of the "no-op" DtoType
// calls in IrAggr, ... that only exist for their side effect.
class IrType {
public:
virtual ~IrType() = default;
@ -150,10 +150,7 @@ public:
protected:
///
explicit IrTypeSArray(Type *dt);
///
static llvm::Type *sarray2llvm(Type *t);
IrTypeSArray(Type *dt, LLType *lt);
};
//////////////////////////////////////////////////////////////////////////////
@ -185,7 +182,7 @@ public:
protected:
///
explicit IrTypeVector(Type *dt);
explicit IrTypeVector(Type *dt, llvm::Type *lt);
static llvm::Type *vector2llvm(Type *dt);
};

View file

@ -26,9 +26,12 @@ IrTypeFunction *IrTypeFunction::get(Type *dt) {
IrFuncTy irFty;
llvm::Type *lt = DtoFunctionType(dt, irFty, nullptr, nullptr);
auto result = new IrTypeFunction(dt, lt, irFty);
dt->ctype = result;
return result;
// Could have already built the type as part of a struct forward reference,
// just as for pointers and arrays.
if (!dt->ctype) {
dt->ctype = new IrTypeFunction(dt, lt, irFty);
}
return dt->ctype->isFunction();
}
//////////////////////////////////////////////////////////////////////////////
@ -47,7 +50,10 @@ IrTypeDelegate *IrTypeDelegate::get(Type *t) {
llvm::Type *types[] = {getVoidPtrType(), getPtrToType(ltf)};
LLStructType *lt = LLStructType::get(gIR->context(), types, false);
auto result = new IrTypeDelegate(t, lt, irFty);
t->ctype = result;
return result;
// Could have already built the type as part of a struct forward reference,
// just as for pointers and arrays.
if (!t->ctype) {
t->ctype = new IrTypeDelegate(t, lt, irFty);
}
return t->ctype->isDelegate();
}

View file

@ -84,6 +84,7 @@ else()
endif()
file(GLOB_RECURSE CORE_D_UNIX ${RUNTIME_DIR}/src/core/sys/posix/*.d)
file(GLOB_RECURSE CORE_D_FREEBSD ${RUNTIME_DIR}/src/core/sys/freebsd/*.d)
file(GLOB_RECURSE CORE_D_NETBSD ${RUNTIME_DIR}/src/core/sys/netbsd/*.d)
file(GLOB_RECURSE CORE_D_LINUX ${RUNTIME_DIR}/src/core/sys/linux/*.d)
file(GLOB_RECURSE CORE_D_OSX ${RUNTIME_DIR}/src/core/sys/osx/*.d)
file(GLOB_RECURSE CORE_D_SOLARIS ${RUNTIME_DIR}/src/core/sys/solaris/*.d)
@ -95,6 +96,9 @@ if(UNIX)
if(${CMAKE_SYSTEM} MATCHES "FreeBSD")
list(APPEND CORE_D_SYS ${CORE_D_FREEBSD})
endif()
if(${CMAKE_SYSTEM} MATCHES "NetBSD")
list(APPEND CORE_D_SYS ${CORE_D_NETBSD})
endif()
if(${CMAKE_SYSTEM} MATCHES "Linux")
list(APPEND CORE_D_SYS ${CORE_D_LINUX})
endif()
@ -214,11 +218,31 @@ configure_file(${PROJECT_PARENT_DIR}/${LDC_EXE}_install.conf.in ${PROJECT_BINARY
# druntime/Phobos compilation helpers.
#
set(GCCBUILTINS "${PROJECT_BINARY_DIR}/gccbuiltins_x86.di")
add_custom_command(
OUTPUT ${GCCBUILTINS}
COMMAND gen_gccbuiltins ${GCCBUILTINS} "x86"
)
set(GCCBUILTINS "")
function(gen_gccbuiltins name)
set(module "gccbuiltins_${name}.di")
if (GCCBUILTINS STREQUAL "")
set(GCCBUILTINS "${module}" PARENT_SCOPE)
else()
set(GCCBUILTINS "${GCCBUILTINS};${module}" PARENT_SCOPE)
endif()
add_custom_command(
OUTPUT ${module}
COMMAND gen_gccbuiltins ${module} "${name}"
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
)
endfunction()
set(target_arch "AArch64;ARM;Mips;PowerPC;SystemZ;X86")
set(target_name "aarch64;arm;mips;ppc;s390;x86")
foreach(target ${LLVM_TARGETS_TO_BUILD})
list(FIND target_arch ${target} idx)
if(idx GREATER -1)
list(GET target_name ${idx} name)
gen_gccbuiltins(${name})
endif()
endforeach()
# Always build zlib and other C parts of the runtime in release mode, regardless
# of what the user chose for LDC itself.

@ -1 +1 @@
Subproject commit 2cdd96be5070cfabf5cf2724a8dea46cd3922999
Subproject commit 65ea3f07dee9132c0aa8344d612e19e520e600df

@ -1 +1 @@
Subproject commit 74730f61530d4d653b047bb02948e15064a214c1
Subproject commit 83fbcc4b18527c2a7c8181a51098f215e4a14b10

@ -1 +1 @@
Subproject commit 2c1a5ed7603f809eab6f565e9ee924cc0f5e1005
Subproject commit 25c2a1be486b6cb60584f5a74fa978450559dbbd