[packages/ldc] up to 1.43.0

atler atler at pld-linux.org
Tue Sep 1 12:08:46 CEST 2026


commit 3f7e934b5834dcfd38d80b7b5c9e31ef21e57449
Author: Jan Palus <atler at pld-linux.org>
Date:   Tue Sep 1 12:08:26 2026 +0200

    up to 1.43.0

 git.patch              | 10578 -----------------------------------------------
 ldc-include-path.patch |     2 +-
 ldc.spec               |    24 +-
 3 files changed, 12 insertions(+), 10592 deletions(-)
---
diff --git a/ldc.spec b/ldc.spec
index 9b1bc61..849eade 100644
--- a/ldc.spec
+++ b/ldc.spec
@@ -6,27 +6,26 @@
 %bcond_without	geany		# geany autocompletion support
 %bcond_with	jit		# dynamic compilation support (JIT) (LLVM 18/19 only)
 
-%define		rel		3
+%define		rel		1
 
-%define	bootstrap_version 1.42.0
+%define	bootstrap_version 1.43.0
 Summary:	LLVM D Compiler
 Summary(pl.UTF-8):	Kompilator D oparty na LLVM
 Name:		ldc
-Version:	1.42.0
+Version:	1.43.0
 Release:	%{rel}
 # The DMD frontend in dmd/* GPL version 1 or artistic license
 # The files gen/asmstmt.cpp and gen/asm-*.hG PL version 2+ or artistic license
 License:	BSD
 Source0:	https://github.com/ldc-developers/ldc/releases/download/v%{version}/%{name}-%{version}-src.tar.gz
-# Source0-md5:	a18a249c2a3d487f79b831fef3d446b9
+# Source0-md5:	a07371f8d988010e98eed3143367c1fe
 Source1:	https://github.com/ldc-developers/ldc/releases/download/v%{bootstrap_version}/%{name}2-%{bootstrap_version}-linux-x86_64.tar.xz
-# Source1-md5:	1b813099a0eaeff0b7353780c0b43c8a
+# Source1-md5:	e02a0763e81134ffba110f39b48f0565
 # for aarch64 bootstrap: https://github.com/ldc-developers/ldc/releases/download/v%{bootstrap_version}/ldc2-%{bootstrap_version}-linux-aarch64.tar.xz
 Source3:	macros.%{name}
 Patch0:		%{name}-include-path.patch
 Patch1:		%{name}-no-default-rpath.patch
 Patch2:		%{name}-dmd.patch
-Patch3:		git.patch
 URL:		https://github.com/ldc-developers/ldc
 # for llvm < 16
 #BuildRequires:	SPIRV-LLVM-Translator-devel
@@ -128,7 +127,6 @@ Obsługa automatycznego dopełniania dla biblioteki Phobos w IDE geany.
 %patch -P0 -p1
 %patch -P1 -p1
 %patch -P2 -p1
-%patch -P3 -p1
 
 %if %{with geany}
 # temp geany config directory for allow geany to generate tags
@@ -257,21 +255,21 @@ rm -rf $RPM_BUILD_ROOT
 %files druntime
 %defattr(644,root,root,755)
 %attr(755,root,root) %{_libdir}/libdruntime-ldc-debug-shared.so.*.*
-%ghost %{_libdir}/libdruntime-ldc-debug-shared.so.112
+%ghost %{_libdir}/libdruntime-ldc-debug-shared.so.113
 %attr(755,root,root) %{_libdir}/libdruntime-ldc-shared.so.*.*
-%ghost %{_libdir}/libdruntime-ldc-shared.so.112
+%ghost %{_libdir}/libdruntime-ldc-shared.so.113
 %if %{with jit}
-%attr(755,root,root) %{_libdir}/libldc-jit.so.112.0
-%ghost %{_libdir}/libldc-jit.so.112
+%attr(755,root,root) %{_libdir}/libldc-jit.so.113.0
+%ghost %{_libdir}/libldc-jit.so.113
 %endif
 
 %files phobos
 %defattr(644,root,root,755)
 %doc runtime/phobos/{LICENSE_1_0.txt,README.md}
 %attr(755,root,root) %{_libdir}/libphobos2-ldc-debug-shared.so.*.*
-%ghost %{_libdir}/libphobos2-ldc-debug-shared.so.112
+%ghost %{_libdir}/libphobos2-ldc-debug-shared.so.113
 %attr(755,root,root) %{_libdir}/libphobos2-ldc-shared.so.*.*
-%ghost %{_libdir}/libphobos2-ldc-shared.so.112
+%ghost %{_libdir}/libphobos2-ldc-shared.so.113
 
 %if %{with geany}
 %files phobos-geany-tags
diff --git a/git.patch b/git.patch
deleted file mode 100644
index 5675698..0000000
--- a/git.patch
+++ /dev/null
@@ -1,10578 +0,0 @@
-diff --git a/CHANGELOG.md b/CHANGELOG.md
-index 647eb518f6..d9f19defa1 100644
---- a/CHANGELOG.md
-+++ b/CHANGELOG.md
-@@ -1,8 +1,13 @@
- # LDC master
- 
- #### Big news
-+- Support for [LLVM 22](https://releases.llvm.org/22.1.0/docs/ReleaseNotes.html). The prebuilt packages use v22.1.2. (#5097, #5102)
-+- Minimum LLVM version raised to 18. (#5094)
-+- DMD-style inline assembly: `asm { naked; }` is now much less of a special case wrt. codegen - such naked functions are now emitted as if `asm { naked; }` was replaced with the `@naked` function UDA. IR-wise, they are not emitted as module-level asm blobs anymore, but regular IR functions. This should lift a few former `asm { naked; }`-specific restrictions and fixed at least one LTO issue. (#5041)
-+- Predefined version `LDC_LLVM_*` now only contains the LLVM major version, i.e., former `version (LDC_LLVM_1801)` with LLVM v18.1 is now `version (LDC_LLVM_18)`. Use `ldc.intrinsics.LLVM_version` for backwards compatibility if really needed. (#5109)
- 
- #### Platform support
-+- Supports LLVM 18 - 22.
- 
- #### Bug fixes
- 
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 81ca3effa7..83584dcae8 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -29,14 +29,13 @@ include(BuildDExecutable)
- # Locate LLVM.
- #
- 
--find_package(LLVM 15.0 REQUIRED
-+find_package(LLVM 18.0 REQUIRED
-     all-targets analysis asmparser asmprinter bitreader bitwriter codegen core
-     debuginfodwarf debuginfomsf debuginfopdb demangle
-     instcombine ipo instrumentation irreader libdriver linker lto mc
-     mcdisassembler mcparser objcarcopts object option profiledata scalaropts
-     selectiondag support tablegen target transformutils vectorize
-     windowsdriver windowsmanifest symbolize ${EXTRA_LLVM_MODULES})
--math(EXPR LDC_LLVM_VER ${LLVM_VERSION_MAJOR}*100+${LLVM_VERSION_MINOR})
- message(STATUS "Using LLVM Version ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
- # Remove LLVMTableGen library from list of libraries
- string(REGEX MATCH "[^;]*LLVMTableGen[^;]*" LLVM_TABLEGEN_LIBRARY "${LLVM_LIBRARIES}")
-@@ -49,7 +48,7 @@ endforeach()
- 
- # Set MLIR support variables if it is found.
- # FIXME: LLVM 14+ (`mlir::OwningModuleRef` replacement)
--if(NOT LDC_WITH_MLIR STREQUAL "OFF" AND LDC_LLVM_VER LESS 1400)
-+if(NOT LDC_WITH_MLIR STREQUAL "OFF" AND LLVM_VERSION_MAJOR LESS 14)
-     include(FindMLIR)
-     if(MLIR_FOUND)
-         message(STATUS "-- Building LDC with MLIR support (${MLIR_ROOT_DIR})")
-@@ -61,46 +60,6 @@ if(NOT LDC_WITH_MLIR STREQUAL "OFF" AND LDC_LLVM_VER LESS 1400)
-     endif()
- endif()
- 
--# Check and adapt for LLVMSPIRVLib (Khronos SPIRV-LLVM-Translator)
--set(LLVM_SPIRV_FOUND OFF)
--if (LDC_LLVM_VER LESS 1600)
--if(MSVC)
--    if(EXISTS "${LLVM_LIBRARY_DIRS}/LLVMSPIRVLib.lib")
--        set(LLVM_SPIRV_FOUND ON)
--        set(LLVM_LIBRARIES "${LLVM_LIBRARY_DIRS}/LLVMSPIRVLib.lib" ${LLVM_LIBRARIES})
--    endif()
--else()
--    if((EXISTS "${LLVM_LIBRARY_DIRS}/libLLVMSPIRVLib.a") OR
--       (EXISTS "${LLVM_LIBRARY_DIRS}/libLLVMSPIRVLib.so") OR
--       (EXISTS "${LLVM_LIBRARY_DIRS}/libLLVMSPIRVLib.dylib"))
--        set(LLVM_SPIRV_FOUND ON)
--        set(LLVM_LIBRARIES -lLLVMSPIRVLib ${LLVM_LIBRARIES})
--    endif()
--endif()
--if(NOT LLVM_SPIRV_FOUND)
--    find_package(PkgConfig)
--    if(PkgConfig_FOUND)
--        if(MSVC)
--            # make pkg-config use -LC:\path\to\build\LLVMSPIRVLib.lib not -L-lLLVMSPIRVLib
--            set(PKG_CONFIG_EXECUTABLE "${PKG_CONFIG_EXECUTABLE} --msvc-syntax")
--        endif()
--        pkg_check_modules(LLVM_SPIRV LLVMSPIRVLib)
--        if(LLVM_SPIRV_FOUND)
--            set(LLVM_SPIRV_FOUND ON) # translate 1 to ON
--            include_directories(${LLVM_SPIRV_INCLUDE_DIRS})
--        else()
--            set(LLVM_SPIRV_FOUND OFF)
--        endif()
--    endif()
--endif()
--if(LLVM_SPIRV_FOUND)
--    message(STATUS "-- Building LDC with SPIR-V support")
--    add_definitions("-DLDC_LLVM_SUPPORTED_TARGET_SPIRV=1")
--else()
--    message(STATUS "-- Building LDC without SPIR-V support: not found")
--endif()
--endif()
--
- #
- # Get info about used Linux distribution.
- #
-@@ -137,6 +96,9 @@ set(ALTERNATIVE_MALLOC_O   ""     CACHE STRING "If specified, adds ALTERNATIVE_M
- # Most linux distributions have a policy of not bundling dependencies like zlib
- set(PHOBOS_SYSTEM_ZLIB OFF CACHE BOOL "Use system zlib instead of Phobos' vendored version")
- 
-+# Force use of softfloat for compiler
-+option(LDC_FORCE_SOFTFLOAT_REAL "Force LDC to be built with 80-bit real in software" OFF)
-+
- if(D_VERSION EQUAL 1)
-     message(FATAL_ERROR "D version 1 is no longer supported.
- Please consider using D version 2 or checkout the 'd1' git branch for the last version supporting D version 1.")
-@@ -175,6 +137,7 @@ if(NOT MSVC_IDE)
- endif()
- 
- if(MSVC)
-+    set(LDC_FORCE_SOFTFLOAT_REAL ON)
-     if(CMAKE_SIZEOF_VOID_P EQUAL 8)
-         message(STATUS "Let D host compiler output 64-bit object files")
-         append("-m64" DFLAGS_BASE)
-@@ -206,6 +169,11 @@ if(MSVC)
-     endforeach()
- endif()
- 
-+if (LDC_FORCE_SOFTFLOAT_REAL)
-+    append("-version=LDC_real_softfloat" DFLAGS_LDC)
-+    append("-DLDC_real_softfloat" LDC_CXXFLAGS)
-+endif()
-+
- # Use separate compiler flags for the frontend and for the LDC-specific parts,
- # as enabling warnings on the DMD frontend only leads to a lot of clutter in
- # the output (LLVM_CXXFLAGS sometimes already includes -Wall).
-@@ -435,10 +403,8 @@ include(HandleLTOPGOBuildOptions)
- set(LDC_DYNAMIC_COMPILE "AUTO" CACHE STRING "Support dynamic compilation (ON|OFF). Enabled by default; not supported for LLVM < 18.")
- option(LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES "Use custom LDC passes in jit" ON)
- if(LDC_DYNAMIC_COMPILE STREQUAL "AUTO")
--    if(LDC_LLVM_VER LESS 1800)
--        set(LDC_DYNAMIC_COMPILE OFF)
-     # FIXME: dynamic-compile regressions with LLVM 20
--    elseif(LDC_LLVM_VER LESS 2000)
-+    if(LLVM_VERSION_MAJOR LESS 20)
-         set(LDC_DYNAMIC_COMPILE ON)
-     else()
-         set(LDC_DYNAMIC_COMPILE OFF)
-@@ -475,13 +441,11 @@ append("-J${PROJECT_SOURCE_DIR}/dmd/res" DFLAGS_LDC)
- 
- append("-version=IN_LLVM" DFLAGS_LDC)
- append("-DIN_LLVM" LDC_CXXFLAGS)
--append("-DOPAQUE_VTBLS" LDC_CXXFLAGS)
- # Predefine LDC_INSTALL_PREFIX as raw string literal, requiring shell + CMake escaping.
- # E.g., for CMAKE_INSTALL_PREFIX=`C:\dir with space`:
- #   g++ "-DLDC_INSTALL_PREFIX=R\"(C:\dir with space)\"" ...
- #   => LDC_INSTALL_PREFIX defined as `R"(C:\dir with space)"`
- append("\"-DLDC_INSTALL_PREFIX=R\\\"(${CMAKE_INSTALL_PREFIX})\\\"\"" LDC_CXXFLAGS)
--append("-DLDC_LLVM_VER=${LDC_LLVM_VER}" LDC_CXXFLAGS)
- append("\"-DLDC_LIBDIR_SUFFIX=R\\\"(${LIB_SUFFIX})\\\"\"" LDC_CXXFLAGS)
- append("-DLDC_HOST_${D_COMPILER_ID}=1" LDC_CXXFLAGS)
- append("-DLDC_HOST_FE_VER=${D_COMPILER_FE_VERSION}" LDC_CXXFLAGS)
-@@ -580,9 +544,6 @@ if(WIN32)
- elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
-     target_link_libraries(${LDC_LIB} dl)
- endif()
--if(LLVM_SPIRV_FOUND)
--    target_link_libraries(${LDC_LIB} ${LLVM_SPIRV_LIBRARIES} ${LLVM_SPIRV_LDFLAGS})
--endif()
- 
- set(LDC_EXE_FULL ${PROJECT_BINARY_DIR}/bin/${LDC_EXE_NAME}${CMAKE_EXECUTABLE_SUFFIX})
- set(LDMD_EXE_FULL ${PROJECT_BINARY_DIR}/bin/${LDMD_EXE_NAME}${CMAKE_EXECUTABLE_SUFFIX})
-@@ -601,19 +562,17 @@ if(MSVC)
-     endif()
- endif()
- if(LDC_WITH_LLD)
--    if(MSVC)
--        list(APPEND LDC_LINKERFLAG_LIST LLVMSymbolize.lib)
--    else()
--        set(LDC_LINKERFLAG_LIST -lLLVMSymbolize ${LDC_LINKERFLAG_LIST})
-+    if(LLVM_VERSION_MAJOR GREATER 21)
-+        if(MSVC)
-+            list(APPEND LDC_LINKERFLAG_LIST LLVMDTLTO.lib)
-+        else()
-+            set(LDC_LINKERFLAG_LIST -lLLVMDTLTO ${LDC_LINKERFLAG_LIST})
-+        endif()
-     endif()
-     if(MSVC)
--        list(APPEND LDC_LINKERFLAG_LIST lldMinGW.lib lldCOFF.lib lldELF.lib lldMachO.lib lldWasm.lib lldCommon.lib)
-+        list(APPEND LDC_LINKERFLAG_LIST lldMinGW.lib lldCOFF.lib lldELF.lib lldMachO.lib lldWasm.lib lldCommon.lib LLVMSymbolize.lib)
-     else()
--        set(LDC_LINKERFLAG_LIST -llldMinGW -llldCOFF -llldELF -llldMachO -llldWasm -llldCommon ${LDC_LINKERFLAG_LIST})
--    endif()
--    if(APPLE)
--        # LLD 13.0.0 on Mac needs libxar
--        list(APPEND LDC_LINKERFLAG_LIST -lxar)
-+        set(LDC_LINKERFLAG_LIST -llldMinGW -llldCOFF -llldELF -llldMachO -llldWasm -llldCommon -lLLVMSymbolize ${LDC_LINKERFLAG_LIST})
-     endif()
-     if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
-         # FreeBSD LLVM port links to zstd, but does not convey this information via CMake
-@@ -799,11 +758,7 @@ endif()
- # another directory.
- set(COMPILER_RT_BASE_DIR "${LLVM_LIBRARY_DIRS}/clang" CACHE PATH "Base path of compiler-rt libraries. If they in are /usr/lib/clang/17/lib/linux/libclang_rt* you should set this value to /usr/lib/clang")
- set(COMPILER_RT_LIBDIR "${COMPILER_RT_BASE_DIR}")
--if(LDC_LLVM_VER LESS 1600)
--    set(COMPILER_RT_LIBDIR "${COMPILER_RT_LIBDIR}/${LLVM_VERSION_BASE_STRING}")
--else()
--    set(COMPILER_RT_LIBDIR "${COMPILER_RT_LIBDIR}/${LLVM_VERSION_MAJOR}")
--endif()
-+set(COMPILER_RT_LIBDIR "${COMPILER_RT_LIBDIR}/${LLVM_VERSION_MAJOR}")
- set(COMPILER_RT_LIBDIR "${COMPILER_RT_LIBDIR}/lib")
- if(APPLE)
-     set(COMPILER_RT_LIBDIR "${COMPILER_RT_LIBDIR}/darwin")
-@@ -881,7 +836,7 @@ if (LDC_INSTALL_LLVM_RUNTIME_LIBS)
-         if(CMAKE_SIZEOF_VOID_P EQUAL 4)
-             set(compilerrt_arch_suffix "i386")
-         endif()
--        if(LDC_LLVM_VER LESS 2000)
-+        if(LLVM_VERSION_MAJOR LESS 20)
-             copy_compilerrt_lib("clang_rt.asan-${compilerrt_arch_suffix}.lib" "ldc_rt.asan.lib" FALSE)
-             copy_compilerrt_lib("clang_rt.lsan-${compilerrt_arch_suffix}.lib" "ldc_rt.lsan.lib" FALSE)
-         else()
-@@ -956,12 +911,6 @@ add_subdirectory(tools)
- 
- set(switches)
- 
--# LLVM 16: Disable function specializations by default.
--# They cause miscompiles of e.g. the frontend for some targets (macOS x86_64 and Windows x64).
--if(LDC_LLVM_VER GREATER 1599 AND LDC_LLVM_VER LESS 1700)
--    list(APPEND switches "-func-specialization-size-threshold=1000000000")
--endif()
--
- list(APPEND switches "-defaultlib=phobos2-ldc,druntime-ldc")
- 
- makeConfSection(NAME "30-compiler" SECTION "default"
-diff --git a/README.md b/README.md
-index 9d8b8e568b..5076bf12f7 100644
---- a/README.md
-+++ b/README.md
-@@ -75,7 +75,7 @@ libraries is available on the project wiki for
- [Windows](https://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
--version (≥ 15) available, there should be no big surprises. Do not
-+version (≥ 18) available, there should be no big surprises. Do not
- forget to make sure the Phobos submodule is up to date:
- 
-     $ cd ldc
-diff --git a/cmake/Modules/FindLLVM.cmake b/cmake/Modules/FindLLVM.cmake
-index 75fa1eee29..018011e8d0 100644
---- a/cmake/Modules/FindLLVM.cmake
-+++ b/cmake/Modules/FindLLVM.cmake
-@@ -36,9 +36,6 @@ set(llvm_config_names llvm-config-21.1 llvm-config211 llvm-config-21
-                       llvm-config-20.1 llvm-config201 llvm-config-20
-                       llvm-config-19.1 llvm-config191 llvm-config-19
-                       llvm-config-18.1 llvm-config181 llvm-config-18
--                      llvm-config-17.0 llvm-config170 llvm-config-17
--                      llvm-config-16.0 llvm-config160 llvm-config-16
--                      llvm-config-15.0 llvm-config150 llvm-config-15
-                       llvm-config)
- find_program(LLVM_CONFIG
-     NAMES ${llvm_config_names}
-@@ -51,14 +48,10 @@ if(APPLE)
-         NAMES ${llvm_config_names}
-         PATHS /opt/local/libexec/llvm-21/bin
-               /opt/local/libexec/llvm-20/bin /opt/local/libexec/llvm-19/bin
--              /opt/local/libexec/llvm-18/bin /opt/local/libexec/llvm-17/bin
--              /opt/local/libexec/llvm-16/bin /opt/local/libexec/llvm-15/bin
--              /opt/local/libexec/llvm/bin
-+              /opt/local/libexec/llvm-18/bin /opt/local/libexec/llvm/bin
-               /usr/local/opt/llvm at 21/bin
-               /usr/local/opt/llvm at 20/bin /usr/local/opt/llvm at 19/bin
--              /usr/local/opt/llvm at 18/bin /usr/local/opt/llvm at 17/bin
--              /usr/local/opt/llvm at 16/bin /usr/local/opt/llvm at 15/bin
--              /usr/local/opt/llvm/bin
-+              /usr/local/opt/llvm at 18/bin /usr/local/opt/llvm/bin
-         NO_DEFAULT_PATH)
- endif()
- 
-diff --git a/dmd/declaration.h b/dmd/declaration.h
-index 7533348374..5c4562aab9 100644
---- a/dmd/declaration.h
-+++ b/dmd/declaration.h
-@@ -581,6 +581,9 @@ public:
-     VarDeclaration *v_argptr;           // '_argptr' variable
-     VarDeclarations *parameters;        // Array of VarDeclaration's for parameters
-     DsymbolTable *labtab;               // statement label symbol table
-+#if IN_LLVM
-+    Identifiers *asmLabels;             // identifiers of labels defined in DMD-style inline assembly
-+#endif
-     Dsymbol *overnext;                  // next in overload list
-     FuncDeclaration *overnext0;         // next in overload list (only used during IFTI)
-     Loc endloc;                         // location of closing curly bracket
-diff --git a/dmd/func.d b/dmd/func.d
-index 6709e32ebb..e39e233eae 100644
---- a/dmd/func.d
-+++ b/dmd/func.d
-@@ -256,6 +256,10 @@ version (IN_LLVM)
-     VarDeclaration v_argptr;            /// '_argptr' variable
-     VarDeclarations* parameters;        /// Array of VarDeclaration's for parameters
-     DsymbolTable labtab;                /// statement label symbol table
-+version (IN_LLVM)
-+{
-+    Identifiers* asmLabels;             /// identifiers of labels defined in DMD-style inline assembly
-+}
-     Dsymbol overnext;                   /// next in overload list
-     FuncDeclaration overnext0;          /// next in overload list (only used during IFTI)
-     Loc endloc;                         /// location of closing curly bracket
-diff --git a/dmd/globals.h b/dmd/globals.h
-index 9d4bf185a5..bad8e9c410 100644
---- a/dmd/globals.h
-+++ b/dmd/globals.h
-@@ -17,11 +17,7 @@
- #include "compiler.h"
- 
- #if IN_LLVM
--#if LDC_LLVM_VER < 1700
--#include "llvm/ADT/Triple.h"
--#else
- #include "llvm/TargetParser/Triple.h"
--#endif
- 
- enum OUTPUTFLAG
- {
-diff --git a/dmd/root/ctfloat.d b/dmd/root/ctfloat.d
-index 2996d7cd60..2ca9e20527 100644
---- a/dmd/root/ctfloat.d
-+++ b/dmd/root/ctfloat.d
-@@ -47,7 +47,8 @@ extern (C++) struct CTFloat
-     version (GNU)
-         enum yl2x_supported = false;
-     else
--        enum yl2x_supported = __traits(compiles, core.math.yl2x(1.0L, 2.0L));
-+        enum yl2x_supported = is(real_t == real) &&
-+                              __traits(compiles, core.math.yl2x(1.0L, 2.0L));
-     enum yl2xp1_supported = yl2x_supported;
- 
-     static void yl2x(const real_t* x, const real_t* y, real_t* res) // IN_LLVM: impure because of log2
-diff --git a/dmd/root/longdouble.d b/dmd/root/longdouble.d
-index 0bbd27a39e..9da7f09e06 100644
---- a/dmd/root/longdouble.d
-+++ b/dmd/root/longdouble.d
-@@ -11,8 +11,14 @@
- 
- module dmd.root.longdouble;
- 
--version (CRuntime_Microsoft)
-+version (LDC_real_softfloat)
- {
-+    version = EnableSoftfloat;
-+    alias longdouble = longdouble_soft;
-+}
-+else version (CRuntime_Microsoft)
-+{
-+    version = EnableSoftfloat;
-     static if (real.sizeof > 8)
-         alias longdouble = real;
-     else
-@@ -23,7 +29,7 @@ else
- 
- // longdouble_soft needed when building the backend with
- // Visual C or the frontend with LDC on Windows
--version (CRuntime_Microsoft):
-+version (EnableSoftfloat):
- extern (C++):
- nothrow:
- @nogc:
-@@ -71,7 +77,7 @@ bool initFPU()
-     return true;
- }
- 
--version(unittest) version(CRuntime_Microsoft)
-+version(unittest)
- extern(D) shared static this()
- {
-     initFPU(); // otherwise not guaranteed to be run before pure unittest below
-diff --git a/dmd/root/longdouble.h b/dmd/root/longdouble.h
-index 150b9f55e1..251be1d0f3 100644
---- a/dmd/root/longdouble.h
-+++ b/dmd/root/longdouble.h
-@@ -11,7 +11,13 @@
- 
- #pragma once
- 
--#if !_MSC_VER // has native 10 byte doubles
-+#if defined(LDC_real_softfloat)
-+#define USE_LONGDOUBLE_SOFTFLOAT 1
-+#elif defined(_MSC_VER)
-+#define USE_LONGDOUBLE_SOFTFLOAT 1
-+#endif
-+
-+#if !USE_LONGDOUBLE_SOFTFLOAT // has native 10 byte doubles
- #include <stdio.h>
- typedef long double longdouble;
- typedef volatile long double volatile_longdouble;
-diff --git a/dmd/statementsem.d b/dmd/statementsem.d
-index 987979bb88..a5be77972f 100644
---- a/dmd/statementsem.d
-+++ b/dmd/statementsem.d
-@@ -3695,6 +3695,13 @@ version (IN_LLVM)
-                 if (auto ls = s.isLabelStatement())
-                 {
-                     sc.func.searchLabel(ls.ident, ls.loc);
-+
-+version (IN_LLVM)
-+{
-+                    if (!sc.func.asmLabels)
-+                        sc.func.asmLabels = new Identifiers();
-+                    sc.func.asmLabels.push(ls.ident);
-+}
-                 }
-             }
-         }
-diff --git a/driver/archiver.cpp b/driver/archiver.cpp
-index 14c91d810c..15725a947d 100644
---- a/driver/archiver.cpp
-+++ b/driver/archiver.cpp
-@@ -14,13 +14,8 @@
- #include "driver/cl_options.h"
- #include "driver/tool.h"
- #include "gen/logger.h"
--#if LDC_LLVM_VER < 1700
--#include "llvm/ADT/Triple.h"
--#include "llvm/Support/Host.h"
--#else
- #include "llvm/TargetParser/Host.h"
- #include "llvm/TargetParser/Triple.h"
--#endif
- #include "llvm/Object/Archive.h"
- #include "llvm/Object/ArchiveWriter.h"
- #include "llvm/Object/MachO.h"
-@@ -45,11 +40,7 @@ namespace llvm_ar {
- StringRef ArchiveName;
- std::vector<const char *> Members;
- 
--#if LDC_LLVM_VER < 1800
--bool Symtab = true;
--#else
- llvm::SymtabWritingMode Symtab = llvm::SymtabWritingMode::NormalSymtab;
--#endif
- bool Deterministic = true;
- bool Thin = false;
- 
-diff --git a/driver/args.cpp b/driver/args.cpp
-index 2485dab7dd..2ce4210a12 100644
---- a/driver/args.cpp
-+++ b/driver/args.cpp
-@@ -170,11 +170,7 @@ int executeAndWait(std::vector<const char *> fullArgs,
-   }
- 
-   const std::vector<llvm::StringRef> argv = toRefsVector(fullArgs);
--#if LDC_LLVM_VER < 1600
--  auto envVars = llvm::None;
--#else
-   auto envVars = std::nullopt;
--#endif
- 
-   return llvm::sys::ExecuteAndWait(argv[0], argv, envVars, {}, 0, 0, errorMsg);
- }
-diff --git a/driver/cache.cpp b/driver/cache.cpp
-index 9e9278847d..2556ef2422 100644
---- a/driver/cache.cpp
-+++ b/driver/cache.cpp
-@@ -309,30 +309,14 @@ void outputIR2ObjRelevantCmdlineArgs(llvm::raw_ostream &hash_os) {
-   hash_os << opts::getFeaturesStr();
-   hash_os << opts::floatABI;
-   const auto relocModel = opts::getRelocModel();
--#if LDC_LLVM_VER >= 1600
-   if (relocModel.has_value())
-     hash_os << relocModel.value();
--#else
--  if (relocModel.hasValue())
--    hash_os << relocModel.getValue();
--#endif
-   const auto codeModel = opts::getCodeModel();
--#if LDC_LLVM_VER >= 1600
-   if (codeModel.has_value())
-     hash_os << codeModel.value();
--#else
--  if (codeModel.hasValue())
--    hash_os << codeModel.getValue();
--#endif
--
-   const auto framePointerUsage = opts::framePointerUsage();
--#if LDC_LLVM_VER >= 1600
-   if (framePointerUsage.has_value())
-     hash_os << static_cast<int>(framePointerUsage.value());
--#else
--  if (framePointerUsage.hasValue())
--    hash_os << static_cast<int>(framePointerUsage.getValue());
--#endif
- }
- 
- // Output to `hash_os` all environment flags that influence object code output
-diff --git a/driver/cl_options-llvm.cpp b/driver/cl_options-llvm.cpp
-index 036e0bfa4f..168fab6adb 100644
---- a/driver/cl_options-llvm.cpp
-+++ b/driver/cl_options-llvm.cpp
-@@ -10,12 +10,8 @@
- #include "driver/cl_options-llvm.h"
- 
- #if LDC_WITH_LLD
--#if LDC_LLVM_VER < 1700
--#include "llvm/ADT/Triple.h"
--#else
- #include "llvm/TargetParser/Triple.h"
- #endif
--#endif
- 
- // Pull in command-line options and helper functions from special LLVM header
- // shared by multiple LLVM tools.
-@@ -35,17 +31,17 @@ std::string getArchStr() {
-   return codegen::getMArch();
- }
- 
--Optional<Reloc::Model> getRelocModel() {
-+std::optional<Reloc::Model> getRelocModel() {
-   return codegen::getExplicitRelocModel();
- }
- 
--Optional<CodeModel::Model> getCodeModel() {
-+std::optional<CodeModel::Model> getCodeModel() {
-   return codegen::getExplicitCodeModel();
- }
- 
- using FPK = llvm::FramePointerKind;
- 
--llvm::Optional<FPK> framePointerUsage() {
-+std::optional<FPK> framePointerUsage() {
-   // Defaults to `FP::None`; no way to check if set explicitly by user except
-   // indirectly via setFunctionAttributes()...
-   return codegen::getFramePointerUsage();
-@@ -89,11 +85,11 @@ TargetOptions initTargetOptionsFromCodeGenFlags() {
-   return ::opts::InitTargetOptionsFromCodeGenFlags(llvm::Triple());
- }
- 
--Optional<Reloc::Model> getRelocModelFromCMModel() {
-+std::optional<Reloc::Model> getRelocModelFromCMModel() {
-   return ::opts::getRelocModel();
- }
- 
--Optional<CodeModel::Model> getCodeModelFromCMModel() {
-+std::optional<CodeModel::Model> getCodeModelFromCMModel() {
-   return ::opts::getCodeModel();
- }
- 
-diff --git a/driver/cl_options-llvm.h b/driver/cl_options-llvm.h
-index 2f39b2401a..69b54359dc 100644
---- a/driver/cl_options-llvm.h
-+++ b/driver/cl_options-llvm.h
-@@ -9,17 +9,10 @@
- 
- #pragma once
- 
--#if LDC_LLVM_VER < 1700
--#include "llvm/ADT/Optional.h"
--#else
--#include <optional>
--namespace llvm {
--template <typename T> using Optional = std::optional<T>;
--}
--#endif
- #include "llvm/Support/CommandLine.h"
- #include "llvm/Support/CodeGen.h"
- #include "llvm/Target/TargetOptions.h"
-+#include <optional>
- 
- namespace llvm {
- class Function;
-@@ -29,9 +22,9 @@ class Triple;
- namespace opts {
- 
- std::string getArchStr();
--llvm::Optional<llvm::Reloc::Model> getRelocModel();
--llvm::Optional<llvm::CodeModel::Model> getCodeModel();
--llvm::Optional<llvm::FramePointerKind> framePointerUsage();
-+std::optional<llvm::Reloc::Model> getRelocModel();
-+std::optional<llvm::CodeModel::Model> getCodeModel();
-+std::optional<llvm::FramePointerKind> framePointerUsage();
- 
- bool disableRedZone();
- bool printTargetFeaturesHelp();
-diff --git a/driver/cl_options.cpp b/driver/cl_options.cpp
-index 5b155a6797..c101cf199c 100644
---- a/driver/cl_options.cpp
-+++ b/driver/cl_options.cpp
-@@ -20,6 +20,12 @@ namespace opts {
- // This vector is filled by parseCommandLine in main.cpp.
- llvm::SmallVector<const char *, 32> allArguments;
- 
-+cl::opt<bool> noBuiltIn(
-+    "fno-builtin",
-+    cl::desc("Disable implicit builtin knowledge of functions"),
-+    cl::ZeroOrMore
-+);
-+
- cl::OptionCategory linkingCategory("Linking options");
- 
- // Positional options first, in order:
-@@ -577,7 +583,7 @@ llvm::FastMathFlags defaultFMF;
- void setDefaultMathOptions(llvm::TargetOptions &targetOptions) {
-   if (fFastMath) {
-     defaultFMF.setFast();
--#if LDC_LLVM_VER < 2200
-+#if LLVM_VERSION_MAJOR < 22
-     targetOptions.UnsafeFPMath = true;
- #endif
-   }
-@@ -788,12 +794,15 @@ static cl::extrahelp
- /// The clashing LLVM options are suffixed with "llvm-" and hidden from the
- /// -help output.
- void createClashingOptions() {
--  llvm::StringMap<cl::Option *> &map = cl::getRegisteredOptions();
--
-+  auto &map = cl::getRegisteredOptions();
-   auto renameAndHide = [&map](const char *from, const char *to) {
-     auto i = map.find(from);
-     if (i != map.end()) {
-+#if LLVM_VERSION_MAJOR >= 22
-+      cl::Option *opt = i->second;
-+#else
-       cl::Option *opt = i->getValue();
-+#endif
-       map.erase(i);
-       if (to) {
-         opt->setArgStr(to);
-@@ -847,7 +856,8 @@ void hideLLVMOptions() {
-       "amdgpu-enable-global-sgpr-addr", "amdgpu-enable-merge-m0",
-       "amdgpu-enable-power-sched", "amdgpu-igrouplp",
-       "amdgpu-indirect-call-specialization-threshold",
--      "amdgpu-kernarg-preload-count", "amdgpu-module-splitting-max-depth",
-+      "amdgpu-kernarg-preload", "amdgpu-kernarg-preload-count",
-+      "amdgpu-module-splitting-max-depth",
-       "amdgpu-promote-alloca-to-vector-limit",
-       "amdgpu-promote-alloca-to-vector-max-regs",
-       "amdgpu-promote-alloca-to-vector-vgpr-ratio",
-@@ -857,9 +867,11 @@ void hideLLVMOptions() {
-       "argext-abi-check", "arm-add-build-attributes",
-       "arm-implicit-it", "asm-instrumentation", "asm-show-inst",
-       "atomic-counter-update-promoted", "atomic-first-counter",
--      "basic-block-address-map", "basic-block-sections",
-+      "basic-block-address-map", "basic-block-section-match-infer",
-+      "basic-block-sections",
-       "basicblock-sections", "bounds-checking-single-trap",
--      "bounds-checking-unique-traps", "bpf-stack-size", "cfg-hide-cold-paths",
-+      "bounds-checking-unique-traps", "bpf-stack-size",
-+      "call-graph-section", "cfg-hide-cold-paths",
-       "cfg-hide-deoptimize-paths", "cfg-hide-unreachable-paths",
-       "check-functions-filter", "code-model", "conditional-counter-update",
-       "cost-kind", "cppfname", "cppfor", "cppgen", "crel",
-@@ -867,18 +879,21 @@ void hideLLVMOptions() {
-       "cvp-dont-process-adds", "debug-counter", "debug-entry-values",
-       "debugger-tune", "debugify-atoms", "debugify-func-limit",
-       "debugify-level", "debugify-quiet", "debug-info-correlate",
--      "denormal-fp-math", "denormal-fp-math-f32",
-+      "denormal-fp-math", "denormal-fp-math-f32", "devirtualize-speculatively",
-       "disable-auto-upgrade-debug-info", "disable-debug-info-verifier",
-       "disable-i2p-p2i-opt",
-       "disable-objc-arc-checkforcfghazards", "disable-promote-alloca-to-lds",
--      "disable-promote-alloca-to-vector", "disable-slp-vectorization",
-+      "disable-promote-alloca-to-vector", "disable-qfp-opt",
-+      "disable-qfp-opt-mul", "disable-slp-vectorization",
-       "disable-spill-fusing",
--      "do-counter-promotion", "dot-cfg-mssa", "dwarf64", "emit-call-site-info",
-+      "do-counter-promotion", "dot-cfg-mssa", "dwarf64",
-+      "elide-all-zero-branch-weights", "emit-bb-hash", "emit-call-site-info",
-       "emit-compact-unwind-non-canonical", "emit-dwarf-unwind",
-       "emit-gnuas-syntax-on-zos", "emscripten-cxx-exceptions-allowed",
-       "emscripten-cxx-exceptions-whitelist",
-       "emulated-tls", "enable-approx-func-fp-math", "enable-correct-eh-support",
-       "enable-cse-in-irtranslator", "enable-cse-in-legalizer",
-+      "enable-devirtualize-speculatively",
-       "enable-emscripten-cxx-exceptions", "enable-emscripten-sjlj",
-       "enable-fp-mad", "enable-gvn-hoist", "enable-gvn-memdep",
-       "enable-gvn-memoryssa",
-@@ -889,7 +904,8 @@ void hideLLVMOptions() {
-       "enable-no-nans-fp-math", "enable-no-signed-zeros-fp-math",
-       "enable-no-trapping-fp-math", "enable-objc-arc-annotations",
-       "enable-objc-arc-opts", "enable-pgo-force-function-attrs",
--      "enable-pie", "enable-scoped-noalias",
-+      "enable-pie", "enable-poison-reuse-guard",
-+      "enable-scoped-noalias",
-       "enable-split-backedge-in-load-pre", "enable-split-loopiv-heuristic",
-       "enable-tbaa", "enable-tlsdesc", "enable-unsafe-fp-math",
-       "enable-vtable-profile-use", "enable-vtable-value-profiling",
-@@ -901,8 +917,8 @@ void hideLLVMOptions() {
-       "force-dwarf-frame-section", "force-opaque-pointers",
-       "force-tail-folding-style",
-       "fs-profile-debug-bw-threshold", "fs-profile-debug-prob-diff-threshold",
--      "generate-merged-base-profiles",
--      "gpsize", "hash-based-counter-split", "hexagon-add-build-attributes",
-+      "generate-merged-base-profiles", "gpsize", "gsframe",
-+      "hash-based-counter-split", "hexagon-add-build-attributes",
-       "hexagon-rdf-limit", "hot-cold-split", "hwasan-percentile-cutoff-hot",
-       "hwasan-random-rate", "ignore-xcoff-visibility",
-       "imp-null-check-page-size", "imp-null-max-insts-to-consider",
-@@ -914,7 +930,8 @@ void hideLLVMOptions() {
-       "instcombine-negator-max-depth", "instcombine-unsafe-select-transform",
-       "instrprof-atomic-counter-update-all", "internalize-public-api-file",
-       "internalize-public-api-list", "intrinsic-cost-strategy",
--      "ir2vec-arg-weight", "ir2vec-opc-weight", "ir2vec-type-weight",
-+      "ir2vec-arg-weight", "ir2vec-kind", "ir2vec-opc-weight",
-+      "ir2vec-type-weight",
-       "ir2vec-vocab-path", "iterative-counter-promotion",
-       "join-liveintervals", "jump-table-type", "large-data-threshold",
-       "limit-float-precision", "lint-abort-on-error", "loongarch-use-aa",
-@@ -927,7 +944,10 @@ void hideLLVMOptions() {
-       "memop-size-large", "memop-size-range", "merror-missing-parenthesis",
-       "merror-noncontigious-register", "mfuture-regs", "mhvx",
-       "mips-compact-branches", "mips16-constant-islands", "mips16-hard-float",
--      "mir-strip-debugify-only", "misexpect-tolerance", "mlsm", "mno-compound",
-+      "mir-strip-debugify-only",
-+      "mir2vec-common-operand-weight", "mir2vec-kind", "mir2vec-opc-weight",
-+      "mir2vec-reg-operand-weight", "mir2vec-vocab-path",
-+      "misexpect-tolerance", "mlsm", "mno-compound",
-       "mno-fixup", "mno-ldc1-sdc1", "mno-pairing",
-       "ms-secure-hotpatch-functions-file", "ms-secure-hotpatch-functions-list",
-       "mwarn-missing-parenthesis",
-@@ -943,10 +963,15 @@ void hideLLVMOptions() {
-       "polly-dump-after", "polly-dump-after-file", "polly-dump-before",
-       "polly-dump-before-file", "pre-RA-sched", "print-after-all",
-       "print-before-all", "print-machineinstrs", "print-module-scope",
--      "print-pipeline-passes", "profile-correlate",
-+      "print-pipeline-passes",
-+      "profcheck-annotate-select", "profcheck-default-function-entry-count",
-+      "profcheck-default-select-false-weight",
-+      "profcheck-default-select-true-weight", "profcheck-weights-for-test",
-+      "profile-correlate",
-       "profile-estimator-loop-weight", "profile-estimator-loop-weight",
-       "profile-file", "profile-info-file", "profile-verifier-noassert",
--      "promote-alloca-vector-loop-user-weight", "pseudo-probe-for-profiling",
-+      "promote-alloca-vector-loop-user-weight", "propeller-infer-threshold",
-+      "pseudo-probe-for-profiling",
-       "r600-ir-structurize", "rdf-dump", "rdf-limit", "recip", "regalloc",
-       "relax-elf-relocations", "remarks-section", "rewrite-map-file",
-       "riscv-add-build-attributes", "riscv-use-aa", "rng-seed",
-@@ -961,11 +986,12 @@ void hideLLVMOptions() {
-       "skip-ret-exit-block",
-       "speculative-counter-promotion-max-exiting",
-       "speculative-counter-promotion-to-loop", "spiller", "spirv-debug",
-+      "spirv-emit-op-names",
-       "spirv-erase-cl-md", "spirv-ext", "spirv-lower-const-expr",
-       "spirv-mem2reg",
-       "spirv-no-deref-attr", "spirv-text", "spirv-verify-regularize-passes",
--      "split-machine-functions", "spv-dump-deps",
--      "spv-emit-nonsemantic-debug-info",
-+      "split-machine-functions", "spv-allow-unknown-intrinsics",
-+      "spv-dump-deps", "spv-emit-nonsemantic-debug-info",
-       "spv-lower-saddwithoverflow-validate", "spvbool-validate",
-       "spvmemmove-validate", "stack-alignment", "stack-protector-guard",
-       "stack-protector-guard-offset", "stack-protector-guard-reg",
-@@ -1016,7 +1042,8 @@ void hideLLVMOptions() {
-                                                "trap-func",
-                                                "W"};
- 
--  llvm::StringMap<cl::Option *> &map = cl::getRegisteredOptions();
-+  auto &map = cl::getRegisteredOptions();
-+
-   for (const auto name : hiddenOptions) {
-     // Check if option exists first for resilience against LLVM changes
-     // between versions.
-diff --git a/driver/cl_options.h b/driver/cl_options.h
-index 964874bcce..481b83adcc 100644
---- a/driver/cl_options.h
-+++ b/driver/cl_options.h
-@@ -41,6 +41,7 @@ extern cl::OptionCategory linkingCategory;
-    egrep -e '^(cl::|#if|#e)' gen/cl_options.cpp \
-     | sed -re 's/^(cl::.*)\(.*$/    extern \1;/'
-  */
-+extern cl::opt<bool> noBuiltIn;
- extern cl::list<std::string> fileList;
- extern cl::list<std::string> runargs;
- extern cl::opt<bool> invokedByLDMD;
-diff --git a/driver/cl_options_instrumentation.cpp b/driver/cl_options_instrumentation.cpp
-index 325f71383d..c8c0a07a77 100644
---- a/driver/cl_options_instrumentation.cpp
-+++ b/driver/cl_options_instrumentation.cpp
-@@ -18,11 +18,7 @@
- #include "dmd/errors.h"
- #include "dmd/globals.h"
- #include "gen/to_string.h"
--#if LDC_LLVM_VER < 1700
--#include "llvm/ADT/Triple.h"
--#else
- #include "llvm/TargetParser/Triple.h"
--#endif
- 
- namespace {
- namespace cl = llvm::cl;
-diff --git a/driver/cl_options_sanitizers.h b/driver/cl_options_sanitizers.h
-index e1eaa3c934..423322e7fd 100644
---- a/driver/cl_options_sanitizers.h
-+++ b/driver/cl_options_sanitizers.h
-@@ -14,7 +14,7 @@
- #pragma once
- 
- #include "driver/cl_helpers.h"
--#if LDC_LLVM_VER >= 2000
-+#if LLVM_VERSION_MAJOR >= 20
- #include "llvm/Transforms/Utils/Instrumentation.h"
- #else
- #include "llvm/Transforms/Instrumentation.h"
-diff --git a/driver/codegenerator.cpp b/driver/codegenerator.cpp
-index 04fdeee4a6..6ec8044eb4 100644
---- a/driver/codegenerator.cpp
-+++ b/driver/codegenerator.cpp
-@@ -37,7 +37,7 @@
- #include "mlir/IR/MLIRContext.h"
- #endif
- 
--#if LDC_LLVM_VER < 2200
-+#if LLVM_VERSION_MAJOR < 22
- namespace llvm {
-   using LLVMRemarkFileHandle = std::unique_ptr<llvm::ToolOutputFile>;
- }
-@@ -218,7 +218,7 @@ void CodeGenerator::prepareLLModule(Module *m) {
-   // name, as it should not collide with a symbol name used somewhere in the
-   // module.
-   ir_ = new IRState(m->srcfile.toChars(), context_);
--#if LDC_LLVM_VER >= 2100
-+#if LLVM_VERSION_MAJOR >= 21
-   ir_->module.setTargetTriple(*global.params.targetTriple);
- #else
-   ir_->module.setTargetTriple(global.params.targetTriple->str());
-diff --git a/driver/cpreprocessor.cpp b/driver/cpreprocessor.cpp
-index fff0e5d223..d4b579d99e 100644
---- a/driver/cpreprocessor.cpp
-+++ b/driver/cpreprocessor.cpp
-@@ -99,7 +99,6 @@ FileName runCPreprocessor(FileName csrcfile, Loc loc, OutBuffer &defines) {
-       // propagate the target to the preprocessor
-       args.push_back("--target=" + triple.getTriple());
- 
--#if LDC_LLVM_VER >= 1800 // getAllProcessorFeatures was introduced in this version
-       // propagate all enabled/disabled features to the preprocessor
-       const auto &subTarget = gTargetMachine->getMCSubtargetInfo();
-       const auto &featureBits = subTarget->getFeatureBits();
-@@ -114,7 +113,6 @@ FileName runCPreprocessor(FileName csrcfile, Loc loc, OutBuffer &defines) {
-         args.push_back(featureString.str().str());
-         featureString.clear();
-       }
--#endif
- 
-       // print macro definitions (clang-cl doesn't support /PD - use clang's
-       // -dD)
-diff --git a/driver/linker-gcc.cpp b/driver/linker-gcc.cpp
-index d3ad82b346..93cb97a492 100644
---- a/driver/linker-gcc.cpp
-+++ b/driver/linker-gcc.cpp
-@@ -27,14 +27,12 @@
- 
- #if LDC_WITH_LLD
- #include "lld/Common/Driver.h"
--#if LDC_LLVM_VER >= 1700
- LLD_HAS_DRIVER(coff)
- LLD_HAS_DRIVER(elf)
- LLD_HAS_DRIVER(mingw)
- LLD_HAS_DRIVER(macho)
- LLD_HAS_DRIVER(wasm)
- #endif
--#endif
- 
- //////////////////////////////////////////////////////////////////////////////
- 
-@@ -161,11 +159,6 @@ void ArgsBuilder::addLTOGoldPluginFlags(bool requirePlugin) {
-     addLdFlag("-plugin-opt=-function-sections");
-   if (TO.DataSections)
-     addLdFlag("-plugin-opt=-data-sections");
--
--#if LDC_LLVM_VER >= 1600 && LDC_LLVM_VER < 1700
--  // LLVM 16: disable function specializations by default
--  addLdFlag("-plugin-opt=-func-specialization-size-threshold=1000000000");
--#endif
- }
- 
- // Returns an empty string when libLTO.dylib was not specified nor found.
-@@ -196,11 +189,6 @@ void ArgsBuilder::addDarwinLTOFlags() {
-   std::string dylibPath = getLTOdylibPath();
-   if (!dylibPath.empty()) {
-     addLdFlag("-lto_library", dylibPath);
--
--#if LDC_LLVM_VER >= 1600 && LDC_LLVM_VER < 1700
--    // LLVM 16: disable function specializations by default
--    addLdFlag("-mllvm", "-func-specialization-size-threshold=1000000000");
--#endif
-   }
- }
- 
-@@ -624,20 +612,11 @@ void ArgsBuilder::build(llvm::StringRef outputPath,
-   }
- 
-   const auto explicitPlatformLibs = getExplicitPlatformLibs();
--#if LDC_LLVM_VER >= 1600
-   if (explicitPlatformLibs.has_value()) {
-     for (const auto &name : explicitPlatformLibs.value()) {
-       args.push_back("-l" + name);
-     }
--  }
--#else
--  if (explicitPlatformLibs.hasValue()) {
--    for (const auto &name : explicitPlatformLibs.getValue()) {
--      args.push_back("-l" + name);
--    }
--  }
--#endif
--  else {
-+  } else {
-     addDefaultPlatformLibs();
-   }
- 
-@@ -656,10 +635,6 @@ void ArgsBuilder::addLinker() {
- //////////////////////////////////////////////////////////////////////////////
- 
- void ArgsBuilder::addUserSwitches() {
--#if LDC_LLVM_VER >= 1800
--  #define startswith starts_with
--#endif
--
-   // additional linker and cc switches (preserve order across both lists)
-   for (unsigned ilink = 0, icc = 0;;) {
-     unsigned linkpos = ilink < opts::linkerSwitches.size()
-@@ -676,9 +651,9 @@ void ArgsBuilder::addUserSwitches() {
-       // Options starting with `-Wl,`, -shared or -static are not handled by
-       // the linker and must be passed to the driver.
-       auto str = llvm::StringRef(p);
--      if (!(str.startswith("-l") || str.startswith("-L") ||
--            str.startswith("-Wl,") || str.startswith("-shared") ||
--            str.startswith("-static"))) {
-+      if (!(str.starts_with("-l") || str.starts_with("-L") ||
-+            str.starts_with("-Wl,") || str.starts_with("-shared") ||
-+            str.starts_with("-static"))) {
-         args.push_back("-Xlinker");
-       }
-       args.push_back(p);
-@@ -688,10 +663,6 @@ void ArgsBuilder::addUserSwitches() {
-       break;
-     }
-   }
--
--#if LDC_LLVM_VER >= 1800
--  #undef startswith
--#endif
- }
- 
- //////////////////////////////////////////////////////////////////////////////
-diff --git a/driver/linker-msvc.cpp b/driver/linker-msvc.cpp
-index ad86ebabdf..931ccc3bb5 100644
---- a/driver/linker-msvc.cpp
-+++ b/driver/linker-msvc.cpp
-@@ -22,10 +22,8 @@
- 
- #if LDC_WITH_LLD
- #include "lld/Common/Driver.h"
--#if LDC_LLVM_VER >= 1700
- LLD_HAS_DRIVER(coff)
- #endif
--#endif
- 
- //////////////////////////////////////////////////////////////////////////////
- 
-@@ -39,22 +37,15 @@ void addMscrtLibs(bool useInternalToolchain, std::vector<std::string> &args) {
-   // We need the vcruntime lib for druntime's exception handling (ldc.eh_msvc).
-   // Pick one of the 4 variants matching the selected main UCRT lib.
- 
--#if LDC_LLVM_VER >= 1700
--#define contains_lower contains_insensitive
--#define endswith_lower ends_with_insensitive
--#else
--#define contains_lower contains_insensitive
--#define endswith_lower endswith_insensitive
--#endif
-   if (useInternalToolchain) {
--    assert(mscrtlibName.contains_lower("vcruntime"));
-+    assert(mscrtlibName.contains_insensitive("vcruntime"));
-     return;
-   }
- 
--  const bool isStatic = mscrtlibName.contains_lower("libcmt");
-+  const bool isStatic = mscrtlibName.contains_insensitive("libcmt");
- 
--  const bool isDebug =
--      mscrtlibName.endswith_lower("d") || mscrtlibName.endswith_lower("d.lib");
-+  const bool isDebug = mscrtlibName.ends_with_insensitive("d") ||
-+                       mscrtlibName.ends_with_insensitive("d.lib");
- 
-   const llvm::StringRef prefix = isStatic ? "lib" : "";
-   const llvm::StringRef suffix = isDebug ? "d" : "";
-@@ -77,9 +68,9 @@ void addSanitizerLibs(bool useInternalToolchain,
-                       std::vector<std::string> &args) {
-   if (opts::isSanitizerEnabled(opts::AddressSanitizer)) {
-     args.push_back("ldc_rt.asan.lib");
--#if LDC_LLVM_VER >= 2000 // extra library since LLVM 20
-+#if LLVM_VERSION_MAJOR >= 20 // extra library since LLVM 20
-     const bool linkStaticCRT =
--        getMscrtLibName(&useInternalToolchain).contains_lower("libcmt");
-+        getMscrtLibName(&useInternalToolchain).contains_insensitive("libcmt");
-     args.push_back((llvm::Twine("ldc_rt.asan_") +
-                     (linkStaticCRT ? "static" : "dynamic") +
-                     "_runtime_thunk.lib")
-@@ -108,7 +99,8 @@ int linkObjToBinaryMSVC(llvm::StringRef outputPath,
- 
-   const bool forceMSVC = env::has(L"LDC_VSDIR_FORCE");
-   const bool useInternalToolchain =
--      (!forceMSVC && getExplicitMscrtLibName().contains_lower("vcruntime")) ||
-+      (!forceMSVC &&
-+       getExplicitMscrtLibName().contains_insensitive("vcruntime")) ||
-       !msvcEnv.setup();
- 
-   if (forceMSVC && useInternalToolchain) {
-@@ -243,22 +235,12 @@ int linkObjToBinaryMSVC(llvm::StringRef outputPath,
-   }
- 
-   auto explicitPlatformLibs = getExplicitPlatformLibs();
--#if LDC_LLVM_VER >= 1600
-   if (explicitPlatformLibs.has_value()) {
-     for (auto &lib : explicitPlatformLibs.value()) {
-       args.push_back(llvm::sys::path::has_extension(lib) ? std::move(lib)
-                                                          : lib + ".lib");
-     }
--  }
--#else
--  if (explicitPlatformLibs.hasValue()) {
--    for (auto &lib : explicitPlatformLibs.getValue()) {
--      args.push_back(llvm::sys::path::has_extension(lib) ? std::move(lib)
--                                                         : lib + ".lib");
--    }
--  }
--#endif
--  else {
-+  } else {
-     // default platform libs
-     // TODO check which libaries are necessary
-     args.insert(args.end(),
-diff --git a/driver/linker.cpp b/driver/linker.cpp
-index 65e0a099e0..44495896ee 100644
---- a/driver/linker.cpp
-+++ b/driver/linker.cpp
-@@ -192,14 +192,10 @@ static std::vector<std::string> getDefaultLibNames() {
- 
- //////////////////////////////////////////////////////////////////////////////
- 
--llvm::Optional<std::vector<std::string>> getExplicitPlatformLibs() {
-+std::optional<std::vector<std::string>> getExplicitPlatformLibs() {
-   if (platformLib.getNumOccurrences() > 0)
-     return parseLibNames(platformLib);
--#if LDC_LLVM_VER < 1600
--  return llvm::None;
--#else
-   return std::nullopt;
--#endif
- }
- 
- //////////////////////////////////////////////////////////////////////////////
-diff --git a/driver/linker.h b/driver/linker.h
-index 28362d8652..4f584f8359 100644
---- a/driver/linker.h
-+++ b/driver/linker.h
-@@ -42,11 +42,7 @@ bool linkAgainstSharedDefaultLibs();
- /**
-  * Returns the -platformlib library names, if specified.
-  */
--#if LDC_LLVM_VER < 1600
--llvm::Optional<std::vector<std::string>> getExplicitPlatformLibs();
--#else
- std::optional<std::vector<std::string>> getExplicitPlatformLibs();
--#endif
- 
- /**
-  * Returns the value of -mscrtlib.
-diff --git a/driver/main.cpp b/driver/main.cpp
-index e1619dc0cb..df3637f55c 100644
---- a/driver/main.cpp
-+++ b/driver/main.cpp
-@@ -57,11 +57,7 @@
- #include "llvm/LinkAllIR.h"
- #include "llvm/LinkAllPasses.h"
- #include "llvm/Support/FileSystem.h"
--#if LDC_LLVM_VER >= 1700
- #include "llvm/TargetParser/Host.h"
--#else
--#include "llvm/Support/Host.h"
--#endif
- #include "llvm/Support/ManagedStatic.h"
- #include "llvm/Support/Path.h"
- #include "llvm/Support/StringSaver.h"
-@@ -189,17 +185,13 @@ void tryParse(const llvm::SmallVectorImpl<const char *> &args, size_t i,
- }
- 
- bool tryParseLowmem(const llvm::SmallVectorImpl<const char *> &args) {
--#if LDC_LLVM_VER >= 1800
--  #define startswith starts_with
--#endif
--
-   bool lowmem = false;
-   for (size_t i = 1; i < args.size(); ++i) {
-     if (args::isRunArg(args[i]))
-       break;
- 
-     llvm::StringRef arg = args[i];
--    if (arg.startswith("-lowmem") || arg.startswith("--lowmem")) {
-+    if (arg.starts_with("-lowmem") || arg.starts_with("--lowmem")) {
-       auto remainder = arg.substr(arg[1] == '-' ? 8 : 7);
-       if (remainder.empty()) {
-         lowmem = true;
-@@ -210,10 +202,6 @@ bool tryParseLowmem(const llvm::SmallVectorImpl<const char *> &args) {
-     }
-   }
-   return lowmem;
--
--#if LDC_LLVM_VER >= 1800
--  #undef startswith
--#endif
- }
- 
- const char *
-@@ -322,7 +310,11 @@ void parseCommandLine(Strings &sourceFiles) {
-     if (auto target = lookupTarget("", triple, errMsg)) {
-       llvm::errs() << "Targeting " << target->getName() << ". ";
-       // this prints the available CPUs and features of the target to stderr...
-+#if LLVM_VERSION_MAJOR >= 22
-+      target->createMCSubtargetInfo(triple, "help", "");
-+#else
-       target->createMCSubtargetInfo(cfg_triple, "help", "");
-+#endif
-     } else {
-       error(Loc(), "%s", errMsg.c_str());
-       fatal();
-@@ -574,13 +566,6 @@ void parseCommandLine(Strings &sourceFiles) {
- 
-   global.params.dihdr.fullOutput = opts::hdrKeepAllBodies;
-   global.params.disableRedZone = opts::disableRedZone();
--
--  // enforce opaque IR pointers
--#if LDC_LLVM_VER >= 1700
--  // supports opaque IR pointers only
--#else
--  getGlobalContext().setOpaquePointers(true);
--#endif
- }
- 
- void initializePasses() {
-@@ -590,28 +575,13 @@ void initializePasses() {
-   initializeCore(Registry);
-   initializeTransformUtils(Registry);
-   initializeScalarOpts(Registry);
--#if LDC_LLVM_VER < 1600
--  initializeObjCARCOpts(Registry);
--#endif
-   initializeVectorization(Registry);
-   initializeInstCombine(Registry);
--#if LDC_LLVM_VER < 1600
--  initializeAggressiveInstCombine(Registry);
--#endif
-   initializeIPO(Registry);
--#if LDC_LLVM_VER < 1600
--  initializeInstrumentation(Registry);
--#endif
-   initializeAnalysis(Registry);
-   initializeCodeGen(Registry);
-   initializeGlobalISel(Registry);
-   initializeTarget(Registry);
--
--#if LDC_LLVM_VER < 1700
--// Initialize passes not included above
--  initializeRewriteSymbolsLegacyPassPass(Registry);
--  initializeSjLjEHPreparePass(Registry);
--#endif
- }
- 
- /// Register the MIPS ABI.
-@@ -774,7 +744,6 @@ void registerPredefinedTargetVersions() {
-   case llvm::Triple::wasm64:
-     VersionCondition::addPredefinedGlobalIdent("WebAssembly");
-     break;
--#if LDC_LLVM_VER >= 1600
-   case llvm::Triple::loongarch32:
-     VersionCondition::addPredefinedGlobalIdent("LoongArch32");
-     registerPredefinedFloatABI("LoongArch_SoftFloat", "LoongArch_HardFloat");
-@@ -786,7 +755,6 @@ void registerPredefinedTargetVersions() {
-   case llvm::Triple::xtensa:
-     VersionCondition::addPredefinedGlobalIdent("Xtensa");
-     break;
--#endif // LDC_LLVM_VER >= 1600
-   default:
-     warning(Loc(), "unknown target CPU architecture: %s",
-             triple.getArchName().str().c_str());
-@@ -1064,7 +1032,7 @@ void registerPredefinedVersions() {
- // Expose LLVM version to runtime
- #define STR(x) #x
- #define XSTR(x) STR(x)
--  VersionCondition::addPredefinedGlobalIdent("LDC_LLVM_" XSTR(LDC_LLVM_VER));
-+  VersionCondition::addPredefinedGlobalIdent("LDC_LLVM_" XSTR(LLVM_VERSION_MAJOR));
- #undef XSTR
- #undef STR
- }
-@@ -1181,15 +1149,9 @@ int cppmain() {
-   }
- 
-   auto relocModel = getRelocModel();
--#if LDC_LLVM_VER >= 1600
-   if (global.params.dll && !relocModel.has_value()) {
-     relocModel = llvm::Reloc::PIC_;
-   }
--#else
--  if (global.params.dll && !relocModel.hasValue()) {
--    relocModel = llvm::Reloc::PIC_;
--  }
--#endif
- 
-   fixupTripleEnv(mTargetTriple);
- 
-diff --git a/driver/plugins.cpp b/driver/plugins.cpp
-index 1356b4c5fd..b6baa8dfba 100644
---- a/driver/plugins.cpp
-+++ b/driver/plugins.cpp
-@@ -25,7 +25,11 @@
- #include "llvm/Support/CommandLine.h"
- #include "llvm/Support/DynamicLibrary.h"
- #include "llvm/ADT/SmallVector.h"
-+#if LLVM_VERSION_MAJOR >= 22
-+#include "llvm/Plugins/PassPlugin.h"
-+#else
- #include "llvm/Passes/PassPlugin.h"
-+#endif
- #include "llvm/Support/Error.h"
- 
- #include "driver/cl_options.h"
-diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp
-index 0afc279bcc..6f85efd660 100644
---- a/driver/targetmachine.cpp
-+++ b/driver/targetmachine.cpp
-@@ -21,21 +21,12 @@
- #include "gen/logger.h"
- #include "llvm/ADT/StringExtras.h"
- #include "llvm/ADT/StringSwitch.h"
--#if LDC_LLVM_VER < 1700
--#include "llvm/ADT/Triple.h"
--#include "llvm/MC/SubtargetFeature.h"
--#include "llvm/Support/Host.h"
--#include "llvm/Support/TargetParser.h"
--#include "llvm/Support/AArch64TargetParser.h"
--#include "llvm/Support/ARMTargetParser.h"
--#else
- #include "llvm/TargetParser/AArch64TargetParser.h"
- #include "llvm/TargetParser/ARMTargetParser.h"
- #include "llvm/TargetParser/Host.h"
- #include "llvm/TargetParser/SubtargetFeature.h"
- #include "llvm/TargetParser/TargetParser.h"
- #include "llvm/TargetParser/Triple.h"
--#endif
- #include "llvm/IR/Module.h"
- #include "llvm/MC/MCObjectFileInfo.h"
- #include "llvm/Support/CommandLine.h"
-@@ -46,10 +37,6 @@
- 
- #include "gen/optimizer.h"
- 
--#if LDC_LLVM_VER >= 1800
--#define startswith starts_with
--#endif
--
- #ifdef LDC_LLVM_SUPPORTS_MACHO_DWARF_LINE_AS_REGULAR_SECTION
- // LDC-LLVM >= 20:
- // On Darwin, emit __debug_line section in __DWARF segment as regular
-@@ -87,65 +74,63 @@ const char *getABI(const llvm::Triple &triple, const llvm::SmallVectorImpl<llvm:
-     switch (triple.getArch()) {
-     case llvm::Triple::arm:
-     case llvm::Triple::armeb:
--      if (ABIName.startswith("aapcs"))
-+      if (ABIName.starts_with("aapcs"))
-         return "aapcs";
--      if (ABIName.startswith("eabi"))
-+      if (ABIName.starts_with("eabi"))
-         return "apcs";
-       break;
-     case llvm::Triple::mips:
-     case llvm::Triple::mipsel:
-     case llvm::Triple::mips64:
-     case llvm::Triple::mips64el:
--      if (ABIName.startswith("o32"))
-+      if (ABIName.starts_with("o32"))
-         return "o32";
--      if (ABIName.startswith("n32"))
-+      if (ABIName.starts_with("n32"))
-         return "n32";
--      if (ABIName.startswith("n64"))
-+      if (ABIName.starts_with("n64"))
-         return "n64";
--      if (ABIName.startswith("eabi"))
-+      if (ABIName.starts_with("eabi"))
-         return "eabi";
-       break;
-     case llvm::Triple::ppc64:
-     case llvm::Triple::ppc64le:
--      if (ABIName.startswith("elfv1"))
-+      if (ABIName.starts_with("elfv1"))
-         return "elfv1";
--      if (ABIName.startswith("elfv2"))
-+      if (ABIName.starts_with("elfv2"))
-         return "elfv2";
-       break;
-     case llvm::Triple::riscv64:
--      if (ABIName.startswith("lp64f"))
-+      if (ABIName.starts_with("lp64f"))
-         return "lp64f";
--      if (ABIName.startswith("lp64d"))
-+      if (ABIName.starts_with("lp64d"))
-         return "lp64d";
--      if (ABIName.startswith("lp64"))
-+      if (ABIName.starts_with("lp64"))
-         return "lp64";
-       break;
-     case llvm::Triple::riscv32:
--      if (ABIName.startswith("ilp32f"))
-+      if (ABIName.starts_with("ilp32f"))
-         return "ilp32f";
--      if (ABIName.startswith("ilp32d"))
-+      if (ABIName.starts_with("ilp32d"))
-         return "ilp32d";
--      if (ABIName.startswith("ilp32"))
-+      if (ABIName.starts_with("ilp32"))
-         return "ilp32";
-       break;
--#if LDC_LLVM_VER >= 1600
-     case llvm::Triple::loongarch32:
--      if (ABIName.startswith("ilp32s"))
-+      if (ABIName.starts_with("ilp32s"))
-         return "ilp32s";
--      if (ABIName.startswith("ilp32f"))
-+      if (ABIName.starts_with("ilp32f"))
-         return "ilp32f";
--      if (ABIName.startswith("ilp32d"))
-+      if (ABIName.starts_with("ilp32d"))
-         return "ilp32d";
-       break;
-     case llvm::Triple::loongarch64:
--      if (ABIName.startswith("lp64f"))
-+      if (ABIName.starts_with("lp64f"))
-         return "lp64f";
--      if (ABIName.startswith("lp64d"))
-+      if (ABIName.starts_with("lp64d"))
-         return "lp64d";
--      if (ABIName.startswith("lp64s"))
-+      if (ABIName.starts_with("lp64s"))
-         return "lp64s";
-       break;
--#endif // LDC_LLVM_VER >= 1600
-     default:
-       break;
-     }
-@@ -169,7 +154,6 @@ const char *getABI(const llvm::Triple &triple, const llvm::SmallVectorImpl<llvm:
-     return "lp64";
-   case llvm::Triple::riscv32:
-     return "ilp32";
--#if LDC_LLVM_VER >= 1600
-   case llvm::Triple::loongarch32:
-     if (isFeatureEnabled(features, "d"))
-       return "ilp32d";
-@@ -182,7 +166,6 @@ const char *getABI(const llvm::Triple &triple, const llvm::SmallVectorImpl<llvm:
-     if (isFeatureEnabled(features, "f"))
-       return "lp64f";
-     return "lp64d";
--#endif // LDC_LLVM_VER >= 1600
-   default:
-     return "";
-   }
-@@ -222,22 +205,22 @@ static std::string getX86TargetCPU(const llvm::Triple &triple) {
-   if (triple.isArch64Bit()) {
-     return "x86-64";
-   }
--  if (triple.getOSName().startswith("haiku")) {
-+  if (triple.getOSName().starts_with("haiku")) {
-     return "i586";
-   }
--  if (triple.getOSName().startswith("openbsd")) {
-+  if (triple.getOSName().starts_with("openbsd")) {
-     return "i486";
-   }
--  if (triple.getOSName().startswith("freebsd")) {
-+  if (triple.getOSName().starts_with("freebsd")) {
-     return "i486";
-   }
--  if (triple.getOSName().startswith("netbsd")) {
-+  if (triple.getOSName().starts_with("netbsd")) {
-     return "i486";
-   }
--  if (triple.getOSName().startswith("openbsd")) {
-+  if (triple.getOSName().starts_with("openbsd")) {
-     return "i486";
-   }
--  if (triple.getOSName().startswith("dragonfly")) {
-+  if (triple.getOSName().starts_with("dragonfly")) {
-     return "i486";
-   }
- 
-@@ -263,12 +246,6 @@ static std::string getARMTargetCPU(const llvm::Triple &triple) {
- }
- 
- static std::string getAArch64TargetCPU(const llvm::Triple &triple) {
--#if LDC_LLVM_VER < 1600
--  auto defaultCPU = llvm::AArch64::getDefaultCPU(triple.getArchName());
--  if (!defaultCPU.empty())
--    return std::string(defaultCPU);
--#endif
--
-   return "generic";
- }
- 
-@@ -309,18 +286,32 @@ static std::string getTargetCPU(const llvm::Triple &triple) {
-     return getRiscv32TargetCPU(triple);
-   case llvm::Triple::riscv64:
-     return getRiscv64TargetCPU(triple);
--#if LDC_LLVM_VER >= 1600
-   case llvm::Triple::loongarch32:
-     return getLoongArch32TargetCPU(triple);
-   case llvm::Triple::loongarch64:
-     return getLoongArch64TargetCPU(triple);
--#endif // LDC_LLVM_VER >= 1600
-   }
- }
- 
- static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) {
-   return llvm::StringSwitch<const char *>(CPU)
-       .Case("strongarm", "v4")
-+#if LLVM_VERSION_MAJOR >= 22
-+      .Cases({"arm7tdmi", "arm7tdmi-s", "arm710t"}, "v4t")
-+      .Cases({"arm720t", "arm9", "arm9tdmi"}, "v4t")
-+      .Cases({"arm920", "arm920t", "arm922t"}, "v4t")
-+      .Cases({"arm940t", "ep9312"}, "v4t")
-+      .Cases({"arm10tdmi", "arm1020t"}, "v5")
-+      .Cases({"arm9e", "arm926ej-s", "arm946e-s"}, "v5e")
-+      .Cases({"arm966e-s", "arm968e-s", "arm10e"}, "v5e")
-+      .Cases({"arm1020e", "arm1022e", "xscale", "iwmmxt"}, "v5e")
-+      .Cases({"arm1136j-s", "arm1136jf-s", "arm1176jz-s"}, "v6")
-+      .Cases({"arm1176jzf-s", "mpcorenovfp", "mpcore"}, "v6")
-+      .Cases({"arm1156t2-s", "arm1156t2f-s"}, "v6t2")
-+      .Cases({"cortex-a5", "cortex-a7", "cortex-a8"}, "v7")
-+      .Cases({"cortex-a9", "cortex-a12", "cortex-a15"}, "v7")
-+      .Cases({"cortex-r4", "cortex-r5"}, "v7r")
-+#else
-       .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t")
-       .Cases("arm720t", "arm9", "arm9tdmi", "v4t")
-       .Cases("arm920", "arm920t", "arm922t", "v4t")
-@@ -335,6 +326,7 @@ static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) {
-       .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
-       .Cases("cortex-a9", "cortex-a12", "cortex-a15", "v7")
-       .Cases("cortex-r4", "cortex-r5", "v7r")
-+#endif
-       .Case("cortex-m0", "v6m")
-       .Case("cortex-m3", "v7m")
-       .Case("cortex-m4", "v7em")
-@@ -349,8 +341,8 @@ static FloatABI::Type getARMFloatABI(const llvm::Triple &triple,
-                                      const char *llvmArchSuffix) {
-   if (triple.isOSDarwin()) {
-     // Darwin defaults to "softfp" for v6 and v7.
--    if (llvm::StringRef(llvmArchSuffix).startswith("v6") ||
--        llvm::StringRef(llvmArchSuffix).startswith("v7")) {
-+    if (llvm::StringRef(llvmArchSuffix).starts_with("v6") ||
-+        llvm::StringRef(llvmArchSuffix).starts_with("v7")) {
-       return FloatABI::SoftFP;
-     }
-     return FloatABI::Soft;
-@@ -361,9 +353,9 @@ static FloatABI::Type getARMFloatABI(const llvm::Triple &triple,
-     return FloatABI::Soft;
-   }
- 
--  if (triple.getVendorName().startswith("hardfloat"))
-+  if (triple.getVendorName().starts_with("hardfloat"))
-     return FloatABI::Hard;
--  if (triple.getVendorName().startswith("softfloat"))
-+  if (triple.getVendorName().starts_with("softfloat"))
-     return FloatABI::SoftFP;
- 
-   switch (triple.getEnvironment()) {
-@@ -375,7 +367,7 @@ static FloatABI::Type getARMFloatABI(const llvm::Triple &triple,
-     // EABI is always AAPCS, and if it was not marked 'hard', it's softfp
-     return FloatABI::SoftFP;
-   case llvm::Triple::Android: {
--    if (llvm::StringRef(llvmArchSuffix).startswith("v7")) {
-+    if (llvm::StringRef(llvmArchSuffix).starts_with("v7")) {
-       return FloatABI::SoftFP;
-     }
-     return FloatABI::Soft;
-@@ -425,7 +417,11 @@ const llvm::Target *lookupTarget(const std::string &arch, llvm::Triple &triple,
-     }
-   } else {
-     std::string tempError;
-+#if LLVM_VERSION_MAJOR >= 22
-+    target = llvm::TargetRegistry::lookupTarget(triple, tempError);
-+#else
-     target = llvm::TargetRegistry::lookupTarget(triple.getTriple(), tempError);
-+#endif
-     if (!target) {
-       errorMsg = "unable to get target for '" + triple.getTriple() +
-                  "', see -version and -mtriple.";
-@@ -440,8 +436,8 @@ createTargetMachine(const std::string targetTriple, const std::string arch,
-                     std::string cpu, const std::string featuresString,
-                     const ExplicitBitness::Type bitness,
-                     FloatABI::Type &floatABI,
--                    llvm::Optional<llvm::Reloc::Model> relocModel,
--                    llvm::Optional<llvm::CodeModel::Model> codeModel,
-+                    std::optional<llvm::Reloc::Model> relocModel,
-+                    std::optional<llvm::CodeModel::Model> codeModel,
-                     const llvm::CodeGenOptLevel codeGenOptLevel,
-                     const bool noLinkerStripDead) {
-   // Determine target triple. If the user didn't explicitly specify one, use
-@@ -543,19 +539,12 @@ createTargetMachine(const std::string targetTriple, const std::string arch,
- 
-   // For LoongArch 64-bit target default to la64 if nothing has been selected
-   // All current LoongArch targets have 64-bit floating point registers.
--#if LDC_LLVM_VER >= 1600
-   if (triple.getArch() == llvm::Triple::loongarch64 && features.empty()) {
-     features = {"+d"};
-   }
--#endif
- 
-   // Handle cases where LLVM picks wrong default relocModel
--#if LDC_LLVM_VER >= 1600
--  if (relocModel.has_value()) {}
--#else
--  if (relocModel.hasValue()) {}
--#endif
--  else {
-+  if (!relocModel.has_value()) {
-     if (triple.isOSDarwin()) {
-       // Darwin defaults to PIC (and as of 10.7.5/LLVM 3.1-3.3, TLS use leads
-       // to crashes for non-PIC code). LLVM doesn't handle this.
-@@ -636,11 +625,6 @@ createTargetMachine(const std::string targetTriple, const std::string arch,
-   // EmuTLS).
-   if (triple.getEnvironment() == llvm::Triple::Android) {
-     targetOptions.EmulatedTLS = false;
--#if LDC_LLVM_VER < 1700
--    // Removed in this commit:
--    // https://github.com/llvm/llvm-project/commit/0d333bf0e3aa37e2e6ae211e3aa80631c3e01b85
--    targetOptions.ExplicitEmulatedTLS = true;
--#endif
-   }
- 
-   const std::string finalFeaturesString =
-@@ -653,7 +637,7 @@ createTargetMachine(const std::string targetTriple, const std::string arch,
-   }
- 
-   return target->createTargetMachine(
--#if LDC_LLVM_VER >= 2100
-+#if LLVM_VERSION_MAJOR >= 21
-                                      triple,
- #else
-                                      triple.str(),
-diff --git a/driver/targetmachine.h b/driver/targetmachine.h
-index 3bfa567e4f..e0c21ee140 100644
---- a/driver/targetmachine.h
-+++ b/driver/targetmachine.h
-@@ -14,24 +14,12 @@
- 
- #pragma once
- 
--#if LDC_LLVM_VER < 1700
--#include "llvm/ADT/Optional.h"
--#else
--#include <optional>
--namespace llvm {
--template <typename T> using Optional = std::optional<T>;
--}
--#endif
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/Support/CodeGen.h"
-+#include <optional>
- #include <string>
- #include <vector>
--namespace llvm {
--#if LDC_LLVM_VER < 1800
--using CodeGenOptLevel = llvm::CodeGenOpt::Level;
--#endif
--}
- 
- namespace ExplicitBitness {
- enum Type { None, M32, M64 };
-@@ -69,8 +57,8 @@ llvm::TargetMachine *
- createTargetMachine(std::string targetTriple, std::string arch, std::string cpu,
-                     std::string featuresString, ExplicitBitness::Type bitness,
-                     FloatABI::Type &floatABI,
--                    llvm::Optional<llvm::Reloc::Model> relocModel,
--                    llvm::Optional<llvm::CodeModel::Model> codeModel,
-+                    std::optional<llvm::Reloc::Model> relocModel,
-+                    std::optional<llvm::CodeModel::Model> codeModel,
-                     llvm::CodeGenOptLevel codeGenOptLevel,
-                     bool noLinkerStripDead);
- 
-diff --git a/driver/toobj.cpp b/driver/toobj.cpp
-index f9789452f4..211d8d88f4 100644
---- a/driver/toobj.cpp
-+++ b/driver/toobj.cpp
-@@ -37,34 +37,14 @@
- #include "llvm/CodeGen/TargetSubtargetInfo.h"
- #include "llvm/Transforms/Utils/Cloning.h"
- #include "llvm/IR/Module.h"
--#ifdef LDC_LLVM_SUPPORTED_TARGET_SPIRV
--#if LDC_LLVM_VER < 1600
--#include "LLVMSPIRVLib/LLVMSPIRVLib.h"
--#endif
--#endif
- #include <cstddef>
- #include <fstream>
- 
--using CodeGenFileType = llvm::CodeGenFileType;
--
--#if LDC_LLVM_VER >= 1800
--constexpr llvm::CodeGenFileType CGFT_AssemblyFile = CodeGenFileType::AssemblyFile;
--constexpr llvm::CodeGenFileType CGFT_ObjectFile = CodeGenFileType::ObjectFile;
--#endif
--
--#if LDC_LLVM_VER < 1700
--static llvm::cl::opt<bool>
--    NoIntegratedAssembler("no-integrated-as", llvm::cl::ZeroOrMore,
--                          llvm::cl::Hidden,
--                          llvm::cl::desc("Disable integrated assembler"));
--#else
- namespace llvm {
- namespace codegen {
- bool getDisableIntegratedAS();
- }
- }
--#define NoIntegratedAssembler llvm::codegen::getDisableIntegratedAS()
--#endif
- 
- namespace {
- 
-@@ -81,21 +61,13 @@ void runDLLImportRelocationPass(llvm::TargetMachine &Target, llvm::Module &m) {
- // based on llc code, University of Illinois Open Source License
- void codegenModule(llvm::TargetMachine &Target, llvm::Module &m,
-                    const char *filename,
--                   CodeGenFileType fileType) {
-+                   llvm::CodeGenFileType fileType) {
-   using namespace llvm;
- 
-   const ComputeBackend::Type cb = getComputeTargetType(&m);
- 
-   if (cb == ComputeBackend::SPIRV) {
--#ifdef LDC_LLVM_SUPPORTED_TARGET_SPIRV
--#if LDC_LLVM_VER < 1600
--    IF_LOG Logger::println("running createSPIRVWriterPass()");
--    std::ofstream out(filename, std::ofstream::binary);
--    llvm::createSPIRVWriterPass(out)->runOnModule(m);
--    IF_LOG Logger::println("Success.");
--    return;
--#endif
--#else
-+#ifndef LDC_LLVM_SUPPORTED_TARGET_SPIRV
-     error(Loc(), "Trying to target SPIRV, but LDC is not built to do so!");
-     return;
- #endif
-@@ -132,11 +104,8 @@ void codegenModule(llvm::TargetMachine &Target, llvm::Module &m,
-           nullptr,  // DWO output file
-           // Always generate assembly for ptx as it is an assembly format
-           // The PTX backend fails if we pass anything else.
--          (cb == ComputeBackend::NVPTX) ? CGFT_AssemblyFile : fileType
--#if LDC_LLVM_VER < 1700
--          , codeGenOptLevel()
--#endif
--      )) {
-+          (cb == ComputeBackend::NVPTX) ? CodeGenFileType::AssemblyFile
-+                                        : fileType)) {
-     llvm_unreachable("no support for asm output");
-   }
- 
-@@ -300,14 +269,14 @@ public:
- void writeObjectFile(llvm::Module *m, const char *filename) {
-   IF_LOG Logger::println("Writing object file to: %s", filename);
-   codegenModule(*gTargetMachine, *m, filename,
--                CGFT_ObjectFile);
-+                llvm::CodeGenFileType::ObjectFile);
- }
- 
- bool shouldAssembleExternally() {
-   // There is no integrated assembler on AIX because XCOFF is not supported.
-   // Starting with LLVM 3.5 the integrated assembler can be used with MinGW.
-   return global.params.output_o &&
--         (NoIntegratedAssembler ||
-+         (llvm::codegen::getDisableIntegratedAS() ||
-           global.params.targetTriple->getOS() == llvm::Triple::AIX);
- }
- 
-@@ -479,10 +448,10 @@ void writeModule(llvm::Module *m, const char *filename) {
-       // to avoid running 'addPassesToEmitFile' passes twice on same module
-       auto clonedModule = llvm::CloneModule(*m);
-       codegenModule(*gTargetMachine, *clonedModule, spath.c_str(),
--                    CGFT_AssemblyFile);
-+                    llvm::CodeGenFileType::AssemblyFile);
-     } else {
-       codegenModule(*gTargetMachine, *m, spath.c_str(),
--                    CGFT_AssemblyFile);
-+                    llvm::CodeGenFileType::AssemblyFile);
-     }
- 
-     if (assembleExternally) {
-diff --git a/driver/tool.cpp b/driver/tool.cpp
-index e64ec96cbd..31ff31cf83 100644
---- a/driver/tool.cpp
-+++ b/driver/tool.cpp
-@@ -20,12 +20,7 @@
- #include "llvm/Support/MemoryBuffer.h"
- #include "llvm/Support/Path.h"
- #include "llvm/Target/TargetMachine.h"
--
--#if LDC_LLVM_VER >= 1600
- #include "llvm/TargetParser/Host.h"
--#else
--#include "llvm/Support/Host.h"
--#endif
- 
- #ifdef _WIN32
- #include <Windows.h>
-@@ -214,12 +209,10 @@ void appendTargetArgsForGcc(std::vector<std::string> &args) {
-   case Triple::nvptx64:
-     args.push_back(triple.isArch64Bit() ? "-m64" : "-m32");
-     return;
--#if LDC_LLVM_VER >= 1600
-   // LoongArch does not use -m32/-m64 and uses -mabi=.
-   case Triple::loongarch64:
-     args.emplace_back(triple.isArch64Bit() ? "-mabi=lp64d" : "-mabi=ilp32d");
-     return;
--#endif // LDC_LLVM_VER >= 1600
-   // MIPS does not have -m32/-m64 but requires -mabi=.
-   case Triple::mips64:
-   case Triple::mips64el:
-diff --git a/gen/abi/abi.cpp b/gen/abi/abi.cpp
-index eab1ca5ca1..5e5a1baa20 100644
---- a/gen/abi/abi.cpp
-+++ b/gen/abi/abi.cpp
-@@ -158,11 +158,7 @@ llvm::CallingConv::ID TargetABI::callingConv(FuncDeclaration *fdecl) {
- void TargetABI::setUnwindTableKind(llvm::Function *fn) {
-   llvm::UWTableKind kind = defaultUnwindTableKind();
-   if (kind != llvm::UWTableKind::None) {
--#if LDC_LLVM_VER >= 1600
-     fn->setUWTableKind(kind);
--#else
--    fn->setUWTableKind(kind);
--#endif
-   }
- }
- 
-@@ -285,10 +281,8 @@ TargetABI *TargetABI::getTarget() {
-   case llvm::Triple::thumb:
-   case llvm::Triple::thumbeb:
-     return getArmTargetABI();
--#if LDC_LLVM_VER >= 1600
-   case llvm::Triple::loongarch64:
-     return getLoongArch64TargetABI();
--#endif // LDC_LLVM_VER >= 1600
-   case llvm::Triple::wasm32:
-   case llvm::Triple::wasm64:
-     return getWasmTargetABI();
-diff --git a/gen/abi/generic.h b/gen/abi/generic.h
-index 6458d28b8b..4def40c790 100644
---- a/gen/abi/generic.h
-+++ b/gen/abi/generic.h
-@@ -260,7 +260,7 @@ struct IndirectByvalRewrite : ABIRewrite {
-     auto &attrs = arg.attrs;
-     attrs.clear();
-     attrs.addAttribute(LLAttribute::NoAlias);
--#if LDC_LLVM_VER >= 2100
-+#if LLVM_VERSION_MAJOR >= 21
-     attrs.addCapturesAttr(llvm::CaptureInfo::none());
- #else
-     attrs.addAttribute(LLAttribute::NoCapture);
-diff --git a/gen/abi/nvptx.cpp b/gen/abi/nvptx.cpp
-index cd81b6261f..31cf01d946 100644
---- a/gen/abi/nvptx.cpp
-+++ b/gen/abi/nvptx.cpp
-@@ -38,7 +38,7 @@ struct NVPTXTargetABI : TargetABI {
-       return;
- 
-     Type *ty = arg.type->toBasetype();
--    llvm::Optional<DcomputePointer> ptr;
-+    std::optional<DcomputePointer> ptr;
-     if (ty->ty == TY::Tstruct &&
-         (ptr = toDcomputePointer(static_cast<TypeStruct *>(ty)->sym))) {
-       pointerRewite.applyTo(arg);
-diff --git a/gen/abi/spirv.cpp b/gen/abi/spirv.cpp
-index 60a3eada37..df8a487acc 100644
---- a/gen/abi/spirv.cpp
-+++ b/gen/abi/spirv.cpp
-@@ -44,7 +44,7 @@ struct SPIRVTargetABI : TargetABI {
-       return;
- 
-     Type *ty = arg.type->toBasetype();
--    llvm::Optional<DcomputePointer> ptr;
-+    std::optional<DcomputePointer> ptr;
-     if (ty->ty == TY::Tstruct &&
-         (ptr = toDcomputePointer(static_cast<TypeStruct *>(ty)->sym))) {
-       pointerRewite.applyTo(arg);
-diff --git a/gen/arrays.cpp b/gen/arrays.cpp
-index 8179679d10..a27c4338e6 100644
---- a/gen/arrays.cpp
-+++ b/gen/arrays.cpp
-@@ -533,11 +533,7 @@ llvm::Constant *arrayLiteralToConst(IRState *p, ArrayLiteralExp *ale) {
-     // extend i1 to i8
-     if (val->getType()->isIntegerTy(1)) {
-       LLType *I8PtrTy = LLType::getInt8Ty(p->context());
--#if LDC_LLVM_VER < 1800
--      val = llvm::ConstantExpr::getZExt(val, I8PtrTy);
--#else
-       val = llvm::ConstantFoldCastOperand(llvm::Instruction::ZExt, val, I8PtrTy, *gDataLayout);
--#endif
-     }
-     if (!elementType) {
-       elementType = val->getType();
-diff --git a/gen/asm-gcc.cpp b/gen/asm-gcc.cpp
-index 9df3c55c2e..60026c6f98 100644
---- a/gen/asm-gcc.cpp
-+++ b/gen/asm-gcc.cpp
-@@ -63,10 +63,6 @@ class ConstraintsBuilder {
-   // Appends a constraint string expression with an optional prefix.
-   // Returns true if the string describes an indirect operand.
-   bool append(Expression *e, char prefix = 0) {
--#if LDC_LLVM_VER >= 1800
--    #define startswith starts_with
--#endif
--
-     auto se = e->isStringExp();
-     assert(se);
-     llvm::StringRef code = peekString(se);
-@@ -81,10 +77,10 @@ class ConstraintsBuilder {
- 
-     // commit any modifier and strip from `code`
-     bool isIndirect = false;
--    if (code.startswith("&")) { // early clobber
-+    if (code.starts_with("&")) { // early clobber
-       str << '&';
-       code = code.substr(1);
--    } else if (code.startswith("*")) { // indirect in/output
-+    } else if (code.starts_with("*")) { // indirect in/output
-       isIndirect = true; // delay the commit
-       code = code.substr(1);
-     }
-@@ -97,10 +93,6 @@ class ConstraintsBuilder {
-     str << ',';
- 
-     return isIndirect;
--
--#if LDC_LLVM_VER >= 1800
--    #undef startswith
--#endif
-   }
- 
-   // Might set `isIndirect` to true (but never resets to false).
-diff --git a/gen/asm-x86.h b/gen/asm-x86.h
-index eecd1a8b65..2104b4155c 100644
---- a/gen/asm-x86.h
-+++ b/gen/asm-x86.h
-@@ -2340,57 +2340,15 @@ struct AsmProcessor {
-                   AsmCode *asmcode, AsmArgMode mode = Mode_Input) {
-     using namespace dmd;
- 
--    if (sc->func->isNaked()) {
--      switch (type) {
--      case Arg_Integer:
--        if (e->type->isUnsigned()) {
--          insnTemplate << "$" << e->toUInteger();
--        } else {
-+    if (type == Arg_Integer) {
-+      if (e->type->isUnsigned()) {
-+        insnTemplate << "$$" << e->toUInteger();
-+      } else {
- #ifndef ASM_X86_64
--          insnTemplate << "$" << static_cast<sinteger_t>(e->toInteger());
-+        insnTemplate << "$$" << static_cast<sinteger_t>(e->toInteger());
- #else
--          insnTemplate << "$" << e->toInteger();
-+        insnTemplate << "$$" << e->toInteger();
- #endif
--        }
--        break;
--
--      case Arg_Pointer:
--        error(stmt->loc, "unsupported pointer reference to `%s` in naked asm",
--                    e->toChars());
--        break;
--
--      case Arg_Memory:
--        // Peel off one layer of explicitly taking the address, if present.
--        if (auto ae = e->isAddrExp()) {
--          e = ae->e1;
--        }
--
--        if (auto v = e->isVarExp()) {
--          if (VarDeclaration *vd = v->var->isVarDeclaration()) {
--            if (!vd->isDataseg()) {
--              error(stmt->loc, "only global variables can be referenced by "
--                          "identifier in naked asm");
--              break;
--            }
--
--            // print out the mangle
--            if (prependExtraUnderscore(vd->resolvedLinkage())) {
--              insnTemplate << "_";
--            }
--            OutBuffer buf;
--            mangleToBuffer(vd, buf);
--            insnTemplate << buf.peekChars();
--            getIrGlobal(vd, true)->nakedUse = true;
--            break;
--          }
--        }
--        error(stmt->loc, "unsupported memory reference to `%s` in naked asm",
--                    e->toChars());
--        break;
--
--      default:
--        llvm_unreachable("Unsupported argument in asm.");
--        break;
-       }
-     } else {
-       insnTemplate << fmt << "<<" << (mode == Mode_Input ? "in" : "out")
-@@ -2401,13 +2359,6 @@ struct AsmProcessor {
-   void addOperand2(const char *fmtpre, const char *fmtpost, AsmArgType type,
-                    Expression *e, AsmCode *asmcode,
-                    AsmArgMode mode = Mode_Input) {
--    if (sc->func->isNaked()) {
--      // taken from above
--      error(stmt->loc, "only global variables can be referenced by identifier in "
--                  "naked asm");
--      return;
--    }
--
-     insnTemplate << fmtpre << "<<" << (mode == Mode_Input ? "in" : "out")
-                  << ">>" << fmtpost;
-     asmcode->args.push_back(AsmArg(type, e, mode));
-@@ -3078,11 +3029,9 @@ struct AsmProcessor {
-               // If we subtract 8 from our const-displacement, then we can use the `H` modifier to ensure
-               // that we always end up with a valid syntax for a memory operand with an offset.
-               // So, we do just that when we have const-displacement in play.
--              // (Only for non-naked asm, as this isn't an issue for naked asm.)
-               //
-               // See also: https://lists.llvm.org/pipermail/llvm-dev/2017-August/116244.html
--              const auto forceLeadingDisplacement = hasConstDisplacement && !sc->func->isNaked();
--              if (forceLeadingDisplacement) {
-+              if (hasConstDisplacement) {
-                 // Subtract 8 from our const-displacement, and prepare to add the 8 from the `H` modifier.
-                 insnTemplate << "-8+";
-               }
-@@ -3092,14 +3041,11 @@ struct AsmProcessor {
-                 use_star = false;
-               }
- 
--              if (!sc->func->isNaked()) // no addrexp in naked asm please :)
--              {
--                Type *tt = pointerTo(e->type);
--                e = createAddrExp(Loc(), e);
--                e->type = tt;
--              }
-+              Type *tt = pointerTo(e->type);
-+              e = createAddrExp(Loc(), e);
-+              e->type = tt;
- 
--              if (forceLeadingDisplacement) {
-+              if (hasConstDisplacement) {
-                 // We have a const-displacement in play, so we add the `H` modifier, as described earlier.
-                 insnTemplate << "${" << "<<" << (mode == Mode_Input ? "in" : "out")
-                              << asmcode->args.size() << ">>" << ":H}";
-diff --git a/gen/asmstmt.cpp b/gen/asmstmt.cpp
-index 12d364d012..b5c868a844 100644
---- a/gen/asmstmt.cpp
-+++ b/gen/asmstmt.cpp
-@@ -532,9 +532,14 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
-       }
-       Identifier *const ident = targetLabel->ident;
- 
--      // if internal, no special handling is necessary, skip
--      if (llvm::any_of(asmblock->internalLabels,
--                       [ident](Identifier *i) { return i->equals(ident); })) {
-+      // if the label is defined in inline asm, we can jump to it directly
-+      if (fd->isNaked() // in naked DMD-style inline-asm functions, all D labels
-+                        // become assembly labels too (and the extra forwarding
-+                        // code would mess with the stack due to an i32 alloca)
-+          || (fd->asmLabels &&
-+              llvm::any_of(*fd->asmLabels, [ident](Identifier *i) {
-+                return i->equals(ident);
-+              }))) {
-         continue;
-       }
- 
-@@ -784,21 +789,3 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
-     p->ir->SetInsertPoint(bb);
-   }
- }
--
--//////////////////////////////////////////////////////////////////////////////
--
--void AsmStatement_toNakedIR(InlineAsmStatement *stmt, IRState *irs) {
--  IF_LOG Logger::println("InlineAsmStatement::toNakedIR(): %s",
--                         stmt->loc.toChars());
--  LOG_SCOPE;
--
--  // is there code?
--  if (!stmt->asmcode) {
--    return;
--  }
--  AsmCode *code = static_cast<AsmCode *>(stmt->asmcode);
--
--  // build asm stmt
--  replace_func_name(irs, code->insnTemplate);
--  irs->nakedAsm << "\t" << code->insnTemplate << std::endl;
--}
-diff --git a/gen/ctfloat.cpp b/gen/ctfloat.cpp
-index ef033c018d..9ce8ad72d7 100644
---- a/gen/ctfloat.cpp
-+++ b/gen/ctfloat.cpp
-@@ -83,7 +83,11 @@ void CTFloat::toAPFloat(const real_t src, APFloat &dst) {
-   u.fp = src;
- 
-   const unsigned sizeInBits = APFloat::getSizeInBits(*apSemantics);
-+#if LLVM_VERSION_MAJOR >= 22
-+  const APInt bits = APInt(sizeInBits, u.bits);
-+#else
-   const APInt bits = APInt(sizeInBits, numUint64Parts, u.bits);
-+#endif
- 
-   dst = APFloat(*apSemantics, bits);
- }
-diff --git a/gen/dcompute/druntime.cpp b/gen/dcompute/druntime.cpp
-index 0f2c79bd4c..829185481c 100644
---- a/gen/dcompute/druntime.cpp
-+++ b/gen/dcompute/druntime.cpp
-@@ -43,17 +43,13 @@ bool isFromLDC_OpenCL(Dsymbol *sym) {
-   return isFromLDC_Mod(sym,Id::opencl);
- }
- 
--llvm::Optional<DcomputePointer> toDcomputePointer(StructDeclaration *sd) {
-+std::optional<DcomputePointer> toDcomputePointer(StructDeclaration *sd) {
-   if (sd->ident != Id::dcPointer || !isFromLDC_DCompute(sd)) {
--#if LDC_LLVM_VER < 1600
--    return llvm::Optional<DcomputePointer>(llvm::None);
--#else
-     return std::optional<DcomputePointer>(std::nullopt);
--#endif
-   }
- 
-   TemplateInstance *ti = sd->isInstantiated();
-   int addrspace = isExpression((*ti->tiargs)[0])->toInteger();
-   Type *type = isType((*ti->tiargs)[1]);
--  return llvm::Optional<DcomputePointer>(DcomputePointer(addrspace, type));
-+  return std::optional<DcomputePointer>(DcomputePointer(addrspace, type));
- }
-diff --git a/gen/dcompute/druntime.h b/gen/dcompute/druntime.h
-index 6ff3b2c8a8..673eb24951 100644
---- a/gen/dcompute/druntime.h
-+++ b/gen/dcompute/druntime.h
-@@ -18,14 +18,7 @@
- #include "gen/irstate.h"
- #include "gen/llvm.h"
- #include "gen/tollvm.h"
--#if LDC_LLVM_VER < 1700
--#include "llvm/ADT/Optional.h"
--#else
- #include <optional>
--namespace llvm {
--template <typename T> using Optional = std::optional<T>;
--}
--#endif
- 
- class Dsymbol;
- class Type;
-@@ -45,4 +38,4 @@ struct DcomputePointer {
-     return LLPointerType::get(getGlobalContext(), as);
-   }
- };
--llvm::Optional<DcomputePointer> toDcomputePointer(StructDeclaration *sd);
-+std::optional<DcomputePointer> toDcomputePointer(StructDeclaration *sd);
-diff --git a/gen/dcompute/targetCUDA.cpp b/gen/dcompute/targetCUDA.cpp
-index ffd2711acc..9861cb2764 100644
---- a/gen/dcompute/targetCUDA.cpp
-+++ b/gen/dcompute/targetCUDA.cpp
-@@ -43,7 +43,7 @@ public:
-         llvm::Reloc::Static, llvm::CodeModel::Medium, codeGenOptLevel(), false);
- 
-     _ir = new IRState("dcomputeTargetCUDA", ctx);
--#if LDC_LLVM_VER >= 2100
-+#if LLVM_VERSION_MAJOR >= 21
-     _ir->module.setTargetTriple(llvm::Triple(tripleString));
- #else
-     _ir->module.setTargetTriple(tripleString);
-diff --git a/gen/dcompute/targetOCL.cpp b/gen/dcompute/targetOCL.cpp
-index b93850c95e..e0fa37310e 100644
---- a/gen/dcompute/targetOCL.cpp
-+++ b/gen/dcompute/targetOCL.cpp
-@@ -24,7 +24,7 @@
- #include <string>
- 
- // from SPIRVInternal.h
--#if LDC_LLVM_VER < 1900
-+#if LLVM_VERSION_MAJOR < 19
- #  define SPIR_TARGETTRIPLE32 "spir-unknown-unknown"
- #  define SPIR_TARGETTRIPLE64 "spir64-unknown-unknown"
- #  define SPIR_DATALAYOUT32                                                    \
-@@ -42,7 +42,7 @@
- #else // LLVM 19+
- #  define SPIR_TARGETTRIPLE32 "spirv-unknown-unknown"
- #  define SPIR_TARGETTRIPLE64 "spirv64-unknown-unknown"
--#  if LDC_LLVM_VER < 2000
-+#  if LLVM_VERSION_MAJOR < 20
- #    define SPIR_DATALAYOUT32                                                  \
-        "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64"                          \
-        "-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1"
-@@ -75,14 +75,13 @@ public:
-     _ir = new IRState("dcomputeTargetOCL", ctx);
-     std::string targTripleStr = is64 ? SPIR_TARGETTRIPLE64
-                                      : SPIR_TARGETTRIPLE32;
--#if LDC_LLVM_VER >= 2100
-+#if LLVM_VERSION_MAJOR >= 21
-     llvm::Triple targTriple = llvm::Triple(targTripleStr);
- #else
-     std::string targTriple = targTripleStr;
- #endif
-     _ir->module.setTargetTriple(targTriple);
- 
--#if LDC_LLVM_VER >= 1600
-     auto floatABI = ::FloatABI::Hard;
-     targetMachine = createTargetMachine(
-             targTripleStr,
-@@ -90,7 +89,6 @@ public:
-             "", {},
-             is64 ? ExplicitBitness::M64 : ExplicitBitness::M32, floatABI,
-             llvm::Reloc::Static, llvm::CodeModel::Medium, codeGenOptLevel(), false);
--#endif
-     _ir->module.setDataLayout(is64 ? SPIR_DATALAYOUT64 : SPIR_DATALAYOUT32);
-     _ir->dcomputetarget = this;
-   }
-@@ -200,7 +198,7 @@ public:
-   void decodeTypes(std::array<llvm::SmallVector<llvm::Metadata *, 8>,count_KernArgMD>& attrs,
-                    VarDeclaration *v)
-   {
--    llvm::Optional<DcomputePointer> ptr;
-+    std::optional<DcomputePointer> ptr;
-     std::string typeQuals;
-     std::string baseTyName;
-     std::string tyName;
-diff --git a/gen/declarations.cpp b/gen/declarations.cpp
-index bdadc84c61..0e43a20ff6 100644
---- a/gen/declarations.cpp
-+++ b/gen/declarations.cpp
-@@ -412,24 +412,19 @@ public:
-   void visit(PragmaDeclaration *decl) override {
-     const auto &triple = *global.params.targetTriple;
- 
--#if LDC_LLVM_VER >= 1800
--    #define endswith ends_with
--    #define startswith starts_with
--#endif
--
-     if (decl->ident == Id::lib) {
-       assert(!irs->dcomputetarget);
-       llvm::StringRef name = getPragmaStringArg(decl);
- 
-       if (triple.isWindowsGNUEnvironment()) {
--        if (name.endswith(".lib")) {
-+        if (name.ends_with(".lib")) {
-           // On MinGW, strip the .lib suffix, if any, to improve compatibility
-           // with code written for DMD (we pass the name to GCC via -l, just as
-           // on Posix).
-           name = name.drop_back(4);
-         }
- 
--        if (name.startswith("shell32")) {
-+        if (name.starts_with("shell32")) {
-           // Another DMD compatibility kludge: Ignore
-           // pragma(lib, "shell32.lib"), it is implicitly provided by
-           // MinGW.
-@@ -438,10 +433,10 @@ public:
-       }
- 
-       if (triple.isWindowsMSVCEnvironment()) {
--        if (name.endswith(".a")) {
-+        if (name.ends_with(".a")) {
-           name = name.drop_back(2);
-         }
--        if (name.endswith(".lib")) {
-+        if (name.ends_with(".lib")) {
-           name = name.drop_back(4);
-         }
- 
-@@ -450,7 +445,7 @@ public:
-         std::string arg = ("/DEFAULTLIB:\"" + name + "\"").str();
-         gIR->addLinkerOption(llvm::StringRef(arg));
-       } else {
--        const bool isStaticLib = name.endswith(".a");
-+        const bool isStaticLib = name.ends_with(".a");
-         const size_t nameLen = name.size();
- 
-         char *arg = nullptr;
-@@ -490,11 +485,6 @@ public:
-       }
-     }
-     visit(static_cast<AttribDeclaration *>(decl));
--
--#if LDC_LLVM_VER >= 1800
--    #undef endswith
--    #undef startswith
--#endif
-   }
- 
-   //////////////////////////////////////////////////////////////////////////
-diff --git a/gen/dibuilder.cpp b/gen/dibuilder.cpp
-index 21b176ef00..df1328ecdb 100644
---- a/gen/dibuilder.cpp
-+++ b/gen/dibuilder.cpp
-@@ -47,13 +47,6 @@ using namespace dmd;
- namespace cl = llvm::cl;
- using LLMetadata = llvm::Metadata;
- 
--#if LDC_LLVM_VER >= 1600
--namespace llvm {
--  template <typename T> using Optional = std::optional<T>;
--  inline constexpr std::nullopt_t None = std::nullopt;
--}
--#endif
--
- static cl::opt<cl::boolOrDefault> emitColumnInfo(
-     "gcolumn-info", cl::ZeroOrMore, cl::Hidden,
-     cl::desc("Include column numbers in line debug infos. Defaults to "
-@@ -426,7 +419,7 @@ DIType DIBuilder::CreateEnumType(TypeEnum *type) {
- DIType DIBuilder::CreatePointerType(TypePointer *type) {
-   // TODO: The addressspace is important for dcompute targets. See e.g.
-   // https://www.mail-archive.com/dwarf-discuss@lists.dwarfstd.org/msg00326.html
--  const llvm::Optional<unsigned> DWARFAddressSpace = llvm::None;
-+  const std::optional<unsigned> DWARFAddressSpace;
- 
-   const auto name = processDIName(type->toPrettyChars(true));
- 
-@@ -672,10 +665,7 @@ DIType DIBuilder::CreateCompositeType(Type *t) {
-     ret = DBuilder.createClassType(
-         scope, name, file, lineNum, sizeInBits, alignmentInBits,
-         classOffsetInBits, DIFlags::FlagZero, derivedFrom, elemsArray,
--#if LDC_LLVM_VER >= 1800
--        runtimeLang,
--#endif
--        vtableHolder, templateParams, uniqueIdentifier);
-+        runtimeLang, vtableHolder, templateParams, uniqueIdentifier);
-   } else {
-     ret = DBuilder.createStructType(scope, name, file, lineNum, sizeInBits,
-                                     alignmentInBits, DIFlags::FlagZero,
-@@ -799,7 +789,7 @@ DISubroutineType DIBuilder::CreateFunctionType(Type *type,
-       DIType ditype = DBuilder.createReferenceType(
-           llvm::dwarf::DW_TAG_pointer_type, pointeeType, target.ptrsize * 8);
-       ditype = DBuilder.createObjectPointerType(ditype
--#if LDC_LLVM_VER >= 2000
-+#if LLVM_VERSION_MAJOR >= 20
-       , /* Implicit */ true
- #endif
-       );
-@@ -819,11 +809,7 @@ DISubroutineType DIBuilder::CreateFunctionType(Type *type,
- }
- 
- DISubroutineType DIBuilder::CreateEmptyFunctionType() {
--#if LDC_LLVM_VER >= 2100 
-   auto paramsArray = DBuilder.getOrCreateTypeArray({});
--#else
--  auto paramsArray = DBuilder.getOrCreateTypeArray(llvm::None);
--#endif
-   return DBuilder.createSubroutineType(paramsArray);
- }
- 
-@@ -869,7 +855,7 @@ DIType DIBuilder::CreateTypeDescription(Type *t, bool voidToUbyte) {
-     // display null as void*
-     return DBuilder.createPointerType(
-         CreateTypeDescription(Type::tvoid), target.ptrsize * 8, 0,
--        /* DWARFAddressSpace */ llvm::None, "typeof(null)");
-+        /* DWARFAddressSpace */ std::nullopt, "typeof(null)");
-   }
-   if (auto te = t->isTypeEnum())
-     return CreateEnumType(te);
-@@ -892,7 +878,7 @@ DIType DIBuilder::CreateTypeDescription(Type *t, bool voidToUbyte) {
-     const auto name =
-         (tc->sym->toPrettyChars(true) + llvm::StringRef("*")).str();
-     return DBuilder.createPointerType(aggregateDIType, target.ptrsize * 8, 0,
--                                      llvm::None, processDIName(name));
-+                                      std::nullopt, processDIName(name));
-   }
-   if (auto tf = t->isTypeFunction())
-     return CreateFunctionType(tf);
-@@ -1229,7 +1215,7 @@ void DIBuilder::EmitValue(llvm::Value *val, VarDeclaration *vd) {
-   auto instr = DBuilder.insertDbgValueIntrinsic(
-       val, debugVariable, DBuilder.createExpression(),
-       IR->ir->getCurrentDebugLocation(), IR->scopebb());
--#if LDC_LLVM_VER >= 1900
-+#if LLVM_VERSION_MAJOR >= 19
-   llvm::cast<llvm::DbgRecord *>
- #endif
-   (instr)->setDebugLoc(IR->ir->getCurrentDebugLocation());
-diff --git a/gen/functions.cpp b/gen/functions.cpp
-index 3c3e6d3d35..b1e106f6bc 100644
---- a/gen/functions.cpp
-+++ b/gen/functions.cpp
-@@ -773,10 +773,8 @@ static LinkageWithCOMDAT lowerFuncLinkage(FuncDeclaration *fdecl) {
-     return LinkageWithCOMDAT(LLGlobalValue::ExternalLinkage, false);
-   }
- 
--  // A body-less declaration always needs to be marked as external in LLVM
--  // (also e.g. naked template functions which would otherwise be weak_odr,
--  // but where the definition is in module-level inline asm).
--  if (!fdecl->fbody || fdecl->isNaked()) {
-+  // A body-less declaration always needs to be marked as external in LLVM.
-+  if (!fdecl->fbody) {
-     return LinkageWithCOMDAT(LLGlobalValue::ExternalLinkage, false);
-   }
- 
-@@ -910,10 +908,6 @@ bool eraseDummyAfterReturnBB(llvm::BasicBlock *bb) {
-  * to be found.
-  */
- void emulateWeakAnyLinkageForMSVC(IrFunction *irFunc, LINK linkage) {
--#if LDC_LLVM_VER >= 1800
--  #define startswith starts_with
--#endif
--
-   LLFunction *func = irFunc->getLLVMFunc();
- 
-   const bool isWin32 = global.params.targetTriple->isArch32Bit();
-@@ -930,18 +924,18 @@ void emulateWeakAnyLinkageForMSVC(IrFunction *irFunc, LINK linkage) {
- 
-   std::string finalWeakMangle = finalMangle.str();
-   if (linkage == LINK::cpp) {
--    assert(finalMangle.startswith("?"));
-+    assert(finalMangle.starts_with("?"));
-     // prepend `__weak_` to first identifier
--    size_t offset = finalMangle.startswith("??$") ? 3 : 1;
-+    size_t offset = finalMangle.starts_with("??$") ? 3 : 1;
-     finalWeakMangle.insert(offset, "__weak_");
-   } else if (linkage == LINK::d) {
-     const size_t offset = isWin32 ? 1 : 0;
--    assert(finalMangle.substr(offset).startswith("_D"));
-+    assert(finalMangle.substr(offset).starts_with("_D"));
-     // prepend a `__weak` package
-     finalWeakMangle.insert(offset + 2, "6__weak");
-   } else {
-     // prepend `__weak_`
--    const size_t offset = isWin32 && finalMangle.startswith("_") ? 1 : 0;
-+    const size_t offset = isWin32 && finalMangle.starts_with("_") ? 1 : 0;
-     finalWeakMangle.insert(offset, "__weak_");
-   }
- 
-@@ -965,10 +959,6 @@ void emulateWeakAnyLinkageForMSVC(IrFunction *irFunc, LINK linkage) {
-   // declaration
-   irFunc->setLLVMFunc(newFunc);
-   func->replaceNonMetadataUsesWith(newFunc);
--
--#if LDC_LLVM_VER >= 1800
--  #undef startswith
--#endif
- }
- 
- } // anonymous namespace
-@@ -1127,12 +1117,6 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
-     gIR->funcGenStates.pop_back();
-   };
- 
--  // if this function is naked, we take over right away! no standard processing!
--  if (fd->isNaked()) {
--    DtoDefineNakedFunction(fd);
--    return;
--  }
--
-   SCOPE_EXIT {
-     if (irFunc->isDynamicCompiled()) {
-       defineDynamicCompiledFunction(gIR, irFunc);
-@@ -1172,6 +1156,10 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
-       func->addFnAttr(LLAttribute::SanitizeAddress);
-     }
- 
-+    if (opts::isSanitizerEnabled(opts::FuzzSanitizer)) {
-+      func->addFnAttr(LLAttribute::OptForFuzzing);
-+    }
-+    
-     if (opts::isSanitizerEnabled(opts::MemorySanitizer & noSanitizeMask)) {
-       func->addFnAttr(LLAttribute::SanitizeMemory);
-     }
-@@ -1190,7 +1178,9 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
-   if (opts::isUsingSampleBasedPGOProfile()) {
-     func->addFnAttr("use-sample-profile");
-   }
--
-+  if (opts::noBuiltIn) {
-+    func->addFnAttr("no-builtins");
-+  }
-   if (fd->hasInlineAsm()) {
-     // disable frame-pointer-elimination for functions with DMD-style inline asm
-     func->addFnAttr("frame-pointer", "all");
-@@ -1210,18 +1200,13 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
-   gIR->ir->setFastMathFlags(irFunc->FMF);
-   gIR->DBuilder.EmitFuncStart(fd);
- 
--  // @naked: emit body and return, no prologue/epilogue
--  if (func->hasFnAttribute(llvm::Attribute::Naked)) {
--    Statement_toIR(fd->fbody, gIR);
--    const bool wasDummy = eraseDummyAfterReturnBB(gIR->scopebb());
--    if (!wasDummy && !gIR->scopereturned()) {
--      // this is what clang does to prevent LLVM complaining about
--      // non-terminated function
--      gIR->ir->CreateUnreachable();
--    }
--    return;
-+  if (fd->isNaked()) { // DMD-style `asm { naked; }`
-+    func->addFnAttr(llvm::Attribute::Naked);
-   }
- 
-+  // @naked: emit body and return, no prologue/epilogue
-+  const bool isNaked = func->hasFnAttribute(llvm::Attribute::Naked);
-+
-   // create temporary allocas block
-   funcGen.allocasBlock =
-       llvm::BasicBlock::Create(gIR->context(), "allocas", func);
-@@ -1229,12 +1214,12 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
-   emitInstrumentationFnEnter(fd);
- 
-   if (global.params.trace && fd->emitInstrumentation && !fd->isCMain() &&
--      !fd->isNaked()) {
-+      !isNaked) {
-     emitDMDStyleFunctionTrace(*gIR, fd, funcGen);
-   }
- 
-   // give the 'this' parameter (an lvalue) storage and debug info
--  if (irFty.arg_this) {
-+  if (!isNaked && irFty.arg_this) {
-     LLValue *thisvar = irFunc->thisArg;
-     assert(thisvar);
- 
-@@ -1256,7 +1241,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
-   }
- 
-   // define all explicit parameters
--  if (fd->parameters)
-+  if (!isNaked && fd->parameters)
-     defineParameters(irFty, *fd->parameters);
- 
-   // Initialize PGO state for this function
-@@ -1322,7 +1307,10 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
- 
-     // pass the previous block into this block
-     gIR->DBuilder.EmitStopPoint(fd->endloc);
--    if (func->getReturnType() == LLType::getVoidTy(gIR->context())) {
-+
-+    if (isNaked) {
-+      gIR->ir->CreateUnreachable();
-+    } else if (func->getReturnType() == LLType::getVoidTy(gIR->context())) {
-       gIR->ir->CreateRetVoid();
-     } else if (isAnyMainFunction(fd)) {
-       gIR->ir->CreateRet(LLConstant::getNullValue(func->getReturnType()));
-@@ -1335,12 +1323,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
-   }
- 
-   // move allocas from temporary block to the start of the function
--#if LDC_LLVM_VER >= 1600
-   beginbb->splice(beginbb->begin(), funcGen.allocasBlock);
--#else
--  beginbb->getInstList().splice(beginbb->begin(),
--                                funcGen.allocasBlock->getInstList());
--#endif
-   funcGen.allocasBlock->eraseFromParent();
-   funcGen.allocasBlock = nullptr;
- 
-diff --git a/gen/functions.h b/gen/functions.h
-index 5dcfa7032d..609da95620 100644
---- a/gen/functions.h
-+++ b/gen/functions.h
-@@ -40,7 +40,6 @@ void DtoResolveFunction(FuncDeclaration *fdecl);
- void DtoDeclareFunction(FuncDeclaration *fdecl);
- void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally = false);
- 
--void DtoDefineNakedFunction(FuncDeclaration *fd);
- void emitABIReturnAsmStmt(IRAsmBlock *asmblock, Loc loc,
-                           FuncDeclaration *fdecl);
- 
-diff --git a/gen/irstate.cpp b/gen/irstate.cpp
-index 6834025129..364e825763 100644
---- a/gen/irstate.cpp
-+++ b/gen/irstate.cpp
-@@ -45,14 +45,14 @@ IrFunction *IRState::func() { return &funcGen().irFunc; }
- 
- llvm::Function *IRState::topfunc() { return func()->getLLVMFunc(); }
- 
--#if LDC_LLVM_VER >= 1900
-+#if LLVM_VERSION_MAJOR >= 19
- llvm::BasicBlock::iterator IRState::nextAllocaPos() {
- #else
- llvm::BasicBlock *IRState::nextAllocaPos() {
- #endif
-   return funcGen()
-       .allocasBlock
--#if LDC_LLVM_VER >= 1900
-+#if LLVM_VERSION_MAJOR >= 19
-       ->end()
- #endif
-       ;
-@@ -203,9 +203,7 @@ LLGlobalVariable *
- getCachedStringLiteralImpl(llvm::Module &module,
-                            llvm::StringMap<LLGlobalVariable *> &cache,
-                            llvm::StringRef key,
--#if LDC_LLVM_VER >= 1700
-                            std::optional< unsigned > addrspace,
--#endif
-                            F initFactory) {
-   auto iter = cache.find(key);
-   if (iter != cache.end()) {
-@@ -214,14 +212,9 @@ getCachedStringLiteralImpl(llvm::Module &module,
- 
-   LLConstant *constant = initFactory();
- 
--  auto gvar =
--      new LLGlobalVariable(module, constant->getType(), true,
--                           LLGlobalValue::PrivateLinkage, constant,
--                           ".str", nullptr, llvm::GlobalValue::NotThreadLocal
--#if LDC_LLVM_VER >= 1700
--                           , addrspace
--#endif
--                           );
-+  auto gvar = new LLGlobalVariable(
-+      module, constant->getType(), true, LLGlobalValue::PrivateLinkage,
-+      constant, ".str", nullptr, llvm::GlobalValue::NotThreadLocal, addrspace);
-   gvar->setUnnamedAddr(LLGlobalValue::UnnamedAddr::Global);
- 
-   cache[key] = gvar;
-@@ -261,30 +254,18 @@ LLGlobalVariable *IRState::getCachedStringLiteral(StringExp *se) {
-   const llvm::StringRef key(reinterpret_cast<const char *>(keyData.ptr),
-                             keyData.length);
- 
--  return getCachedStringLiteralImpl(module, *cache, key,
--#if LDC_LLVM_VER >= 1700
--                                    std::nullopt,
--#endif
--                                    [se]() {
-+  return getCachedStringLiteralImpl(module, *cache, key, std::nullopt, [se]() {
-     // null-terminate
-     return buildStringLiteralConstant(se, se->len + 1);
-   });
- }
- 
--LLGlobalVariable *IRState::getCachedStringLiteral(llvm::StringRef s
--#if LDC_LLVM_VER >= 1700
--                                                  ,std::optional< unsigned > addrspace
--#endif
--                                                  ) {
--  return getCachedStringLiteralImpl(module,
--                                    cachedStringLiterals,
--                                    s,
--#if LDC_LLVM_VER >= 1700
--                                    addrspace,
--#endif
--                                    [&]() {
--    return llvm::ConstantDataArray::getString(context(), s, true);
--  });
-+LLGlobalVariable *
-+IRState::getCachedStringLiteral(llvm::StringRef s,
-+                                std::optional<unsigned> addrspace) {
-+  return getCachedStringLiteralImpl(
-+      module, cachedStringLiterals, s, addrspace,
-+      [&]() { return llvm::ConstantDataArray::getString(context(), s, true); });
- }
- 
- ////////////////////////////////////////////////////////////////////////////////
-diff --git a/gen/irstate.h b/gen/irstate.h
-index 25e963dce9..0e8983a9f7 100644
---- a/gen/irstate.h
-+++ b/gen/irstate.h
-@@ -24,10 +24,10 @@
- #include "llvm/ProfileData/InstrProfReader.h"
- #include <deque>
- #include <memory>
-+#include <optional>
- #include <set>
- #include <sstream>
- #include <vector>
--#include <optional>
- 
- namespace llvm {
- class LLVMContext;
-@@ -94,9 +94,6 @@ struct IRAsmBlock {
-   std::set<std::string> clobs;
-   size_t outputcount;
- 
--  // stores the labels within the asm block
--  std::vector<Identifier *> internalLabels;
--
-   CompoundAsmStatement *asmBlock;
-   LLType *retty;
-   unsigned retn;
-@@ -156,7 +153,7 @@ public:
-   IrFunction *func();
-   llvm::Function *topfunc();
- 
--#if LDC_LLVM_VER >= 1900
-+#if LLVM_VERSION_MAJOR >= 19
-   llvm::BasicBlock::iterator nextAllocaPos();
- #else
-   llvm::BasicBlock *nextAllocaPos();
-@@ -220,7 +217,6 @@ public:
- 
-   // for inline asm
-   IRAsmBlock *asmBlock = nullptr;
--  std::ostringstream nakedAsm;
- 
-   // Globals to pin in the llvm.used array to make sure they are not
-   // eliminated.
-@@ -254,11 +250,9 @@ public:
-   // calls with a StringExp with matching data will return the same variable.
-   // Exception: ulong[]-typed hex strings (not null-terminated either).
-   llvm::GlobalVariable *getCachedStringLiteral(StringExp *se);
--  llvm::GlobalVariable *getCachedStringLiteral(llvm::StringRef s
--#if LDC_LLVM_VER >= 1700
--                                               ,std::optional< unsigned > = std::nullopt
--#endif
--                                               );
-+  llvm::GlobalVariable *
-+  getCachedStringLiteral(llvm::StringRef s,
-+                         std::optional<unsigned> = std::nullopt);
- 
-   // List of functions with cpu or features attributes overriden by user
-   std::vector<IrFunction *> targetCpuOrFeaturesOverridden;
-diff --git a/gen/llvm.h b/gen/llvm.h
-index 45f051aa93..0070894b8b 100644
---- a/gen/llvm.h
-+++ b/gen/llvm.h
-@@ -35,10 +35,10 @@ using llvm::APFloat;
- using llvm::APInt;
- using llvm::IRBuilder;
- 
--#if LDC_LLVM_VER >= 2000
-+#if LLVM_VERSION_MAJOR >= 20
- #define GET_INTRINSIC_DECL(_X, _TY)                                              \
-   (llvm::Intrinsic::getOrInsertDeclaration(&gIR->module, llvm::Intrinsic::_X, _TY))
--#elif LDC_LLVM_VER >= 1900
-+#elif LLVM_VERSION_MAJOR >= 19
- #define GET_INTRINSIC_DECL(_X, _TY)                                              \
-   (llvm::Intrinsic::getDeclaration(&gIR->module, llvm::Intrinsic::_X, _TY))
- #else
-diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp
-index 0771ab54ca..83d72dcc55 100644
---- a/gen/llvmhelpers.cpp
-+++ b/gen/llvmhelpers.cpp
-@@ -1132,11 +1132,7 @@ LLConstant *DtoConstExpInit(Loc loc, Type *targetType, Expression *exp) {
-   // extend i1 to i8
-   if (llType->isIntegerTy(1)) {
-     llType = LLType::getInt8Ty(gIR->context());
--#if LDC_LLVM_VER < 1800
--    val = llvm::ConstantExpr::getZExt(val, llType);
--#else
-     val = llvm::ConstantFoldCastOperand(llvm::Instruction::ZExt, val, llType, *gDataLayout);
--#endif
-   }
- 
-   if (llType == targetLLType)
-@@ -1196,11 +1192,7 @@ LLConstant *DtoConstExpInit(Loc loc, Type *targetType, Expression *exp) {
-            "On initializer integer type mismatch, the target should be wider "
-            "than the source.");
- 
--#if LDC_LLVM_VER < 1800
--    return llvm::ConstantExpr::getZExtOrBitCast(val, target);
--#else
-     return llvm::ConstantFoldCastOperand(llvm::Instruction::ZExt, val, target, *gDataLayout);
--#endif
-   }
- 
-   Logger::println("Unhandled type mismatch, giving up.");
-diff --git a/gen/modules.cpp b/gen/modules.cpp
-index 569859e468..41fcc777b3 100644
---- a/gen/modules.cpp
-+++ b/gen/modules.cpp
-@@ -50,9 +50,7 @@
- #include "llvm/Support/FileSystem.h"
- #include "llvm/Support/Path.h"
- #include "llvm/Transforms/Utils/ModuleUtils.h"
--#if LDC_LLVM_VER >= 1700
- #include "llvm/Support/VirtualFileSystem.h"
--#endif
- 
- #if _AIX || __sun
- #include <alloca.h>
-@@ -340,13 +338,8 @@ void loadInstrProfileData(IRState *irs) {
-     IF_LOG Logger::println("Read profile data from %s",
-                            global.params.datafileInstrProf);
- 
--    auto readerOrErr =
--        llvm::IndexedInstrProfReader::create(global.params.datafileInstrProf
--#if LDC_LLVM_VER >= 1700
--                                             ,
--                                             *llvm::vfs::getRealFileSystem()
--#endif
--        );
-+    auto readerOrErr = llvm::IndexedInstrProfReader::create(
-+        global.params.datafileInstrProf, *llvm::vfs::getRealFileSystem());
-     if (auto E = readerOrErr.takeError()) {
-       handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EI) {
-         error(irs->dmodule->loc, "Could not read profile file '%s': %s",
-diff --git a/gen/ms-cxx-helper.cpp b/gen/ms-cxx-helper.cpp
-index d17cd3c677..815eb5d058 100644
---- a/gen/ms-cxx-helper.cpp
-+++ b/gen/ms-cxx-helper.cpp
-@@ -113,11 +113,7 @@ void cloneBlocks(const std::vector<llvm::BasicBlock *> &srcblocks,
-       if (!newInst)
-         newInst = Inst->clone();
- 
--#if LDC_LLVM_VER < 1600
--      nbb->getInstList().push_back(newInst);
--#else
-       newInst->insertInto(nbb, nbb->end());
--#endif
- 
-       VMap[Inst] = newInst; // Add instruction map to value.
-       if (unwindTo)
-diff --git a/gen/naked.cpp b/gen/naked.cpp
-index 5e5b3ea653..e63ed83d55 100644
---- a/gen/naked.cpp
-+++ b/gen/naked.cpp
-@@ -27,228 +27,6 @@
- 
- using namespace dmd;
- 
--////////////////////////////////////////////////////////////////////////////////
--// FIXME: Integrate these functions
--void AsmStatement_toNakedIR(InlineAsmStatement *stmt, IRState *irs);
--
--////////////////////////////////////////////////////////////////////////////////
--
--class ToNakedIRVisitor : public Visitor {
--  IRState *irs;
--
--public:
--  explicit ToNakedIRVisitor(IRState *irs) : irs(irs) {}
--
--  //////////////////////////////////////////////////////////////////////////
--
--  // Import all functions from class Visitor
--  using Visitor::visit;
--
--  //////////////////////////////////////////////////////////////////////////
--
--  void visit(Statement *stmt) override {
--    error(stmt->loc, "Statement not allowed in naked function");
--  }
--
--  //////////////////////////////////////////////////////////////////////////
--
--  void visit(InlineAsmStatement *stmt) override {
--    AsmStatement_toNakedIR(stmt, irs);
--  }
--
--  //////////////////////////////////////////////////////////////////////////
--
--  void visit(CompoundStatement *stmt) override {
--    IF_LOG Logger::println("CompoundStatement::toNakedIR(): %s",
--                           stmt->loc.toChars());
--    LOG_SCOPE;
--
--    if (stmt->statements) {
--      for (auto s : *stmt->statements) {
--        if (s) {
--          s->accept(this);
--        }
--      }
--    }
--  }
--
--  //////////////////////////////////////////////////////////////////////////
--
--  void visit(ExpStatement *stmt) override {
--    IF_LOG Logger::println("ExpStatement::toNakedIR(): %s",
--                           stmt->loc.toChars());
--    LOG_SCOPE;
--
--    // This happens only if there is a ; at the end:
--    // asm { naked; ... };
--    // Is this a legal AST?
--    if (!stmt->exp) {
--      return;
--    }
--
--    // only expstmt supported in declarations
--    if (!stmt->exp || stmt->exp->op != EXP::declaration) {
--      visit(static_cast<Statement *>(stmt));
--      return;
--    }
--
--    DeclarationExp *d = static_cast<DeclarationExp *>(stmt->exp);
--    VarDeclaration *vd = d->declaration->isVarDeclaration();
--    FuncDeclaration *fd = d->declaration->isFuncDeclaration();
--    EnumDeclaration *ed = d->declaration->isEnumDeclaration();
--
--    // and only static variable/function declaration
--    // no locals or nested stuffies!
--    if (!vd && !fd && !ed) {
--      visit(static_cast<Statement *>(stmt));
--      return;
--    }
--    if (vd && !(vd->storage_class & (STCstatic | STCmanifest))) {
--      error(vd->loc, "non-static variable `%s` not allowed in naked function",
--            vd->toChars());
--      return;
--    }
--    if (fd && !fd->isStatic()) {
--      error(fd->loc,
--            "non-static nested function `%s` not allowed in naked function",
--            fd->toChars());
--      return;
--    }
--    // enum decls should always be safe
--
--    // make sure the symbols gets processed
--    // TODO: codegen() here is likely incorrect
--    Declaration_codegen(d->declaration, irs);
--  }
--
--  //////////////////////////////////////////////////////////////////////////
--
--  void visit(LabelStatement *stmt) override {
--    IF_LOG Logger::println("LabelStatement::toNakedIR(): %s",
--                           stmt->loc.toChars());
--    LOG_SCOPE;
--
--    printLabelName(irs->nakedAsm, mangleExact(irs->func()->decl),
--                   stmt->ident->toChars());
--    irs->nakedAsm << ":";
--
--    if (stmt->statement) {
--      stmt->statement->accept(this);
--    }
--  }
--};
--
--////////////////////////////////////////////////////////////////////////////////
--
--void DtoDefineNakedFunction(FuncDeclaration *fd) {
--  IF_LOG Logger::println("DtoDefineNakedFunction(%s)", mangleExact(fd));
--  LOG_SCOPE;
--
--  // we need to do special processing on the body, since we only want
--  // to allow actual inline asm blocks to reach the final asm output
--
--  std::ostringstream &asmstr = gIR->nakedAsm;
--
--  // build function header
--
--  // FIXME: could we perhaps use llvm asmwriter to give us these details ?
--
--  const char *mangle = mangleExact(fd);
--  std::string fullmangle; // buffer only
--
--  const auto &triple = *global.params.targetTriple;
--  bool const isWin = triple.isOSWindows();
--  bool const isDarwin = triple.isOSDarwin();
--
--  // osx is different
--  // also mangling has an extra underscore prefixed
--  if (isDarwin) {
--    fullmangle += '_';
--    fullmangle += mangle;
--    mangle = fullmangle.c_str();
--
--    asmstr << "\t.section\t__TEXT,__text,regular,pure_instructions"
--           << std::endl;
--    asmstr << "\t.globl\t" << mangle << std::endl;
--    if (fd->isInstantiated()) {
--      asmstr << "\t.weak_definition\t" << mangle << std::endl;
--    }
--    asmstr << "\t.p2align\t4, 0x90" << std::endl;
--    asmstr << mangle << ":" << std::endl;
--  }
--  // Windows is different
--  else if (isWin) {
--    // mangled names starting with '?' (MSVC++ symbols) apparently need quoting
--    if (mangle[0] == '?') {
--      fullmangle += '"';
--      fullmangle += mangle;
--      fullmangle += '"';
--      mangle = fullmangle.c_str();
--    } else if (triple.isArch32Bit()) {
--      // prepend extra underscore for Windows x86
--      fullmangle += '_';
--      fullmangle += mangle;
--      mangle = fullmangle.c_str();
--    }
--
--    asmstr << "\t.def\t" << mangle << ";" << std::endl;
--    // hard code these two numbers for now since gas ignores .scl and llvm
--    // is defaulting to .type 32 for everything I have seen
--    asmstr << "\t.scl\t2;" << std::endl;
--    asmstr << "\t.type\t32;" << std::endl;
--    asmstr << "\t.endef" << std::endl;
--
--    if (fd->isInstantiated()) {
--      asmstr << "\t.section\t.text,\"xr\",discard," << mangle << std::endl;
--    } else {
--      asmstr << "\t.text" << std::endl;
--    }
--    asmstr << "\t.globl\t" << mangle << std::endl;
--    asmstr << "\t.p2align\t4, 0x90" << std::endl;
--    asmstr << mangle << ":" << std::endl;
--  } else {
--    if (fd->isInstantiated()) {
--      asmstr << "\t.section\t.text." << mangle << ",\"axG\", at progbits,"
--             << mangle << ",comdat" << std::endl;
--      asmstr << "\t.weak\t" << mangle << std::endl;
--    } else {
--      asmstr << "\t.text" << std::endl;
--      asmstr << "\t.globl\t" << mangle << std::endl;
--    }
--    asmstr << "\t.p2align\t4, 0x90" << std::endl;
--    asmstr << "\t.type\t" << mangle << ", at function" << std::endl;
--    asmstr << mangle << ":" << std::endl;
--  }
--
--  // emit body
--  ToNakedIRVisitor v(gIR);
--  fd->fbody->accept(&v);
--
--  // We could have generated new errors in toNakedIR(), but we are in codegen
--  // already so we have to abort here.
--  if (global.errors) {
--    fatal();
--  }
--
--  // emit size after body
--  // llvm does this on linux, but not on osx or Win
--  if (!(isWin || isDarwin)) {
--    asmstr << "\t.size\t" << mangle << ", .-" << mangle << std::endl
--           << std::endl;
--  }
--
--  gIR->module.appendModuleInlineAsm(asmstr.str());
--  asmstr.str("");
--
--  if (global.params.dllexport ||
--      (global.params.targetTriple->isOSWindows() && fd->isExport())) {
--    // Embed a linker switch telling the MS linker to export the naked function.
--    // This mimics the effect of the dllexport attribute for regular functions.
--    const auto linkerSwitch = std::string("/EXPORT:") + mangle;
--    gIR->addLinkerOption(llvm::StringRef(linkerSwitch));
--  }
--}
--
- ////////////////////////////////////////////////////////////////////////////////
- 
- void emitABIReturnAsmStmt(IRAsmBlock *asmblock, Loc loc,
-@@ -436,7 +214,7 @@ DValue *DtoInlineAsmExpr(Loc loc, FuncDeclaration *fd,
-   LLSmallVector<LLValue *, 8> operands;
-   LLSmallVector<LLType *, 8> indirectTypes;
-   operands.reserve(n);
--    
-+
-   Type *returnType = fd->type->nextOf();
-   const size_t cisize = constraintInfo.size();
-   const size_t minRequired = n + (returnType->ty == TY::Tvoid ? 0 : 1);
-diff --git a/gen/optimizer.cpp b/gen/optimizer.cpp
-index 7029959452..e418774715 100644
---- a/gen/optimizer.cpp
-+++ b/gen/optimizer.cpp
-@@ -36,11 +36,7 @@
- #include "driver/targetmachine.h"
- #endif
- 
--#if LDC_LLVM_VER < 1700
--#include "llvm/ADT/Triple.h"
--#else
- #include "llvm/TargetParser/Triple.h"
--#endif
- #include "llvm/Analysis/InlineCost.h"
- #include "llvm/Analysis/TargetLibraryInfo.h"
- #include "llvm/Analysis/TargetTransformInfo.h"
-@@ -52,15 +48,12 @@
- #include "llvm/LinkAllPasses.h"
- #include "llvm/Support/CommandLine.h"
- #include "llvm/Target/TargetMachine.h"
--#if LDC_LLVM_VER >= 2000
-+#if LLVM_VERSION_MAJOR >= 20
- #include "llvm/Transforms/Utils/Instrumentation.h"
- #else
- #include "llvm/Transforms/Instrumentation.h"
- #endif
- #include "llvm/Transforms/IPO.h"
--#if LDC_LLVM_VER < 1700
--#include "llvm/Transforms/IPO/PassManagerBuilder.h"
--#endif
- #include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
- #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
- #include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
-@@ -212,7 +205,7 @@ static OptimizationLevel getOptimizationLevel(){
- #ifndef IN_JITRT
- static void addAddressSanitizerPasses(ModulePassManager &mpm,
-                                       OptimizationLevel level
--#if LDC_LLVM_VER >= 2000
-+#if LLVM_VERSION_MAJOR >= 20
-                                       ,
-                                       ThinOrFullLTOPhase
- #endif
-@@ -223,11 +216,7 @@ static void addAddressSanitizerPasses(ModulePassManager &mpm,
-   aso.UseAfterScope = true;
-   aso.UseAfterReturn = opts::fSanitizeAddressUseAfterReturn;
- 
--#if LDC_LLVM_VER >= 1600
-   mpm.addPass(AddressSanitizerPass(aso));
--#else
--  mpm.addPass(ModuleAddressSanitizerPass(aso));
--#endif
- }
- 
- static void addMemorySanitizerPass(ModulePassManager &mpm,
-@@ -236,13 +225,8 @@ static void addMemorySanitizerPass(ModulePassManager &mpm,
-   int trackOrigins = fSanitizeMemoryTrackOrigins;
-   bool recover = opts::isSanitizerRecoveryEnabled(opts::MemorySanitizer);
-   bool kernel = false;
--#if LDC_LLVM_VER >= 1600
-   mpm.addPass(MemorySanitizerPass(
-       MemorySanitizerOptions{trackOrigins, recover, kernel}));
--#else
--  fpm.addPass(MemorySanitizerPass(
--      MemorySanitizerOptions{trackOrigins, recover, kernel}));
--#endif
- 
-   // MemorySanitizer inserts complex instrumentation that mostly follows
-   // the logic of the original code, but operates on "shadow" values.
-@@ -260,7 +244,7 @@ static void addMemorySanitizerPass(ModulePassManager &mpm,
- }
- static void addThreadSanitizerPass(ModulePassManager &mpm,
-                                    OptimizationLevel level
--#if LDC_LLVM_VER >= 2000
-+#if LLVM_VERSION_MAJOR >= 20
-                                    ,
-                                    ThinOrFullLTOPhase
- #endif
-@@ -271,18 +255,13 @@ static void addThreadSanitizerPass(ModulePassManager &mpm,
- 
- static void addSanitizerCoveragePass(ModulePassManager &mpm,
-                                      OptimizationLevel level
--#if LDC_LLVM_VER >= 2000
-+#if LLVM_VERSION_MAJOR >= 20
-                                      ,
-                                      ThinOrFullLTOPhase
- #endif
- ) {
--#if LDC_LLVM_VER >= 1600
-   mpm.addPass(SanitizerCoveragePass(
-       opts::getSanitizerCoverageOptions()));
--#else
--  mpm.addPass(ModuleSanitizerCoveragePass(
--      opts::getSanitizerCoverageOptions()));
--#endif
- }
- // Adds PGO instrumentation generation and use passes.
- static void addPGOPasses(ModulePassManager &mpm, OptimizationLevel level) {
-@@ -291,13 +270,7 @@ static void addPGOPasses(ModulePassManager &mpm, OptimizationLevel level) {
-     options.NoRedZone = global.params.disableRedZone;
-     if (global.params.datafileInstrProf)
-       options.InstrProfileOutput = global.params.datafileInstrProf;
--    mpm.addPass(
--#if LDC_LLVM_VER < 1800
--      InstrProfiling(options)
--#else
--      InstrProfilingLoweringPass(options)
--#endif // LDC_LLVM_VER < 1800
--    );
-+    mpm.addPass(InstrProfilingLoweringPass(options));
-   } else if (opts::isUsingASTBasedPGOProfile()) {
-     // We are generating code with PGO profile information available.
-     // Do indirect call promotion from -O1
-@@ -310,7 +283,7 @@ static void addPGOPasses(ModulePassManager &mpm, OptimizationLevel level) {
- 
- static void addStripExternalsPass(ModulePassManager &mpm,
-                                   OptimizationLevel level
--#if LDC_LLVM_VER >= 2000
-+#if LLVM_VERSION_MAJOR >= 20
-                                   ,
-                                   ThinOrFullLTOPhase
- #endif
-@@ -327,7 +300,7 @@ static void addStripExternalsPass(ModulePassManager &mpm,
- 
- static void addSimplifyDRuntimeCallsPass(ModulePassManager &mpm,
-                                          OptimizationLevel level
--#if LDC_LLVM_VER >= 2000
-+#if LLVM_VERSION_MAJOR >= 20
-                                          ,
-                                          ThinOrFullLTOPhase
- #endif
-@@ -342,7 +315,7 @@ static void addSimplifyDRuntimeCallsPass(ModulePassManager &mpm,
- 
- static void addGarbageCollect2StackPass(ModulePassManager &mpm,
-                                         OptimizationLevel level
--#if LDC_LLVM_VER >= 2000
-+#if LLVM_VERSION_MAJOR >= 20
-                                         ,
-                                         ThinOrFullLTOPhase
- #endif
-@@ -356,58 +329,48 @@ static void addGarbageCollect2StackPass(ModulePassManager &mpm,
- }
- 
- #ifndef IN_JITRT
--static llvm::Optional<PGOOptions> getPGOOptions() {
-+static std::optional<PGOOptions> getPGOOptions() {
-   // FIXME: Do we have these anywhere?
-   bool debugInfoForProfiling = false;
-   bool pseudoProbeForProfiling = false;
-   if (opts::isInstrumentingForIRBasedPGO()) {
-     return PGOOptions(
-         global.params.datafileInstrProf, "", "",
--#if LDC_LLVM_VER >= 1700
-         "" /*MemoryProfileUsePath*/,
--#if LDC_LLVM_VER < 2200
-+#if LLVM_VERSION_MAJOR < 22
-         llvm::vfs::getRealFileSystem(),
--#endif
- #endif
-         PGOOptions::PGOAction::IRInstr, PGOOptions::CSPGOAction::NoCSAction,
--#if LDC_LLVM_VER >= 1900
-+#if LLVM_VERSION_MAJOR >= 19
-         PGOOptions::ColdFuncOpt::Default,
- #endif
-         debugInfoForProfiling, pseudoProbeForProfiling);
-   } else if (opts::isUsingIRBasedPGOProfile()) {
-     return PGOOptions(
-         global.params.datafileInstrProf, "", "",
--#if LDC_LLVM_VER >= 1700
-         "" /*MemoryProfileUsePath*/,
--#if LDC_LLVM_VER < 2200
-+#if LLVM_VERSION_MAJOR < 22
-         llvm::vfs::getRealFileSystem(),
--#endif
- #endif
-         PGOOptions::PGOAction::IRUse, PGOOptions::CSPGOAction::NoCSAction,
--#if LDC_LLVM_VER >= 1900
-+#if LLVM_VERSION_MAJOR >= 19
-         PGOOptions::ColdFuncOpt::Default,
- #endif
-         debugInfoForProfiling, pseudoProbeForProfiling);
-   } else if (opts::isUsingSampleBasedPGOProfile()) {
-     return PGOOptions(
-         global.params.datafileInstrProf, "", "",
--#if LDC_LLVM_VER >= 1700
-         "" /*MemoryProfileUsePath*/,
--#if LDC_LLVM_VER < 2200
-+#if LLVM_VERSION_MAJOR < 22
-         llvm::vfs::getRealFileSystem(),
--#endif
- #endif
-         PGOOptions::PGOAction::SampleUse, PGOOptions::CSPGOAction::NoCSAction,
--#if LDC_LLVM_VER >= 1900
-+#if LLVM_VERSION_MAJOR >= 19
-         PGOOptions::ColdFuncOpt::Default,
- #endif
-         debugInfoForProfiling, pseudoProbeForProfiling);
-   }
--#if LDC_LLVM_VER < 1600
--  return None;
--#else
-   return std::nullopt;
--#endif
- }
- #endif // !IN_JITRT
- 
-@@ -472,17 +435,9 @@ void runOptimizationPasses(llvm::Module *M, llvm::TargetMachine *TM) {
-   bool debugLogging = false;
-   ppo.Indent = false;
-   ppo.SkipAnalyses = false;
--#if LDC_LLVM_VER < 1600
--  StandardInstrumentations si(debugLogging, /*VerifyEach=*/false, ppo);
--#else
-   StandardInstrumentations si(M->getContext(), debugLogging, /*VerifyEach=*/false, ppo);
--#endif
- 
--#if LDC_LLVM_VER < 1700
--  si.registerCallbacks(pic, &fam);
--#else
-   si.registerCallbacks(pic, &mam);
--#endif
- 
-   PassBuilder pb(TM, getPipelineTuningOptions(optLevelVal, sizeLevelVal),
- #ifdef IN_JITRT
-@@ -566,14 +521,14 @@ void runOptimizationPasses(llvm::Module *M, llvm::TargetMachine *TM) {
- 
-   if (optLevelVal == 0) {
- #ifdef IN_JITRT
--#if LDC_LLVM_VER >= 2000
-+#if LLVM_VERSION_MAJOR >= 20
-     const ThinOrFullLTOPhase ltoPrelink = ThinOrFullLTOPhase::None;
- #else
-     const bool ltoPrelink = false;
--#endif // LDC_LLVM_VER >= 2000
-+#endif
-     mpm = pb.buildO0DefaultPipeline(level, ltoPrelink);
--#else
--#if LDC_LLVM_VER >= 2000
-+#else // !IN_JITRT
-+#if LLVM_VERSION_MAJOR >= 20
-     const ThinOrFullLTOPhase ltoPrelink =
-         opts::isUsingLTO()
-             ? (opts::isUsingThinLTO() ? ThinOrFullLTOPhase::ThinLTOPreLink
-@@ -581,15 +536,13 @@ void runOptimizationPasses(llvm::Module *M, llvm::TargetMachine *TM) {
-             : ThinOrFullLTOPhase::None;
- #else
-     const bool ltoPrelink = opts::isUsingLTO();
--#endif // LDC_LLVM_VER >= 2000
-+#endif
-     mpm = pb.buildO0DefaultPipeline(level, ltoPrelink);
--#if LDC_LLVM_VER >= 1700
-   } else if (opts::ltoFatObjects && opts::isUsingLTO()) {
-     mpm = pb.buildFatLTODefaultPipeline(level,
-                                         opts::isUsingThinLTO(),
-                                         opts::isUsingThinLTO()
-     );
--#endif
-   } else if (opts::isUsingThinLTO()) {
-     mpm = pb.buildThinLTOPreLinkDefaultPipeline(level);
-   } else if (opts::isUsingLTO()) {
-diff --git a/gen/optimizer.h b/gen/optimizer.h
-index 8ba3521a28..688b654069 100644
---- a/gen/optimizer.h
-+++ b/gen/optimizer.h
-@@ -19,12 +19,6 @@
- 
- #include "llvm/Support/CommandLine.h"
- 
--namespace llvm {
--#if LDC_LLVM_VER < 1800
--using CodeGenOptLevel = llvm::CodeGenOpt::Level;
--#endif
--}
--
- namespace llvm {
- class raw_ostream;
- }
-diff --git a/gen/passes/DLLImportRelocation.cpp b/gen/passes/DLLImportRelocation.cpp
-index d2dc6c8369..288f71cbfd 100644
---- a/gen/passes/DLLImportRelocation.cpp
-+++ b/gen/passes/DLLImportRelocation.cpp
-@@ -272,11 +272,7 @@ bool DLLImportRelocation::run(Module &m) {
-   Impl impl(m);
-   bool hasChanged = false;
- 
--#if LDC_LLVM_VER >= 1700
-   for (GlobalVariable &global : m.globals()) {
--#else
--  for (GlobalVariable &global : m.getGlobalList()) {
--#endif
-     // TODO: thread-local globals would need to be initialized in a separate TLS
-     // ctor
-     if (!global.hasInitializer() || global.isThreadLocal())
-diff --git a/gen/passes/GarbageCollect2Stack.cpp b/gen/passes/GarbageCollect2Stack.cpp
-index 4c9b82c0c8..a788789c86 100644
---- a/gen/passes/GarbageCollect2Stack.cpp
-+++ b/gen/passes/GarbageCollect2Stack.cpp
-@@ -24,7 +24,7 @@
- #include "llvm/ADT/Statistic.h"
- #include "llvm/ADT/StringMap.h"
- #include "llvm/ADT/StringSwitch.h"
--#if LDC_LLVM_VER >= 2100
-+#if LLVM_VERSION_MAJOR >= 21
- #include "llvm/IR/AbstractCallSite.h"
- #endif
- #include "llvm/IR/Constants.h"
-@@ -100,7 +100,7 @@ Value* FunctionInfo::promote(CallBase *CB, IRBuilder<> &B, const G2StackAnalysis
-   // FIXME: set alignment on alloca?
-   return new AllocaInst(
-       Ty, BB.getModule()->getDataLayout().getAllocaAddrSpace(), ".nongc_mem",
--#if LDC_LLVM_VER >= 1900
-+#if LLVM_VERSION_MAJOR >= 19
-       BB.begin()
- #else
-       &(*BB.begin())
-@@ -352,7 +352,7 @@ static void RemoveCall(CallBase *CB, const G2StackAnalysis &A) {
-   // the dominator tree here.
-   if (auto Invoke = dyn_cast<InvokeInst>(static_cast<Instruction *>(CB))) {
-     BranchInst::Create(Invoke->getNormalDest(),
--#if LDC_LLVM_VER >= 1900
-+#if LLVM_VERSION_MAJOR >= 19
-                        Invoke->getIterator()
- #else
-                        Invoke
-@@ -363,7 +363,7 @@ static void RemoveCall(CallBase *CB, const G2StackAnalysis &A) {
- 
-   // Remove the runtime call.
-   if (A.CGNode) {
--#if LDC_LLVM_VER >= 2100
-+#if LLVM_VERSION_MAJOR >= 21
-     //FIXME: Look into using `LazyCallGraph` and the new pass manager
-     for (auto I = A.CGNode->begin(); ; I++) {
-       assert(I != A.CGNode->end() && "Cannot find callsite to remove!");
-@@ -755,7 +755,7 @@ bool isSafeToStackAllocate(BasicBlock::iterator Alloc, Value *V,
-       auto B = CB->arg_begin(), E = CB->arg_end();
-       for (auto A = B; A != E; ++A) {
-         if (A->get() == V) {
--#if LDC_LLVM_VER >= 2100
-+#if LLVM_VERSION_MAJOR >= 21
-           if (!(CB->paramHasAttr(A - B, llvm::Attribute::AttrKind::Captures) &&
-                 capturesNothing(
-                     CB->getParamAttr(A - B, llvm::Attribute::AttrKind::Captures)
-diff --git a/gen/passes/SimplifyDRuntimeCalls.cpp b/gen/passes/SimplifyDRuntimeCalls.cpp
-index 9dd672f20b..fd698cfeb9 100644
---- a/gen/passes/SimplifyDRuntimeCalls.cpp
-+++ b/gen/passes/SimplifyDRuntimeCalls.cpp
-@@ -160,7 +160,7 @@ Value *ArraySliceCopyOpt::CallOptimizer(Function *Callee, CallInst *CI,
-     Sz = (Int->getValue() * ElemSz->getValue()).getZExtValue();
-   }
- 
--#if LDC_LLVM_VER >= 2100
-+#if LLVM_VERSION_MAJOR >= 21
-   llvm::LocationSize Sz2 =
-       (Sz == llvm::MemoryLocation::UnknownSize)
-           ? llvm::LocationSize::beforeOrAfterPointer()
-diff --git a/gen/pgo_ASTbased.cpp b/gen/pgo_ASTbased.cpp
-index 723cabdd95..c1937b5539 100644
---- a/gen/pgo_ASTbased.cpp
-+++ b/gen/pgo_ASTbased.cpp
-@@ -38,13 +38,17 @@ llvm::cl::opt<bool, false, opts::FlagParser<bool>> enablePGOIndirectCalls(
-     "pgo-indirect-calls", llvm::cl::ZeroOrMore, llvm::cl::Hidden,
-     llvm::cl::desc("(*) Enable PGO of indirect calls"),
-     llvm::cl::init(true));
--}
- 
--#if LDC_LLVM_VER >= 1800
--namespace llvm::support {
--  const auto little = llvm::endianness::little;
--}
-+uint64_t inLittleEndian(uint64_t x) {
-+#if LLVM_VERSION_MAJOR >= 22
-+  return llvm::support::endian::byte_swap<uint64_t>(x,
-+                                                    llvm::endianness::little);
-+#else
-+  return llvm::support::endian::byte_swap<uint64_t, llvm::endianness::little>(
-+      x);
- #endif
-+}
-+} // anonymous namespace
- 
- /// \brief Stable hasher for PGO region counters.
- ///
-@@ -121,8 +125,7 @@ public:
- 
-     // Pass through MD5 if enough work has built up.
-     if (Count && Count % NumTypesPerWord == 0) {
--      using namespace llvm::support;
--      uint64_t Swapped = endian::byte_swap<uint64_t, little>(Working);
-+      uint64_t Swapped = inLittleEndian(Working);
-       MD5.update(llvm::ArrayRef<uint8_t>((uint8_t *)&Swapped, sizeof(Swapped)));
-       Working = 0;
-     }
-@@ -142,8 +145,7 @@ public:
- 
-     // Check for remaining work in Working.
-     if (Working) {
--      using namespace llvm::support;
--      uint64_t Swapped = endian::byte_swap<uint64_t, little>(Working);
-+      uint64_t Swapped = inLittleEndian(Working);
-       MD5.update(llvm::ArrayRef<uint8_t>((uint8_t *)&Swapped, sizeof(Swapped)));
-     }
- 
-@@ -924,11 +926,7 @@ void CodeGenPGO::loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader,
-   auto EC = RecordExpected.takeError();
- 
-   if (EC) {
--#if LDC_LLVM_VER >= 1700
-     auto IPE = std::get<0>(llvm::InstrProfError::take(std::move(EC)));
--#else
--    auto IPE = llvm::InstrProfError::take(std::move(EC));
--#endif
-     if (IPE == llvm::instrprof_error::unknown_function) {
-       IF_LOG Logger::println("No profile data for function: %s",
-                              FuncName.c_str());
-diff --git a/gen/runtime.cpp b/gen/runtime.cpp
-index 5d3cbb6ebf..7ac04957e1 100644
---- a/gen/runtime.cpp
-+++ b/gen/runtime.cpp
-@@ -32,9 +32,7 @@
- #include "ir/irtypefunction.h"
- #include "llvm/Bitcode/BitcodeWriter.h"
- #include "llvm/IR/Attributes.h"
--#if LDC_LLVM_VER >= 1600
- #include "llvm/Support/ModRef.h"
--#endif
- #include "llvm/IR/Module.h"
- #include "llvm/Support/CommandLine.h"
- #include "llvm/Support/MemoryBuffer.h"
-@@ -511,15 +509,9 @@ static void buildRuntimeModule() {
-   // `readonly`
-   {
-     auto addReadOnly = [&](AttrSet& a) {
--#if LDC_LLVM_VER >= 1600
-       a = a.merge(AttrSet(llvm::AttributeList().addFnAttribute(
-                           context, llvm::Attribute::getWithMemoryEffects(
-                             context, llvm::MemoryEffects::readOnly()))));
--#else
--      llvm::AttrBuilder ab(context);
--      ab.addAttribute(llvm::Attribute::ReadOnly);
--      a = a.addToFunction(ab);
--#endif
-     };
-     addReadOnly(Attr_ReadOnly);
-     addReadOnly(Attr_ReadOnly_NoUnwind);
-@@ -542,7 +534,7 @@ static void buildRuntimeModule() {
-   {
-     auto addCapturesNone = [&](int extra, AttrSet& a) {
-       llvm::AttrBuilder ab(context);
--#if LDC_LLVM_VER >= 2100
-+#if LLVM_VERSION_MAJOR >= 21
-       ab.addCapturesAttr(llvm::CaptureInfo::none());
- #else
-       ab.addAttribute(llvm::Attribute::NoCapture);
-diff --git a/gen/semantic-dcompute.cpp b/gen/semantic-dcompute.cpp
-index 5fe5f64e16..1cf3fb4843 100644
---- a/gen/semantic-dcompute.cpp
-+++ b/gen/semantic-dcompute.cpp
-@@ -92,6 +92,9 @@ struct DComputeSemanticAnalyser : public StoppableVisitor {
-       return;
-     }
- 
-+    if (!decl->type)
-+      return;
-+
-     if (decl->type->ty == TY::Taarray) {
-       error(decl->loc, "associative arrays not allowed in `@compute` code");
-       stop = true;
-diff --git a/gen/statements.cpp b/gen/statements.cpp
-index 1bdd3cef30..004fba0656 100644
---- a/gen/statements.cpp
-+++ b/gen/statements.cpp
-@@ -431,7 +431,11 @@ public:
-     if (llvm::ConstantInt *const_val = llvm::dyn_cast<llvm::ConstantInt>(cond_val)) {
-       Statement *executed = stmt->ifbody;
-       Statement *skipped = stmt->elsebody;
-+#if LLVM_VERSION_MAJOR >= 21
-+      if (const_val->isZero()) {
-+#else
-       if (const_val->isZeroValue()) {
-+#endif
-         std::swap(executed, skipped);
-       }
-       if (!containsLabel(skipped)) {
-@@ -441,7 +445,11 @@ public:
-           irs->DBuilder.EmitBlockStart(executed->loc);
-         }
-         // True condition, the branch is taken so emit counter increment.
-+#if LLVM_VERSION_MAJOR >= 21
-+        if (!const_val->isZero()) {
-+#else
-         if (!const_val->isZeroValue()) {
-+#endif
-           PGO.emitCounterIncrement(stmt);
-         }
-         if (executed) {
-@@ -1542,17 +1550,21 @@ public:
-     auto &PGO = irs->funcGen().pgo;
-     PGO.setCurrentStmt(stmt);
- 
-+    auto fd = irs->func()->decl;
-+
-+    const auto getFullAsmLabelString = [stmt, fd]() {
-+      std::stringstream s;
-+      printLabelName(s, mangleExact(fd), stmt->ident->toChars());
-+      s << ":";
-+      return s.str();
-+    };
-+
-     // if it's an inline asm label, we don't create a basicblock, just emit it
-     // in the asm
-     if (irs->asmBlock) {
-       auto a = new IRAsmStmt;
--      std::stringstream label;
--      printLabelName(label, mangleExact(irs->func()->decl),
--                     stmt->ident->toChars());
--      label << ":";
--      a->code = label.str();
-+      a->code = getFullAsmLabelString();
-       irs->asmBlock->s.push_back(a);
--      irs->asmBlock->internalLabels.push_back(stmt->ident);
- 
-       // disable inlining
-       irs->func()->setNeverInline();
-@@ -1566,6 +1578,13 @@ public:
-       }
- 
-       irs->ir->SetInsertPoint(labelBB);
-+
-+      // in a naked DMD-style inline-asm function, create an assembly label too
-+      // (so that inline-asm can jump to it directly)
-+      if (fd->isNaked()) {
-+        DtoInlineAsmExpr(stmt->loc, getFullAsmLabelString(), "", {}, {},
-+                         irs->ir->getVoidTy());
-+      }
-     }
- 
-     PGO.emitCounterIncrement(stmt);
-diff --git a/gen/target.cpp b/gen/target.cpp
-index 7f77923a39..16622a9922 100644
---- a/gen/target.cpp
-+++ b/gen/target.cpp
-@@ -83,10 +83,8 @@ llvm::Type *getRealType(const llvm::Triple &triple) {
- 
-   case Triple::riscv32:
-   case Triple::riscv64:
--#if LDC_LLVM_VER >= 1600
-   case Triple::loongarch32:
-   case Triple::loongarch64:
--#endif // LDC_LLVM_VER >= 1600
-     return LLType::getFP128Ty(ctx);
- 
-   case Triple::wasm32:
-diff --git a/gen/tocall.cpp b/gen/tocall.cpp
-index edc5ef837c..c1b0bc1b3c 100644
---- a/gen/tocall.cpp
-+++ b/gen/tocall.cpp
-@@ -1045,7 +1045,7 @@ DValue *DtoCallFunction(Loc loc, Type *resulttype, DValue *fnval,
-     if (cf->isIntrinsic()) { // override intrinsic attrs
-       attrlist =
-           llvm::Intrinsic::getAttributes(gIR->context(), cf->getIntrinsicID()
--#if LDC_LLVM_VER >= 2100
-+#if LLVM_VERSION_MAJOR >= 21
-                                          ,cf->getFunctionType()
- #endif
-                                          );
-diff --git a/gen/toconstelem.cpp b/gen/toconstelem.cpp
-index c32f6f4a7b..9ded6dddc0 100644
---- a/gen/toconstelem.cpp
-+++ b/gen/toconstelem.cpp
-@@ -522,11 +522,7 @@ public:
-             // extend i1 to i8
-             if (c->getType()->isIntegerTy(1)) {
-               LLType *I8PtrTy = LLType::getInt8Ty(p->context());
--#if LDC_LLVM_VER < 1800
--              c = llvm::ConstantExpr::getZExt(c, I8PtrTy);
--#else
-               c = llvm::ConstantFoldCastOperand(llvm::Instruction::ZExt, c, I8PtrTy, *gDataLayout);
--#endif
-             }
-             varInits[e->sd->fields[i]] = c;
-           }
-diff --git a/gen/toir.cpp b/gen/toir.cpp
-index 0a22d1b0d5..e746c6bbcd 100644
---- a/gen/toir.cpp
-+++ b/gen/toir.cpp
-@@ -1016,11 +1016,7 @@ public:
-   }
- 
-   static llvm::PointerType * getWithSamePointeeType(llvm::PointerType *p, unsigned addressSpace) {
--#if LDC_LLVM_VER >= 1700
-     return llvm::PointerType::get(p->getContext(), addressSpace);
--#else
--    return llvm::PointerType::getWithSamePointeeType(p, addressSpace);
--#endif
-   }
- 
-   //////////////////////////////////////////////////////////////////////////////
-diff --git a/gen/trycatchfinally.cpp b/gen/trycatchfinally.cpp
-index b486228874..510e0c0ac6 100644
---- a/gen/trycatchfinally.cpp
-+++ b/gen/trycatchfinally.cpp
-@@ -323,7 +323,7 @@ CleanupScope::CleanupScope(llvm::BasicBlock *beginBlock,
- }
- 
- namespace {
--#if LDC_LLVM_VER >= 1900
-+#if LLVM_VERSION_MAJOR >= 19
- llvm::BasicBlock::iterator getTerminatorPos(llvm::BasicBlock *bb) {
-   auto it = bb->rbegin().getReverse();
-   assert(it->isTerminator());
-diff --git a/gen/uda.cpp b/gen/uda.cpp
-index a89c2c1e75..63f84e5699 100644
---- a/gen/uda.cpp
-+++ b/gen/uda.cpp
-@@ -210,11 +210,7 @@ void applyAttrAllocSize(StructLiteralExp *sle, IrFunction *irFunc) {
-   if (numArgIdx >= 0) {
-     builder.addAllocSizeAttr(llvmSizeIdx, llvmNumIdx);
-   } else {
--#if LDC_LLVM_VER < 1600
--    builder.addAllocSizeAttr(llvmSizeIdx, llvm::Optional<unsigned>());
--#else
-     builder.addAllocSizeAttr(llvmSizeIdx, std::optional<unsigned>());
--#endif
-   }
- 
-   llvm::Function *func = irFunc->getLLVMFunc();
-@@ -307,10 +303,6 @@ void applyAttrTarget(StructLiteralExp *sle, llvm::Function *func,
-   // The current implementation here does not do any checking of the specified
-   // string and simply passes all to llvm.
- 
--#if LDC_LLVM_VER >= 1800
--  #define startswith starts_with
--#endif
--
-   checkStructElems(sle, {Type::tstring});
-   llvm::StringRef targetspec = getFirstElemString(sle);
- 
-@@ -338,20 +330,20 @@ void applyAttrTarget(StructLiteralExp *sle, llvm::Function *func,
-     if (s.empty())
-       continue;
- 
--    if (s.startswith("arch=")) {
-+    if (s.starts_with("arch=")) {
-       // TODO: be smarter than overwriting the previous arch= setting
-       CPU = s.drop_front(5);
-       continue;
-     }
--    if (s.startswith("tune=")) {
-+    if (s.starts_with("tune=")) {
-       // clang 3.8 ignores tune= too
-       continue;
-     }
--    if (s.startswith("fpmath=")) {
-+    if (s.starts_with("fpmath=")) {
-       // TODO: implementation; clang 3.8 ignores fpmath= too
-       continue;
-     }
--    if (s.startswith("no-")) {
-+    if (s.starts_with("no-")) {
-       std::string f = (std::string("-") + s.drop_front(3)).str();
-       features.emplace_back(std::move(f));
-       continue;
-@@ -370,10 +362,6 @@ void applyAttrTarget(StructLiteralExp *sle, llvm::Function *func,
-                     llvm::join(features.begin(), features.end(), ","));
-     irFunc->targetFeaturesOverridden = true;
-   }
--
--#if LDC_LLVM_VER >= 1800
--  #undef startswith
--#endif
- }
- 
- void applyAttrAssumeUsed(IRState &irs, StructLiteralExp *sle,
-@@ -438,11 +426,7 @@ bool parseCallingConvention(llvm::StringRef name,
-           .Case("intel_ocl_bicc", llvm::CallingConv::Intel_OCL_BI)
-           .Case("x86_64_sysvcc", llvm::CallingConv::X86_64_SysV)
-           .Case("win64cc", llvm::CallingConv::Win64)
--#if LDC_LLVM_VER >= 1800
-           .Case("webkit_jscc", llvm::CallingConv::WASM_EmscriptenInvoke)
--#else
--          .Case("webkit_jscc", llvm::CallingConv::WebKit_JS)
--#endif
-           .Case("anyregcc", llvm::CallingConv::AnyReg)
-           .Case("preserve_mostcc", llvm::CallingConv::PreserveMost)
-           .Case("preserve_allcc", llvm::CallingConv::PreserveAll)
-@@ -450,13 +434,8 @@ bool parseCallingConvention(llvm::StringRef name,
-           .Case("swiftcc", llvm::CallingConv::Swift)
-           .Case("swifttailcc", llvm::CallingConv::SwiftTail)
-           .Case("x86_intrcc", llvm::CallingConv::X86_INTR)
--#if LDC_LLVM_VER >= 1700
-           .Case("hhvmcc", llvm::CallingConv::DUMMY_HHVM)
-           .Case("hhvm_ccc", llvm::CallingConv::DUMMY_HHVM_C)
--#else
--          .Case("hhvmcc", llvm::CallingConv::HHVM)
--          .Case("hhvm_ccc", llvm::CallingConv::HHVM_C)
--#endif
-           .Case("cxx_fast_tlscc", llvm::CallingConv::CXX_FAST_TLS)
-           .Case("amdgpu_vs", llvm::CallingConv::AMDGPU_VS)
-           .Case("amdgpu_gfx", llvm::CallingConv::AMDGPU_Gfx)
-diff --git a/gen/variable_lifetime.cpp b/gen/variable_lifetime.cpp
-index ed0b772dbf..717760881e 100644
---- a/gen/variable_lifetime.cpp
-+++ b/gen/variable_lifetime.cpp
-@@ -53,7 +53,7 @@ void LocalVariableLifetimeAnnotator::addLocalVariable(llvm::AllocaInst *address,
- 
-   // Emit lifetime start
-   irs.CreateCallOrInvoke(getLLVMLifetimeStartFn(),
--#if LDC_LLVM_VER >= 2200
-+#if LLVM_VERSION_MAJOR >= 22
-                          {address},
- #else
-                          {size, address},
-@@ -67,7 +67,7 @@ void LocalVariableLifetimeAnnotator::popScope() {
-     return;
- 
-   for (const auto &var : scopes.back().variables) {
--#if LDC_LLVM_VER < 2200
-+#if LLVM_VERSION_MAJOR < 22
-     auto size = var.first;
- #endif
-     auto address = var.second;
-@@ -75,7 +75,7 @@ void LocalVariableLifetimeAnnotator::popScope() {
-     assert(address);
- 
-     irs.CreateCallOrInvoke(getLLVMLifetimeEndFn(),
--#if LDC_LLVM_VER >= 2200
-+#if LLVM_VERSION_MAJOR >= 22
-                            {address},
- #else
-                            {size, address},
-@@ -92,7 +92,7 @@ llvm::Function *LocalVariableLifetimeAnnotator::getLLVMLifetimeStartFn() {
-     return lifetimeStartFunction;
- 
-   lifetimeStartFunction = llvm::Intrinsic::
--#if LDC_LLVM_VER >= 2000
-+#if LLVM_VERSION_MAJOR >= 20
-     getOrInsertDeclaration(
- #else
-     getDeclaration(
-@@ -108,7 +108,7 @@ llvm::Function *LocalVariableLifetimeAnnotator::getLLVMLifetimeEndFn() {
-     return lifetimeEndFunction;
- 
-   lifetimeEndFunction = llvm::Intrinsic::
--#if LDC_LLVM_VER >= 2000
-+#if LLVM_VERSION_MAJOR >= 20
-     getOrInsertDeclaration(
- #else
-     getDeclaration(
-diff --git a/ir/iraggr.cpp b/ir/iraggr.cpp
-index 28d2ddddd2..94275dafce 100644
---- a/ir/iraggr.cpp
-+++ b/ir/iraggr.cpp
-@@ -63,10 +63,6 @@ bool IrAggr::useDLLImport() const {
- //////////////////////////////////////////////////////////////////////////////
- 
- LLGlobalVariable *IrAggr::getInitSymbol(bool define) {
--#if LDC_LLVM_VER >= 1800
--  #define startswith starts_with
--#endif
--
-   if (!init) {
-     const auto irMangle = getIRMangledInitSymbolName(aggrdecl);
- 
-@@ -74,7 +70,7 @@ LLGlobalVariable *IrAggr::getInitSymbol(bool define) {
-     // special.
-     auto cd = aggrdecl->isClassDeclaration();
-     const bool isBuiltinTypeInfo =
--        cd && llvm::StringRef(cd->ident->toChars()).startswith("TypeInfo_");
-+        cd && llvm::StringRef(cd->ident->toChars()).starts_with("TypeInfo_");
- 
-     // Only declare the symbol if it isn't yet, otherwise the init symbol of
-     // built-in TypeInfos may clash with an existing base-typed forward
-@@ -108,10 +104,6 @@ LLGlobalVariable *IrAggr::getInitSymbol(bool define) {
-   }
- 
-   return init;
--
--#if LDC_LLVM_VER >= 1800
--  #undef startswith
--#endif
- }
- 
- //////////////////////////////////////////////////////////////////////////////
-diff --git a/ir/irtypestruct.cpp b/ir/irtypestruct.cpp
-index cac45683e0..644c196021 100644
---- a/ir/irtypestruct.cpp
-+++ b/ir/irtypestruct.cpp
-@@ -72,7 +72,7 @@ IrTypeStruct *IrTypeStruct::get(StructDeclaration *sd) {
- 
-   // For ldc.dcomptetypes.Pointer!(uint n,T),
-   // emit { T addrspace(gIR->dcomputetarget->mapping[n])* }
--  llvm::Optional<DcomputePointer> p;
-+  std::optional<DcomputePointer> p;
- 
-   if (gIR->dcomputetarget && (p = toDcomputePointer(sd))) {
-     // Translate the virtual dcompute address space into the real one for
-diff --git a/runtime/druntime/src/__importc_builtins.di b/runtime/druntime/src/__importc_builtins.di
-index 476852cd82..3c870c1842 100644
---- a/runtime/druntime/src/__importc_builtins.di
-+++ b/runtime/druntime/src/__importc_builtins.di
-@@ -12,6 +12,10 @@
- 
- module __builtins;
- 
-+import core.stdc.config : c_long, c_ulong;
-+import core.checkedint : adds, subs, muls;
-+
-+
- /* gcc relies on internal __builtin_xxxx functions and templates to
-  * accomplish <stdarg.h>. D does the same thing with templates in core.stdc.stdarg.
-  * Here, we redirect the gcc builtin declarations to the equivalent
-@@ -101,6 +105,11 @@ version (DigitalMars)
-     alias __builtin_fabsf = imported!"core.stdc.math".fabsf;
-     alias __builtin_fabsl = imported!"core.stdc.math".fabsl;
- 
-+    alias __builtin_memcmp = imported!"core.stdc.string".memcmp;
-+    alias __builtin_memcpy = imported!"core.stdc.string".memcpy;
-+    alias __builtin_memmove = imported!"core.stdc.string".memmove;
-+    alias __builtin_memset = imported!"core.stdc.string".memset;
-+
-     ushort __builtin_bswap16()(ushort value)
-     {
-         return cast(ushort) (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00U));
-@@ -161,6 +170,11 @@ else version (LDC)
-     alias __builtin_fabsf = imported!"ldc.intrinsics".llvm_fabs!float;
-     alias __builtin_fabsl = imported!"ldc.intrinsics".llvm_fabs!real;
- 
-+    alias __builtin_memcmp  = imported!"core.stdc.string".memcmp;
-+    alias __builtin_memcpy  = imported!"ldc.intrinsics".llvm_memcpy!size_t;
-+    alias __builtin_memmove = imported!"ldc.intrinsics".llvm_memmove!size_t;
-+    alias __builtin_memset  = imported!"ldc.intrinsics".llvm_memset!size_t;
-+
-     alias __builtin_bswap16 = imported!"ldc.intrinsics".llvm_bswap!ushort;
-     alias __builtin_bswap32 = imported!"ldc.intrinsics".llvm_bswap!uint;
-     alias __builtin_bswap64 = imported!"ldc.intrinsics".llvm_bswap!ulong;
-@@ -172,7 +186,8 @@ else version (LDC)
- 
-     alias __uint128_t = imported!"core.int128".Cent;
- 
--    alias __builtin_alloca = imported!"core.stdc.stdlib".alloca;
-+    pragma(LDC_alloca)
-+    extern(C) void* __builtin_alloca(size_t size) nothrow @nogc pure;
- 
-     // gcc builtins:
- 
-@@ -200,3 +215,233 @@ version (CRuntime_Glibc) version (AArch64)
-     alias __Float32x4_t = __vector(float[4]);
-     alias __Float64x2_t = __vector(double[2]);
- }
-+
-+// https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html
-+
-+private bool overflowOp(alias op, T1, T2, T3)(T1 a, T2 b, ref T3 res)
-+{
-+    bool overflow = false;
-+    res = op(a, b, overflow);
-+    return overflow;
-+}
-+
-+private T builtin_opc(alias op, T)(T a, T b, T carry_in, ref T carry_out)
-+{
-+    carry_out = op(a, b, a) | op(a, carry_in, a);
-+    return a;
-+}
-+
-+pragma(inline, true)
-+{
-+    bool __builtin_add_overflow(T1, T2, T3)(T1 a, T2 b, T3* res) => overflowOp!(adds, T1, T2, T3)(a, b, *res);
-+    bool __builtin_sub_overflow(T1, T2, T3)(T1 a, T2 b, T3* res) => overflowOp!(subs, T1, T2, T3)(a, b, *res);
-+    bool __builtin_mul_overflow(T1, T2, T3)(T1 a, T2 b, T3* res) => overflowOp!(muls, T1, T2, T3)(a, b, *res);
-+    bool __builtin_add_overflow_p(T1, T2, T3)(T1 a, T2 b, T3 c)  => overflowOp!(adds, T1, T2, T3)(a, b, res);
-+    bool __builtin_sub_overflow_p(T1, T2, T3)(T1 a, T2 b, T3 c)  => overflowOp!(subs, T1, T2, T3)(a, b, res);
-+    bool __builtin_mul_overflow_p(T1, T2, T3)(T1 a, T2 b, T3 c)  => overflowOp!(muls, T1, T2, T3)(a, b, res);
-+    bool __builtin_sadd_overflow  ()(int     a, int     b, int*     res) => overflowOp!(adds, int    , int    , int    )(a, b, *res);
-+    bool __builtin_saddl_overflow ()(c_long  a, c_long  b, c_long*  res) => overflowOp!(adds, c_long , c_long , c_long )(a, b, *res);
-+    bool __builtin_saddll_overflow()(long    a, long    b, long*    res) => overflowOp!(adds, long   , long   , long   )(a, b, *res);
-+    bool __builtin_uadd_overflow  ()(uint    a, uint    b, uint*    res) => overflowOp!(adds, uint   , uint   , uint   )(a, b, *res);
-+    bool __builtin_uaddl_overflow ()(c_ulong a, c_ulong b, c_ulong* res) => overflowOp!(adds, c_ulong, c_ulong, c_ulong)(a, b, *res);
-+    bool __builtin_uaddll_overflow()(ulong   a, ulong   b, ulong*   res) => overflowOp!(adds, ulong  , ulong  , ulong  )(a, b, *res);
-+    bool __builtin_ssub_overflow  ()(int     a, int     b, int*     res) => overflowOp!(subs, int    , int    , int    )(a, b, *res);
-+    bool __builtin_ssubl_overflow ()(c_long  a, c_long  b, c_long*  res) => overflowOp!(subs, c_long , c_long , c_long )(a, b, *res);
-+    bool __builtin_ssubll_overflow()(long    a, long    b, long*    res) => overflowOp!(subs, long   , long   , long   )(a, b, *res);
-+    bool __builtin_usub_overflow  ()(uint    a, uint    b, uint*    res) => overflowOp!(subs, uint   , uint   , uint   )(a, b, *res);
-+    bool __builtin_usubl_overflow ()(c_ulong a, c_ulong b, c_ulong* res) => overflowOp!(subs, c_ulong, c_ulong, c_ulong)(a, b, *res);
-+    bool __builtin_usubll_overflow()(ulong   a, ulong   b, ulong*   res) => overflowOp!(subs, ulong  , ulong  , ulong  )(a, b, *res);
-+    bool __builtin_smul_overflow  ()(int     a, int     b, int*     res) => overflowOp!(muls, int    , int    , int    )(a, b, *res);
-+    bool __builtin_smull_overflow ()(c_long  a, c_long  b, c_long*  res) => overflowOp!(muls, c_long , c_long , c_long )(a, b, *res);
-+    bool __builtin_smulll_overflow()(long    a, long    b, long*    res) => overflowOp!(muls, long   , long   , long   )(a, b, *res);
-+    bool __builtin_umul_overflow  ()(uint    a, uint    b, uint*    res) => overflowOp!(muls, uint   , uint   , uint   )(a, b, *res);
-+    bool __builtin_umull_overflow ()(c_ulong a, c_ulong b, c_ulong* res) => overflowOp!(muls, c_ulong, c_ulong, c_ulong)(a, b, *res);
-+    bool __builtin_umulll_overflow()(ulong   a, ulong   b, ulong*   res) => overflowOp!(muls, ulong  , ulong  , ulong  )(a, b, *res);
-+
-+    uint  __builtin_addc  ()(uint  a, uint  b, uint  carry_in, uint*  carry_out) => builtin_opc!(adds, uint )(a, b, carry_in, *carry_out);
-+    ulong __builtin_addcl ()(ulong a, ulong b, uint  carry_in, ulong* carry_out) => builtin_opc!(adds, ulong)(a, b, carry_in, *carry_out);
-+    ulong __builtin_addcll()(ulong a, ulong b, ulong carry_in, ulong* carry_out) => builtin_opc!(adds, ulong)(a, b, carry_in, *carry_out);
-+    uint  __builtin_subc  ()(uint  a, uint  b, uint  carry_in, uint*  carry_out) => builtin_opc!(subs, uint )(a, b, carry_in, *carry_out);
-+    ulong __builtin_subcl ()(ulong a, ulong b, uint  carry_in, ulong* carry_out) => builtin_opc!(subs, ulong)(a, b, carry_in, *carry_out);
-+    ulong __builtin_subcll()(ulong a, ulong b, ulong carry_in, ulong* carry_out) => builtin_opc!(subs, ulong)(a, b, carry_in, *carry_out);
-+}
-+
-+unittest {
-+    int r1;
-+    assert(__builtin_sadd_overflow(2147483647, 1, &r1) == true);
-+    assert(__builtin_sadd_overflow(1, 1, &r1) == false);
-+
-+    assert(__builtin_ssub_overflow(-2147483648, 1, &r1) == true);
-+    assert(__builtin_ssub_overflow(5, 3, &r1) == false);
-+
-+    assert(__builtin_smul_overflow(2000000000, 2, &r1) == true);
-+    assert(__builtin_smul_overflow(10, 20, &r1) == false);
-+
-+    uint ur;
-+    assert(__builtin_uadd_overflow(0xFFFFFFFFu, 1u, &ur) == true);
-+    assert(__builtin_uadd_overflow(10u, 20u, &ur) == false);
-+
-+    assert(__builtin_usub_overflow(0u, 1u, &ur) == true);
-+    assert(__builtin_usub_overflow(20u, 10u, &ur) == false);
-+
-+    assert(__builtin_umul_overflow(0xFFFFFFFFu, 2u, &ur) == true);
-+    assert(__builtin_umul_overflow(10u, 20u, &ur) == false);
-+
-+    uint carry;
-+    uint rr = __builtin_addc(1u, 1u, 0u, &carry);
-+    assert(rr == 2);
-+    assert(carry == 0);
-+
-+    rr = __builtin_addc(0xFFFFFFFFu, 1u, 0u, &carry);
-+    assert(carry == 1);
-+
-+    rr = __builtin_subc(1u, 1u, 0u, &carry);
-+    assert(rr == 0);
-+    assert(carry == 0);
-+
-+    rr = __builtin_subc(0u, 1u, 0u, &carry);
-+    assert(carry == 1);
-+}
-+
-+private U signbit(T, U)(T x)
-+{
-+    T arg = x;
-+    return cast(U)arg >> (T.sizeof * 8 - 1);
-+}
-+
-+pragma(inline, true)
-+{
-+    // https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html
-+    import core.bitop : popcnt, bsr, bsf, rol, ror;
-+    private int clz(T)(T x) => bsr(x) ^ ((int.sizeof * 8)-1);
-+
-+    int __builtin_clz()(uint x)          => clz!uint(x);
-+    int __builtin_clzl()(c_ulong x)      => clz!c_ulong(x);
-+    int __builtin_clzll()(ulong x)       => clz!ulong(x);
-+    int __builtin_clzg(T)(T arg)         => clz(arg);
-+
-+    int __builtin_ctz()(uint x)          => bsf(x);
-+    int __builtin_ctzl()(c_ulong x)      => bsf(x);
-+    int __builtin_ctzll()(ulong x)       => bsf(x);
-+    int __builtin_ctzg(T)(T arg)         => bsf(arg);
-+
<Skipped 6692 lines>
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/ldc.git/commitdiff/3f7e934b5834dcfd38d80b7b5c9e31ef21e57449



More information about the pld-cvs-commit mailing list