mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 09:00:33 +03:00
Merge remote-tracking branch 'origin/master' into merge-2.094
Conflicts: gen/tocall.cpp runtime/phobos
This commit is contained in:
commit
6f5730049b
60 changed files with 2947 additions and 529 deletions
|
@ -54,26 +54,26 @@ components="aarch64 aarch64asmparser aarch64codegen aarch64desc aarch64disassemb
|
||||||
aggressiveinstcombine all all-targets analysis arm armasmparser armcodegen armdesc armdisassembler arminfo \
|
aggressiveinstcombine all all-targets analysis arm armasmparser armcodegen armdesc armdisassembler arminfo \
|
||||||
armutils asmparser asmprinter binaryformat bitreader bitstreamreader bitwriter cfguard codegen core coroutines \
|
armutils asmparser asmprinter binaryformat bitreader bitstreamreader bitwriter cfguard codegen core coroutines \
|
||||||
coverage debuginfocodeview debuginfodwarf debuginfogsym debuginfomsf debuginfopdb demangle dlltooldriver \
|
coverage debuginfocodeview debuginfodwarf debuginfogsym debuginfomsf debuginfopdb demangle dlltooldriver \
|
||||||
dwarflinker engine executionengine frontendopenmp fuzzmutate globalisel instcombine instrumentation interpreter \
|
dwarflinker engine executionengine extensions frontendopenmp fuzzmutate globalisel instcombine instrumentation interpreter \
|
||||||
ipo irreader jitlink libdriver lineeditor linker lto mc mca mcdisassembler mcjit mcparser mirparser native \
|
ipo irreader jitlink libdriver lineeditor linker lto mc mca mcdisassembler mcjit mcparser mirparser native \
|
||||||
nativecodegen objcarcopts object objectyaml option orcerror orcjit passes profiledata remarks runtimedyld \
|
nativecodegen objcarcopts object objectyaml option orcerror orcjit passes profiledata remarks runtimedyld \
|
||||||
scalaropts selectiondag support symbolize tablegen target textapi transformutils vectorize webassembly \
|
scalaropts selectiondag support symbolize tablegen target textapi transformutils vectorize webassembly \
|
||||||
webassemblyasmparser webassemblycodegen webassemblydesc webassemblydisassembler webassemblyinfo windowsmanifest \
|
webassemblyasmparser webassemblycodegen webassemblydesc webassemblydisassembler webassemblyinfo windowsmanifest \
|
||||||
x86 x86asmparser x86codegen x86desc x86disassembler x86info x86utils xray"
|
x86 x86asmparser x86codegen x86desc x86disassembler x86info xray"
|
||||||
static_libs="-lLLVMXRay -lLLVMWindowsManifest -lLLVMTableGen -lLLVMSymbolize -lLLVMDebugInfoPDB -lLLVMOrcJIT \
|
static_libs="-lLLVMXRay -lLLVMWindowsManifest -lLLVMTableGen -lLLVMSymbolize -lLLVMDebugInfoPDB -lLLVMOrcJIT \
|
||||||
-lLLVMOrcError -lLLVMJITLink -lLLVMObjectYAML -lLLVMMIRParser -lLLVMMCA -lLLVMLTO -lLLVMPasses -lLLVMObjCARCOpts \
|
-lLLVMOrcError -lLLVMJITLink -lLLVMObjectYAML -lLLVMMIRParser -lLLVMMCA -lLLVMLTO -lLLVMPasses -lLLVMCoroutines \
|
||||||
-lLLVMLineEditor -lLLVMLibDriver -lLLVMInterpreter -lLLVMFuzzMutate -lLLVMFrontendOpenMP -lLLVMMCJIT \
|
-lLLVMObjCARCOpts -lLLVMipo -lLLVMInstrumentation -lLLVMVectorize -lLLVMLinker -lLLVMIRReader -lLLVMAsmParser \
|
||||||
|
-lLLVMFrontendOpenMP -lLLVMExtensions -lLLVMLineEditor -lLLVMLibDriver -lLLVMInterpreter -lLLVMFuzzMutate -lLLVMMCJIT \
|
||||||
-lLLVMExecutionEngine -lLLVMRuntimeDyld -lLLVMDWARFLinker -lLLVMDlltoolDriver -lLLVMOption -lLLVMDebugInfoGSYM \
|
-lLLVMExecutionEngine -lLLVMRuntimeDyld -lLLVMDWARFLinker -lLLVMDlltoolDriver -lLLVMOption -lLLVMDebugInfoGSYM \
|
||||||
-lLLVMCoverage -lLLVMCoroutines -lLLVMipo -lLLVMInstrumentation -lLLVMVectorize -lLLVMLinker -lLLVMIRReader \
|
-lLLVMCoverage -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMX86Desc -lLLVMX86Info \
|
||||||
-lLLVMAsmParser -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMX86Desc -lLLVMX86Utils \
|
-lLLVMWebAssemblyDisassembler -lLLVMWebAssemblyCodeGen -lLLVMWebAssemblyDesc -lLLVMWebAssemblyAsmParser \
|
||||||
-lLLVMX86Info -lLLVMWebAssemblyDisassembler -lLLVMWebAssemblyCodeGen -lLLVMWebAssemblyDesc \
|
-lLLVMWebAssemblyInfo -lLLVMARMDisassembler -lLLVMARMCodeGen -lLLVMARMAsmParser -lLLVMARMDesc -lLLVMARMUtils \
|
||||||
-lLLVMWebAssemblyAsmParser -lLLVMWebAssemblyInfo -lLLVMARMDisassembler -lLLVMARMCodeGen -lLLVMARMAsmParser \
|
-lLLVMARMInfo -lLLVMAArch64Disassembler -lLLVMMCDisassembler -lLLVMAArch64CodeGen -lLLVMCFGuard -lLLVMGlobalISel \
|
||||||
-lLLVMARMDesc -lLLVMARMUtils -lLLVMARMInfo -lLLVMAArch64Disassembler -lLLVMMCDisassembler -lLLVMAArch64CodeGen \
|
-lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMDebugInfoDWARF -lLLVMCodeGen -lLLVMTarget -lLLVMScalarOpts \
|
||||||
-lLLVMCFGuard -lLLVMGlobalISel -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMDebugInfoDWARF -lLLVMCodeGen \
|
-lLLVMInstCombine -lLLVMAggressiveInstCombine -lLLVMTransformUtils -lLLVMBitWriter -lLLVMAnalysis -lLLVMProfileData \
|
||||||
-lLLVMTarget -lLLVMScalarOpts -lLLVMInstCombine -lLLVMAggressiveInstCombine -lLLVMTransformUtils -lLLVMBitWriter \
|
-lLLVMObject -lLLVMTextAPI -lLLVMBitReader -lLLVMCore -lLLVMRemarks -lLLVMBitstreamReader -lLLVMAArch64AsmParser \
|
||||||
-lLLVMAnalysis -lLLVMProfileData -lLLVMObject -lLLVMTextAPI -lLLVMBitReader -lLLVMCore -lLLVMRemarks \
|
-lLLVMMCParser -lLLVMAArch64Desc -lLLVMMC -lLLVMDebugInfoCodeView -lLLVMDebugInfoMSF -lLLVMBinaryFormat \
|
||||||
-lLLVMBitstreamReader -lLLVMAArch64AsmParser -lLLVMMCParser -lLLVMAArch64Desc -lLLVMMC -lLLVMDebugInfoCodeView \
|
-lLLVMAArch64Utils -lLLVMAArch64Info -lLLVMSupport -lLLVMDemangle"
|
||||||
-lLLVMDebugInfoMSF -lLLVMBinaryFormat -lLLVMAArch64Utils -lLLVMAArch64Info -lLLVMSupport -lLLVMDemangle"
|
|
||||||
shared_libs="-lLLVM-$version"
|
shared_libs="-lLLVM-$version"
|
||||||
libs=$shared_libs
|
libs=$shared_libs
|
||||||
handle_args () {
|
handle_args () {
|
||||||
|
|
|
@ -47,7 +47,7 @@ steps:
|
||||||
if [ "${BUILD_SOURCEBRANCH:0:10}" != "refs/tags/" ]; then
|
if [ "${BUILD_SOURCEBRANCH:0:10}" != "refs/tags/" ]; then
|
||||||
assertsSuffix="-withAsserts"
|
assertsSuffix="-withAsserts"
|
||||||
fi
|
fi
|
||||||
curl -L -o llvm.tar.xz https://github.com/ldc-developers/llvm-project/releases/download/ldc-v$LLVM_VERSION/llvm-$LLVM_VERSION-$HOST_OS-x86_64$assertsSuffix.tar.xz
|
curl -L -o llvm.tar.xz https://github.com/ldc-developers/llvm-project/releases/download/CI/llvm-$LLVM_VERSION-$HOST_OS-x86_64$assertsSuffix.tar.xz
|
||||||
mkdir llvm
|
mkdir llvm
|
||||||
tar -xf llvm.tar.xz --strip 1 -C llvm
|
tar -xf llvm.tar.xz --strip 1 -C llvm
|
||||||
# Set PARALLEL_JOBS env variable and persist it for future steps
|
# Set PARALLEL_JOBS env variable and persist it for future steps
|
||||||
|
@ -110,7 +110,7 @@ steps:
|
||||||
set -ex
|
set -ex
|
||||||
cd ..
|
cd ..
|
||||||
# Download & extract LDC-flavoured LLVM for Android target
|
# Download & extract LDC-flavoured LLVM for Android target
|
||||||
curl -L -o llvm-$ARCH.tar.xz https://github.com/ldc-developers/llvm-project/releases/download/ldc-v$LLVM_VERSION/llvm-$LLVM_VERSION-$CI_OS-$ARCH.tar.xz
|
curl -L -o llvm-$ARCH.tar.xz https://github.com/ldc-developers/llvm-project/releases/download/CI/llvm-$LLVM_VERSION-$CI_OS-$ARCH.tar.xz
|
||||||
mkdir llvm-$ARCH
|
mkdir llvm-$ARCH
|
||||||
tar -xf llvm-$ARCH.tar.xz --strip 1 -C llvm-$ARCH
|
tar -xf llvm-$ARCH.tar.xz --strip 1 -C llvm-$ARCH
|
||||||
# Download & extract Android NDK
|
# Download & extract Android NDK
|
||||||
|
@ -130,7 +130,7 @@ steps:
|
||||||
if [ "$ARCH" = "armv7a" ]; then androidEnv="androideabi"; fi
|
if [ "$ARCH" = "armv7a" ]; then androidEnv="androideabi"; fi
|
||||||
LLVM_TRIPLE=$ARCH--linux-$androidEnv
|
LLVM_TRIPLE=$ARCH--linux-$androidEnv
|
||||||
sed $BUILD_SOURCESDIRECTORY/.azure-pipelines/android-llvm-config.in \
|
sed $BUILD_SOURCESDIRECTORY/.azure-pipelines/android-llvm-config.in \
|
||||||
-e "s|@LLVM_VERSION@|$LLVM_VERSION|g" \
|
-e "s|@LLVM_VERSION@|11.0.0|g" \
|
||||||
-e "s|@LLVM_INSTALL_DIR@|$PWD/llvm-$ARCH|g" \
|
-e "s|@LLVM_INSTALL_DIR@|$PWD/llvm-$ARCH|g" \
|
||||||
-e "s|@LLVM_DEFAULT_TARGET_TRIPLE@|$LLVM_TRIPLE|g" \
|
-e "s|@LLVM_DEFAULT_TARGET_TRIPLE@|$LLVM_TRIPLE|g" \
|
||||||
-e "s|@LLVM_TARGETS@|AArch64 ARM X86 WebAssembly|g" > llvm-$ARCH/bin/llvm-config
|
-e "s|@LLVM_TARGETS@|AArch64 ARM X86 WebAssembly|g" > llvm-$ARCH/bin/llvm-config
|
||||||
|
|
|
@ -56,7 +56,7 @@ steps:
|
||||||
:: Download & extract LDC-flavoured LLVM
|
:: Download & extract LDC-flavoured LLVM
|
||||||
set ASSERTS_SUFFIX=
|
set ASSERTS_SUFFIX=
|
||||||
if not "%BUILD_SOURCEBRANCH:~0,10%" == "refs/tags/" ( set ASSERTS_SUFFIX=-withAsserts)
|
if not "%BUILD_SOURCEBRANCH:~0,10%" == "refs/tags/" ( set ASSERTS_SUFFIX=-withAsserts)
|
||||||
curl -L -o llvm.7z https://github.com/ldc-developers/llvm-project/releases/download/ldc-v%LLVM_VERSION%/llvm-%LLVM_VERSION%-windows-%ARCH%%ASSERTS_SUFFIX%.7z 2>&1
|
curl -L -o llvm.7z https://github.com/ldc-developers/llvm-project/releases/download/CI/llvm-%LLVM_VERSION%-windows-%ARCH%%ASSERTS_SUFFIX%.7z 2>&1
|
||||||
mkdir llvm
|
mkdir llvm
|
||||||
cd llvm
|
cd llvm
|
||||||
7z x ../llvm.7z > nul
|
7z x ../llvm.7z > nul
|
||||||
|
|
|
@ -9,7 +9,7 @@ matrix:
|
||||||
- os: linux
|
- os: linux
|
||||||
arch: arm64
|
arch: arm64
|
||||||
d: ldc-beta
|
d: ldc-beta
|
||||||
env: LLVM_VERSION=10.0.1 PARALLELISM=16 CC=gcc-8 CXX=g++-8 OPTS="-DLDC_INSTALL_LLVM_RUNTIME_LIBS_ARCH=aarch64 -DADDITIONAL_DEFAULT_LDC_SWITCHES='\"-linker=bfd\",' -DCOMPILE_ALL_D_FILES_AT_ONCE=OFF"
|
env: LLVM_VERSION=84863923 PARALLELISM=16 CC=gcc-8 CXX=g++-8 OPTS="-DLDC_INSTALL_LLVM_RUNTIME_LIBS_ARCH=aarch64 -DADDITIONAL_DEFAULT_LDC_SWITCHES='\"-linker=bfd\",' -DCOMPILE_ALL_D_FILES_AT_ONCE=OFF"
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
|
@ -63,7 +63,7 @@ before_install:
|
||||||
- |
|
- |
|
||||||
if [ ! -e "$LLVM_ROOT_DIR/bin/llvm-config" ]; then
|
if [ ! -e "$LLVM_ROOT_DIR/bin/llvm-config" ]; then
|
||||||
if [ "$TRAVIS_CPU_ARCH" = "arm64" ]; then
|
if [ "$TRAVIS_CPU_ARCH" = "arm64" ]; then
|
||||||
llvm_url="https://github.com/ldc-developers/llvm-project/releases/download/ldc-v$LLVM_VERSION/llvm-$LLVM_VERSION-linux-aarch64-withAsserts.tar.xz"
|
llvm_url="https://github.com/ldc-developers/llvm-project/releases/download/CI/llvm-$LLVM_VERSION-linux-aarch64-withAsserts.tar.xz"
|
||||||
else
|
else
|
||||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||||
LLVM_ARCH="x86_64-linux-gnu-ubuntu-16.04"
|
LLVM_ARCH="x86_64-linux-gnu-ubuntu-16.04"
|
||||||
|
|
|
@ -76,7 +76,7 @@ libraries is available on the project wiki for
|
||||||
[Windows](http://wiki.dlang.org/Building_and_hacking_LDC_on_Windows_using_MSVC).
|
[Windows](http://wiki.dlang.org/Building_and_hacking_LDC_on_Windows_using_MSVC).
|
||||||
|
|
||||||
If you have a working C++/D build environment, CMake, and a recent LLVM
|
If you have a working C++/D build environment, CMake, and a recent LLVM
|
||||||
version (≥ 3.9) available, there should be no big surprises. Do not
|
version (≥ 6.0) available, there should be no big surprises. Do not
|
||||||
forget to make sure all the submodules (druntime, phobos, dmd-testsuite)
|
forget to make sure all the submodules (druntime, phobos, dmd-testsuite)
|
||||||
are up to date:
|
are up to date:
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
variables:
|
variables:
|
||||||
LLVM_VERSION: 10.0.1
|
LLVM_VERSION: 84863923
|
||||||
CLANG_VERSION: 10.0.1
|
CLANG_VERSION: 10.0.1
|
||||||
HOST_LDC_VERSION: 1.22.0
|
HOST_LDC_VERSION: 1.22.0
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,8 @@
|
||||||
# We also want an user-specified LLVM_ROOT_DIR to take precedence over the
|
# 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()
|
# system default locations such as /usr/local/bin. Executing find_program()
|
||||||
# multiples times is the approach recommended in the docs.
|
# multiples times is the approach recommended in the docs.
|
||||||
set(llvm_config_names llvm-config-10.0 llvm-config100 llvm-config-10
|
set(llvm_config_names llvm-config-11.0 llvm-config110 llvm-config-11
|
||||||
|
llvm-config-10.0 llvm-config100 llvm-config-10
|
||||||
llvm-config-9.0 llvm-config90 llvm-config-9
|
llvm-config-9.0 llvm-config90 llvm-config-9
|
||||||
llvm-config-8.0 llvm-config80 llvm-config-8
|
llvm-config-8.0 llvm-config80 llvm-config-8
|
||||||
llvm-config-7.0 llvm-config70 llvm-config-7
|
llvm-config-7.0 llvm-config70 llvm-config-7
|
||||||
|
|
|
@ -216,6 +216,7 @@ longdouble_soft ldexpl(longdouble_soft ldval, int exp); // see strtold
|
||||||
inline longdouble_soft fabs (longdouble_soft ld) { return fabsl(ld); }
|
inline longdouble_soft fabs (longdouble_soft ld) { return fabsl(ld); }
|
||||||
inline longdouble_soft sqrt (longdouble_soft ld) { return sqrtl(ld); }
|
inline longdouble_soft sqrt (longdouble_soft ld) { return sqrtl(ld); }
|
||||||
|
|
||||||
|
#if !IN_LLVM
|
||||||
#undef LDBL_DIG
|
#undef LDBL_DIG
|
||||||
#undef LDBL_MAX
|
#undef LDBL_MAX
|
||||||
#undef LDBL_MIN
|
#undef LDBL_MIN
|
||||||
|
@ -235,6 +236,7 @@ inline longdouble_soft sqrt (longdouble_soft ld) { return sqrtl(ld); }
|
||||||
#define LDBL_MIN_EXP (-16381)
|
#define LDBL_MIN_EXP (-16381)
|
||||||
#define LDBL_MAX_10_EXP 4932
|
#define LDBL_MAX_10_EXP 4932
|
||||||
#define LDBL_MIN_10_EXP (-4932)
|
#define LDBL_MIN_10_EXP (-4932)
|
||||||
|
#endif // !IN_LLVM
|
||||||
|
|
||||||
extern const longdouble_soft ld_qnan;
|
extern const longdouble_soft ld_qnan;
|
||||||
extern const longdouble_soft ld_inf;
|
extern const longdouble_soft ld_inf;
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
#include "llvm/Object/MachO.h"
|
#include "llvm/Object/MachO.h"
|
||||||
#include "llvm/Object/ObjectFile.h"
|
#include "llvm/Object/ObjectFile.h"
|
||||||
#include "llvm/Support/Errc.h"
|
#include "llvm/Support/Errc.h"
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
#include "llvm/Support/Host.h"
|
||||||
|
#endif
|
||||||
#include "llvm/Support/Path.h"
|
#include "llvm/Support/Path.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
|
#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
|
||||||
|
|
|
@ -65,13 +65,22 @@ static bool createSymLink(const char *to, const char *from) {
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace sys {
|
namespace sys {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
namespace windows {
|
||||||
|
// Fwd declaration to an internal LLVM function.
|
||||||
|
std::error_code widenPath(const llvm::Twine &Path8,
|
||||||
|
llvm::SmallVectorImpl<wchar_t> &Path16,
|
||||||
|
size_t MaxPathLen = MAX_PATH);
|
||||||
|
}
|
||||||
|
#else
|
||||||
namespace path {
|
namespace path {
|
||||||
// Fwd declaration to an internal LLVM function.
|
// Fwd declaration to an internal LLVM function.
|
||||||
std::error_code widenPath(const llvm::Twine &Path8,
|
std::error_code widenPath(const llvm::Twine &Path8,
|
||||||
llvm::SmallVectorImpl<wchar_t> &Path16);
|
llvm::SmallVectorImpl<wchar_t> &Path16);
|
||||||
}
|
}
|
||||||
}
|
#endif // LDC_LLVM_VER < 1100
|
||||||
}
|
} // namespace sys
|
||||||
|
} // namespace llvm
|
||||||
// Returns true upon error.
|
// Returns true upon error.
|
||||||
namespace {
|
namespace {
|
||||||
template <typename FType>
|
template <typename FType>
|
||||||
|
@ -83,11 +92,17 @@ bool createLink(FType f, const char *to, const char *from) {
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
using llvm::sys::windows::widenPath;
|
||||||
|
#else
|
||||||
|
using llvm::sys::path::widenPath;
|
||||||
|
#endif
|
||||||
|
|
||||||
llvm::SmallVector<wchar_t, 128> wide_from;
|
llvm::SmallVector<wchar_t, 128> wide_from;
|
||||||
llvm::SmallVector<wchar_t, 128> wide_to;
|
llvm::SmallVector<wchar_t, 128> wide_to;
|
||||||
if (llvm::sys::path::widenPath(from, wide_from))
|
if (widenPath(from, wide_from))
|
||||||
return true;
|
return true;
|
||||||
if (llvm::sys::path::widenPath(to, wide_to))
|
if (widenPath(to, wide_to))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!(*f)(wide_from.begin(), wide_to.begin(), NULL))
|
if (!(*f)(wide_from.begin(), wide_to.begin(), NULL))
|
||||||
|
|
|
@ -11,7 +11,11 @@
|
||||||
|
|
||||||
// Pull in command-line options and helper functions from special LLVM header
|
// Pull in command-line options and helper functions from special LLVM header
|
||||||
// shared by multiple LLVM tools.
|
// shared by multiple LLVM tools.
|
||||||
#if LDC_LLVM_VER >= 700
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
#include "llvm/CodeGen/CommandFlags.h"
|
||||||
|
static llvm::codegen::RegisterCodeGenFlags CGF;
|
||||||
|
using namespace llvm;
|
||||||
|
#elif LDC_LLVM_VER >= 700
|
||||||
#include "llvm/CodeGen/CommandFlags.inc"
|
#include "llvm/CodeGen/CommandFlags.inc"
|
||||||
#else
|
#else
|
||||||
#include "llvm/CodeGen/CommandFlags.def"
|
#include "llvm/CodeGen/CommandFlags.def"
|
||||||
|
@ -21,7 +25,7 @@ static cl::opt<bool>
|
||||||
DisableRedZone("disable-red-zone", cl::ZeroOrMore,
|
DisableRedZone("disable-red-zone", cl::ZeroOrMore,
|
||||||
cl::desc("Do not emit code that uses the red zone."));
|
cl::desc("Do not emit code that uses the red zone."));
|
||||||
|
|
||||||
#if LDC_LLVM_VER >= 800
|
#if LDC_LLVM_VER >= 800 && LDC_LLVM_VER < 1100
|
||||||
// legacy option
|
// legacy option
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
disableFPElim("disable-fp-elim", cl::ZeroOrMore, cl::ReallyHidden,
|
disableFPElim("disable-fp-elim", cl::ZeroOrMore, cl::ReallyHidden,
|
||||||
|
@ -32,19 +36,43 @@ static cl::opt<bool>
|
||||||
// in the opts namespace, including some additional helper functions.
|
// in the opts namespace, including some additional helper functions.
|
||||||
namespace opts {
|
namespace opts {
|
||||||
|
|
||||||
std::string getArchStr() { return ::MArch; }
|
std::string getArchStr() {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
return codegen::getMArch();
|
||||||
|
#else
|
||||||
|
return ::MArch;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
Optional<Reloc::Model> getRelocModel() { return ::getRelocModel(); }
|
Optional<Reloc::Model> getRelocModel() {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
return codegen::getExplicitRelocModel();
|
||||||
|
#else
|
||||||
|
return ::getRelocModel();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
Optional<CodeModel::Model> getCodeModel() { return ::getCodeModel(); }
|
Optional<CodeModel::Model> getCodeModel() {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
return codegen::getExplicitCodeModel();
|
||||||
|
#else
|
||||||
|
return ::getCodeModel();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if LDC_LLVM_VER >= 800
|
#if LDC_LLVM_VER >= 800
|
||||||
llvm::Optional<llvm::FramePointer::FP> framePointerUsage() {
|
llvm::Optional<llvm::FramePointer::FP> framePointerUsage() {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
// Defaults to `FP::None`; no way to check if set explicitly by user except
|
||||||
|
// indirectly via setFunctionAttributes()...
|
||||||
|
return codegen::getFramePointerUsage();
|
||||||
|
#else
|
||||||
if (::FramePointerUsage.getNumOccurrences() > 0)
|
if (::FramePointerUsage.getNumOccurrences() > 0)
|
||||||
return ::FramePointerUsage.getValue();
|
return ::FramePointerUsage.getValue();
|
||||||
if (disableFPElim.getNumOccurrences() > 0)
|
if (disableFPElim.getNumOccurrences() > 0)
|
||||||
return disableFPElim ? llvm::FramePointer::All : llvm::FramePointer::None;
|
return disableFPElim ? llvm::FramePointer::All : llvm::FramePointer::None;
|
||||||
return llvm::None;
|
return llvm::None;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
cl::boolOrDefault disableFPElim() {
|
cl::boolOrDefault disableFPElim() {
|
||||||
|
@ -57,6 +85,10 @@ cl::boolOrDefault disableFPElim() {
|
||||||
bool disableRedZone() { return ::DisableRedZone; }
|
bool disableRedZone() { return ::DisableRedZone; }
|
||||||
|
|
||||||
bool printTargetFeaturesHelp() {
|
bool printTargetFeaturesHelp() {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
const auto MCPU = codegen::getMCPU();
|
||||||
|
const auto MAttrs = codegen::getMAttrs();
|
||||||
|
#endif
|
||||||
if (MCPU == "help")
|
if (MCPU == "help")
|
||||||
return true;
|
return true;
|
||||||
return std::any_of(MAttrs.begin(), MAttrs.end(),
|
return std::any_of(MAttrs.begin(), MAttrs.end(),
|
||||||
|
@ -64,11 +96,39 @@ bool printTargetFeaturesHelp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetOptions InitTargetOptionsFromCodeGenFlags() {
|
TargetOptions InitTargetOptionsFromCodeGenFlags() {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
return codegen::InitTargetOptionsFromCodeGenFlags();
|
||||||
|
#else
|
||||||
return ::InitTargetOptionsFromCodeGenFlags();
|
return ::InitTargetOptionsFromCodeGenFlags();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getCPUStr() { return ::getCPUStr(); }
|
std::string getCPUStr() {
|
||||||
std::string getFeaturesStr() { return ::getFeaturesStr(); }
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
return codegen::getCPUStr();
|
||||||
|
#else
|
||||||
|
return ::getCPUStr();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getFeaturesStr() {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
return codegen::getFeaturesStr();
|
||||||
|
#else
|
||||||
|
return ::getFeaturesStr();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LDC_LLVM_VER >= 1000
|
||||||
|
void setFunctionAttributes(StringRef cpu, StringRef features,
|
||||||
|
Function &function) {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
return codegen::setFunctionAttributes(cpu, features, function);
|
||||||
|
#else
|
||||||
|
return ::setFunctionAttributes(cpu, features, function);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} // namespace opts
|
} // namespace opts
|
||||||
|
|
||||||
#if LDC_WITH_LLD
|
#if LDC_WITH_LLD
|
||||||
|
@ -81,30 +141,32 @@ TargetOptions initTargetOptionsFromCodeGenFlags() {
|
||||||
#else
|
#else
|
||||||
TargetOptions InitTargetOptionsFromCodeGenFlags() {
|
TargetOptions InitTargetOptionsFromCodeGenFlags() {
|
||||||
#endif
|
#endif
|
||||||
return ::InitTargetOptionsFromCodeGenFlags();
|
return ::opts::InitTargetOptionsFromCodeGenFlags();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LDC_LLVM_VER >= 1000
|
#if LDC_LLVM_VER >= 1000
|
||||||
Optional<Reloc::Model> getRelocModelFromCMModel() { return ::getRelocModel(); }
|
Optional<Reloc::Model> getRelocModelFromCMModel() {
|
||||||
|
return ::opts::getRelocModel();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LDC_LLVM_VER >= 900
|
#if LDC_LLVM_VER >= 900
|
||||||
Optional<CodeModel::Model> getCodeModelFromCMModel() {
|
Optional<CodeModel::Model> getCodeModelFromCMModel() {
|
||||||
return ::getCodeModel();
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
Optional<CodeModel::Model> GetCodeModelFromCMModel() {
|
Optional<CodeModel::Model> GetCodeModelFromCMModel() {
|
||||||
return ::getCodeModel();
|
#endif
|
||||||
|
return ::opts::getCodeModel();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if LDC_LLVM_VER >= 900
|
#if LDC_LLVM_VER >= 900
|
||||||
std::string getCPUStr() { return ::getCPUStr(); }
|
std::string getCPUStr() { return ::opts::getCPUStr(); }
|
||||||
#elif LDC_LLVM_VER >= 700
|
#elif LDC_LLVM_VER >= 700
|
||||||
std::string GetCPUStr() { return ::getCPUStr(); }
|
std::string GetCPUStr() { return ::opts::getCPUStr(); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LDC_LLVM_VER >= 900
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
std::vector<std::string> getMAttrs() { return codegen::getMAttrs(); }
|
||||||
|
#elif LDC_LLVM_VER >= 900
|
||||||
std::vector<std::string> getMAttrs() { return ::MAttrs; }
|
std::vector<std::string> getMAttrs() { return ::MAttrs; }
|
||||||
#elif LDC_LLVM_VER >= 800
|
#elif LDC_LLVM_VER >= 800
|
||||||
std::vector<std::string> GetMAttrs() { return ::MAttrs; }
|
std::vector<std::string> GetMAttrs() { return ::MAttrs; }
|
||||||
|
|
|
@ -14,6 +14,10 @@
|
||||||
#include "llvm/Support/CodeGen.h"
|
#include "llvm/Support/CodeGen.h"
|
||||||
#include "llvm/Target/TargetOptions.h"
|
#include "llvm/Target/TargetOptions.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
class Function;
|
||||||
|
}
|
||||||
|
|
||||||
namespace opts {
|
namespace opts {
|
||||||
|
|
||||||
std::string getArchStr();
|
std::string getArchStr();
|
||||||
|
@ -31,4 +35,8 @@ bool printTargetFeaturesHelp();
|
||||||
llvm::TargetOptions InitTargetOptionsFromCodeGenFlags();
|
llvm::TargetOptions InitTargetOptionsFromCodeGenFlags();
|
||||||
std::string getCPUStr();
|
std::string getCPUStr();
|
||||||
std::string getFeaturesStr();
|
std::string getFeaturesStr();
|
||||||
|
#if LDC_LLVM_VER >= 1000
|
||||||
|
void setFunctionAttributes(llvm::StringRef cpu, llvm::StringRef features,
|
||||||
|
llvm::Function &function);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -681,17 +681,24 @@ void hideLLVMOptions() {
|
||||||
static const char *const hiddenOptions[] = {
|
static const char *const hiddenOptions[] = {
|
||||||
"aarch64-neon-syntax", "addrsig", "arm-add-build-attributes",
|
"aarch64-neon-syntax", "addrsig", "arm-add-build-attributes",
|
||||||
"arm-implicit-it", "asm-instrumentation", "asm-show-inst",
|
"arm-implicit-it", "asm-instrumentation", "asm-show-inst",
|
||||||
"atomic-counter-update-promoted", "bounds-checking-single-trap",
|
"atomic-counter-update-promoted", "atomic-first-counter",
|
||||||
|
"basicblock-sections", "bounds-checking-single-trap",
|
||||||
|
"cfg-hide-deoptimize-paths", "cfg-hide-unreachable-paths",
|
||||||
"code-model", "cost-kind", "cppfname", "cppfor", "cppgen",
|
"code-model", "cost-kind", "cppfname", "cppfor", "cppgen",
|
||||||
"cvp-dont-add-nowrap-flags",
|
"cvp-dont-add-nowrap-flags",
|
||||||
"cvp-dont-process-adds", "debug-counter", "debug-entry-values",
|
"cvp-dont-process-adds", "debug-counter", "debug-entry-values",
|
||||||
"debugger-tune", "denormal-fp-math", "disable-debug-info-verifier",
|
"debugger-tune", "debugify-level", "debugify-quiet",
|
||||||
|
"denormal-fp-math", "denormal-fp-math-f32", "disable-debug-info-verifier",
|
||||||
"disable-objc-arc-checkforcfghazards", "disable-spill-fusing",
|
"disable-objc-arc-checkforcfghazards", "disable-spill-fusing",
|
||||||
"do-counter-promotion", "emscripten-cxx-exceptions-whitelist",
|
"do-counter-promotion", "dwarf64", "emit-call-site-info",
|
||||||
|
"emscripten-cxx-exceptions-allowed",
|
||||||
|
"emscripten-cxx-exceptions-whitelist",
|
||||||
"emulated-tls", "enable-correct-eh-support",
|
"emulated-tls", "enable-correct-eh-support",
|
||||||
"enable-cse-in-irtranslator", "enable-cse-in-legalizer",
|
"enable-cse-in-irtranslator", "enable-cse-in-legalizer",
|
||||||
"enable-emscripten-cxx-exceptions", "enable-emscripten-sjlj",
|
"enable-emscripten-cxx-exceptions", "enable-emscripten-sjlj",
|
||||||
"enable-fp-mad", "enable-gvn-memdep", "enable-implicit-null-checks",
|
"enable-fp-mad", "enable-gvn-hoist", "enable-gvn-memdep",
|
||||||
|
"enable-gvn-sink", "enable-implicit-null-checks",
|
||||||
|
"enable-load-in-loop-pre",
|
||||||
"enable-load-pre", "enable-loop-simplifycfg-term-folding",
|
"enable-load-pre", "enable-loop-simplifycfg-term-folding",
|
||||||
"enable-misched", "enable-name-compression", "enable-no-infs-fp-math",
|
"enable-misched", "enable-name-compression", "enable-no-infs-fp-math",
|
||||||
"enable-no-nans-fp-math", "enable-no-signed-zeros-fp-math",
|
"enable-no-nans-fp-math", "enable-no-signed-zeros-fp-math",
|
||||||
|
@ -701,23 +708,27 @@ void hideLLVMOptions() {
|
||||||
"exhaustive-register-search", "expensive-combines",
|
"exhaustive-register-search", "expensive-combines",
|
||||||
"fatal-assembler-warnings", "filter-print-funcs",
|
"fatal-assembler-warnings", "filter-print-funcs",
|
||||||
"force-dwarf-frame-section", "gpsize", "hash-based-counter-split",
|
"force-dwarf-frame-section", "gpsize", "hash-based-counter-split",
|
||||||
|
"hot-cold-split",
|
||||||
"imp-null-check-page-size", "imp-null-max-insts-to-consider",
|
"imp-null-check-page-size", "imp-null-max-insts-to-consider",
|
||||||
"import-all-index", "incremental-linker-compatible",
|
"import-all-index", "incremental-linker-compatible",
|
||||||
"instcombine-code-sinking", "instcombine-guard-widening-window",
|
"instcombine-code-sinking", "instcombine-guard-widening-window",
|
||||||
"instcombine-max-iterations", "instcombine-max-num-phis",
|
"instcombine-max-iterations", "instcombine-max-num-phis",
|
||||||
"instcombine-maxarray-size", "instrprof-atomic-counter-update-all",
|
"instcombine-maxarray-size", "instcombine-negator-enabled",
|
||||||
"internalize-public-api-file",
|
"instcombine-negator-max-depth",
|
||||||
|
"instrprof-atomic-counter-update-all", "internalize-public-api-file",
|
||||||
"internalize-public-api-list", "iterative-counter-promotion",
|
"internalize-public-api-list", "iterative-counter-promotion",
|
||||||
"join-liveintervals", "jump-table-type", "limit-float-precision",
|
"join-liveintervals", "jump-table-type", "limit-float-precision",
|
||||||
"lto-embed-bitcode", "matrix-propagate-shape",
|
"lto-embed-bitcode", "matrix-default-layout", "matrix-propagate-shape",
|
||||||
"max-counter-promotions", "max-counter-promotions-per-loop",
|
"max-counter-promotions", "max-counter-promotions-per-loop",
|
||||||
"mc-relax-all", "mc-x86-disable-arith-relaxation", "meabi",
|
"mc-relax-all", "mc-x86-disable-arith-relaxation", "meabi",
|
||||||
"memop-size-large", "memop-size-range", "merror-missing-parenthesis",
|
"memop-size-large", "memop-size-range", "merror-missing-parenthesis",
|
||||||
"merror-noncontigious-register", "mfuture-regs", "mips-compact-branches",
|
"merror-noncontigious-register", "mfuture-regs", "mips-compact-branches",
|
||||||
"mips16-constant-islands", "mips16-hard-float", "mlsm", "mno-compound",
|
"mips16-constant-islands", "mips16-hard-float", "mir-strip-debugify-only",
|
||||||
|
"mlsm", "mno-compound",
|
||||||
"mno-fixup", "mno-ldc1-sdc1", "mno-pairing", "mwarn-missing-parenthesis",
|
"mno-fixup", "mno-ldc1-sdc1", "mno-pairing", "mwarn-missing-parenthesis",
|
||||||
"mwarn-noncontigious-register", "mwarn-sign-mismatch",
|
"mwarn-noncontigious-register", "mwarn-sign-mismatch",
|
||||||
"no-discriminators", "nozero-initialized-in-bss", "nvptx-sched4reg",
|
"no-discriminators", "no-xray-index",
|
||||||
|
"nozero-initialized-in-bss", "nvptx-sched4reg",
|
||||||
"objc-arc-annotation-target-identifier", "pie-copy-relocations",
|
"objc-arc-annotation-target-identifier", "pie-copy-relocations",
|
||||||
"poison-checking-function-local",
|
"poison-checking-function-local",
|
||||||
"polly-dump-after", "polly-dump-after-file", "polly-dump-before",
|
"polly-dump-after", "polly-dump-after-file", "polly-dump-before",
|
||||||
|
@ -727,7 +738,7 @@ void hideLLVMOptions() {
|
||||||
"profile-file", "profile-info-file", "profile-verifier-noassert",
|
"profile-file", "profile-info-file", "profile-verifier-noassert",
|
||||||
"r600-ir-structurize", "rdf-dump", "rdf-limit", "recip", "regalloc",
|
"r600-ir-structurize", "rdf-dump", "rdf-limit", "recip", "regalloc",
|
||||||
"relax-elf-relocations", "remarks-section", "rewrite-map-file", "rng-seed",
|
"relax-elf-relocations", "remarks-section", "rewrite-map-file", "rng-seed",
|
||||||
"safepoint-ir-verifier-print-only",
|
"runtime-counter-relocation", "safepoint-ir-verifier-print-only",
|
||||||
"sample-profile-check-record-coverage",
|
"sample-profile-check-record-coverage",
|
||||||
"sample-profile-check-sample-coverage",
|
"sample-profile-check-sample-coverage",
|
||||||
"sample-profile-inline-hot-threshold",
|
"sample-profile-inline-hot-threshold",
|
||||||
|
@ -735,14 +746,15 @@ void hideLLVMOptions() {
|
||||||
"speculative-counter-promotion-max-exiting",
|
"speculative-counter-promotion-max-exiting",
|
||||||
"speculative-counter-promotion-to-loop", "spiller", "spirv-debug",
|
"speculative-counter-promotion-to-loop", "spiller", "spirv-debug",
|
||||||
"spirv-erase-cl-md", "spirv-lower-const-expr", "spirv-mem2reg",
|
"spirv-erase-cl-md", "spirv-lower-const-expr", "spirv-mem2reg",
|
||||||
"spirv-no-deref-attr", "spirv-text", "spvbool-validate",
|
"spirv-no-deref-attr", "spirv-text",
|
||||||
|
"spv-lower-saddwithoverflow-validate", "spvbool-validate",
|
||||||
"spvmemmove-validate",
|
"spvmemmove-validate",
|
||||||
"stack-alignment", "stack-size-section", "stack-symbol-ordering",
|
"stack-alignment", "stack-size-section", "stack-symbol-ordering",
|
||||||
"stackmap-version", "static-func-full-module-prefix",
|
"stackmap-version", "static-func-full-module-prefix",
|
||||||
"static-func-strip-dirname-prefix", "stats", "stats-json", "strip-debug",
|
"static-func-strip-dirname-prefix", "stats", "stats-json", "strip-debug",
|
||||||
"struct-path-tbaa", "summary-file", "tailcallopt", "thread-model",
|
"struct-path-tbaa", "summary-file", "tail-predication", "tailcallopt",
|
||||||
"time-passes", "time-trace-granularity", "tls-size",
|
"thread-model", "time-passes", "time-trace-granularity", "tls-size",
|
||||||
"unfold-element-atomic-memcpy-max-elements",
|
"unfold-element-atomic-memcpy-max-elements", "unique-bb-section-names",
|
||||||
"unique-section-names", "unit-at-a-time", "use-ctors",
|
"unique-section-names", "unit-at-a-time", "use-ctors",
|
||||||
"verify-debug-info", "verify-dom-info", "verify-loop-info",
|
"verify-debug-info", "verify-dom-info", "verify-loop-info",
|
||||||
"verify-loop-lcssa", "verify-machine-dom-info", "verify-regalloc",
|
"verify-loop-lcssa", "verify-machine-dom-info", "verify-regalloc",
|
||||||
|
@ -750,6 +762,7 @@ void hideLLVMOptions() {
|
||||||
"vp-counters-per-site", "vp-static-alloc",
|
"vp-counters-per-site", "vp-static-alloc",
|
||||||
"x86-align-branch", "x86-align-branch-boundary",
|
"x86-align-branch", "x86-align-branch-boundary",
|
||||||
"x86-branches-within-32B-boundaries", "x86-early-ifcvt",
|
"x86-branches-within-32B-boundaries", "x86-early-ifcvt",
|
||||||
|
"x86-pad-max-prefix-size",
|
||||||
"x86-recip-refinement-steps", "x86-use-vzeroupper",
|
"x86-recip-refinement-steps", "x86-use-vzeroupper",
|
||||||
|
|
||||||
// We enable -fdata-sections/-ffunction-sections by default where it makes
|
// We enable -fdata-sections/-ffunction-sections by default where it makes
|
||||||
|
@ -758,8 +771,7 @@ void hideLLVMOptions() {
|
||||||
// We need our own switch as these two are defined by LLVM and linked to
|
// We need our own switch as these two are defined by LLVM and linked to
|
||||||
// static TargetMachine members, but the default we want to use depends
|
// static TargetMachine members, but the default we want to use depends
|
||||||
// on the target triple (and thus we do not know it until after the
|
// on the target triple (and thus we do not know it until after the
|
||||||
// command
|
// command line has been parsed).
|
||||||
// line has been parsed).
|
|
||||||
"fdata-sections", "ffunction-sections", "data-sections",
|
"fdata-sections", "ffunction-sections", "data-sections",
|
||||||
"function-sections"};
|
"function-sections"};
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,9 @@
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/modules.h"
|
#include "gen/modules.h"
|
||||||
#include "gen/runtime.h"
|
#include "gen/runtime.h"
|
||||||
#if LDC_LLVM_VER >= 900
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
#include "llvm/IR/LLVMRemarkStreamer.h"
|
||||||
|
#elif LDC_LLVM_VER >= 900
|
||||||
#include "llvm/IR/RemarkStreamer.h"
|
#include "llvm/IR/RemarkStreamer.h"
|
||||||
#endif
|
#endif
|
||||||
#include "llvm/Support/FileSystem.h"
|
#include "llvm/Support/FileSystem.h"
|
||||||
|
@ -52,8 +54,13 @@ createAndSetDiagnosticsOutputFile(IRState &irs, llvm::LLVMContext &ctx,
|
||||||
const bool withHotness = opts::isUsingPGOProfile();
|
const bool withHotness = opts::isUsingPGOProfile();
|
||||||
|
|
||||||
#if LDC_LLVM_VER >= 900
|
#if LDC_LLVM_VER >= 900
|
||||||
auto remarksFileOrError = llvm::setupOptimizationRemarks(
|
auto remarksFileOrError =
|
||||||
ctx, diagnosticsFilename, "", "", withHotness);
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
llvm::setupLLVMOptimizationRemarks(
|
||||||
|
#else
|
||||||
|
llvm::setupOptimizationRemarks(
|
||||||
|
#endif
|
||||||
|
ctx, diagnosticsFilename, "", "", withHotness);
|
||||||
if (llvm::Error e = remarksFileOrError.takeError()) {
|
if (llvm::Error e = remarksFileOrError.takeError()) {
|
||||||
irs.dmodule->error("Could not create file %s: %s",
|
irs.dmodule->error("Could not create file %s: %s",
|
||||||
diagnosticsFilename.c_str(),
|
diagnosticsFilename.c_str(),
|
||||||
|
|
|
@ -479,7 +479,11 @@ void translateArgs(const llvm::SmallVectorImpl<const char *> &ldmdArgs,
|
||||||
else if (strcmp(p + 1, "gf") == 0) {
|
else if (strcmp(p + 1, "gf") == 0) {
|
||||||
ldcArgs.push_back("-g");
|
ldcArgs.push_back("-g");
|
||||||
} else if (strcmp(p + 1, "gs") == 0) {
|
} else if (strcmp(p + 1, "gs") == 0) {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
ldcArgs.push_back("-frame-pointer=all");
|
||||||
|
#else
|
||||||
ldcArgs.push_back("-disable-fp-elim");
|
ldcArgs.push_back("-disable-fp-elim");
|
||||||
|
#endif
|
||||||
} else if (strcmp(p + 1, "gx") == 0) {
|
} else if (strcmp(p + 1, "gx") == 0) {
|
||||||
goto Lnot_in_ldc;
|
goto Lnot_in_ldc;
|
||||||
} else if (strcmp(p + 1, "gt") == 0) {
|
} else if (strcmp(p + 1, "gt") == 0) {
|
||||||
|
|
|
@ -321,7 +321,7 @@ void ArgsBuilder::addSanitizerLinkFlags(const llvm::Triple &triple,
|
||||||
|
|
||||||
// When we reach here, we did not find the sanitizer library.
|
// When we reach here, we did not find the sanitizer library.
|
||||||
// Fallback, requires Clang.
|
// Fallback, requires Clang.
|
||||||
args.push_back(fallbackFlag);
|
args.emplace_back(fallbackFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds all required link flags for -fsanitize=fuzzer when libFuzzer library is
|
// Adds all required link flags for -fsanitize=fuzzer when libFuzzer library is
|
||||||
|
|
|
@ -67,6 +67,10 @@ void addSanitizerLibs(std::vector<std::string> &args) {
|
||||||
if (opts::isSanitizerEnabled(opts::AddressSanitizer)) {
|
if (opts::isSanitizerEnabled(opts::AddressSanitizer)) {
|
||||||
args.push_back("ldc_rt.asan.lib");
|
args.push_back("ldc_rt.asan.lib");
|
||||||
}
|
}
|
||||||
|
if (opts::isSanitizerEnabled(opts::FuzzSanitizer)) {
|
||||||
|
args.push_back("ldc_rt.fuzzer.lib");
|
||||||
|
args.push_back("/SUBSYSTEM:CONSOLE"); // pull main() from fuzzer lib
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: remaining sanitizers
|
// TODO: remaining sanitizers
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,7 @@ static std::vector<std::string>
|
||||||
parseLibNames(llvm::StringRef commaSeparatedList, llvm::StringRef suffix = {}) {
|
parseLibNames(llvm::StringRef commaSeparatedList, llvm::StringRef suffix = {}) {
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
|
|
||||||
std::stringstream list(commaSeparatedList);
|
std::stringstream list(commaSeparatedList.str());
|
||||||
while (list.good()) {
|
while (list.good()) {
|
||||||
std::string lib;
|
std::string lib;
|
||||||
std::getline(list, lib, ',');
|
std::getline(list, lib, ',');
|
||||||
|
|
20
gen/aa.cpp
20
gen/aa.cpp
|
@ -65,12 +65,10 @@ DLValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key,
|
||||||
LLValue *castedAATI = DtoBitCast(rawAATI, funcTy->getParamType(1));
|
LLValue *castedAATI = DtoBitCast(rawAATI, funcTy->getParamType(1));
|
||||||
LLValue *valsize = DtoConstSize_t(getTypeAllocSize(DtoType(type)));
|
LLValue *valsize = DtoConstSize_t(getTypeAllocSize(DtoType(type)));
|
||||||
ret = gIR->CreateCallOrInvoke(func, aaval, castedAATI, valsize, pkey,
|
ret = gIR->CreateCallOrInvoke(func, aaval, castedAATI, valsize, pkey,
|
||||||
"aa.index")
|
"aa.index");
|
||||||
.getInstruction();
|
|
||||||
} else {
|
} else {
|
||||||
LLValue *keyti = to_keyti(aa, funcTy->getParamType(1));
|
LLValue *keyti = to_keyti(aa, funcTy->getParamType(1));
|
||||||
ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.index")
|
ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.index");
|
||||||
.getInstruction();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cast return value
|
// cast return value
|
||||||
|
@ -91,12 +89,12 @@ DLValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key,
|
||||||
|
|
||||||
// set up failbb to call the array bounds error runtime function
|
// set up failbb to call the array bounds error runtime function
|
||||||
|
|
||||||
gIR->scope() = IRScope(failbb);
|
gIR->ir->SetInsertPoint(failbb);
|
||||||
|
|
||||||
DtoBoundsCheckFailCall(gIR, loc);
|
DtoBoundsCheckFailCall(gIR, loc);
|
||||||
|
|
||||||
// if ok, proceed in okbb
|
// if ok, proceed in okbb
|
||||||
gIR->scope() = IRScope(okbb);
|
gIR->ir->SetInsertPoint(okbb);
|
||||||
}
|
}
|
||||||
return new DLValue(type, ret);
|
return new DLValue(type, ret);
|
||||||
}
|
}
|
||||||
|
@ -134,8 +132,7 @@ DValue *DtoAAIn(Loc &loc, Type *type, DValue *aa, DValue *key) {
|
||||||
pkey = DtoBitCast(pkey, getVoidPtrType());
|
pkey = DtoBitCast(pkey, getVoidPtrType());
|
||||||
|
|
||||||
// call runtime
|
// call runtime
|
||||||
LLValue *ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.in")
|
LLValue *ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.in");
|
||||||
.getInstruction();
|
|
||||||
|
|
||||||
// cast return value
|
// cast return value
|
||||||
LLType *targettype = DtoType(type);
|
LLType *targettype = DtoType(type);
|
||||||
|
@ -179,9 +176,9 @@ DValue *DtoAARemove(Loc &loc, DValue *aa, DValue *key) {
|
||||||
pkey = DtoBitCast(pkey, funcTy->getParamType(2));
|
pkey = DtoBitCast(pkey, funcTy->getParamType(2));
|
||||||
|
|
||||||
// call runtime
|
// call runtime
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey);
|
LLValue *res = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey);
|
||||||
|
|
||||||
return new DImValue(Type::tbool, call.getInstruction());
|
return new DImValue(Type::tbool, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -197,8 +194,7 @@ LLValue *DtoAAEquals(Loc &loc, TOK op, DValue *l, DValue *r) {
|
||||||
LLValue *abval = DtoBitCast(DtoRVal(r), funcTy->getParamType(2));
|
LLValue *abval = DtoBitCast(DtoRVal(r), funcTy->getParamType(2));
|
||||||
LLValue *aaTypeInfo = DtoTypeInfoOf(t);
|
LLValue *aaTypeInfo = DtoTypeInfoOf(t);
|
||||||
LLValue *res =
|
LLValue *res =
|
||||||
gIR->CreateCallOrInvoke(func, aaTypeInfo, aaval, abval, "aaEqRes")
|
gIR->CreateCallOrInvoke(func, aaTypeInfo, aaval, abval, "aaEqRes");
|
||||||
.getInstruction();
|
|
||||||
|
|
||||||
const auto predicate = eqTokToICmpPred(op, /* invert = */ true);
|
const auto predicate = eqTokToICmpPred(op, /* invert = */ true);
|
||||||
res = gIR->ir->CreateICmp(predicate, res, DtoConstInt(0));
|
res = gIR->ir->CreateICmp(predicate, res, DtoConstInt(0));
|
||||||
|
|
|
@ -36,7 +36,12 @@ struct LLTypeMemoryLayout {
|
||||||
const size_t sizeInBits = getTypeBitSize(type);
|
const size_t sizeInBits = getTypeBitSize(type);
|
||||||
assert(sizeInBits % 8 == 0);
|
assert(sizeInBits % 8 == 0);
|
||||||
return llvm::VectorType::get(LLIntegerType::get(gIR->context(), 8),
|
return llvm::VectorType::get(LLIntegerType::get(gIR->context(), 8),
|
||||||
sizeInBits / 8);
|
sizeInBits / 8
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
,
|
||||||
|
/*Scalable=*/false
|
||||||
|
#endif
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LLStructType *structType = isaStruct(type)) {
|
if (LLStructType *structType = isaStruct(type)) {
|
||||||
|
|
|
@ -144,7 +144,7 @@ static void DtoArrayInit(Loc &loc, LLValue *ptr, LLValue *length,
|
||||||
llvm::BranchInst::Create(condbb, gIR->scopebb());
|
llvm::BranchInst::Create(condbb, gIR->scopebb());
|
||||||
|
|
||||||
// replace current scope
|
// replace current scope
|
||||||
gIR->scope() = IRScope(condbb);
|
gIR->ir->SetInsertPoint(condbb);
|
||||||
|
|
||||||
// create the condition
|
// create the condition
|
||||||
LLValue *cond_val =
|
LLValue *cond_val =
|
||||||
|
@ -155,7 +155,7 @@ static void DtoArrayInit(Loc &loc, LLValue *ptr, LLValue *length,
|
||||||
llvm::BranchInst::Create(bodybb, endbb, cond_val, gIR->scopebb());
|
llvm::BranchInst::Create(bodybb, endbb, cond_val, gIR->scopebb());
|
||||||
|
|
||||||
// rewrite scope
|
// rewrite scope
|
||||||
gIR->scope() = IRScope(bodybb);
|
gIR->ir->SetInsertPoint(bodybb);
|
||||||
|
|
||||||
LLValue *itr_val = DtoLoad(itr);
|
LLValue *itr_val = DtoLoad(itr);
|
||||||
// assign array element value
|
// assign array element value
|
||||||
|
@ -171,7 +171,7 @@ static void DtoArrayInit(Loc &loc, LLValue *ptr, LLValue *length,
|
||||||
llvm::BranchInst::Create(condbb, gIR->scopebb());
|
llvm::BranchInst::Create(condbb, gIR->scopebb());
|
||||||
|
|
||||||
// rewrite the scope
|
// rewrite the scope
|
||||||
gIR->scope() = IRScope(endbb);
|
gIR->ir->SetInsertPoint(endbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -198,7 +198,7 @@ static void copySlice(Loc &loc, LLValue *dstarr, LLValue *dstlen, LLValue *srcar
|
||||||
const bool checksEnabled =
|
const bool checksEnabled =
|
||||||
global.params.useAssert == CHECKENABLEon || gIR->emitArrayBoundsChecks();
|
global.params.useAssert == CHECKENABLEon || gIR->emitArrayBoundsChecks();
|
||||||
if (checksEnabled && !knownInBounds) {
|
if (checksEnabled && !knownInBounds) {
|
||||||
LLValue *fn = getRuntimeFunction(loc, gIR->module, "_d_array_slice_copy");
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_array_slice_copy");
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, {dstarr, dstlen, srcarr, srclen, DtoConstSize_t(elementSize)}, "",
|
fn, {dstarr, dstlen, srcarr, srclen, DtoConstSize_t(elementSize)}, "",
|
||||||
/*isNothrow=*/true);
|
/*isNothrow=*/true);
|
||||||
|
@ -293,20 +293,18 @@ void DtoArrayAssign(Loc &loc, DValue *lhs, DValue *rhs, int op,
|
||||||
}
|
}
|
||||||
} else if (isConstructing) {
|
} else if (isConstructing) {
|
||||||
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_arrayctor");
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_arrayctor");
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(fn, DtoTypeInfoOf(elemType),
|
gIR->CreateCallOrInvoke(fn, DtoTypeInfoOf(elemType),
|
||||||
DtoSlice(rhsPtr, rhsLength),
|
DtoSlice(rhsPtr, rhsLength),
|
||||||
DtoSlice(lhsPtr, lhsLength));
|
DtoSlice(lhsPtr, lhsLength));
|
||||||
call.setCallingConv(llvm::CallingConv::C);
|
|
||||||
} else // assigning
|
} else // assigning
|
||||||
{
|
{
|
||||||
LLValue *tmpSwap = DtoAlloca(elemType, "arrayAssign.tmpSwap");
|
LLValue *tmpSwap = DtoAlloca(elemType, "arrayAssign.tmpSwap");
|
||||||
LLFunction *fn = getRuntimeFunction(
|
LLFunction *fn = getRuntimeFunction(
|
||||||
loc, gIR->module,
|
loc, gIR->module,
|
||||||
!canSkipPostblit ? "_d_arrayassign_l" : "_d_arrayassign_r");
|
!canSkipPostblit ? "_d_arrayassign_l" : "_d_arrayassign_r");
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoTypeInfoOf(elemType), DtoSlice(rhsPtr, rhsLength),
|
fn, DtoTypeInfoOf(elemType), DtoSlice(rhsPtr, rhsLength),
|
||||||
DtoSlice(lhsPtr, lhsLength), DtoBitCast(tmpSwap, getVoidPtrType()));
|
DtoSlice(lhsPtr, lhsLength), DtoBitCast(tmpSwap, getVoidPtrType()));
|
||||||
call.setCallingConv(llvm::CallingConv::C);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// scalar rhs:
|
// scalar rhs:
|
||||||
|
@ -335,12 +333,11 @@ void DtoArrayAssign(Loc &loc, DValue *lhs, DValue *rhs, int op,
|
||||||
LLFunction *fn = getRuntimeFunction(loc, gIR->module,
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module,
|
||||||
isConstructing ? "_d_arraysetctor"
|
isConstructing ? "_d_arraysetctor"
|
||||||
: "_d_arraysetassign");
|
: "_d_arraysetassign");
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, lhsPtr, DtoBitCast(makeLValue(loc, rhs), getVoidPtrType()),
|
fn, lhsPtr, DtoBitCast(makeLValue(loc, rhs), getVoidPtrType()),
|
||||||
gIR->ir->CreateTruncOrBitCast(lhsLength,
|
gIR->ir->CreateTruncOrBitCast(lhsLength,
|
||||||
LLType::getInt32Ty(gIR->context())),
|
LLType::getInt32Ty(gIR->context())),
|
||||||
DtoTypeInfoOf(stripModifiers(t2)));
|
DtoTypeInfoOf(stripModifiers(t2)));
|
||||||
call.setCallingConv(llvm::CallingConv::C);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -704,8 +701,7 @@ DSliceValue *DtoNewDynArray(Loc &loc, Type *arrayType, DValue *dim,
|
||||||
|
|
||||||
// call allocator
|
// call allocator
|
||||||
LLValue *newArray =
|
LLValue *newArray =
|
||||||
gIR->CreateCallOrInvoke(fn, arrayTypeInfo, arrayLen, ".gc_mem")
|
gIR->CreateCallOrInvoke(fn, arrayTypeInfo, arrayLen, ".gc_mem");
|
||||||
.getInstruction();
|
|
||||||
|
|
||||||
// return a DSliceValue with the well-known length for better optimizability
|
// return a DSliceValue with the well-known length for better optimizability
|
||||||
auto ptr =
|
auto ptr =
|
||||||
|
@ -774,8 +770,7 @@ DSliceValue *DtoNewMulDimDynArray(Loc &loc, Type *arrayType, DValue **dims,
|
||||||
|
|
||||||
// call allocator
|
// call allocator
|
||||||
LLValue *newptr =
|
LLValue *newptr =
|
||||||
gIR->CreateCallOrInvoke(fn, arrayTypeInfo, DtoLoad(darray), ".gc_mem")
|
gIR->CreateCallOrInvoke(fn, arrayTypeInfo, DtoLoad(darray), ".gc_mem");
|
||||||
.getInstruction();
|
|
||||||
|
|
||||||
IF_LOG Logger::cout() << "final ptr = " << *newptr << '\n';
|
IF_LOG Logger::cout() << "final ptr = " << *newptr << '\n';
|
||||||
|
|
||||||
|
@ -802,12 +797,10 @@ DSliceValue *DtoResizeDynArray(Loc &loc, Type *arrayType, DValue *array,
|
||||||
getRuntimeFunction(loc, gIR->module, zeroInit ? "_d_arraysetlengthT"
|
getRuntimeFunction(loc, gIR->module, zeroInit ? "_d_arraysetlengthT"
|
||||||
: "_d_arraysetlengthiT");
|
: "_d_arraysetlengthiT");
|
||||||
|
|
||||||
LLValue *newArray =
|
LLValue *newArray = gIR->CreateCallOrInvoke(
|
||||||
gIR->CreateCallOrInvoke(
|
fn, DtoTypeInfoOf(arrayType), newdim,
|
||||||
fn, DtoTypeInfoOf(arrayType), newdim,
|
DtoBitCast(DtoLVal(array), fn->getFunctionType()->getParamType(2)),
|
||||||
DtoBitCast(DtoLVal(array), fn->getFunctionType()->getParamType(2)),
|
".gc_mem");
|
||||||
".gc_mem")
|
|
||||||
.getInstruction();
|
|
||||||
|
|
||||||
return getSlice(arrayType, newArray);
|
return getSlice(arrayType, newArray);
|
||||||
}
|
}
|
||||||
|
@ -853,14 +846,11 @@ DSliceValue *DtoCatAssignArray(Loc &loc, DValue *arr, Expression *exp) {
|
||||||
|
|
||||||
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_arrayappendT");
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module, "_d_arrayappendT");
|
||||||
// Call _d_arrayappendT(TypeInfo ti, byte[] *px, byte[] y)
|
// Call _d_arrayappendT(TypeInfo ti, byte[] *px, byte[] y)
|
||||||
LLValue *newArray =
|
LLValue *newArray = gIR->CreateCallOrInvoke(
|
||||||
gIR->CreateCallOrInvoke(
|
fn, DtoTypeInfoOf(arrayType),
|
||||||
fn, DtoTypeInfoOf(arrayType),
|
DtoBitCast(DtoLVal(arr), fn->getFunctionType()->getParamType(1)),
|
||||||
DtoBitCast(DtoLVal(arr), fn->getFunctionType()->getParamType(1)),
|
DtoAggrPaint(DtoSlice(exp), fn->getFunctionType()->getParamType(2)),
|
||||||
DtoAggrPaint(DtoSlice(exp),
|
".appendedArray");
|
||||||
fn->getFunctionType()->getParamType(2)),
|
|
||||||
".appendedArray")
|
|
||||||
.getInstruction();
|
|
||||||
|
|
||||||
return getSlice(arrayType, newArray);
|
return getSlice(arrayType, newArray);
|
||||||
}
|
}
|
||||||
|
@ -929,8 +919,7 @@ DSliceValue *DtoCatArrays(Loc &loc, Type *arrayType, Expression *exp1,
|
||||||
args.push_back(val);
|
args.push_back(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto newArray =
|
auto newArray = gIR->CreateCallOrInvoke(fn, args, ".appendedArray");
|
||||||
gIR->CreateCallOrInvoke(fn, args, ".appendedArray").getInstruction();
|
|
||||||
return getSlice(arrayType, newArray);
|
return getSlice(arrayType, newArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -944,13 +933,10 @@ DSliceValue *DtoAppendDChar(Loc &loc, DValue *arr, Expression *exp,
|
||||||
LLFunction *fn = getRuntimeFunction(loc, gIR->module, func);
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module, func);
|
||||||
|
|
||||||
// Call function (ref string x, dchar c)
|
// Call function (ref string x, dchar c)
|
||||||
LLValue *newArray =
|
LLValue *newArray = gIR->CreateCallOrInvoke(
|
||||||
gIR->CreateCallOrInvoke(
|
fn, DtoBitCast(DtoLVal(arr), fn->getFunctionType()->getParamType(0)),
|
||||||
fn,
|
DtoBitCast(valueToAppend, fn->getFunctionType()->getParamType(1)),
|
||||||
DtoBitCast(DtoLVal(arr), fn->getFunctionType()->getParamType(0)),
|
".appendedArray");
|
||||||
DtoBitCast(valueToAppend, fn->getFunctionType()->getParamType(1)),
|
|
||||||
".appendedArray")
|
|
||||||
.getInstruction();
|
|
||||||
|
|
||||||
return getSlice(arr->type, newArray);
|
return getSlice(arr->type, newArray);
|
||||||
}
|
}
|
||||||
|
@ -1003,7 +989,7 @@ LLValue *DtoArrayEqCmp_impl(Loc &loc, const char *func, DValue *l,
|
||||||
args.push_back(DtoBitCast(tival, fn->getFunctionType()->getParamType(2)));
|
args.push_back(DtoBitCast(tival, fn->getFunctionType()->getParamType(2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return gIR->CreateCallOrInvoke(fn, args).getInstruction();
|
return gIR->CreateCallOrInvoke(fn, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When `true` is returned, the type can be compared using `memcmp`.
|
/// When `true` is returned, the type can be compared using `memcmp`.
|
||||||
|
@ -1118,12 +1104,12 @@ LLValue *DtoArrayEqCmp_memcmp(Loc &loc, DValue *l, DValue *r, IRState &irs) {
|
||||||
// Note: no extra null checks are needed before passing the pointers to memcmp.
|
// Note: no extra null checks are needed before passing the pointers to memcmp.
|
||||||
// The array comparison is UB for non-zero length, and memcmp will correctly
|
// The array comparison is UB for non-zero length, and memcmp will correctly
|
||||||
// return 0 (equality) when the length is zero.
|
// return 0 (equality) when the length is zero.
|
||||||
irs.scope() = IRScope(memcmpBB);
|
irs.ir->SetInsertPoint(memcmpBB);
|
||||||
auto memcmpAnswer = callMemcmp(loc, irs, l_ptr, r_ptr, l_length);
|
auto memcmpAnswer = callMemcmp(loc, irs, l_ptr, r_ptr, l_length);
|
||||||
irs.ir->CreateBr(memcmpEndBB);
|
irs.ir->CreateBr(memcmpEndBB);
|
||||||
|
|
||||||
// Merge the result of length check and memcmp call into a phi node.
|
// Merge the result of length check and memcmp call into a phi node.
|
||||||
irs.scope() = IRScope(memcmpEndBB);
|
irs.ir->SetInsertPoint(memcmpEndBB);
|
||||||
llvm::PHINode *phi =
|
llvm::PHINode *phi =
|
||||||
irs.ir->CreatePHI(LLType::getInt32Ty(gIR->context()), 2, "cmp_result");
|
irs.ir->CreatePHI(LLType::getInt32Ty(gIR->context()), 2, "cmp_result");
|
||||||
phi->addIncoming(DtoConstInt(1), incomingBB);
|
phi->addIncoming(DtoConstInt(1), incomingBB);
|
||||||
|
@ -1348,11 +1334,11 @@ void DtoIndexBoundsCheck(Loc &loc, DValue *arr, DValue *index) {
|
||||||
gIR->ir->CreateCondBr(cond, okbb, failbb);
|
gIR->ir->CreateCondBr(cond, okbb, failbb);
|
||||||
|
|
||||||
// set up failbb to call the array bounds error runtime function
|
// set up failbb to call the array bounds error runtime function
|
||||||
gIR->scope() = IRScope(failbb);
|
gIR->ir->SetInsertPoint(failbb);
|
||||||
DtoBoundsCheckFailCall(gIR, loc);
|
DtoBoundsCheckFailCall(gIR, loc);
|
||||||
|
|
||||||
// if ok, proceed in okbb
|
// if ok, proceed in okbb
|
||||||
gIR->scope() = IRScope(okbb);
|
gIR->ir->SetInsertPoint(okbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoBoundsCheckFailCall(IRState *irs, Loc &loc) {
|
void DtoBoundsCheckFailCall(IRState *irs, Loc &loc) {
|
||||||
|
|
|
@ -752,11 +752,11 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
|
||||||
pair.second),
|
pair.second),
|
||||||
casebb);
|
casebb);
|
||||||
|
|
||||||
p->scope() = IRScope(casebb);
|
p->ir->SetInsertPoint(casebb);
|
||||||
DtoGoto(stmt->loc, pair.first);
|
DtoGoto(stmt->loc, pair.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
p->scope() = IRScope(bb);
|
p->ir->SetInsertPoint(bb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,10 +103,8 @@ DValue *DtoNewClass(Loc &loc, TypeClass *tc, NewExp *newexp) {
|
||||||
loc, gIR->module, useEHAlloc ? "_d_newThrowable" : "_d_allocclass");
|
loc, gIR->module, useEHAlloc ? "_d_newThrowable" : "_d_allocclass");
|
||||||
LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(),
|
LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(),
|
||||||
DtoType(getClassInfoType()));
|
DtoType(getClassInfoType()));
|
||||||
mem = gIR->CreateCallOrInvoke(fn, ci,
|
mem = gIR->CreateCallOrInvoke(
|
||||||
useEHAlloc ? ".newthrowable_alloc"
|
fn, ci, useEHAlloc ? ".newthrowable_alloc" : ".newclass_gc_alloc");
|
||||||
: ".newclass_gc_alloc")
|
|
||||||
.getInstruction();
|
|
||||||
mem = DtoBitCast(mem, DtoType(tc),
|
mem = DtoBitCast(mem, DtoType(tc),
|
||||||
useEHAlloc ? ".newthrowable" : ".newclass_gc");
|
useEHAlloc ? ".newthrowable" : ".newclass_gc");
|
||||||
doInit = !useEHAlloc;
|
doInit = !useEHAlloc;
|
||||||
|
@ -221,11 +219,11 @@ void DtoFinalizeScopeClass(Loc &loc, LLValue *inst, bool hasDtor) {
|
||||||
getNullValue(monitor->getType()), ".hasMonitor");
|
getNullValue(monitor->getType()), ".hasMonitor");
|
||||||
llvm::BranchInst::Create(ifbb, endbb, hasMonitor, gIR->scopebb());
|
llvm::BranchInst::Create(ifbb, endbb, hasMonitor, gIR->scopebb());
|
||||||
|
|
||||||
gIR->scope() = IRScope(ifbb);
|
gIR->ir->SetInsertPoint(ifbb);
|
||||||
DtoFinalizeClass(loc, inst);
|
DtoFinalizeClass(loc, inst);
|
||||||
gIR->ir->CreateBr(endbb);
|
gIR->ir->CreateBr(endbb);
|
||||||
|
|
||||||
gIR->scope() = IRScope(endbb);
|
gIR->ir->SetInsertPoint(endbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -375,7 +373,7 @@ DValue *DtoDynamicCastObject(Loc &loc, DValue *val, Type *_to) {
|
||||||
assert(funcTy->getParamType(1) == cinfo->getType());
|
assert(funcTy->getParamType(1) == cinfo->getType());
|
||||||
|
|
||||||
// call it
|
// call it
|
||||||
LLValue *ret = gIR->CreateCallOrInvoke(func, obj, cinfo).getInstruction();
|
LLValue *ret = gIR->CreateCallOrInvoke(func, obj, cinfo);
|
||||||
|
|
||||||
// cast return value
|
// cast return value
|
||||||
ret = DtoBitCast(ret, DtoType(_to));
|
ret = DtoBitCast(ret, DtoType(_to));
|
||||||
|
@ -409,7 +407,7 @@ DValue *DtoDynamicCastInterface(Loc &loc, DValue *val, Type *_to) {
|
||||||
cinfo = DtoBitCast(cinfo, funcTy->getParamType(1));
|
cinfo = DtoBitCast(cinfo, funcTy->getParamType(1));
|
||||||
|
|
||||||
// call it
|
// call it
|
||||||
LLValue *ret = gIR->CreateCallOrInvoke(func, ptr, cinfo).getInstruction();
|
LLValue *ret = gIR->CreateCallOrInvoke(func, ptr, cinfo);
|
||||||
|
|
||||||
// cast return value
|
// cast return value
|
||||||
ret = DtoBitCast(ret, DtoType(_to));
|
ret = DtoBitCast(ret, DtoType(_to));
|
||||||
|
|
|
@ -207,7 +207,7 @@ void DIBuilder::SetValue(const Loc &loc, llvm::Value *value,
|
||||||
IR->scopebb());
|
IR->scopebb());
|
||||||
}
|
}
|
||||||
|
|
||||||
DIFile DIBuilder::CreateFile(Loc &loc) {
|
DIFile DIBuilder::CreateFile(const Loc &loc) {
|
||||||
const char *filename = loc.filename;
|
const char *filename = loc.filename;
|
||||||
if (!filename)
|
if (!filename)
|
||||||
filename = IR->dmodule->srcfile.toChars();
|
filename = IR->dmodule->srcfile.toChars();
|
||||||
|
@ -385,14 +385,19 @@ DIType DIBuilder::CreateVectorType(Type *type) {
|
||||||
// translate void vectors to byte vectors
|
// translate void vectors to byte vectors
|
||||||
if (te->toBasetype()->ty == Tvoid)
|
if (te->toBasetype()->ty == Tvoid)
|
||||||
te = Type::tuns8;
|
te = Type::tuns8;
|
||||||
int64_t Dim = tv->size(Loc()) / te->size(Loc());
|
const auto dim = tv->size(Loc()) / te->size(Loc());
|
||||||
LLMetadata *subscripts[] = {DBuilder.getOrCreateSubrange(0, Dim)};
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
const auto Dim = llvm::ConstantAsMetadata::get(DtoConstSize_t(dim));
|
||||||
|
auto subscript = DBuilder.getOrCreateSubrange(Dim, nullptr, nullptr, nullptr);
|
||||||
|
#else
|
||||||
|
auto subscript = DBuilder.getOrCreateSubrange(0, dim);
|
||||||
|
#endif
|
||||||
|
|
||||||
return DBuilder.createVectorType(
|
return DBuilder.createVectorType(
|
||||||
getTypeAllocSize(T) * 8, // size (bits)
|
getTypeAllocSize(T) * 8, // size (bits)
|
||||||
getABITypeAlign(T) * 8, // align (bits)
|
getABITypeAlign(T) * 8, // align (bits)
|
||||||
CreateTypeDescription(te), // element type
|
CreateTypeDescription(te), // element type
|
||||||
DBuilder.getOrCreateArray(subscripts) // subscripts
|
DBuilder.getOrCreateArray({subscript}) // subscripts
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,8 +686,14 @@ DIType DIBuilder::CreateSArrayType(Type *type) {
|
||||||
llvm::SmallVector<LLMetadata *, 8> subscripts;
|
llvm::SmallVector<LLMetadata *, 8> subscripts;
|
||||||
while (t->ty == Tsarray) {
|
while (t->ty == Tsarray) {
|
||||||
TypeSArray *tsa = static_cast<TypeSArray *>(t);
|
TypeSArray *tsa = static_cast<TypeSArray *>(t);
|
||||||
int64_t Count = tsa->dim->toInteger();
|
const auto count = tsa->dim->toInteger();
|
||||||
auto subscript = DBuilder.getOrCreateSubrange(0, Count);
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
const auto Count = llvm::ConstantAsMetadata::get(DtoConstSize_t(count));
|
||||||
|
const auto subscript =
|
||||||
|
DBuilder.getOrCreateSubrange(Count, nullptr, nullptr, nullptr);
|
||||||
|
#else
|
||||||
|
const auto subscript = DBuilder.getOrCreateSubrange(0, count);
|
||||||
|
#endif
|
||||||
subscripts.push_back(subscript);
|
subscripts.push_back(subscript);
|
||||||
t = t->nextOf();
|
t = t->nextOf();
|
||||||
}
|
}
|
||||||
|
@ -1138,26 +1149,15 @@ void DIBuilder::EmitFuncStart(FuncDeclaration *fd) {
|
||||||
Logger::println("D to dwarf funcstart");
|
Logger::println("D to dwarf funcstart");
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
assert(static_cast<llvm::MDNode *>(getIrFunc(fd)->diSubprogram) != 0);
|
auto irFunc = getIrFunc(fd);
|
||||||
|
assert(irFunc->diSubprogram);
|
||||||
|
irFunc->getLLVMFunc()->setSubprogram(irFunc->diSubprogram);
|
||||||
|
|
||||||
|
IR->ir->SetCurrentDebugLocation({}); // clear first
|
||||||
EmitStopPoint(fd->loc);
|
EmitStopPoint(fd->loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DIBuilder::EmitFuncEnd(FuncDeclaration *fd) {
|
void DIBuilder::EmitBlockStart(const Loc &loc) {
|
||||||
if (!mustEmitLocationsDebugInfo())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Logger::println("D to dwarf funcend");
|
|
||||||
LOG_SCOPE;
|
|
||||||
|
|
||||||
auto irFunc = getIrFunc(fd);
|
|
||||||
|
|
||||||
assert(static_cast<llvm::MDNode *>(irFunc->diSubprogram) != 0);
|
|
||||||
EmitStopPoint(fd->endloc);
|
|
||||||
|
|
||||||
irFunc->getLLVMFunc()->setSubprogram(irFunc->diSubprogram);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DIBuilder::EmitBlockStart(Loc &loc) {
|
|
||||||
if (!mustEmitLocationsDebugInfo())
|
if (!mustEmitLocationsDebugInfo())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1182,7 +1182,7 @@ void DIBuilder::EmitBlockEnd() {
|
||||||
fn->diLexicalBlocks.pop();
|
fn->diLexicalBlocks.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DIBuilder::EmitStopPoint(Loc &loc) {
|
void DIBuilder::EmitStopPoint(const Loc &loc) {
|
||||||
if (!mustEmitLocationsDebugInfo())
|
if (!mustEmitLocationsDebugInfo())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1191,6 +1191,7 @@ void DIBuilder::EmitStopPoint(Loc &loc) {
|
||||||
// cannot do this in all cases).
|
// cannot do this in all cases).
|
||||||
if (!loc.linnum && IR->ir->getCurrentDebugLocation())
|
if (!loc.linnum && IR->ir->getCurrentDebugLocation())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
unsigned linnum = loc.linnum;
|
unsigned linnum = loc.linnum;
|
||||||
// without proper loc use the line of the enclosing symbol that has line
|
// without proper loc use the line of the enclosing symbol that has line
|
||||||
// number debug info
|
// number debug info
|
||||||
|
@ -1204,11 +1205,8 @@ void DIBuilder::EmitStopPoint(Loc &loc) {
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
IR->ir->SetCurrentDebugLocation(
|
IR->ir->SetCurrentDebugLocation(
|
||||||
llvm::DebugLoc::get(linnum, col, GetCurrentScope()));
|
llvm::DebugLoc::get(linnum, col, GetCurrentScope()));
|
||||||
currentLoc = loc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Loc DIBuilder::GetCurrentLoc() const { return currentLoc; }
|
|
||||||
|
|
||||||
void DIBuilder::EmitValue(llvm::Value *val, VarDeclaration *vd) {
|
void DIBuilder::EmitValue(llvm::Value *val, VarDeclaration *vd) {
|
||||||
auto sub = IR->func()->variableMap.find(vd);
|
auto sub = IR->func()->variableMap.find(vd);
|
||||||
if (sub == IR->func()->variableMap.end())
|
if (sub == IR->func()->variableMap.end())
|
||||||
|
|
|
@ -72,8 +72,6 @@ class DIBuilder {
|
||||||
return CUNode;
|
return CUNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loc currentLoc;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DIBuilder(IRState *const IR);
|
explicit DIBuilder(IRState *const IR);
|
||||||
|
|
||||||
|
@ -114,18 +112,13 @@ public:
|
||||||
/// \brief Emits debug info for function start
|
/// \brief Emits debug info for function start
|
||||||
void EmitFuncStart(FuncDeclaration *fd);
|
void EmitFuncStart(FuncDeclaration *fd);
|
||||||
|
|
||||||
/// \brief Emits debug info for function end
|
|
||||||
void EmitFuncEnd(FuncDeclaration *fd);
|
|
||||||
|
|
||||||
/// \brief Emits debug info for block start
|
/// \brief Emits debug info for block start
|
||||||
void EmitBlockStart(Loc &loc);
|
void EmitBlockStart(const Loc &loc);
|
||||||
|
|
||||||
/// \brief Emits debug info for block end
|
/// \brief Emits debug info for block end
|
||||||
void EmitBlockEnd();
|
void EmitBlockEnd();
|
||||||
|
|
||||||
Loc GetCurrentLoc() const;
|
void EmitStopPoint(const Loc &loc);
|
||||||
|
|
||||||
void EmitStopPoint(Loc &loc);
|
|
||||||
|
|
||||||
void EmitValue(llvm::Value *val, VarDeclaration *vd);
|
void EmitValue(llvm::Value *val, VarDeclaration *vd);
|
||||||
|
|
||||||
|
@ -171,7 +164,7 @@ private:
|
||||||
llvm::SmallVector<llvm::Metadata *, 16> &elems);
|
llvm::SmallVector<llvm::Metadata *, 16> &elems);
|
||||||
void AddStaticMembers(AggregateDeclaration *sd, ldc::DIFile file,
|
void AddStaticMembers(AggregateDeclaration *sd, ldc::DIFile file,
|
||||||
llvm::SmallVector<llvm::Metadata *, 16> &elems);
|
llvm::SmallVector<llvm::Metadata *, 16> &elems);
|
||||||
DIFile CreateFile(Loc &loc);
|
DIFile CreateFile(const Loc &loc);
|
||||||
DIFile CreateFile();
|
DIFile CreateFile();
|
||||||
DIFile CreateFile(Dsymbol* decl);
|
DIFile CreateFile(Dsymbol* decl);
|
||||||
DIType CreateBasicType(Type *type);
|
DIType CreateBasicType(Type *type);
|
||||||
|
|
|
@ -193,8 +193,8 @@ void stripModule(llvm::Module &module) {
|
||||||
|
|
||||||
void fixRtModule(llvm::Module &newModule,
|
void fixRtModule(llvm::Module &newModule,
|
||||||
const decltype(IRState::dynamicCompiledFunctions) &funcs) {
|
const decltype(IRState::dynamicCompiledFunctions) &funcs) {
|
||||||
std::unordered_map<std::string, std::string> thunkVar2func;
|
std::unordered_map<std::string, llvm::StringRef> thunkVar2func;
|
||||||
std::unordered_map<std::string, std::string> thunkFun2func;
|
std::unordered_map<std::string, llvm::StringRef> thunkFun2func;
|
||||||
std::unordered_set<std::string> externalFuncs;
|
std::unordered_set<std::string> externalFuncs;
|
||||||
for (auto &&it : funcs) {
|
for (auto &&it : funcs) {
|
||||||
assert(nullptr != it.first);
|
assert(nullptr != it.first);
|
||||||
|
@ -769,7 +769,12 @@ void createThunkFunc(llvm::Module &module, const llvm::Function *src,
|
||||||
for (auto &arg : dst->args()) {
|
for (auto &arg : dst->args()) {
|
||||||
args.push_back(&arg);
|
args.push_back(&arg);
|
||||||
}
|
}
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
auto ret = builder.CreateCall(
|
||||||
|
llvm::FunctionCallee(dst->getFunctionType(), thunkPtr), args);
|
||||||
|
#else
|
||||||
auto ret = builder.CreateCall(thunkPtr, args);
|
auto ret = builder.CreateCall(thunkPtr, args);
|
||||||
|
#endif
|
||||||
ret->setCallingConv(src->getCallingConv());
|
ret->setCallingConv(src->getCallingConv());
|
||||||
ret->setAttributes(src->getAttributes());
|
ret->setAttributes(src->getAttributes());
|
||||||
if (dst->getReturnType()->isVoidTy()) {
|
if (dst->getReturnType()->isVoidTy()) {
|
||||||
|
|
|
@ -103,9 +103,10 @@ FuncGenState::FuncGenState(IrFunction &irFunc, IRState &irs)
|
||||||
: irFunc(irFunc), scopes(irs), jumpTargets(scopes), switchTargets(),
|
: irFunc(irFunc), scopes(irs), jumpTargets(scopes), switchTargets(),
|
||||||
irs(irs) {}
|
irs(irs) {}
|
||||||
|
|
||||||
llvm::CallSite FuncGenState::callOrInvoke(llvm::Value *callee,
|
LLCallBasePtr FuncGenState::callOrInvoke(llvm::Value *callee,
|
||||||
llvm::ArrayRef<llvm::Value *> args,
|
llvm::FunctionType *calleeType,
|
||||||
const char *name, bool isNothrow) {
|
llvm::ArrayRef<llvm::Value *> args,
|
||||||
|
const char *name, bool isNothrow) {
|
||||||
// If this is a direct call, we might be able to use the callee attributes
|
// If this is a direct call, we might be able to use the callee attributes
|
||||||
// to our advantage.
|
// to our advantage.
|
||||||
llvm::Function *calleeFn = llvm::dyn_cast<llvm::Function>(callee);
|
llvm::Function *calleeFn = llvm::dyn_cast<llvm::Function>(callee);
|
||||||
|
@ -123,8 +124,14 @@ llvm::CallSite FuncGenState::callOrInvoke(llvm::Value *callee,
|
||||||
// calls inside a funclet must be annotated with its value
|
// calls inside a funclet must be annotated with its value
|
||||||
llvm::SmallVector<llvm::OperandBundleDef, 2> BundleList;
|
llvm::SmallVector<llvm::OperandBundleDef, 2> BundleList;
|
||||||
|
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
llvm::FunctionCallee calleeArg(calleeType, callee);
|
||||||
|
#else
|
||||||
|
auto calleeArg = callee;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (doesNotThrow || scopes.empty()) {
|
if (doesNotThrow || scopes.empty()) {
|
||||||
llvm::CallInst *call = irs.ir->CreateCall(callee, args, BundleList, name);
|
auto call = irs.ir->CreateCall(calleeArg, args, BundleList, name);
|
||||||
if (calleeFn) {
|
if (calleeFn) {
|
||||||
call->setAttributes(calleeFn->getAttributes());
|
call->setAttributes(calleeFn->getAttributes());
|
||||||
}
|
}
|
||||||
|
@ -134,12 +141,12 @@ llvm::CallSite FuncGenState::callOrInvoke(llvm::Value *callee,
|
||||||
llvm::BasicBlock *landingPad = scopes.getLandingPad();
|
llvm::BasicBlock *landingPad = scopes.getLandingPad();
|
||||||
|
|
||||||
llvm::BasicBlock *postinvoke = irs.insertBB("postinvoke");
|
llvm::BasicBlock *postinvoke = irs.insertBB("postinvoke");
|
||||||
llvm::InvokeInst *invoke = irs.ir->CreateInvoke(
|
auto invoke = irs.ir->CreateInvoke(calleeArg, postinvoke, landingPad, args,
|
||||||
callee, postinvoke, landingPad, args, BundleList, name);
|
BundleList, name);
|
||||||
if (calleeFn) {
|
if (calleeFn) {
|
||||||
invoke->setAttributes(calleeFn->getAttributes());
|
invoke->setAttributes(calleeFn->getAttributes());
|
||||||
}
|
}
|
||||||
|
|
||||||
irs.scope() = IRScope(postinvoke);
|
irs.ir->SetInsertPoint(postinvoke);
|
||||||
return invoke;
|
return invoke;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include "gen/pgo_ASTbased.h"
|
#include "gen/pgo_ASTbased.h"
|
||||||
#include "gen/trycatchfinally.h"
|
#include "gen/trycatchfinally.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/IR/CallSite.h"
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class Identifier;
|
class Identifier;
|
||||||
|
@ -200,9 +199,10 @@ public:
|
||||||
|
|
||||||
/// Emits a call or invoke to the given callee, depending on whether there
|
/// Emits a call or invoke to the given callee, depending on whether there
|
||||||
/// are catches/cleanups active or not.
|
/// are catches/cleanups active or not.
|
||||||
llvm::CallSite callOrInvoke(llvm::Value *callee,
|
LLCallBasePtr callOrInvoke(llvm::Value *callee,
|
||||||
llvm::ArrayRef<llvm::Value *> args,
|
llvm::FunctionType *calleeType,
|
||||||
const char *name = "", bool isNothrow = false);
|
llvm::ArrayRef<llvm::Value *> args,
|
||||||
|
const char *name = "", bool isNothrow = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IRState &irs;
|
IRState &irs;
|
||||||
|
|
|
@ -454,20 +454,28 @@ void applyParamAttrsToLLFunc(TypeFunction *f, IrFuncTy &irFty,
|
||||||
/// does the same). See https://llvm.org/bugs/show_bug.cgi?id=23172
|
/// does the same). See https://llvm.org/bugs/show_bug.cgi?id=23172
|
||||||
void applyTargetMachineAttributes(llvm::Function &func,
|
void applyTargetMachineAttributes(llvm::Function &func,
|
||||||
const llvm::TargetMachine &target) {
|
const llvm::TargetMachine &target) {
|
||||||
const llvm::TargetOptions &TO = target.Options;
|
const auto dcompute = gIR->dcomputetarget;
|
||||||
|
|
||||||
// TODO: implement commandline switches to change the default values.
|
|
||||||
// TODO: (correctly) apply these for NVPTX (but not for SPIRV).
|
// TODO: (correctly) apply these for NVPTX (but not for SPIRV).
|
||||||
if (gIR->dcomputetarget && gIR->dcomputetarget->target == DComputeTarget::OpenCL)
|
if (dcompute && dcompute->target == DComputeTarget::OpenCL)
|
||||||
return;
|
return;
|
||||||
if (!gIR->dcomputetarget) {
|
const auto cpu = dcompute ? "" : target.getTargetCPU();
|
||||||
// Target CPU capabilities
|
const auto features = dcompute ? "" : target.getTargetFeatureString();
|
||||||
func.addFnAttr("target-cpu", target.getTargetCPU());
|
|
||||||
auto featStr = target.getTargetFeatureString();
|
#if LDC_LLVM_VER >= 1000
|
||||||
if (!featStr.empty())
|
opts::setFunctionAttributes(cpu, features, func);
|
||||||
func.addFnAttr("target-features", featStr);
|
if (opts::fFastMath) // -ffast-math[=true] overrides -enable-unsafe-fp-math
|
||||||
}
|
func.addFnAttr("unsafe-fp-math", "true");
|
||||||
|
if (!func.hasFnAttribute("frame-pointer")) // not explicitly set by user
|
||||||
|
func.addFnAttr("frame-pointer", isOptimizationEnabled() ? "none" : "all");
|
||||||
|
#else
|
||||||
|
if (!cpu.empty())
|
||||||
|
func.addFnAttr("target-cpu", cpu);
|
||||||
|
if (!features.empty())
|
||||||
|
func.addFnAttr("target-features", features);
|
||||||
|
|
||||||
// Floating point settings
|
// Floating point settings
|
||||||
|
const auto &TO = target.Options;
|
||||||
func.addFnAttr("unsafe-fp-math", TO.UnsafeFPMath ? "true" : "false");
|
func.addFnAttr("unsafe-fp-math", TO.UnsafeFPMath ? "true" : "false");
|
||||||
// This option was removed from llvm::TargetOptions in LLVM 5.0.
|
// This option was removed from llvm::TargetOptions in LLVM 5.0.
|
||||||
// Clang sets this to true when `-cl-mad-enable` is passed (OpenCL only).
|
// Clang sets this to true when `-cl-mad-enable` is passed (OpenCL only).
|
||||||
|
@ -490,10 +498,11 @@ void applyTargetMachineAttributes(llvm::Function &func,
|
||||||
func.addFnAttr("frame-pointer", "all");
|
func.addFnAttr("frame-pointer", "all");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#else
|
#else // LDC_LLVM_VER < 800
|
||||||
func.addFnAttr("no-frame-pointer-elim",
|
func.addFnAttr("no-frame-pointer-elim",
|
||||||
willEliminateFramePointer() ? "false" : "true");
|
willEliminateFramePointer() ? "false" : "true");
|
||||||
#endif
|
#endif
|
||||||
|
#endif // LDC_LLVM_VER < 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyXRayAttributes(FuncDeclaration &fdecl, llvm::Function &func) {
|
void applyXRayAttributes(FuncDeclaration &fdecl, llvm::Function &func) {
|
||||||
|
@ -883,12 +892,11 @@ void emitDMDStyleFunctionTrace(IRState &irs, FuncDeclaration *fd,
|
||||||
// Push cleanup block that calls _c_trace_epi at function exit.
|
// Push cleanup block that calls _c_trace_epi at function exit.
|
||||||
{
|
{
|
||||||
auto traceEpilogBB = irs.insertBB("trace_epi");
|
auto traceEpilogBB = irs.insertBB("trace_epi");
|
||||||
auto saveScope = irs.scope();
|
const auto savedInsertPoint = irs.saveInsertPoint();
|
||||||
irs.scope() = IRScope(traceEpilogBB);
|
irs.ir->SetInsertPoint(traceEpilogBB);
|
||||||
irs.ir->CreateCall(
|
irs.ir->CreateCall(
|
||||||
getRuntimeFunction(fd->endloc, irs.module, "_c_trace_epi"));
|
getRuntimeFunction(fd->endloc, irs.module, "_c_trace_epi"));
|
||||||
funcGen.scopes.pushCleanup(traceEpilogBB, irs.scopebb());
|
funcGen.scopes.pushCleanup(traceEpilogBB, irs.scopebb());
|
||||||
irs.scope() = saveScope;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -926,7 +934,7 @@ void emulateWeakAnyLinkageForMSVC(LLFunction *func, LINK linkage) {
|
||||||
finalMangle = mangleBuffer;
|
finalMangle = mangleBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string finalWeakMangle = finalMangle;
|
std::string finalWeakMangle = finalMangle.str();
|
||||||
if (linkage == LINKcpp) {
|
if (linkage == LINKcpp) {
|
||||||
assert(finalMangle.startswith("?"));
|
assert(finalMangle.startswith("?"));
|
||||||
// prepend `__weak_` to first identifier
|
// prepend `__weak_` to first identifier
|
||||||
|
@ -1165,13 +1173,10 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
|
||||||
llvm::BasicBlock *beginbb =
|
llvm::BasicBlock *beginbb =
|
||||||
llvm::BasicBlock::Create(gIR->context(), "", func);
|
llvm::BasicBlock::Create(gIR->context(), "", func);
|
||||||
|
|
||||||
gIR->scopes.push_back(IRScope(beginbb));
|
// set up the IRBuilder scope for the function
|
||||||
SCOPE_EXIT {
|
const auto savedIRBuilderScope = gIR->setInsertPoint(beginbb);
|
||||||
gIR->scopes.pop_back();
|
gIR->ir->setFastMathFlags(irFunc->FMF);
|
||||||
};
|
gIR->DBuilder.EmitFuncStart(fd);
|
||||||
|
|
||||||
// Set the FastMath options for this function scope.
|
|
||||||
gIR->scopes.back().builder.setFastMathFlags(irFunc->FMF);
|
|
||||||
|
|
||||||
// @naked: emit body and return, no prologue/epilogue
|
// @naked: emit body and return, no prologue/epilogue
|
||||||
if (func->hasFnAttribute(llvm::Attribute::Naked)) {
|
if (func->hasFnAttribute(llvm::Attribute::Naked)) {
|
||||||
|
@ -1194,9 +1199,6 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
|
||||||
"alloca_point", beginbb);
|
"alloca_point", beginbb);
|
||||||
funcGen.allocapoint = allocaPoint;
|
funcGen.allocapoint = allocaPoint;
|
||||||
|
|
||||||
// debug info - after all allocas, but before any llvm.dbg.declare etc
|
|
||||||
gIR->DBuilder.EmitFuncStart(fd);
|
|
||||||
|
|
||||||
emitInstrumentationFnEnter(fd);
|
emitInstrumentationFnEnter(fd);
|
||||||
|
|
||||||
if (global.params.trace && fd->emitInstrumentation && !fd->isCMain() &&
|
if (global.params.trace && fd->emitInstrumentation && !fd->isCMain() &&
|
||||||
|
@ -1277,11 +1279,10 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
|
||||||
{
|
{
|
||||||
auto *vaendBB =
|
auto *vaendBB =
|
||||||
llvm::BasicBlock::Create(gIR->context(), "vaend", gIR->topfunc());
|
llvm::BasicBlock::Create(gIR->context(), "vaend", gIR->topfunc());
|
||||||
IRScope saveScope = gIR->scope();
|
const auto savedInsertPoint = gIR->saveInsertPoint();
|
||||||
gIR->scope() = IRScope(vaendBB);
|
gIR->ir->SetInsertPoint(vaendBB);
|
||||||
gIR->ir->CreateCall(GET_INTRINSIC_DECL(vaend), llAp);
|
gIR->ir->CreateCall(GET_INTRINSIC_DECL(vaend), llAp);
|
||||||
funcGen.scopes.pushCleanup(vaendBB, gIR->scopebb());
|
funcGen.scopes.pushCleanup(vaendBB, gIR->scopebb());
|
||||||
gIR->scope() = saveScope;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1297,7 +1298,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
|
||||||
if (!funcGen.retBlock)
|
if (!funcGen.retBlock)
|
||||||
funcGen.retBlock = gIR->insertBB("return");
|
funcGen.retBlock = gIR->insertBB("return");
|
||||||
funcGen.scopes.runCleanups(0, funcGen.retBlock);
|
funcGen.scopes.runCleanups(0, funcGen.retBlock);
|
||||||
gIR->scope() = IRScope(funcGen.retBlock);
|
gIR->ir->SetInsertPoint(funcGen.retBlock);
|
||||||
}
|
}
|
||||||
funcGen.scopes.popCleanups(0);
|
funcGen.scopes.popCleanups(0);
|
||||||
}
|
}
|
||||||
|
@ -1322,7 +1323,6 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
|
||||||
gIR->ir->CreateRet(llvm::UndefValue::get(func->getReturnType()));
|
gIR->ir->CreateRet(llvm::UndefValue::get(func->getReturnType()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gIR->DBuilder.EmitFuncEnd(fd);
|
|
||||||
|
|
||||||
// erase alloca point
|
// erase alloca point
|
||||||
if (allocaPoint->getParent()) {
|
if (allocaPoint->getParent()) {
|
||||||
|
|
|
@ -26,20 +26,9 @@ llvm::TargetMachine *gTargetMachine = nullptr;
|
||||||
const llvm::DataLayout *gDataLayout = nullptr;
|
const llvm::DataLayout *gDataLayout = nullptr;
|
||||||
TargetABI *gABI = nullptr;
|
TargetABI *gABI = nullptr;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
IRScope::IRScope() : builder(gIR->context()) { begin = nullptr; }
|
|
||||||
|
|
||||||
IRScope::IRScope(llvm::BasicBlock *b) : begin(b), builder(b) {}
|
|
||||||
|
|
||||||
IRScope &IRScope::operator=(const IRScope &rhs) {
|
|
||||||
begin = rhs.begin;
|
|
||||||
builder.SetInsertPoint(begin);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
IRState::IRState(const char *name, llvm::LLVMContext &context)
|
IRState::IRState(const char *name, llvm::LLVMContext &context)
|
||||||
: module(name, context), objc(module), DBuilder(this) {
|
: builder(context), module(name, context), objc(module), DBuilder(this) {
|
||||||
ir.state = this;
|
ir.state = this;
|
||||||
mem.addRange(&inlineAsmLocs, sizeof(inlineAsmLocs));
|
mem.addRange(&inlineAsmLocs, sizeof(inlineAsmLocs));
|
||||||
}
|
}
|
||||||
|
@ -57,20 +46,20 @@ llvm::Function *IRState::topfunc() { return func()->getLLVMFunc(); }
|
||||||
|
|
||||||
llvm::Instruction *IRState::topallocapoint() { return funcGen().allocapoint; }
|
llvm::Instruction *IRState::topallocapoint() { return funcGen().allocapoint; }
|
||||||
|
|
||||||
IRScope &IRState::scope() {
|
std::unique_ptr<IRBuilderScope> IRState::setInsertPoint(llvm::BasicBlock *bb) {
|
||||||
assert(!scopes.empty());
|
auto savedScope = llvm::make_unique<IRBuilderScope>(builder);
|
||||||
return scopes.back();
|
builder.SetInsertPoint(bb);
|
||||||
|
return savedScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::BasicBlock *IRState::scopebb() {
|
std::unique_ptr<llvm::IRBuilderBase::InsertPointGuard>
|
||||||
IRScope &s = scope();
|
IRState::saveInsertPoint() {
|
||||||
assert(s.begin);
|
return llvm::make_unique<llvm::IRBuilderBase::InsertPointGuard>(builder);
|
||||||
return s.begin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IRState::scopereturned() {
|
bool IRState::scopereturned() {
|
||||||
// return scope().returned;
|
auto bb = scopebb();
|
||||||
return !scopebb()->empty() && scopebb()->back().isTerminator();
|
return !bb->empty() && bb->back().isTerminator();
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::BasicBlock *IRState::insertBBBefore(llvm::BasicBlock *successor,
|
llvm::BasicBlock *IRState::insertBBBefore(llvm::BasicBlock *successor,
|
||||||
|
@ -89,35 +78,42 @@ llvm::BasicBlock *IRState::insertBB(const llvm::Twine &name) {
|
||||||
return insertBBAfter(scopebb(), name);
|
return insertBBAfter(scopebb(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, const char *Name) {
|
llvm::Instruction *IRState::CreateCallOrInvoke(LLFunction *Callee,
|
||||||
return funcGen().callOrInvoke(Callee, {}, Name);
|
const char *Name) {
|
||||||
|
return CreateCallOrInvoke(Callee, {}, Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee,
|
llvm::Instruction *IRState::CreateCallOrInvoke(LLFunction *Callee,
|
||||||
llvm::ArrayRef<LLValue *> Args,
|
llvm::ArrayRef<LLValue *> Args,
|
||||||
const char *Name, bool isNothrow) {
|
const char *Name,
|
||||||
return funcGen().callOrInvoke(Callee, Args, Name, isNothrow);
|
bool isNothrow) {
|
||||||
|
return funcGen().callOrInvoke(Callee, Callee->getFunctionType(), Args, Name,
|
||||||
|
isNothrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
llvm::Instruction *IRState::CreateCallOrInvoke(LLFunction *Callee,
|
||||||
const char *Name) {
|
LLValue *Arg1,
|
||||||
return funcGen().callOrInvoke(Callee, {Arg1}, Name);
|
const char *Name) {
|
||||||
|
return CreateCallOrInvoke(Callee, llvm::ArrayRef<LLValue *>(Arg1), Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
llvm::Instruction *IRState::CreateCallOrInvoke(LLFunction *Callee,
|
||||||
LLValue *Arg2, const char *Name) {
|
LLValue *Arg1, LLValue *Arg2,
|
||||||
|
const char *Name) {
|
||||||
return CreateCallOrInvoke(Callee, {Arg1, Arg2}, Name);
|
return CreateCallOrInvoke(Callee, {Arg1, Arg2}, Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
llvm::Instruction *IRState::CreateCallOrInvoke(LLFunction *Callee,
|
||||||
LLValue *Arg2, LLValue *Arg3,
|
LLValue *Arg1, LLValue *Arg2,
|
||||||
const char *Name) {
|
LLValue *Arg3,
|
||||||
|
const char *Name) {
|
||||||
return CreateCallOrInvoke(Callee, {Arg1, Arg2, Arg3}, Name);
|
return CreateCallOrInvoke(Callee, {Arg1, Arg2, Arg3}, Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCallSite IRState::CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
llvm::Instruction *IRState::CreateCallOrInvoke(LLFunction *Callee,
|
||||||
LLValue *Arg2, LLValue *Arg3,
|
LLValue *Arg1, LLValue *Arg2,
|
||||||
LLValue *Arg4, const char *Name) {
|
LLValue *Arg3, LLValue *Arg4,
|
||||||
|
const char *Name) {
|
||||||
return CreateCallOrInvoke(Callee, {Arg1, Arg2, Arg3, Arg4}, Name);
|
return CreateCallOrInvoke(Callee, {Arg1, Arg2, Arg3, Arg4}, Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,8 +280,8 @@ const Loc &IRState::getInlineAsmSrcLoc(unsigned srcLocCookie) const {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
IRBuilder<> *IRBuilderHelper::operator->() {
|
IRBuilder<> *IRBuilderHelper::operator->() {
|
||||||
IRBuilder<> &b = state->scope().builder;
|
IRBuilder<> &b = state->builder;
|
||||||
assert(b.GetInsertBlock() != NULL);
|
assert(b.GetInsertBlock());
|
||||||
return &b;
|
return &b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include "ir/irvar.h"
|
#include "ir/irvar.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringMap.h"
|
||||||
#include "llvm/IR/CallSite.h"
|
|
||||||
#include "llvm/ProfileData/InstrProfReader.h"
|
#include "llvm/ProfileData/InstrProfReader.h"
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -59,16 +58,15 @@ class StructLiteralExp;
|
||||||
struct IrFunction;
|
struct IrFunction;
|
||||||
struct IrModule;
|
struct IrModule;
|
||||||
|
|
||||||
// represents a scope
|
// Saves the IRBuilder state and restores it on destruction.
|
||||||
struct IRScope {
|
struct IRBuilderScope {
|
||||||
llvm::BasicBlock *begin;
|
private:
|
||||||
IRBuilder<> builder;
|
llvm::IRBuilderBase::InsertPointGuard ipGuard;
|
||||||
|
llvm::IRBuilderBase::FastMathFlagGuard fmfGuard;
|
||||||
|
|
||||||
IRScope();
|
public:
|
||||||
IRScope(const IRScope &) = default;
|
explicit IRBuilderScope(llvm::IRBuilderBase &builder)
|
||||||
explicit IRScope(llvm::BasicBlock *b);
|
: ipGuard(builder), fmfGuard(builder) {}
|
||||||
|
|
||||||
IRScope &operator=(const IRScope &rhs);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IRBuilderHelper {
|
struct IRBuilderHelper {
|
||||||
|
@ -111,6 +109,9 @@ struct IRAsmBlock {
|
||||||
// represents the LLVM module (object file)
|
// represents the LLVM module (object file)
|
||||||
struct IRState {
|
struct IRState {
|
||||||
private:
|
private:
|
||||||
|
IRBuilder<> builder;
|
||||||
|
friend struct IRBuilderHelper;
|
||||||
|
|
||||||
std::vector<std::pair<llvm::GlobalVariable *, llvm::Constant *>>
|
std::vector<std::pair<llvm::GlobalVariable *, llvm::Constant *>>
|
||||||
globalsToReplace;
|
globalsToReplace;
|
||||||
Array<Loc> inlineAsmLocs; // tracked by GC
|
Array<Loc> inlineAsmLocs; // tracked by GC
|
||||||
|
@ -154,10 +155,16 @@ public:
|
||||||
llvm::Function *topfunc();
|
llvm::Function *topfunc();
|
||||||
llvm::Instruction *topallocapoint();
|
llvm::Instruction *topallocapoint();
|
||||||
|
|
||||||
// basic block scopes
|
// Use this to set the IRBuilder's insertion point for a new function.
|
||||||
std::vector<IRScope> scopes;
|
// The previous IRBuilder state is restored when the returned value is
|
||||||
IRScope &scope();
|
// destructed. Use `ir->SetInsertPoint()` instead to change the insertion
|
||||||
llvm::BasicBlock *scopebb();
|
// point inside the same function.
|
||||||
|
std::unique_ptr<IRBuilderScope> setInsertPoint(llvm::BasicBlock *bb);
|
||||||
|
// Use this to have the IRBuilder's current insertion point (incl. debug
|
||||||
|
// location) restored when the returned value is destructed.
|
||||||
|
std::unique_ptr<llvm::IRBuilderBase::InsertPointGuard> saveInsertPoint();
|
||||||
|
// Returns the basic block the IRBuilder currently inserts into.
|
||||||
|
llvm::BasicBlock *scopebb() { return ir->GetInsertBlock(); }
|
||||||
bool scopereturned();
|
bool scopereturned();
|
||||||
|
|
||||||
// Creates a new basic block and inserts it before the specified one.
|
// Creates a new basic block and inserts it before the specified one.
|
||||||
|
@ -171,21 +178,22 @@ public:
|
||||||
llvm::BasicBlock *insertBB(const llvm::Twine &name);
|
llvm::BasicBlock *insertBB(const llvm::Twine &name);
|
||||||
|
|
||||||
// create a call or invoke, depending on the landing pad info
|
// create a call or invoke, depending on the landing pad info
|
||||||
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, const char *Name = "");
|
llvm::Instruction *CreateCallOrInvoke(LLFunction *Callee,
|
||||||
llvm::CallSite CreateCallOrInvoke(LLValue *Callee,
|
const char *Name = "");
|
||||||
llvm::ArrayRef<LLValue *> Args,
|
llvm::Instruction *CreateCallOrInvoke(LLFunction *Callee,
|
||||||
const char *Name = "",
|
llvm::ArrayRef<LLValue *> Args,
|
||||||
bool isNothrow = false);
|
const char *Name = "",
|
||||||
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
bool isNothrow = false);
|
||||||
const char *Name = "");
|
llvm::Instruction *CreateCallOrInvoke(LLFunction *Callee, LLValue *Arg1,
|
||||||
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
const char *Name = "");
|
||||||
LLValue *Arg2, const char *Name = "");
|
llvm::Instruction *CreateCallOrInvoke(LLFunction *Callee, LLValue *Arg1,
|
||||||
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
LLValue *Arg2, const char *Name = "");
|
||||||
LLValue *Arg2, LLValue *Arg3,
|
llvm::Instruction *CreateCallOrInvoke(LLFunction *Callee, LLValue *Arg1,
|
||||||
const char *Name = "");
|
LLValue *Arg2, LLValue *Arg3,
|
||||||
llvm::CallSite CreateCallOrInvoke(LLValue *Callee, LLValue *Arg1,
|
const char *Name = "");
|
||||||
LLValue *Arg2, LLValue *Arg3, LLValue *Arg4,
|
llvm::Instruction *CreateCallOrInvoke(LLFunction *Callee, LLValue *Arg1,
|
||||||
const char *Name = "");
|
LLValue *Arg2, LLValue *Arg3,
|
||||||
|
LLValue *Arg4, const char *Name = "");
|
||||||
|
|
||||||
// this holds the array being indexed or sliced so $ will work
|
// this holds the array being indexed or sliced so $ will work
|
||||||
// might be a better way but it works. problem is I only get a
|
// might be a better way but it works. problem is I only get a
|
||||||
|
|
28
gen/llvm.h
28
gen/llvm.h
|
@ -30,7 +30,9 @@
|
||||||
#include "llvm/IR/DataLayout.h"
|
#include "llvm/IR/DataLayout.h"
|
||||||
#include "llvm/IR/IRBuilder.h"
|
#include "llvm/IR/IRBuilder.h"
|
||||||
#include "llvm/IR/DebugInfo.h"
|
#include "llvm/IR/DebugInfo.h"
|
||||||
|
#if LDC_LLVM_VER < 800
|
||||||
#include "llvm/IR/CallSite.h"
|
#include "llvm/IR/CallSite.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if LDC_LLVM_VER >= 1000
|
#if LDC_LLVM_VER >= 1000
|
||||||
// LLVM >= 10 requires C++14 and no longer has llvm::make_unique. Add it back
|
// LLVM >= 10 requires C++14 and no longer has llvm::make_unique. Add it back
|
||||||
|
@ -46,8 +48,14 @@ using llvm::APInt;
|
||||||
using llvm::IRBuilder;
|
using llvm::IRBuilder;
|
||||||
|
|
||||||
#if LDC_LLVM_VER >= 1000
|
#if LDC_LLVM_VER >= 1000
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
#define LLAlign llvm::Align
|
||||||
|
#else
|
||||||
|
#define LLAlign llvm::MaybeAlign
|
||||||
|
#endif
|
||||||
#define LLMaybeAlign llvm::MaybeAlign
|
#define LLMaybeAlign llvm::MaybeAlign
|
||||||
#else
|
#else
|
||||||
|
#define LLAlign
|
||||||
#define LLMaybeAlign
|
#define LLMaybeAlign
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -75,6 +83,22 @@ using llvm::IRBuilder;
|
||||||
#define LLConstantInt llvm::ConstantInt
|
#define LLConstantInt llvm::ConstantInt
|
||||||
#define LLConstantFP llvm::ConstantFP
|
#define LLConstantFP llvm::ConstantFP
|
||||||
|
|
||||||
#define LLCallSite llvm::CallSite
|
|
||||||
|
|
||||||
#define LLSmallVector llvm::SmallVector
|
#define LLSmallVector llvm::SmallVector
|
||||||
|
|
||||||
|
#if LDC_LLVM_VER >= 800
|
||||||
|
using LLCallBasePtr = llvm::CallBase *;
|
||||||
|
#else
|
||||||
|
class LLCallBasePtr {
|
||||||
|
llvm::CallSite CS;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LLCallBasePtr(llvm::CallInst *CI) : CS(CI) {}
|
||||||
|
LLCallBasePtr(llvm::InvokeInst *II) : CS(II) {}
|
||||||
|
explicit LLCallBasePtr(llvm::Instruction *I) : CS(I) {}
|
||||||
|
|
||||||
|
llvm::CallSite *operator->() { return &CS; }
|
||||||
|
|
||||||
|
operator llvm::CallSite &() { return CS; }
|
||||||
|
operator llvm::Instruction *() { return CS.getInstruction(); }
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
|
@ -85,7 +85,7 @@ LLValue *DtoNew(Loc &loc, Type *newtype) {
|
||||||
LLConstant *ti = DtoTypeInfoOf(newtype);
|
LLConstant *ti = DtoTypeInfoOf(newtype);
|
||||||
assert(isaPointer(ti));
|
assert(isaPointer(ti));
|
||||||
// call runtime allocator
|
// call runtime allocator
|
||||||
LLValue *mem = gIR->CreateCallOrInvoke(fn, ti, ".gc_mem").getInstruction();
|
LLValue *mem = gIR->CreateCallOrInvoke(fn, ti, ".gc_mem");
|
||||||
// cast
|
// cast
|
||||||
return DtoBitCast(mem, DtoPtrToType(newtype), ".gc_mem");
|
return DtoBitCast(mem, DtoPtrToType(newtype), ".gc_mem");
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ LLValue *DtoNewStruct(Loc &loc, TypeStruct *newtype) {
|
||||||
loc, gIR->module,
|
loc, gIR->module,
|
||||||
newtype->isZeroInit(newtype->sym->loc) ? "_d_newitemT" : "_d_newitemiT");
|
newtype->isZeroInit(newtype->sym->loc) ? "_d_newitemT" : "_d_newitemiT");
|
||||||
LLConstant *ti = DtoTypeInfoOf(newtype);
|
LLConstant *ti = DtoTypeInfoOf(newtype);
|
||||||
LLValue *mem = gIR->CreateCallOrInvoke(fn, ti, ".gc_struct").getInstruction();
|
LLValue *mem = gIR->CreateCallOrInvoke(fn, ti, ".gc_struct");
|
||||||
return DtoBitCast(mem, DtoPtrToType(newtype), ".gc_struct");
|
return DtoBitCast(mem, DtoPtrToType(newtype), ".gc_struct");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +180,9 @@ llvm::AllocaInst *DtoArrayAlloca(Type *type, unsigned arraysize,
|
||||||
auto ai = new llvm::AllocaInst(
|
auto ai = new llvm::AllocaInst(
|
||||||
lltype, gIR->module.getDataLayout().getAllocaAddrSpace(),
|
lltype, gIR->module.getDataLayout().getAllocaAddrSpace(),
|
||||||
DtoConstUint(arraysize), name, gIR->topallocapoint());
|
DtoConstUint(arraysize), name, gIR->topallocapoint());
|
||||||
ai->setAlignment(LLMaybeAlign(DtoAlignment(type)));
|
if (auto alignment = DtoAlignment(type)) {
|
||||||
|
ai->setAlignment(LLAlign(alignment));
|
||||||
|
}
|
||||||
return ai;
|
return ai;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +192,7 @@ llvm::AllocaInst *DtoRawAlloca(LLType *lltype, size_t alignment,
|
||||||
lltype, gIR->module.getDataLayout().getAllocaAddrSpace(), name,
|
lltype, gIR->module.getDataLayout().getAllocaAddrSpace(), name,
|
||||||
gIR->topallocapoint());
|
gIR->topallocapoint());
|
||||||
if (alignment) {
|
if (alignment) {
|
||||||
ai->setAlignment(LLMaybeAlign(alignment));
|
ai->setAlignment(LLAlign(alignment));
|
||||||
}
|
}
|
||||||
return ai;
|
return ai;
|
||||||
}
|
}
|
||||||
|
@ -201,7 +203,7 @@ LLValue *DtoGcMalloc(Loc &loc, LLType *lltype, const char *name) {
|
||||||
// parameters
|
// parameters
|
||||||
LLValue *size = DtoConstSize_t(getTypeAllocSize(lltype));
|
LLValue *size = DtoConstSize_t(getTypeAllocSize(lltype));
|
||||||
// call runtime allocator
|
// call runtime allocator
|
||||||
LLValue *mem = gIR->CreateCallOrInvoke(fn, size, name).getInstruction();
|
LLValue *mem = gIR->CreateCallOrInvoke(fn, size, name);
|
||||||
// cast
|
// cast
|
||||||
return DtoBitCast(mem, getPtrToType(lltype), name);
|
return DtoBitCast(mem, getPtrToType(lltype), name);
|
||||||
}
|
}
|
||||||
|
@ -632,8 +634,7 @@ DValue *DtoCastVector(Loc &loc, DValue *val, Type *to) {
|
||||||
LLValue *vector = DtoRVal(val);
|
LLValue *vector = DtoRVal(val);
|
||||||
IF_LOG Logger::cout() << "src: " << *vector << " to type: " << *tolltype
|
IF_LOG Logger::cout() << "src: " << *vector << " to type: " << *tolltype
|
||||||
<< " (creating temporary)\n";
|
<< " (creating temporary)\n";
|
||||||
LLValue *array = DtoAlloca(to);
|
LLValue *array = DtoAllocaDump(vector, tolltype, DtoAlignment(val->type));
|
||||||
DtoStore(vector, DtoBitCast(array, getPtrToType(vector->getType())));
|
|
||||||
return new DLValue(to, array);
|
return new DLValue(to, array);
|
||||||
}
|
}
|
||||||
if (totype->ty == Tvector && to->size() == val->type->size()) {
|
if (totype->ty == Tvector && to->size() == val->type->size()) {
|
||||||
|
@ -1228,7 +1229,12 @@ LLConstant *DtoConstExpInit(Loc &loc, Type *targetType, Expression *exp) {
|
||||||
assert(tv->basetype->ty == Tsarray);
|
assert(tv->basetype->ty == Tsarray);
|
||||||
dinteger_t elemCount =
|
dinteger_t elemCount =
|
||||||
static_cast<TypeSArray *>(tv->basetype)->dim->toInteger();
|
static_cast<TypeSArray *>(tv->basetype)->dim->toInteger();
|
||||||
return llvm::ConstantVector::getSplat(elemCount, val);
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
const auto elementCount = llvm::ElementCount(elemCount, false);
|
||||||
|
#else
|
||||||
|
const auto elementCount = elemCount;
|
||||||
|
#endif
|
||||||
|
return llvm::ConstantVector::getSplat(elementCount, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (llType->isIntegerTy() && targetLLType->isIntegerTy()) {
|
if (llType->isIntegerTy() && targetLLType->isIntegerTy()) {
|
||||||
|
@ -1307,9 +1313,14 @@ static char *DtoOverloadedIntrinsicName(TemplateInstance *ti,
|
||||||
if (dtype->isPPC_FP128Ty()) { // special case
|
if (dtype->isPPC_FP128Ty()) { // special case
|
||||||
replacement = "ppcf128";
|
replacement = "ppcf128";
|
||||||
} else if (dtype->isVectorTy()) {
|
} else if (dtype->isVectorTy()) {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
auto vectorType = llvm::cast<llvm::FixedVectorType>(dtype);
|
||||||
|
#else
|
||||||
|
auto vectorType = llvm::cast<llvm::VectorType>(dtype);
|
||||||
|
#endif
|
||||||
llvm::raw_string_ostream stream(replacement);
|
llvm::raw_string_ostream stream(replacement);
|
||||||
stream << 'v' << dtype->getVectorNumElements() << prefix
|
stream << 'v' << vectorType->getNumElements() << prefix
|
||||||
<< gDataLayout->getTypeSizeInBits(dtype->getVectorElementType());
|
<< gDataLayout->getTypeSizeInBits(vectorType->getElementType());
|
||||||
stream.flush();
|
stream.flush();
|
||||||
} else {
|
} else {
|
||||||
replacement = prefix + std::to_string(gDataLayout->getTypeSizeInBits(dtype));
|
replacement = prefix + std::to_string(gDataLayout->getTypeSizeInBits(dtype));
|
||||||
|
|
|
@ -131,14 +131,14 @@ bool willCrossModuleInline() {
|
||||||
return enableCrossModuleInlining == llvm::cl::BOU_TRUE;
|
return enableCrossModuleInlining == llvm::cl::BOU_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LDC_LLVM_VER >= 800
|
#if LDC_LLVM_VER >= 800 && LDC_LLVM_VER < 1000
|
||||||
llvm::FramePointer::FP whichFramePointersToEmit() {
|
llvm::FramePointer::FP whichFramePointersToEmit() {
|
||||||
if (auto option = opts::framePointerUsage())
|
if (auto option = opts::framePointerUsage())
|
||||||
return *option;
|
return *option;
|
||||||
return isOptimizationEnabled() ? llvm::FramePointer::None
|
return isOptimizationEnabled() ? llvm::FramePointer::None
|
||||||
: llvm::FramePointer::All;
|
: llvm::FramePointer::All;
|
||||||
}
|
}
|
||||||
#else
|
#elif LDC_LLVM_VER < 800
|
||||||
bool willEliminateFramePointer() {
|
bool willEliminateFramePointer() {
|
||||||
const llvm::cl::boolOrDefault disableFPElimEnum = opts::disableFPElim();
|
const llvm::cl::boolOrDefault disableFPElimEnum = opts::disableFPElim();
|
||||||
return disableFPElimEnum == llvm::cl::BOU_FALSE ||
|
return disableFPElimEnum == llvm::cl::BOU_FALSE ||
|
||||||
|
|
|
@ -34,9 +34,9 @@ bool willInline();
|
||||||
|
|
||||||
bool willCrossModuleInline();
|
bool willCrossModuleInline();
|
||||||
|
|
||||||
#if LDC_LLVM_VER >= 800
|
#if LDC_LLVM_VER >= 800 && LDC_LLVM_VER < 1000
|
||||||
llvm::FramePointer::FP whichFramePointersToEmit();
|
llvm::FramePointer::FP whichFramePointersToEmit();
|
||||||
#else
|
#elif LDC_LLVM_VER < 800
|
||||||
bool willEliminateFramePointer();
|
bool willEliminateFramePointer();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringMap.h"
|
||||||
#include "llvm/IR/CallSite.h"
|
|
||||||
#include "llvm/IR/Constants.h"
|
#include "llvm/IR/Constants.h"
|
||||||
#include "llvm/IR/DataLayout.h"
|
#include "llvm/IR/DataLayout.h"
|
||||||
#include "llvm/IR/Dominators.h"
|
#include "llvm/IR/Dominators.h"
|
||||||
|
@ -115,14 +114,14 @@ public:
|
||||||
|
|
||||||
// Analyze the current call, filling in some fields. Returns true if
|
// Analyze the current call, filling in some fields. Returns true if
|
||||||
// this is an allocation we can stack-allocate.
|
// this is an allocation we can stack-allocate.
|
||||||
virtual bool analyze(CallSite CS, const Analysis &A) = 0;
|
virtual bool analyze(LLCallBasePtr CB, const Analysis &A) = 0;
|
||||||
|
|
||||||
// Returns the alloca to replace this call.
|
// Returns the alloca to replace this call.
|
||||||
// It will always be inserted before the call.
|
// It will always be inserted before the call.
|
||||||
virtual Value *promote(CallSite CS, IRBuilder<> &B, const Analysis &A) {
|
virtual Value *promote(LLCallBasePtr CB, IRBuilder<> &B, const Analysis &A) {
|
||||||
NumGcToStack++;
|
NumGcToStack++;
|
||||||
|
|
||||||
auto &BB = CS.getCaller()->getEntryBlock();
|
auto &BB = CB->getCaller()->getEntryBlock();
|
||||||
Instruction *Begin = &(*BB.begin());
|
Instruction *Begin = &(*BB.begin());
|
||||||
|
|
||||||
// FIXME: set alignment on alloca?
|
// FIXME: set alignment on alloca?
|
||||||
|
@ -167,8 +166,8 @@ public:
|
||||||
TypeInfoFI(ReturnType::Type returnType, unsigned tiArgNr)
|
TypeInfoFI(ReturnType::Type returnType, unsigned tiArgNr)
|
||||||
: FunctionInfo(returnType), TypeInfoArgNr(tiArgNr) {}
|
: FunctionInfo(returnType), TypeInfoArgNr(tiArgNr) {}
|
||||||
|
|
||||||
bool analyze(CallSite CS, const Analysis &A) override {
|
bool analyze(LLCallBasePtr CB, const Analysis &A) override {
|
||||||
Value *TypeInfo = CS.getArgument(TypeInfoArgNr);
|
Value *TypeInfo = CB->getArgOperand(TypeInfoArgNr);
|
||||||
Ty = A.getTypeFor(TypeInfo);
|
Ty = A.getTypeFor(TypeInfo);
|
||||||
if (!Ty) {
|
if (!Ty) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -188,12 +187,12 @@ public:
|
||||||
: TypeInfoFI(returnType, tiArgNr), ArrSizeArgNr(arrSizeArgNr),
|
: TypeInfoFI(returnType, tiArgNr), ArrSizeArgNr(arrSizeArgNr),
|
||||||
Initialized(initialized) {}
|
Initialized(initialized) {}
|
||||||
|
|
||||||
bool analyze(CallSite CS, const Analysis &A) override {
|
bool analyze(LLCallBasePtr CB, const Analysis &A) override {
|
||||||
if (!TypeInfoFI::analyze(CS, A)) {
|
if (!TypeInfoFI::analyze(CB, A)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
arrSize = CS.getArgument(ArrSizeArgNr);
|
arrSize = CB->getArgOperand(ArrSizeArgNr);
|
||||||
|
|
||||||
// Extract the element type from the array type.
|
// Extract the element type from the array type.
|
||||||
const StructType *ArrTy = dyn_cast<StructType>(Ty);
|
const StructType *ArrTy = dyn_cast<StructType>(Ty);
|
||||||
|
@ -217,17 +216,17 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value *promote(CallSite CS, IRBuilder<> &B, const Analysis &A) override {
|
Value *promote(LLCallBasePtr CB, IRBuilder<> &B, const Analysis &A) override {
|
||||||
IRBuilder<> Builder = B;
|
|
||||||
// If the allocation is of constant size it's best to put it in the
|
// If the allocation is of constant size it's best to put it in the
|
||||||
// entry block, so do so if we're not already there.
|
// entry block, so do so if we're not already there.
|
||||||
// For dynamically-sized allocations it's best to avoid the overhead
|
// For dynamically-sized allocations it's best to avoid the overhead
|
||||||
// of allocating them if possible, so leave those where they are.
|
// of allocating them if possible, so leave those where they are.
|
||||||
// While we're at it, update statistics too.
|
// While we're at it, update statistics too.
|
||||||
|
const IRBuilderBase::InsertPointGuard savedInsertPoint(B);
|
||||||
if (isa<Constant>(arrSize)) {
|
if (isa<Constant>(arrSize)) {
|
||||||
BasicBlock &Entry = CS.getCaller()->getEntryBlock();
|
BasicBlock &Entry = CB->getCaller()->getEntryBlock();
|
||||||
if (Builder.GetInsertBlock() != &Entry) {
|
if (B.GetInsertBlock() != &Entry) {
|
||||||
Builder.SetInsertPoint(&Entry, Entry.begin());
|
B.SetInsertPoint(&Entry, Entry.begin());
|
||||||
}
|
}
|
||||||
NumGcToStack++;
|
NumGcToStack++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -235,9 +234,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert array size to 32 bits if necessary
|
// Convert array size to 32 bits if necessary
|
||||||
Value *count = Builder.CreateIntCast(arrSize, Builder.getInt32Ty(), false);
|
Value *count = B.CreateIntCast(arrSize, B.getInt32Ty(), false);
|
||||||
AllocaInst *alloca =
|
AllocaInst *alloca =
|
||||||
Builder.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align?
|
B.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align?
|
||||||
|
|
||||||
if (Initialized) {
|
if (Initialized) {
|
||||||
// For now, only zero-init is supported.
|
// For now, only zero-init is supported.
|
||||||
|
@ -250,11 +249,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ReturnType == ReturnType::Array) {
|
if (ReturnType == ReturnType::Array) {
|
||||||
Value *arrStruct = llvm::UndefValue::get(CS.getType());
|
Value *arrStruct = llvm::UndefValue::get(CB->getType());
|
||||||
arrStruct = Builder.CreateInsertValue(arrStruct, arrSize, 0);
|
arrStruct = B.CreateInsertValue(arrStruct, arrSize, 0);
|
||||||
Value *memPtr =
|
Value *memPtr =
|
||||||
Builder.CreateBitCast(alloca, PointerType::getUnqual(B.getInt8Ty()));
|
B.CreateBitCast(alloca, PointerType::getUnqual(B.getInt8Ty()));
|
||||||
arrStruct = Builder.CreateInsertValue(arrStruct, memPtr, 1);
|
arrStruct = B.CreateInsertValue(arrStruct, memPtr, 1);
|
||||||
return arrStruct;
|
return arrStruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,11 +264,11 @@ public:
|
||||||
// FunctionInfo for _d_allocclass
|
// FunctionInfo for _d_allocclass
|
||||||
class AllocClassFI : public FunctionInfo {
|
class AllocClassFI : public FunctionInfo {
|
||||||
public:
|
public:
|
||||||
bool analyze(CallSite CS, const Analysis &A) override {
|
bool analyze(LLCallBasePtr CB, const Analysis &A) override {
|
||||||
if (CS.arg_size() != 1) {
|
if (CB->arg_size() != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Value *arg = CS.getArgument(0)->stripPointerCasts();
|
Value *arg = CB->getArgOperand(0)->stripPointerCasts();
|
||||||
GlobalVariable *ClassInfo = dyn_cast<GlobalVariable>(arg);
|
GlobalVariable *ClassInfo = dyn_cast<GlobalVariable>(arg);
|
||||||
if (!ClassInfo) {
|
if (!ClassInfo) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -322,12 +321,12 @@ class UntypedMemoryFI : public FunctionInfo {
|
||||||
Value *SizeArg;
|
Value *SizeArg;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool analyze(CallSite CS, const Analysis &A) override {
|
bool analyze(LLCallBasePtr CB, const Analysis &A) override {
|
||||||
if (CS.arg_size() < SizeArgNr + 1) {
|
if (CB->arg_size() < SizeArgNr + 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SizeArg = CS.getArgument(SizeArgNr);
|
SizeArg = CB->getArgOperand(SizeArgNr);
|
||||||
|
|
||||||
// If the user explicitly disabled the limits, don't even check
|
// If the user explicitly disabled the limits, don't even check
|
||||||
// whether the allocated size fits in 32 bits. This could cause
|
// whether the allocated size fits in 32 bits. This could cause
|
||||||
|
@ -341,21 +340,21 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should be i8.
|
// Should be i8.
|
||||||
Ty = CS.getType()->getContainedType(0);
|
Ty = CB->getType()->getContainedType(0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value *promote(CallSite CS, IRBuilder<> &B, const Analysis &A) override {
|
Value *promote(LLCallBasePtr CB, IRBuilder<> &B, const Analysis &A) override {
|
||||||
IRBuilder<> Builder = B;
|
|
||||||
// If the allocation is of constant size it's best to put it in the
|
// If the allocation is of constant size it's best to put it in the
|
||||||
// entry block, so do so if we're not already there.
|
// entry block, so do so if we're not already there.
|
||||||
// For dynamically-sized allocations it's best to avoid the overhead
|
// For dynamically-sized allocations it's best to avoid the overhead
|
||||||
// of allocating them if possible, so leave those where they are.
|
// of allocating them if possible, so leave those where they are.
|
||||||
// While we're at it, update statistics too.
|
// While we're at it, update statistics too.
|
||||||
|
const IRBuilderBase::InsertPointGuard savedInsertPoint(B);
|
||||||
if (isa<Constant>(SizeArg)) {
|
if (isa<Constant>(SizeArg)) {
|
||||||
BasicBlock &Entry = CS.getCaller()->getEntryBlock();
|
BasicBlock &Entry = CB->getCaller()->getEntryBlock();
|
||||||
if (Builder.GetInsertBlock() != &Entry) {
|
if (B.GetInsertBlock() != &Entry) {
|
||||||
Builder.SetInsertPoint(&Entry, Entry.begin());
|
B.SetInsertPoint(&Entry, Entry.begin());
|
||||||
}
|
}
|
||||||
NumGcToStack++;
|
NumGcToStack++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -363,11 +362,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert array size to 32 bits if necessary
|
// Convert array size to 32 bits if necessary
|
||||||
Value *count = Builder.CreateIntCast(SizeArg, Builder.getInt32Ty(), false);
|
Value *count = B.CreateIntCast(SizeArg, B.getInt32Ty(), false);
|
||||||
AllocaInst *alloca =
|
AllocaInst *alloca =
|
||||||
Builder.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align?
|
B.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align?
|
||||||
|
|
||||||
return Builder.CreateBitCast(alloca, CS.getType());
|
return B.CreateBitCast(alloca, CB->getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit UntypedMemoryFI(unsigned sizeArgNr)
|
explicit UntypedMemoryFI(unsigned sizeArgNr)
|
||||||
|
@ -430,26 +429,24 @@ GarbageCollect2Stack::GarbageCollect2Stack()
|
||||||
KnownFunctions["_d_allocmemory"] = &AllocMemory;
|
KnownFunctions["_d_allocmemory"] = &AllocMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RemoveCall(CallSite CS, const Analysis &A) {
|
static void RemoveCall(LLCallBasePtr CB, const Analysis &A) {
|
||||||
// For an invoke instruction, we insert a branch to the normal target BB
|
// For an invoke instruction, we insert a branch to the normal target BB
|
||||||
// immediately before it. Ideally, we would find a way to not invalidate
|
// immediately before it. Ideally, we would find a way to not invalidate
|
||||||
// the dominator tree here.
|
// the dominator tree here.
|
||||||
if (CS.isInvoke()) {
|
if (auto Invoke = dyn_cast<InvokeInst>(static_cast<Instruction *>(CB))) {
|
||||||
InvokeInst *Invoke = cast<InvokeInst>(CS.getInstruction());
|
|
||||||
|
|
||||||
BranchInst::Create(Invoke->getNormalDest(), Invoke);
|
BranchInst::Create(Invoke->getNormalDest(), Invoke);
|
||||||
Invoke->getUnwindDest()->removePredecessor(CS->getParent());
|
Invoke->getUnwindDest()->removePredecessor(CB->getParent());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the runtime call.
|
// Remove the runtime call.
|
||||||
if (A.CGNode) {
|
if (A.CGNode) {
|
||||||
#if LDC_LLVM_VER >= 900
|
#if LDC_LLVM_VER >= 900
|
||||||
A.CGNode->removeCallEdgeFor(*cast<CallBase>(CS.getInstruction()));
|
A.CGNode->removeCallEdgeFor(*CB);
|
||||||
#else
|
#else
|
||||||
A.CGNode->removeCallEdgeFor(CS);
|
A.CGNode->removeCallEdgeFor(CB);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
CS->eraseFromParent();
|
static_cast<Instruction *>(CB)->eraseFromParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -483,13 +480,20 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
|
||||||
|
|
||||||
// Ignore non-calls.
|
// Ignore non-calls.
|
||||||
Instruction *Inst = &(*(I++));
|
Instruction *Inst = &(*(I++));
|
||||||
CallSite CS(Inst);
|
#if LDC_LLVM_VER >= 800
|
||||||
if (!CS.getInstruction()) {
|
auto CB = dyn_cast<CallBase>(Inst);
|
||||||
|
if (!CB) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
LLCallBasePtr CB(Inst);
|
||||||
|
if (!CB->getInstruction()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Ignore indirect calls and calls to non-external functions.
|
// Ignore indirect calls and calls to non-external functions.
|
||||||
Function *Callee = CS.getCalledFunction();
|
Function *Callee = CB->getCalledFunction();
|
||||||
if (Callee == nullptr || !Callee->isDeclaration() ||
|
if (Callee == nullptr || !Callee->isDeclaration() ||
|
||||||
!Callee->hasExternalLinkage()) {
|
!Callee->hasExternalLinkage()) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -503,16 +507,16 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
|
||||||
|
|
||||||
FunctionInfo *info = OMI->getValue();
|
FunctionInfo *info = OMI->getValue();
|
||||||
|
|
||||||
if (Inst->use_empty()) {
|
if (static_cast<Instruction *>(CB)->use_empty()) {
|
||||||
Changed = true;
|
Changed = true;
|
||||||
NumDeleted++;
|
NumDeleted++;
|
||||||
RemoveCall(CS, A);
|
RemoveCall(CB, A);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVM_DEBUG(errs() << "GarbageCollect2Stack inspecting: " << *Inst);
|
LLVM_DEBUG(errs() << "GarbageCollect2Stack inspecting: " << *CB);
|
||||||
|
|
||||||
if (!info->analyze(CS, A)) {
|
if (!info->analyze(CB, A)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,7 +526,7 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!isSafeToStackAllocate(originalI, Inst, DT, RemoveTailCallInsts)) {
|
if (!isSafeToStackAllocate(originalI, CB, DT, RemoveTailCallInsts)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -537,18 +541,18 @@ bool GarbageCollect2Stack::runOnFunction(Function &F) {
|
||||||
}
|
}
|
||||||
|
|
||||||
IRBuilder<> Builder(&BB, originalI);
|
IRBuilder<> Builder(&BB, originalI);
|
||||||
Value *newVal = info->promote(CS, Builder, A);
|
Value *newVal = info->promote(CB, Builder, A);
|
||||||
|
|
||||||
LLVM_DEBUG(errs() << "Promoted to: " << *newVal);
|
LLVM_DEBUG(errs() << "Promoted to: " << *newVal);
|
||||||
|
|
||||||
// Make sure the type is the same as it was before, and replace all
|
// Make sure the type is the same as it was before, and replace all
|
||||||
// uses of the runtime call with the alloca.
|
// uses of the runtime call with the alloca.
|
||||||
if (newVal->getType() != Inst->getType()) {
|
if (newVal->getType() != CB->getType()) {
|
||||||
newVal = Builder.CreateBitCast(newVal, Inst->getType());
|
newVal = Builder.CreateBitCast(newVal, CB->getType());
|
||||||
}
|
}
|
||||||
Inst->replaceAllUsesWith(newVal);
|
static_cast<Instruction *>(CB)->replaceAllUsesWith(newVal);
|
||||||
|
|
||||||
RemoveCall(CS, A);
|
RemoveCall(CB, A);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -818,11 +822,15 @@ bool isSafeToStackAllocate(BasicBlock::iterator Alloc, Value *V,
|
||||||
switch (I->getOpcode()) {
|
switch (I->getOpcode()) {
|
||||||
case Instruction::Call:
|
case Instruction::Call:
|
||||||
case Instruction::Invoke: {
|
case Instruction::Invoke: {
|
||||||
CallSite CS(I);
|
#if LDC_LLVM_VER >= 800
|
||||||
|
auto CB = llvm::cast<CallBase>(I);
|
||||||
|
#else
|
||||||
|
LLCallBasePtr CB(I);
|
||||||
|
#endif
|
||||||
// Not captured if the callee is readonly, doesn't return a copy through
|
// Not captured if the callee is readonly, doesn't return a copy through
|
||||||
// its return value and doesn't unwind (a readonly function can leak bits
|
// its return value and doesn't unwind (a readonly function can leak bits
|
||||||
// by throwing an exception or not depending on the input value).
|
// by throwing an exception or not depending on the input value).
|
||||||
if (CS.onlyReadsMemory() && CS.doesNotThrow() &&
|
if (CB->onlyReadsMemory() && CB->doesNotThrow() &&
|
||||||
I->getType() == llvm::Type::getVoidTy(I->getContext())) {
|
I->getType() == llvm::Type::getVoidTy(I->getContext())) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -834,18 +842,17 @@ bool isSafeToStackAllocate(BasicBlock::iterator Alloc, Value *V,
|
||||||
// that loading a value from a pointer does not cause the pointer to be
|
// that loading a value from a pointer does not cause the pointer to be
|
||||||
// captured, even though the loaded value might be the pointer itself
|
// captured, even though the loaded value might be the pointer itself
|
||||||
// (think of self-referential objects).
|
// (think of self-referential objects).
|
||||||
CallSite::arg_iterator B = CS.arg_begin(), E = CS.arg_end();
|
auto B = CB->arg_begin(), E = CB->arg_end();
|
||||||
for (CallSite::arg_iterator A = B; A != E; ++A) {
|
for (auto A = B; A != E; ++A) {
|
||||||
if (A->get() == V) {
|
if (A->get() == V) {
|
||||||
if (!CS.paramHasAttr(A - B, llvm::Attribute::AttrKind::NoCapture)) {
|
if (!CB->paramHasAttr(A - B, llvm::Attribute::AttrKind::NoCapture)) {
|
||||||
// The parameter is not marked 'nocapture' - captured.
|
// The parameter is not marked 'nocapture' - captured.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CS.isCall()) {
|
if (auto call = dyn_cast<CallInst>(static_cast<Instruction *>(CB))) {
|
||||||
CallInst *CI = cast<CallInst>(I);
|
if (call->isTailCall()) {
|
||||||
if (CI->isTailCall()) {
|
RemoveTailCallInsts.push_back(call);
|
||||||
RemoveTailCallInsts.push_back(CI);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,7 +276,7 @@ public:
|
||||||
// Pop the cleanups pushed during evaluation of the return expression.
|
// Pop the cleanups pushed during evaluation of the return expression.
|
||||||
funcGen.scopes.popCleanups(cleanupScopeBeforeExpression);
|
funcGen.scopes.popCleanups(cleanupScopeBeforeExpression);
|
||||||
|
|
||||||
irs->scope() = IRScope(funcGen.retBlock);
|
irs->ir->SetInsertPoint(funcGen.retBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we need to emit the actual return instruction, do so.
|
// If we need to emit the actual return instruction, do so.
|
||||||
|
@ -299,7 +299,7 @@ public:
|
||||||
// Finally, create a new predecessor-less dummy bb as the current IRScope
|
// Finally, create a new predecessor-less dummy bb as the current IRScope
|
||||||
// to make sure we do not emit any extra instructions after the terminating
|
// to make sure we do not emit any extra instructions after the terminating
|
||||||
// instruction (ret or branch to return bb), which would be illegal IR.
|
// instruction (ret or branch to return bb), which would be illegal IR.
|
||||||
irs->scope() = IRScope(irs->insertBB("dummy.afterreturn"));
|
irs->ir->SetInsertPoint(irs->insertBB("dummy.afterreturn"));
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -426,7 +426,7 @@ public:
|
||||||
PGO.addBranchWeights(brinstr, brweights);
|
PGO.addBranchWeights(brinstr, brweights);
|
||||||
|
|
||||||
// replace current scope
|
// replace current scope
|
||||||
irs->scope() = IRScope(ifbb);
|
irs->ir->SetInsertPoint(ifbb);
|
||||||
|
|
||||||
// do scoped statements
|
// do scoped statements
|
||||||
|
|
||||||
|
@ -441,7 +441,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stmt->elsebody) {
|
if (stmt->elsebody) {
|
||||||
irs->scope() = IRScope(elsebb);
|
irs->ir->SetInsertPoint(elsebb);
|
||||||
irs->DBuilder.EmitBlockStart(stmt->elsebody->loc);
|
irs->DBuilder.EmitBlockStart(stmt->elsebody->loc);
|
||||||
stmt->elsebody->accept(this);
|
stmt->elsebody->accept(this);
|
||||||
if (!irs->scopereturned()) {
|
if (!irs->scopereturned()) {
|
||||||
|
@ -454,7 +454,7 @@ public:
|
||||||
irs->DBuilder.EmitBlockEnd();
|
irs->DBuilder.EmitBlockEnd();
|
||||||
|
|
||||||
// rewrite the scope
|
// rewrite the scope
|
||||||
irs->scope() = IRScope(endbb);
|
irs->ir->SetInsertPoint(endbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -495,7 +495,7 @@ public:
|
||||||
irs->ir->CreateBr(whilebb);
|
irs->ir->CreateBr(whilebb);
|
||||||
|
|
||||||
// replace current scope
|
// replace current scope
|
||||||
irs->scope() = IRScope(whilebb);
|
irs->ir->SetInsertPoint(whilebb);
|
||||||
|
|
||||||
// create the condition
|
// create the condition
|
||||||
emitCoverageLinecountInc(stmt->condition->loc);
|
emitCoverageLinecountInc(stmt->condition->loc);
|
||||||
|
@ -514,7 +514,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// rewrite scope
|
// rewrite scope
|
||||||
irs->scope() = IRScope(whilebodybb);
|
irs->ir->SetInsertPoint(whilebodybb);
|
||||||
|
|
||||||
// while body code
|
// while body code
|
||||||
irs->funcGen().jumpTargets.pushLoopTarget(stmt, whilebb, endbb);
|
irs->funcGen().jumpTargets.pushLoopTarget(stmt, whilebb, endbb);
|
||||||
|
@ -530,7 +530,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// rewrite the scope
|
// rewrite the scope
|
||||||
irs->scope() = IRScope(endbb);
|
irs->ir->SetInsertPoint(endbb);
|
||||||
|
|
||||||
// end the dwarf lexical block
|
// end the dwarf lexical block
|
||||||
irs->DBuilder.EmitBlockEnd();
|
irs->DBuilder.EmitBlockEnd();
|
||||||
|
@ -558,7 +558,7 @@ public:
|
||||||
llvm::BranchInst::Create(dowhilebb, irs->scopebb());
|
llvm::BranchInst::Create(dowhilebb, irs->scopebb());
|
||||||
|
|
||||||
// replace current scope
|
// replace current scope
|
||||||
irs->scope() = IRScope(dowhilebb);
|
irs->ir->SetInsertPoint(dowhilebb);
|
||||||
|
|
||||||
// do-while body code
|
// do-while body code
|
||||||
irs->funcGen().jumpTargets.pushLoopTarget(stmt, condbb, endbb);
|
irs->funcGen().jumpTargets.pushLoopTarget(stmt, condbb, endbb);
|
||||||
|
@ -570,7 +570,7 @@ public:
|
||||||
|
|
||||||
// branch to condition block
|
// branch to condition block
|
||||||
llvm::BranchInst::Create(condbb, irs->scopebb());
|
llvm::BranchInst::Create(condbb, irs->scopebb());
|
||||||
irs->scope() = IRScope(condbb);
|
irs->ir->SetInsertPoint(condbb);
|
||||||
|
|
||||||
// create the condition
|
// create the condition
|
||||||
emitCoverageLinecountInc(stmt->condition->loc);
|
emitCoverageLinecountInc(stmt->condition->loc);
|
||||||
|
@ -592,7 +592,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// rewrite the scope
|
// rewrite the scope
|
||||||
irs->scope() = IRScope(endbb);
|
irs->ir->SetInsertPoint(endbb);
|
||||||
|
|
||||||
// end the dwarf lexical block
|
// end the dwarf lexical block
|
||||||
irs->DBuilder.EmitBlockEnd();
|
irs->DBuilder.EmitBlockEnd();
|
||||||
|
@ -635,7 +635,7 @@ public:
|
||||||
irs->funcGen().jumpTargets.pushLoopTarget(scopeStart, forincbb, endbb);
|
irs->funcGen().jumpTargets.pushLoopTarget(scopeStart, forincbb, endbb);
|
||||||
|
|
||||||
// replace current scope
|
// replace current scope
|
||||||
irs->scope() = IRScope(forbb);
|
irs->ir->SetInsertPoint(forbb);
|
||||||
|
|
||||||
// create the condition
|
// create the condition
|
||||||
llvm::Value *cond_val;
|
llvm::Value *cond_val;
|
||||||
|
@ -658,7 +658,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// rewrite scope
|
// rewrite scope
|
||||||
irs->scope() = IRScope(forbodybb);
|
irs->ir->SetInsertPoint(forbodybb);
|
||||||
|
|
||||||
// do for body code
|
// do for body code
|
||||||
PGO.emitCounterIncrement(stmt);
|
PGO.emitCounterIncrement(stmt);
|
||||||
|
@ -670,7 +670,7 @@ public:
|
||||||
if (!irs->scopereturned()) {
|
if (!irs->scopereturned()) {
|
||||||
llvm::BranchInst::Create(forincbb, irs->scopebb());
|
llvm::BranchInst::Create(forincbb, irs->scopebb());
|
||||||
}
|
}
|
||||||
irs->scope() = IRScope(forincbb);
|
irs->ir->SetInsertPoint(forincbb);
|
||||||
|
|
||||||
// increment
|
// increment
|
||||||
if (stmt->increment) {
|
if (stmt->increment) {
|
||||||
|
@ -687,7 +687,7 @@ public:
|
||||||
irs->funcGen().jumpTargets.popLoopTarget();
|
irs->funcGen().jumpTargets.popLoopTarget();
|
||||||
|
|
||||||
// rewrite the scope
|
// rewrite the scope
|
||||||
irs->scope() = IRScope(endbb);
|
irs->ir->SetInsertPoint(endbb);
|
||||||
|
|
||||||
// end the dwarf lexical block
|
// end the dwarf lexical block
|
||||||
irs->DBuilder.EmitBlockEnd();
|
irs->DBuilder.EmitBlockEnd();
|
||||||
|
@ -731,7 +731,7 @@ public:
|
||||||
|
|
||||||
// the break terminated this basicblock, start a new one
|
// the break terminated this basicblock, start a new one
|
||||||
llvm::BasicBlock *bb = irs->insertBB("afterbreak");
|
llvm::BasicBlock *bb = irs->insertBB("afterbreak");
|
||||||
irs->scope() = IRScope(bb);
|
irs->ir->SetInsertPoint(bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -766,7 +766,7 @@ public:
|
||||||
|
|
||||||
// the continue terminated this basicblock, start a new one
|
// the continue terminated this basicblock, start a new one
|
||||||
llvm::BasicBlock *bb = irs->insertBB("aftercontinue");
|
llvm::BasicBlock *bb = irs->insertBB("aftercontinue");
|
||||||
irs->scope() = IRScope(bb);
|
irs->ir->SetInsertPoint(bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -818,7 +818,7 @@ public:
|
||||||
: irs->insertBBAfter(finallybb, "try.success");
|
: irs->insertBBAfter(finallybb, "try.success");
|
||||||
|
|
||||||
// Emit the finally block and set up the cleanup scope for it.
|
// Emit the finally block and set up the cleanup scope for it.
|
||||||
irs->scope() = IRScope(finallybb);
|
irs->ir->SetInsertPoint(finallybb);
|
||||||
irs->DBuilder.EmitBlockStart(stmt->finalbody->loc);
|
irs->DBuilder.EmitBlockStart(stmt->finalbody->loc);
|
||||||
stmt->finalbody->accept(this);
|
stmt->finalbody->accept(this);
|
||||||
irs->DBuilder.EmitBlockEnd();
|
irs->DBuilder.EmitBlockEnd();
|
||||||
|
@ -832,7 +832,7 @@ public:
|
||||||
irs->funcGen().scopes.pushCleanup(finallybb, irs->scopebb());
|
irs->funcGen().scopes.pushCleanup(finallybb, irs->scopebb());
|
||||||
}
|
}
|
||||||
// Emit the try block.
|
// Emit the try block.
|
||||||
irs->scope() = IRScope(trybb);
|
irs->ir->SetInsertPoint(trybb);
|
||||||
|
|
||||||
assert(stmt->_body);
|
assert(stmt->_body);
|
||||||
irs->DBuilder.EmitBlockStart(stmt->_body->loc);
|
irs->DBuilder.EmitBlockStart(stmt->_body->loc);
|
||||||
|
@ -842,7 +842,7 @@ public:
|
||||||
if (successbb) {
|
if (successbb) {
|
||||||
if (!computeCode)
|
if (!computeCode)
|
||||||
irs->funcGen().scopes.runCleanups(cleanupBefore, successbb);
|
irs->funcGen().scopes.runCleanups(cleanupBefore, successbb);
|
||||||
irs->scope() = IRScope(successbb);
|
irs->ir->SetInsertPoint(successbb);
|
||||||
// PGO counter tracks the continuation of the try-finally statement
|
// PGO counter tracks the continuation of the try-finally statement
|
||||||
PGO.emitCounterIncrement(stmt);
|
PGO.emitCounterIncrement(stmt);
|
||||||
}
|
}
|
||||||
|
@ -874,7 +874,7 @@ public:
|
||||||
irs->funcGen().scopes.pushTryCatch(stmt, endbb);
|
irs->funcGen().scopes.pushTryCatch(stmt, endbb);
|
||||||
|
|
||||||
// Emit the try block.
|
// Emit the try block.
|
||||||
irs->scope() = IRScope(trybb);
|
irs->ir->SetInsertPoint(trybb);
|
||||||
|
|
||||||
assert(stmt->_body);
|
assert(stmt->_body);
|
||||||
irs->DBuilder.EmitBlockStart(stmt->_body->loc);
|
irs->DBuilder.EmitBlockStart(stmt->_body->loc);
|
||||||
|
@ -886,7 +886,7 @@ public:
|
||||||
|
|
||||||
irs->funcGen().scopes.popTryCatch();
|
irs->funcGen().scopes.popTryCatch();
|
||||||
|
|
||||||
irs->scope() = IRScope(endbb);
|
irs->ir->SetInsertPoint(endbb);
|
||||||
|
|
||||||
// PGO counter tracks the continuation of the try statement
|
// PGO counter tracks the continuation of the try statement
|
||||||
PGO.emitCounterIncrement(stmt);
|
PGO.emitCounterIncrement(stmt);
|
||||||
|
@ -920,7 +920,7 @@ public:
|
||||||
|
|
||||||
// TODO: Should not be needed.
|
// TODO: Should not be needed.
|
||||||
llvm::BasicBlock *bb = irs->insertBB("afterthrow");
|
llvm::BasicBlock *bb = irs->insertBB("afterthrow");
|
||||||
irs->scope() = IRScope(bb);
|
irs->ir->SetInsertPoint(bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -986,7 +986,7 @@ public:
|
||||||
|
|
||||||
// do switch body
|
// do switch body
|
||||||
assert(stmt->_body);
|
assert(stmt->_body);
|
||||||
irs->scope() = IRScope(bodybb);
|
irs->ir->SetInsertPoint(bodybb);
|
||||||
funcGen.jumpTargets.pushBreakTarget(stmt, endbb);
|
funcGen.jumpTargets.pushBreakTarget(stmt, endbb);
|
||||||
stmt->_body->accept(this);
|
stmt->_body->accept(this);
|
||||||
funcGen.jumpTargets.popBreakTarget();
|
funcGen.jumpTargets.popBreakTarget();
|
||||||
|
@ -994,7 +994,7 @@ public:
|
||||||
llvm::BranchInst::Create(endbb, irs->scopebb());
|
llvm::BranchInst::Create(endbb, irs->scopebb());
|
||||||
}
|
}
|
||||||
|
|
||||||
irs->scope() = IRScope(oldbb);
|
irs->ir->SetInsertPoint(oldbb);
|
||||||
if (useSwitchInst) {
|
if (useSwitchInst) {
|
||||||
// The case index value.
|
// The case index value.
|
||||||
LLValue *condVal = DtoRVal(toElemDtor(stmt->condition));
|
LLValue *condVal = DtoRVal(toElemDtor(stmt->condition));
|
||||||
|
@ -1018,7 +1018,7 @@ public:
|
||||||
{
|
{
|
||||||
llvm::BasicBlock *defaultcntr =
|
llvm::BasicBlock *defaultcntr =
|
||||||
irs->insertBBBefore(defaultTargetBB, "defaultcntr");
|
irs->insertBBBefore(defaultTargetBB, "defaultcntr");
|
||||||
irs->scope() = IRScope(defaultcntr);
|
irs->ir->SetInsertPoint(defaultcntr);
|
||||||
if (stmt->sdefault)
|
if (stmt->sdefault)
|
||||||
PGO.emitCounterIncrement(stmt->sdefault);
|
PGO.emitCounterIncrement(stmt->sdefault);
|
||||||
llvm::BranchInst::Create(defaultTargetBB, defaultcntr);
|
llvm::BranchInst::Create(defaultTargetBB, defaultcntr);
|
||||||
|
@ -1033,7 +1033,7 @@ public:
|
||||||
const auto body = funcGen.switchTargets.get(cs);
|
const auto body = funcGen.switchTargets.get(cs);
|
||||||
|
|
||||||
auto casecntr = irs->insertBBBefore(body, "casecntr");
|
auto casecntr = irs->insertBBBefore(body, "casecntr");
|
||||||
irs->scope() = IRScope(casecntr);
|
irs->ir->SetInsertPoint(casecntr);
|
||||||
PGO.emitCounterIncrement(cs);
|
PGO.emitCounterIncrement(cs);
|
||||||
llvm::BranchInst::Create(body, casecntr);
|
llvm::BranchInst::Create(body, casecntr);
|
||||||
si->addCase(isaConstantInt(indices[i]), casecntr);
|
si->addCase(isaConstantInt(indices[i]), casecntr);
|
||||||
|
@ -1068,13 +1068,13 @@ public:
|
||||||
// Prepend extra BB to "default:" to increment profiling counter.
|
// Prepend extra BB to "default:" to increment profiling counter.
|
||||||
llvm::BasicBlock *defaultcntr =
|
llvm::BasicBlock *defaultcntr =
|
||||||
irs->insertBBBefore(defaultTargetBB, "defaultcntr");
|
irs->insertBBBefore(defaultTargetBB, "defaultcntr");
|
||||||
irs->scope() = IRScope(defaultcntr);
|
irs->ir->SetInsertPoint(defaultcntr);
|
||||||
PGO.emitCounterIncrement(stmt->sdefault);
|
PGO.emitCounterIncrement(stmt->sdefault);
|
||||||
llvm::BranchInst::Create(defaultTargetBB, defaultcntr);
|
llvm::BranchInst::Create(defaultTargetBB, defaultcntr);
|
||||||
defaultTargetBB = defaultcntr;
|
defaultTargetBB = defaultcntr;
|
||||||
}
|
}
|
||||||
|
|
||||||
irs->scope() = IRScope(nextbb);
|
irs->ir->SetInsertPoint(nextbb);
|
||||||
auto failedCompareCount = incomingPGORegionCount;
|
auto failedCompareCount = incomingPGORegionCount;
|
||||||
for (size_t i = 0; i < caseCount; ++i) {
|
for (size_t i = 0; i < caseCount; ++i) {
|
||||||
LLValue *cmp = irs->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ, indices[i],
|
LLValue *cmp = irs->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ, indices[i],
|
||||||
|
@ -1087,12 +1087,10 @@ public:
|
||||||
if (PGO.emitsInstrumentation()) {
|
if (PGO.emitsInstrumentation()) {
|
||||||
llvm::BasicBlock *casecntr =
|
llvm::BasicBlock *casecntr =
|
||||||
irs->insertBBBefore(casejumptargetbb, "casecntr");
|
irs->insertBBBefore(casejumptargetbb, "casecntr");
|
||||||
auto savedbb = irs->scope();
|
const auto savedInsertPoint = irs->saveInsertPoint();
|
||||||
irs->scope() = IRScope(casecntr);
|
irs->ir->SetInsertPoint(casecntr);
|
||||||
PGO.emitCounterIncrement(cs);
|
PGO.emitCounterIncrement(cs);
|
||||||
llvm::BranchInst::Create(casejumptargetbb, casecntr);
|
llvm::BranchInst::Create(casejumptargetbb, casecntr);
|
||||||
irs->scope() = savedbb;
|
|
||||||
|
|
||||||
casejumptargetbb = casecntr;
|
casejumptargetbb = casecntr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1111,13 +1109,13 @@ public:
|
||||||
PGO.addBranchWeights(branchinst, brweights);
|
PGO.addBranchWeights(branchinst, brweights);
|
||||||
}
|
}
|
||||||
|
|
||||||
irs->scope() = IRScope(nextbb);
|
irs->ir->SetInsertPoint(nextbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::BranchInst::Create(defaultTargetBB, irs->scopebb());
|
llvm::BranchInst::Create(defaultTargetBB, irs->scopebb());
|
||||||
}
|
}
|
||||||
|
|
||||||
irs->scope() = IRScope(endbb);
|
irs->ir->SetInsertPoint(endbb);
|
||||||
// PGO counter tracks exit point of switch statement:
|
// PGO counter tracks exit point of switch statement:
|
||||||
PGO.emitCounterIncrement(stmt);
|
PGO.emitCounterIncrement(stmt);
|
||||||
}
|
}
|
||||||
|
@ -1141,7 +1139,7 @@ public:
|
||||||
llvm::BranchInst::Create(body, irs->scopebb());
|
llvm::BranchInst::Create(body, irs->scopebb());
|
||||||
}
|
}
|
||||||
|
|
||||||
irs->scope() = IRScope(body);
|
irs->ir->SetInsertPoint(body);
|
||||||
|
|
||||||
assert(stmt->statement);
|
assert(stmt->statement);
|
||||||
irs->DBuilder.EmitBlockStart(stmt->statement->loc);
|
irs->DBuilder.EmitBlockStart(stmt->statement->loc);
|
||||||
|
@ -1172,7 +1170,7 @@ public:
|
||||||
llvm::BranchInst::Create(body, irs->scopebb());
|
llvm::BranchInst::Create(body, irs->scopebb());
|
||||||
}
|
}
|
||||||
|
|
||||||
irs->scope() = IRScope(body);
|
irs->ir->SetInsertPoint(body);
|
||||||
|
|
||||||
assert(stmt->statement);
|
assert(stmt->statement);
|
||||||
irs->DBuilder.EmitBlockStart(stmt->statement->loc);
|
irs->DBuilder.EmitBlockStart(stmt->statement->loc);
|
||||||
|
@ -1231,7 +1229,7 @@ public:
|
||||||
llvm::BasicBlock *nextbb = (i + 1 == nstmt) ? endbb : blocks[i + 1];
|
llvm::BasicBlock *nextbb = (i + 1 == nstmt) ? endbb : blocks[i + 1];
|
||||||
|
|
||||||
// update scope
|
// update scope
|
||||||
irs->scope() = IRScope(thisbb);
|
irs->ir->SetInsertPoint(thisbb);
|
||||||
|
|
||||||
// push loop scope
|
// push loop scope
|
||||||
// continue goes to next statement, break goes to end
|
// continue goes to next statement, break goes to end
|
||||||
|
@ -1251,7 +1249,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
irs->scope() = IRScope(endbb);
|
irs->ir->SetInsertPoint(endbb);
|
||||||
|
|
||||||
// PGO counter tracks the continuation after the loop
|
// PGO counter tracks the continuation after the loop
|
||||||
PGO.emitCounterIncrement(stmt);
|
PGO.emitCounterIncrement(stmt);
|
||||||
|
@ -1334,7 +1332,7 @@ public:
|
||||||
llvm::BranchInst::Create(condbb, irs->scopebb());
|
llvm::BranchInst::Create(condbb, irs->scopebb());
|
||||||
|
|
||||||
// condition
|
// condition
|
||||||
irs->scope() = IRScope(condbb);
|
irs->ir->SetInsertPoint(condbb);
|
||||||
|
|
||||||
LLValue *done = nullptr;
|
LLValue *done = nullptr;
|
||||||
LLValue *load = DtoLoad(keyvar);
|
LLValue *load = DtoLoad(keyvar);
|
||||||
|
@ -1353,7 +1351,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// init body
|
// init body
|
||||||
irs->scope() = IRScope(bodybb);
|
irs->ir->SetInsertPoint(bodybb);
|
||||||
PGO.emitCounterIncrement(stmt);
|
PGO.emitCounterIncrement(stmt);
|
||||||
|
|
||||||
// get value for this iteration
|
// get value for this iteration
|
||||||
|
@ -1383,7 +1381,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// next
|
// next
|
||||||
irs->scope() = IRScope(nextbb);
|
irs->ir->SetInsertPoint(nextbb);
|
||||||
if (stmt->op == TOKforeach) {
|
if (stmt->op == TOKforeach) {
|
||||||
LLValue *load = DtoLoad(keyvar);
|
LLValue *load = DtoLoad(keyvar);
|
||||||
load = irs->ir->CreateAdd(load, LLConstantInt::get(keytype, 1, false));
|
load = irs->ir->CreateAdd(load, LLConstantInt::get(keytype, 1, false));
|
||||||
|
@ -1395,7 +1393,7 @@ public:
|
||||||
irs->DBuilder.EmitBlockEnd();
|
irs->DBuilder.EmitBlockEnd();
|
||||||
|
|
||||||
// end
|
// end
|
||||||
irs->scope() = IRScope(endbb);
|
irs->ir->SetInsertPoint(endbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1438,7 +1436,7 @@ public:
|
||||||
llvm::BranchInst::Create(condbb, irs->scopebb());
|
llvm::BranchInst::Create(condbb, irs->scopebb());
|
||||||
|
|
||||||
// CONDITION
|
// CONDITION
|
||||||
irs->scope() = IRScope(condbb);
|
irs->ir->SetInsertPoint(condbb);
|
||||||
|
|
||||||
// first we test that lwr < upr
|
// first we test that lwr < upr
|
||||||
lower = DtoLoad(keyval);
|
lower = DtoLoad(keyval);
|
||||||
|
@ -1462,7 +1460,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// BODY
|
// BODY
|
||||||
irs->scope() = IRScope(bodybb);
|
irs->ir->SetInsertPoint(bodybb);
|
||||||
PGO.emitCounterIncrement(stmt);
|
PGO.emitCounterIncrement(stmt);
|
||||||
|
|
||||||
// reverse foreach decrements here
|
// reverse foreach decrements here
|
||||||
|
@ -1486,7 +1484,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEXT
|
// NEXT
|
||||||
irs->scope() = IRScope(nextbb);
|
irs->ir->SetInsertPoint(nextbb);
|
||||||
|
|
||||||
// forward foreach increments here
|
// forward foreach increments here
|
||||||
if (stmt->op == TOKforeach) {
|
if (stmt->op == TOKforeach) {
|
||||||
|
@ -1503,7 +1501,7 @@ public:
|
||||||
irs->DBuilder.EmitBlockEnd();
|
irs->DBuilder.EmitBlockEnd();
|
||||||
|
|
||||||
// END
|
// END
|
||||||
irs->scope() = IRScope(endbb);
|
irs->ir->SetInsertPoint(endbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1538,7 +1536,7 @@ public:
|
||||||
llvm::BranchInst::Create(labelBB, irs->scopebb());
|
llvm::BranchInst::Create(labelBB, irs->scopebb());
|
||||||
}
|
}
|
||||||
|
|
||||||
irs->scope() = IRScope(labelBB);
|
irs->ir->SetInsertPoint(labelBB);
|
||||||
}
|
}
|
||||||
|
|
||||||
PGO.emitCounterIncrement(stmt);
|
PGO.emitCounterIncrement(stmt);
|
||||||
|
@ -1565,7 +1563,7 @@ public:
|
||||||
|
|
||||||
// TODO: Should not be needed.
|
// TODO: Should not be needed.
|
||||||
llvm::BasicBlock *bb = irs->insertBB("aftergoto");
|
llvm::BasicBlock *bb = irs->insertBB("aftergoto");
|
||||||
irs->scope() = IRScope(bb);
|
irs->ir->SetInsertPoint(bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1590,7 +1588,7 @@ public:
|
||||||
|
|
||||||
// TODO: Should not be needed.
|
// TODO: Should not be needed.
|
||||||
llvm::BasicBlock *bb = irs->insertBB("aftergotodefault");
|
llvm::BasicBlock *bb = irs->insertBB("aftergotodefault");
|
||||||
irs->scope() = IRScope(bb);
|
irs->ir->SetInsertPoint(bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1616,7 +1614,7 @@ public:
|
||||||
|
|
||||||
// TODO: Should not be needed.
|
// TODO: Should not be needed.
|
||||||
llvm::BasicBlock *bb = irs->insertBB("aftergotocase");
|
llvm::BasicBlock *bb = irs->insertBB("aftergotocase");
|
||||||
irs->scope() = IRScope(bb);
|
irs->ir->SetInsertPoint(bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -405,7 +405,9 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
|
||||||
|
|
||||||
llvm::StoreInst *ret = p->ir->CreateStore(val, ptr);
|
llvm::StoreInst *ret = p->ir->CreateStore(val, ptr);
|
||||||
ret->setAtomic(llvm::AtomicOrdering(atomicOrdering));
|
ret->setAtomic(llvm::AtomicOrdering(atomicOrdering));
|
||||||
ret->setAlignment(LLMaybeAlign(getTypeAllocSize(val->getType())));
|
if (auto alignment = getTypeAllocSize(val->getType())) {
|
||||||
|
ret->setAlignment(LLAlign(alignment));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,7 +437,9 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e,
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::LoadInst *load = p->ir->CreateLoad(ptr);
|
llvm::LoadInst *load = p->ir->CreateLoad(ptr);
|
||||||
load->setAlignment(LLMaybeAlign(getTypeAllocSize(load->getType())));
|
if (auto alignment = getTypeAllocSize(load->getType())) {
|
||||||
|
load->setAlignment(LLAlign(alignment));
|
||||||
|
}
|
||||||
load->setAtomic(llvm::AtomicOrdering(atomicOrdering));
|
load->setAtomic(llvm::AtomicOrdering(atomicOrdering));
|
||||||
llvm::Value *val = load;
|
llvm::Value *val = load;
|
||||||
if (val->getType() != pointeeType) {
|
if (val->getType() != pointeeType) {
|
||||||
|
@ -868,21 +872,22 @@ DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
|
||||||
}
|
}
|
||||||
|
|
||||||
// call the function
|
// call the function
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(callable, args, "", tf->isnothrow());
|
LLCallBasePtr call = gIR->funcGen().callOrInvoke(callable, callableTy, args,
|
||||||
|
"", tf->isnothrow());
|
||||||
|
|
||||||
// PGO: Insert instrumentation or attach profile metadata at indirect call
|
// PGO: Insert instrumentation or attach profile metadata at indirect call
|
||||||
// sites.
|
// sites.
|
||||||
if (!call.getCalledFunction()) {
|
if (!call->getCalledFunction()) {
|
||||||
auto &PGO = gIR->funcGen().pgo;
|
auto &PGO = gIR->funcGen().pgo;
|
||||||
PGO.emitIndirectCallPGO(call.getInstruction(), callable);
|
PGO.emitIndirectCallPGO(call, callable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get return value
|
// get return value
|
||||||
const int sretArgIndex =
|
const int sretArgIndex =
|
||||||
(irFty.arg_sret && irFty.arg_this && gABI->passThisBeforeSret(tf) ? 1
|
(irFty.arg_sret && irFty.arg_this && gABI->passThisBeforeSret(tf) ? 1
|
||||||
: 0);
|
: 0);
|
||||||
LLValue *retllval =
|
LLValue *retllval = irFty.arg_sret ? args[sretArgIndex]
|
||||||
(irFty.arg_sret ? args[sretArgIndex] : call.getInstruction());
|
: static_cast<llvm::Instruction *>(call);
|
||||||
bool retValIsLVal =
|
bool retValIsLVal =
|
||||||
(tf->isref() && returnTy != Tvoid) || (irFty.arg_sret != nullptr);
|
(tf->isref() && returnTy != Tvoid) || (irFty.arg_sret != nullptr);
|
||||||
|
|
||||||
|
@ -1002,16 +1007,16 @@ DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
|
||||||
gIR->context(),
|
gIR->context(),
|
||||||
static_cast<llvm::Intrinsic::ID>(llfunc->getIntrinsicID()));
|
static_cast<llvm::Intrinsic::ID>(llfunc->getIntrinsicID()));
|
||||||
} else {
|
} else {
|
||||||
call.setCallingConv(callconv);
|
call->setCallingConv(callconv);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
call.setCallingConv(callconv);
|
call->setCallingConv(callconv);
|
||||||
}
|
}
|
||||||
// merge in function attributes set in callOrInvoke
|
// merge in function attributes set in callOrInvoke
|
||||||
attrlist = attrlist.addAttributes(
|
attrlist = attrlist.addAttributes(
|
||||||
gIR->context(), LLAttributeList::FunctionIndex,
|
gIR->context(), LLAttributeList::FunctionIndex,
|
||||||
llvm::AttrBuilder(call.getAttributes(), LLAttributeList::FunctionIndex));
|
llvm::AttrBuilder(call->getAttributes(), LLAttributeList::FunctionIndex));
|
||||||
call.setAttributes(attrlist);
|
call->setAttributes(attrlist);
|
||||||
|
|
||||||
// Special case for struct constructor calls: For temporaries, using the
|
// Special case for struct constructor calls: For temporaries, using the
|
||||||
// this pointer value returned from the constructor instead of the alloca
|
// this pointer value returned from the constructor instead of the alloca
|
||||||
|
|
|
@ -664,8 +664,13 @@ public:
|
||||||
// cast.
|
// cast.
|
||||||
// FIXME: Check DMD source to understand why two different ASTs are
|
// FIXME: Check DMD source to understand why two different ASTs are
|
||||||
// constructed.
|
// constructed.
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
const auto elementCount = llvm::ElementCount(elemCount, false);
|
||||||
|
#else
|
||||||
|
const auto elementCount = elemCount;
|
||||||
|
#endif
|
||||||
result = llvm::ConstantVector::getSplat(
|
result = llvm::ConstantVector::getSplat(
|
||||||
elemCount, toConstElem(e->e1->optimize(WANTvalue)));
|
elementCount, toConstElem(e->e1->optimize(WANTvalue)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
45
gen/toir.cpp
45
gen/toir.cpp
|
@ -187,12 +187,10 @@ namespace {
|
||||||
void pushVarDtorCleanup(IRState *p, VarDeclaration *vd) {
|
void pushVarDtorCleanup(IRState *p, VarDeclaration *vd) {
|
||||||
llvm::BasicBlock *beginBB = p->insertBB(llvm::Twine("dtor.") + vd->toChars());
|
llvm::BasicBlock *beginBB = p->insertBB(llvm::Twine("dtor.") + vd->toChars());
|
||||||
|
|
||||||
// TODO: Clean this up with push/pop insertion point methods.
|
const auto savedInsertPoint = p->saveInsertPoint();
|
||||||
IRScope oldScope = p->scope();
|
p->ir->SetInsertPoint(beginBB);
|
||||||
p->scope() = IRScope(beginBB);
|
|
||||||
toElemDtor(vd->edtor);
|
toElemDtor(vd->edtor);
|
||||||
p->funcGen().scopes.pushCleanup(beginBB, p->scopebb());
|
p->funcGen().scopes.pushCleanup(beginBB, p->scopebb());
|
||||||
p->scope() = oldScope;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +251,7 @@ public:
|
||||||
llvm::BasicBlock *endbb = p->insertBB("toElem.success");
|
llvm::BasicBlock *endbb = p->insertBB("toElem.success");
|
||||||
p->funcGen().scopes.runCleanups(initialCleanupScope, endbb);
|
p->funcGen().scopes.runCleanups(initialCleanupScope, endbb);
|
||||||
p->funcGen().scopes.popCleanups(initialCleanupScope);
|
p->funcGen().scopes.popCleanups(initialCleanupScope);
|
||||||
p->scope() = IRScope(endbb);
|
p->ir->SetInsertPoint(endbb);
|
||||||
|
|
||||||
destructTemporaries = false;
|
destructTemporaries = false;
|
||||||
}
|
}
|
||||||
|
@ -1146,10 +1144,10 @@ public:
|
||||||
|
|
||||||
p->ir->CreateCondBr(okCond, okbb, failbb);
|
p->ir->CreateCondBr(okCond, okbb, failbb);
|
||||||
|
|
||||||
p->scope() = IRScope(failbb);
|
p->ir->SetInsertPoint(failbb);
|
||||||
DtoBoundsCheckFailCall(p, e->loc);
|
DtoBoundsCheckFailCall(p, e->loc);
|
||||||
|
|
||||||
p->scope() = IRScope(okbb);
|
p->ir->SetInsertPoint(okbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// offset by lower
|
// offset by lower
|
||||||
|
@ -1268,19 +1266,19 @@ public:
|
||||||
lfptr, rfptr, ".fptreqcmp");
|
lfptr, rfptr, ".fptreqcmp");
|
||||||
llvm::BranchInst::Create(fptreq, fptrneq, fptreqcmp, p->scopebb());
|
llvm::BranchInst::Create(fptreq, fptrneq, fptreqcmp, p->scopebb());
|
||||||
|
|
||||||
p->scope() = IRScope(fptreq);
|
p->ir->SetInsertPoint(fptreq);
|
||||||
llvm::Value *lctx = p->ir->CreateExtractValue(lhs, 0, ".lctx");
|
llvm::Value *lctx = p->ir->CreateExtractValue(lhs, 0, ".lctx");
|
||||||
llvm::Value *rctx = p->ir->CreateExtractValue(rhs, 0, ".rctx");
|
llvm::Value *rctx = p->ir->CreateExtractValue(rhs, 0, ".rctx");
|
||||||
llvm::Value *ctxcmp =
|
llvm::Value *ctxcmp =
|
||||||
p->ir->CreateICmp(icmpPred, lctx, rctx, ".ctxcmp");
|
p->ir->CreateICmp(icmpPred, lctx, rctx, ".ctxcmp");
|
||||||
llvm::BranchInst::Create(dgcmpend, p->scopebb());
|
llvm::BranchInst::Create(dgcmpend, p->scopebb());
|
||||||
|
|
||||||
p->scope() = IRScope(fptrneq);
|
p->ir->SetInsertPoint(fptrneq);
|
||||||
llvm::Value *fptrcmp =
|
llvm::Value *fptrcmp =
|
||||||
p->ir->CreateICmp(icmpPred, lfptr, rfptr, ".fptrcmp");
|
p->ir->CreateICmp(icmpPred, lfptr, rfptr, ".fptrcmp");
|
||||||
llvm::BranchInst::Create(dgcmpend, p->scopebb());
|
llvm::BranchInst::Create(dgcmpend, p->scopebb());
|
||||||
|
|
||||||
p->scope() = IRScope(dgcmpend);
|
p->ir->SetInsertPoint(dgcmpend);
|
||||||
llvm::PHINode *phi = p->ir->CreatePHI(ctxcmp->getType(), 2, ".dgcmp");
|
llvm::PHINode *phi = p->ir->CreatePHI(ctxcmp->getType(), 2, ".dgcmp");
|
||||||
phi->addIncoming(ctxcmp, fptreq);
|
phi->addIncoming(ctxcmp, fptreq);
|
||||||
phi->addIncoming(fptrcmp, fptrneq);
|
phi->addIncoming(fptrcmp, fptrneq);
|
||||||
|
@ -1656,7 +1654,7 @@ public:
|
||||||
// assign branch weights to this branch instruction.
|
// assign branch weights to this branch instruction.
|
||||||
|
|
||||||
// failed: call assert runtime function
|
// failed: call assert runtime function
|
||||||
p->scope() = IRScope(failedbb);
|
p->ir->SetInsertPoint(failedbb);
|
||||||
|
|
||||||
if (global.params.checkAction == CHECKACTION_halt) {
|
if (global.params.checkAction == CHECKACTION_halt) {
|
||||||
p->ir->CreateCall(GET_INTRINSIC_DECL(trap), {});
|
p->ir->CreateCall(GET_INTRINSIC_DECL(trap), {});
|
||||||
|
@ -1680,7 +1678,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// passed:
|
// passed:
|
||||||
p->scope() = IRScope(passedbb);
|
p->ir->SetInsertPoint(passedbb);
|
||||||
|
|
||||||
// class/struct invariants
|
// class/struct invariants
|
||||||
if (global.params.useInvariants != CHECKENABLEon)
|
if (global.params.useInvariants != CHECKENABLEon)
|
||||||
|
@ -1765,7 +1763,7 @@ public:
|
||||||
p->ir->CreateCondBr(ubool, isAndAnd ? rhsBB : endBB,
|
p->ir->CreateCondBr(ubool, isAndAnd ? rhsBB : endBB,
|
||||||
isAndAnd ? endBB : rhsBB, branchweights);
|
isAndAnd ? endBB : rhsBB, branchweights);
|
||||||
|
|
||||||
p->scope() = IRScope(rhsBB);
|
p->ir->SetInsertPoint(rhsBB);
|
||||||
PGO.emitCounterIncrement(e);
|
PGO.emitCounterIncrement(e);
|
||||||
emitCoverageLinecountInc(e->e2->loc);
|
emitCoverageLinecountInc(e->e2->loc);
|
||||||
DValue *v = toElemDtor(e->e2);
|
DValue *v = toElemDtor(e->e2);
|
||||||
|
@ -1777,7 +1775,7 @@ public:
|
||||||
|
|
||||||
llvm::BasicBlock *newblock = p->scopebb();
|
llvm::BasicBlock *newblock = p->scopebb();
|
||||||
llvm::BranchInst::Create(endBB, p->scopebb());
|
llvm::BranchInst::Create(endBB, p->scopebb());
|
||||||
p->scope() = IRScope(endBB);
|
p->ir->SetInsertPoint(endBB);
|
||||||
|
|
||||||
// DMD allows stuff like `x == 0 && assert(false)`
|
// DMD allows stuff like `x == 0 && assert(false)`
|
||||||
if (e->type->toBasetype()->ty == Tvoid) {
|
if (e->type->toBasetype()->ty == Tvoid) {
|
||||||
|
@ -1822,7 +1820,7 @@ public:
|
||||||
// this is sensible, since someone might goto behind the assert
|
// this is sensible, since someone might goto behind the assert
|
||||||
// and prevents compiler errors if a terminator follows the assert
|
// and prevents compiler errors if a terminator follows the assert
|
||||||
llvm::BasicBlock *bb = p->insertBB("afterhalt");
|
llvm::BasicBlock *bb = p->insertBB("afterhalt");
|
||||||
p->scope() = IRScope(bb);
|
p->ir->SetInsertPoint(bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -2004,7 +2002,7 @@ public:
|
||||||
auto branchweights = PGO.createProfileWeights(truecount, falsecount);
|
auto branchweights = PGO.createProfileWeights(truecount, falsecount);
|
||||||
p->ir->CreateCondBr(cond_val, condtrue, condfalse, branchweights);
|
p->ir->CreateCondBr(cond_val, condtrue, condfalse, branchweights);
|
||||||
|
|
||||||
p->scope() = IRScope(condtrue);
|
p->ir->SetInsertPoint(condtrue);
|
||||||
PGO.emitCounterIncrement(e);
|
PGO.emitCounterIncrement(e);
|
||||||
DValue *u = toElem(e->e1);
|
DValue *u = toElem(e->e1);
|
||||||
if (retPtr) {
|
if (retPtr) {
|
||||||
|
@ -2013,7 +2011,7 @@ public:
|
||||||
}
|
}
|
||||||
llvm::BranchInst::Create(condend, p->scopebb());
|
llvm::BranchInst::Create(condend, p->scopebb());
|
||||||
|
|
||||||
p->scope() = IRScope(condfalse);
|
p->ir->SetInsertPoint(condfalse);
|
||||||
DValue *v = toElem(e->e2);
|
DValue *v = toElem(e->e2);
|
||||||
if (retPtr) {
|
if (retPtr) {
|
||||||
LLValue *lval = makeLValue(e->loc, v);
|
LLValue *lval = makeLValue(e->loc, v);
|
||||||
|
@ -2021,7 +2019,7 @@ public:
|
||||||
}
|
}
|
||||||
llvm::BranchInst::Create(condend, p->scopebb());
|
llvm::BranchInst::Create(condend, p->scopebb());
|
||||||
|
|
||||||
p->scope() = IRScope(condend);
|
p->ir->SetInsertPoint(condend);
|
||||||
if (retPtr)
|
if (retPtr)
|
||||||
result = new DSpecialRefValue(e->type, retPtr);
|
result = new DSpecialRefValue(e->type, retPtr);
|
||||||
}
|
}
|
||||||
|
@ -2429,8 +2427,7 @@ public:
|
||||||
LLValue *valuesArray = DtoAggrPaint(slice, funcTy->getParamType(2));
|
LLValue *valuesArray = DtoAggrPaint(slice, funcTy->getParamType(2));
|
||||||
|
|
||||||
LLValue *aa = gIR->CreateCallOrInvoke(func, aaTypeInfo, keysArray,
|
LLValue *aa = gIR->CreateCallOrInvoke(func, aaTypeInfo, keysArray,
|
||||||
valuesArray, "aa")
|
valuesArray, "aa");
|
||||||
.getInstruction();
|
|
||||||
if (basetype->ty != Taarray) {
|
if (basetype->ty != Taarray) {
|
||||||
LLValue *tmp = DtoAlloca(e->type, "aaliteral");
|
LLValue *tmp = DtoAlloca(e->type, "aaliteral");
|
||||||
DtoStore(aa, DtoGEP(tmp, 0u, 0));
|
DtoStore(aa, DtoGEP(tmp, 0u, 0));
|
||||||
|
@ -2624,7 +2621,13 @@ public:
|
||||||
DValue *val = toElem(e->e1);
|
DValue *val = toElem(e->e1);
|
||||||
LLValue *llElement = getCastElement(val);
|
LLValue *llElement = getCastElement(val);
|
||||||
if (auto llConstant = isaConstant(llElement)) {
|
if (auto llConstant = isaConstant(llElement)) {
|
||||||
auto vectorConstant = llvm::ConstantVector::getSplat(N, llConstant);
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
const auto elementCount = llvm::ElementCount(N, false);
|
||||||
|
#else
|
||||||
|
const auto elementCount = N;
|
||||||
|
#endif
|
||||||
|
auto vectorConstant =
|
||||||
|
llvm::ConstantVector::getSplat(elementCount, llConstant);
|
||||||
DtoStore(vectorConstant, dstMem);
|
DtoStore(vectorConstant, dstMem);
|
||||||
} else {
|
} else {
|
||||||
for (unsigned int i = 0; i < N; ++i) {
|
for (unsigned int i = 0; i < N; ++i) {
|
||||||
|
|
|
@ -452,7 +452,9 @@ LLValue *DtoLoad(LLValue *src, const char *name) {
|
||||||
// the type.
|
// the type.
|
||||||
LLValue *DtoAlignedLoad(LLValue *src, const char *name) {
|
LLValue *DtoAlignedLoad(LLValue *src, const char *name) {
|
||||||
llvm::LoadInst *ld = gIR->ir->CreateLoad(src, name);
|
llvm::LoadInst *ld = gIR->ir->CreateLoad(src, name);
|
||||||
ld->setAlignment(LLMaybeAlign(getABITypeAlign(ld->getType())));
|
if (auto alignment = getABITypeAlign(ld->getType())) {
|
||||||
|
ld->setAlignment(LLAlign(alignment));
|
||||||
|
}
|
||||||
return ld;
|
return ld;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,7 +491,9 @@ void DtoAlignedStore(LLValue *src, LLValue *dst) {
|
||||||
assert(src->getType() != llvm::Type::getInt1Ty(gIR->context()) &&
|
assert(src->getType() != llvm::Type::getInt1Ty(gIR->context()) &&
|
||||||
"Should store bools as i8 instead of i1.");
|
"Should store bools as i8 instead of i1.");
|
||||||
llvm::StoreInst *st = gIR->ir->CreateStore(src, dst);
|
llvm::StoreInst *st = gIR->ir->CreateStore(src, dst);
|
||||||
st->setAlignment(LLMaybeAlign(getABITypeAlign(src->getType())));
|
if (auto alignment = getABITypeAlign(src->getType())) {
|
||||||
|
st->setAlignment(LLAlign(alignment));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -74,7 +74,7 @@ void TryCatchScope::emitCatchBodies(IRState &irs, llvm::Value *ehPtrSlot) {
|
||||||
for (auto c : *stmt->catches) {
|
for (auto c : *stmt->catches) {
|
||||||
auto catchBB =
|
auto catchBB =
|
||||||
irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars());
|
irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars());
|
||||||
irs.scope() = IRScope(catchBB);
|
irs.ir->SetInsertPoint(catchBB);
|
||||||
irs.DBuilder.EmitBlockStart(c->loc);
|
irs.DBuilder.EmitBlockStart(c->loc);
|
||||||
PGO.emitCounterIncrement(c);
|
PGO.emitCounterIncrement(c);
|
||||||
|
|
||||||
|
@ -218,9 +218,8 @@ void emitBeginCatchMSVC(IRState &irs, Catch *ctch,
|
||||||
|
|
||||||
// redirect scope to avoid the generation of debug info before the
|
// redirect scope to avoid the generation of debug info before the
|
||||||
// catchpad
|
// catchpad
|
||||||
IRScope save = irs.scope();
|
const auto savedInsertPoint = irs.saveInsertPoint();
|
||||||
irs.scope() = IRScope(gIR->topallocapoint()->getParent());
|
irs.ir->SetInsertPoint(gIR->topallocapoint());
|
||||||
irs.scope().builder.SetInsertPoint(gIR->topallocapoint());
|
|
||||||
DtoDeclarationExp(var);
|
DtoDeclarationExp(var);
|
||||||
|
|
||||||
// catch handler will be outlined, so always treat as a nested reference
|
// catch handler will be outlined, so always treat as a nested reference
|
||||||
|
@ -232,9 +231,6 @@ void emitBeginCatchMSVC(IRState &irs, Catch *ctch,
|
||||||
cpyObj = exnObj;
|
cpyObj = exnObj;
|
||||||
exnObj = DtoAlloca(var->type, "exnObj");
|
exnObj = DtoAlloca(var->type, "exnObj");
|
||||||
}
|
}
|
||||||
irs.scope() = save;
|
|
||||||
irs.DBuilder.EmitStopPoint(ctch->loc); // re-set debug loc after the
|
|
||||||
// SetInsertPoint(allocaInst) call
|
|
||||||
} else if (ctch->type) {
|
} else if (ctch->type) {
|
||||||
// catch without var
|
// catch without var
|
||||||
exnObj = DtoAlloca(ctch->type, "exnObj");
|
exnObj = DtoAlloca(ctch->type, "exnObj");
|
||||||
|
@ -275,7 +271,7 @@ void emitBeginCatchMSVC(IRState &irs, Catch *ctch,
|
||||||
// outside the catch funclet
|
// outside the catch funclet
|
||||||
llvm::BasicBlock *catchhandler = irs.insertBB("catchhandler");
|
llvm::BasicBlock *catchhandler = irs.insertBB("catchhandler");
|
||||||
llvm::CatchReturnInst::Create(catchpad, catchhandler, irs.scopebb());
|
llvm::CatchReturnInst::Create(catchpad, catchhandler, irs.scopebb());
|
||||||
irs.scope() = IRScope(catchhandler);
|
irs.ir->SetInsertPoint(catchhandler);
|
||||||
irs.funcGen().pgo.emitCounterIncrement(ctch);
|
irs.funcGen().pgo.emitCounterIncrement(ctch);
|
||||||
if (!isCPPclass) {
|
if (!isCPPclass) {
|
||||||
auto enterCatchFn =
|
auto enterCatchFn =
|
||||||
|
@ -302,7 +298,7 @@ void TryCatchScope::emitCatchBodiesMSVC(IRState &irs, llvm::Value *) {
|
||||||
auto catchBB =
|
auto catchBB =
|
||||||
irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars());
|
irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars());
|
||||||
|
|
||||||
irs.scope() = IRScope(catchBB);
|
irs.ir->SetInsertPoint(catchBB);
|
||||||
irs.DBuilder.EmitBlockStart(c->loc);
|
irs.DBuilder.EmitBlockStart(c->loc);
|
||||||
|
|
||||||
emitBeginCatchMSVC(irs, c, catchSwitchInst);
|
emitBeginCatchMSVC(irs, c, catchSwitchInst);
|
||||||
|
@ -366,9 +362,9 @@ llvm::BasicBlock *CleanupScope::run(IRState &irs, llvm::BasicBlock *sourceBlock,
|
||||||
// We need a branch selector if we are here...
|
// We need a branch selector if we are here...
|
||||||
if (!branchSelector) {
|
if (!branchSelector) {
|
||||||
// ... and have not created one yet, so do so now.
|
// ... and have not created one yet, so do so now.
|
||||||
|
llvm::Type *branchSelectorType = llvm::Type::getInt32Ty(irs.context());
|
||||||
branchSelector = new llvm::AllocaInst(
|
branchSelector = new llvm::AllocaInst(
|
||||||
llvm::Type::getInt32Ty(irs.context()),
|
branchSelectorType, irs.module.getDataLayout().getAllocaAddrSpace(),
|
||||||
irs.module.getDataLayout().getAllocaAddrSpace(),
|
|
||||||
llvm::Twine("branchsel.") + beginBlock()->getName(),
|
llvm::Twine("branchsel.") + beginBlock()->getName(),
|
||||||
irs.topallocapoint());
|
irs.topallocapoint());
|
||||||
|
|
||||||
|
@ -381,7 +377,11 @@ llvm::BasicBlock *CleanupScope::run(IRState &irs, llvm::BasicBlock *sourceBlock,
|
||||||
// And convert the BranchInst to the existing branch target to a
|
// And convert the BranchInst to the existing branch target to a
|
||||||
// SelectInst so we can append the other cases to it.
|
// SelectInst so we can append the other cases to it.
|
||||||
endBlock()->getTerminator()->eraseFromParent();
|
endBlock()->getTerminator()->eraseFromParent();
|
||||||
llvm::Value *sel = new llvm::LoadInst(branchSelector, "", endBlock());
|
llvm::Value *sel = new llvm::LoadInst(
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
branchSelectorType,
|
||||||
|
#endif
|
||||||
|
branchSelector, "", endBlock());
|
||||||
llvm::SwitchInst::Create(
|
llvm::SwitchInst::Create(
|
||||||
sel, exitTargets[0].branchTarget,
|
sel, exitTargets[0].branchTarget,
|
||||||
1, // Expected number of branches, only for pre-allocating.
|
1, // Expected number of branches, only for pre-allocating.
|
||||||
|
@ -689,12 +689,12 @@ llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// save and rewrite scope
|
// save and rewrite scope
|
||||||
IRScope savedIRScope = irs.scope();
|
const auto savedInsertPoint = irs.saveInsertPoint();
|
||||||
|
|
||||||
// insert landing pads at the end of the function, in emission order,
|
// insert landing pads at the end of the function, in emission order,
|
||||||
// to improve human-readability of the IR
|
// to improve human-readability of the IR
|
||||||
llvm::BasicBlock *beginBB = irs.insertBBBefore(nullptr, "landingPad");
|
llvm::BasicBlock *beginBB = irs.insertBBBefore(nullptr, "landingPad");
|
||||||
irs.scope() = IRScope(beginBB);
|
irs.ir->SetInsertPoint(beginBB);
|
||||||
|
|
||||||
llvm::LandingPadInst *landingPad = createLandingPadInst(irs);
|
llvm::LandingPadInst *landingPad = createLandingPadInst(irs);
|
||||||
|
|
||||||
|
@ -724,7 +724,7 @@ llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() {
|
||||||
llvm::BasicBlock *afterCleanupBB =
|
llvm::BasicBlock *afterCleanupBB =
|
||||||
irs.insertBB(beginBB->getName() + llvm::Twine(".after.cleanup"));
|
irs.insertBB(beginBB->getName() + llvm::Twine(".after.cleanup"));
|
||||||
runCleanups(lastCleanup, newCleanup, afterCleanupBB);
|
runCleanups(lastCleanup, newCleanup, afterCleanupBB);
|
||||||
irs.scope() = IRScope(afterCleanupBB);
|
irs.ir->SetInsertPoint(afterCleanupBB);
|
||||||
lastCleanup = newCleanup;
|
lastCleanup = newCleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -747,7 +747,7 @@ llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() {
|
||||||
irs.ir->CreateCondBr(
|
irs.ir->CreateCondBr(
|
||||||
irs.ir->CreateICmpEQ(irs.ir->CreateLoad(ehSelectorSlot), ehTypeId),
|
irs.ir->CreateICmpEQ(irs.ir->CreateLoad(ehSelectorSlot), ehTypeId),
|
||||||
cb.bodyBB, mismatchBB, cb.branchWeights);
|
cb.bodyBB, mismatchBB, cb.branchWeights);
|
||||||
irs.scope() = IRScope(mismatchBB);
|
irs.ir->SetInsertPoint(mismatchBB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -765,7 +765,6 @@ llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() {
|
||||||
irs.ir->CreateBr(resumeUnwindBlock);
|
irs.ir->CreateBr(resumeUnwindBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
irs.scope() = savedIRScope;
|
|
||||||
return beginBB;
|
return beginBB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -780,13 +779,13 @@ llvm::BasicBlock *TryCatchFinallyScopes::getOrCreateResumeUnwindBlock() {
|
||||||
resumeUnwindBlock = irs.insertBB("eh.resume");
|
resumeUnwindBlock = irs.insertBB("eh.resume");
|
||||||
|
|
||||||
llvm::BasicBlock *oldBB = irs.scopebb();
|
llvm::BasicBlock *oldBB = irs.scopebb();
|
||||||
irs.scope() = IRScope(resumeUnwindBlock);
|
irs.ir->SetInsertPoint(resumeUnwindBlock);
|
||||||
|
|
||||||
llvm::Function *resumeFn = getUnwindResumeFunction(Loc(), irs.module);
|
llvm::Function *resumeFn = getUnwindResumeFunction(Loc(), irs.module);
|
||||||
irs.ir->CreateCall(resumeFn, DtoLoad(getOrCreateEhPtrSlot()));
|
irs.ir->CreateCall(resumeFn, DtoLoad(getOrCreateEhPtrSlot()));
|
||||||
irs.ir->CreateUnreachable();
|
irs.ir->CreateUnreachable();
|
||||||
|
|
||||||
irs.scope() = IRScope(oldBB);
|
irs.ir->SetInsertPoint(oldBB);
|
||||||
}
|
}
|
||||||
return resumeUnwindBlock;
|
return resumeUnwindBlock;
|
||||||
}
|
}
|
||||||
|
@ -844,9 +843,7 @@ TryCatchFinallyScopes::runCleanupPad(CleanupCursor scope,
|
||||||
// can place an exception frame (but not done here)
|
// can place an exception frame (but not done here)
|
||||||
auto frame = getNullPtr(getVoidPtrType());
|
auto frame = getNullPtr(getVoidPtrType());
|
||||||
|
|
||||||
auto savedInsertBlock = irs.ir->GetInsertBlock();
|
const auto savedInsertPoint = irs.saveInsertPoint();
|
||||||
auto savedInsertPoint = irs.ir->GetInsertPoint();
|
|
||||||
auto savedDbgLoc = irs.DBuilder.GetCurrentLoc();
|
|
||||||
|
|
||||||
auto endFn = getRuntimeFunction(Loc(), irs.module, "_d_leave_cleanup");
|
auto endFn = getRuntimeFunction(Loc(), irs.module, "_d_leave_cleanup");
|
||||||
irs.ir->SetInsertPoint(cleanupret);
|
irs.ir->SetInsertPoint(cleanupret);
|
||||||
|
@ -865,8 +862,5 @@ TryCatchFinallyScopes::runCleanupPad(CleanupCursor scope,
|
||||||
beginFn, frame, {llvm::OperandBundleDef("funclet", cleanuppad)}, "");
|
beginFn, frame, {llvm::OperandBundleDef("funclet", cleanuppad)}, "");
|
||||||
llvm::BranchInst::Create(copybb, cleanupret, exec, cleanupbb);
|
llvm::BranchInst::Create(copybb, cleanupret, exec, cleanupbb);
|
||||||
|
|
||||||
irs.ir->SetInsertPoint(savedInsertBlock, savedInsertPoint);
|
|
||||||
irs.DBuilder.EmitStopPoint(savedDbgLoc);
|
|
||||||
|
|
||||||
return cleanupbb;
|
return cleanupbb;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "llvm/ADT/StringExtras.h"
|
#include "llvm/ADT/StringExtras.h"
|
||||||
#include "llvm/ADT/StringSwitch.h"
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
|
|
||||||
|
#if LDC_LLVM_VER < 1100
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
// Auto-generate:
|
// Auto-generate:
|
||||||
// Attribute::AttrKind getAttrKindFromName(StringRef AttrName) { ... }
|
// Attribute::AttrKind getAttrKindFromName(StringRef AttrName) { ... }
|
||||||
|
@ -26,6 +27,7 @@ namespace llvm {
|
||||||
#include "llvm/IR/Attributes.inc"
|
#include "llvm/IR/Attributes.inc"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -205,7 +207,11 @@ void applyAttrLLVMAttr(StructLiteralExp *sle, llvm::AttrBuilder &attrs) {
|
||||||
llvm::StringRef key = getStringElem(sle, 0);
|
llvm::StringRef key = getStringElem(sle, 0);
|
||||||
llvm::StringRef value = getStringElem(sle, 1);
|
llvm::StringRef value = getStringElem(sle, 1);
|
||||||
if (value.empty()) {
|
if (value.empty()) {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
const auto kind = llvm::Attribute::getAttrKindFromName(key);
|
||||||
|
#else
|
||||||
const auto kind = llvm::getAttrKindFromName(key);
|
const auto kind = llvm::getAttrKindFromName(key);
|
||||||
|
#endif
|
||||||
if (kind != llvm::Attribute::None) {
|
if (kind != llvm::Attribute::None) {
|
||||||
attrs.addAttribute(kind);
|
attrs.addAttribute(kind);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -560,8 +560,9 @@ void IrClass::defineInterfaceVtbl(BaseClass *b, bool new_instance,
|
||||||
// create entry and end blocks
|
// create entry and end blocks
|
||||||
llvm::BasicBlock *beginbb =
|
llvm::BasicBlock *beginbb =
|
||||||
llvm::BasicBlock::Create(gIR->context(), "", thunk);
|
llvm::BasicBlock::Create(gIR->context(), "", thunk);
|
||||||
gIR->scopes.push_back(IRScope(beginbb));
|
|
||||||
|
|
||||||
|
// set up the IRBuilder scope for the thunk
|
||||||
|
const auto savedIRBuilderScope = gIR->setInsertPoint(beginbb);
|
||||||
gIR->DBuilder.EmitFuncStart(thunkFd);
|
gIR->DBuilder.EmitFuncStart(thunkFd);
|
||||||
|
|
||||||
// Copy the function parameters, so later we can pass them to the
|
// Copy the function parameters, so later we can pass them to the
|
||||||
|
@ -604,11 +605,6 @@ void IrClass::defineInterfaceVtbl(BaseClass *b, bool new_instance,
|
||||||
llvm::ReturnInst::Create(gIR->context(), call, beginbb);
|
llvm::ReturnInst::Create(gIR->context(), call, beginbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
gIR->DBuilder.EmitFuncEnd(thunkFd);
|
|
||||||
|
|
||||||
// clean up
|
|
||||||
gIR->scopes.pop_back();
|
|
||||||
|
|
||||||
gIR->funcGenStates.pop_back();
|
gIR->funcGenStates.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -220,5 +220,10 @@ llvm::Type *IrTypeVector::vector2llvm(Type *dt) {
|
||||||
TypeSArray *tsa = static_cast<TypeSArray *>(tv->basetype);
|
TypeSArray *tsa = static_cast<TypeSArray *>(tv->basetype);
|
||||||
uint64_t dim = static_cast<uint64_t>(tsa->dim->toUInteger());
|
uint64_t dim = static_cast<uint64_t>(tsa->dim->toUInteger());
|
||||||
LLType *elemType = DtoMemType(tsa->next);
|
LLType *elemType = DtoMemType(tsa->next);
|
||||||
return llvm::VectorType::get(elemType, dim);
|
return llvm::VectorType::get(elemType, dim
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
,
|
||||||
|
/*Scalable=*/false
|
||||||
|
#endif
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,14 @@
|
||||||
#include "valueparser.h"
|
#include "valueparser.h"
|
||||||
|
|
||||||
#if LDC_LLVM_VER >= 1000
|
#if LDC_LLVM_VER >= 1000
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
#define LLAlign llvm::Align
|
||||||
|
#else
|
||||||
|
#define LLAlign llvm::MaybeAlign
|
||||||
|
#endif
|
||||||
#define LLMaybeAlign llvm::MaybeAlign
|
#define LLMaybeAlign llvm::MaybeAlign
|
||||||
#else
|
#else
|
||||||
|
#define LLAlign
|
||||||
#define LLMaybeAlign
|
#define LLMaybeAlign
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -77,14 +83,16 @@ allocParam(llvm::IRBuilder<> &builder, llvm::Type &srcType,
|
||||||
if (param.type == ParamType::Aggregate && srcType.isPointerTy()) {
|
if (param.type == ParamType::Aggregate && srcType.isPointerTy()) {
|
||||||
auto elemType = llvm::cast<llvm::PointerType>(&srcType)->getElementType();
|
auto elemType = llvm::cast<llvm::PointerType>(&srcType)->getElementType();
|
||||||
auto stackArg = builder.CreateAlloca(elemType);
|
auto stackArg = builder.CreateAlloca(elemType);
|
||||||
stackArg->setAlignment(LLMaybeAlign(layout.getABITypeAlignment(elemType)));
|
if (auto alignment = layout.getABITypeAlignment(elemType))
|
||||||
|
stackArg->setAlignment(LLAlign(alignment));
|
||||||
auto init =
|
auto init =
|
||||||
parseInitializer(layout, *elemType, param.data, errHandler, override);
|
parseInitializer(layout, *elemType, param.data, errHandler, override);
|
||||||
builder.CreateStore(init, stackArg);
|
builder.CreateStore(init, stackArg);
|
||||||
return stackArg;
|
return stackArg;
|
||||||
}
|
}
|
||||||
auto stackArg = builder.CreateAlloca(&srcType);
|
auto stackArg = builder.CreateAlloca(&srcType);
|
||||||
stackArg->setAlignment(LLMaybeAlign(layout.getABITypeAlignment(&srcType)));
|
if (auto alignment = layout.getABITypeAlignment(&srcType))
|
||||||
|
stackArg->setAlignment(LLAlign(alignment));
|
||||||
auto init =
|
auto init =
|
||||||
parseInitializer(layout, srcType, param.data, errHandler, override);
|
parseInitializer(layout, srcType, param.data, errHandler, override);
|
||||||
builder.CreateStore(init, stackArg);
|
builder.CreateStore(init, stackArg);
|
||||||
|
|
|
@ -135,11 +135,21 @@ void printFunction(const llvm::MCDisassembler &disasm,
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case llvm::MCDisassembler::Fail:
|
case llvm::MCDisassembler::Fail:
|
||||||
streamer.EmitRawText("failed to disassemble");
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
streamer.emitRawText(
|
||||||
|
#else
|
||||||
|
streamer.EmitRawText(
|
||||||
|
#endif
|
||||||
|
"failed to disassemble");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case llvm::MCDisassembler::SoftFail:
|
case llvm::MCDisassembler::SoftFail:
|
||||||
streamer.EmitRawText("potentially undefined instruction encoding:");
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
streamer.emitRawText(
|
||||||
|
#else
|
||||||
|
streamer.EmitRawText(
|
||||||
|
#endif
|
||||||
|
"potentially undefined instruction encoding:");
|
||||||
LLVM_FALLTHROUGH;
|
LLVM_FALLTHROUGH;
|
||||||
|
|
||||||
case llvm::MCDisassembler::Success:
|
case llvm::MCDisassembler::Success:
|
||||||
|
@ -152,14 +162,22 @@ void printFunction(const llvm::MCDisassembler &disasm,
|
||||||
}
|
}
|
||||||
} else if (Stage::Emit == stage) {
|
} else if (Stage::Emit == stage) {
|
||||||
if (auto label = symTable.getTargetLabel(pos)) {
|
if (auto label = symTable.getTargetLabel(pos)) {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
streamer.emitLabel(label);
|
||||||
|
#else
|
||||||
streamer.EmitLabel(label);
|
streamer.EmitLabel(label);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
commentStream.flush();
|
commentStream.flush();
|
||||||
if (!comment.empty()) {
|
if (!comment.empty()) {
|
||||||
streamer.AddComment(comment);
|
streamer.AddComment(comment);
|
||||||
comment.clear();
|
comment.clear();
|
||||||
}
|
}
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
streamer.emitInstruction(inst, sti);
|
||||||
|
#else
|
||||||
streamer.EmitInstruction(inst, sti);
|
streamer.EmitInstruction(inst, sti);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -304,7 +322,11 @@ void disassemble(const llvm::TargetMachine &tm,
|
||||||
for (const auto &symbol : object.symbols()) {
|
for (const auto &symbol : object.symbols()) {
|
||||||
const auto secIt = llvm::cantFail(symbol.getSection());
|
const auto secIt = llvm::cantFail(symbol.getSection());
|
||||||
if (object.section_end() != secIt) {
|
if (object.section_end() != secIt) {
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
auto offset = llvm::cantFail(symbol.getValue());
|
||||||
|
#else
|
||||||
auto offset = symbol.getValue();
|
auto offset = symbol.getValue();
|
||||||
|
#endif
|
||||||
sectionsToProcess[secIt->getIndex()].push_back(offset);
|
sectionsToProcess[secIt->getIndex()].push_back(offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,9 +344,7 @@ void disassemble(const llvm::TargetMachine &tm,
|
||||||
const auto sec = *secIt;
|
const auto sec = *secIt;
|
||||||
llvm::StringRef data;
|
llvm::StringRef data;
|
||||||
#if LDC_LLVM_VER >= 900
|
#if LDC_LLVM_VER >= 900
|
||||||
auto dataOrError = sec.getContents();
|
data = llvm::cantFail(sec.getContents());
|
||||||
assert(dataOrError);
|
|
||||||
data = *dataOrError;
|
|
||||||
#else
|
#else
|
||||||
sec.getContents(data);
|
sec.getContents(data);
|
||||||
#endif
|
#endif
|
||||||
|
@ -333,7 +353,11 @@ void disassemble(const llvm::TargetMachine &tm,
|
||||||
llvm::cantFail(symbol.getType())) {
|
llvm::cantFail(symbol.getType())) {
|
||||||
symTable.reset();
|
symTable.reset();
|
||||||
symTable.addLabel(0, 0, name); // Function start
|
symTable.addLabel(0, 0, name); // Function start
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
auto offset = llvm::cantFail(symbol.getValue());
|
||||||
|
#else
|
||||||
auto offset = symbol.getValue();
|
auto offset = symbol.getValue();
|
||||||
|
#endif
|
||||||
processRelocations(symTable, offset, object, sec);
|
processRelocations(symTable, offset, object, sec);
|
||||||
|
|
||||||
// TODO: something more optimal
|
// TODO: something more optimal
|
||||||
|
@ -360,7 +384,11 @@ void disassemble(const llvm::TargetMachine &tm,
|
||||||
reinterpret_cast<const uint8_t *>(data.data() + offset), size);
|
reinterpret_cast<const uint8_t *>(data.data() + offset), size);
|
||||||
|
|
||||||
printFunction(*disasm, *mcia, buff, symTable, *sti, *asmStreamer);
|
printFunction(*disasm, *mcia, buff, symTable, *sti, *asmStreamer);
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
asmStreamer->emitRawText("");
|
||||||
|
#else
|
||||||
asmStreamer->EmitRawText("");
|
asmStreamer->EmitRawText("");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,7 +202,12 @@ std::shared_ptr<llvm::orc::SymbolResolver>
|
||||||
DynamicCompilerContext::createResolver() {
|
DynamicCompilerContext::createResolver() {
|
||||||
return llvm::orc::createLegacyLookupResolver(
|
return llvm::orc::createLegacyLookupResolver(
|
||||||
execSession,
|
execSession,
|
||||||
|
#if LDC_LLVM_VER >= 1100
|
||||||
|
[this](llvm::StringRef name_) -> llvm::JITSymbol {
|
||||||
|
const std::string name = name_.str();
|
||||||
|
#else
|
||||||
[this](const std::string &name) -> llvm::JITSymbol {
|
[this](const std::string &name) -> llvm::JITSymbol {
|
||||||
|
#endif
|
||||||
if (auto Sym = compileLayer.findSymbol(name, false)) {
|
if (auto Sym = compileLayer.findSymbol(name, false)) {
|
||||||
return Sym;
|
return Sym;
|
||||||
} else if (auto Err = Sym.takeError()) {
|
} else if (auto Err = Sym.takeError()) {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c358e433e7d3621549b0834a90e9cce55bd43d06
|
Subproject commit 0d04cf72770a356033e8e5fca657b9b7316bc957
|
|
@ -13,7 +13,7 @@ env:
|
||||||
global:
|
global:
|
||||||
- secure: RQ6gpJFPBDGVlnz+ZzSgeMpkcnvcA/7Lzyj/r06fMFR5iOz2cYaImCekNRw2PlhYQ+0FCQ119TLMKNOa7OUu6XxUp5LZtq7pSB6QLe3RB3YysFsosNPlY/wyyRsrW9ICEbDP/X8kPcfrDtOPGS/dGIwgeo0+R4Yl0OLDK9GrExEY45bWgvuLqoWDO89pi31kBk5LG5MAYhHZ0UTdboi5A2GRT0T8M0kr53jBRka8FGkbncXfHp9+/6IjTVJoUduRkdsk0A9RN1KRoao6rtrBNNvwIStc6zxJSOHszoaTp/K/ucGC4InZl/9GHPS/Y78SGKn7YJv3tGmcGzqAxrVaXQ==
|
- secure: RQ6gpJFPBDGVlnz+ZzSgeMpkcnvcA/7Lzyj/r06fMFR5iOz2cYaImCekNRw2PlhYQ+0FCQ119TLMKNOa7OUu6XxUp5LZtq7pSB6QLe3RB3YysFsosNPlY/wyyRsrW9ICEbDP/X8kPcfrDtOPGS/dGIwgeo0+R4Yl0OLDK9GrExEY45bWgvuLqoWDO89pi31kBk5LG5MAYhHZ0UTdboi5A2GRT0T8M0kr53jBRka8FGkbncXfHp9+/6IjTVJoUduRkdsk0A9RN1KRoao6rtrBNNvwIStc6zxJSOHszoaTp/K/ucGC4InZl/9GHPS/Y78SGKn7YJv3tGmcGzqAxrVaXQ==
|
||||||
matrix:
|
matrix:
|
||||||
- LLVM_VERSION=10.0.1
|
- LLVM_VERSION=84863923
|
||||||
HOST_LDC_VERSION=1.22.0
|
HOST_LDC_VERSION=1.22.0
|
||||||
EXTRA_CMAKE_FLAGS="-DBUILD_LTO_LIBS=ON -DCMAKE_EXE_LINKER_FLAGS=-static-libstdc++ -DJITRT_EXTRA_LDFLAGS=-static-libstdc++ -DLDC_INSTALL_LTOPLUGIN=ON -DLDC_INSTALL_LLVM_RUNTIME_LIBS=ON -DLDC_INSTALL_LLVM_RUNTIME_LIBS_ARCH=aarch64"
|
EXTRA_CMAKE_FLAGS="-DBUILD_LTO_LIBS=ON -DCMAKE_EXE_LINKER_FLAGS=-static-libstdc++ -DJITRT_EXTRA_LDFLAGS=-static-libstdc++ -DLDC_INSTALL_LTOPLUGIN=ON -DLDC_INSTALL_LLVM_RUNTIME_LIBS=ON -DLDC_INSTALL_LLVM_RUNTIME_LIBS_ARCH=aarch64"
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ build:
|
||||||
echo 'Using LLVM with enabled assertions'
|
echo 'Using LLVM with enabled assertions'
|
||||||
assertsSuffix="-withAsserts"
|
assertsSuffix="-withAsserts"
|
||||||
fi
|
fi
|
||||||
curl -L -o llvm.tar.xz https://github.com/ldc-developers/llvm-project/releases/download/ldc-v$LLVM_VERSION/llvm-$LLVM_VERSION-linux-aarch64$assertsSuffix.tar.xz
|
curl -L -o llvm.tar.xz https://github.com/ldc-developers/llvm-project/releases/download/CI/llvm-$LLVM_VERSION-linux-aarch64$assertsSuffix.tar.xz
|
||||||
- mkdir llvm
|
- mkdir llvm
|
||||||
- tar -xf llvm.tar.xz --strip 1 -C llvm
|
- tar -xf llvm.tar.xz --strip 1 -C llvm
|
||||||
- rm llvm.tar.xz
|
- rm llvm.tar.xz
|
||||||
|
|
|
@ -17,10 +17,6 @@ void foo()
|
||||||
|
|
||||||
// COMMON: attributes #[[KEYVALUE]]
|
// COMMON: attributes #[[KEYVALUE]]
|
||||||
// COMMON-DAG: "target-cpu"=
|
// COMMON-DAG: "target-cpu"=
|
||||||
// COMMON-DAG: "unsafe-fp-math"="false"
|
|
||||||
// COMMON-DAG: "less-precise-fpmad"="false"
|
|
||||||
// COMMON-DAG: "no-infs-fp-math"="false"
|
|
||||||
// COMMON-DAG: "no-nans-fp-math"="false"
|
|
||||||
|
|
||||||
// WITH_FP-DAG: "frame-pointer"="all"
|
// WITH_FP-DAG: "frame-pointer"="all"
|
||||||
// NO_FP-DAG: "frame-pointer"="none"
|
// NO_FP-DAG: "frame-pointer"="none"
|
||||||
|
|
|
@ -91,7 +91,7 @@ extern (C) double aliasInlineUnsafe(double[] a, double[] b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLVM-LABEL: define{{.*}} @aliasInlineSafe
|
// LLVM-LABEL: define{{.*}} @aliasInlineSafe
|
||||||
// LLVM-SAME: #[[UNSAFEFPMATH2:[0-9]+]]
|
// LLVM-SAME: #[[NO_UNSAFEFPMATH:[0-9]+]]
|
||||||
// ASM-LABEL: aliasInlineSafe:
|
// ASM-LABEL: aliasInlineSafe:
|
||||||
extern (C) double aliasInlineSafe(double[] a, double[] b)
|
extern (C) double aliasInlineSafe(double[] a, double[] b)
|
||||||
{
|
{
|
||||||
|
@ -113,6 +113,8 @@ double neverInlinedEnclosingFunction()
|
||||||
return muladd(1.0, 2.0, 3.0);
|
return muladd(1.0, 2.0, 3.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLVM-DAG: attributes #[[UNSAFEFPMATH]] ={{.*}} "unsafe-fp-math"="true"
|
// LLVM: attributes #[[UNSAFEFPMATH]] ={{.*}} "unsafe-fp-math"="true"
|
||||||
// LLVM-DAG: attributes #[[UNSAFEFPMATH2]] ={{.*}} "unsafe-fp-math"="false"
|
// LLVM: attributes #[[FEAT]] ={{.*}} "target-features"="{{.*}}+fma{{.*}}"
|
||||||
// LLVM-DAG: attributes #[[FEAT]] ={{.*}} "target-features"="{{.*}}+fma{{.*}}"
|
|
||||||
|
// LLVM: attributes #[[NO_UNSAFEFPMATH]] =
|
||||||
|
// LLVM-NOT: "unsafe-fp-math"="true"
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
// REQUIRES: XRay_RT
|
// REQUIRES: XRay_RT
|
||||||
|
|
||||||
|
// fails on macOS with LLVM 11 due to a linker error, see
|
||||||
|
// https://github.com/llvm/llvm-test-suite/commit/2c3c4a6286d453f763c0245c6536ddd368f0db99
|
||||||
|
// XFAIL: Darwin && atleast_llvm1100
|
||||||
|
|
||||||
// RUN: %ldc -fxray-instrument -fxray-instruction-threshold=1 -of=%t%exe %s -vv | FileCheck %s
|
// RUN: %ldc -fxray-instrument -fxray-instruction-threshold=1 -of=%t%exe %s -vv | FileCheck %s
|
||||||
|
|
||||||
void foo()
|
void foo()
|
||||||
|
|
|
@ -84,7 +84,7 @@ config.available_features.add("llvm%d" % config.llvm_version)
|
||||||
plusoneable_llvmversion = config.llvm_version // 10 + config.llvm_version%10
|
plusoneable_llvmversion = config.llvm_version // 10 + config.llvm_version%10
|
||||||
for version in range(60, plusoneable_llvmversion+1):
|
for version in range(60, plusoneable_llvmversion+1):
|
||||||
config.available_features.add("atleast_llvm%d0%d" % (version//10, version%10))
|
config.available_features.add("atleast_llvm%d0%d" % (version//10, version%10))
|
||||||
for version in range(plusoneable_llvmversion, 101):
|
for version in range(plusoneable_llvmversion, 111):
|
||||||
config.available_features.add("atmost_llvm%d0%d" % (version//10, version%10))
|
config.available_features.add("atmost_llvm%d0%d" % (version//10, version%10))
|
||||||
|
|
||||||
# Define OS as available feature (Windows, Darwin, Linux)
|
# Define OS as available feature (Windows, Darwin, Linux)
|
||||||
|
|
|
@ -50,7 +50,11 @@ bool FuncEntryCallPass::runOnFunction(Function &F) {
|
||||||
// (this includes e.g. `ldc.register_dso`!)
|
// (this includes e.g. `ldc.register_dso`!)
|
||||||
llvm::BasicBlock &block = F.getEntryBlock();
|
llvm::BasicBlock &block = F.getEntryBlock();
|
||||||
IRBuilder<> builder(&block, block.begin());
|
IRBuilder<> builder(&block, block.begin());
|
||||||
|
#if LLVM_VERSION >= 1100
|
||||||
|
builder.CreateCall(FunctionCallee(cast<Function>(funcToCallUponEntry)));
|
||||||
|
#else
|
||||||
builder.CreateCall(funcToCallUponEntry);
|
builder.CreateCall(funcToCallUponEntry);
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Test linking C++ stdlib (or not) with -fsanitize=fuzzer
|
// Test linking C++ stdlib (or not) with -fsanitize=fuzzer
|
||||||
|
|
||||||
// REQUIRES: Fuzzer
|
// REQUIRES: Fuzzer
|
||||||
|
// UNSUPPORTED: Windows
|
||||||
|
|
||||||
// RUN: %ldc -v -fsanitize=fuzzer %s | FileCheck %s
|
// RUN: %ldc -v -fsanitize=fuzzer %s | FileCheck %s
|
||||||
// "lib(ldc|clang)_rt.fuzzer.*.a" since LLVM 6.0
|
// "lib(ldc|clang)_rt.fuzzer.*.a" since LLVM 6.0
|
||||||
|
|
|
@ -3,22 +3,21 @@ import platform
|
||||||
import re
|
import re
|
||||||
|
|
||||||
# Add "ASan" and "Fuzzer" feature if the runtime library is available.
|
# Add "ASan" and "Fuzzer" feature if the runtime library is available.
|
||||||
# On Windows, the ASan library is apparently quite fragile and only works
|
for file in os.listdir(config.ldc2_lib_dir):
|
||||||
# with certain versions of Microsoft's runtime.
|
m = re.match('.*asan.*', file)
|
||||||
if (platform.system() == 'Darwin') or (platform.system() == 'Linux'):
|
if m is not None:
|
||||||
for file in os.listdir(config.ldc2_lib_dir):
|
config.available_features.add('ASan')
|
||||||
m = re.match('.*asan.*', file)
|
continue
|
||||||
if m is not None:
|
# FreeBSD TSan needs https://reviews.llvm.org/D85292
|
||||||
config.available_features.add('ASan')
|
if platform.system() != 'FreeBSD':
|
||||||
continue
|
|
||||||
m = re.match('.*tsan.*', file)
|
m = re.match('.*tsan.*', file)
|
||||||
if m is not None:
|
if m is not None:
|
||||||
config.available_features.add('TSan')
|
config.available_features.add('TSan')
|
||||||
continue
|
continue
|
||||||
m = re.match('.*(F|f)uzzer.*', file)
|
m = re.match('.*(F|f)uzzer.*', file)
|
||||||
if m is not None:
|
if m is not None:
|
||||||
config.available_features.add('Fuzzer')
|
config.available_features.add('Fuzzer')
|
||||||
continue
|
continue
|
||||||
if 'ASan' in config.available_features:
|
if 'ASan' in config.available_features:
|
||||||
# On Darwin, ASan defaults to `abort_on_error=1`, which would make tests run
|
# On Darwin, ASan defaults to `abort_on_error=1`, which would make tests run
|
||||||
# much slower. Let's override this and run lit tests with 'abort_on_error=0'.
|
# much slower. Let's override this and run lit tests with 'abort_on_error=0'.
|
||||||
|
|
1344
tools/ldc-profdata/llvm-profdata-11.0.cpp
Normal file
1344
tools/ldc-profdata/llvm-profdata-11.0.cpp
Normal file
File diff suppressed because it is too large
Load diff
859
utils/FileCheck-11.0.cpp
Normal file
859
utils/FileCheck-11.0.cpp
Normal file
|
@ -0,0 +1,859 @@
|
||||||
|
//===- FileCheck.cpp - Check that File's Contents match what is expected --===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// FileCheck does a line-by line check of a file that validates whether it
|
||||||
|
// contains the expected content. This is useful for regression tests etc.
|
||||||
|
//
|
||||||
|
// This program exits with an exit status of 2 on error, exit status of 0 if
|
||||||
|
// the file matched the expected contents, and exit status of 1 if it did not
|
||||||
|
// contain the expected contents.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
#include "llvm/Support/InitLLVM.h"
|
||||||
|
#include "llvm/Support/Process.h"
|
||||||
|
#include "llvm/Support/WithColor.h"
|
||||||
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
#include "llvm/Support/FileCheck.h"
|
||||||
|
#include <cmath>
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
static cl::extrahelp FileCheckOptsEnv(
|
||||||
|
"\nOptions are parsed from the environment variable FILECHECK_OPTS and\n"
|
||||||
|
"from the command line.\n");
|
||||||
|
|
||||||
|
static cl::opt<std::string>
|
||||||
|
CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional);
|
||||||
|
|
||||||
|
static cl::opt<std::string>
|
||||||
|
InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
|
||||||
|
cl::init("-"), cl::value_desc("filename"));
|
||||||
|
|
||||||
|
static cl::list<std::string> CheckPrefixes(
|
||||||
|
"check-prefix",
|
||||||
|
cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
|
||||||
|
static cl::alias CheckPrefixesAlias(
|
||||||
|
"check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated,
|
||||||
|
cl::NotHidden,
|
||||||
|
cl::desc(
|
||||||
|
"Alias for -check-prefix permitting multiple comma separated values"));
|
||||||
|
|
||||||
|
static cl::list<std::string> CommentPrefixes(
|
||||||
|
"comment-prefixes", cl::CommaSeparated, cl::Hidden,
|
||||||
|
cl::desc("Comma-separated list of comment prefixes to use from check file\n"
|
||||||
|
"(defaults to 'COM,RUN'). Please avoid using this feature in\n"
|
||||||
|
"LLVM's LIT-based test suites, which should be easier to\n"
|
||||||
|
"maintain if they all follow a consistent comment style. This\n"
|
||||||
|
"feature is meant for non-LIT test suites using FileCheck."));
|
||||||
|
|
||||||
|
static cl::opt<bool> NoCanonicalizeWhiteSpace(
|
||||||
|
"strict-whitespace",
|
||||||
|
cl::desc("Do not treat all horizontal whitespace as equivalent"));
|
||||||
|
|
||||||
|
static cl::opt<bool> IgnoreCase(
|
||||||
|
"ignore-case",
|
||||||
|
cl::desc("Use case-insensitive matching"));
|
||||||
|
|
||||||
|
static cl::list<std::string> ImplicitCheckNot(
|
||||||
|
"implicit-check-not",
|
||||||
|
cl::desc("Add an implicit negative check with this pattern to every\n"
|
||||||
|
"positive check. This can be used to ensure that no instances of\n"
|
||||||
|
"this pattern occur which are not matched by a positive pattern"),
|
||||||
|
cl::value_desc("pattern"));
|
||||||
|
|
||||||
|
static cl::list<std::string>
|
||||||
|
GlobalDefines("D", cl::AlwaysPrefix,
|
||||||
|
cl::desc("Define a variable to be used in capture patterns."),
|
||||||
|
cl::value_desc("VAR=VALUE"));
|
||||||
|
|
||||||
|
static cl::opt<bool> AllowEmptyInput(
|
||||||
|
"allow-empty", cl::init(false),
|
||||||
|
cl::desc("Allow the input file to be empty. This is useful when making\n"
|
||||||
|
"checks that some error message does not occur, for example."));
|
||||||
|
|
||||||
|
static cl::opt<bool> MatchFullLines(
|
||||||
|
"match-full-lines", cl::init(false),
|
||||||
|
cl::desc("Require all positive matches to cover an entire input line.\n"
|
||||||
|
"Allows leading and trailing whitespace if --strict-whitespace\n"
|
||||||
|
"is not also passed."));
|
||||||
|
|
||||||
|
static cl::opt<bool> EnableVarScope(
|
||||||
|
"enable-var-scope", cl::init(false),
|
||||||
|
cl::desc("Enables scope for regex variables. Variables with names that\n"
|
||||||
|
"do not start with '$' will be reset at the beginning of\n"
|
||||||
|
"each CHECK-LABEL block."));
|
||||||
|
|
||||||
|
static cl::opt<bool> AllowDeprecatedDagOverlap(
|
||||||
|
"allow-deprecated-dag-overlap", cl::init(false),
|
||||||
|
cl::desc("Enable overlapping among matches in a group of consecutive\n"
|
||||||
|
"CHECK-DAG directives. This option is deprecated and is only\n"
|
||||||
|
"provided for convenience as old tests are migrated to the new\n"
|
||||||
|
"non-overlapping CHECK-DAG implementation.\n"));
|
||||||
|
|
||||||
|
static cl::opt<bool> Verbose(
|
||||||
|
"v", cl::init(false), cl::ZeroOrMore,
|
||||||
|
cl::desc("Print directive pattern matches, or add them to the input dump\n"
|
||||||
|
"if enabled.\n"));
|
||||||
|
|
||||||
|
static cl::opt<bool> VerboseVerbose(
|
||||||
|
"vv", cl::init(false), cl::ZeroOrMore,
|
||||||
|
cl::desc("Print information helpful in diagnosing internal FileCheck\n"
|
||||||
|
"issues, or add it to the input dump if enabled. Implies\n"
|
||||||
|
"-v.\n"));
|
||||||
|
|
||||||
|
// The order of DumpInputValue members affects their precedence, as documented
|
||||||
|
// for -dump-input below.
|
||||||
|
enum DumpInputValue {
|
||||||
|
DumpInputNever,
|
||||||
|
DumpInputFail,
|
||||||
|
DumpInputAlways,
|
||||||
|
DumpInputHelp
|
||||||
|
};
|
||||||
|
|
||||||
|
static cl::list<DumpInputValue> DumpInputs(
|
||||||
|
"dump-input",
|
||||||
|
cl::desc("Dump input to stderr, adding annotations representing\n"
|
||||||
|
"currently enabled diagnostics. When there are multiple\n"
|
||||||
|
"occurrences of this option, the <value> that appears earliest\n"
|
||||||
|
"in the list below has precedence. The default is 'fail'.\n"),
|
||||||
|
cl::value_desc("mode"),
|
||||||
|
cl::values(clEnumValN(DumpInputHelp, "help", "Explain input dump and quit"),
|
||||||
|
clEnumValN(DumpInputAlways, "always", "Always dump input"),
|
||||||
|
clEnumValN(DumpInputFail, "fail", "Dump input on failure"),
|
||||||
|
clEnumValN(DumpInputNever, "never", "Never dump input")));
|
||||||
|
|
||||||
|
// The order of DumpInputFilterValue members affects their precedence, as
|
||||||
|
// documented for -dump-input-filter below.
|
||||||
|
enum DumpInputFilterValue {
|
||||||
|
DumpInputFilterError,
|
||||||
|
DumpInputFilterAnnotation,
|
||||||
|
DumpInputFilterAnnotationFull,
|
||||||
|
DumpInputFilterAll
|
||||||
|
};
|
||||||
|
|
||||||
|
static cl::list<DumpInputFilterValue> DumpInputFilters(
|
||||||
|
"dump-input-filter",
|
||||||
|
cl::desc("In the dump requested by -dump-input, print only input lines of\n"
|
||||||
|
"kind <value> plus any context specified by -dump-input-context.\n"
|
||||||
|
"When there are multiple occurrences of this option, the <value>\n"
|
||||||
|
"that appears earliest in the list below has precedence. The\n"
|
||||||
|
"default is 'error' when -dump-input=fail, and it's 'all' when\n"
|
||||||
|
"-dump-input=always.\n"),
|
||||||
|
cl::values(clEnumValN(DumpInputFilterAll, "all", "All input lines"),
|
||||||
|
clEnumValN(DumpInputFilterAnnotationFull, "annotation-full",
|
||||||
|
"Input lines with annotations"),
|
||||||
|
clEnumValN(DumpInputFilterAnnotation, "annotation",
|
||||||
|
"Input lines with starting points of annotations"),
|
||||||
|
clEnumValN(DumpInputFilterError, "error",
|
||||||
|
"Input lines with starting points of error "
|
||||||
|
"annotations")));
|
||||||
|
|
||||||
|
static cl::list<unsigned> DumpInputContexts(
|
||||||
|
"dump-input-context", cl::value_desc("N"),
|
||||||
|
cl::desc("In the dump requested by -dump-input, print <N> input lines\n"
|
||||||
|
"before and <N> input lines after any lines specified by\n"
|
||||||
|
"-dump-input-filter. When there are multiple occurrences of\n"
|
||||||
|
"this option, the largest specified <N> has precedence. The\n"
|
||||||
|
"default is 5.\n"));
|
||||||
|
|
||||||
|
typedef cl::list<std::string>::const_iterator prefix_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void DumpCommandLine(int argc, char **argv) {
|
||||||
|
errs() << "FileCheck command line: ";
|
||||||
|
for (int I = 0; I < argc; I++)
|
||||||
|
errs() << " " << argv[I];
|
||||||
|
errs() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MarkerStyle {
|
||||||
|
/// The starting char (before tildes) for marking the line.
|
||||||
|
char Lead;
|
||||||
|
/// What color to use for this annotation.
|
||||||
|
raw_ostream::Colors Color;
|
||||||
|
/// A note to follow the marker, or empty string if none.
|
||||||
|
std::string Note;
|
||||||
|
/// Does this marker indicate inclusion by -dump-input-filter=error?
|
||||||
|
bool FiltersAsError;
|
||||||
|
MarkerStyle() {}
|
||||||
|
MarkerStyle(char Lead, raw_ostream::Colors Color,
|
||||||
|
const std::string &Note = "", bool FiltersAsError = false)
|
||||||
|
: Lead(Lead), Color(Color), Note(Note), FiltersAsError(FiltersAsError) {
|
||||||
|
assert((!FiltersAsError || !Note.empty()) &&
|
||||||
|
"expected error diagnostic to have note");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
|
||||||
|
switch (MatchTy) {
|
||||||
|
case FileCheckDiag::MatchFoundAndExpected:
|
||||||
|
return MarkerStyle('^', raw_ostream::GREEN);
|
||||||
|
case FileCheckDiag::MatchFoundButExcluded:
|
||||||
|
return MarkerStyle('!', raw_ostream::RED, "error: no match expected",
|
||||||
|
/*FiltersAsError=*/true);
|
||||||
|
case FileCheckDiag::MatchFoundButWrongLine:
|
||||||
|
return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line",
|
||||||
|
/*FiltersAsError=*/true);
|
||||||
|
case FileCheckDiag::MatchFoundButDiscarded:
|
||||||
|
return MarkerStyle('!', raw_ostream::CYAN,
|
||||||
|
"discard: overlaps earlier match");
|
||||||
|
case FileCheckDiag::MatchNoneAndExcluded:
|
||||||
|
return MarkerStyle('X', raw_ostream::GREEN);
|
||||||
|
case FileCheckDiag::MatchNoneButExpected:
|
||||||
|
return MarkerStyle('X', raw_ostream::RED, "error: no match found",
|
||||||
|
/*FiltersAsError=*/true);
|
||||||
|
case FileCheckDiag::MatchFuzzy:
|
||||||
|
return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match",
|
||||||
|
/*FiltersAsError=*/true);
|
||||||
|
}
|
||||||
|
llvm_unreachable_internal("unexpected match type");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpInputAnnotationHelp(raw_ostream &OS) {
|
||||||
|
OS << "The following description was requested by -dump-input=help to\n"
|
||||||
|
<< "explain the input dump printed by FileCheck.\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "Related command-line options:\n"
|
||||||
|
<< "\n"
|
||||||
|
<< " - -dump-input=<value> enables or disables the input dump\n"
|
||||||
|
<< " - -dump-input-filter=<value> filters the input lines\n"
|
||||||
|
<< " - -dump-input-context=<N> adjusts the context of filtered lines\n"
|
||||||
|
<< " - -v and -vv add more annotations\n"
|
||||||
|
<< " - -color forces colors to be enabled both in the dump and below\n"
|
||||||
|
<< " - -help documents the above options in more detail\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "These options can also be set via FILECHECK_OPTS. For example, for\n"
|
||||||
|
<< "maximum debugging output on failures:\n"
|
||||||
|
<< "\n"
|
||||||
|
<< " $ FILECHECK_OPTS='-dump-input-filter=all -vv -color' ninja check\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "Input dump annotation format:\n"
|
||||||
|
<< "\n";
|
||||||
|
|
||||||
|
// Labels for input lines.
|
||||||
|
OS << " - ";
|
||||||
|
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";
|
||||||
|
OS << " labels line number L of the input file\n";
|
||||||
|
|
||||||
|
// Labels for annotation lines.
|
||||||
|
OS << " - ";
|
||||||
|
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";
|
||||||
|
OS << " labels the only match result for either (1) a pattern of type T"
|
||||||
|
<< " from\n"
|
||||||
|
<< " line L of the check file if L is an integer or (2) the"
|
||||||
|
<< " I-th implicit\n"
|
||||||
|
<< " pattern if L is \"imp\" followed by an integer "
|
||||||
|
<< "I (index origin one)\n";
|
||||||
|
OS << " - ";
|
||||||
|
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";
|
||||||
|
OS << " labels the Nth match result for such a pattern\n";
|
||||||
|
|
||||||
|
// Markers on annotation lines.
|
||||||
|
OS << " - ";
|
||||||
|
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";
|
||||||
|
OS << " marks good match (reported if -v)\n"
|
||||||
|
<< " - ";
|
||||||
|
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";
|
||||||
|
OS << " marks bad match, such as:\n"
|
||||||
|
<< " - CHECK-NEXT on same line as previous match (error)\n"
|
||||||
|
<< " - CHECK-NOT found (error)\n"
|
||||||
|
<< " - CHECK-DAG overlapping match (discarded, reported if "
|
||||||
|
<< "-vv)\n"
|
||||||
|
<< " - ";
|
||||||
|
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";
|
||||||
|
OS << " marks search range when no match is found, such as:\n"
|
||||||
|
<< " - CHECK-NEXT not found (error)\n"
|
||||||
|
<< " - CHECK-NOT not found (success, reported if -vv)\n"
|
||||||
|
<< " - CHECK-DAG not found after discarded matches (error)\n"
|
||||||
|
<< " - ";
|
||||||
|
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?";
|
||||||
|
OS << " marks fuzzy match when no match is found\n";
|
||||||
|
|
||||||
|
// Elided lines.
|
||||||
|
OS << " - ";
|
||||||
|
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "...";
|
||||||
|
OS << " indicates elided input lines and annotations, as specified by\n"
|
||||||
|
<< " -dump-input-filter and -dump-input-context\n";
|
||||||
|
|
||||||
|
// Colors.
|
||||||
|
OS << " - colors ";
|
||||||
|
WithColor(OS, raw_ostream::GREEN, true) << "success";
|
||||||
|
OS << ", ";
|
||||||
|
WithColor(OS, raw_ostream::RED, true) << "error";
|
||||||
|
OS << ", ";
|
||||||
|
WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match";
|
||||||
|
OS << ", ";
|
||||||
|
WithColor(OS, raw_ostream::CYAN, true, false) << "discarded match";
|
||||||
|
OS << ", ";
|
||||||
|
WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input";
|
||||||
|
OS << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An annotation for a single input line.
|
||||||
|
struct InputAnnotation {
|
||||||
|
/// The index of the match result across all checks
|
||||||
|
unsigned DiagIndex;
|
||||||
|
/// The label for this annotation.
|
||||||
|
std::string Label;
|
||||||
|
/// Is this the initial fragment of a diagnostic that has been broken across
|
||||||
|
/// multiple lines?
|
||||||
|
bool IsFirstLine;
|
||||||
|
/// What input line (one-origin indexing) this annotation marks. This might
|
||||||
|
/// be different from the starting line of the original diagnostic if
|
||||||
|
/// !IsFirstLine.
|
||||||
|
unsigned InputLine;
|
||||||
|
/// The column range (one-origin indexing, open end) in which to mark the
|
||||||
|
/// input line. If InputEndCol is UINT_MAX, treat it as the last column
|
||||||
|
/// before the newline.
|
||||||
|
unsigned InputStartCol, InputEndCol;
|
||||||
|
/// The marker to use.
|
||||||
|
MarkerStyle Marker;
|
||||||
|
/// Whether this annotation represents a good match for an expected pattern.
|
||||||
|
bool FoundAndExpectedMatch;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Get an abbreviation for the check type.
|
||||||
|
std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
|
||||||
|
switch (Ty) {
|
||||||
|
case Check::CheckPlain:
|
||||||
|
if (Ty.getCount() > 1)
|
||||||
|
return "count";
|
||||||
|
return "check";
|
||||||
|
case Check::CheckNext:
|
||||||
|
return "next";
|
||||||
|
case Check::CheckSame:
|
||||||
|
return "same";
|
||||||
|
case Check::CheckNot:
|
||||||
|
return "not";
|
||||||
|
case Check::CheckDAG:
|
||||||
|
return "dag";
|
||||||
|
case Check::CheckLabel:
|
||||||
|
return "label";
|
||||||
|
case Check::CheckEmpty:
|
||||||
|
return "empty";
|
||||||
|
case Check::CheckComment:
|
||||||
|
return "com";
|
||||||
|
case Check::CheckEOF:
|
||||||
|
return "eof";
|
||||||
|
case Check::CheckBadNot:
|
||||||
|
return "bad-not";
|
||||||
|
case Check::CheckBadCount:
|
||||||
|
return "bad-count";
|
||||||
|
case Check::CheckNone:
|
||||||
|
llvm_unreachable("invalid FileCheckType");
|
||||||
|
}
|
||||||
|
llvm_unreachable("unknown FileCheckType");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
|
||||||
|
const std::pair<unsigned, unsigned> &ImpPatBufferIDRange,
|
||||||
|
const std::vector<FileCheckDiag> &Diags,
|
||||||
|
std::vector<InputAnnotation> &Annotations,
|
||||||
|
unsigned &LabelWidth) {
|
||||||
|
// How many diagnostics have we seen so far?
|
||||||
|
unsigned DiagCount = 0;
|
||||||
|
// How many diagnostics has the current check seen so far?
|
||||||
|
unsigned CheckDiagCount = 0;
|
||||||
|
// What's the widest label?
|
||||||
|
LabelWidth = 0;
|
||||||
|
for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd;
|
||||||
|
++DiagItr) {
|
||||||
|
InputAnnotation A;
|
||||||
|
A.DiagIndex = DiagCount++;
|
||||||
|
|
||||||
|
// Build label, which uniquely identifies this check result.
|
||||||
|
unsigned CheckBufferID = SM.FindBufferContainingLoc(DiagItr->CheckLoc);
|
||||||
|
auto CheckLineAndCol =
|
||||||
|
SM.getLineAndColumn(DiagItr->CheckLoc, CheckBufferID);
|
||||||
|
llvm::raw_string_ostream Label(A.Label);
|
||||||
|
Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":";
|
||||||
|
if (CheckBufferID == CheckFileBufferID)
|
||||||
|
Label << CheckLineAndCol.first;
|
||||||
|
else if (ImpPatBufferIDRange.first <= CheckBufferID &&
|
||||||
|
CheckBufferID < ImpPatBufferIDRange.second)
|
||||||
|
Label << "imp" << (CheckBufferID - ImpPatBufferIDRange.first + 1);
|
||||||
|
else
|
||||||
|
llvm_unreachable("expected diagnostic's check location to be either in "
|
||||||
|
"the check file or for an implicit pattern");
|
||||||
|
unsigned CheckDiagIndex = UINT_MAX;
|
||||||
|
auto DiagNext = std::next(DiagItr);
|
||||||
|
if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy &&
|
||||||
|
DiagItr->CheckLoc == DiagNext->CheckLoc)
|
||||||
|
CheckDiagIndex = CheckDiagCount++;
|
||||||
|
else if (CheckDiagCount) {
|
||||||
|
CheckDiagIndex = CheckDiagCount;
|
||||||
|
CheckDiagCount = 0;
|
||||||
|
}
|
||||||
|
if (CheckDiagIndex != UINT_MAX)
|
||||||
|
Label << "'" << CheckDiagIndex;
|
||||||
|
Label.flush();
|
||||||
|
LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size());
|
||||||
|
|
||||||
|
A.Marker = GetMarker(DiagItr->MatchTy);
|
||||||
|
A.FoundAndExpectedMatch =
|
||||||
|
DiagItr->MatchTy == FileCheckDiag::MatchFoundAndExpected;
|
||||||
|
|
||||||
|
// Compute the mark location, and break annotation into multiple
|
||||||
|
// annotations if it spans multiple lines.
|
||||||
|
A.IsFirstLine = true;
|
||||||
|
A.InputLine = DiagItr->InputStartLine;
|
||||||
|
A.InputStartCol = DiagItr->InputStartCol;
|
||||||
|
if (DiagItr->InputStartLine == DiagItr->InputEndLine) {
|
||||||
|
// Sometimes ranges are empty in order to indicate a specific point, but
|
||||||
|
// that would mean nothing would be marked, so adjust the range to
|
||||||
|
// include the following character.
|
||||||
|
A.InputEndCol =
|
||||||
|
std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);
|
||||||
|
Annotations.push_back(A);
|
||||||
|
} else {
|
||||||
|
assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&
|
||||||
|
"expected input range not to be inverted");
|
||||||
|
A.InputEndCol = UINT_MAX;
|
||||||
|
Annotations.push_back(A);
|
||||||
|
for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine;
|
||||||
|
L <= E; ++L) {
|
||||||
|
// If a range ends before the first column on a line, then it has no
|
||||||
|
// characters on that line, so there's nothing to render.
|
||||||
|
if (DiagItr->InputEndCol == 1 && L == E)
|
||||||
|
break;
|
||||||
|
InputAnnotation B;
|
||||||
|
B.DiagIndex = A.DiagIndex;
|
||||||
|
B.Label = A.Label;
|
||||||
|
B.IsFirstLine = false;
|
||||||
|
B.InputLine = L;
|
||||||
|
B.Marker = A.Marker;
|
||||||
|
B.Marker.Lead = '~';
|
||||||
|
B.Marker.Note = "";
|
||||||
|
B.InputStartCol = 1;
|
||||||
|
if (L != E)
|
||||||
|
B.InputEndCol = UINT_MAX;
|
||||||
|
else
|
||||||
|
B.InputEndCol = DiagItr->InputEndCol;
|
||||||
|
B.FoundAndExpectedMatch = A.FoundAndExpectedMatch;
|
||||||
|
Annotations.push_back(B);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned FindInputLineInFilter(
|
||||||
|
DumpInputFilterValue DumpInputFilter, unsigned CurInputLine,
|
||||||
|
const std::vector<InputAnnotation>::iterator &AnnotationBeg,
|
||||||
|
const std::vector<InputAnnotation>::iterator &AnnotationEnd) {
|
||||||
|
if (DumpInputFilter == DumpInputFilterAll)
|
||||||
|
return CurInputLine;
|
||||||
|
for (auto AnnotationItr = AnnotationBeg; AnnotationItr != AnnotationEnd;
|
||||||
|
++AnnotationItr) {
|
||||||
|
switch (DumpInputFilter) {
|
||||||
|
case DumpInputFilterAll:
|
||||||
|
llvm_unreachable("unexpected DumpInputFilterAll");
|
||||||
|
break;
|
||||||
|
case DumpInputFilterAnnotationFull:
|
||||||
|
return AnnotationItr->InputLine;
|
||||||
|
case DumpInputFilterAnnotation:
|
||||||
|
if (AnnotationItr->IsFirstLine)
|
||||||
|
return AnnotationItr->InputLine;
|
||||||
|
break;
|
||||||
|
case DumpInputFilterError:
|
||||||
|
if (AnnotationItr->IsFirstLine && AnnotationItr->Marker.FiltersAsError)
|
||||||
|
return AnnotationItr->InputLine;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UINT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// To OS, print a vertical ellipsis (right-justified at LabelWidth) if it would
|
||||||
|
/// occupy less lines than ElidedLines, but print ElidedLines otherwise. Either
|
||||||
|
/// way, clear ElidedLines. Thus, if ElidedLines is empty, do nothing.
|
||||||
|
static void DumpEllipsisOrElidedLines(raw_ostream &OS, std::string &ElidedLines,
|
||||||
|
unsigned LabelWidth) {
|
||||||
|
if (ElidedLines.empty())
|
||||||
|
return;
|
||||||
|
unsigned EllipsisLines = 3;
|
||||||
|
if (EllipsisLines < StringRef(ElidedLines).count('\n')) {
|
||||||
|
for (unsigned i = 0; i < EllipsisLines; ++i) {
|
||||||
|
WithColor(OS, raw_ostream::BLACK, /*Bold=*/true)
|
||||||
|
<< right_justify(".", LabelWidth);
|
||||||
|
OS << '\n';
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
OS << ElidedLines;
|
||||||
|
ElidedLines.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
|
||||||
|
DumpInputFilterValue DumpInputFilter,
|
||||||
|
unsigned DumpInputContext,
|
||||||
|
StringRef InputFileText,
|
||||||
|
std::vector<InputAnnotation> &Annotations,
|
||||||
|
unsigned LabelWidth) {
|
||||||
|
OS << "Input was:\n<<<<<<\n";
|
||||||
|
|
||||||
|
// Sort annotations.
|
||||||
|
std::sort(Annotations.begin(), Annotations.end(),
|
||||||
|
[](const InputAnnotation &A, const InputAnnotation &B) {
|
||||||
|
// 1. Sort annotations in the order of the input lines.
|
||||||
|
//
|
||||||
|
// This makes it easier to find relevant annotations while
|
||||||
|
// iterating input lines in the implementation below. FileCheck
|
||||||
|
// does not always produce diagnostics in the order of input
|
||||||
|
// lines due to, for example, CHECK-DAG and CHECK-NOT.
|
||||||
|
if (A.InputLine != B.InputLine)
|
||||||
|
return A.InputLine < B.InputLine;
|
||||||
|
// 2. Sort annotations in the temporal order FileCheck produced
|
||||||
|
// their associated diagnostics.
|
||||||
|
//
|
||||||
|
// This sort offers several benefits:
|
||||||
|
//
|
||||||
|
// A. On a single input line, the order of annotations reflects
|
||||||
|
// the FileCheck logic for processing directives/patterns.
|
||||||
|
// This can be helpful in understanding cases in which the
|
||||||
|
// order of the associated directives/patterns in the check
|
||||||
|
// file or on the command line either (i) does not match the
|
||||||
|
// temporal order in which FileCheck looks for matches for the
|
||||||
|
// directives/patterns (due to, for example, CHECK-LABEL,
|
||||||
|
// CHECK-NOT, or `--implicit-check-not`) or (ii) does match
|
||||||
|
// that order but does not match the order of those
|
||||||
|
// diagnostics along an input line (due to, for example,
|
||||||
|
// CHECK-DAG).
|
||||||
|
//
|
||||||
|
// On the other hand, because our presentation format presents
|
||||||
|
// input lines in order, there's no clear way to offer the
|
||||||
|
// same benefit across input lines. For consistency, it might
|
||||||
|
// then seem worthwhile to have annotations on a single line
|
||||||
|
// also sorted in input order (that is, by input column).
|
||||||
|
// However, in practice, this appears to be more confusing
|
||||||
|
// than helpful. Perhaps it's intuitive to expect annotations
|
||||||
|
// to be listed in the temporal order in which they were
|
||||||
|
// produced except in cases the presentation format obviously
|
||||||
|
// and inherently cannot support it (that is, across input
|
||||||
|
// lines).
|
||||||
|
//
|
||||||
|
// B. When diagnostics' annotations are split among multiple
|
||||||
|
// input lines, the user must track them from one input line
|
||||||
|
// to the next. One property of the sort chosen here is that
|
||||||
|
// it facilitates the user in this regard by ensuring the
|
||||||
|
// following: when comparing any two input lines, a
|
||||||
|
// diagnostic's annotations are sorted in the same position
|
||||||
|
// relative to all other diagnostics' annotations.
|
||||||
|
return A.DiagIndex < B.DiagIndex;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Compute the width of the label column.
|
||||||
|
const unsigned char *InputFilePtr = InputFileText.bytes_begin(),
|
||||||
|
*InputFileEnd = InputFileText.bytes_end();
|
||||||
|
unsigned LineCount = InputFileText.count('\n');
|
||||||
|
if (InputFileEnd[-1] != '\n')
|
||||||
|
++LineCount;
|
||||||
|
unsigned LineNoWidth = std::log10(LineCount) + 1;
|
||||||
|
// +3 below adds spaces (1) to the left of the (right-aligned) line numbers
|
||||||
|
// on input lines and (2) to the right of the (left-aligned) labels on
|
||||||
|
// annotation lines so that input lines and annotation lines are more
|
||||||
|
// visually distinct. For example, the spaces on the annotation lines ensure
|
||||||
|
// that input line numbers and check directive line numbers never align
|
||||||
|
// horizontally. Those line numbers might not even be for the same file.
|
||||||
|
// One space would be enough to achieve that, but more makes it even easier
|
||||||
|
// to see.
|
||||||
|
LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;
|
||||||
|
|
||||||
|
// Print annotated input lines.
|
||||||
|
unsigned PrevLineInFilter = 0; // 0 means none so far
|
||||||
|
unsigned NextLineInFilter = 0; // 0 means uncomputed, UINT_MAX means none
|
||||||
|
std::string ElidedLines;
|
||||||
|
raw_string_ostream ElidedLinesOS(ElidedLines);
|
||||||
|
ColorMode TheColorMode =
|
||||||
|
WithColor(OS).colorsEnabled() ? ColorMode::Enable : ColorMode::Disable;
|
||||||
|
if (TheColorMode == ColorMode::Enable)
|
||||||
|
ElidedLinesOS.enable_colors(true);
|
||||||
|
auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();
|
||||||
|
for (unsigned Line = 1;
|
||||||
|
InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;
|
||||||
|
++Line) {
|
||||||
|
const unsigned char *InputFileLine = InputFilePtr;
|
||||||
|
|
||||||
|
// Compute the previous and next line included by the filter.
|
||||||
|
if (NextLineInFilter < Line)
|
||||||
|
NextLineInFilter = FindInputLineInFilter(DumpInputFilter, Line,
|
||||||
|
AnnotationItr, AnnotationEnd);
|
||||||
|
assert(NextLineInFilter && "expected NextLineInFilter to be computed");
|
||||||
|
if (NextLineInFilter == Line)
|
||||||
|
PrevLineInFilter = Line;
|
||||||
|
|
||||||
|
// Elide this input line and its annotations if it's not within the
|
||||||
|
// context specified by -dump-input-context of an input line included by
|
||||||
|
// -dump-input-filter. However, in case the resulting ellipsis would occupy
|
||||||
|
// more lines than the input lines and annotations it elides, buffer the
|
||||||
|
// elided lines and annotations so we can print them instead.
|
||||||
|
raw_ostream *LineOS = &OS;
|
||||||
|
if ((!PrevLineInFilter || PrevLineInFilter + DumpInputContext < Line) &&
|
||||||
|
(NextLineInFilter == UINT_MAX ||
|
||||||
|
Line + DumpInputContext < NextLineInFilter))
|
||||||
|
LineOS = &ElidedLinesOS;
|
||||||
|
else {
|
||||||
|
LineOS = &OS;
|
||||||
|
DumpEllipsisOrElidedLines(OS, ElidedLinesOS.str(), LabelWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print right-aligned line number.
|
||||||
|
WithColor(*LineOS, raw_ostream::BLACK, /*Bold=*/true, /*BF=*/false,
|
||||||
|
TheColorMode)
|
||||||
|
<< format_decimal(Line, LabelWidth) << ": ";
|
||||||
|
|
||||||
|
// For the case where -v and colors are enabled, find the annotations for
|
||||||
|
// good matches for expected patterns in order to highlight everything
|
||||||
|
// else in the line. There are no such annotations if -v is disabled.
|
||||||
|
std::vector<InputAnnotation> FoundAndExpectedMatches;
|
||||||
|
if (Req.Verbose && TheColorMode == ColorMode::Enable) {
|
||||||
|
for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;
|
||||||
|
++I) {
|
||||||
|
if (I->FoundAndExpectedMatch)
|
||||||
|
FoundAndExpectedMatches.push_back(*I);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print numbered line with highlighting where there are no matches for
|
||||||
|
// expected patterns.
|
||||||
|
bool Newline = false;
|
||||||
|
{
|
||||||
|
WithColor COS(*LineOS, raw_ostream::SAVEDCOLOR, /*Bold=*/false,
|
||||||
|
/*BG=*/false, TheColorMode);
|
||||||
|
bool InMatch = false;
|
||||||
|
if (Req.Verbose)
|
||||||
|
COS.changeColor(raw_ostream::CYAN, true, true);
|
||||||
|
for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {
|
||||||
|
bool WasInMatch = InMatch;
|
||||||
|
InMatch = false;
|
||||||
|
for (auto M : FoundAndExpectedMatches) {
|
||||||
|
if (M.InputStartCol <= Col && Col < M.InputEndCol) {
|
||||||
|
InMatch = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!WasInMatch && InMatch)
|
||||||
|
COS.resetColor();
|
||||||
|
else if (WasInMatch && !InMatch)
|
||||||
|
COS.changeColor(raw_ostream::CYAN, true, true);
|
||||||
|
if (*InputFilePtr == '\n')
|
||||||
|
Newline = true;
|
||||||
|
else
|
||||||
|
COS << *InputFilePtr;
|
||||||
|
++InputFilePtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*LineOS << '\n';
|
||||||
|
unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
|
||||||
|
|
||||||
|
// Print any annotations.
|
||||||
|
while (AnnotationItr != AnnotationEnd &&
|
||||||
|
AnnotationItr->InputLine == Line) {
|
||||||
|
WithColor COS(*LineOS, AnnotationItr->Marker.Color, /*Bold=*/true,
|
||||||
|
/*BG=*/false, TheColorMode);
|
||||||
|
// The two spaces below are where the ": " appears on input lines.
|
||||||
|
COS << left_justify(AnnotationItr->Label, LabelWidth) << " ";
|
||||||
|
unsigned Col;
|
||||||
|
for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)
|
||||||
|
COS << ' ';
|
||||||
|
COS << AnnotationItr->Marker.Lead;
|
||||||
|
// If InputEndCol=UINT_MAX, stop at InputLineWidth.
|
||||||
|
for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth;
|
||||||
|
++Col)
|
||||||
|
COS << '~';
|
||||||
|
const std::string &Note = AnnotationItr->Marker.Note;
|
||||||
|
if (!Note.empty()) {
|
||||||
|
// Put the note at the end of the input line. If we were to instead
|
||||||
|
// put the note right after the marker, subsequent annotations for the
|
||||||
|
// same input line might appear to mark this note instead of the input
|
||||||
|
// line.
|
||||||
|
for (; Col <= InputLineWidth; ++Col)
|
||||||
|
COS << ' ';
|
||||||
|
COS << ' ' << Note;
|
||||||
|
}
|
||||||
|
COS << '\n';
|
||||||
|
++AnnotationItr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DumpEllipsisOrElidedLines(OS, ElidedLinesOS.str(), LabelWidth);
|
||||||
|
|
||||||
|
OS << ">>>>>>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
// Enable use of ANSI color codes because FileCheck is using them to
|
||||||
|
// highlight text.
|
||||||
|
llvm::sys::Process::UseANSIEscapeCodes(true);
|
||||||
|
|
||||||
|
InitLLVM X(argc, argv);
|
||||||
|
cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,
|
||||||
|
"FILECHECK_OPTS");
|
||||||
|
|
||||||
|
// Select -dump-input* values. The -help documentation specifies the default
|
||||||
|
// value and which value to choose if an option is specified multiple times.
|
||||||
|
// In the latter case, the general rule of thumb is to choose the value that
|
||||||
|
// provides the most information.
|
||||||
|
DumpInputValue DumpInput =
|
||||||
|
DumpInputs.empty()
|
||||||
|
? DumpInputFail
|
||||||
|
: *std::max_element(DumpInputs.begin(), DumpInputs.end());
|
||||||
|
DumpInputFilterValue DumpInputFilter;
|
||||||
|
if (DumpInputFilters.empty())
|
||||||
|
DumpInputFilter = DumpInput == DumpInputAlways ? DumpInputFilterAll
|
||||||
|
: DumpInputFilterError;
|
||||||
|
else
|
||||||
|
DumpInputFilter =
|
||||||
|
*std::max_element(DumpInputFilters.begin(), DumpInputFilters.end());
|
||||||
|
unsigned DumpInputContext = DumpInputContexts.empty()
|
||||||
|
? 5
|
||||||
|
: *std::max_element(DumpInputContexts.begin(),
|
||||||
|
DumpInputContexts.end());
|
||||||
|
|
||||||
|
if (DumpInput == DumpInputHelp) {
|
||||||
|
DumpInputAnnotationHelp(outs());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (CheckFilename.empty()) {
|
||||||
|
errs() << "<check-file> not specified\n";
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileCheckRequest Req;
|
||||||
|
for (StringRef Prefix : CheckPrefixes)
|
||||||
|
Req.CheckPrefixes.push_back(Prefix);
|
||||||
|
|
||||||
|
for (StringRef Prefix : CommentPrefixes)
|
||||||
|
Req.CommentPrefixes.push_back(Prefix);
|
||||||
|
|
||||||
|
for (StringRef CheckNot : ImplicitCheckNot)
|
||||||
|
Req.ImplicitCheckNot.push_back(CheckNot);
|
||||||
|
|
||||||
|
bool GlobalDefineError = false;
|
||||||
|
for (StringRef G : GlobalDefines) {
|
||||||
|
size_t EqIdx = G.find('=');
|
||||||
|
if (EqIdx == std::string::npos) {
|
||||||
|
errs() << "Missing equal sign in command-line definition '-D" << G
|
||||||
|
<< "'\n";
|
||||||
|
GlobalDefineError = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (EqIdx == 0) {
|
||||||
|
errs() << "Missing variable name in command-line definition '-D" << G
|
||||||
|
<< "'\n";
|
||||||
|
GlobalDefineError = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Req.GlobalDefines.push_back(G);
|
||||||
|
}
|
||||||
|
if (GlobalDefineError)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
Req.AllowEmptyInput = AllowEmptyInput;
|
||||||
|
Req.EnableVarScope = EnableVarScope;
|
||||||
|
Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;
|
||||||
|
Req.Verbose = Verbose;
|
||||||
|
Req.VerboseVerbose = VerboseVerbose;
|
||||||
|
Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;
|
||||||
|
Req.MatchFullLines = MatchFullLines;
|
||||||
|
Req.IgnoreCase = IgnoreCase;
|
||||||
|
|
||||||
|
if (VerboseVerbose)
|
||||||
|
Req.Verbose = true;
|
||||||
|
|
||||||
|
FileCheck FC(Req);
|
||||||
|
if (!FC.ValidateCheckPrefixes())
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
Regex PrefixRE = FC.buildCheckPrefixRegex();
|
||||||
|
std::string REError;
|
||||||
|
if (!PrefixRE.isValid(REError)) {
|
||||||
|
errs() << "Unable to combine check-prefix strings into a prefix regular "
|
||||||
|
"expression! This is likely a bug in FileCheck's verification of "
|
||||||
|
"the check-prefix strings. Regular expression parsing failed "
|
||||||
|
"with the following error: "
|
||||||
|
<< REError << "\n";
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceMgr SM;
|
||||||
|
|
||||||
|
// Read the expected strings from the check file.
|
||||||
|
ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =
|
||||||
|
MemoryBuffer::getFileOrSTDIN(CheckFilename);
|
||||||
|
if (std::error_code EC = CheckFileOrErr.getError()) {
|
||||||
|
errs() << "Could not open check file '" << CheckFilename
|
||||||
|
<< "': " << EC.message() << '\n';
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
MemoryBuffer &CheckFile = *CheckFileOrErr.get();
|
||||||
|
|
||||||
|
SmallString<4096> CheckFileBuffer;
|
||||||
|
StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);
|
||||||
|
|
||||||
|
unsigned CheckFileBufferID =
|
||||||
|
SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
|
||||||
|
CheckFileText, CheckFile.getBufferIdentifier()),
|
||||||
|
SMLoc());
|
||||||
|
|
||||||
|
std::pair<unsigned, unsigned> ImpPatBufferIDRange;
|
||||||
|
if (FC.readCheckFile(SM, CheckFileText, PrefixRE, &ImpPatBufferIDRange))
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
// Open the file to check and add it to SourceMgr.
|
||||||
|
ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =
|
||||||
|
MemoryBuffer::getFileOrSTDIN(InputFilename);
|
||||||
|
if (InputFilename == "-")
|
||||||
|
InputFilename = "<stdin>"; // Overwrite for improved diagnostic messages
|
||||||
|
if (std::error_code EC = InputFileOrErr.getError()) {
|
||||||
|
errs() << "Could not open input file '" << InputFilename
|
||||||
|
<< "': " << EC.message() << '\n';
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
MemoryBuffer &InputFile = *InputFileOrErr.get();
|
||||||
|
|
||||||
|
if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {
|
||||||
|
errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
|
||||||
|
DumpCommandLine(argc, argv);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallString<4096> InputFileBuffer;
|
||||||
|
StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);
|
||||||
|
|
||||||
|
SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
|
||||||
|
InputFileText, InputFile.getBufferIdentifier()),
|
||||||
|
SMLoc());
|
||||||
|
|
||||||
|
std::vector<FileCheckDiag> Diags;
|
||||||
|
int ExitCode = FC.checkInput(SM, InputFileText,
|
||||||
|
DumpInput == DumpInputNever ? nullptr : &Diags)
|
||||||
|
? EXIT_SUCCESS
|
||||||
|
: 1;
|
||||||
|
if (DumpInput == DumpInputAlways ||
|
||||||
|
(ExitCode == 1 && DumpInput == DumpInputFail)) {
|
||||||
|
errs() << "\n"
|
||||||
|
<< "Input file: " << InputFilename << "\n"
|
||||||
|
<< "Check file: " << CheckFilename << "\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "-dump-input=help explains the following input dump.\n"
|
||||||
|
<< "\n";
|
||||||
|
std::vector<InputAnnotation> Annotations;
|
||||||
|
unsigned LabelWidth;
|
||||||
|
BuildInputAnnotations(SM, CheckFileBufferID, ImpPatBufferIDRange, Diags,
|
||||||
|
Annotations, LabelWidth);
|
||||||
|
DumpAnnotatedInput(errs(), Req, DumpInputFilter, DumpInputContext,
|
||||||
|
InputFileText, Annotations, LabelWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExitCode;
|
||||||
|
}
|
|
@ -68,16 +68,17 @@ string dtype(Record* rec, bool readOnlyMem)
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
string attributes(ListInit* propertyList)
|
StringRef attributes(ListInit* propertyList)
|
||||||
{
|
{
|
||||||
string prop =
|
const auto prop = propertyList->size()
|
||||||
propertyList->size()
|
? propertyList->getElementAsRecord(0)->getName()
|
||||||
? propertyList->getElementAsRecord(0)->getName() : "";
|
: "";
|
||||||
|
|
||||||
return
|
if (prop == "IntrNoMem")
|
||||||
prop == "IntrNoMem" ? " pure @safe" :
|
return " pure @safe";
|
||||||
prop == "IntrReadArgMem" ? " pure" :
|
if (prop == "IntrReadArgMem" || prop == "IntrReadWriteArgMem")
|
||||||
prop == "IntrReadWriteArgMem" ? " pure" : "";
|
return " pure";
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void processRecord(raw_ostream& os, Record& rec, string arch)
|
void processRecord(raw_ostream& os, Record& rec, string arch)
|
||||||
|
@ -85,8 +86,8 @@ void processRecord(raw_ostream& os, Record& rec, string arch)
|
||||||
if(!rec.getValue("GCCBuiltinName"))
|
if(!rec.getValue("GCCBuiltinName"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
string builtinName = rec.getValueAsString("GCCBuiltinName");
|
const StringRef builtinName = rec.getValueAsString("GCCBuiltinName");
|
||||||
string name = rec.getName();
|
string name = rec.getName().str();
|
||||||
|
|
||||||
if(name.substr(0, 4) != "int_" || name.find(arch) == string::npos)
|
if(name.substr(0, 4) != "int_" || name.find(arch) == string::npos)
|
||||||
return;
|
return;
|
||||||
|
@ -96,9 +97,8 @@ void processRecord(raw_ostream& os, Record& rec, string arch)
|
||||||
name = string("llvm.") + name;
|
name = string("llvm.") + name;
|
||||||
|
|
||||||
ListInit* propsList = rec.getValueAsListInit("IntrProperties");
|
ListInit* propsList = rec.getValueAsListInit("IntrProperties");
|
||||||
string prop =
|
const StringRef prop =
|
||||||
propsList->size()
|
propsList->size() ? propsList->getElementAsRecord(0)->getName() : "";
|
||||||
? propsList->getElementAsRecord(0)->getName() : "";
|
|
||||||
|
|
||||||
bool readOnlyMem = prop == "IntrReadArgMem" || prop == "IntrReadMem";
|
bool readOnlyMem = prop == "IntrReadArgMem" || prop == "IntrReadMem";
|
||||||
|
|
||||||
|
@ -127,8 +127,8 @@ void processRecord(raw_ostream& os, Record& rec, string arch)
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
os << "pragma(LDC_intrinsic, \"" + name + "\")\n ";
|
os << "pragma(LDC_intrinsic, \"" << name << "\")\n ";
|
||||||
os << ret + " " + builtinName + "(";
|
os << ret << " " << builtinName << "(";
|
||||||
|
|
||||||
if(params.size())
|
if(params.size())
|
||||||
os << params[0];
|
os << params[0];
|
||||||
|
@ -136,7 +136,7 @@ void processRecord(raw_ostream& os, Record& rec, string arch)
|
||||||
for(size_t i = 1; i < params.size(); i++)
|
for(size_t i = 1; i < params.size(); i++)
|
||||||
os << ", " << params[i];
|
os << ", " << params[i];
|
||||||
|
|
||||||
os << ")" + attributes(propsList) + ";\n\n";
|
os << ")" << attributes(propsList) << ";\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string arch;
|
std::string arch;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue