diff --git a/buildbot/configure.py b/buildbot/configure.py index 8477469031a99..9283ac1a7bd08 100644 --- a/buildbot/configure.py +++ b/buildbot/configure.py @@ -51,7 +51,6 @@ def do_configure(args, passthrough_args): llvm_enable_projects = "clang;" + llvm_external_projects libclc_build_native = "OFF" libclc_targets_to_build = "" - libclc_gen_remangled_variants = "OFF" sycl_build_ur_hip_platform = "AMD" sycl_clang_extra_flags = "" sycl_werror = "OFF" @@ -91,7 +90,6 @@ def do_configure(args, passthrough_args): if args.cuda: llvm_targets_to_build += ";NVPTX" libclc_targets_to_build = libclc_nvidia_target_names - libclc_gen_remangled_variants = "ON" sycl_enabled_backends.append("cuda") if args.hip: @@ -102,7 +100,6 @@ def do_configure(args, passthrough_args): elif args.hip_platform == "NVIDIA" and not args.cuda: llvm_targets_to_build += ";NVPTX" libclc_targets_to_build += libclc_nvidia_target_names - libclc_gen_remangled_variants = "ON" sycl_build_ur_hip_platform = args.hip_platform sycl_enabled_backends.append("hip") @@ -112,7 +109,6 @@ def do_configure(args, passthrough_args): libclc_targets_to_build += ";" + args.native_cpu_libclc_targets else: libclc_build_native = "ON" - libclc_gen_remangled_variants = "ON" sycl_enabled_backends.append("native_cpu") # all llvm compiler targets don't require 3rd party dependencies, so can be @@ -161,7 +157,6 @@ def do_configure(args, passthrough_args): # Add NVIDIA libclc targets if libclc_nvidia_target_names not in libclc_targets_to_build: libclc_targets_to_build += libclc_nvidia_target_names - libclc_gen_remangled_variants = "ON" spirv_enable_dis = "ON" if args.enable_backends: @@ -240,9 +235,6 @@ def do_configure(args, passthrough_args): cmake_cmd.extend( [ "-DLIBCLC_TARGETS_TO_BUILD={}".format(libclc_targets_to_build), - "-DLIBCLC_GENERATE_REMANGLED_VARIANTS={}".format( - libclc_gen_remangled_variants - ), "-DLIBCLC_NATIVECPU_HOST_TARGET={}".format(libclc_build_native), ] ) diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index bd256388f3223..6f7299bf71c2b 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -502,6 +502,9 @@ CODEGENOPT(DisableSYCLEarlyOpts, 1, 0, Benign) /// which do not contain "user" code. CODEGENOPT(OptimizeSYCLFramework, 1, 0, Benign) +/// Whether to remangle SPIR-V built-ins in libspirv for SYCL. +CODEGENOPT(SYCLRemangleLibspirv, 1, 0, Benign) + /// Whether to use alloca address space for `sret` arguments. /// TODO: This option can be removed once a fix goes in that can /// work with the community changes for using the alloca address space. diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index a954909785b6b..cf5b7f25462e5 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -9532,6 +9532,11 @@ defm offload_use_alloca_addrspace_for_srets : BoolFOption<"offload-use-alloca-ad PosFlag, NegFlag>; +def fsycl_remangle_libspirv + : Flag<["-"], "fsycl-remangle-libspirv">, + HelpText<"Remangle SPIR-V built-ins in libspirv for SYCL">, + MarshallingInfoFlag>; + } // let Visibility = [CC1Option] def sycl_std_EQ : Joined<["-"], "sycl-std=">, Group, diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 188f0a08a2464..c0e66ad29f6fe 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -59,6 +59,7 @@ #include "llvm/SYCLLowerIR/SYCLOptimizeBarriers.h" #include "llvm/SYCLLowerIR/SYCLPropagateAspectsUsage.h" #include "llvm/SYCLLowerIR/SYCLPropagateJointMatrixUsage.h" +#include "llvm/SYCLLowerIR/SYCLRemangleLibspirv.h" #include "llvm/SYCLLowerIR/SYCLVirtualFunctionsAnalysis.h" #include "llvm/SYCLLowerIR/UtilsSYCLNativeCPU.h" #include "llvm/Support/BuryPointer.h" @@ -1103,6 +1104,13 @@ void EmitAssemblyHelper::RunOptimizationPipeline( }); } + if (CodeGenOpts.SYCLRemangleLibspirv) { + PB.registerOptimizerLastEPCallback( + [&](ModulePassManager &MPM, OptimizationLevel, ThinOrFullLTOPhase) { + MPM.addPass(SYCLRemangleLibspirvPass()); + }); + } + const bool PrepareForThinLTO = CodeGenOpts.PrepareForThinLTO; const bool PrepareForLTO = CodeGenOpts.PrepareForLTO; diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp index a90b0c150608c..30132d5fe1120 100644 --- a/clang/lib/Driver/ToolChains/SYCL.cpp +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -40,8 +40,8 @@ getLibSpirvBasename(const llvm::Triple &HostTriple) { // All known windows environments except Cygwin use 32-bit long. llvm::SmallString<64> Result(HostTriple.isOSWindows() && !HostTriple.isWindowsCygwinEnvironment() - ? "remangled-l32-signed_char.libspirv.bc" - : "remangled-l64-signed_char.libspirv.bc"); + ? "libspirv.l32.signed_char.bc" + : "libspirv.l64.signed_char.bc"); return Result; } diff --git a/clang/test/CodeGen/sycl-remangle-libspirv-pipeline.cl b/clang/test/CodeGen/sycl-remangle-libspirv-pipeline.cl new file mode 100644 index 0000000000000..27435bc272b80 --- /dev/null +++ b/clang/test/CodeGen/sycl-remangle-libspirv-pipeline.cl @@ -0,0 +1,16 @@ +// Test that -fsycl-remangle-libspirv flag enables SYCLRemangleLibspirvPass. + +// RUN: %clang_cc1 -triple spir64-unknown-unknown -emit-llvm-bc -o /dev/null \ +// RUN: -mllvm -print-pipeline-passes \ +// RUN: %s 2>&1 | FileCheck --check-prefixes=DEFAULT %s + +// DEFAULT-NOT: sycl-remangle-libspirv + +// RUN: %clang_cc1 -triple spir64-unknown-unknown -emit-llvm-bc -o /dev/null \ +// RUN: -mllvm -print-pipeline-passes \ +// RUN: -fsycl-remangle-libspirv \ +// RUN: %s 2>&1 | FileCheck --check-prefixes=ENABLED %s + +// ENABLED: sycl-remangle-libspirv + +void test() {} diff --git a/clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/amdgcn-amd-amdhsa/remangled-l32-signed_char.libspirv.bc b/clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/amdgcn-amd-amdhsa/libspirv.l32.signed_char.bc similarity index 100% rename from clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/amdgcn-amd-amdhsa/remangled-l32-signed_char.libspirv.bc rename to clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/amdgcn-amd-amdhsa/libspirv.l32.signed_char.bc diff --git a/clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/amdgcn-amd-amdhsa/remangled-l64-signed_char.libspirv.bc b/clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/amdgcn-amd-amdhsa/libspirv.l64.signed_char.bc similarity index 100% rename from clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/amdgcn-amd-amdhsa/remangled-l64-signed_char.libspirv.bc rename to clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/amdgcn-amd-amdhsa/libspirv.l64.signed_char.bc diff --git a/clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l32-signed_char.libspirv.bc b/clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l32.signed_char.bc similarity index 100% rename from clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l32-signed_char.libspirv.bc rename to clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l32.signed_char.bc diff --git a/clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l64-signed_char.libspirv.bc b/clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l64.signed_char.bc similarity index 100% rename from clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l64-signed_char.libspirv.bc rename to clang/test/Driver/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l64.signed_char.bc diff --git a/clang/test/Driver/sycl-cuda-rdc.cpp b/clang/test/Driver/sycl-cuda-rdc.cpp index 57eda221cc1c9..6539fc7bd9d9e 100644 --- a/clang/test/Driver/sycl-cuda-rdc.cpp +++ b/clang/test/Driver/sycl-cuda-rdc.cpp @@ -5,7 +5,7 @@ // UNSUPPORTED: system-windows // RUN: %clangxx -### -fsycl -fsycl-targets=nvptx64-nvidia-cuda -Xsycl-target-backend --cuda-gpu-arch=sm_61 -fgpu-rdc -nocudalib \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l64-signed_char.libspirv.bc %s 2>&1 \ +// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l64.signed_char.bc %s 2>&1 \ // RUN: | FileCheck %s -check-prefix=CHECK-SYCL_RDC_NVPTX // Verify that ptxas does not pass "-c" diff --git a/clang/test/Driver/sycl-device-obj-asm.cpp b/clang/test/Driver/sycl-device-obj-asm.cpp index a32b2ab74ca0f..603124153dea3 100644 --- a/clang/test/Driver/sycl-device-obj-asm.cpp +++ b/clang/test/Driver/sycl-device-obj-asm.cpp @@ -30,10 +30,10 @@ /// -fsycl-device-obj=asm should always be accompanied by -fsycl-device-only /// and -S, check that the compiler issues a correct warning message: -// RUN: %clang -### -nocudalib -fsycl-device-only -fsycl -fsycl-targets=nvptx64-nvidia-cuda -Xsycl-target-backend=nvptx64-nvidia-cuda --cuda-gpu-arch=sm_50 -fsycl-device-obj=asm %s 2>&1 -o - -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l64-signed_char.libspirv.bc | FileCheck %s --check-prefix=CHECK-NO-DEV-ONLY-NO-S +// RUN: %clang -### -nocudalib -fsycl-device-only -fsycl -fsycl-targets=nvptx64-nvidia-cuda -Xsycl-target-backend=nvptx64-nvidia-cuda --cuda-gpu-arch=sm_50 -fsycl-device-obj=asm %s 2>&1 -o - -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l64.signed_char.bc | FileCheck %s --check-prefix=CHECK-NO-DEV-ONLY-NO-S // CHECK-NO-DEV-ONLY-NO-S: warning: -fsycl-device-obj=asm flag has an effect only when compiling device code and emitting assembly, make sure both -fsycl-device-only and -S flags are present; will be ignored [-Wunused-command-line-argument] /// -fsycl-device-obj=asm will finish at generating assembly stage, hence /// inform users that generating library will not be possible (ignore -c) -// RUN: %clang -### -nocudalib -fsycl-device-only -fsycl -fsycl-targets=nvptx64-nvidia-cuda -Xsycl-target-backend=nvptx64-nvidia-cuda --cuda-gpu-arch=sm_50 -fsycl-device-obj=asm %s 2>&1 -fsycl-device-only -S -c -o - -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l64-signed_char.libspirv.bc | FileCheck %s --check-prefix=CHECK-DASH-C-IGNORE +// RUN: %clang -### -nocudalib -fsycl-device-only -fsycl -fsycl-targets=nvptx64-nvidia-cuda -Xsycl-target-backend=nvptx64-nvidia-cuda --cuda-gpu-arch=sm_50 -fsycl-device-obj=asm %s 2>&1 -fsycl-device-only -S -c -o - -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l64.signed_char.bc | FileCheck %s --check-prefix=CHECK-DASH-C-IGNORE // CHECK-DASH-C-IGNORE: warning: argument unused during compilation: '-c' [-Wunused-command-line-argument] diff --git a/clang/test/Driver/sycl-libspirv-invalid.cpp b/clang/test/Driver/sycl-libspirv-invalid.cpp index 0683721031755..874964d829b53 100644 --- a/clang/test/Driver/sycl-libspirv-invalid.cpp +++ b/clang/test/Driver/sycl-libspirv-invalid.cpp @@ -5,31 +5,31 @@ // RUN: -fsycl-targets=nvptx64-nvidia-cuda --cuda-path=%S/Inputs/CUDA/usr/local/cuda \ // RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/no-libspirv-exists-here.bc %s 2>&1 \ // RUN: | FileCheck --check-prefix=ERR-CUDA %s -// ERR-CUDA: cannot find 'remangled-l64-signed_char.libspirv.bc'; +// ERR-CUDA: cannot find 'libspirv.l64.signed_char.bc'; // ERR-CUDA-SAME: provide path to libspirv library via '-fsycl-libspirv-path', or pass '-fno-sycl-libspirv' to build without linking with libspirv // RUN: not %clangxx -### -std=c++11 -target x86_64-unknown-windows-msvc -fsycl -nocudalib \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda --cuda-path=%S/Inputs/CUDA/usr/local/cuda \ // RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/no-libspirv-exists-here.bc %s 2>&1 \ // RUN: | FileCheck --check-prefix=ERR-CUDA-WIN %s -// ERR-CUDA-WIN: cannot find 'remangled-l32-signed_char.libspirv.bc'; +// ERR-CUDA-WIN: cannot find 'libspirv.l32.signed_char.bc'; // ERR-CUDA-WIN-SAME: provide path to libspirv library via '-fsycl-libspirv-path', or pass '-fno-sycl-libspirv' to build without linking with libspirv // RUN: not %clangxx -### -std=c++11 -target x86_64-unknown-linux-gnu -fsycl -nogpulib \ // RUN: -fsycl-targets=amdgcn-amd-amdhsa -Xsycl-target-backend --offload-arch=gfx908 \ // RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/no-libspirv-exists-here.bc %s 2>&1 \ // RUN: | FileCheck --check-prefix=ERR-HIP %s -// ERR-HIP: cannot find 'remangled-l64-signed_char.libspirv.bc'; +// ERR-HIP: cannot find 'libspirv.l64.signed_char.bc'; // ERR-HIP-SAME: provide path to libspirv library via '-fsycl-libspirv-path', or pass '-fno-sycl-libspirv' to build without linking with libspirv // RUN: %clangxx -### -std=c++11 -target x86_64-unknown-linux-gnu -fsycl \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda --cuda-path=%S/Inputs/CUDA/usr/local/cuda \ // RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/no-libspirv-exists-here.bc -fno-sycl-libspirv %s 2>&1 \ // RUN: | FileCheck --check-prefix=OK-CUDA %s -// OK-CUDA-NOT: cannot find suitable 'remangled-l64-signed_char.libspirv.bc' +// OK-CUDA-NOT: cannot find suitable 'libspirv.l64.signed_char.bc' // RUN: %clangxx -### -std=c++11 -target x86_64-unknown-linux-gnu -fsycl -nogpulib \ // RUN: -fsycl-targets=amdgcn-amd-amdhsa -Xsycl-target-backend --offload-arch=gfx908 \ // RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/no-libspirv-exists-here.bc -fno-sycl-libspirv %s 2>&1 \ // RUN: | FileCheck --check-prefix=OK-HIP %s -// OK-HIP-NOT: cannot find 'remangled-l64-signed_char.libspirv.bc' +// OK-HIP-NOT: cannot find 'libspirv.l64.signed_char.bc' diff --git a/clang/test/Driver/sycl-libspirv-toolchain.cpp b/clang/test/Driver/sycl-libspirv-toolchain.cpp index 17b3b8d4f9862..e057d0278ab94 100644 --- a/clang/test/Driver/sycl-libspirv-toolchain.cpp +++ b/clang/test/Driver/sycl-libspirv-toolchain.cpp @@ -6,43 +6,43 @@ // RUN: | FileCheck %s --check-prefixes=CHECK-WINDOWS // RUN: %clang -### -resource-dir %{resource_dir} -fsycl -fsycl-targets=nvptx64-nvidia-cuda -nocudalib -target x86_64-unknown-windows-gnu %s 2>&1 \ // RUN: | FileCheck %s --check-prefixes=CHECK-WINDOWS -// CHECK-WINDOWS: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "{{.*[\\/]}}remangled-l32-signed_char.libspirv.bc" +// CHECK-WINDOWS: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "{{.*[\\/]}}libspirv.l32.signed_char.bc" // // RUN: %clang -### -resource-dir %{resource_dir} -fsycl -fsycl-targets=nvptx64-nvidia-cuda -nocudalib -target x86_64-unknown-linux-gnu %s 2>&1 \ // RUN: | FileCheck %s --check-prefixes=CHECK-LINUX // RUN: %clang -### -resource-dir %{resource_dir} -fsycl -fsycl-targets=nvptx64-nvidia-cuda -nocudalib -target x86_64-unknown-windows-cygnus %s 2>&1 \ // RUN: | FileCheck %s --check-prefixes=CHECK-LINUX -// CHECK-LINUX: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "{{.*[\\/]}}remangled-l64-signed_char.libspirv.bc" +// CHECK-LINUX: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "{{.*[\\/]}}libspirv.l64.signed_char.bc" // // RUN: %clang -### -resource-dir %{resource_dir} -fsycl -fsycl-targets=amdgcn-amd-amdhsa -Xsycl-target-backend --offload-arch=gfx908 -nogpulib -target x86_64-unknown-windows-msvc %s 2>&1 \ // RUN: | FileCheck %s --check-prefixes=CHECK-AMDGCN-WINDOWS -// CHECK-AMDGCN-WINDOWS: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "{{.*[\\/]}}remangled-l32-signed_char.libspirv.bc" +// CHECK-AMDGCN-WINDOWS: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "{{.*[\\/]}}libspirv.l32.signed_char.bc" // // RUN: %clang -### -resource-dir %{resource_dir} -fsycl -fsycl-device-only -fsycl-targets=nvptx64-nvidia-cuda -nocudalib %s 2>&1 \ // RUN: | FileCheck %s --check-prefixes=CHECK-DEVICE-ONLY -// CHECK-DEVICE-ONLY: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "{{.*[\\/]}}remangled-{{.*}}.libspirv.bc" +// CHECK-DEVICE-ONLY: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "{{.*[\\/]}}libspirv.l[[#]].signed_char.bc" // // Only link libspirv in SYCL language mode, `-fno-sycl-libspirv` should result in a warning // RUN: %clang -### -x cu -fno-sycl-libspirv -nocudainc -nocudalib %s 2>&1 | FileCheck %s --check-prefixes=CHECK-CUDA // CHECK-CUDA: warning: argument unused during compilation: '-fno-sycl-libspirv' [-Wunused-command-line-argument] // CHECK-CUDA: "-cc1"{{.*}} "-fcuda-is-device" -// CHECK-CUDA-NOT: "-mlink-builtin-bitcode" "{{.*}}.libspirv.bc" +// CHECK-CUDA-NOT: "-mlink-builtin-bitcode" "{{.*}}libspirv.l[[#]].signed_char.bc" // -// The path to the remangled libspirv bitcode file is determined by the resource directory +// The path to the libspirv bitcode file is determined by the resource directory // RUN: %clang -### -resource-dir %{resource_dir} -fsycl -fsycl-targets=nvptx64-nvidia-cuda -nocudalib %s 2>&1 \ // RUN: | FileCheck %s -DRESOURCE_DIR=%{resource_dir} --check-prefixes=CHECK-DIR -// CHECK-DIR: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "[[RESOURCE_DIR]]{{.*[\\/]}}remangled-{{.*}}.libspirv.bc" +// CHECK-DIR: "-cc1"{{.*}} "-fsycl-is-device"{{.*}} "-mlink-builtin-bitcode" "[[RESOURCE_DIR]]{{.*[\\/]}}libspirv.l[[#]].signed_char.bc" // // If libspirv path doesn't exist, error is reported. // DEFINE: %{nonexistent_dir} = %/S/Inputs/SYCL/does_not_exist/lib/clang/resource_dir // RUN: not %clang -### -resource-dir %{nonexistent_dir} -fsycl -fsycl-targets=nvptx64-nvidia-cuda -nocudalib %s 2>&1 \ // RUN: | FileCheck %s -DDIR=%{nonexistent_dir} --check-prefixes=CHECK-HHH-NONEXISTENT -// CHECK-HHH-NONEXISTENT: error: cannot find 'remangled-{{.*}}.libspirv.bc'; provide path to libspirv library via '-fsycl-libspirv-path', or pass '-fno-sycl-libspirv' to build without linking with libspirv +// CHECK-HHH-NONEXISTENT: error: cannot find 'libspirv.l[[#]].signed_char.bc'; provide path to libspirv library via '-fsycl-libspirv-path', or pass '-fno-sycl-libspirv' to build without linking with libspirv // // RUN: not %clang -### -resource-dir %{nonexistent_dir} -fsycl -fsycl-targets=amdgcn-amd-amdhsa -Xsycl-target-backend --offload-arch=gfx908 -nogpulib %s 2>&1 \ // RUN: | FileCheck %s -DDIR=%{nonexistent_dir} --check-prefixes=CHECK-AMDGCN-HHH-NONEXISTENT -// CHECK-AMDGCN-HHH-NONEXISTENT: clang: error: cannot find 'remangled-{{.*}}.libspirv.bc'; provide path to libspirv library via '-fsycl-libspirv-path', or pass '-fno-sycl-libspirv' to build without linking with libspirv +// CHECK-AMDGCN-HHH-NONEXISTENT: clang: error: cannot find 'libspirv.l[[#]].signed_char.bc'; provide path to libspirv library via '-fsycl-libspirv-path', or pass '-fno-sycl-libspirv' to build without linking with libspirv // // RUN: not %clang -fdriver-only -resource-dir %{nonexistent_dir} -fsycl -fsycl-targets=nvptx64-nvidia-cuda -nocudalib %s 2>&1 \ // RUN: | FileCheck %s -DDIR=%{nonexistent_dir} --check-prefixes=CHECK-DO-NONEXISTENT -// CHECK-DO-NONEXISTENT: error: cannot find 'remangled-{{.*}}.libspirv.bc'; provide path to libspirv library via '-fsycl-libspirv-path', or pass '-fno-sycl-libspirv' to build without linking with libspirv +// CHECK-DO-NONEXISTENT: error: cannot find 'libspirv.l[[#]].signed_char.bc'; provide path to libspirv library via '-fsycl-libspirv-path', or pass '-fno-sycl-libspirv' to build without linking with libspirv diff --git a/clang/test/Driver/sycl-nvptx-link.cpp b/clang/test/Driver/sycl-nvptx-link.cpp index 5090958fef9c0..107c6f710c79e 100644 --- a/clang/test/Driver/sycl-nvptx-link.cpp +++ b/clang/test/Driver/sycl-nvptx-link.cpp @@ -42,7 +42,7 @@ // CHECK: llvm-link // CHECK-SAME: -only-needed -// CHECK-SAME: remangled-{{.*}}-signed_char.libspirv.bc +// CHECK-SAME: libspirv.l[[#]].signed_char.bc // LIBDEVICE10-SAME: libdevice.10.bc // LIBDEVICE30-SAME: libdevice.compute_30.10.bc // LIBDEVICE35-SAME: libdevice.compute_35.10.bc diff --git a/clang/test/Driver/sycl-offload-nvptx.cpp b/clang/test/Driver/sycl-offload-nvptx.cpp index 8b72f722a8e97..a24625857bc02 100644 --- a/clang/test/Driver/sycl-offload-nvptx.cpp +++ b/clang/test/Driver/sycl-offload-nvptx.cpp @@ -2,18 +2,20 @@ // UNSUPPORTED: system-windows +// DEFINE: %{resource_dir} = %/S/Inputs/SYCL/lib/clang/resource_dir + /// Check action graph. // RUN: %clangxx -### -std=c++11 -target x86_64-unknown-linux-gnu -fsycl \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda --cuda-path=%S/Inputs/CUDA/usr/local/cuda \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/libspirv.bc %s 2>&1 \ +// RUN: -resource-dir %{resource_dir} %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-ACTIONS %s // // RUN: %clang_cl -### -fsycl \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda --cuda-path=%S/Inputs/CUDA/usr/local/cuda \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/libspirv.bc %s 2>&1 \ +// RUN: -resource-dir %{resource_dir} %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-ACTIONS-WIN %s -// CHK-ACTIONS: "-cc1" "-triple" "nvptx64-nvidia-cuda" "-{{.*}}"-aux-triple" "x86_64-unknown-linux-gnu"{{.*}} "-fsycl-is-device"{{.*}} "-Wno-sycl-strict"{{.*}} "-sycl-std=2020" {{.*}} "-emit-llvm-bc" {{.*}} "-internal-isystem" "{{.*}}bin{{[/\\]+}}..{{[/\\]+}}include{{[/\\]+}}sycl{{[/\\]+}}stl_wrappers"{{.*}} "-mlink-builtin-bitcode" "{{.*}}libspirv.bc"{{.*}} "-mlink-builtin-bitcode" "{{.*}}libdevice{{.*}}.10.bc"{{.*}} "-target-sdk-version=[[CUDA_VERSION:[0-9.]+]]"{{.*}} "-target-cpu" "sm_75"{{.*}} "-target-feature" "+ptx63"{{.*}} "-std=c++11"{{.*}} +// CHK-ACTIONS: "-cc1" "-triple" "nvptx64-nvidia-cuda" "-{{.*}}"-aux-triple" "x86_64-unknown-linux-gnu"{{.*}} "-fsycl-is-device"{{.*}} "-Wno-sycl-strict"{{.*}} "-sycl-std=2020" {{.*}} "-emit-llvm-bc" {{.*}} "-internal-isystem" "{{.*}}bin{{[/\\]+}}..{{[/\\]+}}include{{[/\\]+}}sycl{{[/\\]+}}stl_wrappers"{{.*}} "-mlink-builtin-bitcode" "{{.*}}libspirv.l64.signed_char.bc"{{.*}} "-mlink-builtin-bitcode" "{{.*}}libdevice{{.*}}.10.bc"{{.*}} "-target-sdk-version=[[CUDA_VERSION:[0-9.]+]]"{{.*}} "-target-cpu" "sm_75"{{.*}} "-target-feature" "+ptx63"{{.*}} "-std=c++11"{{.*}} // CHK-ACTIONS: sycl-post-link // CHK-ACTIONS-NOT: -split // CHK-ACTIONS-SAME: -o @@ -25,7 +27,7 @@ // CHK-ACTIONS-NOT: "-mllvm -sycl-opt" // CHK-ACTIONS: clang-offload-wrapper"{{.*}} "-host=x86_64-unknown-linux-gnu" "-target=nvptx64" "-kind=sycl"{{.*}} -// CHK-ACTIONS-WIN: "-cc1" "-triple" "nvptx64-nvidia-cuda" "-{{.*}}"-aux-triple" "x86_64-pc-windows-msvc"{{.*}} "-fsycl-is-device"{{.*}} "-Wno-sycl-strict"{{.*}} "-sycl-std=2020" {{.*}} "-emit-llvm-bc" {{.*}} "-internal-isystem" "{{.*}}bin{{[/\\]+}}..{{[/\\]+}}include{{[/\\]+}}sycl{{[/\\]+}}stl_wrappers"{{.*}} "-mlink-builtin-bitcode" "{{.*}}libspirv.bc"{{.*}} "-mlink-builtin-bitcode" "{{.*}}libdevice{{.*}}.10.bc"{{.*}} "-target-sdk-version=[[CUDA_VERSION:[0-9.]+]]"{{.*}} "-target-cpu" "sm_75"{{.*}} "-target-feature" "+ptx63"{{.*}} +// CHK-ACTIONS-WIN: "-cc1" "-triple" "nvptx64-nvidia-cuda" "-{{.*}}"-aux-triple" "x86_64-pc-windows-msvc"{{.*}} "-fsycl-is-device"{{.*}} "-Wno-sycl-strict"{{.*}} "-sycl-std=2020" {{.*}} "-emit-llvm-bc" {{.*}} "-internal-isystem" "{{.*}}bin{{[/\\]+}}..{{[/\\]+}}include{{[/\\]+}}sycl{{[/\\]+}}stl_wrappers"{{.*}} "-mlink-builtin-bitcode" "{{.*}}libspirv.l32.signed_char.bc"{{.*}} "-mlink-builtin-bitcode" "{{.*}}libdevice{{.*}}.10.bc"{{.*}} "-target-sdk-version=[[CUDA_VERSION:[0-9.]+]]"{{.*}} "-target-cpu" "sm_75"{{.*}} "-target-feature" "+ptx63"{{.*}} // CHK-ACTIONS-WIN: sycl-post-link // CHK-ACTIONS-WIN-NOT: -split // CHK-ACTIONS-WIN-SAME: -o @@ -42,7 +44,7 @@ // RUN: %clangxx -ccc-print-phases --sysroot=%S/Inputs/SYCL -std=c++11 \ // RUN: -target x86_64-unknown-linux-gnu -fsycl --no-offloadlib \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda %s 2>&1 \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l32-signed_char.libspirv.bc \ +// RUN: -resource-dir %{resource_dir} \ // RUN: --cuda-path=%S/Inputs/CUDA_111/usr/local/cuda \ // RUN: | FileCheck -check-prefix=CHK-PHASES-NO-CC %s // @@ -75,7 +77,7 @@ // RUN: %clangxx -ccc-print-phases --sysroot=%S/Inputs/SYCL -std=c++11 \ // RUN: -target x86_64-unknown-linux-gnu -fsycl --no-offloadlib \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l32-signed_char.libspirv.bc \ +// RUN: -resource-dir %{resource_dir} \ // RUN: --cuda-path=%S/Inputs/CUDA_111/usr/local/cuda \ // RUN: -Xsycl-target-backend "--cuda-gpu-arch=sm_35" %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-PHASES %s @@ -114,12 +116,12 @@ // // RUN: not %clangxx -### -std=c++11 -target x86_64-unknown-linux-gnu -fsycl \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda --cuda-path=%S/Inputs/no/CUDA/path/here \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/libspirv.bc %s 2>&1 \ +// RUN: -resource-dir %{resource_dir} %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-CUDA-PATH-ERROR %s // // RUN: not %clang_cl -### -fsycl \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda --cuda-path=%S/Inputs/no/CUDA/path/here \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/libspirv.bc %s 2>&1 \ +// RUN: -resource-dir %{resource_dir} %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-CUDA-PATH-ERROR %s // // CHK-CUDA-PATH-ERROR: provide path to different CUDA installation via '--cuda-path', or pass '-nocudalib' to build without linking with libdevice @@ -127,12 +129,12 @@ // // RUN: %clangxx -### -std=c++11 -target x86_64-unknown-linux-gnu -fsycl \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda --cuda-path=%S/Inputs/no/CUDA/path/here \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/libspirv.bc -nocudalib %s 2>&1 \ +// RUN: -resource-dir %{resource_dir} -nocudalib %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-CUDA-NO-LIB %s // // RUN: %clang_cl -### -fsycl \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda --cuda-path=%S/Inputs/no/CUDA/path/here \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/libspirv.bc -nocudalib %s 2>&1 \ +// RUN: -resource-dir %{resource_dir} -nocudalib %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-CUDA-NO-LIB %s // // CHK-CUDA-NO-LIB-NOT: provide path to different CUDA installation via '--cuda-path', or pass '-nocudalib' to build without linking with libdevice @@ -141,7 +143,7 @@ // Check that flags linked to fsycl-cuda-compatibility are set correctly // RUN: %clangxx -### -std=c++11 -target x86_64-unknown-linux-gnu -fsycl -fsycl-cuda-compatibility \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda --cuda-path=%S/Inputs/CUDA/usr/local/cuda \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/libspirv.bc %s 2>&1 \ +// RUN: -resource-dir %{resource_dir} %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-ACTIONS-CUDA-COMPAT %s // CHK-ACTIONS-CUDA-COMPAT: "-cc1" "-triple" "nvptx64-nvidia-cuda"{{.*}} "-fsycl-is-device"{{.*}} "-fsycl-cuda-compatibility"{{.*}} "-fdeclspec"{{.*}} "-fcuda-allow-variadic-functions"{{.*}} "-target-sdk-version=10.0"{{.*}} "-include" "__clang_cuda_runtime_wrapper.h" // CHK-ACTIONS-CUDA-COMPAT: "-cc1" "-triple" "x86_64-unknown-linux-gnu"{{.*}} "-fsycl-is-host"{{.*}} "-fsycl-cuda-compatibility"{{.*}} "-fdeclspec"{{.*}} "-fcuda-allow-variadic-functions"{{.*}} "-aux-triple" "nvptx64-nvidia-cuda"{{.*}} "-target-sdk-version=10.0"{{.*}} "-include" "__clang_cuda_runtime_wrapper.h" diff --git a/clang/test/Driver/sycl-offload-old-model.cpp b/clang/test/Driver/sycl-offload-old-model.cpp index 8f23f90d5aea3..ebe46935ea6fe 100644 --- a/clang/test/Driver/sycl-offload-old-model.cpp +++ b/clang/test/Driver/sycl-offload-old-model.cpp @@ -605,7 +605,7 @@ /// Verify that triple-boundarch pairs are correct with multi-targetting // RUN: %clang -target x86_64-unknown-linux-gnu -fsycl --no-offload-new-driver -fno-sycl-instrument-device-code --no-offloadlib \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda,spir64 -ccc-print-phases --cuda-path=%S/Inputs/CUDA_111/usr/local/cuda \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l64-signed_char.libspirv.bc %s 2>&1 \ +// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l64.signed_char.bc %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-PHASE-MULTI-TARG-BOUND-ARCH %s // CHK-PHASE-MULTI-TARG-BOUND-ARCH: 0: input, "[[INPUT:.+\.cpp]]", c++, (host-sycl) // CHK-PHASE-MULTI-TARG-BOUND-ARCH: 1: preprocessor, {0}, c++-cpp-output, (host-sycl) @@ -644,7 +644,7 @@ // RUN: -fno-sycl-instrument-device-code --no-offloadlib \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda,spir64_gen \ // RUN: --cuda-path=%S/Inputs/CUDA_111/usr/local/cuda \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l64-signed_char.libspirv.bc \ +// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l64.signed_char.bc \ // RUN: -Xsycl-target-backend=spir64_gen "-device skl" \ // RUN: -ccc-print-phases %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-PHASE-MULTI-TARG-BOUND-ARCH2 %s @@ -686,7 +686,7 @@ // RUN: %clang -target x86_64-unknown-linux-gnu -fsycl --no-offload-new-driver \ // RUN: -fno-sycl-instrument-device-code --no-offloadlib \ // RUN: --cuda-path=%S/Inputs/CUDA_111/usr/local/cuda \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l64-signed_char.libspirv.bc \ +// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l64.signed_char.bc \ // RUN: -fsycl-targets=spir64,nvptx64-nvidia-cuda -ccc-print-phases %s 2>&1 \ // RUN: | FileCheck -check-prefix=CHK-PHASE-MULTI-TARG-BOUND-ARCH-FLIPPED %s // CHK-PHASE-MULTI-TARG-BOUND-ARCH-FLIPPED: 0: input, "[[INPUT:.+\.cpp]]", c++, (host-sycl) @@ -728,7 +728,7 @@ // RUN: %clang -target x86_64-unknown-linux-gnu -fsycl --no-offload-new-driver \ // RUN: -fno-sycl-instrument-device-code --no-offloadlib \ // RUN: --cuda-path=%S/Inputs/CUDA_111/usr/local/cuda \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l64-signed_char.libspirv.bc \ +// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l64.signed_char.bc \ // RUN: -fsycl-targets=spir64,nvptx64-nvidia-cuda,amdgcn-amd-amdhsa \ // RUN: -Xsycl-target-backend=nvptx64-nvidia-cuda --offload-arch=sm_75 \ // RUN: -Xsycl-target-backend=amdgcn-amd-amdhsa --offload-arch=gfx908 -ccc-print-phases %s 2>&1 \ diff --git a/clang/test/Driver/sycl-offload-static-lib-2-old-model.cpp b/clang/test/Driver/sycl-offload-static-lib-2-old-model.cpp index 6231014b8fe53..8d81a530e35b1 100644 --- a/clang/test/Driver/sycl-offload-static-lib-2-old-model.cpp +++ b/clang/test/Driver/sycl-offload-static-lib-2-old-model.cpp @@ -88,12 +88,12 @@ // RUN: touch %t_lib.a // RUN: %clangxx -target x86_64-unknown-linux-gnu -fno-sycl-instrument-device-code \ // RUN: --cuda-path=%S/Inputs/CUDA_111/usr/local/cuda \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l64-signed_char.libspirv.bc \ +// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l64.signed_char.bc \ // RUN: --no-offloadlib -fsycl --no-offload-new-driver %t_lib.a -ccc-print-phases %s 2>&1 \ // RUN: | FileCheck %s -check-prefix=STATIC_LIB_SRC -DBUNDLE_TRIPLE=sycl-spir64-unknown-unknown // RUN: %clangxx -target x86_64-unknown-linux-gnu -fno-sycl-instrument-device-code --no-offloadlib \ // RUN: --cuda-path=%S/Inputs/CUDA_111/usr/local/cuda \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l64-signed_char.libspirv.bc \ +// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l64.signed_char.bc \ // RUN: -fsycl-targets=nvptx64-nvidia-cuda -fsycl --no-offload-new-driver %t_lib.a -ccc-print-phases %s 2>&1 \ // RUN: | FileCheck %s -check-prefix=STATIC_LIB_SRC-CUDA // STATIC_LIB_SRC: 0: input, "[[INPUTA:.+\.a]]", object, (host-sycl) diff --git a/clang/test/Driver/sycl-oneapi-gpu-nvidia.cpp b/clang/test/Driver/sycl-oneapi-gpu-nvidia.cpp index c5064baf4beea..1665d4253ff8f 100644 --- a/clang/test/Driver/sycl-oneapi-gpu-nvidia.cpp +++ b/clang/test/Driver/sycl-oneapi-gpu-nvidia.cpp @@ -64,7 +64,7 @@ /// Test for proper creation of fat object // RUN: %clangxx -c -fsycl -fno-sycl-libspirv -nocudalib -fsycl-targets=nvidia_gpu_sm_50 \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/libspirv.bc \ +// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/libspirv.l64.signed_char.bc \ // RUN: -target x86_64-unknown-linux-gnu -### %s 2>&1 | \ // RUN: FileCheck %s --check-prefix=NVIDIA_FATO // NVIDIA_FATO: clang-offload-bundler{{.*}} "-type=o" @@ -73,7 +73,7 @@ /// Test for proper consumption of fat object // RUN: touch %t.o // RUN: %clangxx -fsycl -fno-sycl-libspirv -nocudalib -fsycl-targets=nvidia_gpu_sm_50 \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/libspirv.bc \ +// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/libspirv.l64.signed_char.bc \ // RUN: -target x86_64-unknown-linux-gnu -### %t.o 2>&1 | \ // RUN: FileCheck %s --check-prefix=NVIDIA_CONSUME_FAT // NVIDIA_CONSUME_FAT: clang-offload-bundler{{.*}} "-type=o" @@ -84,7 +84,7 @@ /// offload action used for compilation and backend compilation. // RUN: %clangxx -fsycl -fsycl-targets=nvidia_gpu_sm_50 --no-offloadlib \ // RUN: -fno-sycl-instrument-device-code --cuda-path=%S/Inputs/CUDA_111/usr/local/cuda \ -// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/remangled-l64-signed_char.libspirv.bc \ +// RUN: -fsycl-libspirv-path=%S/Inputs/SYCL/lib/clang/resource_dir/lib/nvptx64-nvidia-cuda/libspirv.l64.signed_char.bc \ // RUN: -target x86_64-unknown-linux-gnu -ccc-print-phases %s 2>&1 | \ // RUN: FileCheck %s --check-prefix=NVIDIA_CHECK_PHASES // NVIDIA_CHECK_PHASES: 0: input, "[[INPUT:.+\.cpp]]", c++, (host-sycl) diff --git a/libclc/CMakeLists.txt b/libclc/CMakeLists.txt index 131fc4925d610..f35466a0613dc 100644 --- a/libclc/CMakeLists.txt +++ b/libclc/CMakeLists.txt @@ -135,7 +135,7 @@ if( EXISTS ${LIBCLC_CUSTOM_LLVM_TOOLS_BINARY_DIR} ) # the variable name is used to cache the result of find_program. If we used # the same name, a user wouldn't be able to switch a build between default # and custom tools. - foreach( tool IN ITEMS clang llvm-as llvm-link opt llvm-spirv libclc-remangler ) + foreach( tool IN ITEMS clang llvm-as llvm-link opt llvm-spirv ) find_program( LLVM_CUSTOM_TOOL_${tool} ${tool} PATHS ${LIBCLC_CUSTOM_LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH ) set( ${tool}_exe ${LLVM_CUSTOM_TOOL_${tool}} ) @@ -144,7 +144,7 @@ if( EXISTS ${LIBCLC_CUSTOM_LLVM_TOOLS_BINARY_DIR} ) # If we've requested a custom binary directory, there are some otherwise # optional tools which we want to ensure are present. - foreach( tool IN ITEMS llvm-spirv libclc-remangler ) + foreach( tool IN ITEMS llvm-spirv ) if( NOT EXISTS "${${tool}_exe}" AND "${${tool}_target}" STREQUAL "" ) message( FATAL_ERROR "libclc toolchain incomplete!" ) endif() @@ -197,9 +197,6 @@ if( LIBCLC_USE_SPIRV_BACKEND OR llvm-spirv_exe ) list( APPEND LIBCLC_TARGETS_ALL spirv-mesa3d- spirv64-mesa3d- ) endif() -option( LIBCLC_GENERATE_REMANGLED_VARIANTS - "Generate remangled variants of enabled libclc targets." OFF ) - # Verify that the user hasn't requested mesa3d targets without an available # llvm-spirv tool. if( spirv-mesa3d- IN_LIST LIBCLC_TARGETS_TO_BUILD @@ -245,9 +242,6 @@ endforeach(t) # headers are not $build/include/ which is what LLVM_INCLUDE_DIR is set to. include_directories( ${LLVM_INCLUDE_DIRS} ) -# Configure libclc-remangler tool -add_subdirectory( utils ) - # Setup arch devices set( r600--_devices cedar cypress barts cayman ) set( amdgcn--_devices tahiti ) @@ -470,9 +464,6 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} ) list( APPEND build_flags -mllvm --amdgpu-oclc-reflect-enable=false ) endif() - set( LIBCLC_ARCH_OBJFILE_DIR "${LIBCLC_OBJFILE_DIR}/${arch_suffix}" ) - file( MAKE_DIRECTORY ${LIBCLC_ARCH_OBJFILE_DIR} ) - # Build for OpenCL 3.0 independently of the target or device. list( APPEND build_flags -cl-std=CL3.0 ) @@ -552,11 +543,27 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} ) LIB_FILES ${clc_lib_files} ) - if( BUILD_LIBSPIRV_${t} ) - set( spirv_build_flags ${build_flags} ) - list( APPEND spirv_build_flags - # Enable SPIR-V builtin function declarations, so they don't have to be - # explicity declared in the soruce. + set(opencl_build_flags ${build_flags} + -Xclang -fdeclare-opencl-builtins + -I${CMAKE_CURRENT_SOURCE_DIR}/opencl/include) + + add_libclc_builtin_set( + ARCH ${ARCH} + DEVICE ${d} + ARCH_SUFFIX ${arch_suffix} + TRIPLE ${clang_triple} + COMPILE_FLAGS ${opencl_build_flags} + OPT_FLAGS ${opt_flags} + LIB_FILES ${opencl_lib_files} + ALIASES ${${d}_aliases} + OUTPUT_FILENAME libclc + PARENT_TARGET libclc-opencl-builtins + # Link in the CLC builtins and internalize their symbols + INTERNAL_LINK_DEPENDENCIES builtins.link.clc-${arch_suffix} + ) + + if(BUILD_LIBSPIRV_${t}) + set(spirv_build_flags ${build_flags} -Xclang -fdeclare-spirv-builtins -I${CMAKE_CURRENT_SOURCE_DIR}/libspirv/include/ ) @@ -565,7 +572,6 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} ) ARCH ${ARCH} ARCH_SUFFIX libspirv-${arch_suffix} TRIPLE ${clang_triple} - REMANGLE ${LIBCLC_GENERATE_REMANGLED_VARIANTS} COMPILE_FLAGS ${spirv_build_flags} OPT_FLAGS ${opt_flags} LIB_FILES ${libspirv_lib_files} @@ -575,29 +581,30 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} ) # Link in the CLC builtins and internalize their symbols INTERNAL_LINK_DEPENDENCIES builtins.link.clc-${arch_suffix} ) - endif() - list( APPEND build_flags - -Xclang -fdeclare-opencl-builtins - -I${CMAKE_CURRENT_SOURCE_DIR}/opencl/include - ) - set( opencl_build_flags ${build_flags} ) - - - add_libclc_builtin_set( - ARCH ${ARCH} - DEVICE ${d} - ARCH_SUFFIX ${arch_suffix} - TRIPLE ${clang_triple} - COMPILE_FLAGS ${opencl_build_flags} - OPT_FLAGS ${opt_flags} - LIB_FILES ${opencl_lib_files} - ALIASES ${${d}_aliases} - OUTPUT_FILENAME libclc - PARENT_TARGET libclc-opencl-builtins - # Link in the CLC builtins and internalize their symbols - INTERNAL_LINK_DEPENDENCIES builtins.link.clc-${arch_suffix} - ) + foreach(long_width 32 64) + foreach(char_signedness signed unsigned) + set(spirv_remangle_build_flags ${spirv_build_flags} + -Xclang -fsycl-remangle-libspirv + -mllvm -remangle-long-width=${long_width} + -mllvm -remangle-char-signedness=${char_signedness} + ) + add_libclc_builtin_set( + ARCH ${ARCH} + ARCH_SUFFIX libspirv-${arch_suffix}-${long_width}-${char_signedness} + TRIPLE ${clang_triple} + COMPILE_FLAGS ${spirv_remangle_build_flags} + OPT_FLAGS ${opt_flags} + LIB_FILES ${libspirv_lib_files} + ALIASES ${${d}_aliases} + OUTPUT_FILENAME libspirv.l${long_width}.${char_signedness}_char + PARENT_TARGET libspirv-builtins + # Link in the CLC builtins and internalize their symbols + INTERNAL_LINK_DEPENDENCIES builtins.link.clc-${arch_suffix} + ) + endforeach() + endforeach() + endif() endforeach( d ) endforeach( t ) diff --git a/libclc/cmake/modules/AddLibclc.cmake b/libclc/cmake/modules/AddLibclc.cmake index e2cc8004a5aa5..280b3e9449388 100644 --- a/libclc/cmake/modules/AddLibclc.cmake +++ b/libclc/cmake/modules/AddLibclc.cmake @@ -271,7 +271,7 @@ endfunction() function(add_libclc_builtin_set) cmake_parse_arguments(ARG "CLC_INTERNAL" - "ARCH;DEVICE;TRIPLE;ARCH_SUFFIX;REMANGLE;OUTPUT_FILENAME;PARENT_TARGET" + "ARCH;DEVICE;TRIPLE;ARCH_SUFFIX;OUTPUT_FILENAME;PARENT_TARGET" "LIB_FILES;COMPILE_FLAGS;OPT_FLAGS;ALIASES;INTERNAL_LINK_DEPENDENCIES" ${ARGN} ) @@ -280,6 +280,9 @@ function(add_libclc_builtin_set) message( FATAL_ERROR "Must provide ARCH, ARCH_SUFFIX, and TRIPLE" ) endif() + set( LIBCLC_ARCH_OBJFILE_DIR "${LIBCLC_OBJFILE_DIR}/${ARG_ARCH_SUFFIX}" ) + file( MAKE_DIRECTORY ${LIBCLC_ARCH_OBJFILE_DIR} ) + set( bytecode_files ) set( bytecode_ir_files ) foreach( file IN LISTS ARG_LIB_FILES ) @@ -455,70 +458,6 @@ function(add_libclc_builtin_set) return() endif() - # Generate remangled variants if requested - if( ARG_REMANGLE ) - set( dummy_in ${library_dir}/libclc_dummy_in.cc ) - add_custom_command( OUTPUT ${dummy_in} - COMMAND ${CMAKE_COMMAND} -E touch ${dummy_in} - ) - set(long_widths l32 l64) - set(char_signedness signed unsigned) - - # All permutations of [l32, l64] and [signed, unsigned] - foreach(long_width ${long_widths}) - foreach(signedness ${char_signedness}) - # Remangle - set( remangled_filename remangled-${long_width}-${signedness}_char.${LIBCLC_OUTPUT_FILENAME}.bc ) - set( builtins_remangle_path "${library_dir}/${remangled_filename}" ) - - add_custom_command( OUTPUT "${builtins_remangle_path}" - COMMAND ${libclc-remangler_exe} - -o "${builtins_remangle_path}" - --triple=${ARG_TRIPLE} - --long-width=${long_width} - --char-signedness=${signedness} - --input-ir=${libclc_builtins_lib} - ${dummy_in} - DEPENDS library-${ARG_ARCH_SUFFIX} ${libclc_builtins_lib} ${libclc-remangler_target} ${dummy_in}) - set( remangled_target ${remangled_filename}.${ARG_TRIPLE} ) - add_custom_target( ${remangled_target} ALL - DEPENDS "${builtins_remangle_path}" "${dummy_in}" ) - set_target_properties( ${remangled_target} - PROPERTIES TARGET_FILE "${builtins_remangle_path}" ) - - # Add dependency to top-level pseudo target to ease making other - # targets dependent on libclc. - add_dependencies( ${ARG_PARENT_TARGET} ${remangled_target} ) - - # Keep remangled variants - install( - FILES ${builtins_remangle_path} - DESTINATION ${LIBCLC_INSTALL_DIR}/${ARG_TRIPLE} - COMPONENT ${ARG_PARENT_TARGET} - ) - endforeach() - endforeach() - - # For remangler tests we do not care about long_width, or signedness, as it - # performs no substitutions. - # Collect all remangler tests in libclc-remangler-tests to later add - # dependency against check-libclc. - set(libclc-remangler-tests) - set(libclc-remangler-test-no 0) - foreach(target-ir ${builtins_opt_lib} ${builtins_link_lib} ${libclc_builtins_lib}) - math(EXPR libclc-remangler-test-no "${libclc-remangler-test-no}+1") - set(current-test "libclc-remangler-test-${ARG_ARCH_SUFFIX}-${libclc-remangler-test-no}") - add_custom_target(${current-test} - COMMAND ${libclc-remangler_exe} - --long-width=l32 - --char-signedness=signed - --input-ir=${target-ir} - ${dummy_in} -t -o - - DEPENDS ${libclc_builtins_lib} "${dummy_in}" ${libclc-remangler_target}) - list(APPEND libclc-remangler-tests ${current-test}) - endforeach() - endif() - # Add a test for whether or not the libraries contain unresolved functions # which would usually indicate a build problem. Note that we don't perform # this test for all libclc targets: diff --git a/libclc/libspirv/lib/ptx-nvidiacl/images/image.cl b/libclc/libspirv/lib/ptx-nvidiacl/images/image.cl index b270b4b7dfb03..c26e9f0dcbdb1 100644 --- a/libclc/libspirv/lib/ptx-nvidiacl/images/image.cl +++ b/libclc/libspirv/lib/ptx-nvidiacl/images/image.cl @@ -3788,28 +3788,28 @@ _CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(ushort4, 3, Dv4_t, v4j16, Dv3_f, 3, dX.x, dX.y, dX.z, dY.x, dY.y, dY.z) // Char -_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char, 1, a, i8, f, float coord, +_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char, 1, c, i8, f, float coord, COORD_PARAMS_1D, S2_S2_, , dX, dY) -_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char, 2, a, i8, Dv2_f, float2 coord, +_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char, 2, c, i8, Dv2_f, float2 coord, COORD_PARAMS_2D, S3_S3_, 2, dX.x, dX.y, dY.x, dY.y) -_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char, 3, a, i8, Dv3_f, float3 coord, +_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char, 3, c, i8, Dv3_f, float3 coord, COORD_PARAMS_3D, S3_S3_, 3, dX.x, dX.y, dX.z, dY.x, dY.y, dY.z) -_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char2, 1, Dv2_a, v2i8, f, float coord, +_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char2, 1, Dv2_c, v2i8, f, float coord, COORD_PARAMS_1D, S3_S3_, , dX, dY) -_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char2, 2, Dv2_a, v2i8, Dv2_f, +_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char2, 2, Dv2_c, v2i8, Dv2_f, float2 coord, COORD_PARAMS_2D, S4_S4_, 2, dX.x, dX.y, dY.x, dY.y) -_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char2, 3, Dv2_a, v2i8, Dv3_f, +_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char2, 3, Dv2_c, v2i8, Dv3_f, float3 coord, COORD_PARAMS_3D, S4_S4_, 3, dX.x, dX.y, dX.z, dY.x, dY.y, dY.z) -_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char4, 1, Dv4_a, v4i8, f, float coord, +_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char4, 1, Dv4_c, v4i8, f, float coord, COORD_PARAMS_1D, S3_S3_, , dX, dY) -_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char4, 2, Dv4_a, v4i8, Dv2_f, +_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char4, 2, Dv4_c, v4i8, Dv2_f, float2 coord, COORD_PARAMS_2D, S4_S4_, 2, dX.x, dX.y, dY.x, dY.y) -_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char4, 3, Dv4_a, v4i8, Dv3_f, +_CLC_DEFINE_MIPMAP_BINDLESS_READS_BUILTIN(char4, 3, Dv4_c, v4i8, Dv3_f, float3 coord, COORD_PARAMS_3D, S4_S4_, 3, dX.x, dX.y, dX.z, dY.x, dY.y, dY.z) diff --git a/libclc/test/CMakeLists.txt b/libclc/test/CMakeLists.txt index 8232f7bc17af4..c7916f415eee9 100644 --- a/libclc/test/CMakeLists.txt +++ b/libclc/test/CMakeLists.txt @@ -45,12 +45,4 @@ foreach( t ${LIBCLC_TARGET_TO_TEST} ) ) endforeach( t ) -if(LIBCLC_GENERATE_REMANGLED_VARIANTS) - # Now that check-libclc is defined make sure that all remangler targets depend - # on it. - foreach(remangler-test ${libclc-remangler-tests}) - set_property(GLOBAL APPEND PROPERTY LLVM_LIBCLC_ADDITIONAL_TEST_TARGETS ${remangler-test}) - set_property(GLOBAL APPEND PROPERTY LLVM_ALL_ADDITIONAL_TEST_TARGETS ${remangler-test}) - endforeach() -endif() umbrella_lit_testsuite_end(check-libclc) diff --git a/libclc/utils/CMakeLists.txt b/libclc/utils/CMakeLists.txt deleted file mode 100644 index f612a9516c8f7..0000000000000 --- a/libclc/utils/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -# Setup remangler tool -add_llvm_subdirectory(LIBCLC TOOL libclc-remangler) diff --git a/libclc/utils/libclc-remangler/CMakeLists.txt b/libclc/utils/libclc-remangler/CMakeLists.txt deleted file mode 100644 index c764eed682f06..0000000000000 --- a/libclc/utils/libclc-remangler/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -# Setup libclc-remangler -set(LLVM_LINK_COMPONENTS - BitWriter - BitReader - Core - Demangle - Support - TransformUtils - IRReader - TargetParser - ) - -add_clang_tool(libclc-remangler LibclcRemangler.cpp) - -setup_host_tool( libclc-remangler LIBCLC_REMANGLER - libclc-remangler_exe libclc-remangler_target ) - -target_include_directories(libclc-remangler PRIVATE - ${CMAKE_SOURCE_DIR}/../clang/include - ${CMAKE_BINARY_DIR}/tools/clang/include) - -clang_target_link_libraries(libclc-remangler - PRIVATE - clangAST - clangBasic - clangFrontend - clangTooling - clangSerialization - LLVMOption - ) diff --git a/libclc/utils/libclc-remangler/LibclcRemangler.cpp b/libclc/utils/libclc-remangler/LibclcRemangler.cpp deleted file mode 100644 index 6979b2fbddd12..0000000000000 --- a/libclc/utils/libclc-remangler/LibclcRemangler.cpp +++ /dev/null @@ -1,1090 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements a tool for ensuring consistent mangling between libclc -// and the target. This tool remangles all functions using `long`, -// `unsigned long`, and `char` to appear as if they use `long long`, -// `unsigned long long`, and `signed char`, as is consistent with the primitive -// types defined by OpenCL C. Following a remangling, the original function -// mangling will be built as a clone of either the remangled function or a -// function with a suitable function if any exists. In some cases a clone of -// the remangled function is created for functions where multiple parameters -// have been replaced, and the replaced values are aliases. -// -// Original Clone Example: -// If libclc defined a function `f(long)` the mangled name would be -// `_Z1fl`. The remangler would rename this function to `_Z1fx` -// (`f(long long)`.) If the target uses 64-bit `long`, `_Z1fl` is -// cloned from the old function now under the name `_Z1fx`, whereas if -// the target uses 32-bit `long`, `_Z1fl` is cloned from `_Z1fi` -// (`f(int)`) if such a function exists. -// -// Remangled Clone Example: -// In cases where the remangled name squashes valid versions of a -// function a clone is created. `f(long, char, signed char)` would be -// mangled to `_Z1flca`. The remangler would rename this function to -// `_Z1fxaa` (`f(long long, signed char, signed char)`). If the target -// uses a signed char then a valid clone `_Z1fxca`, (`f(long long, -// char, signed char)`), is not defined. The remangler creates a clone -// of the renamed function,`_Z1fxaa`, to this permutation, `_Z1fxca`. -// -// Remangled Pointer Address Space Example: -// If libclc defined a function `f(int *)`, the mangled name is -// `_Z1fPU3AS4i` for a target when generic address space is 4. The -// remangler would rename this function to `_Z1fPi`, to be -// consistent with SYCL device code mangling for the target. If libclc -// defined a function `f(private int *)`, the mangled name is -// `_Z1fPi` when default address space is private. The remangler would -// rename it to `_Z1fPU3AS0i`. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/Mangle.h" -#include "clang/AST/NestedNameSpecifier.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Tooling/CommonOptionsParser.h" -#include "clang/Tooling/Tooling.h" -#include "llvm/Bitcode/BitcodeReader.h" -#include "llvm/Bitcode/BitcodeWriter.h" -#include "llvm/Demangle/ItaniumDemangle.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DiagnosticInfo.h" -#include "llvm/IR/DiagnosticPrinter.h" -#include "llvm/IRReader/IRReader.h" -#include "llvm/Support/ToolOutputFile.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Transforms/Utils/ValueMapper.h" - -#include - -using namespace clang; -using namespace clang::tooling; -using namespace llvm; -using namespace llvm::itanium_demangle; - -enum class Signedness { Signed, Unsigned }; -enum class SupportedLongWidth { L32, L64 }; - -static ExitOnError ExitOnErr; - -static StringRef TmpSuffix = ".tmp"; - -// Apply a custom category to all command-line options so that they are the -// only ones displayed. -static llvm::cl::OptionCategory - LibCLCRemanglerToolCategory("libclc-remangler-tool options"); - -static cl::opt - InputIRFilename("input-ir", cl::desc(""), - cl::cat(LibCLCRemanglerToolCategory)); -static cl::opt OutputFilename("o", cl::init("-"), - cl::desc("Output filename")); -static cl::opt TargetTriple("triple", cl::init(""), - cl::desc("Device target triple")); -static cl::opt - LongWidth("long-width", - cl::values(clEnumValN(SupportedLongWidth::L32, "l32", - "long is 32-bit wide."), - clEnumValN(SupportedLongWidth::L64, "l64", - "long is 64-bit wide.")), - cl::cat(LibCLCRemanglerToolCategory)); -static cl::opt CharSignedness( - "char-signedness", - cl::values(clEnumValN(Signedness::Signed, "signed", "char is signed."), - clEnumValN(Signedness::Unsigned, "unsigned", - "char is unsigned.")), - cl::cat(LibCLCRemanglerToolCategory)); -static cl::opt Verbose("v", cl::desc("Enable verbose output"), - cl::init(false), - cl::cat(LibCLCRemanglerToolCategory)); -static cl::opt TextualOut("S", cl::desc("Emit LLVM textual assembly"), - cl::init(false), - cl::cat(LibCLCRemanglerToolCategory)); -static cl::opt TestRun("t", cl::desc("Enable test run"), cl::init(false), - cl::cat(LibCLCRemanglerToolCategory)); - -// CommonOptionsParser declares HelpMessage with a description of the common -// command-line options related to the compilation database and input files. -// It's nice to have this help message in all tools. -static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); - -namespace { -inline StringRef asRef(std::string_view S) { return {&*S.begin(), S.size()}; } -class BumpPointerAllocator { -public: - BumpPointerAllocator() - : BlockList(new(InitialBuffer) BlockMeta{nullptr, 0}) {} - BumpPointerAllocator(const BumpPointerAllocator &) = delete; - BumpPointerAllocator &operator=(const BumpPointerAllocator &) = delete; - - void *allocate(size_t N) { - N = (N + 15u) & ~15u; - if (N + BlockList->Current >= UsableAllocSize) { - if (N > UsableAllocSize) - return allocateMassive(N); - grow(); - } - BlockList->Current += N; - return static_cast(reinterpret_cast(BlockList + 1) + - BlockList->Current - N); - } - - void reset() { - while (BlockList) { - BlockMeta *Tmp = BlockList; - BlockList = BlockList->Next; - if (reinterpret_cast(Tmp) != InitialBuffer) - std::free(Tmp); - } - BlockList = new (InitialBuffer) BlockMeta{nullptr, 0}; - } - - ~BumpPointerAllocator() { reset(); } - -private: - void grow() { - char *NewMeta = static_cast(std::malloc(AllocSize)); - if (NewMeta == nullptr) - std::terminate(); - BlockList = new (NewMeta) BlockMeta{BlockList, 0}; - } - - void *allocateMassive(size_t NBytes) { - NBytes += sizeof(BlockMeta); - BlockMeta *NewMeta = reinterpret_cast(std::malloc(NBytes)); - if (NewMeta == nullptr) - std::terminate(); - BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0}; - return static_cast(NewMeta + 1); - } - -private: - struct BlockMeta { - BlockMeta *Next; - size_t Current; - }; - - static constexpr size_t AllocSize = 4096; - static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta); - - alignas(max_align_t) char InitialBuffer[AllocSize]; - BlockMeta *BlockList = nullptr; -}; - -class DefaultAllocator { -public: - void reset() { Alloc.reset(); } - - template T *makeNode(Args &&...A) { - return new (Alloc.allocate(sizeof(T))) T(std::forward(A)...); - } - - void *allocateNodeArray(size_t Sz) { - return Alloc.allocate(sizeof(itanium_demangle::Node *) * Sz); - } - -private: - BumpPointerAllocator Alloc; -}; - -clang::QualType getBaseType(StringRef Name, clang::ASTContext *AST, - bool &IsVariadic) { - clang::QualType Res; - // First find the match against `QualType`... - if (Name == "void") - Res = AST->VoidTy; - else if (Name == "wchar_t") - Res = AST->WCharTy; - else if (Name == "bool") - Res = AST->BoolTy; - else if (Name == "char") - Res = AST->CharTy; - else if (Name == "signed char") - Res = AST->SignedCharTy; - else if (Name == "unsigned char") - Res = AST->UnsignedCharTy; - else if (Name == "short") - Res = AST->ShortTy; - else if (Name == "unsigned short") - Res = AST->UnsignedShortTy; - else if (Name == "int") - Res = AST->IntTy; - else if (Name == "unsigned int") - Res = AST->UnsignedIntTy; - else if (Name == "long") - Res = AST->LongTy; - else if (Name == "unsigned long") - Res = AST->UnsignedLongTy; - else if (Name == "long long") - Res = AST->LongLongTy; - else if (Name == "unsigned long long") - Res = AST->UnsignedLongLongTy; - else if (Name == "__int128") - Res = AST->Int128Ty; - else if (Name == "unsigned __int128") - Res = AST->UnsignedInt128Ty; - else if (Name == "float") - Res = AST->FloatTy; - else if (Name == "double") - Res = AST->DoubleTy; - else if (Name == "long double") - Res = AST->LongDoubleTy; - else if (Name == "__float128") - Res = AST->Float128Ty; - else if (Name == "...") { - Res = clang::QualType{}; - IsVariadic = true; - } else if (Name == "decimal64") - assert(false && "unhandled type name: decimal64"); - else if (Name == "decimal128") - assert(false && "unhandled type name: decimal128"); - else if (Name == "decimal32") - assert(false && "unhandled type name: decimal32"); - else if (Name == "decimal16") - assert(false && "unhandled type name: decimal16"); - else if (Name == "char32_t") - Res = AST->Char32Ty; - else if (Name == "char16_t") - Res = AST->Char16Ty; - else if (Name == "char8_t") - Res = AST->Char8Ty; - else if (Name == "_Float16") - Res = AST->Float16Ty; - else if (Name == "half") - Res = AST->HalfTy; - else if (Name == "auto") - Res = AST->AutoDeductTy; - else if (Name == "decltype(auto)") - assert(false && "unhandled type name: decltype(auto)"); - else if (Name == "std::nullptr_t") - Res = AST->NullPtrTy; - else if (Name == "_BitInt") - assert(false && "unhandled type name: _BitInt"); - else { - auto &II = AST->Idents.get(Name); - auto *DC = AST->getTranslationUnitDecl(); - auto *ED = EnumDecl::Create(*AST, DC, SourceLocation(), SourceLocation(), - &II, nullptr, false, false, true); - Res = AST->getCanonicalTagType(ED); - } - return Res; -} -} // unnamed namespace - -using Demangler = ManglingParser; - -class Remangler { -public: - Remangler(ASTContext *AST, const Node *Root, - const SmallDenseMap &TypeReplacements) - : AST(AST), Root(Root), TypeReplacements(TypeReplacements) { - MangleContext.reset( - ItaniumMangleContext::create(*AST, AST->getDiagnostics())); - TargetDefaultAddrSpace = AST->getTargetAddressSpace(LangAS::Default); - } - - bool hasFailed() { return Failed; } - - // Generate mangled function name, based on a given itanium_demangle `Node`. - std::string remangle() { - clang::QualType RetTy; - SmallVector TemplateArgTys; - SmallVector InputArgTys; - bool IsVariadic = false; - nodeToQualTypes(RetTy, TemplateArgTys, InputArgTys, IsVariadic); - auto *FD = createKernelDecl(RetTy, TemplateArgTys, InputArgTys, IsVariadic); - assert(MangleContext->shouldMangleDeclName(FD) && - "It should always be possible to mangle libclc func."); - - std::string Buf; - raw_string_ostream Out(Buf); - MangleContext->mangleName(FD, Out); - return Buf; - } - -private: - // Helper struct to aggregate information about types. - struct NodeKindInfo { - NodeKindInfo(Node::Kind K) : K(K) {} - NodeKindInfo(Node::Kind K, size_t NumElemsOrAS) : K(K) { - Data = NumElemsOrAS; - } - NodeKindInfo(Node::Kind K, itanium_demangle::Qualifiers Quals) : K(K) { - Data = 0; - if (Quals & itanium_demangle::Qualifiers::QualConst) - Data |= clang::Qualifiers::TQ::Const; - if (Quals & itanium_demangle::Qualifiers::QualVolatile) - Data |= clang::Qualifiers::TQ::Volatile; - if (Quals & itanium_demangle::Qualifiers::QualRestrict) - Data |= clang::Qualifiers::TQ::Restrict; - } - NodeKindInfo(Node::Kind K, const char *S, size_t N) : K(K) { - DataStr.assign(S, N); - } - Node::Kind K; - size_t Data = 0; - std::string DataStr; - }; - - // Construct FunctionDecl from return, argument and template types. - FunctionDecl *createKernelDecl( - clang::QualType RetTy, const SmallVector &TemplateArgTys, - const SmallVector &InputArgTys, bool IsVariadic) { - // Copy in InputArgTys as this function can mutate them. - auto ArgTys{InputArgTys}; - // Create this with a void ret no args prototype, will be fixed up after - // we've seen all the params. - FunctionProtoType::ExtProtoInfo Info(CC_DeviceKernel); - Info.Variadic = IsVariadic; - clang::QualType const VoidFuncType = - AST->getFunctionType(AST->VoidTy, {}, Info); - FunctionDecl *FD = FunctionDecl::Create( - *AST, AST->getTranslationUnitDecl(), SourceLocation{}, - DeclarationNameInfo(), VoidFuncType, - AST->getTrivialTypeSourceInfo(AST->VoidTy), SC_None, false, false, - false, ConstexprSpecKind::Unspecified,/*TrailingRequiresClause=*/{}); - FD->setImplicitlyInline(false); - - // Set the name. - const auto *Encoding = static_cast(Root); - assert( - (Encoding->getName()->getKind() == Node::Kind::KNameType || - Encoding->getName()->getKind() == Node::Kind::KNameWithTemplateArgs) && - "Expected KNameType or KNameWithTemplateArgs node."); - StringRef KernelName; - if (Encoding->getName()->getKind() == Node::Kind::KNameType) { - auto *NT = static_cast(Encoding->getName()); - KernelName = asRef(NT->getBaseName()); - } else { - auto *NT = static_cast(Encoding->getName()); - KernelName = asRef(NT->getBaseName()); - } - FD->setDeclName(&AST->Idents.get(KernelName)); - - // Construct the argument list. - SmallVector ArgParams; - for (auto &QT : ArgTys) { - auto &II = AST->Idents.get(""); - auto *TTSI = AST->getTrivialTypeSourceInfo(QT); - auto *NewParam = - ParmVarDecl::Create(*AST, FD, SourceLocation(), SourceLocation(), &II, - QT, TTSI, SC_None, nullptr); - NewParam->setScopeInfo(0, ArgParams.size()); - NewParam->setDeclContext(FD); - ArgParams.push_back(NewParam); - } - - // If not templated, finish here. - if (TemplateArgTys.empty()) { - clang::QualType const FuncType = - AST->getFunctionType(RetTy, ArgTys, Info); - FD->setType(FuncType); - FD->setParams(ArgParams); - return FD; - } - - // Use FD as a base for a future function specialisation. - FunctionDecl *FDSpecialization = FunctionDecl::Create( - *AST, AST->getTranslationUnitDecl(), SourceLocation{}, - DeclarationNameInfo(), VoidFuncType, - AST->getTrivialTypeSourceInfo(AST->VoidTy), SC_None, false, false, - false, ConstexprSpecKind::Unspecified,/*TrailingRequiresClause=*/{}); - FDSpecialization->setImplicitlyInline(false); - - FDSpecialization->setDeclName(&AST->Idents.get(KernelName)); - - // Will be used to build template parameter list. - SmallVector TemplateNamedDecls; - // Used for setting template specialisation. - SmallVector TemplateArguments; - // Used for the fixups. - SmallVector TemplateTypeParamTys; - unsigned TemplateIndex = 0; - for (auto &TemplateArgQT : TemplateArgTys) { - std::string const Name{std::string{"TempTy"} + - std::to_string(TemplateIndex)}; - auto &II = AST->Idents.get(Name); - auto *TTPD = TemplateTypeParmDecl::Create( - *AST, FDSpecialization->getDeclContext(), SourceLocation(), - SourceLocation(), 0, TemplateIndex, &II, /* Typename */ true, - /*ParameterPack*/ false); - TTPD->setDefaultArgument(*AST, - TemplateArgumentLoc()); - - TemplateNamedDecls.emplace_back(TTPD); - auto TA = TemplateArgument(TemplateArgQT); - TemplateArguments.emplace_back(TA); - - // Store this qualified type with newly created proper template type - // param qualified type. - TemplateTypeParamTys.push_back( - AST->getTemplateTypeParmType(0, TemplateIndex, false, TTPD)); - - ++TemplateIndex; - } - // Fix up the template types in the original FD's arg tys and return ty. - auto AreQTsEqual = [&](const clang::QualType &LHS, - const clang::QualType &RHS) -> bool { - auto *LID = LHS.getBaseTypeIdentifier(); - auto *RID = RHS.getBaseTypeIdentifier(); - return (RID && LID && LID->isStr(RID->getName())) || LHS == RHS; - }; - unsigned NumReplaced = 0; - unsigned Idx = 0; - for (auto &TemplateArgQT : TemplateArgTys) { - if (AreQTsEqual(TemplateArgQT, RetTy)) { - RetTy = TemplateTypeParamTys[Idx]; - goto Found; - } - for (unsigned i = 0; i < ArgTys.size(); ++i) { - if (AreQTsEqual(ArgTys[i], TemplateArgQT)) { - ArgTys[i] = TemplateTypeParamTys[Idx]; - goto Found; - } - } - Found: - ++NumReplaced; - ++Idx; - } - assert(NumReplaced >= TemplateTypeParamTys.size() && - "Expected full specialization."); - // Now that the template types have been patched up, set functions type. - clang::QualType const TemplateFuncType = - AST->getFunctionType(RetTy, ArgTys, Info); - FD->setType(TemplateFuncType); - FD->setParams(ArgParams); - FDSpecialization->setType(TemplateFuncType); - FDSpecialization->setParams(ArgParams); - - auto *TPL = TemplateParameterList::Create( - *AST, SourceLocation(), SourceLocation(), TemplateNamedDecls, - SourceLocation(), nullptr); - auto *FTD = FunctionTemplateDecl::Create(*AST, FD->getDeclContext(), - SourceLocation(), - DeclarationName(), TPL, FD); - auto TAArr = ArrayRef(TemplateArguments.begin(), TemplateArguments.size()); - auto *TAL = TemplateArgumentList::CreateCopy(*AST, TAArr); - FDSpecialization->setTemplateParameterListsInfo(*AST, TPL); - FDSpecialization->setFunctionTemplateSpecialization( - FTD, TAL, nullptr, TSK_ExplicitSpecialization); - - return FDSpecialization; - } - - // Peel off additional type info, such as CV qualifiers or pointers, by - // recursively calling itself. The information is appended to `PossibleKinds` - // vector. - // The base case is achieved in `handleLeafTypeNode`. - std::pair - handleTypeNode(const Node *TypeNode, - SmallVector &PossibleKinds) { - auto Kind = TypeNode->getKind(); - switch (Kind) { - case Node::Kind::KPointerType: { - PossibleKinds.push_back(NodeKindInfo(Kind)); - const auto *PType = - static_cast(TypeNode); - return handleTypeNode(PType->getPointee(), PossibleKinds); - } - case Node::Kind::KVectorType: { - const auto *VecType = - static_cast(TypeNode); - assert(VecType->getDimension()->getKind() == Node::Kind::KNameType); - const auto *Dims = static_cast( - VecType->getDimension()); - size_t DimNum; - if (asRef(Dims->getName()).getAsInteger(10, DimNum) || !DimNum) { - assert(false && "invalid vector size specifier"); - break; - } - PossibleKinds.push_back(NodeKindInfo(Kind, DimNum)); - return handleTypeNode(VecType->getBaseType(), PossibleKinds); - } - case Node::Kind::KBinaryFPType: { - const itanium_demangle::BinaryFPType *BFPType = - static_cast(TypeNode); - assert(BFPType->getDimension()->getKind() == Node::Kind::KNameType); - const auto *NameTypeNode = - static_cast( - BFPType->getDimension()); - assert(asRef(NameTypeNode->getBaseName()) == "16" && - "Unexpected binary floating point type."); - // BinaryFPType is encoded as: BinaryFPType(NameType("16")), manually - // construct "_Float16" NamedType node so we can pass it directly to - // handleLeafTypeNode. - NameType const FP16{"_Float16"}; - return handleLeafTypeNode(FP16.getName(), PossibleKinds); - } - case Node::Kind::KVendorExtQualType: { - const auto *ExtQualType = - static_cast(TypeNode); - StringRef AS = asRef(ExtQualType->getExt()); - if (!AS.starts_with("AS")) { - assert(false && "Unexpected ExtQualType."); - break; - } - size_t ASNum; - if (AS.drop_front(2).getAsInteger(10, ASNum)) { - assert(false && "Unexpected ExtQualType."); - break; - } - PossibleKinds.push_back({Kind, ASNum}); - return handleTypeNode(ExtQualType->getTy(), PossibleKinds); - } - case Node::Kind::KQualType: { - auto *QType = static_cast(TypeNode); - PossibleKinds.push_back({Kind, QType->getQuals()}); - return handleTypeNode(QType->getChild(), PossibleKinds); - } - case Node::Kind::KNameType: { - auto *NT = static_cast(TypeNode); - return handleLeafTypeNode(NT->getName(), PossibleKinds); - } - case Node::Kind::KNestedName: { - const auto *NN = - static_cast(TypeNode); - OutputBuffer QB; - NN->Qual->print(QB); - PossibleKinds.push_back({Kind, QB.getBuffer(), QB.getCurrentPosition()}); - auto *NT = static_cast(NN->Name); - return handleLeafTypeNode(NT->getName(), PossibleKinds); - } - default: { - OutputBuffer ErrorTypeOut; - TypeNode->print(ErrorTypeOut); - errs() << "Unhandled type: " << ErrorTypeOut.getBuffer() << "\n"; - free(ErrorTypeOut.getBuffer()); - Failed = true; - } - } - - llvm_unreachable("Unhandled type."); - return std::make_pair(clang::QualType{}, false); - } - - // Handle undecorated type that can be matched against `QualType`, also - // returning if variadic. - std::pair - handleLeafTypeNode(std::string_view Name, - SmallVector &PossibleKinds) { - return handleLeafTypeNode(asRef(Name), PossibleKinds); - } - - std::pair - handleLeafTypeNode(StringRef Name, SmallVector &PossibleKinds) { - - // When in test run, don't enable replacements and assert that re-mangled - // name matches the original. - if (!TestRun) { - auto It = TypeReplacements.find(Name.begin()); - if (It != TypeReplacements.end()) - Name = It->second; - } - - bool IsVariadic = false; - clang::QualType Res = getBaseType(Name, AST, IsVariadic); - - // then apply gathered information to that `QualType`. - - // Handle `KNestedName` first, as it will create a new `QualType`. - auto KNNMatcher = [](NodeKindInfo &NKI) { - return NKI.K == Node::Kind::KNestedName; - }; - auto *KNN = - std::find_if(PossibleKinds.begin(), PossibleKinds.end(), KNNMatcher); - if (KNN != PossibleKinds.end()) { - assert(PossibleKinds.end() == std::find_if(std::next(KNN), - PossibleKinds.end(), - KNNMatcher) && - "Expected only one KNestedName kind."); - - // Construct the full name to check if it has already been handled. - std::string const N{KNN->DataStr + " " + - Res.getBaseTypeIdentifier()->getName().str()}; - if (NestedNamesQTMap.count(N) == 0) { - assert(StringRef(KNN->DataStr).starts_with("__spv") && - "Unexpected nested prefix"); - SourceLocation const SL{}; - RecordDecl *RD = nullptr; - if (!SpvNamespace) - SpvNamespace = NamespaceDecl::Create( - *AST, AST->getTranslationUnitDecl(), false, SL, SL, - &AST->Idents.get("__spv", tok::TokenKind::identifier), nullptr, - false); - std::string StructName = - StringRef(KNN->DataStr).split("__spv::").second.str(); - auto *II = &AST->Idents.get(StructName, tok::TokenKind::identifier); - RD = RecordDecl::Create(*AST, TagTypeKind::Struct, SpvNamespace, SL, SL, II); - NestedNameSpecifier NNS = - NestedNameSpecifier(*AST, SpvNamespace, /*Prefix=*/std::nullopt); - auto RecordQT = AST->getCanonicalTagType(RD); - NNS = NestedNameSpecifier(RecordQT->getTypePtr()); - auto &EnumName = - AST->Idents.get(Res.getBaseTypeIdentifier()->getName()); - // We need to recreate the enum, now that we have access to all the - // namespace/class info. - auto *ED = - EnumDecl::Create(*AST, RD, SourceLocation(), SourceLocation(), - &EnumName, nullptr, false, false, true); - Res = AST->getCanonicalTagType(ED); - Res = AST->getTagType(ElaboratedTypeKeyword::None, NNS, ED, - /*OwnsTag=*/false); - // Store the elaborated type for reuse, this is important as clang uses - // substitutions for ET based on the object not the name enclosed in. - NestedNamesQTMap[N] = Res; - } else - Res = NestedNamesQTMap[N]; - } - - // Iterate in reversed order to preserve the semantics. - for (auto I = PossibleKinds.rbegin(); I != PossibleKinds.rend(); ++I) { - switch (I->K) { - case Node::Kind::KPointerType: { - if (TargetDefaultAddrSpace != 0) { - if (Res.hasAddressSpace() && - toTargetAddressSpace(Res.getAddressSpace()) == - TargetDefaultAddrSpace) - Res = AST->removeAddrSpaceQualType(Res); - else if (!Res.hasAddressSpace()) - Res = AST->getAddrSpaceQualType(Res, LangAS::opencl_private); - } - Res = AST->getPointerType(Res); - break; - } - case Node::Kind::KVectorType: { - Res = AST->getVectorType(Res, I->Data, - clang::VectorKind::Generic); - break; - } - case Node::Kind::KQualType: { - auto Quals = clang::Qualifiers::fromFastMask(I->Data); - Res = AST->getQualifiedType(Res, Quals); - break; - } - case Node::Kind::KVendorExtQualType: { - auto AS = getLangASFromTargetAS(I->Data); - Res = AST->getAddrSpaceQualType(Res, AS); - break; - } - case Node::Kind::KNestedName: { - // Handled already. - break; - } - default: { - llvm_unreachable("Unexpected Node Kind."); - } - } - } - - return std::make_pair(Res, IsVariadic); - } - - // Traverse the itanium_demangle node and generate QualTypes corresponding to - // the function's return type, input arguments and template params. - void nodeToQualTypes(clang::QualType &RetTy, - SmallVector &TemplateArgTys, - SmallVector &ArgTys, bool &IsVariadic) { - const FunctionEncoding *Encoding = - static_cast(Root); - - SmallVector PossibleKinds; - if (Encoding->getReturnType()) { - RetTy = - std::get<0>(handleTypeNode(Encoding->getReturnType(), PossibleKinds)); - } else - RetTy = AST->VoidTy; - - if (Encoding->getName()->getKind() == Node::Kind::KNameWithTemplateArgs) { - const NameWithTemplateArgs *NWTA = - static_cast(Encoding->getName()); - assert(NWTA->getKind() == Node::Kind::KNameWithTemplateArgs); - const TemplateArgs *TA = - static_cast(NWTA->TemplateArgs); - for (auto *TPT : TA->getParams()) { - PossibleKinds.clear(); - auto Res = handleTypeNode(TPT, PossibleKinds); - assert(!std::get<1>(Res) && "Variadic in template params."); - TemplateArgTys.push_back(std::get<0>(Res)); - } - } - - for (auto *PT : Encoding->getParams()) { - PossibleKinds.clear(); - auto Res = handleTypeNode(PT, PossibleKinds); - if (std::get<1>(Res)) { - IsVariadic = true; - continue; - } - ArgTys.push_back(std::get<0>(Res)); - } - } - -private: - ASTContext *AST = nullptr; - std::unique_ptr MangleContext{}; - const Node *Root = nullptr; - const SmallDenseMap &TypeReplacements; - - bool Failed = false; - - std::map NestedNamesQTMap{}; - NamespaceDecl *SpvNamespace = nullptr; - - unsigned TargetDefaultAddrSpace; -}; - -class TargetTypeReplacements { - SmallDenseMap ParameterTypeReplacements; - SmallDenseMap CloneTypeReplacements; - SmallDenseMap RemangledCloneTypeReplacements; - - void createRemangledTypeReplacements() { - // RemangleTypes which are not aliases or not the exact same alias - // type - for (auto &PTR : ParameterTypeReplacements) { - const char *From = PTR.getFirst(); - const char *To = PTR.getSecond(); - if (CloneTypeReplacements.find(From) == CloneTypeReplacements.end()) - RemangledCloneTypeReplacements[From] = To; - else if (CloneTypeReplacements[From] != To) - RemangledCloneTypeReplacements[From] = To; - } - // Replace char with signed char - RemangledCloneTypeReplacements["char"] = "signed char"; - } - -public: - TargetTypeReplacements() { - // Replace long with long long - ParameterTypeReplacements["long"] = "long long"; - ParameterTypeReplacements["unsigned long"] = "unsigned long long"; - - // Replace char with signed char - ParameterTypeReplacements["char"] = "signed char"; - - // Make replaced long functions clones of either integer or long - // long variant - if (LongWidth == SupportedLongWidth::L32) { - CloneTypeReplacements["long"] = "int"; - CloneTypeReplacements["unsigned long"] = "unsigned int"; - } else { - CloneTypeReplacements["long"] = "long long"; - CloneTypeReplacements["unsigned long"] = "unsigned long long"; - } - - // Make replaced char functions clones of explicit signed char or unsigned - // char type - if (CharSignedness == Signedness::Signed) { - CloneTypeReplacements["char"] = "signed char"; - } else { - CloneTypeReplacements["char"] = "unsigned char"; - } - - ParameterTypeReplacements["half"] = "_Float16"; - - createRemangledTypeReplacements(); - } - - const SmallDenseMap & - getParameterTypeReplacements() const { - return ParameterTypeReplacements; - } - - const SmallDenseMap & - getCloneTypeReplacements() const { - return CloneTypeReplacements; - } - - const SmallDenseMap & - getRemangledCloneTypeReplacements() const { - return RemangledCloneTypeReplacements; - } -}; - -class LibCLCRemangler : public ASTConsumer { -public: - LibCLCRemangler() : ASTCtx(nullptr), LLVMCtx(), Replacements() {} - - void Initialize(ASTContext &C) override { - ASTCtx = &C; - std::unique_ptr const Buff = ExitOnErr( - errorOrToExpected(MemoryBuffer::getFileOrSTDIN(InputIRFilename))); - - SMDiagnostic Err; - std::unique_ptr const M = - parseIR(Buff.get()->getMemBufferRef(), Err, LLVMCtx); - - if (!M) { - Err.print("libclc-remangler", errs()); - exit(1); - } - - handleModule(M.get()); - } - -private: - bool createClones(llvm::Module *M, StringRef OriginalMangledName, - std::string RemangledName, - const itanium_demangle::Node *FunctionTree, - TargetTypeReplacements &Replacements) { - // create clone of original function - if (!createCloneFromMap(M, OriginalMangledName, FunctionTree, - Replacements.getCloneTypeReplacements(), - /* CloneeTypeReplacement= */ true)) - return false; - - // create clone of remangled function - return createCloneFromMap(M, RemangledName, FunctionTree, - Replacements.getRemangledCloneTypeReplacements()); - } - - bool createCloneFromMap( - llvm::Module *M, StringRef OriginalName, - const itanium_demangle::Node *FunctionTree, - const SmallDenseMap &TypeReplacements, - bool CloneeTypeReplacement = false) { - Remangler ATR{ASTCtx, FunctionTree, TypeReplacements}; - - std::string RemangledName = ATR.remangle(); - - if (ATR.hasFailed()) - return false; - - // Name has not changed from the original name. - if (RemangledName == OriginalName) - return true; - - std::string CloneName; - StringRef CloneeName; - if (CloneeTypeReplacement) { - CloneName = OriginalName; - CloneeName = RemangledName; - } else { - CloneName = std::move(RemangledName); - CloneeName = OriginalName; - } - - // If the clone name is an original function in the module, it may later be - // remangled and must be replaced. Example (TargetDefaultAddrSpace != 0): - // _Z1fPm -> remangled to _Z1fPU3AS0y; remangler clones back to _Z1fPm to - // preserve the original. Later, _Z1fPU3AS4m -> remangled to _Z1fPy; we need - // to clone _Z1fPy to _Z1fPm, but it already exists. To avoid a clash, - // append a temporary suffix (e.g., _Z1fPm$TmpSuffix). The suffix is removed - // in post-processing, and the old Z1fPm (clone of _Z1fPU3AS0y) is replaced - // by Z1fPm$TmpSuffix. - if (M->getFunction(CloneName)) { - CloneName += TmpSuffix; - if (M->getFunction(CloneName)) - return true; - } - - if (Function *Clonee = M->getFunction(CloneeName)) { - ValueToValueMapTy Dummy; - Function *NewF = CloneFunction(Clonee, Dummy); - NewF->setName(CloneName); - } else if (Verbose) { - errs() << "Could not create copy " << CloneName << " : missing " - << CloneeName.data() << '\n'; - } - return true; - } - - bool remangleFunction(Function &Func, llvm::Module *M) { - if (Func.hasLocalLinkage()) - return true; - - if (!Func.getName().starts_with("_Z")) - return true; - - std::string const MangledName = Func.getName().str(); - Demangler D{MangledName.data(), MangledName.data() + MangledName.size()}; - const itanium_demangle::Node *FunctionTree = D.parse(); - if (!FunctionTree) { - errs() << "Unable to demangle name: " << MangledName << '\n'; - return false; - } - - // Try to change the parameter types in the function name using the - // mappings. - Remangler R{ASTCtx, FunctionTree, - Replacements.getParameterTypeReplacements()}; - - std::string RemangledName = R.remangle(); - - if (R.hasFailed()) - return false; - - if (RemangledName != MangledName) { - RenamedFunctions.insert(MangledName); - if (Verbose || TestRun) { - errs() << "Mangling changed:" - << "\n" - << "Original: " << MangledName << "\n" - << "New: " << RemangledName << "\n"; - } - // In test run mode, where no substitution is made, change in mangling - // name represents a failure. Report an error. - if (TestRun) { - errs() << "Test run failure!\n"; - return false; - } - - // When TargetDefaultAddrSpace is not 0, there is a possibility that - // RemangledName may already exist. For instance, the function name - // _Z1fPU3AS4i would be remangled to _Z1fPi, which is a valid variant and - // might already be present. Since we cannot alter the name of an existing - // variant function that may not have been processed yet (it will become a - // clone of the original function), we append a temporary suffix to - // RemangledName to prevent a name clash. This temporary suffix will be - // removed eventually and Old _Z1fPi will be replaced by _Z1fPi$TmpSuffix. - if (M->getFunction(RemangledName)) - RemangledName += TmpSuffix; - - // If the remangled name already exists in the module then we have to - // assume it does the right thing already. We're only going to end up - // creating a copy of that function without external users being able to - // reach it. - if (M->getFunction(RemangledName)) { - return true; - } - - Func.setName(RemangledName); - - // Make a clone of a suitable function using the old name if there is a - // type-mapping and the corresponding clonee function exists. - if (!createClones(M, MangledName, RemangledName, FunctionTree, - Replacements)) - return false; - } - return true; - } - - // The temporary suffix is removed from the remangled or cloned name. - void postProcessRemoveTmpSuffix(llvm::Module *M) { - if (TestRun) - return; - std::vector ToErase; - for (auto &F : make_early_inc_range(*M)) { - StringRef Name = F.getName(); - if (!Name.consume_back(TmpSuffix)) - continue; - if (auto *Func = M->getFunction(Name)) { - if (RenamedFunctions.count(Name.str())) { - // Drop unuseful clone of the original or remangled function. - Func->replaceAllUsesWith(ConstantPointerNull::get(Func->getType())); - Func->setName(""); - ToErase.push_back(Func); - } else { - // Name doesn't exist in the original module. Drop unuseful clone of - // remangled function. - F.eraseFromParent(); - continue; - } - } - // Complete the mangling process, e.g. from _Z1fPU3AS4i to _Z1fPi. - F.setName(Name); - } - for (auto *F : ToErase) - F->eraseFromParent(); - } - - void handleModule(llvm::Module *M) { - std::error_code EC; - std::unique_ptr Out( - new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None)); - if (EC) { - errs() << EC.message() << '\n'; - exit(1); - } - - // This module is built explicitly for linking with any .bc compiled with - // the "nvptx64-nvidia-cuda" (CUDA) or "amdgcn-amd-amdhsa" (HIP AMD) - // triples. Therefore we update the module triple. - if (M->getTargetTriple().str() == "nvptx64-unknown-nvidiacl") { - M->setTargetTriple(Triple("nvptx64-nvidia-cuda")); - } else if (M->getTargetTriple().str() == "amdgcn-unknown-amdhsa") { - M->setTargetTriple(Triple("amdgcn-amd-amdhsa")); - } - - std::vector FuncList; - for (auto &Func : M->getFunctionList()) - FuncList.push_back(&Func); - - bool Success = true; - for (auto *Func : FuncList) - Success &= remangleFunction(*Func, M); - postProcessRemoveTmpSuffix(M); - // Only fail after all to give as much context as possible. - if (!Success) { - errs() << "Failed to remangle all mangled functions in module.\n"; - exit(1); - } - - if (TestRun) { - if (Verbose) - errs() << "Successfully processed: " << FuncList.size() - << " functions.\n"; - return; - } - - if (TextualOut) - M->print(Out->os(), nullptr, true); - else - WriteBitcodeToFile(*M, Out->os()); - - // Declare success. - Out->keep(); - } - -private: - ASTContext *ASTCtx; - LLVMContext LLVMCtx; - TargetTypeReplacements Replacements; - // Functions in the input module that have been renamed due to remangling. - std::unordered_set RenamedFunctions; -}; - -class LibCLCRemanglerActionFactory { -public: - LibCLCRemanglerActionFactory() {} - - std::unique_ptr newASTConsumer() { - return std::make_unique(); - } -}; - -int main(int argc, const char **argv) { - auto ExpectedParser = CommonOptionsParser::create( - argc, argv, LibCLCRemanglerToolCategory, cl::ZeroOrMore); - if (!ExpectedParser) { - // Fail gracefully for unsupported options. - errs() << ExpectedParser.takeError(); - return 1; - } - - // Use a default Compilation DB instead of the build one, as it might contain - // toolchain specific options, not compatible with clang. - // Configure the triple to ensure that clang correctly sets up TargetInfo - // which is essential for querying the target address space. This allows the - // remangler to have the same target address space mapping as the mangling - // performed in the SYCL device code compilation. - std::vector CommandLine; - CommandLine.push_back("-cc1"); - CommandLine.push_back("-triple"); - CommandLine.push_back(TargetTriple); - // Workaround error: unknown argument -resource-dir=, which isn't a CC1Option. - CommandLine.push_back("-resource-dir"); - CommandLine.push_back("."); - FixedCompilationDatabase Compilations(".", CommandLine); - ClangTool Tool(Compilations, ExpectedParser->getSourcePathList()); - - LibCLCRemanglerActionFactory LRAF{}; - std::unique_ptr FrontendFactory; - FrontendFactory = newFrontendActionFactory(&LRAF); - return Tool.run(FrontendFactory.get()); -} diff --git a/llvm/include/llvm/SYCLLowerIR/MangleUtils.h b/llvm/include/llvm/SYCLLowerIR/MangleUtils.h new file mode 100644 index 0000000000000..aa0a09928ffcc --- /dev/null +++ b/llvm/include/llvm/SYCLLowerIR/MangleUtils.h @@ -0,0 +1,163 @@ +//===- MangleUtils.h - SPIR mangling helpers for SYCL -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Contains code derived from SPIRV-LLVM Translator. License available at: +// https://github.com/KhronosGroup/SPIRV-LLVM-Translator/blob/main/LICENSE.TXT +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYCLLOWERIR_MANGLEUTILS_H +#define LLVM_SYCLLOWERIR_MANGLEUTILS_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { + +namespace SPIR { + +static constexpr unsigned ADDRESS_SPACE_GENERIC = ~0u; + +enum TypePrimitiveEnum { + PRIMITIVE_BOOL, + PRIMITIVE_SCHAR, + PRIMITIVE_UCHAR, + PRIMITIVE_CHAR, + PRIMITIVE_USHORT, + PRIMITIVE_SHORT, + PRIMITIVE_UINT, + PRIMITIVE_INT, + PRIMITIVE_ULONG, + PRIMITIVE_LONG, + PRIMITIVE_ULONGLONG, + PRIMITIVE_LONGLONG, + PRIMITIVE_FLOAT16, + PRIMITIVE_HALF, + PRIMITIVE_FLOAT, + PRIMITIVE_DOUBLE, + PRIMITIVE_VOID, + PRIMITIVE_NUM +}; + +enum TypeEnum { + TYPE_ID_PRIMITIVE, + TYPE_ID_POINTER, + TYPE_ID_VECTOR, + TYPE_ID_TEMPLATE_PARAMETER, + TYPE_ID_STRUCTURE +}; + +enum TypeAttributeEnum { ATTR_RESTRICT, ATTR_VOLATILE, ATTR_CONST }; + +struct TypeVisitor; +struct PrimitiveType; +struct VectorType; +struct PointerType; +struct TemplateParameterType; +struct UserDefinedType; + +struct ParamType : public RefCountedBase { + ParamType(TypeEnum TypeId) : TypeId(TypeId) {} + virtual ~ParamType() {} + virtual void accept(TypeVisitor *) const = 0; + TypeEnum getTypeId() const { return TypeId; } + +protected: + TypeEnum TypeId; +}; + +typedef IntrusiveRefCntPtr RefParamType; + +template +struct ParamTypeBase : public ParamType { + ParamTypeBase() : ParamType(EnumVal) {} + + static bool classof(const ParamType *P) { return P->getTypeId() == EnumVal; } +}; + +struct PrimitiveType : public ParamTypeBase { + PrimitiveType(TypePrimitiveEnum P) : Primitive(P) {} + void accept(TypeVisitor *Visitor) const override; + TypePrimitiveEnum getPrimitive() const { return Primitive; } + +private: + TypePrimitiveEnum Primitive; +}; + +struct PointerType : public ParamTypeBase { + PointerType(const RefParamType Type) : PType(Type) { + Qualifiers[0] = Qualifiers[1] = Qualifiers[2] = false; + } + void accept(TypeVisitor *Visitor) const override; + const RefParamType &getPointee() const { return PType; } + void setAddressSpace(unsigned AS) { AddressSpace = AS; } + unsigned getAddressSpace() const { return AddressSpace; } + void setQualifier(TypeAttributeEnum Qual, bool Enabled); + bool hasQualifier(TypeAttributeEnum Qual) const; + +private: + RefParamType PType; + bool Qualifiers[3]; + unsigned AddressSpace = ADDRESS_SPACE_GENERIC; +}; + +struct VectorType : public ParamTypeBase { + VectorType(const RefParamType Type, int Len) : PType(Type), Len(Len) {} + void accept(TypeVisitor *Visitor) const override; + const RefParamType &getScalarType() const { return PType; } + int getLength() const { return Len; } + +private: + RefParamType PType; + int Len; +}; + +struct TemplateParameterType + : public ParamTypeBase { + TemplateParameterType(unsigned Index) : Index(Index) {} + void accept(TypeVisitor *Visitor) const override; + unsigned getIndex() const { return Index; } + +private: + unsigned Index; +}; + +struct UserDefinedType + : public ParamTypeBase { + UserDefinedType(StringRef Name) : Name(Name) {} + void accept(TypeVisitor *Visitor) const override; + StringRef getName() const { return Name; } + +private: + SmallString<32> Name; +}; + +struct TypeVisitor { + virtual ~TypeVisitor() {} + virtual void visit(const PrimitiveType *) = 0; + virtual void visit(const VectorType *) = 0; + virtual void visit(const PointerType *) = 0; + virtual void visit(const TemplateParameterType *) = 0; + virtual void visit(const UserDefinedType *) = 0; +}; + +class NameMangler { +public: + void mangleTemplateName(StringRef Name, ArrayRef TemplateArgs, + SmallVectorImpl &MangledName); + + void mangle(StringRef Name, ArrayRef Params, + SmallVectorImpl &MangledName); +}; + +} // namespace SPIR + +} // namespace llvm + +#endif // LLVM_SYCLLOWERIR_MANGLEUTILS_H diff --git a/llvm/include/llvm/SYCLLowerIR/SYCLRemangleLibspirv.h b/llvm/include/llvm/SYCLLowerIR/SYCLRemangleLibspirv.h new file mode 100644 index 0000000000000..c3b917dcac75b --- /dev/null +++ b/llvm/include/llvm/SYCLLowerIR/SYCLRemangleLibspirv.h @@ -0,0 +1,28 @@ +//===- SYCLRemangleLibspirv.h - Remangle libspirv builtins for SYCL -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Remangles __spirv_* builtin functions in libspirv to provide mangled +// variants for both OpenCL C and SYCL type representations, allowing +// SYCL device code to link libspirv. + +#ifndef LLVM_SYCLLOWERIR_SYCLREMANGLELIBSPIRV_H +#define LLVM_SYCLLOWERIR_SYCLREMANGLELIBSPIRV_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class SYCLRemangleLibspirvPass + : public PassInfoMixin { +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); +}; + +} // namespace llvm + +#endif // LLVM_SYCLLOWERIR_SYCLREMANGLELIBSPIRV_H diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 6cbae99f58479..d67c8ab807a2c 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -204,6 +204,7 @@ #include "llvm/SYCLLowerIR/SYCLOptimizeBarriers.h" #include "llvm/SYCLLowerIR/SYCLPropagateAspectsUsage.h" #include "llvm/SYCLLowerIR/SYCLPropagateJointMatrixUsage.h" +#include "llvm/SYCLLowerIR/SYCLRemangleLibspirv.h" #include "llvm/SYCLLowerIR/SYCLVirtualFunctionsAnalysis.h" #include "llvm/SYCLLowerIR/SpecConstants.h" #include "llvm/Support/CodeGen.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 42751c3b0f53d..cfcddf1c1ec36 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -197,6 +197,7 @@ MODULE_PASS("sycl-propagate-aspects-usage", SYCLPropagateAspectsUsagePass()) MODULE_PASS("sycl-propagate-joint-matrix-usage", SYCLPropagateJointMatrixUsagePass()) MODULE_PASS("sycl-add-opt-level-attribute", SYCLAddOptLevelAttributePass()) MODULE_PASS("compile-time-properties", CompileTimePropertiesPass()) +MODULE_PASS("sycl-remangle-libspirv", SYCLRemangleLibspirvPass()) MODULE_PASS("cleanup-sycl-metadata", CleanupSYCLMetadataPass()) MODULE_PASS("sycl-create-nvvm-annotations", SYCLCreateNVVMAnnotationsPass()) MODULE_PASS("lower-slm-reservation-calls", ESIMDLowerSLMReservationCalls()) diff --git a/llvm/lib/SYCLLowerIR/CMakeLists.txt b/llvm/lib/SYCLLowerIR/CMakeLists.txt index 020e4c378b1c2..bb9f28c57814a 100644 --- a/llvm/lib/SYCLLowerIR/CMakeLists.txt +++ b/llvm/lib/SYCLLowerIR/CMakeLists.txt @@ -42,6 +42,7 @@ add_llvm_component_library(LLVMSYCLLowerIR LowerInvokeSimd.cpp LowerWGLocalMemory.cpp LowerWGScope.cpp + MangleUtils.cpp MutatePrintfAddrspace.cpp SpecConstants.cpp SYCLAddOptLevelAttribute.cpp @@ -54,6 +55,7 @@ add_llvm_component_library(LLVMSYCLLowerIR SYCLOptimizeBarriers.cpp SYCLPropagateAspectsUsage.cpp SYCLPropagateJointMatrixUsage.cpp + SYCLRemangleLibspirv.cpp SYCLVirtualFunctionsAnalysis.cpp SYCLUtils.cpp diff --git a/llvm/lib/SYCLLowerIR/MangleUtils.cpp b/llvm/lib/SYCLLowerIR/MangleUtils.cpp new file mode 100644 index 0000000000000..7b9d5704844f6 --- /dev/null +++ b/llvm/lib/SYCLLowerIR/MangleUtils.cpp @@ -0,0 +1,293 @@ +//===- MangleUtils.cpp - SPIR mangling helpers for SYCL -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Contains code derived from SPIRV-LLVM Translator. License available at: +// https://github.com/KhronosGroup/SPIRV-LLVM-Translator/blob/main/LICENSE.TXT +// +//===----------------------------------------------------------------------===// + +#include "llvm/SYCLLowerIR/MangleUtils.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::SPIR; + +namespace { + +// Mangling utilities. +// clang-format off +#define PRIMITIVE_TYPES_MAP(X) \ + X(PRIMITIVE_BOOL, "b") \ + X(PRIMITIVE_SCHAR, "a") \ + X(PRIMITIVE_UCHAR, "h") \ + X(PRIMITIVE_CHAR, "c") \ + X(PRIMITIVE_USHORT, "t") \ + X(PRIMITIVE_SHORT, "s") \ + X(PRIMITIVE_UINT, "j") \ + X(PRIMITIVE_INT, "i") \ + X(PRIMITIVE_ULONG, "m") \ + X(PRIMITIVE_LONG, "l") \ + X(PRIMITIVE_ULONGLONG, "y") \ + X(PRIMITIVE_LONGLONG, "x") \ + X(PRIMITIVE_FLOAT16, "DF16_") \ + X(PRIMITIVE_HALF, "Dh") \ + X(PRIMITIVE_FLOAT, "f") \ + X(PRIMITIVE_DOUBLE, "d") \ + X(PRIMITIVE_VOID, "v") +// clang-format on + +StringRef mangledPrimitiveString(TypePrimitiveEnum T) { + switch (T) { +#define TYPE_ENUM_CASE(Enum, Mangled) \ + case Enum: \ + return Mangled; + PRIMITIVE_TYPES_MAP(TYPE_ENUM_CASE) +#undef TYPE_ENUM_CASE + default: + return {}; + } +} + +#undef PRIMITIVE_TYPES_MAP + +void appendTemplateParameterMangling(unsigned Index, raw_ostream &Stream) { + Stream << 'T'; + if (Index > 0) + Stream << (Index - 1); + Stream << '_'; +} + +SmallString<8> getLeafTypeMangling(const ParamType *Type) { + if (const auto *Prim = dyn_cast(Type)) { + SmallString<8> Buffer; + Buffer += mangledPrimitiveString(Prim->getPrimitive()); + return Buffer; + } + if (const auto *TemplateParam = dyn_cast(Type)) { + SmallString<8> Buffer; + raw_svector_ostream Stream(Buffer); + appendTemplateParameterMangling(TemplateParam->getIndex(), Stream); + return Buffer; + } + return {}; +} + +SmallString<5> getMangledAddressSpace(unsigned AS) { + if (AS == ADDRESS_SPACE_GENERIC) + return {}; + SmallString<5> ASStr{"U"}; + raw_svector_ostream ASStrStream(ASStr); + if (AS < 10) + ASStrStream << "3"; // size of "ASx" + else + ASStrStream << (2 + NumDigitsBase10(AS)); // size of "ASxx...." + ASStrStream << "AS" << AS; + return ASStr; +} + +} // anonymous namespace + +void PrimitiveType::accept(TypeVisitor *Visitor) const { + return Visitor->visit(this); +} + +void PointerType::accept(TypeVisitor *Visitor) const { + return Visitor->visit(this); +} + +void PointerType::setQualifier(TypeAttributeEnum Qual, bool Enabled) { + if (Qual == ATTR_RESTRICT) + Qualifiers[0] = Enabled; + else if (Qual == ATTR_VOLATILE) + Qualifiers[1] = Enabled; + else if (Qual == ATTR_CONST) + Qualifiers[2] = Enabled; +} + +bool PointerType::hasQualifier(TypeAttributeEnum Qual) const { + if (Qual == ATTR_RESTRICT) + return Qualifiers[0]; + if (Qual == ATTR_VOLATILE) + return Qualifiers[1]; + if (Qual == ATTR_CONST) + return Qualifiers[2]; + return false; +} + +void VectorType::accept(TypeVisitor *Visitor) const { + return Visitor->visit(this); +} + +void TemplateParameterType::accept(TypeVisitor *Visitor) const { + return Visitor->visit(this); +} + +void UserDefinedType::accept(TypeVisitor *Visitor) const { + return Visitor->visit(this); +} + +class MangleVisitor : public TypeVisitor { +public: + MangleVisitor(SmallVectorImpl &Buffer, raw_ostream &Stream, + unsigned InitialSeqId = 0) + : Buffer(Buffer), Stream(Stream), SeqId(InitialSeqId) {} + + void visit(const PrimitiveType *T) override { + Stream << mangledPrimitiveString(T->getPrimitive()); + } + + void visit(const PointerType *P) override { + size_t Pos = Buffer.size(); + SmallString<8> AttrMangling = getPointerAttributesManglingWithMode(P); + SmallString<8> PtrTypePrefix("P"); + PtrTypePrefix += AttrMangling; + if (!mangleSubstitution(P, PtrTypePrefix)) { + Stream << PtrTypePrefix; + P->getPointee()->accept(static_cast(this)); + if (!AttrMangling.empty()) + recordSubstitution(currentBuffer().substr(Pos + 1)); + recordSubstitution(currentBuffer().substr(Pos)); + } + } + + void visit(const VectorType *V) override { + size_t Index = Buffer.size(); + SmallString<16> TypeStorage; + raw_svector_ostream TypeStream(TypeStorage); + TypeStream << "Dv" << V->getLength() << '_'; + StringRef TypeStr(TypeStorage); + if (!mangleSubstitution(V, TypeStr)) { + Stream << TypeStr; + V->getScalarType()->accept(this); + recordSubstitution(currentBuffer().substr(Index)); + } + } + + void visit(const TemplateParameterType *T) override { + appendTemplateParameterMangling(T->getIndex(), Stream); + } + + void visit(const UserDefinedType *U) override { + size_t Index = Buffer.size(); + StringRef Name = U->getName(); + if (!mangleSubstitution(U, Name)) { + Stream << Name.size() << Name; + recordSubstitution(currentBuffer().substr(Index)); + } + } + +private: + StringRef currentBuffer() const { + return StringRef(Buffer.data(), Buffer.size()); + } + + SmallString<8> getPointerAttributesManglingWithMode(const PointerType *P) { + SmallString<8> QualStr; + // Handle address space. + QualStr += getMangledAddressSpace(P->getAddressSpace()); + // Handle qualifiers. + if (P->hasQualifier(ATTR_RESTRICT)) + QualStr += 'r'; + if (P->hasQualifier(ATTR_VOLATILE)) + QualStr += 'V'; + if (P->hasQualifier(ATTR_CONST)) + QualStr += 'K'; + return QualStr; + } + + void mangleSequenceID(unsigned SeqID) { + if (SeqID == 1) + Stream << '0'; + else if (SeqID > 1) { + SmallString<8> Bstr; + constexpr StringRef Charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + SeqID--; + for (; SeqID != 0; SeqID /= 36) + Bstr.push_back(Charset[SeqID % 36]); + for (char C : llvm::reverse(Bstr)) + Stream << C; + } + Stream << '_'; + } + + bool mangleSubstitution(const ParamType *Type, StringRef TypeStr) { + if (currentBuffer().find(TypeStr) == StringRef::npos) + return false; + + SmallString<32> ThisTypeStr(TypeStr); + if (const auto *P = dyn_cast(Type)) { + ThisTypeStr += getPointeeMangling(P->getPointee()); + } else if (const VectorType *PVec = dyn_cast(Type)) { + SmallString<8> NType = getLeafTypeMangling(PVec->getScalarType().get()); + if (!NType.empty()) + ThisTypeStr += NType; + } + auto It = Substitutions.find(StringRef(ThisTypeStr)); + if (It == Substitutions.end()) + return false; + + unsigned SeqID = It->getValue(); + Stream << 'S'; + mangleSequenceID(SeqID); + return true; + } + + SmallString<32> getPointeeMangling(RefParamType Pointee) { + // Generates a simplified mangling of the pointee type for substitution + // matching, without recursive substitutions. + SmallString<32> Mangling; + raw_svector_ostream ManglingStream(Mangling); + + while (const auto *P = dyn_cast(Pointee.get())) { + ManglingStream << 'P' << getPointerAttributesManglingWithMode(P); + Pointee = P->getPointee(); + } + + if (const auto *U = dyn_cast(Pointee.get())) { + StringRef Name = U->getName(); + ManglingStream << Name.size() << Name; + } else { + SmallString<8> LeafMangling = getLeafTypeMangling(Pointee.get()); + if (!LeafMangling.empty()) + ManglingStream << LeafMangling; + } + return Mangling; + } + void recordSubstitution(StringRef Str) { Substitutions[Str] = SeqId++; } + + SmallVectorImpl &Buffer; + raw_ostream &Stream; + unsigned SeqId; + StringMap Substitutions; +}; + +void NameMangler::mangleTemplateName(StringRef Name, + ArrayRef TemplateArgs, + SmallVectorImpl &MangledName) { + MangledName.clear(); + raw_svector_ostream Stream(MangledName); + Stream << "_Z" << Name.size() << Name; + if (!TemplateArgs.empty()) { + Stream << 'I'; + MangleVisitor Visitor(MangledName, Stream, 1); + for (const auto &TemplateArg : TemplateArgs) + TemplateArg->accept(&Visitor); + Stream << 'E'; + } +} + +void NameMangler::mangle(StringRef Name, ArrayRef Params, + SmallVectorImpl &MangledName) { + MangledName.clear(); + raw_svector_ostream Stream(MangledName); + Stream << "_Z" << Name.size() << Name; + MangleVisitor Visitor(MangledName, Stream, 0); + for (const auto &P : Params) + P->accept(&Visitor); +} diff --git a/llvm/lib/SYCLLowerIR/SYCLRemangleLibspirv.cpp b/llvm/lib/SYCLLowerIR/SYCLRemangleLibspirv.cpp new file mode 100644 index 0000000000000..4ce9bc9502abd --- /dev/null +++ b/llvm/lib/SYCLLowerIR/SYCLRemangleLibspirv.cpp @@ -0,0 +1,796 @@ +//===- SYCLRemangleLibspirv.cpp - Remangle libspirv builtins for SYCL -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a pass that remangles __spirv_* builtin functions to +// provide multiple SYCL mangled variants for different type representations. +// It ensures consistent mangling between libspirv and the target. +// +// Three-Map Transformation: +// For each function the pass applies three type maps in sequence: +// +// - Rename (Parameter type replacements): +// Rename the function. char -> signed char (always), half -> _Float16, +// long -> long long, unsigned long -> unsigned long long. +// +// - CloneOriginal (Clone type replacements): +// After Rename, the original OpenCL-mangled name no longer exists. +// CloneOriginal recreates it so callers using OpenCL type names still link. +// Clone source is found by applying CloneOriginal's map to original name: +// char -> signed char (signed) / unsigned char (unsigned), +// long -> int (L32) or long long (L64), +// unsigned long -> unsigned int (L32) or unsigned long long (L64). +// +// - CloneRemangled (Remangled clone type replacements): +// When Rename renames a function with multiple parameters, it may absorb +// valid permutations of the remangled name. For example, +// `f(long long, char, signed char)` (`_Z1fxca`) is absorbed by +// `_Z1fxaa` after Rename renames `f(long, char, signed char)`. +// CloneRemangled creates these missing permutations by cloning the +// Rename-renamed function. It covers entries where Rename and +// CloneOriginal differ: +// char -> signed char, half -> _Float16, +// long -> long long (L32 only), +// unsigned long -> unsigned long long (L32 only). +// +// Remangled Pointer Address Space Example: +// If libspirv defines a function `f(int *)`, the mangled name is +// `_Z1fPU3AS4i` for a target when generic address space is 4. It is renamed +// to `_Z1fPi`, to be consistent with SYCL mangling. If libspirv defines a +// function `f(private int *)`, the mangled name is `_Z1fPi` when default +// address space is private. The pass renames it to `_Z1fPU3AS0i`. +// +// Type Remappings: +// +// 1. long <-> long long (64-bit platforms) +// OpenCL C defines only "long" (always 64-bit). SYCL has both "long" and +// "long long" (both 64-bit on 64-bit platforms). The pass creates both +// variants to support calls using either type. +// +// Rename: +// _Z17__spirv_ocl_s_absl -> _Z17__spirv_ocl_s_absx +// (long) -> (long long) +// +// CloneOriginal (clone, L64): +// _Z17__spirv_ocl_s_absx -> _Z17__spirv_ocl_s_absl +// (long long) -> (long) +// +// 2. char <-> signed char (when char is signed on host) +// OpenCL C uses "char" for signed 8-bit. SYCL distinguishes "char" and +// "signed char". When host char is signed (e.g., x86), both variants are +// created with the same IR type but different mangling. +// +// Rename: +// _Z17__spirv_ocl_s_absc -> _Z17__spirv_ocl_s_absa +// (char) -> (signed char) +// +// CloneOriginal (clone, signed): +// _Z17__spirv_ocl_s_absa -> _Z17__spirv_ocl_s_absc +// (signed char) -> (char) +// +// 2a. char <-> unsigned char (when char is unsigned on host) +// When host char is unsigned (e.g., ARM, PowerPC, RISCV), the pass maps +// 'char' to 'unsigned char' to match the host's char signedness. +// +// Rename: +// _Z15__spirv_ocl_clzc -> _Z15__spirv_ocl_clza +// (char) -> (signed char) +// +// CloneOriginal (clone, unsigned): +// _Z15__spirv_ocl_clzh -> _Z15__spirv_ocl_clzc +// (unsigned char) -> (char) +// +// 3. half -> _Float16 +// SYCL uses _Float16 vendor extension. OpenCL C uses the 'half' type. +// The pass renames 'half' functions to '_Float16'. No back-clone is created +// since there is no CloneOriginal entry for 'half'. +// +// Rename: +// _Z16__spirv_ocl_fabsDh -> _Z16__spirv_ocl_fabsDF16_ +// (half) -> (_Float16) +// +// 4. long <-> int (32-bit platforms only) +// On 32-bit platforms and Windows (LLP64), 'long' is 32-bit. +// Rename still maps long to long long (see section 1). +// CloneOriginal additionally clones from 'int' to recreate the 'long' +// variant. +// +// Rename: +// _Z17__spirv_ocl_s_absl -> _Z17__spirv_ocl_s_absx +// (long) -> (long long) +// +// CloneOriginal (clone, L32): +// _Z17__spirv_ocl_s_absi -> _Z17__spirv_ocl_s_absl +// (int) -> (long) +// +// 5. Vector Types +// Vector transformations apply element-type transformations recursively. +// +// Example: _Z16__spirv_ocl_fabsDv16_Dh -> _Z16__spirv_ocl_fabsDv16_DF16_ +// (vector) -> (vector<_Float16, 16>) +// +// The implementation includes: +// 1. SPIR type system +// 2. SPIR name mangler for generating mangled names with transformed types +// 3. Bridge from itanium_demangle::Node to SPIR::ParamType +// 4. Type transformation logic for target-specific mappings +// 5. Function cloning with temporary suffix collision handling +// +//===----------------------------------------------------------------------===// + +#include "llvm/SYCLLowerIR/SYCLRemangleLibspirv.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Demangle/ItaniumDemangle.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" +#include "llvm/SYCLLowerIR/MangleUtils.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" +#include "llvm/Transforms/Utils/Cloning.h" + +using namespace llvm; + +#define DEBUG_TYPE "sycl-remangle-libspirv" + +static cl::opt RemangleSPIRVTarget( + "remangle-spirv-target", + cl::desc( + "Enable SYCL builtin remangling for SPIR/SPIRV targets " + "(default: false, as these targets already have correct mangling)"), + cl::init(false)); + +static cl::opt + LongWidth("remangle-long-width", + cl::desc("Width of long type in bits (default: 64)"), + cl::init(64)); + +enum class Signedness { Signed, Unsigned }; + +static cl::opt CharSignedness( + "remangle-char-signedness", + cl::values(clEnumValN(Signedness::Signed, "signed", "char is signed."), + clEnumValN(Signedness::Unsigned, "unsigned", + "char is unsigned."))); + +static constexpr StringRef TmpSuffix = ".tmp"; + +namespace { + +//===----------------------------------------------------------------------===// +// Extended from SPIR Type System (adapted from SPIRV-LLVM-Translator Mangler). +//===----------------------------------------------------------------------===// + +// Transformation mode for type replacements. +enum class TransformMode { + // Rename: rename OpenCL C types to SYCL types. + // char -> signed char (always), half -> _Float16 + // long -> long long, unsigned long -> unsigned long long + Rename, + + // CloneOriginal: find clonee source for creating back-clones. + // char -> signed char (signed target) or unsigned char (unsigned target) + // long -> int (L32) or long long (L64) + // unsigned long -> unsigned int (L32) or unsigned long long (L64) + // (half, _Float16, signed char, unsigned char: no transformation) + CloneOriginal, + + // CloneRemangled: find target for second clone. Derived from Rename entries + // where Rename[k] != CloneOriginal[k], plus + // char -> signed char. + // char -> signed char (always), half -> _Float16 + // long -> long long (L32 only; L64: no entry, stays as long) + // unsigned long -> unsigned long long (L32 only; L64: no entry) + CloneRemangled, +}; + +using namespace llvm::itanium_demangle; + +// Bridge itanium_demangle::Node to SPIR::ParamType. +class NodeToSPIRType { + bool IsSPIRV = false; + TransformMode Mode; + +public: + NodeToSPIRType(const Triple &TT, TransformMode Mode) : Mode(Mode) { + IsSPIRV = TT.isSPIR() || TT.isSPIRV(); + } + + SPIR::RefParamType convert(const Node *N) { + if (!N) + return SPIR::RefParamType(); + + switch (N->getKind()) { + case Node::KNameType: + return convertNameType(static_cast(N)); + case Node::KPointerType: + return convertPointerType( + static_cast(N)); + case Node::KVectorType: + return convertVectorType( + static_cast(N)); + case Node::KQualType: + return convert(static_cast(N)->getChild()); + case Node::KTemplateParamQualifiedArg: + return convertTemplateParamQualifiedArg( + static_cast(N)); + case Node::KSyntheticTemplateParamName: + return convertSyntheticTemplateParamName( + static_cast(N)); + case Node::KForwardTemplateReference: + return convertForwardTemplateReference( + static_cast(N)); + case Node::KVendorExtQualType: + return convertVendorExtQualType( + static_cast(N)); + case Node::KBinaryFPType: + return SPIR::RefParamType( + new SPIR::PrimitiveType(SPIR::PRIMITIVE_FLOAT16)); + default: + return SPIR::RefParamType(); + } + } + +private: + SPIR::RefParamType + convertTemplateParamQualifiedArg(const TemplateParamQualifiedArg *TPQA) { + const Node *Arg = nullptr; + TPQA->match([&](Node *, Node *ArgNode) { Arg = ArgNode; }); + return convert(Arg); + } + + SPIR::RefParamType + convertSyntheticTemplateParamName(const SyntheticTemplateParamName *TPN) { + TemplateParamKind Kind = TemplateParamKind::Type; + unsigned Index = 0; + TPN->match([&](TemplateParamKind K, unsigned I) { + Kind = K; + Index = I; + }); + if (Kind != TemplateParamKind::Type) + return SPIR::RefParamType(); + return SPIR::RefParamType(new SPIR::TemplateParameterType(Index)); + } + + SPIR::RefParamType + convertForwardTemplateReference(const ForwardTemplateReference *FTR) { + if (FTR->Ref) + return convert(FTR->Ref); + return SPIR::RefParamType(new SPIR::TemplateParameterType(FTR->Index)); + } + + // Convert a demangled type name to SPIR type representation. + // Primitive types are handled explicitly for type transformation. All other + // types (images, events, samplers, pipes, user structs) become + // UserDefinedType and pass through unchanged. + SPIR::RefParamType convertNameType(const NameType *NT) { + StringRef Name(NT->getName()); + SPIR::TypePrimitiveEnum Prim = SPIR::PRIMITIVE_INT; + + if (Name == "bool") + Prim = SPIR::PRIMITIVE_BOOL; + else if (Name == "char") { + if (Mode == TransformMode::Rename || + Mode == TransformMode::CloneRemangled) { + // Rename and CloneRemangled: always char -> signed char. + Prim = SPIR::PRIMITIVE_SCHAR; + } else { + // CloneOriginal. + Prim = (CharSignedness == Signedness::Signed) ? SPIR::PRIMITIVE_SCHAR + : SPIR::PRIMITIVE_UCHAR; + } + } else if (Name == "signed char") + Prim = SPIR::PRIMITIVE_SCHAR; + else if (Name == "unsigned char") + Prim = SPIR::PRIMITIVE_UCHAR; + else if (Name == "short") + Prim = SPIR::PRIMITIVE_SHORT; + else if (Name == "unsigned short") + Prim = SPIR::PRIMITIVE_USHORT; + else if (Name == "int") + Prim = SPIR::PRIMITIVE_INT; + else if (Name == "unsigned int") + Prim = SPIR::PRIMITIVE_UINT; + else if (Name == "long") { + if (Mode == TransformMode::Rename) { + // Rename: long -> long long (always). + Prim = SPIR::PRIMITIVE_LONGLONG; + } else if (Mode == TransformMode::CloneOriginal) { + // CloneOriginal: long -> int (L32) or long long (L64). + Prim = + (LongWidth == 32) ? SPIR::PRIMITIVE_INT : SPIR::PRIMITIVE_LONGLONG; + } else { + // CloneRemangled: long -> long long (L32); stays as long on L64. + Prim = + (LongWidth == 32) ? SPIR::PRIMITIVE_LONGLONG : SPIR::PRIMITIVE_LONG; + } + } else if (Name == "unsigned long") { + if (Mode == TransformMode::Rename) { + // Rename: unsigned long -> unsigned long long (always). + Prim = SPIR::PRIMITIVE_ULONGLONG; + } else if (Mode == TransformMode::CloneOriginal) { + // CloneOriginal: unsigned long -> unsigned int (L32) or ull (L64). + Prim = (LongWidth == 32) ? SPIR::PRIMITIVE_UINT + : SPIR::PRIMITIVE_ULONGLONG; + } else { + // CloneRemangled: unsigned long -> ull (L32); stays as ulong on L64. + Prim = (LongWidth == 32) ? SPIR::PRIMITIVE_ULONGLONG + : SPIR::PRIMITIVE_ULONG; + } + } else if (Name == "long long") + Prim = SPIR::PRIMITIVE_LONGLONG; + else if (Name == "unsigned long long") + Prim = SPIR::PRIMITIVE_ULONGLONG; + else if (Name == "_Float16") + Prim = SPIR::PRIMITIVE_FLOAT16; + else if (Name == "half") { + if (Mode == TransformMode::Rename || + Mode == TransformMode::CloneRemangled) { + // Rename and CloneRemangled: half -> _Float16. + Prim = SPIR::PRIMITIVE_FLOAT16; + } else { + // CloneOriginal: stays as half. + Prim = SPIR::PRIMITIVE_HALF; + } + } else if (Name == "float") + Prim = SPIR::PRIMITIVE_FLOAT; + else if (Name == "double") + Prim = SPIR::PRIMITIVE_DOUBLE; + else if (Name == "void") + Prim = SPIR::PRIMITIVE_VOID; + else + return SPIR::RefParamType(new SPIR::UserDefinedType(Name)); + + return SPIR::RefParamType(new SPIR::PrimitiveType(Prim)); + } + + SPIR::RefParamType + convertPointerType(const itanium_demangle::PointerType *PT) { + const Node *PointeeNode = PT->getPointee(); + + // Extract address space qualifier from pointer type. + // + // In Itanium mangling, address space qualifiers are encoded as vendor + // extensions in the pointee type, not the pointer itself. We extract + // the AS qualifier here and apply it to the pointer (which is how SPIR + // represents it), then continue processing the unwrapped pointee type. + // + // We must extract address space BEFORE CV-qualifiers because the structure + // is: PointerType -> VendorExtQualType(AS) -> QualType(CV) -> BaseType. + + // Default value, e.g. for implicit pointers (no AS qualifier). + unsigned AS = IsSPIRV ? 0 : SPIR::ADDRESS_SPACE_GENERIC; + if (PointeeNode->getKind() == Node::KVendorExtQualType) { + const auto *VT = static_cast(PointeeNode); + StringRef Ext(VT->getExt()); + if (Ext.starts_with("AS")) { + [[maybe_unused]] bool Success = to_integer(Ext.drop_front(2), AS, 10); + assert(Success && "Unexpected non-integer address space"); + // Use the inner type, not the VendorExtQualType wrapper. + PointeeNode = VT->getTy(); + } + } + + // Extract CV-qualifiers (const/volatile/restrict) from QualType nodes. + // In Itanium mangling, qualifiers appear as QualType wrappers around the + // actual pointee type. We need to extract and preserve these qualifiers + // for correct OpenCL function signature matching. + // + // Example: pointer to const int with address space is represented as: + // PointerType -> VendorExtQualType(AS1) -> QualType(const) -> + // NameType("int") + // And mangles as "PU3AS1Ki" where U3AS1=AS1, K=const, i=int. + bool IsConst = false; + bool IsVolatile = false; + bool IsRestrict = false; + + while (PointeeNode->getKind() == Node::KQualType) { + const auto *QT = static_cast(PointeeNode); + Qualifiers Quals = QT->getQuals(); + if (Quals & QualConst) + IsConst = true; + if (Quals & QualVolatile) + IsVolatile = true; + if (Quals & QualRestrict) + IsRestrict = true; + PointeeNode = QT->getChild(); + } + + SPIR::RefParamType Pointee = convert(PointeeNode); + if (!Pointee) + return SPIR::RefParamType(); + + auto *Ptr = new SPIR::PointerType(Pointee); + Ptr->setAddressSpace(AS); + // Apply CV-qualifiers to the pointer. + Ptr->setQualifier(SPIR::ATTR_CONST, IsConst); + Ptr->setQualifier(SPIR::ATTR_VOLATILE, IsVolatile); + Ptr->setQualifier(SPIR::ATTR_RESTRICT, IsRestrict); + return SPIR::RefParamType(Ptr); + } + + SPIR::RefParamType convertVectorType(const itanium_demangle::VectorType *VT) { + const Node *BaseNode = VT->getBaseType(); + SPIR::RefParamType Base = convert(BaseNode); + if (!Base) + return SPIR::RefParamType(); + + // Extract vector length from dimension node. + const Node *DimNode = VT->getDimension(); + if (DimNode->getKind() == Node::KNameType) { + StringRef DimStr(static_cast(DimNode)->getName()); + int Len = 0; + if (to_integer(DimStr, Len, 10)) + return SPIR::RefParamType(new SPIR::VectorType(Base, Len)); + } + return SPIR::RefParamType(); + } + + SPIR::RefParamType convertVendorExtQualType(const VendorExtQualType *VT) { + StringRef Ext(VT->getExt()); + SPIR::RefParamType Base = convert(VT->getTy()); + if (!Base) + return Base; + + // Handle address space qualifiers. + if (Ext.starts_with("AS")) { + unsigned AS = 0; + if (to_integer(Ext.drop_front(2), AS, 10)) + if (auto *PT = dyn_cast(Base.get())) + PT->setAddressSpace(AS); + } + return Base; + } +}; + +SPIR::RefParamType cloneType(SPIR::RefParamType Type) { + if (!Type) + return Type; + + if (const auto *Prim = dyn_cast(Type.get())) { + // Primitive remapping happens in NodeToSPIRType; this only deep-copies. + return SPIR::RefParamType(new SPIR::PrimitiveType(Prim->getPrimitive())); + } else if (const auto *Ptr = dyn_cast(Type.get())) { + SPIR::RefParamType Pointee = cloneType(Ptr->getPointee()); + auto *NewPtr = new SPIR::PointerType(Pointee); + NewPtr->setAddressSpace(Ptr->getAddressSpace()); + NewPtr->setQualifier(SPIR::ATTR_CONST, Ptr->hasQualifier(SPIR::ATTR_CONST)); + NewPtr->setQualifier(SPIR::ATTR_VOLATILE, + Ptr->hasQualifier(SPIR::ATTR_VOLATILE)); + NewPtr->setQualifier(SPIR::ATTR_RESTRICT, + Ptr->hasQualifier(SPIR::ATTR_RESTRICT)); + return SPIR::RefParamType(NewPtr); + } else if (const auto *Vec = dyn_cast(Type.get())) { + SPIR::RefParamType Scalar = cloneType(Vec->getScalarType()); + return SPIR::RefParamType(new SPIR::VectorType(Scalar, Vec->getLength())); + } + return Type; +} + +// Simple allocator for demangling. +class SimpleAllocator { + BumpPtrAllocator Alloc; + +public: + void reset() { Alloc.Reset(); } + + template T *makeNode(Args &&...A) { + return new (Alloc.Allocate(sizeof(T), alignof(T))) + T(std::forward(A)...); + } + + void *allocateNodeArray(size_t Sz) { + return Alloc.Allocate(sizeof(Node *) * Sz, alignof(Node *)); + } +}; + +using Demangler = ManglingParser; + +struct NameBoundaryParser : ManglingParser { + using ManglingParser::ManglingParser; + + NameBoundaryParser(const char *First, const char *Last, + const char *InputBegin) + : ManglingParser(First, Last), InputBegin(InputBegin) {} + + size_t getTemplateSuffixStart() const { return First - InputBegin; } + + const char *InputBegin; +}; + +size_t findTemplateSuffixStart(StringRef MangledName) { + if (!MangledName.starts_with("_Z")) + return StringRef::npos; + + NameBoundaryParser Parser(MangledName.data() + 2, + MangledName.data() + MangledName.size(), + MangledName.data()); + const Node *ParsedName = Parser.parseName(); + if (!ParsedName || ParsedName->getKind() != Node::KNameWithTemplateArgs) + return StringRef::npos; + return Parser.getTemplateSuffixStart(); +} + +bool isValidRemangledBuiltinName(StringRef MangledName, + StringRef ExpectedBaseName) { + Demangler D(MangledName.data(), MangledName.data() + MangledName.size()); + const Node *Root = D.parse(); + if (!Root || Root->getKind() != Node::KFunctionEncoding) + return false; + + const auto *Encoding = static_cast(Root); + const Node *NameNode = Encoding->getName(); + return NameNode && StringRef(NameNode->getBaseName()) == ExpectedBaseName; +} + +// Remangle a function name. +// Returns true and writes the new mangled name if transformation is needed. +bool tryRemangleFuncName(StringRef MangledName, const Triple &TT, + TransformMode Mode, + SmallVectorImpl &RemangledName) { + RemangledName.clear(); + + Demangler D(MangledName.data(), MangledName.data() + MangledName.size()); + const Node *Root = D.parse(); + if (!Root || Root->getKind() != Node::KFunctionEncoding) + return false; + + const auto *Encoding = static_cast(Root); + + // Check if function has template arguments. + // For templated functions like __spirv_ImageRead, the structure is: + // NameWithTemplateArgs -> Name (base name) + TemplateArgs (template params) + // For non-templated functions, it's just a Name node. + const Node *NameNode = Encoding->getName(); + StringRef BaseName = NameNode->getBaseName(); + bool HasTemplateArgs = NameNode->getKind() == Node::KNameWithTemplateArgs; + + // Validate no whitespace (would indicate malformed demangling). + if (BaseName.contains(' ')) + return false; + + // Convert template arguments and function parameter types. + NodeToSPIRType Converter(TT, Mode); + + SmallVector TemplateArgTypes; + SmallVector Params; + + if (HasTemplateArgs) { + const auto *TemplatedName = + static_cast(NameNode); + if (!TemplatedName->TemplateArgs || + TemplatedName->TemplateArgs->getKind() != Node::KTemplateArgs) + return false; + + const auto *TemplateArgList = + static_cast( + TemplatedName->TemplateArgs); + for (const Node *TemplateArgNode : TemplateArgList->getParams()) { + SPIR::RefParamType TemplateArgType = Converter.convert(TemplateArgNode); + if (!TemplateArgType) + return false; + TemplateArgType = cloneType(TemplateArgType); + TemplateArgTypes.push_back(TemplateArgType); + } + } + + NodeArray ParamNodes = Encoding->getParams(); + if (ParamNodes.empty() && TemplateArgTypes.empty()) + return false; + + for (const Node *ParamNode : ParamNodes) { + SPIR::RefParamType ParamType = Converter.convert(ParamNode); + if (!ParamType) { + // If any parameter fails to convert, this is likely a malformed/invalid + // mangling. Don't try to remangle it. + return false; + } + ParamType = cloneType(ParamType); + Params.push_back(ParamType); + } + + // Remangle using SPIR mangler. Templated functions are only handled + // structurally when all template arguments can be represented as supported + // type nodes; otherwise we conservatively skip remangling. + SmallString<128> Result; + SPIR::NameMangler Mangler; + if (HasTemplateArgs) { + size_t TemplateSuffixStart = findTemplateSuffixStart(MangledName); + if (TemplateSuffixStart == StringRef::npos) + return false; + + SmallString<128> RemangledTemplatePrefix; + Mangler.mangleTemplateName(BaseName, TemplateArgTypes, + RemangledTemplatePrefix); + + Result = RemangledTemplatePrefix; + Result += MangledName.substr(TemplateSuffixStart); + } else { + Mangler.mangle(BaseName, Params, Result); + } + + // Final validation: ensure the new mangled name is different from the + // original. If they're the same or if Result is malformed, don't transform. + if (Result == MangledName) + return false; + + assert(isValidRemangledBuiltinName(Result, BaseName) && + "invalid remangled builtin name"); + + RemangledName = Result; + return true; +} + +// Make a clone of a suitable function using the old name if there is a +// type-mapping and the corresponding clonee function exists. +// TransformMode::CloneOriginal: CloneName=OrigName, CloneeName=TypeResult. +// TransformMode::CloneRemangled: CloneName=TypeResult, CloneeName=OrigName. +void createCloneFromMap(const Triple &TT, Module &M, StringRef OrigName, + StringRef MangledForRemap, TransformMode Mode) { + SmallString<128> RemangledName; + bool HasRemangledName = + tryRemangleFuncName(MangledForRemap, TT, Mode, RemangledName); + + if (!HasRemangledName) + RemangledName = MangledForRemap; + + if (StringRef(RemangledName) == OrigName) + return; // No transformation needed + + SmallString<128> CloneName; + StringRef CloneeName; + if (Mode == TransformMode::CloneOriginal) { + CloneName = OrigName; + CloneeName = RemangledName; + } else { + CloneName = RemangledName; + CloneeName = OrigName; + } + + // TmpSuffix: if CloneName already exists, append .tmp (will be resolved + // in postProcessRemoveTmpSuffix). + if (M.getFunction(CloneName)) { + CloneName += TmpSuffix; + if (M.getFunction(CloneName)) + return; // Both base and .tmp exist, skip + } + + if (Function *Clonee = M.getFunction(CloneeName)) { + ValueToValueMapTy VMap; + Function *Clone = CloneFunction(Clonee, VMap); + Clone->setName(CloneName); + LLVM_DEBUG(dbgs() << "clone " << Clone->getName() << " <- " + << Clonee->getName() << "\n"); + } +} + +// Resolve .tmp collisions. +void postProcessRemoveTmpSuffix(Module &M, + const StringSet<> &RenamedFunctions) { + SmallVector TmpFunctions; + for (Function &F : M) + if (F.getName().ends_with(TmpSuffix)) + TmpFunctions.push_back(&F); + + SmallVector ToErase; + for (Function *F : TmpFunctions) { + StringRef FName = F->getName(); + StringRef BaseName = FName.drop_back(TmpSuffix.size()); + if (Function *Existing = M.getFunction(BaseName)) { + if (RenamedFunctions.count(BaseName)) { + // BaseName was an original function that got renamed by Rename. Replace + // it with this .tmp clone (which has more accurate typing). + Existing->replaceAllUsesWith( + ConstantPointerNull::get(Existing->getType())); + Existing->setName(""); + ToErase.push_back(Existing); + } else { + // BaseName exists but was not renamed by Rename. This .tmp is + // redundant. Replace uses of .tmp with Existing and erase. + F->replaceAllUsesWith(Existing); + F->eraseFromParent(); + continue; + } + } + // Rename .tmp function to its base name. + F->setName(BaseName); + } + + for (Function *F : ToErase) + F->eraseFromParent(); +} + +} // anonymous namespace + +PreservedAnalyses SYCLRemangleLibspirvPass::run(Module &M, + ModuleAnalysisManager &MAM) { + // Require explicit configuration via command line options. + if (LongWidth.getNumOccurrences() == 0 || + CharSignedness.getNumOccurrences() == 0) + return PreservedAnalyses::all(); + + const Triple TT(M.getTargetTriple()); + + // Skip SPIR/SPIRV targets by default unless explicitly enabled. + if ((TT.isSPIR() || TT.isSPIRV()) && !RemangleSPIRVTarget) + return PreservedAnalyses::all(); + + bool Changed = false; + // Track functions whose original names were renamed. + StringSet<> RenamedFunctions; + SmallVector Worklist; + + for (Function &F : M) { + // Skip intrinsics and non-mangled names. + if (F.isIntrinsic() || !F.getName().starts_with("_Z")) + continue; + + // Skip __clc_ function declarations. Remangling them requires multiple clc + // library variants to match libspirv mangling. + if (F.isDeclaration() && F.getName().contains("__clc_")) + continue; + + // Skip internal/private linkage functions (won't be called externally). + if (F.hasLocalLinkage()) + continue; + + Worklist.push_back(&F); + } + + for (Function *F : Worklist) { + StringRef Name = F->getName(); + + SmallString<128> MangledName = Name; + + // Try to change the parameter types in the function name. + SmallString<128> RemangledName; + if (!tryRemangleFuncName(MangledName, TT, TransformMode::Rename, + RemangledName)) { + continue; + } + + RenamedFunctions.insert(MangledName); + + // TmpSuffix: if target already exists, append .tmp. + if (M.getFunction(RemangledName)) + RemangledName += TmpSuffix; + assert(!M.getFunction(RemangledName) && + "Remangling collision: third function attempted to use an existing " + "target name"); + + Changed = true; + + F->setName(RemangledName); + + LLVM_DEBUG(dbgs() << "remangle " << MangledName << " -> " << RemangledName + << "\n"); + + // Declarations: rename only, no cloning (they are forward decls of + // builtins called from other builtins in a single .cl file). + if (F->isDeclaration()) + continue; + + // Create clone of original function. + createCloneFromMap(TT, M, MangledName, MangledName, + TransformMode::CloneOriginal); + + // Create clone of remangled function. + createCloneFromMap(TT, M, RemangledName, MangledName, + TransformMode::CloneRemangled); + } + + postProcessRemoveTmpSuffix(M, RenamedFunctions); + + return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); +} diff --git a/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/bidirectional-collision.ll b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/bidirectional-collision.ll new file mode 100644 index 0000000000000..e6d05020f1197 --- /dev/null +++ b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/bidirectional-collision.ll @@ -0,0 +1,40 @@ +; RUN: opt -passes=sycl-remangle-libspirv --remangle-long-width=64 --remangle-char-signedness=signed -mtriple=nvptx64-nvidia-cuda -S < %s | FileCheck %s + +; Test TmpSuffix collision handling for bidirectional transformations. +; +; In normal operation, the pass creates long long variants (Pxiix, Pyiiy) without +; collision. However, this test creates a bidirectional collision scenario by +; providing BOTH Pliil and Pxiix as inputs (even though Pxiix is not in real +; libspirv source). Test the TmpSuffix logic that handles collisions when: +; Map 1: Pxiix -> Pliil (collision: Pliil already exists) +; Map 2: Pliil -> Pxiix (collision: Pxiix already exists) + +define void @_Z19__spirv_AtomicStorePliil(ptr, i32, i32, i64) { unreachable } +; CHECK-DAG: define void @_Z19__spirv_AtomicStorePxiix( +; CHECK-DAG: define void @_Z19__spirv_AtomicStorePliil( + +define void @_Z19__spirv_AtomicStorePmiim(ptr, i32, i32, i64) { unreachable } +; CHECK-DAG: define void @_Z19__spirv_AtomicStorePyiiy( +; CHECK-DAG: define void @_Z19__spirv_AtomicStorePmiim( + +define void @_Z19__spirv_AtomicStorePU3AS1liil(ptr addrspace(1), i32, i32, i64) { unreachable } +; CHECK-DAG: define void @_Z19__spirv_AtomicStorePU3AS1xiix(ptr addrspace(1) +; CHECK-DAG: define void @_Z19__spirv_AtomicStorePU3AS1liil(ptr addrspace(1) + +define void @_Z19__spirv_AtomicStorePU3AS3liil(ptr addrspace(3), i32, i32, i64) { unreachable } +; CHECK-DAG: define void @_Z19__spirv_AtomicStorePU3AS3xiix(ptr addrspace(3) +; CHECK-DAG: define void @_Z19__spirv_AtomicStorePU3AS3liil(ptr addrspace(3) + +define void @_Z19__spirv_AtomicStorePU3AS1miim(ptr addrspace(1), i32, i32, i64) { unreachable } +; CHECK-DAG: define void @_Z19__spirv_AtomicStorePU3AS1yiiy(ptr addrspace(1) +; CHECK-DAG: define void @_Z19__spirv_AtomicStorePU3AS1miim(ptr addrspace(1) + +define void @_Z19__spirv_AtomicStorePU3AS3miim(ptr addrspace(3), i32, i32, i64) { unreachable } +; CHECK-DAG: define void @_Z19__spirv_AtomicStorePU3AS3yiiy(ptr addrspace(3) +; CHECK-DAG: define void @_Z19__spirv_AtomicStorePU3AS3miim(ptr addrspace(3) + +define <4 x half> @_Z30__spirv_ImageSampleExplicitLodImDv4_DhDv3_fET0_T_T1_iS4_S4_(i64, <3 x float>, i32, <3 x float>, <3 x float>) { unreachable } +; CHECK-DAG: define <4 x half> @_Z30__spirv_ImageSampleExplicitLodIyDv4_DF16_Dv3_fET0_T_T1_iS4_S4_( + +define <4 x half> @_Z30__spirv_ImageSampleExplicitLodImDv4_DF16_Dv3_fET0_T_T1_iS4_S4_(i64, <3 x float>, i32, <3 x float>, <3 x float>) { unreachable } +; CHECK-DAG: define <4 x half> @_Z30__spirv_ImageSampleExplicitLodImDv4_DF16_Dv3_fET0_T_T1_iS4_S4_( diff --git a/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/char-signed.ll b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/char-signed.ll new file mode 100644 index 0000000000000..638e5f1ba066d --- /dev/null +++ b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/char-signed.ll @@ -0,0 +1,27 @@ +; RUN: opt -passes=sycl-remangle-libspirv --remangle-long-width=64 --remangle-char-signedness=signed -mtriple=nvptx64-nvidia-cuda -S < %s | FileCheck %s + +; Test checks remangling when char is signed. + +; signed char parameter. +define i8 @_Z17__spirv_ocl_s_absa(i8) { unreachable } +; CHECK-DAG: define i8 @_Z17__spirv_ocl_s_absa( + +; char parameter (should stay as char). +define i8 @_Z17__spirv_ocl_s_absc(i8) { unreachable } +; CHECK-DAG: define i8 @_Z17__spirv_ocl_s_absc( + +; unsigned char parameter (should stay as uchar). +define i8 @_Z17__spirv_ocl_u_absh(i8) { unreachable } +; CHECK-DAG: define i8 @_Z17__spirv_ocl_u_absh( + +; vec4 signed char (substitutions preserved after transformation). +define <4 x i8> @_Z20__spirv_ocl_s_mul_hiDv4_aS_(<4 x i8>, <4 x i8>) { unreachable } +; CHECK-DAG: define <4 x i8> @_Z20__spirv_ocl_s_mul_hiDv4_aS_( + +; vec16 signed char (substitutions preserved after transformation). +define <16 x i8> @_Z20__spirv_ocl_s_mul_hiDv16_aS_(<16 x i8>, <16 x i8>) { unreachable } +; CHECK-DAG: define <16 x i8> @_Z20__spirv_ocl_s_mul_hiDv16_aS_( + +; vector of signed char (alternate builtin for variety). +define <16 x i8> @_Z17__spirv_ocl_s_absDv16_a(<16 x i8>) { unreachable } +; CHECK-DAG: define <16 x i8> @_Z17__spirv_ocl_s_absDv16_a( diff --git a/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/char-unsigned.ll b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/char-unsigned.ll new file mode 100644 index 0000000000000..00007b7e29e81 --- /dev/null +++ b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/char-unsigned.ll @@ -0,0 +1,38 @@ +; RUN: opt -passes=sycl-remangle-libspirv --remangle-long-width=64 --remangle-char-signedness=unsigned -mtriple=nvptx64-nvidia-cuda -S < %s | FileCheck %s + +; Test checks remangling when char is unsigned. + +; scalar char parameter. +define signext range(i8 0, 9) i8 @_Z15__spirv_ocl_clzc(i8 signext) { unreachable } +define zeroext range(i8 0, 9) i8 @_Z15__spirv_ocl_clzh(i8 zeroext) { unreachable } +; CHECK-DAG: define signext range(i8 0, 9) i8 @_Z15__spirv_ocl_clza(i8 signext +; CHECK-DAG: define zeroext range(i8 0, 9) i8 @_Z15__spirv_ocl_clzh(i8 zeroext +; CHECK-DAG: define zeroext range(i8 0, 9) i8 @_Z15__spirv_ocl_clzc(i8 zeroext + +; vector of char. +define <4 x i8> @_Z20__spirv_ocl_popcountDv4_c(<4 x i8>) { unreachable } +define <4 x i8> @_Z20__spirv_ocl_popcountDv4_h(<4 x i8>) { unreachable } +; CHECK-DAG: define <4 x i8> @_Z20__spirv_ocl_popcountDv4_a( +; CHECK-DAG: define <4 x i8> @_Z20__spirv_ocl_popcountDv4_h( +; CHECK-DAG: define <4 x i8> @_Z20__spirv_ocl_popcountDv4_c( + +; char parameter with substitutions. +define signext i8 @_Z18__spirv_ocl_rotatecc(i8 signext, i8 signext) { unreachable } +define zeroext i8 @_Z18__spirv_ocl_rotatehh(i8 zeroext, i8 zeroext) { unreachable } +; CHECK-DAG: define signext i8 @_Z18__spirv_ocl_rotateaa(i8 signext {{.*}}, i8 signext {{.*}}) +; CHECK-DAG: define zeroext i8 @_Z18__spirv_ocl_rotatehh(i8 zeroext {{.*}}, i8 zeroext {{.*}}) +; CHECK-DAG: define zeroext i8 @_Z18__spirv_ocl_rotatecc(i8 zeroext {{.*}}, i8 zeroext {{.*}}) + +; multiple char parameters. +define signext i8 @_Z21__spirv_ocl_bitselectccc(i8 signext, i8 signext, i8 signext) { unreachable } +define zeroext i8 @_Z21__spirv_ocl_bitselecthhh(i8 zeroext, i8 zeroext, i8 zeroext) { unreachable } +; CHECK-DAG: define signext i8 @_Z21__spirv_ocl_bitselectaaa(i8 signext {{.*}}, i8 signext {{.*}}, i8 signext {{.*}}) +; CHECK-DAG: define zeroext i8 @_Z21__spirv_ocl_bitselecthhh(i8 zeroext {{.*}}, i8 zeroext {{.*}}, i8 zeroext {{.*}}) +; CHECK-DAG: define zeroext i8 @_Z21__spirv_ocl_bitselectccc(i8 zeroext {{.*}}, i8 zeroext {{.*}}, i8 zeroext {{.*}}) + +; vector with substitution preserved. +define <16 x i8> @_Z21__spirv_ocl_bitselectDv16_cS_S_(<16 x i8>, <16 x i8>, <16 x i8>) { unreachable } +define <16 x i8> @_Z21__spirv_ocl_bitselectDv16_hS_S_(<16 x i8>, <16 x i8>, <16 x i8>) { unreachable } +; CHECK-DAG: define <16 x i8> @_Z21__spirv_ocl_bitselectDv16_aS_S_( +; CHECK-DAG: define <16 x i8> @_Z21__spirv_ocl_bitselectDv16_hS_S_( +; CHECK-DAG: define <16 x i8> @_Z21__spirv_ocl_bitselectDv16_cS_S_( diff --git a/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/filter-non-spirv.ll b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/filter-non-spirv.ll new file mode 100644 index 0000000000000..2c659d18802bb --- /dev/null +++ b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/filter-non-spirv.ll @@ -0,0 +1,39 @@ +; RUN: opt -passes=sycl-remangle-libspirv --remangle-long-width=64 --remangle-char-signedness=signed -mtriple=nvptx64-nvidia-cuda -S < %s | FileCheck %s + +; Test that non-SPIR-V builtins and malformed SPIR-V names are not remangled. + +; User function with long parameter. +define void @_Z10user_func1l(i64) { unreachable } +; CHECK-DAG: define void @_Z10user_func1l( + +; User function with long long parameter. +define void @_Z10user_func1x(i64) { unreachable } +; CHECK-DAG: define void @_Z10user_func1x( + +; User function with _Float16. +define void @_Z10user_func1DF16_(half) { unreachable } +; CHECK-DAG: define void @_Z10user_func1DF16_( + +; User function with signed char. +define void @_Z10user_func1a(i8) { unreachable } +; CHECK-DAG: define void @_Z10user_func1a( + +; User function with vector of long. +define void @_Z10user_func1Dv4_l(<4 x i64>) { unreachable } +; CHECK-DAG: define void @_Z10user_func1Dv4_l( + +; LLVM intrinsic. +declare i64 @llvm.abs.i64(i64) +; CHECK-DAG: declare i64 @llvm.abs.i64( + +; Non-mangled function. +define void @simple_function(i64) { unreachable } +; CHECK-DAG: define void @simple_function( + +; Wrong mangled name length (says 17 but actual is different). +define <4 x half> @_Z17__spirv_ocl_fabsDv4_DF16_(<4 x half>) { unreachable } +; CHECK-DAG: define <4 x half> @_Z17__spirv_ocl_fabsDv4_DF16_( + +; Invalid type encoding - demangler can parse but converter fails. +define void @_Z15__spirv_invalidXYZ(i32) { unreachable } +; CHECK-DAG: define void @_Z15__spirv_invalidXYZ( diff --git a/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/float16-types.ll b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/float16-types.ll new file mode 100644 index 0000000000000..b282415e67283 --- /dev/null +++ b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/float16-types.ll @@ -0,0 +1,16 @@ +; RUN: opt -passes=sycl-remangle-libspirv --remangle-long-width=64 --remangle-char-signedness=signed -mtriple=nvptx64-nvidia-cuda -S < %s | FileCheck %s + +; Test _Float16/half type remangling. + +; _Float16 parameter. +define half @_Z16__spirv_ocl_fabsDh(half) { unreachable } +; CHECK-DAG: define half @_Z16__spirv_ocl_fabsDF16_( + +; vector of _Float16. +define <4 x half> @_Z16__spirv_ocl_fabsDv4_Dh(<4 x half>) { unreachable } +; CHECK-DAG: define <4 x half> @_Z16__spirv_ocl_fabsDv4_DF16_( + +; _Float16 in complex function with address spaces, substitutions, const qualifier, and ocl_event. +define ptr @_Z22__spirv_GroupAsyncCopyiPU3AS3Dv2_DhPU3AS1KS_mm9ocl_event(i32, ptr addrspace(3), ptr addrspace(1), i64, i64, ptr) { unreachable } +; CHECK-DAG: define ptr @_Z22__spirv_GroupAsyncCopyiPU3AS3Dv2_DF16_PU3AS1KS_yy9ocl_event( +; CHECK-DAG: define ptr @_Z22__spirv_GroupAsyncCopyiPU3AS3Dv2_DF16_PU3AS1KS_mm9ocl_event( diff --git a/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/long-types.ll b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/long-types.ll new file mode 100644 index 0000000000000..de29cc7f924b1 --- /dev/null +++ b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/long-types.ll @@ -0,0 +1,79 @@ +; RUN: opt -passes=sycl-remangle-libspirv --remangle-long-width=64 --remangle-char-signedness=signed -mtriple=nvptx64-nvidia-cuda -S < %s | FileCheck %s --check-prefix=CHECK-NVPTX64 +; RUN: opt -passes=sycl-remangle-libspirv --remangle-long-width=32 --remangle-char-signedness=signed -mtriple=x86_64-pc-windows-msvc -S < %s | FileCheck %s --check-prefix=CHECK-WIN64 +; RUN: opt -passes=sycl-remangle-libspirv --remangle-long-width=32 --remangle-char-signedness=signed -mtriple=i386-pc-linux-gnu -S < %s | FileCheck %s --check-prefix=CHECK-I386 + +; Test long/long long type (signed and unsigned) remangling. + +; long parameter (i64 on 64-bit Linux, i32 on Windows/32-bit). +define i64 @_Z17__spirv_ocl_s_absl(i64) { unreachable } +define i32 @_Z17__spirv_ocl_s_absi(i32) { unreachable } +; CHECK-NVPTX64-DAG: define i64 @_Z17__spirv_ocl_s_absx( +; CHECK-NVPTX64-DAG: define i32 @_Z17__spirv_ocl_s_absi( +; CHECK-NVPTX64-DAG: define i64 @_Z17__spirv_ocl_s_absl( +; CHECK-WIN64-DAG: define i64 @_Z17__spirv_ocl_s_absx( +; CHECK-WIN64-DAG: define i32 @_Z17__spirv_ocl_s_absi( +; CHECK-WIN64-DAG: define i32 @_Z17__spirv_ocl_s_absl( +; CHECK-I386-DAG: define i64 @_Z17__spirv_ocl_s_absx( +; CHECK-I386-DAG: define i32 @_Z17__spirv_ocl_s_absi( +; CHECK-I386-DAG: define i32 @_Z17__spirv_ocl_s_absl( + +; unsigned long parameter. +define i64 @_Z17__spirv_ocl_u_absm(i64) { unreachable } +define i32 @_Z17__spirv_ocl_u_absj(i32) { unreachable } +; CHECK-NVPTX64-DAG: define i64 @_Z17__spirv_ocl_u_absy( +; CHECK-NVPTX64-DAG: define i32 @_Z17__spirv_ocl_u_absj( +; CHECK-NVPTX64-DAG: define i64 @_Z17__spirv_ocl_u_absm( +; CHECK-WIN64-DAG: define i64 @_Z17__spirv_ocl_u_absy( +; CHECK-WIN64-DAG: define i32 @_Z17__spirv_ocl_u_absj( +; CHECK-WIN64-DAG: define i32 @_Z17__spirv_ocl_u_absm( +; CHECK-I386-DAG: define i64 @_Z17__spirv_ocl_u_absy( +; CHECK-I386-DAG: define i32 @_Z17__spirv_ocl_u_absj( +; CHECK-I386-DAG: define i32 @_Z17__spirv_ocl_u_absm( + +; vec8 long (substitutions preserved). +define <8 x i64> @_Z20__spirv_ocl_s_mul_hiDv8_lS_(<8 x i64>, <8 x i64>) { unreachable } +define <8 x i32> @_Z20__spirv_ocl_s_mul_hiDv8_iS_(<8 x i32>, <8 x i32>) { unreachable } +; CHECK-NVPTX64-DAG: define <8 x i64> @_Z20__spirv_ocl_s_mul_hiDv8_xS_( +; CHECK-NVPTX64-DAG: define <8 x i32> @_Z20__spirv_ocl_s_mul_hiDv8_iS_( +; CHECK-NVPTX64-DAG: define <8 x i64> @_Z20__spirv_ocl_s_mul_hiDv8_lS_( +; CHECK-WIN64-DAG: define <8 x i64> @_Z20__spirv_ocl_s_mul_hiDv8_xS_( +; CHECK-WIN64-DAG: define <8 x i32> @_Z20__spirv_ocl_s_mul_hiDv8_iS_( +; CHECK-WIN64-DAG: define <8 x i32> @_Z20__spirv_ocl_s_mul_hiDv8_lS_( +; CHECK-I386-DAG: define <8 x i64> @_Z20__spirv_ocl_s_mul_hiDv8_xS_( +; CHECK-I386-DAG: define <8 x i32> @_Z20__spirv_ocl_s_mul_hiDv8_iS_( +; CHECK-I386-DAG: define <8 x i32> @_Z20__spirv_ocl_s_mul_hiDv8_lS_( + +; vec4 unsigned long. +define <4 x i64> @_Z20__spirv_ocl_u_mul_hiDv4_mS_(<4 x i64>, <4 x i64>) { unreachable } +define <4 x i32> @_Z20__spirv_ocl_u_mul_hiDv4_jS_(<4 x i32>, <4 x i32>) { unreachable } +; CHECK-NVPTX64-DAG: define <4 x i64> @_Z20__spirv_ocl_u_mul_hiDv4_yS_( +; CHECK-NVPTX64-DAG: define <4 x i32> @_Z20__spirv_ocl_u_mul_hiDv4_jS_( +; CHECK-NVPTX64-DAG: define <4 x i64> @_Z20__spirv_ocl_u_mul_hiDv4_mS_( +; CHECK-WIN64-DAG: define <4 x i64> @_Z20__spirv_ocl_u_mul_hiDv4_yS_( +; CHECK-WIN64-DAG: define <4 x i32> @_Z20__spirv_ocl_u_mul_hiDv4_jS_( +; CHECK-WIN64-DAG: define <4 x i32> @_Z20__spirv_ocl_u_mul_hiDv4_mS_( +; CHECK-I386-DAG: define <4 x i64> @_Z20__spirv_ocl_u_mul_hiDv4_yS_( +; CHECK-I386-DAG: define <4 x i32> @_Z20__spirv_ocl_u_mul_hiDv4_jS_( +; CHECK-I386-DAG: define <4 x i32> @_Z20__spirv_ocl_u_mul_hiDv4_mS_( + +; AtomicStore with long parameter. +define void @_Z19__spirv_AtomicStorePliil(ptr, i32, i32, i64) { unreachable } +define void @_Z19__spirv_AtomicStorePliii(ptr, i32, i32, i32) { unreachable } +; CHECK-NVPTX64-DAG: define void @_Z19__spirv_AtomicStorePxiix(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i64 {{.*}}) +; CHECK-NVPTX64-DAG: define void @_Z19__spirv_AtomicStorePxiii(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) +; CHECK-NVPTX64-DAG: define void @_Z19__spirv_AtomicStorePliil(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i64 {{.*}}) +; CHECK-WIN64-DAG: define void @_Z19__spirv_AtomicStorePxiix(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i64 {{.*}}) +; CHECK-WIN64-DAG: define void @_Z19__spirv_AtomicStorePxiii(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) +; CHECK-I386-DAG: define void @_Z19__spirv_AtomicStorePxiix(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i64 {{.*}}) +; CHECK-I386-DAG: define void @_Z19__spirv_AtomicStorePxiii(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) + +; AtomicStore with unsigned long parameter. +define void @_Z19__spirv_AtomicStorePmiim(ptr, i32, i32, i64) { unreachable } +define void @_Z19__spirv_AtomicStorePmiij(ptr, i32, i32, i32) { unreachable } +; CHECK-NVPTX64-DAG: define void @_Z19__spirv_AtomicStorePyiiy(ptr %0, i32 {{.*}}, i32 {{.*}}, i64 {{.*}}) +; CHECK-NVPTX64-DAG: define void @_Z19__spirv_AtomicStorePyiij(ptr %0, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) +; CHECK-NVPTX64-DAG: define void @_Z19__spirv_AtomicStorePmiim(ptr %0, i32 {{.*}}, i32 {{.*}}, i64 {{.*}}) +; CHECK-WIN64-DAG: define void @_Z19__spirv_AtomicStorePyiiy(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i64 {{.*}}) +; CHECK-WIN64-DAG: define void @_Z19__spirv_AtomicStorePyiij(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) +; CHECK-I386-DAG: define void @_Z19__spirv_AtomicStorePyiiy(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i64 {{.*}}) +; CHECK-I386-DAG: define void @_Z19__spirv_AtomicStorePyiij(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) diff --git a/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/pointer-addrspace.ll b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/pointer-addrspace.ll new file mode 100644 index 0000000000000..274b87ec47d93 --- /dev/null +++ b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/pointer-addrspace.ll @@ -0,0 +1,37 @@ +; RUN: opt -passes=sycl-remangle-libspirv --remangle-spirv-target --remangle-long-width=64 --remangle-char-signedness=signed -mtriple=spir64-unknown-unknown -S < %s | FileCheck %s + +; Test pointer type transformations with various address spaces. + +; Pointer with explicit AS1 (global) - preserved. +define spir_func float @_Z17__spirv_ocl_fractfPU3AS1f(float, ptr addrspace(1)) { unreachable } +; CHECK-DAG: define spir_func float @_Z17__spirv_ocl_fractfPU3AS1f( + +; Pointer with explicit AS2 (constant) - preserved. +define spir_func float @_Z17__spirv_ocl_fractfPU3AS2f(float, ptr addrspace(2)) { unreachable } +; CHECK-DAG: define spir_func float @_Z17__spirv_ocl_fractfPU3AS2f( + +; Pointer with explicit AS3 (local) - preserved. +define spir_func float @_Z17__spirv_ocl_fractfPU3AS3f(float, ptr addrspace(3)) { unreachable } +; CHECK-DAG: define spir_func float @_Z17__spirv_ocl_fractfPU3AS3f( + +; Pointer without AS qualifier (implicit private) - becomes explicit AS0. +define spir_func float @_Z17__spirv_ocl_fractfPf(float, ptr) { unreachable } +; CHECK-DAG: define spir_func float @_Z17__spirv_ocl_fractfPU3AS0f( + +; Pointer with explicit AS4 (generic) - becomes implicit. +define spir_func float @_Z17__spirv_ocl_fractfPU3AS4f(float, ptr addrspace(4)) { unreachable } +; CHECK-DAG: define spir_func float @_Z17__spirv_ocl_fractfPf( + +; Pointer to half. +define spir_func half @_Z17__spirv_ocl_fractDhPDh(half, ptr) { unreachable } +; CHECK-DAG: define spir_func half @_Z17__spirv_ocl_fractDF16_PU3AS0DF16_( + +; Pointer to double. +define spir_func double @_Z17__spirv_ocl_fractdPd(double, ptr) { unreachable } +; CHECK-DAG: define spir_func double @_Z17__spirv_ocl_fractdPU3AS0d( + +; Pointer to vector (substitution for vector type). +; fract(<4 x float>, <4 x float>*) +define spir_func <4 x float> @_Z17__spirv_ocl_fractDv4_fPS_(<4 x float>, ptr) { unreachable } +; CHECK-DAG: define spir_func <4 x float> @_Z17__spirv_ocl_fractDv4_fPU3AS0S_( + diff --git a/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/qualifiers-and-structs.ll b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/qualifiers-and-structs.ll new file mode 100644 index 0000000000000..8025c088be758 --- /dev/null +++ b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/qualifiers-and-structs.ll @@ -0,0 +1,25 @@ +; RUN: opt -passes=sycl-remangle-libspirv --remangle-long-width=64 --remangle-char-signedness=signed -mtriple=nvptx64-nvidia-cuda -S < %s | FileCheck %s + +; Test CV-qualifiers (const/volatile/restrict) preservation in remangling. + +; Pointer to const long (K = const qualifier is preserved). +define i64 @_Z17__spirv_ocl_vloadlPKl(i64, ptr) { unreachable } +; CHECK-DAG: define i64 @_Z17__spirv_ocl_vloadxPKx( +; CHECK-DAG: define i64 @_Z17__spirv_ocl_vloadlPKl( + +; Pointer to volatile int (V = volatile qualifier is preserved). +define i32 @_Z17__spirv_ocl_vloadiPVi(i32, ptr) { unreachable } +; CHECK-DAG: define i32 @_Z17__spirv_ocl_vloadiPVi( + +; Pointer to const volatile double (both K and V qualifiers preserved). +define double @_Z17__spirv_ocl_vloaddPVKd(double, ptr) { unreachable } +; CHECK-DAG: define double @_Z17__spirv_ocl_vloaddPVKd( + +; Pointer to restrict float (r = restrict qualifier is preserved). +define float @_Z17__spirv_ocl_vloadfPrf(float, ptr) { unreachable } +; CHECK-DAG: define float @_Z17__spirv_ocl_vloadfPrf( + +; GroupAsyncCopy with vector<8, _Float16> and const qualifier. +define ptr @_Z22__spirv_GroupAsyncCopyiPU3AS1Dv8_DhPU3AS3KS_mm9ocl_event(i32, ptr addrspace(1), ptr addrspace(3), i64, i64, ptr) { unreachable } +; CHECK-DAG: define ptr @_Z22__spirv_GroupAsyncCopyiPU3AS1Dv8_DF16_PU3AS3KS_yy9ocl_event( +; CHECK-DAG: define ptr @_Z22__spirv_GroupAsyncCopyiPU3AS1Dv8_DF16_PU3AS3KS_mm9ocl_event( diff --git a/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/template-types.ll b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/template-types.ll new file mode 100644 index 0000000000000..ad17dff9b96d5 --- /dev/null +++ b/llvm/test/SYCLLowerIR/SYCLRemangleLibspirv/template-types.ll @@ -0,0 +1,108 @@ +; RUN: opt -passes=sycl-remangle-libspirv --remangle-long-width=64 --remangle-char-signedness=signed -mtriple=nvptx64-nvidia-cuda -S < %s | FileCheck %s + +; Test template parameter transformation for various types. + +;===------------------------------------------------------------------------===; +; Template with _Float16 parameter. +; __spirv_ImageRead<_Float16>(unsigned long, float) +;===------------------------------------------------------------------------=== + +define half @_Z17__spirv_ImageReadIDhmfET_T0_T1_(i64, float) { unreachable } +; CHECK-DAG: define half @_Z17__spirv_ImageReadIDF16_yfET_T0_T1_( +; CHECK-DAG: define half @_Z17__spirv_ImageReadIDF16_mfET_T0_T1_( + +; Template with vector<4, _Float16> parameter. +; __spirv_ImageRead>(unsigned long, float) +define <4 x half> @_Z17__spirv_ImageReadIDv4_DhmfET_T0_T1_(i64, float) { unreachable } +; CHECK-DAG: define <4 x half> @_Z17__spirv_ImageReadIDv4_DF16_yfET_T0_T1_( +; CHECK-DAG: define <4 x half> @_Z17__spirv_ImageReadIDv4_DF16_mfET_T0_T1_( + +; Template with int parameter (should stay as-is). +; __spirv_ImageRead(unsigned long, float) +define i32 @_Z17__spirv_ImageReadIimfET_T0_T1_(i64, float) { unreachable } +; CHECK-DAG: define i32 @_Z17__spirv_ImageReadIiyfET_T0_T1_( +; CHECK-DAG: define i32 @_Z17__spirv_ImageReadIimfET_T0_T1_( + +; Template with float parameter. +; __spirv_ImageRead(unsigned long, float) +define float @_Z17__spirv_ImageReadIfmfET_T0_T1_(i64, float) { unreachable } +; CHECK-DAG: define float @_Z17__spirv_ImageReadIfyfET_T0_T1_( +; CHECK-DAG: define float @_Z17__spirv_ImageReadIfmfET_T0_T1_( + +; Template with vector<4, float> parameter. +; __spirv_ImageRead>(unsigned long, float) +define <4 x float> @_Z17__spirv_ImageReadIDv4_fmfET_T0_T1_(i64, float) { unreachable } +; CHECK-DAG: define <4 x float> @_Z17__spirv_ImageReadIDv4_fyfET_T0_T1_( +; CHECK-DAG: define <4 x float> @_Z17__spirv_ImageReadIDv4_fmfET_T0_T1_( + +;===------------------------------------------------------------------------===; +; Template with char parameter. +;===------------------------------------------------------------------------=== + +; Template with char parameter. +; __spirv_ImageRead(unsigned long, float) +define i8 @_Z17__spirv_ImageReadIcmfET_T0_T1_(i64, float) { unreachable } +; CHECK-DAG: define i8 @_Z17__spirv_ImageReadIayfET_T0_T1_( +; CHECK-DAG: define i8 @_Z17__spirv_ImageReadIcmfET_T0_T1_( +; CHECK-DAG: define i8 @_Z17__spirv_ImageReadIamfET_T0_T1_( + +; Template with vector<4, char> parameter +; __spirv_ImageRead>(unsigned long, float) +define <4 x i8> @_Z17__spirv_ImageReadIDv4_cmfET_T0_T1_(i64, float) { unreachable } +; CHECK-DAG: define <4 x i8> @_Z17__spirv_ImageReadIDv4_ayfET_T0_T1_( +; CHECK-DAG: define <4 x i8> @_Z17__spirv_ImageReadIDv4_cmfET_T0_T1_( +; CHECK-DAG: define <4 x i8> @_Z17__spirv_ImageReadIDv4_amfET_T0_T1_( + +; Template with unsigned char parameter (should stay as unsigned char). +; __spirv_ImageRead(unsigned long, float) +define i8 @_Z17__spirv_ImageReadIhmfET_T0_T1_(i64, float) { unreachable } +; CHECK-DAG: define i8 @_Z17__spirv_ImageReadIhyfET_T0_T1_( +; CHECK-DAG: define i8 @_Z17__spirv_ImageReadIhmfET_T0_T1_( + +; Test scalar char transformation. +; __spirv_ImageArrayWrite +define void @_Z23__spirv_ImageArrayWriteImicEvT_T0_iT1_(i64, i32, i32, i8) { unreachable } +; CHECK-DAG: define void @_Z23__spirv_ImageArrayWriteIyiaEvT_T0_iT1_( + +;===------------------------------------------------------------------------===; +; Complex template with multiple parameters and function name containing 'E' +; Test that we don't corrupt symbols with 'E' in the function name. +; __spirv_ImageSampleExplicitLod<__spirv_SampledImage__image1d_ro, vec4, float> +;===------------------------------------------------------------------------=== + +; Test the fix for template parsing where function names like "ExplicitLod" +; contain the character 'E' which could be confused with template delimiters. +; The pass should NOT transform this (no type transformations needed). +define <4 x i32> @_Z30__spirv_ImageSampleExplicitLodI32__spirv_SampledImage__image1d_roDv4_jfET0_T_T1_if(i64, i32, float, i32, float) { unreachable } +; CHECK-DAG: define <4 x i32> @_Z30__spirv_ImageSampleExplicitLodI32__spirv_SampledImage__image1d_roDv4_jfET0_T_T1_if( + +; Same function but with half in template args. +; __spirv_ImageSampleExplicitLod<__spirv_SampledImage__image1d_ro, vec4, float> +define <4 x half> @_Z30__spirv_ImageSampleExplicitLodI32__spirv_SampledImage__image1d_roDv4_DhfET0_T_T1_if(i64, i32, float, i32, float) { unreachable } +; CHECK-DAG: define <4 x half> @_Z30__spirv_ImageSampleExplicitLodI32__spirv_SampledImage__image1d_roDv4_DF16_fET0_T_T1_if( + +;===------------------------------------------------------------------------===; +; Test that substitution references (S_, S0_, S1_) are correctly expanded. +;===------------------------------------------------------------------------===; + +; Test substitution preservation in array functions. +; __spirv_ImageArrayWrite, vec2> +; Template args: m (primitive, not substitutable), Dv2_i (substitutable), S0_ (reference to Dv2_i) +; The pass should NOT expand S0_ - libspirv.bc has S0_ in the symbol. +define void @_Z23__spirv_ImageArrayWriteImDv2_iS0_EvT_T0_iT1_(i64, <2 x i32>, i32, <2 x i32>) { unreachable } +; CHECK-DAG: define void @_Z23__spirv_ImageArrayWriteIyDv2_iS0_EvT_T0_iT1_( +; CHECK-DAG: define void @_Z23__spirv_ImageArrayWriteImDv2_iS0_EvT_T0_iT1_( + +; Test substitution preservation with SampledImageArrayFetch. +; __spirv_SampledImageArrayFetch, ulong, vec2> +; Template args: Dv2_i (substitutable), m (primitive), S0_ (reference to Dv2_i). +; The pass should NOT expand S0_ - libspirv.bc has S0_ in the symbol. +define <2 x i32> @_Z30__spirv_SampledImageArrayFetchIDv2_imS0_ET_T0_T1_i(i64, <2 x i32>, i32) { unreachable } +; CHECK-DAG: define <2 x i32> @_Z30__spirv_SampledImageArrayFetchIDv2_iyS0_ET_T0_T1_i( +; CHECK-DAG: define <2 x i32> @_Z30__spirv_SampledImageArrayFetchIDv2_imS0_ET_T0_T1_i( + +; Test substitution preservation for non-array functions. +; __spirv_ImageFetch, ulong, vec2> +define <2 x i32> @_Z18__spirv_ImageFetchIDv2_imS0_ET_T0_T1_(i64, <2 x i32>) { unreachable } +; CHECK-DAG: define <2 x i32> @_Z18__spirv_ImageFetchIDv2_iyS0_ET_T0_T1_( +; CHECK-DAG: define <2 x i32> @_Z18__spirv_ImageFetchIDv2_imS0_ET_T0_T1_( diff --git a/sycl-jit/jit-compiler/lib/rtc/DeviceCompilation.cpp b/sycl-jit/jit-compiler/lib/rtc/DeviceCompilation.cpp index e755aa7f893f2..ab54b59f01658 100644 --- a/sycl-jit/jit-compiler/lib/rtc/DeviceCompilation.cpp +++ b/sycl-jit/jit-compiler/lib/rtc/DeviceCompilation.cpp @@ -842,9 +842,9 @@ Error jit_compiler::linkDeviceLibraries(llvm::Module &Module, // Based on the OS and the format decide on the version of libspirv. // NOTE: this will be problematic if cross-compiling between OSes. #ifdef _WIN32 - std::string Libclc = "remangled-l32-signed_char.libspirv.bc"; + std::string Libclc = "libspirv.l32.signed_char.bc"; #else - std::string Libclc = "remangled-l64-signed_char.libspirv.bc"; + std::string Libclc = "libspirv.l64.signed_char.bc"; #endif LibNames.push_back(Libclc); } @@ -865,7 +865,6 @@ Error jit_compiler::linkDeviceLibraries(llvm::Module &Module, TC.loadBitcodeLibrary(LibPath, Context).moveInto(LibModule)) { return Error; } - if (Linker::linkModules(Module, std::move(LibModule), Linker::LinkOnlyNeeded)) { return createStringError("Unable to link device library %s: %s", diff --git a/sycl/doc/design/CompilerAndRuntimeDesign.md b/sycl/doc/design/CompilerAndRuntimeDesign.md index 7c3723d58e1fe..50043bd3bbb1e 100644 --- a/sycl/doc/design/CompilerAndRuntimeDesign.md +++ b/sycl/doc/design/CompilerAndRuntimeDesign.md @@ -568,10 +568,9 @@ objects never goes through SPIR-V. Instead it is passed directly in bitcode form down to the NVPTX Back End. All produced bitcode depends on two libraries, `libdevice.bc` (provided by the CUDA SDK) and `libspirv.bc` variants (built by the libclc project). `libspirv.bc` is not used directly. -Instead it is used to generate remangled variants -`remangled-l64-signed_char.libspirv.bc` and -`remangled-l32-signed_char.libspirv.bc` to handle primitive type -differences between Linux and Windows. +Instead it is used to generate remangled variants `libspirv.l64.signed_char.bc` +and `libspirv.l32.signed_char.bc` to handle primitive type differences between +Linux and Windows. ##### Device code post-link step for CUDA @@ -607,14 +606,9 @@ Differences between the primitive types can cause applications to use incompatible libclc built-ins. A remangler creates multiple libspirv files with different remangled function names to support both Windows and Linux. When building a SYCL application targeting the CUDA backend the driver -will link the device code with -`remangled-l32-signed_char.libspirv.bc` if the host target is -Windows or it will link the device code with -`remangled-l64-signed_char.libspirv.bc` if the host target is -Linux. - -When the SYCL compiler is in device mode and targeting the NVPTX backend, the -compiler exposes NVPTX builtins supported by clang. +will link the device code with `libspirv.l32.signed_char.bc` if the host target +is Windows or it will link the device code with `libspirv.l64.signed_char.bc` if +the host target is Linux. *Note: this enable NVPTX specific features which cannot be supported by other targets or the host.* diff --git a/sycl/test/check_device_code/native_cpu/sycl-native-cpu-libclc-linux.cpp b/sycl/test/check_device_code/native_cpu/sycl-native-cpu-libclc-linux.cpp index 90a9994937438..415015bbedf26 100644 --- a/sycl/test/check_device_code/native_cpu/sycl-native-cpu-libclc-linux.cpp +++ b/sycl/test/check_device_code/native_cpu/sycl-native-cpu-libclc-linux.cpp @@ -2,4 +2,4 @@ // REQUIRES: native_cpu && linux // RUN: %clang -### -fsycl -fsycl-targets=native_cpu -target x86_64-unknown-linux-gnu %s 2> %t.ncpu.out // RUN: FileCheck %s --input-file %t.ncpu.out -// CHECK: {{(\\|/)}}remangled-l64-signed_char.libspirv.bc" +// CHECK: {{(\\|/)}}libspirv.l64.signed_char.bc" diff --git a/sycl/test/check_device_code/native_cpu/sycl-native-cpu-libclc-windows.cpp b/sycl/test/check_device_code/native_cpu/sycl-native-cpu-libclc-windows.cpp index 4db8c72aa4943..9a2acaa604559 100644 --- a/sycl/test/check_device_code/native_cpu/sycl-native-cpu-libclc-windows.cpp +++ b/sycl/test/check_device_code/native_cpu/sycl-native-cpu-libclc-windows.cpp @@ -4,4 +4,4 @@ // Check that l32 variant is selected for Windows // RUN: %clang -### -fsycl -fsycl-targets=native_cpu -target x86_64-windows %s 2> %t-win.ncpu.out // RUN: FileCheck %s --input-file %t-win.ncpu.out --check-prefix=CHECK-WIN -// CHECK-WIN: {{(\\|/)}}remangled-l32-signed_char.libspirv.bc" +// CHECK-WIN: {{(\\|/)}}libspirv.l32.signed_char.bc"