diff --git a/CMakeLists.txt b/CMakeLists.txt
index 29bfac8fcb..c45580b7d2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
 #
-#  Copyright (c) 2018-2023, Intel Corporation
+#  Copyright (c) 2018-2024, Intel Corporation
 #
 #  SPDX-License-Identifier: BSD-3-Clause
 
@@ -440,6 +440,8 @@ target_sources(${PROJECT_NAME}
         "src/bitcode_lib.h"
         "src/builtins.cpp"
         "src/builtins.h"
+        "src/builtins-decl.cpp"
+        "src/builtins-decl.h"
         "src/ctx.cpp"
         "src/ctx.h"
         "src/decl.cpp"
@@ -559,10 +561,14 @@ if (MSVC)
     set_source_files_properties(${BISON_OUTPUT} PROPERTIES COMPILE_FLAGS /wd4005)
 else()
     target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function ${LLVM_CPP_FLAGS})
-    # Security options
+    # Security options for both Debug and Release builds
     target_compile_options(${PROJECT_NAME} PRIVATE -fstack-protector-strong
-                           -fdata-sections -ffunction-sections -fno-delete-null-pointer-checks
-                           -Wformat -Wformat-security -fwrapv)
+                           -fno-delete-null-pointer-checks -Wformat -Wformat-security -fwrapv)
+    # Additional security options for Release mode
+    # Should be combined with link-time optimization (-Wl,--gc-sections during the linking phase)
+    if (CMAKE_BUILD_TYPE STREQUAL "Release")
+        target_compile_options(${PROJECT_NAME} PRIVATE -fdata-sections -ffunction-sections)
+    endif()
     # LLVM 14 switches default DWARF version from v4 to v5
     # but gdb < 10.1 can't read DWARF v5.
     # https://discourse.llvm.org/t/gdb-10-1-cant-read-clangs-dwarf-v5/6035
@@ -605,12 +611,15 @@ if (WIN32)
     endif()
 elseif (APPLE)
 else()
-    # Link options for security hardening.
+    # Common security hardening options for both Debug and Release
     target_link_options(${PROJECT_NAME}
         PUBLIC "SHELL: -z noexecstack"
                "SHELL: -z relro"
-               "SHELL: -z now"
-               "SHELL: -Wl,--gc-sections")
+               "SHELL: -z now")
+    # Additional options for Release mode
+    if(CMAKE_BUILD_TYPE MATCHES Release)
+        target_link_options(${PROJECT_NAME} PUBLIC "SHELL: -Wl,--gc-sections")
+    endif()
 endif()
 
 if (ISPC_STATIC_STDCXX_LINK OR ISPC_STATIC_LINK)
diff --git a/alloy.py b/alloy.py
index 6e276526c1..1dc9905943 100755
--- a/alloy.py
+++ b/alloy.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-#  Copyright (c) 2013-2023, Intel Corporation
+#  Copyright (c) 2013-2024, Intel Corporation
 #
 #  SPDX-License-Identifier: BSD-3-Clause
 
@@ -93,6 +93,8 @@ def checkout_LLVM(component, version_LLVM, target_dir, from_validation, verbose)
     # git: "release/16.x"
     if  version_LLVM == "trunk":
         GIT_TAG="main"
+    elif  version_LLVM == "18_1":
+        GIT_TAG="llvmorg-18.1.1"
     elif  version_LLVM == "17_0":
         GIT_TAG="llvmorg-17.0.6"
     elif  version_LLVM == "16_0":
diff --git a/llvm_patches/16_0_17_0_18_1-X86-getFauxShuffleMask-handle-fp-int-bitcast.patch b/llvm_patches/16_0_17_0_18_1-X86-getFauxShuffleMask-handle-fp-int-bitcast.patch
new file mode 100644
index 0000000000..f197b35051
--- /dev/null
+++ b/llvm_patches/16_0_17_0_18_1-X86-getFauxShuffleMask-handle-fp-int-bitcast.patch
@@ -0,0 +1,40 @@
+# This patch is required to fix the issue #2777
+From 7aa6ddfea210b6b114ac649c4d3219138e9cc52a Mon Sep 17 00:00:00 2001
+From: Simon Pilgrim <llvm-dev@redking.me.uk>
+Date: Thu, 29 Feb 2024 10:32:37 +0000
+Subject: [PATCH] [X86] getFauxShuffleMask - handle
+ insert_vector_elt(bitcast(extract_vector_elt(x))) shuffle patterns
+
+If the bitcast is between types of equal scalar size (i.e. fp<->int bitcasts), then we can safely peek through them
+
+Fixes #83289
+---
+ llvm/lib/Target/X86/X86ISelLowering.cpp | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
+index e43b33eed470..22eea8b3d43d 100644
+--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
++++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
+@@ -8477,13 +8477,16 @@ static bool getFauxShuffleMask(SDValue N, const APInt &DemandedElts,
+       }
+     }
+ 
+-    // Peek through trunc/aext/zext.
++    // Peek through trunc/aext/zext/bitcast.
+     // TODO: aext shouldn't require SM_SentinelZero padding.
+     // TODO: handle shift of scalars.
+     unsigned MinBitsPerElt = Scl.getScalarValueSizeInBits();
+     while (Scl.getOpcode() == ISD::TRUNCATE ||
+            Scl.getOpcode() == ISD::ANY_EXTEND ||
+-           Scl.getOpcode() == ISD::ZERO_EXTEND) {
++           Scl.getOpcode() == ISD::ZERO_EXTEND ||
++           (Scl.getOpcode() == ISD::BITCAST &&
++            Scl.getScalarValueSizeInBits() ==
++                Scl.getOperand(0).getScalarValueSizeInBits())) {
+       Scl = Scl.getOperand(0);
+       MinBitsPerElt =
+           std::min<unsigned>(MinBitsPerElt, Scl.getScalarValueSizeInBits());
+-- 
+2.25.1
+
diff --git a/llvm_patches/16_0_17_0_dbghelp_mitigation.patch b/llvm_patches/16_0_17_0_18_1_dbghelp_mitigation.patch
similarity index 100%
rename from llvm_patches/16_0_17_0_dbghelp_mitigation.patch
rename to llvm_patches/16_0_17_0_18_1_dbghelp_mitigation.patch
diff --git a/llvm_patches/18_1_disable-A-B-A-B-and-BSWAP-in-InstCombine.patch b/llvm_patches/18_1_disable-A-B-A-B-and-BSWAP-in-InstCombine.patch
new file mode 100644
index 0000000000..0655a86aa9
--- /dev/null
+++ b/llvm_patches/18_1_disable-A-B-A-B-and-BSWAP-in-InstCombine.patch
@@ -0,0 +1,64 @@
+# This patch is needed for ISPC for Xe only
+
+# 1. Transformation of add to or is not safe for VC backend.
+# 2. bswap intrinsics is not supported in VC backend yet.
+diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+index 8a00b75a1f..7e3147b6cb 100644
+--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
++++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+@@ -29,6 +29,7 @@
+ #include "llvm/Support/AlignOf.h"
+ #include "llvm/Support/Casting.h"
+ #include "llvm/Support/KnownBits.h"
++#include "llvm/TargetParser/Triple.h"
+ #include "llvm/Transforms/InstCombine/InstCombiner.h"
+ #include <cassert>
+ #include <utility>
+@@ -1579,11 +1580,15 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
+   if (match(&I, m_c_BinOp(m_ZExt(m_Value(A)), m_SExt(m_Deferred(A)))) &&
+       A->getType()->isIntOrIntVectorTy(1))
+     return replaceInstUsesWith(I, Constant::getNullValue(I.getType()));
+-
+-  // A+B --> A|B iff A and B have no bits set in common.
++
+   WithCache<const Value *> LHSCache(LHS), RHSCache(RHS);
+-  if (haveNoCommonBitsSet(LHSCache, RHSCache, SQ.getWithInstruction(&I)))
+-    return BinaryOperator::CreateDisjointOr(LHS, RHS);
++
++  // Disable this transformation for ISPC SPIR-V
++  if (!Triple(I.getModule()->getTargetTriple()).isSPIR()) {
++    // A+B --> A|B iff A and B have no bits set in common.
++    if (haveNoCommonBitsSet(LHSCache, RHSCache, SQ.getWithInstruction(&I)))
++      return BinaryOperator::CreateDisjointOr(LHS, RHS);
++  }
+ 
+   if (Instruction *Ext = narrowMathIfNoOverflow(I))
+     return Ext;
+diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+index 5fd944a859..ad3ae96393 100644
+--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
++++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+@@ -16,6 +16,7 @@
+ #include "llvm/IR/ConstantRange.h"
+ #include "llvm/IR/Intrinsics.h"
+ #include "llvm/IR/PatternMatch.h"
++#include "llvm/TargetParser/Triple.h"
+ #include "llvm/Transforms/InstCombine/InstCombiner.h"
+ #include "llvm/Transforms/Utils/Local.h"
+ 
+@@ -3389,9 +3390,12 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
+   if (Instruction *FoldedLogic = foldBinOpIntoSelectOrPhi(I))
+     return FoldedLogic;
+ 
+-  if (Instruction *BitOp = matchBSwapOrBitReverse(I, /*MatchBSwaps*/ true,
+-                                                  /*MatchBitReversals*/ true))
+-    return BitOp;
++  // Disable this transformation for ISPC SPIR-V
++  if (!Triple(I.getModule()->getTargetTriple()).isSPIR()) {
++    if (Instruction *BitOp = matchBSwapOrBitReverse(I, /*MatchBSwaps*/ true,
++                                                   /*MatchBitReversals*/ true))
++      return BitOp;
++  }
+ 
+   if (Instruction *Funnel = matchFunnelShift(I, *this, DT))
+     return Funnel;
diff --git a/src/ast.cpp b/src/ast.cpp
index 0386f16996..b9e1360fa2 100644
--- a/src/ast.cpp
+++ b/src/ast.cpp
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2011-2023, Intel Corporation
+  Copyright (c) 2011-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -101,7 +101,7 @@ void Indent::Done() {
 
 ASTNode::~ASTNode() {}
 
-void ASTNode::Print() const {
+void ASTNode::Dump() const {
     Indent indent;
     indent.pushSingle();
     Print(indent);
diff --git a/src/ast.h b/src/ast.h
index 9baf8d07b3..fb69bb84b7 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2011-2023, Intel Corporation
+  Copyright (c) 2011-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -173,7 +173,7 @@ class ASTNode : public Traceable {
     unsigned getValueID() const { return SubclassID; }
 
     /** A function for interactive debugging */
-    void Print() const;
+    void Dump() const;
 
     /** A function that should be used for hierarchical AST dump. */
     virtual void Print(Indent &indent) const = 0;
diff --git a/src/builtins-decl.cpp b/src/builtins-decl.cpp
new file mode 100644
index 0000000000..18c3ed1b35
--- /dev/null
+++ b/src/builtins-decl.cpp
@@ -0,0 +1,923 @@
+/*
+  Copyright (c) 2024, Intel Corporation
+
+  SPDX-License-Identifier: BSD-3-Clause
+*/
+
+#include "builtins-decl.h"
+
+#define DECL_BUILTIN_NAME(NAME) const char *const NAME = #NAME
+
+namespace ispc {
+
+namespace builtin {
+
+DECL_BUILTIN_NAME(__acos_uniform_double);
+DECL_BUILTIN_NAME(__acos_uniform_float);
+DECL_BUILTIN_NAME(__acos_uniform_half);
+DECL_BUILTIN_NAME(__acos_varying_double);
+DECL_BUILTIN_NAME(__acos_varying_float);
+DECL_BUILTIN_NAME(__acos_varying_half);
+DECL_BUILTIN_NAME(__add_float);
+DECL_BUILTIN_NAME(__add_int32);
+DECL_BUILTIN_NAME(__add_uniform_double);
+DECL_BUILTIN_NAME(__add_uniform_int32);
+DECL_BUILTIN_NAME(__add_uniform_int64);
+DECL_BUILTIN_NAME(__add_varying_double);
+DECL_BUILTIN_NAME(__add_varying_int32);
+DECL_BUILTIN_NAME(__add_varying_int64);
+DECL_BUILTIN_NAME(__all);
+DECL_BUILTIN_NAME(__any);
+DECL_BUILTIN_NAME(__aos_to_soa2_double);
+DECL_BUILTIN_NAME(__aos_to_soa2_double1);
+DECL_BUILTIN_NAME(__aos_to_soa2_double16);
+DECL_BUILTIN_NAME(__aos_to_soa2_double32);
+DECL_BUILTIN_NAME(__aos_to_soa2_double4);
+DECL_BUILTIN_NAME(__aos_to_soa2_double64);
+DECL_BUILTIN_NAME(__aos_to_soa2_double8);
+DECL_BUILTIN_NAME(__aos_to_soa2_float);
+DECL_BUILTIN_NAME(__aos_to_soa2_float1);
+DECL_BUILTIN_NAME(__aos_to_soa2_float16);
+DECL_BUILTIN_NAME(__aos_to_soa2_float32);
+DECL_BUILTIN_NAME(__aos_to_soa2_float4);
+DECL_BUILTIN_NAME(__aos_to_soa2_float64);
+DECL_BUILTIN_NAME(__aos_to_soa2_float8);
+DECL_BUILTIN_NAME(__aos_to_soa3_double);
+DECL_BUILTIN_NAME(__aos_to_soa3_double1);
+DECL_BUILTIN_NAME(__aos_to_soa3_double16);
+DECL_BUILTIN_NAME(__aos_to_soa3_double32);
+DECL_BUILTIN_NAME(__aos_to_soa3_double4);
+DECL_BUILTIN_NAME(__aos_to_soa3_double64);
+DECL_BUILTIN_NAME(__aos_to_soa3_double8);
+DECL_BUILTIN_NAME(__aos_to_soa3_float);
+DECL_BUILTIN_NAME(__aos_to_soa3_float1);
+DECL_BUILTIN_NAME(__aos_to_soa3_float16);
+DECL_BUILTIN_NAME(__aos_to_soa3_float32);
+DECL_BUILTIN_NAME(__aos_to_soa3_float4);
+DECL_BUILTIN_NAME(__aos_to_soa3_float64);
+DECL_BUILTIN_NAME(__aos_to_soa3_float8);
+DECL_BUILTIN_NAME(__aos_to_soa4_double);
+DECL_BUILTIN_NAME(__aos_to_soa4_double1);
+DECL_BUILTIN_NAME(__aos_to_soa4_double16);
+DECL_BUILTIN_NAME(__aos_to_soa4_double32);
+DECL_BUILTIN_NAME(__aos_to_soa4_double4);
+DECL_BUILTIN_NAME(__aos_to_soa4_double64);
+DECL_BUILTIN_NAME(__aos_to_soa4_double8);
+DECL_BUILTIN_NAME(__aos_to_soa4_float);
+DECL_BUILTIN_NAME(__aos_to_soa4_float1);
+DECL_BUILTIN_NAME(__aos_to_soa4_float16);
+DECL_BUILTIN_NAME(__aos_to_soa4_float32);
+DECL_BUILTIN_NAME(__aos_to_soa4_float4);
+DECL_BUILTIN_NAME(__aos_to_soa4_float64);
+DECL_BUILTIN_NAME(__aos_to_soa4_float8);
+DECL_BUILTIN_NAME(__asin_uniform_double);
+DECL_BUILTIN_NAME(__asin_uniform_float);
+DECL_BUILTIN_NAME(__asin_uniform_half);
+DECL_BUILTIN_NAME(__asin_varying_double);
+DECL_BUILTIN_NAME(__asin_varying_float);
+DECL_BUILTIN_NAME(__asin_varying_half);
+DECL_BUILTIN_NAME(__atan2_uniform_double);
+DECL_BUILTIN_NAME(__atan2_uniform_float);
+DECL_BUILTIN_NAME(__atan2_uniform_half);
+DECL_BUILTIN_NAME(__atan2_varying_double);
+DECL_BUILTIN_NAME(__atan2_varying_float);
+DECL_BUILTIN_NAME(__atan2_varying_half);
+DECL_BUILTIN_NAME(__atan_uniform_double);
+DECL_BUILTIN_NAME(__atan_uniform_float);
+DECL_BUILTIN_NAME(__atan_uniform_half);
+DECL_BUILTIN_NAME(__atan_varying_double);
+DECL_BUILTIN_NAME(__atan_varying_float);
+DECL_BUILTIN_NAME(__atan_varying_half);
+DECL_BUILTIN_NAME(__atomic_add_int32_global);
+DECL_BUILTIN_NAME(__atomic_add_int64_global);
+DECL_BUILTIN_NAME(__atomic_add_uniform_int32_global);
+DECL_BUILTIN_NAME(__atomic_add_uniform_int64_global);
+DECL_BUILTIN_NAME(__atomic_and_int32_global);
+DECL_BUILTIN_NAME(__atomic_and_int64_global);
+DECL_BUILTIN_NAME(__atomic_and_uniform_int32_global);
+DECL_BUILTIN_NAME(__atomic_and_uniform_int64_global);
+DECL_BUILTIN_NAME(__atomic_compare_exchange_double_global);
+DECL_BUILTIN_NAME(__atomic_compare_exchange_float_global);
+DECL_BUILTIN_NAME(__atomic_compare_exchange_int32_global);
+DECL_BUILTIN_NAME(__atomic_compare_exchange_int64_global);
+DECL_BUILTIN_NAME(__atomic_compare_exchange_uniform_double_global);
+DECL_BUILTIN_NAME(__atomic_compare_exchange_uniform_float_global);
+DECL_BUILTIN_NAME(__atomic_compare_exchange_uniform_int32_global);
+DECL_BUILTIN_NAME(__atomic_compare_exchange_uniform_int64_global);
+DECL_BUILTIN_NAME(__atomic_max_uniform_int32_global);
+DECL_BUILTIN_NAME(__atomic_max_uniform_int64_global);
+DECL_BUILTIN_NAME(__atomic_min_uniform_int32_global);
+DECL_BUILTIN_NAME(__atomic_min_uniform_int64_global);
+DECL_BUILTIN_NAME(__atomic_or_int32_global);
+DECL_BUILTIN_NAME(__atomic_or_int64_global);
+DECL_BUILTIN_NAME(__atomic_or_uniform_int32_global);
+DECL_BUILTIN_NAME(__atomic_or_uniform_int64_global);
+DECL_BUILTIN_NAME(__atomic_sub_int32_global);
+DECL_BUILTIN_NAME(__atomic_sub_int64_global);
+DECL_BUILTIN_NAME(__atomic_sub_uniform_int32_global);
+DECL_BUILTIN_NAME(__atomic_sub_uniform_int64_global);
+DECL_BUILTIN_NAME(__atomic_swap_double_global);
+DECL_BUILTIN_NAME(__atomic_swap_float_global);
+DECL_BUILTIN_NAME(__atomic_swap_int32_global);
+DECL_BUILTIN_NAME(__atomic_swap_int64_global);
+DECL_BUILTIN_NAME(__atomic_swap_uniform_double_global);
+DECL_BUILTIN_NAME(__atomic_swap_uniform_float_global);
+DECL_BUILTIN_NAME(__atomic_swap_uniform_int32_global);
+DECL_BUILTIN_NAME(__atomic_swap_uniform_int64_global);
+DECL_BUILTIN_NAME(__atomic_umax_uniform_uint32_global);
+DECL_BUILTIN_NAME(__atomic_umax_uniform_uint64_global);
+DECL_BUILTIN_NAME(__atomic_umin_uniform_uint32_global);
+DECL_BUILTIN_NAME(__atomic_umin_uniform_uint64_global);
+DECL_BUILTIN_NAME(__atomic_xor_int32_global);
+DECL_BUILTIN_NAME(__atomic_xor_int64_global);
+DECL_BUILTIN_NAME(__atomic_xor_uniform_int32_global);
+DECL_BUILTIN_NAME(__atomic_xor_uniform_int64_global);
+DECL_BUILTIN_NAME(__avg_down_int16);
+DECL_BUILTIN_NAME(__avg_down_int8);
+DECL_BUILTIN_NAME(__avg_down_uint16);
+DECL_BUILTIN_NAME(__avg_down_uint8);
+DECL_BUILTIN_NAME(__avg_up_int16);
+DECL_BUILTIN_NAME(__avg_up_int8);
+DECL_BUILTIN_NAME(__avg_up_uint16);
+DECL_BUILTIN_NAME(__avg_up_uint8);
+DECL_BUILTIN_NAME(__broadcast_double);
+DECL_BUILTIN_NAME(__broadcast_float);
+DECL_BUILTIN_NAME(__broadcast_half);
+DECL_BUILTIN_NAME(__broadcast_i16);
+DECL_BUILTIN_NAME(__broadcast_i32);
+DECL_BUILTIN_NAME(__broadcast_i64);
+DECL_BUILTIN_NAME(__broadcast_i8);
+DECL_BUILTIN_NAME(__cast_mask_to_i1);
+DECL_BUILTIN_NAME(__cast_mask_to_i16);
+DECL_BUILTIN_NAME(__cast_mask_to_i32);
+DECL_BUILTIN_NAME(__cast_mask_to_i64);
+DECL_BUILTIN_NAME(__cast_mask_to_i8);
+DECL_BUILTIN_NAME(__ceil_uniform_double);
+DECL_BUILTIN_NAME(__ceil_uniform_float);
+DECL_BUILTIN_NAME(__ceil_uniform_half);
+DECL_BUILTIN_NAME(__ceil_varying_double);
+DECL_BUILTIN_NAME(__ceil_varying_float);
+DECL_BUILTIN_NAME(__ceil_varying_half);
+DECL_BUILTIN_NAME(__clock);
+DECL_BUILTIN_NAME(__cos_uniform_double);
+DECL_BUILTIN_NAME(__cos_uniform_float);
+DECL_BUILTIN_NAME(__cos_uniform_half);
+DECL_BUILTIN_NAME(__cos_varying_double);
+DECL_BUILTIN_NAME(__cos_varying_float);
+DECL_BUILTIN_NAME(__cos_varying_half);
+DECL_BUILTIN_NAME(__count_leading_zeros_i32);
+DECL_BUILTIN_NAME(__count_leading_zeros_i64);
+DECL_BUILTIN_NAME(__count_trailing_zeros_i32);
+DECL_BUILTIN_NAME(__count_trailing_zeros_i64);
+DECL_BUILTIN_NAME(__delete_uniform_32rt);
+DECL_BUILTIN_NAME(__delete_uniform_64rt);
+DECL_BUILTIN_NAME(__delete_varying_32rt);
+DECL_BUILTIN_NAME(__delete_varying_64rt);
+DECL_BUILTIN_NAME(__do_assert_uniform);
+DECL_BUILTIN_NAME(__do_assert_varying);
+DECL_BUILTIN_NAME(__do_assume_uniform);
+DECL_BUILTIN_NAME(__do_print);
+DECL_BUILTIN_NAME(__doublebits_uniform_int64);
+DECL_BUILTIN_NAME(__doublebits_varying_int64);
+DECL_BUILTIN_NAME(__exclusive_scan_add_double);
+DECL_BUILTIN_NAME(__exclusive_scan_add_float);
+DECL_BUILTIN_NAME(__exclusive_scan_add_half);
+DECL_BUILTIN_NAME(__exclusive_scan_add_i32);
+DECL_BUILTIN_NAME(__exclusive_scan_add_i64);
+DECL_BUILTIN_NAME(__exclusive_scan_and_i32);
+DECL_BUILTIN_NAME(__exclusive_scan_and_i64);
+DECL_BUILTIN_NAME(__exclusive_scan_or_i32);
+DECL_BUILTIN_NAME(__exclusive_scan_or_i64);
+DECL_BUILTIN_NAME(__exp_uniform_double);
+DECL_BUILTIN_NAME(__exp_uniform_float);
+DECL_BUILTIN_NAME(__exp_uniform_half);
+DECL_BUILTIN_NAME(__exp_varying_double);
+DECL_BUILTIN_NAME(__exp_varying_float);
+DECL_BUILTIN_NAME(__exp_varying_half);
+DECL_BUILTIN_NAME(__extract_bool);
+DECL_BUILTIN_NAME(__extract_int16);
+DECL_BUILTIN_NAME(__extract_int32);
+DECL_BUILTIN_NAME(__extract_int64);
+DECL_BUILTIN_NAME(__extract_int8);
+DECL_BUILTIN_NAME(__extract_mask_hi);
+DECL_BUILTIN_NAME(__extract_mask_low);
+DECL_BUILTIN_NAME(__fast_masked_vload);
+DECL_BUILTIN_NAME(__fastmath);
+DECL_BUILTIN_NAME(__floatbits_uniform_int32);
+DECL_BUILTIN_NAME(__floatbits_varying_int32);
+DECL_BUILTIN_NAME(__float_to_half_uniform);
+DECL_BUILTIN_NAME(__float_to_half_varying);
+DECL_BUILTIN_NAME(__floor_uniform_double);
+DECL_BUILTIN_NAME(__floor_uniform_float);
+DECL_BUILTIN_NAME(__floor_uniform_half);
+DECL_BUILTIN_NAME(__floor_varying_double);
+DECL_BUILTIN_NAME(__floor_varying_float);
+DECL_BUILTIN_NAME(__floor_varying_half);
+DECL_BUILTIN_NAME(__gather32_double);
+DECL_BUILTIN_NAME(__gather32_float);
+DECL_BUILTIN_NAME(__gather32_generic_double);
+DECL_BUILTIN_NAME(__gather32_generic_float);
+DECL_BUILTIN_NAME(__gather32_generic_half);
+DECL_BUILTIN_NAME(__gather32_generic_i16);
+DECL_BUILTIN_NAME(__gather32_generic_i32);
+DECL_BUILTIN_NAME(__gather32_generic_i64);
+DECL_BUILTIN_NAME(__gather32_generic_i8);
+DECL_BUILTIN_NAME(__gather32_half);
+DECL_BUILTIN_NAME(__gather32_i16);
+DECL_BUILTIN_NAME(__gather32_i32);
+DECL_BUILTIN_NAME(__gather32_i64);
+DECL_BUILTIN_NAME(__gather32_i8);
+DECL_BUILTIN_NAME(__gather64_double);
+DECL_BUILTIN_NAME(__gather64_float);
+DECL_BUILTIN_NAME(__gather64_generic_double);
+DECL_BUILTIN_NAME(__gather64_generic_float);
+DECL_BUILTIN_NAME(__gather64_generic_half);
+DECL_BUILTIN_NAME(__gather64_generic_i16);
+DECL_BUILTIN_NAME(__gather64_generic_i32);
+DECL_BUILTIN_NAME(__gather64_generic_i64);
+DECL_BUILTIN_NAME(__gather64_generic_i8);
+DECL_BUILTIN_NAME(__gather64_half);
+DECL_BUILTIN_NAME(__gather64_i16);
+DECL_BUILTIN_NAME(__gather64_i32);
+DECL_BUILTIN_NAME(__gather64_i64);
+DECL_BUILTIN_NAME(__gather64_i8);
+DECL_BUILTIN_NAME(__gather_base_offsets32_double);
+DECL_BUILTIN_NAME(__gather_base_offsets32_float);
+DECL_BUILTIN_NAME(__gather_base_offsets32_half);
+DECL_BUILTIN_NAME(__gather_base_offsets32_i16);
+DECL_BUILTIN_NAME(__gather_base_offsets32_i32);
+DECL_BUILTIN_NAME(__gather_base_offsets32_i64);
+DECL_BUILTIN_NAME(__gather_base_offsets32_i8);
+DECL_BUILTIN_NAME(__gather_base_offsets64_double);
+DECL_BUILTIN_NAME(__gather_base_offsets64_float);
+DECL_BUILTIN_NAME(__gather_base_offsets64_half);
+DECL_BUILTIN_NAME(__gather_base_offsets64_i16);
+DECL_BUILTIN_NAME(__gather_base_offsets64_i32);
+DECL_BUILTIN_NAME(__gather_base_offsets64_i64);
+DECL_BUILTIN_NAME(__gather_base_offsets64_i8);
+DECL_BUILTIN_NAME(__gather_elt32_double);
+DECL_BUILTIN_NAME(__gather_elt32_float);
+DECL_BUILTIN_NAME(__gather_elt32_half);
+DECL_BUILTIN_NAME(__gather_elt32_i16);
+DECL_BUILTIN_NAME(__gather_elt32_i32);
+DECL_BUILTIN_NAME(__gather_elt32_i64);
+DECL_BUILTIN_NAME(__gather_elt32_i8);
+DECL_BUILTIN_NAME(__gather_elt64_double);
+DECL_BUILTIN_NAME(__gather_elt64_float);
+DECL_BUILTIN_NAME(__gather_elt64_half);
+DECL_BUILTIN_NAME(__gather_elt64_i16);
+DECL_BUILTIN_NAME(__gather_elt64_i32);
+DECL_BUILTIN_NAME(__gather_elt64_i64);
+DECL_BUILTIN_NAME(__gather_elt64_i8);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets32_double);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets32_float);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets32_half);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets32_i16);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets32_i32);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets32_i64);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets32_i8);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets64_double);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets64_float);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets64_half);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets64_i16);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets64_i32);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets64_i64);
+DECL_BUILTIN_NAME(__gather_factored_base_offsets64_i8);
+DECL_BUILTIN_NAME(__get_system_isa);
+DECL_BUILTIN_NAME(__halfbits_uniform_int16);
+DECL_BUILTIN_NAME(__halfbits_varying_int16);
+DECL_BUILTIN_NAME(__half_to_float_uniform);
+DECL_BUILTIN_NAME(__half_to_float_varying);
+DECL_BUILTIN_NAME(__idiv_int16);
+DECL_BUILTIN_NAME(__idiv_int32);
+DECL_BUILTIN_NAME(__idiv_int8);
+DECL_BUILTIN_NAME(__idiv_uint16);
+DECL_BUILTIN_NAME(__idiv_uint32);
+DECL_BUILTIN_NAME(__idiv_uint8);
+DECL_BUILTIN_NAME(__insert_bool);
+DECL_BUILTIN_NAME(__insert_int16);
+DECL_BUILTIN_NAME(__insert_int32);
+DECL_BUILTIN_NAME(__insert_int64);
+DECL_BUILTIN_NAME(__insert_int8);
+DECL_BUILTIN_NAME(__intbits_uniform_double);
+DECL_BUILTIN_NAME(__intbits_uniform_float);
+DECL_BUILTIN_NAME(__intbits_uniform_half);
+DECL_BUILTIN_NAME(__intbits_varying_double);
+DECL_BUILTIN_NAME(__intbits_varying_float);
+DECL_BUILTIN_NAME(__intbits_varying_half);
+DECL_BUILTIN_NAME(__is_compile_time_constant_mask);
+DECL_BUILTIN_NAME(__is_compile_time_constant_uniform_int32);
+DECL_BUILTIN_NAME(__is_compile_time_constant_varying_int32);
+DECL_BUILTIN_NAME(ISPCAlloc);
+DECL_BUILTIN_NAME(ISPCLaunch);
+DECL_BUILTIN_NAME(ISPCSync);
+DECL_BUILTIN_NAME(__keep_funcs_live);
+DECL_BUILTIN_NAME(__log_uniform_double);
+DECL_BUILTIN_NAME(__log_uniform_float);
+DECL_BUILTIN_NAME(__log_uniform_half);
+DECL_BUILTIN_NAME(__log_varying_double);
+DECL_BUILTIN_NAME(__log_varying_float);
+DECL_BUILTIN_NAME(__log_varying_half);
+DECL_BUILTIN_NAME(__masked_load_blend_double);
+DECL_BUILTIN_NAME(__masked_load_blend_float);
+DECL_BUILTIN_NAME(__masked_load_blend_half);
+DECL_BUILTIN_NAME(__masked_load_blend_i16);
+DECL_BUILTIN_NAME(__masked_load_blend_i32);
+DECL_BUILTIN_NAME(__masked_load_blend_i64);
+DECL_BUILTIN_NAME(__masked_load_blend_i8);
+DECL_BUILTIN_NAME(__masked_load_double);
+DECL_BUILTIN_NAME(__masked_load_float);
+DECL_BUILTIN_NAME(__masked_load_half);
+DECL_BUILTIN_NAME(__masked_load_i16);
+DECL_BUILTIN_NAME(__masked_load_i32);
+DECL_BUILTIN_NAME(__masked_load_i64);
+DECL_BUILTIN_NAME(__masked_load_i8);
+DECL_BUILTIN_NAME(__masked_store_blend_double);
+DECL_BUILTIN_NAME(__masked_store_blend_float);
+DECL_BUILTIN_NAME(__masked_store_blend_half);
+DECL_BUILTIN_NAME(__masked_store_blend_i16);
+DECL_BUILTIN_NAME(__masked_store_blend_i32);
+DECL_BUILTIN_NAME(__masked_store_blend_i64);
+DECL_BUILTIN_NAME(__masked_store_blend_i8);
+DECL_BUILTIN_NAME(__masked_store_double);
+DECL_BUILTIN_NAME(__masked_store_float);
+DECL_BUILTIN_NAME(__masked_store_half);
+DECL_BUILTIN_NAME(__masked_store_i16);
+DECL_BUILTIN_NAME(__masked_store_i32);
+DECL_BUILTIN_NAME(__masked_store_i64);
+DECL_BUILTIN_NAME(__masked_store_i8);
+DECL_BUILTIN_NAME(__max_uniform_double);
+DECL_BUILTIN_NAME(__max_uniform_float);
+DECL_BUILTIN_NAME(__max_uniform_half);
+DECL_BUILTIN_NAME(__max_uniform_int32);
+DECL_BUILTIN_NAME(__max_uniform_int64);
+DECL_BUILTIN_NAME(__max_uniform_uint32);
+DECL_BUILTIN_NAME(__max_uniform_uint64);
+DECL_BUILTIN_NAME(__max_varying_double);
+DECL_BUILTIN_NAME(__max_varying_float);
+DECL_BUILTIN_NAME(__max_varying_half);
+DECL_BUILTIN_NAME(__max_varying_int32);
+DECL_BUILTIN_NAME(__max_varying_int64);
+DECL_BUILTIN_NAME(__max_varying_uint32);
+DECL_BUILTIN_NAME(__max_varying_uint64);
+DECL_BUILTIN_NAME(__memcpy32);
+DECL_BUILTIN_NAME(__memcpy64);
+DECL_BUILTIN_NAME(__memmove32);
+DECL_BUILTIN_NAME(__memmove64);
+DECL_BUILTIN_NAME(__memory_barrier);
+DECL_BUILTIN_NAME(__memset32);
+DECL_BUILTIN_NAME(__memset64);
+DECL_BUILTIN_NAME(__min_uniform_double);
+DECL_BUILTIN_NAME(__min_uniform_float);
+DECL_BUILTIN_NAME(__min_uniform_half);
+DECL_BUILTIN_NAME(__min_uniform_int32);
+DECL_BUILTIN_NAME(__min_uniform_int64);
+DECL_BUILTIN_NAME(__min_uniform_uint32);
+DECL_BUILTIN_NAME(__min_uniform_uint64);
+DECL_BUILTIN_NAME(__min_varying_double);
+DECL_BUILTIN_NAME(__min_varying_float);
+DECL_BUILTIN_NAME(__min_varying_half);
+DECL_BUILTIN_NAME(__min_varying_int32);
+DECL_BUILTIN_NAME(__min_varying_int64);
+DECL_BUILTIN_NAME(__min_varying_uint32);
+DECL_BUILTIN_NAME(__min_varying_uint64);
+DECL_BUILTIN_NAME(__movmsk);
+DECL_BUILTIN_NAME(__new_uniform_32rt);
+DECL_BUILTIN_NAME(__new_uniform_64rt);
+DECL_BUILTIN_NAME(__new_varying32_32rt);
+DECL_BUILTIN_NAME(__new_varying32_64rt);
+DECL_BUILTIN_NAME(__new_varying64_64rt);
+DECL_BUILTIN_NAME(__none);
+DECL_BUILTIN_NAME(__num_cores);
+DECL_BUILTIN_NAME(__packed_load_activei32);
+DECL_BUILTIN_NAME(__packed_load_activei64);
+DECL_BUILTIN_NAME(__packed_store_active2i32);
+DECL_BUILTIN_NAME(__packed_store_active2i64);
+DECL_BUILTIN_NAME(__packed_store_activei32);
+DECL_BUILTIN_NAME(__packed_store_activei64);
+DECL_BUILTIN_NAME(__padds_ui16);
+DECL_BUILTIN_NAME(__padds_ui32);
+DECL_BUILTIN_NAME(__padds_ui64);
+DECL_BUILTIN_NAME(__padds_ui8);
+DECL_BUILTIN_NAME(__padds_vi16);
+DECL_BUILTIN_NAME(__padds_vi32);
+DECL_BUILTIN_NAME(__padds_vi64);
+DECL_BUILTIN_NAME(__padds_vi8);
+DECL_BUILTIN_NAME(__paddus_ui16);
+DECL_BUILTIN_NAME(__paddus_ui32);
+DECL_BUILTIN_NAME(__paddus_ui64);
+DECL_BUILTIN_NAME(__paddus_ui8);
+DECL_BUILTIN_NAME(__paddus_vi16);
+DECL_BUILTIN_NAME(__paddus_vi32);
+DECL_BUILTIN_NAME(__paddus_vi64);
+DECL_BUILTIN_NAME(__paddus_vi8);
+DECL_BUILTIN_NAME(__pmuls_ui16);
+DECL_BUILTIN_NAME(__pmuls_ui32);
+DECL_BUILTIN_NAME(__pmuls_ui8);
+DECL_BUILTIN_NAME(__pmuls_vi16);
+DECL_BUILTIN_NAME(__pmuls_vi32);
+DECL_BUILTIN_NAME(__pmuls_vi8);
+DECL_BUILTIN_NAME(__pmulus_ui16);
+DECL_BUILTIN_NAME(__pmulus_ui32);
+DECL_BUILTIN_NAME(__pmulus_ui8);
+DECL_BUILTIN_NAME(__pmulus_vi16);
+DECL_BUILTIN_NAME(__pmulus_vi32);
+DECL_BUILTIN_NAME(__pmulus_vi8);
+DECL_BUILTIN_NAME(__popcnt_int32);
+DECL_BUILTIN_NAME(__popcnt_int64);
+DECL_BUILTIN_NAME(__pow_uniform_double);
+DECL_BUILTIN_NAME(__pow_uniform_float);
+DECL_BUILTIN_NAME(__pow_uniform_half);
+DECL_BUILTIN_NAME(__pow_varying_double);
+DECL_BUILTIN_NAME(__pow_varying_float);
+DECL_BUILTIN_NAME(__pow_varying_half);
+DECL_BUILTIN_NAME(__prefetch_read_sized_uniform_1);
+DECL_BUILTIN_NAME(__prefetch_read_sized_uniform_2);
+DECL_BUILTIN_NAME(__prefetch_read_sized_uniform_3);
+DECL_BUILTIN_NAME(__prefetch_read_sized_uniform_nt);
+DECL_BUILTIN_NAME(__prefetch_read_sized_varying_1);
+DECL_BUILTIN_NAME(__prefetch_read_sized_varying_2);
+DECL_BUILTIN_NAME(__prefetch_read_sized_varying_3);
+DECL_BUILTIN_NAME(__prefetch_read_sized_varying_nt);
+DECL_BUILTIN_NAME(__prefetch_read_uniform_1);
+DECL_BUILTIN_NAME(__prefetch_read_uniform_2);
+DECL_BUILTIN_NAME(__prefetch_read_uniform_3);
+DECL_BUILTIN_NAME(__prefetch_read_uniform_nt);
+DECL_BUILTIN_NAME(__prefetch_read_varying_1);
+DECL_BUILTIN_NAME(__prefetch_read_varying_1_native);
+DECL_BUILTIN_NAME(__prefetch_read_varying_2);
+DECL_BUILTIN_NAME(__prefetch_read_varying_2_native);
+DECL_BUILTIN_NAME(__prefetch_read_varying_3);
+DECL_BUILTIN_NAME(__prefetch_read_varying_3_native);
+DECL_BUILTIN_NAME(__prefetch_read_varying_nt);
+DECL_BUILTIN_NAME(__prefetch_read_varying_nt_native);
+DECL_BUILTIN_NAME(__prefetch_write_uniform_1);
+DECL_BUILTIN_NAME(__prefetch_write_uniform_2);
+DECL_BUILTIN_NAME(__prefetch_write_uniform_3);
+DECL_BUILTIN_NAME(__prefetch_write_varying_1);
+DECL_BUILTIN_NAME(__prefetch_write_varying_1_native);
+DECL_BUILTIN_NAME(__prefetch_write_varying_2);
+DECL_BUILTIN_NAME(__prefetch_write_varying_2_native);
+DECL_BUILTIN_NAME(__prefetch_write_varying_3);
+DECL_BUILTIN_NAME(__prefetch_write_varying_3_native);
+DECL_BUILTIN_NAME(__pseudo_gather32_double);
+DECL_BUILTIN_NAME(__pseudo_gather32_float);
+DECL_BUILTIN_NAME(__pseudo_gather32_half);
+DECL_BUILTIN_NAME(__pseudo_gather32_i16);
+DECL_BUILTIN_NAME(__pseudo_gather32_i32);
+DECL_BUILTIN_NAME(__pseudo_gather32_i64);
+DECL_BUILTIN_NAME(__pseudo_gather32_i8);
+DECL_BUILTIN_NAME(__pseudo_gather64_double);
+DECL_BUILTIN_NAME(__pseudo_gather64_float);
+DECL_BUILTIN_NAME(__pseudo_gather64_half);
+DECL_BUILTIN_NAME(__pseudo_gather64_i16);
+DECL_BUILTIN_NAME(__pseudo_gather64_i32);
+DECL_BUILTIN_NAME(__pseudo_gather64_i64);
+DECL_BUILTIN_NAME(__pseudo_gather64_i8);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets32_double);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets32_float);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets32_half);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets32_i16);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets32_i32);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets32_i64);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets32_i8);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets64_double);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets64_float);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets64_half);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets64_i16);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets64_i32);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets64_i64);
+DECL_BUILTIN_NAME(__pseudo_gather_base_offsets64_i8);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets32_double);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets32_float);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets32_half);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets32_i16);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets32_i32);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets32_i64);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets32_i8);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets64_double);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets64_float);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets64_half);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets64_i16);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets64_i32);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets64_i64);
+DECL_BUILTIN_NAME(__pseudo_gather_factored_base_offsets64_i8);
+DECL_BUILTIN_NAME(__pseudo_masked_store_double);
+DECL_BUILTIN_NAME(__pseudo_masked_store_float);
+DECL_BUILTIN_NAME(__pseudo_masked_store_half);
+DECL_BUILTIN_NAME(__pseudo_masked_store_i16);
+DECL_BUILTIN_NAME(__pseudo_masked_store_i32);
+DECL_BUILTIN_NAME(__pseudo_masked_store_i64);
+DECL_BUILTIN_NAME(__pseudo_masked_store_i8);
+DECL_BUILTIN_NAME(__pseudo_prefetch_read_varying_1);
+DECL_BUILTIN_NAME(__pseudo_prefetch_read_varying_1_native);
+DECL_BUILTIN_NAME(__pseudo_prefetch_read_varying_2);
+DECL_BUILTIN_NAME(__pseudo_prefetch_read_varying_2_native);
+DECL_BUILTIN_NAME(__pseudo_prefetch_read_varying_3);
+DECL_BUILTIN_NAME(__pseudo_prefetch_read_varying_3_native);
+DECL_BUILTIN_NAME(__pseudo_prefetch_read_varying_nt);
+DECL_BUILTIN_NAME(__pseudo_prefetch_read_varying_nt_native);
+DECL_BUILTIN_NAME(__pseudo_prefetch_write_varying_1);
+DECL_BUILTIN_NAME(__pseudo_prefetch_write_varying_1_native);
+DECL_BUILTIN_NAME(__pseudo_prefetch_write_varying_2);
+DECL_BUILTIN_NAME(__pseudo_prefetch_write_varying_2_native);
+DECL_BUILTIN_NAME(__pseudo_prefetch_write_varying_3);
+DECL_BUILTIN_NAME(__pseudo_prefetch_write_varying_3_native);
+DECL_BUILTIN_NAME(__pseudo_scatter32_double);
+DECL_BUILTIN_NAME(__pseudo_scatter32_float);
+DECL_BUILTIN_NAME(__pseudo_scatter32_half);
+DECL_BUILTIN_NAME(__pseudo_scatter32_i16);
+DECL_BUILTIN_NAME(__pseudo_scatter32_i32);
+DECL_BUILTIN_NAME(__pseudo_scatter32_i64);
+DECL_BUILTIN_NAME(__pseudo_scatter32_i8);
+DECL_BUILTIN_NAME(__pseudo_scatter64_double);
+DECL_BUILTIN_NAME(__pseudo_scatter64_float);
+DECL_BUILTIN_NAME(__pseudo_scatter64_half);
+DECL_BUILTIN_NAME(__pseudo_scatter64_i16);
+DECL_BUILTIN_NAME(__pseudo_scatter64_i32);
+DECL_BUILTIN_NAME(__pseudo_scatter64_i64);
+DECL_BUILTIN_NAME(__pseudo_scatter64_i8);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets32_double);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets32_float);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets32_half);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets32_i16);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets32_i32);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets32_i64);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets32_i8);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets64_double);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets64_float);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets64_half);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets64_i16);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets64_i32);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets64_i64);
+DECL_BUILTIN_NAME(__pseudo_scatter_base_offsets64_i8);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets32_double);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets32_float);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets32_half);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets32_i16);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets32_i32);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets32_i64);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets32_i8);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets64_double);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets64_float);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets64_half);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets64_i16);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets64_i32);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets64_i64);
+DECL_BUILTIN_NAME(__pseudo_scatter_factored_base_offsets64_i8);
+DECL_BUILTIN_NAME(__psubs_ui16);
+DECL_BUILTIN_NAME(__psubs_ui32);
+DECL_BUILTIN_NAME(__psubs_ui64);
+DECL_BUILTIN_NAME(__psubs_ui8);
+DECL_BUILTIN_NAME(__psubs_vi16);
+DECL_BUILTIN_NAME(__psubs_vi32);
+DECL_BUILTIN_NAME(__psubs_vi64);
+DECL_BUILTIN_NAME(__psubs_vi8);
+DECL_BUILTIN_NAME(__psubus_ui16);
+DECL_BUILTIN_NAME(__psubus_ui32);
+DECL_BUILTIN_NAME(__psubus_ui64);
+DECL_BUILTIN_NAME(__psubus_ui8);
+DECL_BUILTIN_NAME(__psubus_vi16);
+DECL_BUILTIN_NAME(__psubus_vi32);
+DECL_BUILTIN_NAME(__psubus_vi64);
+DECL_BUILTIN_NAME(__psubus_vi8);
+DECL_BUILTIN_NAME(__rcp_fast_uniform_double);
+DECL_BUILTIN_NAME(__rcp_fast_uniform_float);
+DECL_BUILTIN_NAME(__rcp_fast_uniform_half);
+DECL_BUILTIN_NAME(__rcp_fast_varying_double);
+DECL_BUILTIN_NAME(__rcp_fast_varying_float);
+DECL_BUILTIN_NAME(__rcp_fast_varying_half);
+DECL_BUILTIN_NAME(__rcp_uniform_double);
+DECL_BUILTIN_NAME(__rcp_uniform_float);
+DECL_BUILTIN_NAME(__rcp_uniform_half);
+DECL_BUILTIN_NAME(__rcp_varying_double);
+DECL_BUILTIN_NAME(__rcp_varying_float);
+DECL_BUILTIN_NAME(__rcp_varying_half);
+DECL_BUILTIN_NAME(__rdrand_i16);
+DECL_BUILTIN_NAME(__rdrand_i32);
+DECL_BUILTIN_NAME(__rdrand_i64);
+DECL_BUILTIN_NAME(__reduce_add_double);
+DECL_BUILTIN_NAME(__reduce_add_float);
+DECL_BUILTIN_NAME(__reduce_add_half);
+DECL_BUILTIN_NAME(__reduce_add_int16);
+DECL_BUILTIN_NAME(__reduce_add_int32);
+DECL_BUILTIN_NAME(__reduce_add_int64);
+DECL_BUILTIN_NAME(__reduce_add_int8);
+DECL_BUILTIN_NAME(__reduce_equal_double);
+DECL_BUILTIN_NAME(__reduce_equal_float);
+DECL_BUILTIN_NAME(__reduce_equal_half);
+DECL_BUILTIN_NAME(__reduce_equal_int32);
+DECL_BUILTIN_NAME(__reduce_equal_int64);
+DECL_BUILTIN_NAME(__reduce_max_double);
+DECL_BUILTIN_NAME(__reduce_max_float);
+DECL_BUILTIN_NAME(__reduce_max_half);
+DECL_BUILTIN_NAME(__reduce_max_int32);
+DECL_BUILTIN_NAME(__reduce_max_int64);
+DECL_BUILTIN_NAME(__reduce_max_uint32);
+DECL_BUILTIN_NAME(__reduce_max_uint64);
+DECL_BUILTIN_NAME(__reduce_min_double);
+DECL_BUILTIN_NAME(__reduce_min_float);
+DECL_BUILTIN_NAME(__reduce_min_half);
+DECL_BUILTIN_NAME(__reduce_min_int32);
+DECL_BUILTIN_NAME(__reduce_min_int64);
+DECL_BUILTIN_NAME(__reduce_min_uint32);
+DECL_BUILTIN_NAME(__reduce_min_uint64);
+DECL_BUILTIN_NAME(__restore_ftz_daz_flags);
+DECL_BUILTIN_NAME(__rotate_double);
+DECL_BUILTIN_NAME(__rotate_float);
+DECL_BUILTIN_NAME(__rotate_half);
+DECL_BUILTIN_NAME(__rotate_i16);
+DECL_BUILTIN_NAME(__rotate_i32);
+DECL_BUILTIN_NAME(__rotate_i64);
+DECL_BUILTIN_NAME(__rotate_i8);
+DECL_BUILTIN_NAME(__round_uniform_double);
+DECL_BUILTIN_NAME(__round_uniform_float);
+DECL_BUILTIN_NAME(__round_uniform_half);
+DECL_BUILTIN_NAME(__round_varying_double);
+DECL_BUILTIN_NAME(__round_varying_float);
+DECL_BUILTIN_NAME(__round_varying_half);
+DECL_BUILTIN_NAME(__rsqrt_fast_uniform_double);
+DECL_BUILTIN_NAME(__rsqrt_fast_uniform_float);
+DECL_BUILTIN_NAME(__rsqrt_fast_varying_double);
+DECL_BUILTIN_NAME(__rsqrt_fast_varying_float);
+DECL_BUILTIN_NAME(__rsqrt_uniform_double);
+DECL_BUILTIN_NAME(__rsqrt_uniform_float);
+DECL_BUILTIN_NAME(__rsqrt_uniform_half);
+DECL_BUILTIN_NAME(__rsqrt_varying_double);
+DECL_BUILTIN_NAME(__rsqrt_varying_float);
+DECL_BUILTIN_NAME(__rsqrt_varying_half);
+DECL_BUILTIN_NAME(__saturating_add_i16);
+DECL_BUILTIN_NAME(__saturating_add_i32);
+DECL_BUILTIN_NAME(__saturating_add_i64);
+DECL_BUILTIN_NAME(__saturating_add_i8);
+DECL_BUILTIN_NAME(__saturating_add_ui16);
+DECL_BUILTIN_NAME(__saturating_add_ui32);
+DECL_BUILTIN_NAME(__saturating_add_ui64);
+DECL_BUILTIN_NAME(__saturating_add_ui8);
+DECL_BUILTIN_NAME(__saturating_mul_i16);
+DECL_BUILTIN_NAME(__saturating_mul_i32);
+DECL_BUILTIN_NAME(__saturating_mul_i8);
+DECL_BUILTIN_NAME(__saturating_mul_ui16);
+DECL_BUILTIN_NAME(__saturating_mul_ui32);
+DECL_BUILTIN_NAME(__saturating_mul_ui8);
+DECL_BUILTIN_NAME(__scatter32_double);
+DECL_BUILTIN_NAME(__scatter32_float);
+DECL_BUILTIN_NAME(__scatter32_generic_double);
+DECL_BUILTIN_NAME(__scatter32_generic_float);
+DECL_BUILTIN_NAME(__scatter32_generic_half);
+DECL_BUILTIN_NAME(__scatter32_generic_i16);
+DECL_BUILTIN_NAME(__scatter32_generic_i32);
+DECL_BUILTIN_NAME(__scatter32_generic_i64);
+DECL_BUILTIN_NAME(__scatter32_generic_i8);
+DECL_BUILTIN_NAME(__scatter32_half);
+DECL_BUILTIN_NAME(__scatter32_i16);
+DECL_BUILTIN_NAME(__scatter32_i32);
+DECL_BUILTIN_NAME(__scatter32_i64);
+DECL_BUILTIN_NAME(__scatter32_i8);
+DECL_BUILTIN_NAME(__scatter64_double);
+DECL_BUILTIN_NAME(__scatter64_float);
+DECL_BUILTIN_NAME(__scatter64_generic_double);
+DECL_BUILTIN_NAME(__scatter64_generic_float);
+DECL_BUILTIN_NAME(__scatter64_generic_half);
+DECL_BUILTIN_NAME(__scatter64_generic_i16);
+DECL_BUILTIN_NAME(__scatter64_generic_i32);
+DECL_BUILTIN_NAME(__scatter64_generic_i64);
+DECL_BUILTIN_NAME(__scatter64_generic_i8);
+DECL_BUILTIN_NAME(__scatter64_half);
+DECL_BUILTIN_NAME(__scatter64_i16);
+DECL_BUILTIN_NAME(__scatter64_i32);
+DECL_BUILTIN_NAME(__scatter64_i64);
+DECL_BUILTIN_NAME(__scatter64_i8);
+DECL_BUILTIN_NAME(__scatter_base_offsets32_double);
+DECL_BUILTIN_NAME(__scatter_base_offsets32_float);
+DECL_BUILTIN_NAME(__scatter_base_offsets32_half);
+DECL_BUILTIN_NAME(__scatter_base_offsets32_i16);
+DECL_BUILTIN_NAME(__scatter_base_offsets32_i32);
+DECL_BUILTIN_NAME(__scatter_base_offsets32_i64);
+DECL_BUILTIN_NAME(__scatter_base_offsets32_i8);
+DECL_BUILTIN_NAME(__scatter_base_offsets64_double);
+DECL_BUILTIN_NAME(__scatter_base_offsets64_float);
+DECL_BUILTIN_NAME(__scatter_base_offsets64_half);
+DECL_BUILTIN_NAME(__scatter_base_offsets64_i16);
+DECL_BUILTIN_NAME(__scatter_base_offsets64_i32);
+DECL_BUILTIN_NAME(__scatter_base_offsets64_i64);
+DECL_BUILTIN_NAME(__scatter_base_offsets64_i8);
+DECL_BUILTIN_NAME(__scatter_elt32_double);
+DECL_BUILTIN_NAME(__scatter_elt32_float);
+DECL_BUILTIN_NAME(__scatter_elt32_half);
+DECL_BUILTIN_NAME(__scatter_elt32_i16);
+DECL_BUILTIN_NAME(__scatter_elt32_i32);
+DECL_BUILTIN_NAME(__scatter_elt32_i64);
+DECL_BUILTIN_NAME(__scatter_elt32_i8);
+DECL_BUILTIN_NAME(__scatter_elt64_double);
+DECL_BUILTIN_NAME(__scatter_elt64_float);
+DECL_BUILTIN_NAME(__scatter_elt64_half);
+DECL_BUILTIN_NAME(__scatter_elt64_i16);
+DECL_BUILTIN_NAME(__scatter_elt64_i32);
+DECL_BUILTIN_NAME(__scatter_elt64_i64);
+DECL_BUILTIN_NAME(__scatter_elt64_i8);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets32_double);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets32_float);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets32_half);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets32_i16);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets32_i32);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets32_i64);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets32_i8);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets64_double);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets64_float);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets64_half);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets64_i16);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets64_i32);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets64_i64);
+DECL_BUILTIN_NAME(__scatter_factored_base_offsets64_i8);
+DECL_BUILTIN_NAME(__send_eot);
+DECL_BUILTIN_NAME(__set_ftz_daz_flags);
+DECL_BUILTIN_NAME(__set_system_isa);
+DECL_BUILTIN_NAME(__sext_uniform_bool);
+DECL_BUILTIN_NAME(__sext_varying_bool);
+DECL_BUILTIN_NAME(__shift_double);
+DECL_BUILTIN_NAME(__shift_float);
+DECL_BUILTIN_NAME(__shift_half);
+DECL_BUILTIN_NAME(__shift_i16);
+DECL_BUILTIN_NAME(__shift_i32);
+DECL_BUILTIN_NAME(__shift_i64);
+DECL_BUILTIN_NAME(__shift_i8);
+DECL_BUILTIN_NAME(__shuffle2_double);
+DECL_BUILTIN_NAME(__shuffle2_float);
+DECL_BUILTIN_NAME(__shuffle2_half);
+DECL_BUILTIN_NAME(__shuffle2_i16);
+DECL_BUILTIN_NAME(__shuffle2_i32);
+DECL_BUILTIN_NAME(__shuffle2_i64);
+DECL_BUILTIN_NAME(__shuffle2_i8);
+DECL_BUILTIN_NAME(__shuffle_double);
+DECL_BUILTIN_NAME(__shuffle_float);
+DECL_BUILTIN_NAME(__shuffle_half);
+DECL_BUILTIN_NAME(__shuffle_i16);
+DECL_BUILTIN_NAME(__shuffle_i32);
+DECL_BUILTIN_NAME(__shuffle_i64);
+DECL_BUILTIN_NAME(__shuffle_i8);
+DECL_BUILTIN_NAME(__sincos_uniform_double);
+DECL_BUILTIN_NAME(__sincos_uniform_float);
+DECL_BUILTIN_NAME(__sincos_uniform_half);
+DECL_BUILTIN_NAME(__sincos_varying_double);
+DECL_BUILTIN_NAME(__sincos_varying_float);
+DECL_BUILTIN_NAME(__sincos_varying_half);
+DECL_BUILTIN_NAME(__sin_uniform_double);
+DECL_BUILTIN_NAME(__sin_uniform_float);
+DECL_BUILTIN_NAME(__sin_uniform_half);
+DECL_BUILTIN_NAME(__sin_varying_double);
+DECL_BUILTIN_NAME(__sin_varying_float);
+DECL_BUILTIN_NAME(__sin_varying_half);
+DECL_BUILTIN_NAME(__soa_to_aos2_double);
+DECL_BUILTIN_NAME(__soa_to_aos2_double1);
+DECL_BUILTIN_NAME(__soa_to_aos2_double16);
+DECL_BUILTIN_NAME(__soa_to_aos2_double32);
+DECL_BUILTIN_NAME(__soa_to_aos2_double4);
+DECL_BUILTIN_NAME(__soa_to_aos2_double64);
+DECL_BUILTIN_NAME(__soa_to_aos2_double8);
+DECL_BUILTIN_NAME(__soa_to_aos2_float);
+DECL_BUILTIN_NAME(__soa_to_aos2_float1);
+DECL_BUILTIN_NAME(__soa_to_aos2_float16);
+DECL_BUILTIN_NAME(__soa_to_aos2_float32);
+DECL_BUILTIN_NAME(__soa_to_aos2_float4);
+DECL_BUILTIN_NAME(__soa_to_aos2_float64);
+DECL_BUILTIN_NAME(__soa_to_aos2_float8);
+DECL_BUILTIN_NAME(__soa_to_aos3_double);
+DECL_BUILTIN_NAME(__soa_to_aos3_double1);
+DECL_BUILTIN_NAME(__soa_to_aos3_double16);
+DECL_BUILTIN_NAME(__soa_to_aos3_double32);
+DECL_BUILTIN_NAME(__soa_to_aos3_double4);
+DECL_BUILTIN_NAME(__soa_to_aos3_double64);
+DECL_BUILTIN_NAME(__soa_to_aos3_double8);
+DECL_BUILTIN_NAME(__soa_to_aos3_float);
+DECL_BUILTIN_NAME(__soa_to_aos3_float1);
+DECL_BUILTIN_NAME(__soa_to_aos3_float16);
+DECL_BUILTIN_NAME(__soa_to_aos3_float32);
+DECL_BUILTIN_NAME(__soa_to_aos3_float4);
+DECL_BUILTIN_NAME(__soa_to_aos3_float64);
+DECL_BUILTIN_NAME(__soa_to_aos3_float8);
+DECL_BUILTIN_NAME(__soa_to_aos4_double);
+DECL_BUILTIN_NAME(__soa_to_aos4_double1);
+DECL_BUILTIN_NAME(__soa_to_aos4_double16);
+DECL_BUILTIN_NAME(__soa_to_aos4_double32);
+DECL_BUILTIN_NAME(__soa_to_aos4_double4);
+DECL_BUILTIN_NAME(__soa_to_aos4_double64);
+DECL_BUILTIN_NAME(__soa_to_aos4_double8);
+DECL_BUILTIN_NAME(__soa_to_aos4_float);
+DECL_BUILTIN_NAME(__soa_to_aos4_float1);
+DECL_BUILTIN_NAME(__soa_to_aos4_float16);
+DECL_BUILTIN_NAME(__soa_to_aos4_float32);
+DECL_BUILTIN_NAME(__soa_to_aos4_float4);
+DECL_BUILTIN_NAME(__soa_to_aos4_float64);
+DECL_BUILTIN_NAME(__soa_to_aos4_float8);
+DECL_BUILTIN_NAME(__sqrt_uniform_double);
+DECL_BUILTIN_NAME(__sqrt_uniform_float);
+DECL_BUILTIN_NAME(__sqrt_uniform_half);
+DECL_BUILTIN_NAME(__sqrt_varying_double);
+DECL_BUILTIN_NAME(__sqrt_varying_float);
+DECL_BUILTIN_NAME(__sqrt_varying_half);
+DECL_BUILTIN_NAME(__stdlib_acosf);
+DECL_BUILTIN_NAME(__stdlib_asin);
+DECL_BUILTIN_NAME(__stdlib_asinf);
+DECL_BUILTIN_NAME(__stdlib_atan);
+DECL_BUILTIN_NAME(__stdlib_atan2);
+DECL_BUILTIN_NAME(__stdlib_atan2f);
+DECL_BUILTIN_NAME(__stdlib_atanf);
+DECL_BUILTIN_NAME(__stdlib_cos);
+DECL_BUILTIN_NAME(__stdlib_cosf);
+DECL_BUILTIN_NAME(__stdlib_exp);
+DECL_BUILTIN_NAME(__stdlib_expf);
+DECL_BUILTIN_NAME(__stdlib_log);
+DECL_BUILTIN_NAME(__stdlib_logf);
+DECL_BUILTIN_NAME(__stdlib_pow);
+DECL_BUILTIN_NAME(__stdlib_powf);
+DECL_BUILTIN_NAME(__stdlib_sin);
+DECL_BUILTIN_NAME(__stdlib_sincos);
+DECL_BUILTIN_NAME(__stdlib_sincosf);
+DECL_BUILTIN_NAME(__stdlib_sinf);
+DECL_BUILTIN_NAME(__stdlib_tan);
+DECL_BUILTIN_NAME(__stdlib_tanf);
+DECL_BUILTIN_NAME(__streaming_load_uniform_double);
+DECL_BUILTIN_NAME(__streaming_load_uniform_float);
+DECL_BUILTIN_NAME(__streaming_load_uniform_half);
+DECL_BUILTIN_NAME(__streaming_load_uniform_i16);
+DECL_BUILTIN_NAME(__streaming_load_uniform_i32);
+DECL_BUILTIN_NAME(__streaming_load_uniform_i64);
+DECL_BUILTIN_NAME(__streaming_load_uniform_i8);
+DECL_BUILTIN_NAME(__streaming_load_varying_double);
+DECL_BUILTIN_NAME(__streaming_load_varying_float);
+DECL_BUILTIN_NAME(__streaming_load_varying_half);
+DECL_BUILTIN_NAME(__streaming_load_varying_i16);
+DECL_BUILTIN_NAME(__streaming_load_varying_i32);
+DECL_BUILTIN_NAME(__streaming_load_varying_i64);
+DECL_BUILTIN_NAME(__streaming_load_varying_i8);
+DECL_BUILTIN_NAME(__streaming_store_uniform_double);
+DECL_BUILTIN_NAME(__streaming_store_uniform_float);
+DECL_BUILTIN_NAME(__streaming_store_uniform_half);
+DECL_BUILTIN_NAME(__streaming_store_uniform_i16);
+DECL_BUILTIN_NAME(__streaming_store_uniform_i32);
+DECL_BUILTIN_NAME(__streaming_store_uniform_i64);
+DECL_BUILTIN_NAME(__streaming_store_uniform_i8);
+DECL_BUILTIN_NAME(__streaming_store_varying_double);
+DECL_BUILTIN_NAME(__streaming_store_varying_float);
+DECL_BUILTIN_NAME(__streaming_store_varying_half);
+DECL_BUILTIN_NAME(__streaming_store_varying_i16);
+DECL_BUILTIN_NAME(__streaming_store_varying_i32);
+DECL_BUILTIN_NAME(__streaming_store_varying_i64);
+DECL_BUILTIN_NAME(__streaming_store_varying_i8);
+DECL_BUILTIN_NAME(__svml_acosd);
+DECL_BUILTIN_NAME(__svml_acosf);
+DECL_BUILTIN_NAME(__svml_asind);
+DECL_BUILTIN_NAME(__svml_asinf);
+DECL_BUILTIN_NAME(__svml_atan2d);
+DECL_BUILTIN_NAME(__svml_atan2f);
+DECL_BUILTIN_NAME(__svml_atand);
+DECL_BUILTIN_NAME(__svml_atanf);
+DECL_BUILTIN_NAME(__svml_cosd);
+DECL_BUILTIN_NAME(__svml_cosf);
+DECL_BUILTIN_NAME(__svml_expd);
+DECL_BUILTIN_NAME(__svml_expf);
+DECL_BUILTIN_NAME(__svml_invsqrtd);
+DECL_BUILTIN_NAME(__svml_invsqrtf);
+DECL_BUILTIN_NAME(__svml_logd);
+DECL_BUILTIN_NAME(__svml_logf);
+DECL_BUILTIN_NAME(__svml_powd);
+DECL_BUILTIN_NAME(__svml_powf);
+DECL_BUILTIN_NAME(__svml_sincosd);
+DECL_BUILTIN_NAME(__svml_sincosf);
+DECL_BUILTIN_NAME(__svml_sind);
+DECL_BUILTIN_NAME(__svml_sinf);
+DECL_BUILTIN_NAME(__svml_sqrtd);
+DECL_BUILTIN_NAME(__svml_sqrtf);
+DECL_BUILTIN_NAME(__svml_tand);
+DECL_BUILTIN_NAME(__svml_tanf);
+DECL_BUILTIN_NAME(__tan_uniform_double);
+DECL_BUILTIN_NAME(__tan_uniform_float);
+DECL_BUILTIN_NAME(__tan_uniform_half);
+DECL_BUILTIN_NAME(__tan_varying_double);
+DECL_BUILTIN_NAME(__tan_varying_float);
+DECL_BUILTIN_NAME(__tan_varying_half);
+DECL_BUILTIN_NAME(__task_count);
+DECL_BUILTIN_NAME(__task_count0);
+DECL_BUILTIN_NAME(__task_count1);
+DECL_BUILTIN_NAME(__task_count2);
+DECL_BUILTIN_NAME(__task_index);
+DECL_BUILTIN_NAME(__task_index0);
+DECL_BUILTIN_NAME(__task_index1);
+DECL_BUILTIN_NAME(__task_index2);
+DECL_BUILTIN_NAME(__trunc_uniform_double);
+DECL_BUILTIN_NAME(__trunc_uniform_float);
+DECL_BUILTIN_NAME(__trunc_uniform_half);
+DECL_BUILTIN_NAME(__trunc_varying_double);
+DECL_BUILTIN_NAME(__trunc_varying_float);
+DECL_BUILTIN_NAME(__trunc_varying_half);
+DECL_BUILTIN_NAME(__undef_uniform);
+DECL_BUILTIN_NAME(__undef_varying);
+DECL_BUILTIN_NAME(__vec4_add_float);
+DECL_BUILTIN_NAME(__vec4_add_int32);
+DECL_BUILTIN_NAME(__vselect_float);
+DECL_BUILTIN_NAME(__vselect_i32);
+
+} // namespace builtin
+
+} // namespace ispc
\ No newline at end of file
diff --git a/src/builtins-decl.h b/src/builtins-decl.h
new file mode 100644
index 0000000000..b4e6dad43f
--- /dev/null
+++ b/src/builtins-decl.h
@@ -0,0 +1,936 @@
+/*
+  Copyright (c) 2024, Intel Corporation
+
+  SPDX-License-Identifier: BSD-3-Clause
+*/
+
+// Builtins are target-specific functions implemented using LLVM IR. They are
+// located in builtins directory. Their names typically start with double
+// underscores. Unlike Standard Library functions, they are not guaranteed to
+// be stable as compiler evolves. But they are used to implement the Standard
+// Library.
+//
+// During compilation flow ISPC compiler sometimes needs to treat builtins
+// differently than user functions or stdlib functions, or does optimizations
+// that recognize certain builtins (like gather/scatter optimization flow).
+// Addressing builtins by string representation of the name in the source code
+// is error prone, so this file solves this problem by defining the pointer
+// with builtin name pointing to a C-string representing the name. For example,
+// instead of using "__any" identifier, it's available as builtin::__any.
+//
+// This file has to be the only place to declare builtin names that used across
+// ISPC code base. The list is alphabetically sorted for convenience.
+
+namespace ispc {
+
+namespace builtin {
+
+extern const char *const __acos_uniform_double;
+extern const char *const __acos_uniform_float;
+extern const char *const __acos_uniform_half;
+extern const char *const __acos_varying_double;
+extern const char *const __acos_varying_float;
+extern const char *const __acos_varying_half;
+extern const char *const __add_float;
+extern const char *const __add_int32;
+extern const char *const __add_uniform_double;
+extern const char *const __add_uniform_int32;
+extern const char *const __add_uniform_int64;
+extern const char *const __add_varying_double;
+extern const char *const __add_varying_int32;
+extern const char *const __add_varying_int64;
+extern const char *const __all;
+extern const char *const __any;
+extern const char *const __aos_to_soa2_double;
+extern const char *const __aos_to_soa2_double1;
+extern const char *const __aos_to_soa2_double16;
+extern const char *const __aos_to_soa2_double32;
+extern const char *const __aos_to_soa2_double4;
+extern const char *const __aos_to_soa2_double64;
+extern const char *const __aos_to_soa2_double8;
+extern const char *const __aos_to_soa2_float;
+extern const char *const __aos_to_soa2_float1;
+extern const char *const __aos_to_soa2_float16;
+extern const char *const __aos_to_soa2_float32;
+extern const char *const __aos_to_soa2_float4;
+extern const char *const __aos_to_soa2_float64;
+extern const char *const __aos_to_soa2_float8;
+extern const char *const __aos_to_soa3_double;
+extern const char *const __aos_to_soa3_double1;
+extern const char *const __aos_to_soa3_double16;
+extern const char *const __aos_to_soa3_double32;
+extern const char *const __aos_to_soa3_double4;
+extern const char *const __aos_to_soa3_double64;
+extern const char *const __aos_to_soa3_double8;
+extern const char *const __aos_to_soa3_float;
+extern const char *const __aos_to_soa3_float1;
+extern const char *const __aos_to_soa3_float16;
+extern const char *const __aos_to_soa3_float32;
+extern const char *const __aos_to_soa3_float4;
+extern const char *const __aos_to_soa3_float64;
+extern const char *const __aos_to_soa3_float8;
+extern const char *const __aos_to_soa4_double;
+extern const char *const __aos_to_soa4_double1;
+extern const char *const __aos_to_soa4_double16;
+extern const char *const __aos_to_soa4_double32;
+extern const char *const __aos_to_soa4_double4;
+extern const char *const __aos_to_soa4_double64;
+extern const char *const __aos_to_soa4_double8;
+extern const char *const __aos_to_soa4_float;
+extern const char *const __aos_to_soa4_float1;
+extern const char *const __aos_to_soa4_float16;
+extern const char *const __aos_to_soa4_float32;
+extern const char *const __aos_to_soa4_float4;
+extern const char *const __aos_to_soa4_float64;
+extern const char *const __aos_to_soa4_float8;
+extern const char *const __asin_uniform_double;
+extern const char *const __asin_uniform_float;
+extern const char *const __asin_uniform_half;
+extern const char *const __asin_varying_double;
+extern const char *const __asin_varying_float;
+extern const char *const __asin_varying_half;
+extern const char *const __atan2_uniform_double;
+extern const char *const __atan2_uniform_float;
+extern const char *const __atan2_uniform_half;
+extern const char *const __atan2_varying_double;
+extern const char *const __atan2_varying_float;
+extern const char *const __atan2_varying_half;
+extern const char *const __atan_uniform_double;
+extern const char *const __atan_uniform_float;
+extern const char *const __atan_uniform_half;
+extern const char *const __atan_varying_double;
+extern const char *const __atan_varying_float;
+extern const char *const __atan_varying_half;
+extern const char *const __atomic_add_int32_global;
+extern const char *const __atomic_add_int64_global;
+extern const char *const __atomic_add_uniform_int32_global;
+extern const char *const __atomic_add_uniform_int64_global;
+extern const char *const __atomic_and_int32_global;
+extern const char *const __atomic_and_int64_global;
+extern const char *const __atomic_and_uniform_int32_global;
+extern const char *const __atomic_and_uniform_int64_global;
+extern const char *const __atomic_compare_exchange_double_global;
+extern const char *const __atomic_compare_exchange_float_global;
+extern const char *const __atomic_compare_exchange_int32_global;
+extern const char *const __atomic_compare_exchange_int64_global;
+extern const char *const __atomic_compare_exchange_uniform_double_global;
+extern const char *const __atomic_compare_exchange_uniform_float_global;
+extern const char *const __atomic_compare_exchange_uniform_int32_global;
+extern const char *const __atomic_compare_exchange_uniform_int64_global;
+extern const char *const __atomic_max_uniform_int32_global;
+extern const char *const __atomic_max_uniform_int64_global;
+extern const char *const __atomic_min_uniform_int32_global;
+extern const char *const __atomic_min_uniform_int64_global;
+extern const char *const __atomic_or_int32_global;
+extern const char *const __atomic_or_int64_global;
+extern const char *const __atomic_or_uniform_int32_global;
+extern const char *const __atomic_or_uniform_int64_global;
+extern const char *const __atomic_sub_int32_global;
+extern const char *const __atomic_sub_int64_global;
+extern const char *const __atomic_sub_uniform_int32_global;
+extern const char *const __atomic_sub_uniform_int64_global;
+extern const char *const __atomic_swap_double_global;
+extern const char *const __atomic_swap_float_global;
+extern const char *const __atomic_swap_int32_global;
+extern const char *const __atomic_swap_int64_global;
+extern const char *const __atomic_swap_uniform_double_global;
+extern const char *const __atomic_swap_uniform_float_global;
+extern const char *const __atomic_swap_uniform_int32_global;
+extern const char *const __atomic_swap_uniform_int64_global;
+extern const char *const __atomic_umax_uniform_uint32_global;
+extern const char *const __atomic_umax_uniform_uint64_global;
+extern const char *const __atomic_umin_uniform_uint32_global;
+extern const char *const __atomic_umin_uniform_uint64_global;
+extern const char *const __atomic_xor_int32_global;
+extern const char *const __atomic_xor_int64_global;
+extern const char *const __atomic_xor_uniform_int32_global;
+extern const char *const __atomic_xor_uniform_int64_global;
+extern const char *const __avg_down_int16;
+extern const char *const __avg_down_int8;
+extern const char *const __avg_down_uint16;
+extern const char *const __avg_down_uint8;
+extern const char *const __avg_up_int16;
+extern const char *const __avg_up_int8;
+extern const char *const __avg_up_uint16;
+extern const char *const __avg_up_uint8;
+extern const char *const __broadcast_double;
+extern const char *const __broadcast_float;
+extern const char *const __broadcast_half;
+extern const char *const __broadcast_i16;
+extern const char *const __broadcast_i32;
+extern const char *const __broadcast_i64;
+extern const char *const __broadcast_i8;
+extern const char *const __cast_mask_to_i1;
+extern const char *const __cast_mask_to_i16;
+extern const char *const __cast_mask_to_i32;
+extern const char *const __cast_mask_to_i64;
+extern const char *const __cast_mask_to_i8;
+extern const char *const __ceil_uniform_double;
+extern const char *const __ceil_uniform_float;
+extern const char *const __ceil_uniform_half;
+extern const char *const __ceil_varying_double;
+extern const char *const __ceil_varying_float;
+extern const char *const __ceil_varying_half;
+extern const char *const __clock;
+extern const char *const __cos_uniform_double;
+extern const char *const __cos_uniform_float;
+extern const char *const __cos_uniform_half;
+extern const char *const __cos_varying_double;
+extern const char *const __cos_varying_float;
+extern const char *const __cos_varying_half;
+extern const char *const __count_leading_zeros_i32;
+extern const char *const __count_leading_zeros_i64;
+extern const char *const __count_trailing_zeros_i32;
+extern const char *const __count_trailing_zeros_i64;
+extern const char *const __delete_uniform_32rt;
+extern const char *const __delete_uniform_64rt;
+extern const char *const __delete_varying_32rt;
+extern const char *const __delete_varying_64rt;
+extern const char *const __do_assert_uniform;
+extern const char *const __do_assert_varying;
+extern const char *const __do_assume_uniform;
+extern const char *const __do_print;
+extern const char *const __doublebits_uniform_int64;
+extern const char *const __doublebits_varying_int64;
+extern const char *const __exclusive_scan_add_double;
+extern const char *const __exclusive_scan_add_float;
+extern const char *const __exclusive_scan_add_half;
+extern const char *const __exclusive_scan_add_i32;
+extern const char *const __exclusive_scan_add_i64;
+extern const char *const __exclusive_scan_and_i32;
+extern const char *const __exclusive_scan_and_i64;
+extern const char *const __exclusive_scan_or_i32;
+extern const char *const __exclusive_scan_or_i64;
+extern const char *const __exp_uniform_double;
+extern const char *const __exp_uniform_float;
+extern const char *const __exp_uniform_half;
+extern const char *const __exp_varying_double;
+extern const char *const __exp_varying_float;
+extern const char *const __exp_varying_half;
+extern const char *const __extract_bool;
+extern const char *const __extract_int16;
+extern const char *const __extract_int32;
+extern const char *const __extract_int64;
+extern const char *const __extract_int8;
+extern const char *const __extract_mask_hi;
+extern const char *const __extract_mask_low;
+extern const char *const __fast_masked_vload;
+extern const char *const __fastmath;
+extern const char *const __floatbits_uniform_int32;
+extern const char *const __floatbits_varying_int32;
+extern const char *const __float_to_half_uniform;
+extern const char *const __float_to_half_varying;
+extern const char *const __floor_uniform_double;
+extern const char *const __floor_uniform_float;
+extern const char *const __floor_uniform_half;
+extern const char *const __floor_varying_double;
+extern const char *const __floor_varying_float;
+extern const char *const __floor_varying_half;
+extern const char *const __gather32_double;
+extern const char *const __gather32_float;
+extern const char *const __gather32_generic_double;
+extern const char *const __gather32_generic_float;
+extern const char *const __gather32_generic_half;
+extern const char *const __gather32_generic_i16;
+extern const char *const __gather32_generic_i32;
+extern const char *const __gather32_generic_i64;
+extern const char *const __gather32_generic_i8;
+extern const char *const __gather32_half;
+extern const char *const __gather32_i16;
+extern const char *const __gather32_i32;
+extern const char *const __gather32_i64;
+extern const char *const __gather32_i8;
+extern const char *const __gather64_double;
+extern const char *const __gather64_float;
+extern const char *const __gather64_generic_double;
+extern const char *const __gather64_generic_float;
+extern const char *const __gather64_generic_half;
+extern const char *const __gather64_generic_i16;
+extern const char *const __gather64_generic_i32;
+extern const char *const __gather64_generic_i64;
+extern const char *const __gather64_generic_i8;
+extern const char *const __gather64_half;
+extern const char *const __gather64_i16;
+extern const char *const __gather64_i32;
+extern const char *const __gather64_i64;
+extern const char *const __gather64_i8;
+extern const char *const __gather_base_offsets32_double;
+extern const char *const __gather_base_offsets32_float;
+extern const char *const __gather_base_offsets32_half;
+extern const char *const __gather_base_offsets32_i16;
+extern const char *const __gather_base_offsets32_i32;
+extern const char *const __gather_base_offsets32_i64;
+extern const char *const __gather_base_offsets32_i8;
+extern const char *const __gather_base_offsets64_double;
+extern const char *const __gather_base_offsets64_float;
+extern const char *const __gather_base_offsets64_half;
+extern const char *const __gather_base_offsets64_i16;
+extern const char *const __gather_base_offsets64_i32;
+extern const char *const __gather_base_offsets64_i64;
+extern const char *const __gather_base_offsets64_i8;
+extern const char *const __gather_elt32_double;
+extern const char *const __gather_elt32_float;
+extern const char *const __gather_elt32_half;
+extern const char *const __gather_elt32_i16;
+extern const char *const __gather_elt32_i32;
+extern const char *const __gather_elt32_i64;
+extern const char *const __gather_elt32_i8;
+extern const char *const __gather_elt64_double;
+extern const char *const __gather_elt64_float;
+extern const char *const __gather_elt64_half;
+extern const char *const __gather_elt64_i16;
+extern const char *const __gather_elt64_i32;
+extern const char *const __gather_elt64_i64;
+extern const char *const __gather_elt64_i8;
+extern const char *const __gather_factored_base_offsets32_double;
+extern const char *const __gather_factored_base_offsets32_float;
+extern const char *const __gather_factored_base_offsets32_half;
+extern const char *const __gather_factored_base_offsets32_i16;
+extern const char *const __gather_factored_base_offsets32_i32;
+extern const char *const __gather_factored_base_offsets32_i64;
+extern const char *const __gather_factored_base_offsets32_i8;
+extern const char *const __gather_factored_base_offsets64_double;
+extern const char *const __gather_factored_base_offsets64_float;
+extern const char *const __gather_factored_base_offsets64_half;
+extern const char *const __gather_factored_base_offsets64_i16;
+extern const char *const __gather_factored_base_offsets64_i32;
+extern const char *const __gather_factored_base_offsets64_i64;
+extern const char *const __gather_factored_base_offsets64_i8;
+extern const char *const __get_system_isa;
+extern const char *const __halfbits_uniform_int16;
+extern const char *const __halfbits_varying_int16;
+extern const char *const __half_to_float_uniform;
+extern const char *const __half_to_float_varying;
+extern const char *const __idiv_int16;
+extern const char *const __idiv_int32;
+extern const char *const __idiv_int8;
+extern const char *const __idiv_uint16;
+extern const char *const __idiv_uint32;
+extern const char *const __idiv_uint8;
+extern const char *const __insert_bool;
+extern const char *const __insert_int16;
+extern const char *const __insert_int32;
+extern const char *const __insert_int64;
+extern const char *const __insert_int8;
+extern const char *const __intbits_uniform_double;
+extern const char *const __intbits_uniform_float;
+extern const char *const __intbits_uniform_half;
+extern const char *const __intbits_varying_double;
+extern const char *const __intbits_varying_float;
+extern const char *const __intbits_varying_half;
+extern const char *const __is_compile_time_constant_mask;
+extern const char *const __is_compile_time_constant_uniform_int32;
+extern const char *const __is_compile_time_constant_varying_int32;
+extern const char *const ISPCAlloc;
+extern const char *const ISPCLaunch;
+extern const char *const ISPCSync;
+extern const char *const __keep_funcs_live;
+extern const char *const __log_uniform_double;
+extern const char *const __log_uniform_float;
+extern const char *const __log_uniform_half;
+extern const char *const __log_varying_double;
+extern const char *const __log_varying_float;
+extern const char *const __log_varying_half;
+extern const char *const __masked_load_blend_double;
+extern const char *const __masked_load_blend_float;
+extern const char *const __masked_load_blend_half;
+extern const char *const __masked_load_blend_i16;
+extern const char *const __masked_load_blend_i32;
+extern const char *const __masked_load_blend_i64;
+extern const char *const __masked_load_blend_i8;
+extern const char *const __masked_load_double;
+extern const char *const __masked_load_float;
+extern const char *const __masked_load_half;
+extern const char *const __masked_load_i16;
+extern const char *const __masked_load_i32;
+extern const char *const __masked_load_i64;
+extern const char *const __masked_load_i8;
+extern const char *const __masked_store_blend_double;
+extern const char *const __masked_store_blend_float;
+extern const char *const __masked_store_blend_half;
+extern const char *const __masked_store_blend_i16;
+extern const char *const __masked_store_blend_i32;
+extern const char *const __masked_store_blend_i64;
+extern const char *const __masked_store_blend_i8;
+extern const char *const __masked_store_double;
+extern const char *const __masked_store_float;
+extern const char *const __masked_store_half;
+extern const char *const __masked_store_i16;
+extern const char *const __masked_store_i32;
+extern const char *const __masked_store_i64;
+extern const char *const __masked_store_i8;
+extern const char *const __max_uniform_double;
+extern const char *const __max_uniform_float;
+extern const char *const __max_uniform_half;
+extern const char *const __max_uniform_int32;
+extern const char *const __max_uniform_int64;
+extern const char *const __max_uniform_uint32;
+extern const char *const __max_uniform_uint64;
+extern const char *const __max_varying_double;
+extern const char *const __max_varying_float;
+extern const char *const __max_varying_half;
+extern const char *const __max_varying_int32;
+extern const char *const __max_varying_int64;
+extern const char *const __max_varying_uint32;
+extern const char *const __max_varying_uint64;
+extern const char *const __memcpy32;
+extern const char *const __memcpy64;
+extern const char *const __memmove32;
+extern const char *const __memmove64;
+extern const char *const __memory_barrier;
+extern const char *const __memset32;
+extern const char *const __memset64;
+extern const char *const __min_uniform_double;
+extern const char *const __min_uniform_float;
+extern const char *const __min_uniform_half;
+extern const char *const __min_uniform_int32;
+extern const char *const __min_uniform_int64;
+extern const char *const __min_uniform_uint32;
+extern const char *const __min_uniform_uint64;
+extern const char *const __min_varying_double;
+extern const char *const __min_varying_float;
+extern const char *const __min_varying_half;
+extern const char *const __min_varying_int32;
+extern const char *const __min_varying_int64;
+extern const char *const __min_varying_uint32;
+extern const char *const __min_varying_uint64;
+extern const char *const __movmsk;
+extern const char *const __new_uniform_32rt;
+extern const char *const __new_uniform_64rt;
+extern const char *const __new_varying32_32rt;
+extern const char *const __new_varying32_64rt;
+extern const char *const __new_varying64_64rt;
+extern const char *const __none;
+extern const char *const __num_cores;
+extern const char *const __packed_load_activei32;
+extern const char *const __packed_load_activei64;
+extern const char *const __packed_store_active2i32;
+extern const char *const __packed_store_active2i64;
+extern const char *const __packed_store_activei32;
+extern const char *const __packed_store_activei64;
+extern const char *const __padds_ui16;
+extern const char *const __padds_ui32;
+extern const char *const __padds_ui64;
+extern const char *const __padds_ui8;
+extern const char *const __padds_vi16;
+extern const char *const __padds_vi32;
+extern const char *const __padds_vi64;
+extern const char *const __padds_vi8;
+extern const char *const __paddus_ui16;
+extern const char *const __paddus_ui32;
+extern const char *const __paddus_ui64;
+extern const char *const __paddus_ui8;
+extern const char *const __paddus_vi16;
+extern const char *const __paddus_vi32;
+extern const char *const __paddus_vi64;
+extern const char *const __paddus_vi8;
+extern const char *const __pmuls_ui16;
+extern const char *const __pmuls_ui32;
+extern const char *const __pmuls_ui8;
+extern const char *const __pmuls_vi16;
+extern const char *const __pmuls_vi32;
+extern const char *const __pmuls_vi8;
+extern const char *const __pmulus_ui16;
+extern const char *const __pmulus_ui32;
+extern const char *const __pmulus_ui8;
+extern const char *const __pmulus_vi16;
+extern const char *const __pmulus_vi32;
+extern const char *const __pmulus_vi8;
+extern const char *const __popcnt_int32;
+extern const char *const __popcnt_int64;
+extern const char *const __pow_uniform_double;
+extern const char *const __pow_uniform_float;
+extern const char *const __pow_uniform_half;
+extern const char *const __pow_varying_double;
+extern const char *const __pow_varying_float;
+extern const char *const __pow_varying_half;
+extern const char *const __prefetch_read_sized_uniform_1;
+extern const char *const __prefetch_read_sized_uniform_2;
+extern const char *const __prefetch_read_sized_uniform_3;
+extern const char *const __prefetch_read_sized_uniform_nt;
+extern const char *const __prefetch_read_sized_varying_1;
+extern const char *const __prefetch_read_sized_varying_2;
+extern const char *const __prefetch_read_sized_varying_3;
+extern const char *const __prefetch_read_sized_varying_nt;
+extern const char *const __prefetch_read_uniform_1;
+extern const char *const __prefetch_read_uniform_2;
+extern const char *const __prefetch_read_uniform_3;
+extern const char *const __prefetch_read_uniform_nt;
+extern const char *const __prefetch_read_varying_1;
+extern const char *const __prefetch_read_varying_1_native;
+extern const char *const __prefetch_read_varying_2;
+extern const char *const __prefetch_read_varying_2_native;
+extern const char *const __prefetch_read_varying_3;
+extern const char *const __prefetch_read_varying_3_native;
+extern const char *const __prefetch_read_varying_nt;
+extern const char *const __prefetch_read_varying_nt_native;
+extern const char *const __prefetch_write_uniform_1;
+extern const char *const __prefetch_write_uniform_2;
+extern const char *const __prefetch_write_uniform_3;
+extern const char *const __prefetch_write_varying_1;
+extern const char *const __prefetch_write_varying_1_native;
+extern const char *const __prefetch_write_varying_2;
+extern const char *const __prefetch_write_varying_2_native;
+extern const char *const __prefetch_write_varying_3;
+extern const char *const __prefetch_write_varying_3_native;
+extern const char *const __pseudo_gather32_double;
+extern const char *const __pseudo_gather32_float;
+extern const char *const __pseudo_gather32_half;
+extern const char *const __pseudo_gather32_i16;
+extern const char *const __pseudo_gather32_i32;
+extern const char *const __pseudo_gather32_i64;
+extern const char *const __pseudo_gather32_i8;
+extern const char *const __pseudo_gather64_double;
+extern const char *const __pseudo_gather64_float;
+extern const char *const __pseudo_gather64_half;
+extern const char *const __pseudo_gather64_i16;
+extern const char *const __pseudo_gather64_i32;
+extern const char *const __pseudo_gather64_i64;
+extern const char *const __pseudo_gather64_i8;
+extern const char *const __pseudo_gather_base_offsets32_double;
+extern const char *const __pseudo_gather_base_offsets32_float;
+extern const char *const __pseudo_gather_base_offsets32_half;
+extern const char *const __pseudo_gather_base_offsets32_i16;
+extern const char *const __pseudo_gather_base_offsets32_i32;
+extern const char *const __pseudo_gather_base_offsets32_i64;
+extern const char *const __pseudo_gather_base_offsets32_i8;
+extern const char *const __pseudo_gather_base_offsets64_double;
+extern const char *const __pseudo_gather_base_offsets64_float;
+extern const char *const __pseudo_gather_base_offsets64_half;
+extern const char *const __pseudo_gather_base_offsets64_i16;
+extern const char *const __pseudo_gather_base_offsets64_i32;
+extern const char *const __pseudo_gather_base_offsets64_i64;
+extern const char *const __pseudo_gather_base_offsets64_i8;
+extern const char *const __pseudo_gather_factored_base_offsets32_double;
+extern const char *const __pseudo_gather_factored_base_offsets32_float;
+extern const char *const __pseudo_gather_factored_base_offsets32_half;
+extern const char *const __pseudo_gather_factored_base_offsets32_i16;
+extern const char *const __pseudo_gather_factored_base_offsets32_i32;
+extern const char *const __pseudo_gather_factored_base_offsets32_i64;
+extern const char *const __pseudo_gather_factored_base_offsets32_i8;
+extern const char *const __pseudo_gather_factored_base_offsets64_double;
+extern const char *const __pseudo_gather_factored_base_offsets64_float;
+extern const char *const __pseudo_gather_factored_base_offsets64_half;
+extern const char *const __pseudo_gather_factored_base_offsets64_i16;
+extern const char *const __pseudo_gather_factored_base_offsets64_i32;
+extern const char *const __pseudo_gather_factored_base_offsets64_i64;
+extern const char *const __pseudo_gather_factored_base_offsets64_i8;
+extern const char *const __pseudo_masked_store_double;
+extern const char *const __pseudo_masked_store_float;
+extern const char *const __pseudo_masked_store_half;
+extern const char *const __pseudo_masked_store_i16;
+extern const char *const __pseudo_masked_store_i32;
+extern const char *const __pseudo_masked_store_i64;
+extern const char *const __pseudo_masked_store_i8;
+extern const char *const __pseudo_prefetch_read_varying_1;
+extern const char *const __pseudo_prefetch_read_varying_1_native;
+extern const char *const __pseudo_prefetch_read_varying_2;
+extern const char *const __pseudo_prefetch_read_varying_2_native;
+extern const char *const __pseudo_prefetch_read_varying_3;
+extern const char *const __pseudo_prefetch_read_varying_3_native;
+extern const char *const __pseudo_prefetch_read_varying_nt;
+extern const char *const __pseudo_prefetch_read_varying_nt_native;
+extern const char *const __pseudo_prefetch_write_varying_1;
+extern const char *const __pseudo_prefetch_write_varying_1_native;
+extern const char *const __pseudo_prefetch_write_varying_2;
+extern const char *const __pseudo_prefetch_write_varying_2_native;
+extern const char *const __pseudo_prefetch_write_varying_3;
+extern const char *const __pseudo_prefetch_write_varying_3_native;
+extern const char *const __pseudo_scatter32_double;
+extern const char *const __pseudo_scatter32_float;
+extern const char *const __pseudo_scatter32_half;
+extern const char *const __pseudo_scatter32_i16;
+extern const char *const __pseudo_scatter32_i32;
+extern const char *const __pseudo_scatter32_i64;
+extern const char *const __pseudo_scatter32_i8;
+extern const char *const __pseudo_scatter64_double;
+extern const char *const __pseudo_scatter64_float;
+extern const char *const __pseudo_scatter64_half;
+extern const char *const __pseudo_scatter64_i16;
+extern const char *const __pseudo_scatter64_i32;
+extern const char *const __pseudo_scatter64_i64;
+extern const char *const __pseudo_scatter64_i8;
+extern const char *const __pseudo_scatter_base_offsets32_double;
+extern const char *const __pseudo_scatter_base_offsets32_float;
+extern const char *const __pseudo_scatter_base_offsets32_half;
+extern const char *const __pseudo_scatter_base_offsets32_i16;
+extern const char *const __pseudo_scatter_base_offsets32_i32;
+extern const char *const __pseudo_scatter_base_offsets32_i64;
+extern const char *const __pseudo_scatter_base_offsets32_i8;
+extern const char *const __pseudo_scatter_base_offsets64_double;
+extern const char *const __pseudo_scatter_base_offsets64_float;
+extern const char *const __pseudo_scatter_base_offsets64_half;
+extern const char *const __pseudo_scatter_base_offsets64_i16;
+extern const char *const __pseudo_scatter_base_offsets64_i32;
+extern const char *const __pseudo_scatter_base_offsets64_i64;
+extern const char *const __pseudo_scatter_base_offsets64_i8;
+extern const char *const __pseudo_scatter_factored_base_offsets32_double;
+extern const char *const __pseudo_scatter_factored_base_offsets32_float;
+extern const char *const __pseudo_scatter_factored_base_offsets32_half;
+extern const char *const __pseudo_scatter_factored_base_offsets32_i16;
+extern const char *const __pseudo_scatter_factored_base_offsets32_i32;
+extern const char *const __pseudo_scatter_factored_base_offsets32_i64;
+extern const char *const __pseudo_scatter_factored_base_offsets32_i8;
+extern const char *const __pseudo_scatter_factored_base_offsets64_double;
+extern const char *const __pseudo_scatter_factored_base_offsets64_float;
+extern const char *const __pseudo_scatter_factored_base_offsets64_half;
+extern const char *const __pseudo_scatter_factored_base_offsets64_i16;
+extern const char *const __pseudo_scatter_factored_base_offsets64_i32;
+extern const char *const __pseudo_scatter_factored_base_offsets64_i64;
+extern const char *const __pseudo_scatter_factored_base_offsets64_i8;
+extern const char *const __psubs_ui16;
+extern const char *const __psubs_ui32;
+extern const char *const __psubs_ui64;
+extern const char *const __psubs_ui8;
+extern const char *const __psubs_vi16;
+extern const char *const __psubs_vi32;
+extern const char *const __psubs_vi64;
+extern const char *const __psubs_vi8;
+extern const char *const __psubus_ui16;
+extern const char *const __psubus_ui32;
+extern const char *const __psubus_ui64;
+extern const char *const __psubus_ui8;
+extern const char *const __psubus_vi16;
+extern const char *const __psubus_vi32;
+extern const char *const __psubus_vi64;
+extern const char *const __psubus_vi8;
+extern const char *const __rcp_fast_uniform_double;
+extern const char *const __rcp_fast_uniform_float;
+extern const char *const __rcp_fast_uniform_half;
+extern const char *const __rcp_fast_varying_double;
+extern const char *const __rcp_fast_varying_float;
+extern const char *const __rcp_fast_varying_half;
+extern const char *const __rcp_uniform_double;
+extern const char *const __rcp_uniform_float;
+extern const char *const __rcp_uniform_half;
+extern const char *const __rcp_varying_double;
+extern const char *const __rcp_varying_float;
+extern const char *const __rcp_varying_half;
+extern const char *const __rdrand_i16;
+extern const char *const __rdrand_i32;
+extern const char *const __rdrand_i64;
+extern const char *const __reduce_add_double;
+extern const char *const __reduce_add_float;
+extern const char *const __reduce_add_half;
+extern const char *const __reduce_add_int16;
+extern const char *const __reduce_add_int32;
+extern const char *const __reduce_add_int64;
+extern const char *const __reduce_add_int8;
+extern const char *const __reduce_equal_double;
+extern const char *const __reduce_equal_float;
+extern const char *const __reduce_equal_half;
+extern const char *const __reduce_equal_int32;
+extern const char *const __reduce_equal_int64;
+extern const char *const __reduce_max_double;
+extern const char *const __reduce_max_float;
+extern const char *const __reduce_max_half;
+extern const char *const __reduce_max_int32;
+extern const char *const __reduce_max_int64;
+extern const char *const __reduce_max_uint32;
+extern const char *const __reduce_max_uint64;
+extern const char *const __reduce_min_double;
+extern const char *const __reduce_min_float;
+extern const char *const __reduce_min_half;
+extern const char *const __reduce_min_int32;
+extern const char *const __reduce_min_int64;
+extern const char *const __reduce_min_uint32;
+extern const char *const __reduce_min_uint64;
+extern const char *const __restore_ftz_daz_flags;
+extern const char *const __rotate_double;
+extern const char *const __rotate_float;
+extern const char *const __rotate_half;
+extern const char *const __rotate_i16;
+extern const char *const __rotate_i32;
+extern const char *const __rotate_i64;
+extern const char *const __rotate_i8;
+extern const char *const __round_uniform_double;
+extern const char *const __round_uniform_float;
+extern const char *const __round_uniform_half;
+extern const char *const __round_varying_double;
+extern const char *const __round_varying_float;
+extern const char *const __round_varying_half;
+extern const char *const __rsqrt_fast_uniform_double;
+extern const char *const __rsqrt_fast_uniform_float;
+extern const char *const __rsqrt_fast_varying_double;
+extern const char *const __rsqrt_fast_varying_float;
+extern const char *const __rsqrt_uniform_double;
+extern const char *const __rsqrt_uniform_float;
+extern const char *const __rsqrt_uniform_half;
+extern const char *const __rsqrt_varying_double;
+extern const char *const __rsqrt_varying_float;
+extern const char *const __rsqrt_varying_half;
+extern const char *const __saturating_add_i16;
+extern const char *const __saturating_add_i32;
+extern const char *const __saturating_add_i64;
+extern const char *const __saturating_add_i8;
+extern const char *const __saturating_add_ui16;
+extern const char *const __saturating_add_ui32;
+extern const char *const __saturating_add_ui64;
+extern const char *const __saturating_add_ui8;
+extern const char *const __saturating_mul_i16;
+extern const char *const __saturating_mul_i32;
+extern const char *const __saturating_mul_i8;
+extern const char *const __saturating_mul_ui16;
+extern const char *const __saturating_mul_ui32;
+extern const char *const __saturating_mul_ui8;
+extern const char *const __scatter32_double;
+extern const char *const __scatter32_float;
+extern const char *const __scatter32_generic_double;
+extern const char *const __scatter32_generic_float;
+extern const char *const __scatter32_generic_half;
+extern const char *const __scatter32_generic_i16;
+extern const char *const __scatter32_generic_i32;
+extern const char *const __scatter32_generic_i64;
+extern const char *const __scatter32_generic_i8;
+extern const char *const __scatter32_half;
+extern const char *const __scatter32_i16;
+extern const char *const __scatter32_i32;
+extern const char *const __scatter32_i64;
+extern const char *const __scatter32_i8;
+extern const char *const __scatter64_double;
+extern const char *const __scatter64_float;
+extern const char *const __scatter64_generic_double;
+extern const char *const __scatter64_generic_float;
+extern const char *const __scatter64_generic_half;
+extern const char *const __scatter64_generic_i16;
+extern const char *const __scatter64_generic_i32;
+extern const char *const __scatter64_generic_i64;
+extern const char *const __scatter64_generic_i8;
+extern const char *const __scatter64_half;
+extern const char *const __scatter64_i16;
+extern const char *const __scatter64_i32;
+extern const char *const __scatter64_i64;
+extern const char *const __scatter64_i8;
+extern const char *const __scatter_base_offsets32_double;
+extern const char *const __scatter_base_offsets32_float;
+extern const char *const __scatter_base_offsets32_half;
+extern const char *const __scatter_base_offsets32_i16;
+extern const char *const __scatter_base_offsets32_i32;
+extern const char *const __scatter_base_offsets32_i64;
+extern const char *const __scatter_base_offsets32_i8;
+extern const char *const __scatter_base_offsets64_double;
+extern const char *const __scatter_base_offsets64_float;
+extern const char *const __scatter_base_offsets64_half;
+extern const char *const __scatter_base_offsets64_i16;
+extern const char *const __scatter_base_offsets64_i32;
+extern const char *const __scatter_base_offsets64_i64;
+extern const char *const __scatter_base_offsets64_i8;
+extern const char *const __scatter_elt32_double;
+extern const char *const __scatter_elt32_float;
+extern const char *const __scatter_elt32_half;
+extern const char *const __scatter_elt32_i16;
+extern const char *const __scatter_elt32_i32;
+extern const char *const __scatter_elt32_i64;
+extern const char *const __scatter_elt32_i8;
+extern const char *const __scatter_elt64_double;
+extern const char *const __scatter_elt64_float;
+extern const char *const __scatter_elt64_half;
+extern const char *const __scatter_elt64_i16;
+extern const char *const __scatter_elt64_i32;
+extern const char *const __scatter_elt64_i64;
+extern const char *const __scatter_elt64_i8;
+extern const char *const __scatter_factored_base_offsets32_double;
+extern const char *const __scatter_factored_base_offsets32_float;
+extern const char *const __scatter_factored_base_offsets32_half;
+extern const char *const __scatter_factored_base_offsets32_i16;
+extern const char *const __scatter_factored_base_offsets32_i32;
+extern const char *const __scatter_factored_base_offsets32_i64;
+extern const char *const __scatter_factored_base_offsets32_i8;
+extern const char *const __scatter_factored_base_offsets64_double;
+extern const char *const __scatter_factored_base_offsets64_float;
+extern const char *const __scatter_factored_base_offsets64_half;
+extern const char *const __scatter_factored_base_offsets64_i16;
+extern const char *const __scatter_factored_base_offsets64_i32;
+extern const char *const __scatter_factored_base_offsets64_i64;
+extern const char *const __scatter_factored_base_offsets64_i8;
+extern const char *const __send_eot;
+extern const char *const __set_ftz_daz_flags;
+extern const char *const __set_system_isa;
+extern const char *const __sext_uniform_bool;
+extern const char *const __sext_varying_bool;
+extern const char *const __shift_double;
+extern const char *const __shift_float;
+extern const char *const __shift_half;
+extern const char *const __shift_i16;
+extern const char *const __shift_i32;
+extern const char *const __shift_i64;
+extern const char *const __shift_i8;
+extern const char *const __shuffle2_double;
+extern const char *const __shuffle2_float;
+extern const char *const __shuffle2_half;
+extern const char *const __shuffle2_i16;
+extern const char *const __shuffle2_i32;
+extern const char *const __shuffle2_i64;
+extern const char *const __shuffle2_i8;
+extern const char *const __shuffle_double;
+extern const char *const __shuffle_float;
+extern const char *const __shuffle_half;
+extern const char *const __shuffle_i16;
+extern const char *const __shuffle_i32;
+extern const char *const __shuffle_i64;
+extern const char *const __shuffle_i8;
+extern const char *const __sincos_uniform_double;
+extern const char *const __sincos_uniform_float;
+extern const char *const __sincos_uniform_half;
+extern const char *const __sincos_varying_double;
+extern const char *const __sincos_varying_float;
+extern const char *const __sincos_varying_half;
+extern const char *const __sin_uniform_double;
+extern const char *const __sin_uniform_float;
+extern const char *const __sin_uniform_half;
+extern const char *const __sin_varying_double;
+extern const char *const __sin_varying_float;
+extern const char *const __sin_varying_half;
+extern const char *const __soa_to_aos2_double;
+extern const char *const __soa_to_aos2_double1;
+extern const char *const __soa_to_aos2_double16;
+extern const char *const __soa_to_aos2_double32;
+extern const char *const __soa_to_aos2_double4;
+extern const char *const __soa_to_aos2_double64;
+extern const char *const __soa_to_aos2_double8;
+extern const char *const __soa_to_aos2_float;
+extern const char *const __soa_to_aos2_float1;
+extern const char *const __soa_to_aos2_float16;
+extern const char *const __soa_to_aos2_float32;
+extern const char *const __soa_to_aos2_float4;
+extern const char *const __soa_to_aos2_float64;
+extern const char *const __soa_to_aos2_float8;
+extern const char *const __soa_to_aos3_double;
+extern const char *const __soa_to_aos3_double1;
+extern const char *const __soa_to_aos3_double16;
+extern const char *const __soa_to_aos3_double32;
+extern const char *const __soa_to_aos3_double4;
+extern const char *const __soa_to_aos3_double64;
+extern const char *const __soa_to_aos3_double8;
+extern const char *const __soa_to_aos3_float;
+extern const char *const __soa_to_aos3_float1;
+extern const char *const __soa_to_aos3_float16;
+extern const char *const __soa_to_aos3_float32;
+extern const char *const __soa_to_aos3_float4;
+extern const char *const __soa_to_aos3_float64;
+extern const char *const __soa_to_aos3_float8;
+extern const char *const __soa_to_aos4_double;
+extern const char *const __soa_to_aos4_double1;
+extern const char *const __soa_to_aos4_double16;
+extern const char *const __soa_to_aos4_double32;
+extern const char *const __soa_to_aos4_double4;
+extern const char *const __soa_to_aos4_double64;
+extern const char *const __soa_to_aos4_double8;
+extern const char *const __soa_to_aos4_float;
+extern const char *const __soa_to_aos4_float1;
+extern const char *const __soa_to_aos4_float16;
+extern const char *const __soa_to_aos4_float32;
+extern const char *const __soa_to_aos4_float4;
+extern const char *const __soa_to_aos4_float64;
+extern const char *const __soa_to_aos4_float8;
+extern const char *const __sqrt_uniform_double;
+extern const char *const __sqrt_uniform_float;
+extern const char *const __sqrt_uniform_half;
+extern const char *const __sqrt_varying_double;
+extern const char *const __sqrt_varying_float;
+extern const char *const __sqrt_varying_half;
+extern const char *const __stdlib_acosf;
+extern const char *const __stdlib_asin;
+extern const char *const __stdlib_asinf;
+extern const char *const __stdlib_atan;
+extern const char *const __stdlib_atan2;
+extern const char *const __stdlib_atan2f;
+extern const char *const __stdlib_atanf;
+extern const char *const __stdlib_cos;
+extern const char *const __stdlib_cosf;
+extern const char *const __stdlib_exp;
+extern const char *const __stdlib_expf;
+extern const char *const __stdlib_log;
+extern const char *const __stdlib_logf;
+extern const char *const __stdlib_pow;
+extern const char *const __stdlib_powf;
+extern const char *const __stdlib_sin;
+extern const char *const __stdlib_sincos;
+extern const char *const __stdlib_sincosf;
+extern const char *const __stdlib_sinf;
+extern const char *const __stdlib_tan;
+extern const char *const __stdlib_tanf;
+extern const char *const __streaming_load_uniform_double;
+extern const char *const __streaming_load_uniform_float;
+extern const char *const __streaming_load_uniform_half;
+extern const char *const __streaming_load_uniform_i16;
+extern const char *const __streaming_load_uniform_i32;
+extern const char *const __streaming_load_uniform_i64;
+extern const char *const __streaming_load_uniform_i8;
+extern const char *const __streaming_load_varying_double;
+extern const char *const __streaming_load_varying_float;
+extern const char *const __streaming_load_varying_half;
+extern const char *const __streaming_load_varying_i16;
+extern const char *const __streaming_load_varying_i32;
+extern const char *const __streaming_load_varying_i64;
+extern const char *const __streaming_load_varying_i8;
+extern const char *const __streaming_store_uniform_double;
+extern const char *const __streaming_store_uniform_float;
+extern const char *const __streaming_store_uniform_half;
+extern const char *const __streaming_store_uniform_i16;
+extern const char *const __streaming_store_uniform_i32;
+extern const char *const __streaming_store_uniform_i64;
+extern const char *const __streaming_store_uniform_i8;
+extern const char *const __streaming_store_varying_double;
+extern const char *const __streaming_store_varying_float;
+extern const char *const __streaming_store_varying_half;
+extern const char *const __streaming_store_varying_i16;
+extern const char *const __streaming_store_varying_i32;
+extern const char *const __streaming_store_varying_i64;
+extern const char *const __streaming_store_varying_i8;
+extern const char *const __svml_acosd;
+extern const char *const __svml_acosf;
+extern const char *const __svml_asind;
+extern const char *const __svml_asinf;
+extern const char *const __svml_atan2d;
+extern const char *const __svml_atan2f;
+extern const char *const __svml_atand;
+extern const char *const __svml_atanf;
+extern const char *const __svml_cosd;
+extern const char *const __svml_cosf;
+extern const char *const __svml_expd;
+extern const char *const __svml_expf;
+extern const char *const __svml_invsqrtd;
+extern const char *const __svml_invsqrtf;
+extern const char *const __svml_logd;
+extern const char *const __svml_logf;
+extern const char *const __svml_powd;
+extern const char *const __svml_powf;
+extern const char *const __svml_sincosd;
+extern const char *const __svml_sincosf;
+extern const char *const __svml_sind;
+extern const char *const __svml_sinf;
+extern const char *const __svml_sqrtd;
+extern const char *const __svml_sqrtf;
+extern const char *const __svml_tand;
+extern const char *const __svml_tanf;
+extern const char *const __tan_uniform_double;
+extern const char *const __tan_uniform_float;
+extern const char *const __tan_uniform_half;
+extern const char *const __tan_varying_double;
+extern const char *const __tan_varying_float;
+extern const char *const __tan_varying_half;
+extern const char *const __task_count;
+extern const char *const __task_count0;
+extern const char *const __task_count1;
+extern const char *const __task_count2;
+extern const char *const __task_index;
+extern const char *const __task_index0;
+extern const char *const __task_index1;
+extern const char *const __task_index2;
+extern const char *const __trunc_uniform_double;
+extern const char *const __trunc_uniform_float;
+extern const char *const __trunc_uniform_half;
+extern const char *const __trunc_varying_double;
+extern const char *const __trunc_varying_float;
+extern const char *const __trunc_varying_half;
+extern const char *const __undef_uniform;
+extern const char *const __undef_varying;
+extern const char *const __vec4_add_float;
+extern const char *const __vec4_add_int32;
+extern const char *const __vselect_float;
+extern const char *const __vselect_i32;
+
+} // namespace builtin
+
+} // namespace ispc
diff --git a/src/builtins.cpp b/src/builtins.cpp
index e76adefdbc..a0b776e40c 100644
--- a/src/builtins.cpp
+++ b/src/builtins.cpp
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2010-2023, Intel Corporation
+  Copyright (c) 2010-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -43,6 +43,7 @@
 #endif
 
 using namespace ispc;
+using namespace ispc::builtin;
 
 extern int yyparse();
 struct yy_buffer_state;
@@ -173,7 +174,7 @@ static bool lCreateISPCSymbol(llvm::Function *func, SymbolTable *symbolTable) {
     // symbol creation code below assumes that any LLVM vector of i32s is a
     // varying int32.  Here, we need that to be interpreted as a varying
     // bool, so just have a one-off override for that one...
-    if (g->target->getMaskBitCount() != 1 && name == "__sext_varying_bool") {
+    if (g->target->getMaskBitCount() != 1 && name == builtin::__sext_varying_bool) {
         const Type *returnType = AtomicType::VaryingInt32;
         llvm::SmallVector<const Type *, 8> argTypes;
         argTypes.push_back(AtomicType::VaryingBool);
@@ -353,621 +354,618 @@ static void lCheckModuleIntrinsics(llvm::Module *module) {
 static void lSetInternalFunctions(llvm::Module *module) {
     // clang-format off
     const char *names[] = {
-        "__add_float",
-        "__add_int32",
-        "__add_uniform_double",
-        "__add_uniform_int32",
-        "__add_uniform_int64",
-        "__add_varying_double",
-        "__add_varying_int32",
-        "__add_varying_int64",
-        "__all",
-        "__any",
-        "__aos_to_soa2_double",
-        "__aos_to_soa2_double1",
-        "__aos_to_soa2_double16",
-        "__aos_to_soa2_double32",
-        "__aos_to_soa2_double4",
-        "__aos_to_soa2_double64",
-        "__aos_to_soa2_double8",
-        "__aos_to_soa2_float",
-        "__aos_to_soa2_float1",
-        "__aos_to_soa2_float16",
-        "__aos_to_soa2_float32",
-        "__aos_to_soa2_float4",
-        "__aos_to_soa2_float64",
-        "__aos_to_soa2_float8",
-        "__aos_to_soa3_double",
-        "__aos_to_soa3_double1",
-        "__aos_to_soa3_double16",
-        "__aos_to_soa3_double32",
-        "__aos_to_soa3_double4",
-        "__aos_to_soa3_double64",
-        "__aos_to_soa3_double8",
-        "__aos_to_soa3_float",
-        "__aos_to_soa3_float1",
-        "__aos_to_soa3_float16",
-        "__aos_to_soa3_float32",
-        "__aos_to_soa3_float4",
-        "__aos_to_soa3_float64",
-        "__aos_to_soa3_float8",
-        "__aos_to_soa4_double",
-        "__aos_to_soa4_double1",
-        "__aos_to_soa4_double16",
-        "__aos_to_soa4_double32",
-        "__aos_to_soa4_double4",
-        "__aos_to_soa4_double64",
-        "__aos_to_soa4_double8",
-        "__aos_to_soa4_float",
-        "__aos_to_soa4_float1",
-        "__aos_to_soa4_float16",
-        "__aos_to_soa4_float32",
-        "__aos_to_soa4_float4",
-        "__aos_to_soa4_float64",
-        "__aos_to_soa4_float8",
-        "__atomic_add_int32_global",
-        "__atomic_add_int64_global",
-        "__atomic_add_uniform_int32_global",
-        "__atomic_add_uniform_int64_global",
-        "__atomic_and_int32_global",
-        "__atomic_and_int64_global",
-        "__atomic_and_uniform_int32_global",
-        "__atomic_and_uniform_int64_global",
-        "__atomic_compare_exchange_double_global",
-        "__atomic_compare_exchange_float_global",
-        "__atomic_compare_exchange_int32_global",
-        "__atomic_compare_exchange_int64_global",
-        "__atomic_compare_exchange_uniform_double_global",
-        "__atomic_compare_exchange_uniform_float_global",
-        "__atomic_compare_exchange_uniform_int32_global",
-        "__atomic_compare_exchange_uniform_int64_global",
-        "__atomic_max_uniform_int32_global",
-        "__atomic_max_uniform_int64_global",
-        "__atomic_min_uniform_int32_global",
-        "__atomic_min_uniform_int64_global",
-        "__atomic_or_int32_global",
-        "__atomic_or_int64_global",
-        "__atomic_or_uniform_int32_global",
-        "__atomic_or_uniform_int64_global",
-        "__atomic_sub_int32_global",
-        "__atomic_sub_int64_global",
-        "__atomic_sub_uniform_int32_global",
-        "__atomic_sub_uniform_int64_global",
-        "__atomic_swap_double_global",
-        "__atomic_swap_float_global",
-        "__atomic_swap_int32_global",
-        "__atomic_swap_int64_global",
-        "__atomic_swap_uniform_double_global",
-        "__atomic_swap_uniform_float_global",
-        "__atomic_swap_uniform_int32_global",
-        "__atomic_swap_uniform_int64_global",
-        "__atomic_umax_uniform_uint32_global",
-        "__atomic_umax_uniform_uint64_global",
-        "__atomic_umin_uniform_uint32_global",
-        "__atomic_umin_uniform_uint64_global",
-        "__atomic_xor_int32_global",
-        "__atomic_xor_int64_global",
-        "__atomic_xor_uniform_int32_global",
-        "__atomic_xor_uniform_int64_global",
-        "__broadcast_double",
-        "__broadcast_float",
-        "__broadcast_half",
-        "__broadcast_i16",
-        "__broadcast_i32",
-        "__broadcast_i64",
-        "__broadcast_i8",
-        "__cast_mask_to_i1",
-        "__cast_mask_to_i8",
-        "__cast_mask_to_i16",
-        "__cast_mask_to_i32",
-        "__cast_mask_to_i64",
-        "__ceil_uniform_double",
-        "__ceil_uniform_float",
-        "__ceil_uniform_half",
-        "__ceil_varying_double",
-        "__ceil_varying_float",
-        "__ceil_varying_half",
-        "__clock",
-        "__count_trailing_zeros_i32",
-        "__count_trailing_zeros_i64",
-        "__count_leading_zeros_i32",
-        "__count_leading_zeros_i64",
-        "__delete_uniform_32rt",
-        "__delete_uniform_64rt",
-        "__delete_varying_32rt",
-        "__delete_varying_64rt",
-        "__do_assume_uniform",
-        "__do_assert_uniform",
-        "__do_assert_varying",
-        "__do_print",
-#ifdef ISPC_XE_ENABLED
-        "__send_eot",
-#endif //ISPC_XE_ENABLED
-        "__doublebits_uniform_int64",
-        "__doublebits_varying_int64",
-        "__exclusive_scan_add_double",
-        "__exclusive_scan_add_float",
-        "__exclusive_scan_add_half",
-        "__exclusive_scan_add_i32",
-        "__exclusive_scan_add_i64",
-        "__exclusive_scan_and_i32",
-        "__exclusive_scan_and_i64",
-        "__exclusive_scan_or_i32",
-        "__exclusive_scan_or_i64",
-        "__extract_bool",
-        "__extract_int16",
-        "__extract_int32",
-        "__extract_int64",
-        "__extract_int8",
-        "__extract_mask_low",
-        "__extract_mask_hi",
-        "__fastmath",
-        "__float_to_half_uniform",
-        "__float_to_half_varying",
-        "__halfbits_uniform_int16",
-        "__halfbits_varying_int16",
-        "__floatbits_uniform_int32",
-        "__floatbits_varying_int32",
-        "__floor_uniform_double",
-        "__floor_uniform_float",
-        "__floor_uniform_half",
-        "__floor_varying_double",
-        "__floor_varying_float",
-        "__floor_varying_half",
-        "__get_system_isa",
-        "__half_to_float_uniform",
-        "__half_to_float_varying",
-        "__idiv_uint8",
-        "__idiv_uint16",
-        "__idiv_uint32",
-        "__idiv_int8",
-        "__idiv_int16",
-        "__idiv_int32",
-        "__insert_bool",
-        "__insert_int16",
-        "__insert_int32",
-        "__insert_int64",
-        "__insert_int8",
-        "__intbits_uniform_double",
-        "__intbits_uniform_float",
-        "__intbits_uniform_half",
-        "__intbits_varying_double",
-        "__intbits_varying_float",
-        "__intbits_varying_half",
-        "__max_uniform_double",
-        "__max_uniform_float",
-        "__max_uniform_half",
-        "__max_uniform_int32",
-        "__max_uniform_int64",
-        "__max_uniform_uint32",
-        "__max_uniform_uint64",
-        "__max_varying_double",
-        "__max_varying_float",
-        "__max_varying_half",
-        "__max_varying_int32",
-        "__max_varying_int64",
-        "__max_varying_uint32",
-        "__max_varying_uint64",
-        "__memory_barrier",
-        "__memcpy32",
-        "__memcpy64",
-        "__memmove32",
-        "__memmove64",
-        "__memset32",
-        "__memset64",
-        "__min_uniform_double",
-        "__min_uniform_float",
-        "__min_uniform_half",
-        "__min_uniform_int32",
-        "__min_uniform_int64",
-        "__min_uniform_uint32",
-        "__min_uniform_uint64",
-        "__min_varying_double",
-        "__min_varying_float",
-        "__min_varying_half",
-        "__min_varying_int32",
-        "__min_varying_int64",
-        "__min_varying_uint32",
-        "__min_varying_uint64",
-        "__movmsk",
-        "__new_uniform_32rt",
-        "__new_uniform_64rt",
-        "__new_varying32_32rt",
-        "__new_varying32_64rt",
-        "__new_varying64_64rt",
-        "__none",
-        "__num_cores",
-        "__packed_load_activei32",
-        "__packed_load_activei64",
-        "__packed_store_activei32",
-        "__packed_store_activei64",
-        "__packed_store_active2i32",
-        "__packed_store_active2i64",
-        "__padds_ui8",
-        "__padds_ui16",
-        "__padds_ui32",
-        "__padds_ui64",
-        "__padds_vi8",
-        "__padds_vi16",
-        "__padds_vi32",
-        "__padds_vi64",
-        "__paddus_ui8",
-        "__paddus_ui16",
-        "__paddus_ui32",
-        "__paddus_ui64",
-        "__paddus_vi8",
-        "__paddus_vi16",
-        "__paddus_vi32",
-        "__paddus_vi64",
-        "__pmuls_ui8",
-        "__pmuls_ui16",
-        "__pmuls_ui32",
-        "__pmuls_vi8",
-        "__pmuls_vi16",
-        "__pmuls_vi32",
-        "__pmulus_ui8",
-        "__pmulus_ui16",
-        "__pmulus_ui32",
-        "__pmulus_vi8",
-        "__pmulus_vi16",
-        "__pmulus_vi32",
-        "__popcnt_int32",
-        "__popcnt_int64",
-        "__prefetch_read_uniform_1",
-        "__prefetch_read_uniform_2",
-        "__prefetch_read_uniform_3",
-        "__prefetch_read_uniform_nt",
-        "__prefetch_write_uniform_1",
-        "__prefetch_write_uniform_2",
-        "__prefetch_write_uniform_3",
-        "__prefetch_read_sized_uniform_1",
-        "__prefetch_read_sized_uniform_2",
-        "__prefetch_read_sized_uniform_3",
-        "__prefetch_read_sized_uniform_nt",
-        "__pseudo_prefetch_read_varying_1",
-        "__pseudo_prefetch_read_varying_2",
-        "__pseudo_prefetch_read_varying_3",
-        "__pseudo_prefetch_read_varying_nt",
-        "__pseudo_prefetch_write_varying_1",
-        "__pseudo_prefetch_write_varying_2",
-        "__pseudo_prefetch_write_varying_3",
-        "__prefetch_read_sized_varying_1",
-        "__prefetch_read_sized_varying_2",
-        "__prefetch_read_sized_varying_3",
-        "__prefetch_read_sized_varying_nt",
-        "__psubs_ui8",
-        "__psubs_ui16",
-        "__psubs_ui32",
-        "__psubs_ui64",
-        "__psubs_vi8",
-        "__psubs_vi16",
-        "__psubs_vi32",
-        "__psubs_vi64",
-        "__psubus_ui8",
-        "__psubus_ui16",
-        "__psubus_ui32",
-        "__psubus_ui64",
-        "__psubus_vi8",
-        "__psubus_vi16",
-        "__psubus_vi32",
-        "__psubus_vi64",
-        "__rcp_fast_uniform_double",
-        "__rcp_fast_uniform_float",
-        "__rcp_fast_uniform_half",
-        "__rcp_fast_varying_double",
-        "__rcp_fast_varying_float",
-        "__rcp_fast_varying_half",
-        "__rcp_uniform_double",
-        "__rcp_uniform_float",
-        "__rcp_uniform_half",
-        "__rcp_varying_double",
-        "__rcp_varying_float",
-        "__rcp_varying_half",
-        "__rdrand_i16",
-        "__rdrand_i32",
-        "__rdrand_i64",
-        "__reduce_add_double",
-        "__reduce_add_float",
-        "__reduce_add_half",
-        "__reduce_add_int8",
-        "__reduce_add_int16",
-        "__reduce_add_int32",
-        "__reduce_add_int64",
-        "__reduce_equal_double",
-        "__reduce_equal_float",
-        "__reduce_equal_half",
-        "__reduce_equal_int32",
-        "__reduce_equal_int64",
-        "__reduce_max_double",
-        "__reduce_max_float",
-        "__reduce_max_half",
-        "__reduce_max_int32",
-        "__reduce_max_int64",
-        "__reduce_max_uint32",
-        "__reduce_max_uint64",
-        "__reduce_min_double",
-        "__reduce_min_float",
-        "__reduce_min_half",
-        "__reduce_min_int32",
-        "__reduce_min_int64",
-        "__reduce_min_uint32",
-        "__reduce_min_uint64",
-        "__restore_ftz_daz_flags",
-        "__rotate_double",
-        "__rotate_float",
-        "__rotate_half",
-        "__rotate_i16",
-        "__rotate_i32",
-        "__rotate_i64",
-        "__rotate_i8",
-        "__round_uniform_double",
-        "__round_uniform_float",
-        "__round_uniform_half",
-        "__round_varying_double",
-        "__round_varying_float",
-        "__round_varying_half",
-        "__rsqrt_fast_uniform_double",
-        "__rsqrt_fast_uniform_float",
-        "__rsqrt_fast_varying_double",
-        "__rsqrt_fast_varying_float",
-        "__rsqrt_uniform_double",
-        "__rsqrt_uniform_float",
-        "__rsqrt_uniform_half",
-        "__rsqrt_varying_double",
-        "__rsqrt_varying_float",
-        "__rsqrt_varying_half",
-        "__saturating_add_i8",
-        "__saturating_add_i16",
-        "__saturating_add_i32",
-        "__saturating_add_i64",
-        "__saturating_add_ui8",
-        "__saturating_add_ui16",
-        "__saturating_add_ui32",
-        "__saturating_add_ui64",
-        "__saturating_mul_i8",
-        "__saturating_mul_i16",
-        "__saturating_mul_i32",
-        "__saturating_mul_ui8",
-        "__saturating_mul_ui16",
-        "__saturating_mul_ui32",
-        "__set_ftz_daz_flags",
-        "__set_system_isa",
-        "__sext_uniform_bool",
-        "__sext_varying_bool",
-        "__shift_double",
-        "__shift_float",
-        "__shift_half",
-        "__shift_i16",
-        "__shift_i32",
-        "__shift_i64",
-        "__shift_i8",
-        "__shuffle2_double",
-        "__shuffle2_float",
-        "__shuffle2_half",
-        "__shuffle2_i16",
-        "__shuffle2_i32",
-        "__shuffle2_i64",
-        "__shuffle2_i8",
-        "__shuffle_double",
-        "__shuffle_float",
-        "__shuffle_half",
-        "__shuffle_i16",
-        "__shuffle_i32",
-        "__shuffle_i64",
-        "__shuffle_i8",
-        "__soa_to_aos2_double",
-        "__soa_to_aos2_double1",
-        "__soa_to_aos2_double16",
-        "__soa_to_aos2_double32",
-        "__soa_to_aos2_double4",
-        "__soa_to_aos2_double64",
-        "__soa_to_aos2_double8",
-        "__soa_to_aos2_float",
-        "__soa_to_aos2_float1",
-        "__soa_to_aos2_float16",
-        "__soa_to_aos2_float32",
-        "__soa_to_aos2_float4",
-        "__soa_to_aos2_float64",
-        "__soa_to_aos2_float8",
-        "__soa_to_aos3_double",
-        "__soa_to_aos3_double1",
-        "__soa_to_aos3_double16",
-        "__soa_to_aos3_double32",
-        "__soa_to_aos3_double4",
-        "__soa_to_aos3_double64",
-        "__soa_to_aos3_double8",
-        "__soa_to_aos3_float",
-        "__soa_to_aos3_float1",
-        "__soa_to_aos3_float16",
-        "__soa_to_aos3_float32",
-        "__soa_to_aos3_float4",
-        "__soa_to_aos3_float64",
-        "__soa_to_aos3_float8",
-        "__soa_to_aos4_double",
-        "__soa_to_aos4_double1",
-        "__soa_to_aos4_double16",
-        "__soa_to_aos4_double32",
-        "__soa_to_aos4_double4",
-        "__soa_to_aos4_double64",
-        "__soa_to_aos4_double8",
-        "__soa_to_aos4_float",
-        "__soa_to_aos4_float1",
-        "__soa_to_aos4_float16",
-        "__soa_to_aos4_float32",
-        "__soa_to_aos4_float4",
-        "__soa_to_aos4_float64",
-        "__soa_to_aos4_float8",
-        "__sqrt_uniform_double",
-        "__sqrt_uniform_float",
-        "__sqrt_uniform_half",
-        "__sqrt_varying_double",
-        "__sqrt_varying_float",
-        "__sqrt_varying_half",
-        "__stdlib_acosf",
-        "__stdlib_asinf",
-        "__stdlib_atan",
-        "__stdlib_atan2",
-        "__stdlib_atan2f",
-        "__stdlib_atanf",
-        "__stdlib_cos",
-        "__stdlib_cosf",
-        "__stdlib_exp",
-        "__stdlib_expf",
-        "__stdlib_log",
-        "__stdlib_logf",
-        "__stdlib_pow",
-        "__stdlib_powf",
-        "__stdlib_sin",
-        "__stdlib_asin",
-        "__stdlib_sincos",
-        "__stdlib_sincosf",
-        "__stdlib_sinf",
-        "__stdlib_tan",
-        "__stdlib_tanf",
-        "__streaming_load_uniform_double",
-        "__streaming_load_uniform_float",
-        "__streaming_load_uniform_half",
-        "__streaming_load_uniform_i8",
-        "__streaming_load_uniform_i16",
-        "__streaming_load_uniform_i32",
-        "__streaming_load_uniform_i64",
-        "__streaming_load_varying_double",
-        "__streaming_load_varying_float",
-        "__streaming_load_varying_half",
-        "__streaming_load_varying_i8",
-        "__streaming_load_varying_i16",
-        "__streaming_load_varying_i32",
-        "__streaming_load_varying_i64",
-        "__streaming_store_uniform_double",
-        "__streaming_store_uniform_float",
-        "__streaming_store_uniform_half",
-        "__streaming_store_uniform_i8",
-        "__streaming_store_uniform_i16",
-        "__streaming_store_uniform_i32",
-        "__streaming_store_uniform_i64",
-        "__streaming_store_varying_double",
-        "__streaming_store_varying_float",
-        "__streaming_store_varying_half",
-        "__streaming_store_varying_i8",
-        "__streaming_store_varying_i16",
-        "__streaming_store_varying_i32",
-        "__streaming_store_varying_i64",
-        "__svml_sind",
-        "__svml_asind",
-        "__svml_cosd",
-        "__svml_acosd",
-        "__svml_sincosd",
-        "__svml_tand",
-        "__svml_atand",
-        "__svml_atan2d",
-        "__svml_expd",
-        "__svml_logd",
-        "__svml_powd",
-        "__svml_sqrtd",
-        "__svml_invsqrtd",
-        "__svml_sinf",
-        "__svml_asinf",
-        "__svml_cosf",
-        "__svml_acosf",
-        "__svml_sincosf",
-        "__svml_tanf",
-        "__svml_atanf",
-        "__svml_atan2f",
-        "__svml_expf",
-        "__svml_logf",
-        "__svml_powf",
-        "__svml_sqrtf",
-        "__svml_invsqrtf",
-        "__trunc_uniform_double",
-        "__trunc_uniform_float",
-        "__trunc_uniform_half",
-        "__trunc_varying_double",
-        "__trunc_varying_float",
-        "__trunc_varying_half",
-        "__log_uniform_half",
-        "__log_varying_half",
-        "__exp_uniform_half",
-        "__exp_varying_half",
-        "__pow_uniform_half",
-        "__pow_varying_half",
-        "__log_uniform_float",
-        "__log_varying_float",
-        "__exp_uniform_float",
-        "__exp_varying_float",
-        "__pow_uniform_float",
-        "__pow_varying_float",
-        "__log_uniform_double",
-        "__log_varying_double",
-        "__exp_uniform_double",
-        "__exp_varying_double",
-        "__pow_uniform_double",
-        "__pow_varying_double",
-        "__sin_varying_float",
-        "__asin_varying_float",
-        "__cos_varying_float",
-        "__acos_varying_float",
-        "__sincos_varying_float",
-        "__tan_varying_float",
-        "__atan_varying_float",
-        "__atan2_varying_float",
-        "__sin_uniform_float",
-        "__asin_uniform_float",
-        "__cos_uniform_float",
-        "__acos_uniform_float",
-        "__sincos_uniform_float",
-        "__tan_uniform_float",
-        "__atan_uniform_float",
-        "__atan2_uniform_float",
-        "__sin_varying_half",
-        "__asin_varying_half",
-        "__cos_varying_half",
-        "__acos_varying_half",
-        "__sincos_varying_half",
-        "__tan_varying_half",
-        "__atan_varying_half",
-        "__atan2_varying_half",
-        "__sin_uniform_half",
-        "__asin_uniform_half",
-        "__cos_uniform_half",
-        "__acos_uniform_half",
-        "__sincos_uniform_half",
-        "__tan_uniform_half",
-        "__atan_uniform_half",
-        "__atan2_uniform_half",
-        "__sin_varying_double",
-        "__asin_varying_double",
-        "__cos_varying_double",
-        "__acos_varying_double",
-        "__sincos_varying_double",
-        "__tan_varying_double",
-        "__atan_varying_double",
-        "__atan2_varying_double",
-        "__sin_uniform_double",
-        "__asin_uniform_double",
-        "__cos_uniform_double",
-        "__acos_uniform_double",
-        "__sincos_uniform_double",
-        "__tan_uniform_double",
-        "__atan_uniform_double",
-        "__atan2_uniform_double",
-        "__undef_uniform",
-        "__undef_varying",
-        "__vec4_add_float",
-        "__vec4_add_int32",
-        "__vselect_float",
-        "__vselect_i32",
-        "ISPCAlloc",
-        "ISPCLaunch",
-        "ISPCSync",
-// ISPC_XE_ENABLED
-        "__task_index0",
-        "__task_index1",
-        "__task_index2",
-        "__task_index",
-        "__task_count0",
-        "__task_count1",
-        "__task_count2",
-        "__task_count",
+        __add_float,
+        __add_int32,
+        __add_uniform_double,
+        __add_uniform_int32,
+        __add_uniform_int64,
+        __add_varying_double,
+        __add_varying_int32,
+        __add_varying_int64,
+        __all,
+        __any,
+        __aos_to_soa2_double,
+        __aos_to_soa2_double1,
+        __aos_to_soa2_double16,
+        __aos_to_soa2_double32,
+        __aos_to_soa2_double4,
+        __aos_to_soa2_double64,
+        __aos_to_soa2_double8,
+        __aos_to_soa2_float,
+        __aos_to_soa2_float1,
+        __aos_to_soa2_float16,
+        __aos_to_soa2_float32,
+        __aos_to_soa2_float4,
+        __aos_to_soa2_float64,
+        __aos_to_soa2_float8,
+        __aos_to_soa3_double,
+        __aos_to_soa3_double1,
+        __aos_to_soa3_double16,
+        __aos_to_soa3_double32,
+        __aos_to_soa3_double4,
+        __aos_to_soa3_double64,
+        __aos_to_soa3_double8,
+        __aos_to_soa3_float,
+        __aos_to_soa3_float1,
+        __aos_to_soa3_float16,
+        __aos_to_soa3_float32,
+        __aos_to_soa3_float4,
+        __aos_to_soa3_float64,
+        __aos_to_soa3_float8,
+        __aos_to_soa4_double,
+        __aos_to_soa4_double1,
+        __aos_to_soa4_double16,
+        __aos_to_soa4_double32,
+        __aos_to_soa4_double4,
+        __aos_to_soa4_double64,
+        __aos_to_soa4_double8,
+        __aos_to_soa4_float,
+        __aos_to_soa4_float1,
+        __aos_to_soa4_float16,
+        __aos_to_soa4_float32,
+        __aos_to_soa4_float4,
+        __aos_to_soa4_float64,
+        __aos_to_soa4_float8,
+        __atomic_add_int32_global,
+        __atomic_add_int64_global,
+        __atomic_add_uniform_int32_global,
+        __atomic_add_uniform_int64_global,
+        __atomic_and_int32_global,
+        __atomic_and_int64_global,
+        __atomic_and_uniform_int32_global,
+        __atomic_and_uniform_int64_global,
+        __atomic_compare_exchange_double_global,
+        __atomic_compare_exchange_float_global,
+        __atomic_compare_exchange_int32_global,
+        __atomic_compare_exchange_int64_global,
+        __atomic_compare_exchange_uniform_double_global,
+        __atomic_compare_exchange_uniform_float_global,
+        __atomic_compare_exchange_uniform_int32_global,
+        __atomic_compare_exchange_uniform_int64_global,
+        __atomic_max_uniform_int32_global,
+        __atomic_max_uniform_int64_global,
+        __atomic_min_uniform_int32_global,
+        __atomic_min_uniform_int64_global,
+        __atomic_or_int32_global,
+        __atomic_or_int64_global,
+        __atomic_or_uniform_int32_global,
+        __atomic_or_uniform_int64_global,
+        __atomic_sub_int32_global,
+        __atomic_sub_int64_global,
+        __atomic_sub_uniform_int32_global,
+        __atomic_sub_uniform_int64_global,
+        __atomic_swap_double_global,
+        __atomic_swap_float_global,
+        __atomic_swap_int32_global,
+        __atomic_swap_int64_global,
+        __atomic_swap_uniform_double_global,
+        __atomic_swap_uniform_float_global,
+        __atomic_swap_uniform_int32_global,
+        __atomic_swap_uniform_int64_global,
+        __atomic_umax_uniform_uint32_global,
+        __atomic_umax_uniform_uint64_global,
+        __atomic_umin_uniform_uint32_global,
+        __atomic_umin_uniform_uint64_global,
+        __atomic_xor_int32_global,
+        __atomic_xor_int64_global,
+        __atomic_xor_uniform_int32_global,
+        __atomic_xor_uniform_int64_global,
+        __broadcast_double,
+        __broadcast_float,
+        __broadcast_half,
+        __broadcast_i16,
+        __broadcast_i32,
+        __broadcast_i64,
+        __broadcast_i8,
+        __cast_mask_to_i1,
+        __cast_mask_to_i8,
+        __cast_mask_to_i16,
+        __cast_mask_to_i32,
+        __cast_mask_to_i64,
+        __ceil_uniform_double,
+        __ceil_uniform_float,
+        __ceil_uniform_half,
+        __ceil_varying_double,
+        __ceil_varying_float,
+        __ceil_varying_half,
+        __clock,
+        __count_trailing_zeros_i32,
+        __count_trailing_zeros_i64,
+        __count_leading_zeros_i32,
+        __count_leading_zeros_i64,
+        __delete_uniform_32rt,
+        __delete_uniform_64rt,
+        __delete_varying_32rt,
+        __delete_varying_64rt,
+        __do_assume_uniform,
+        __do_assert_uniform,
+        __do_assert_varying,
+        __do_print,
+        __send_eot,
+        __doublebits_uniform_int64,
+        __doublebits_varying_int64,
+        __exclusive_scan_add_double,
+        __exclusive_scan_add_float,
+        __exclusive_scan_add_half,
+        __exclusive_scan_add_i32,
+        __exclusive_scan_add_i64,
+        __exclusive_scan_and_i32,
+        __exclusive_scan_and_i64,
+        __exclusive_scan_or_i32,
+        __exclusive_scan_or_i64,
+        __extract_bool,
+        __extract_int16,
+        __extract_int32,
+        __extract_int64,
+        __extract_int8,
+        __extract_mask_low,
+        __extract_mask_hi,
+        __fastmath,
+        __float_to_half_uniform,
+        __float_to_half_varying,
+        __halfbits_uniform_int16,
+        __halfbits_varying_int16,
+        __floatbits_uniform_int32,
+        __floatbits_varying_int32,
+        __floor_uniform_double,
+        __floor_uniform_float,
+        __floor_uniform_half,
+        __floor_varying_double,
+        __floor_varying_float,
+        __floor_varying_half,
+        __get_system_isa,
+        __half_to_float_uniform,
+        __half_to_float_varying,
+        __idiv_uint8,
+        __idiv_uint16,
+        __idiv_uint32,
+        __idiv_int8,
+        __idiv_int16,
+        __idiv_int32,
+        __insert_bool,
+        __insert_int16,
+        __insert_int32,
+        __insert_int64,
+        __insert_int8,
+        __intbits_uniform_double,
+        __intbits_uniform_float,
+        __intbits_uniform_half,
+        __intbits_varying_double,
+        __intbits_varying_float,
+        __intbits_varying_half,
+        __max_uniform_double,
+        __max_uniform_float,
+        __max_uniform_half,
+        __max_uniform_int32,
+        __max_uniform_int64,
+        __max_uniform_uint32,
+        __max_uniform_uint64,
+        __max_varying_double,
+        __max_varying_float,
+        __max_varying_half,
+        __max_varying_int32,
+        __max_varying_int64,
+        __max_varying_uint32,
+        __max_varying_uint64,
+        __memory_barrier,
+        __memcpy32,
+        __memcpy64,
+        __memmove32,
+        __memmove64,
+        __memset32,
+        __memset64,
+        __min_uniform_double,
+        __min_uniform_float,
+        __min_uniform_half,
+        __min_uniform_int32,
+        __min_uniform_int64,
+        __min_uniform_uint32,
+        __min_uniform_uint64,
+        __min_varying_double,
+        __min_varying_float,
+        __min_varying_half,
+        __min_varying_int32,
+        __min_varying_int64,
+        __min_varying_uint32,
+        __min_varying_uint64,
+        __movmsk,
+        __new_uniform_32rt,
+        __new_uniform_64rt,
+        __new_varying32_32rt,
+        __new_varying32_64rt,
+        __new_varying64_64rt,
+        __none,
+        __num_cores,
+        __packed_load_activei32,
+        __packed_load_activei64,
+        __packed_store_activei32,
+        __packed_store_activei64,
+        __packed_store_active2i32,
+        __packed_store_active2i64,
+        __padds_ui8,
+        __padds_ui16,
+        __padds_ui32,
+        __padds_ui64,
+        __padds_vi8,
+        __padds_vi16,
+        __padds_vi32,
+        __padds_vi64,
+        __paddus_ui8,
+        __paddus_ui16,
+        __paddus_ui32,
+        __paddus_ui64,
+        __paddus_vi8,
+        __paddus_vi16,
+        __paddus_vi32,
+        __paddus_vi64,
+        __pmuls_ui8,
+        __pmuls_ui16,
+        __pmuls_ui32,
+        __pmuls_vi8,
+        __pmuls_vi16,
+        __pmuls_vi32,
+        __pmulus_ui8,
+        __pmulus_ui16,
+        __pmulus_ui32,
+        __pmulus_vi8,
+        __pmulus_vi16,
+        __pmulus_vi32,
+        __popcnt_int32,
+        __popcnt_int64,
+        __prefetch_read_uniform_1,
+        __prefetch_read_uniform_2,
+        __prefetch_read_uniform_3,
+        __prefetch_read_uniform_nt,
+        __prefetch_write_uniform_1,
+        __prefetch_write_uniform_2,
+        __prefetch_write_uniform_3,
+        __prefetch_read_sized_uniform_1,
+        __prefetch_read_sized_uniform_2,
+        __prefetch_read_sized_uniform_3,
+        __prefetch_read_sized_uniform_nt,
+        __pseudo_prefetch_read_varying_1,
+        __pseudo_prefetch_read_varying_2,
+        __pseudo_prefetch_read_varying_3,
+        __pseudo_prefetch_read_varying_nt,
+        __pseudo_prefetch_write_varying_1,
+        __pseudo_prefetch_write_varying_2,
+        __pseudo_prefetch_write_varying_3,
+        __prefetch_read_sized_varying_1,
+        __prefetch_read_sized_varying_2,
+        __prefetch_read_sized_varying_3,
+        __prefetch_read_sized_varying_nt,
+        __psubs_ui8,
+        __psubs_ui16,
+        __psubs_ui32,
+        __psubs_ui64,
+        __psubs_vi8,
+        __psubs_vi16,
+        __psubs_vi32,
+        __psubs_vi64,
+        __psubus_ui8,
+        __psubus_ui16,
+        __psubus_ui32,
+        __psubus_ui64,
+        __psubus_vi8,
+        __psubus_vi16,
+        __psubus_vi32,
+        __psubus_vi64,
+        __rcp_fast_uniform_double,
+        __rcp_fast_uniform_float,
+        __rcp_fast_uniform_half,
+        __rcp_fast_varying_double,
+        __rcp_fast_varying_float,
+        __rcp_fast_varying_half,
+        __rcp_uniform_double,
+        __rcp_uniform_float,
+        __rcp_uniform_half,
+        __rcp_varying_double,
+        __rcp_varying_float,
+        __rcp_varying_half,
+        __rdrand_i16,
+        __rdrand_i32,
+        __rdrand_i64,
+        __reduce_add_double,
+        __reduce_add_float,
+        __reduce_add_half,
+        __reduce_add_int8,
+        __reduce_add_int16,
+        __reduce_add_int32,
+        __reduce_add_int64,
+        __reduce_equal_double,
+        __reduce_equal_float,
+        __reduce_equal_half,
+        __reduce_equal_int32,
+        __reduce_equal_int64,
+        __reduce_max_double,
+        __reduce_max_float,
+        __reduce_max_half,
+        __reduce_max_int32,
+        __reduce_max_int64,
+        __reduce_max_uint32,
+        __reduce_max_uint64,
+        __reduce_min_double,
+        __reduce_min_float,
+        __reduce_min_half,
+        __reduce_min_int32,
+        __reduce_min_int64,
+        __reduce_min_uint32,
+        __reduce_min_uint64,
+        __restore_ftz_daz_flags,
+        __rotate_double,
+        __rotate_float,
+        __rotate_half,
+        __rotate_i16,
+        __rotate_i32,
+        __rotate_i64,
+        __rotate_i8,
+        __round_uniform_double,
+        __round_uniform_float,
+        __round_uniform_half,
+        __round_varying_double,
+        __round_varying_float,
+        __round_varying_half,
+        __rsqrt_fast_uniform_double,
+        __rsqrt_fast_uniform_float,
+        __rsqrt_fast_varying_double,
+        __rsqrt_fast_varying_float,
+        __rsqrt_uniform_double,
+        __rsqrt_uniform_float,
+        __rsqrt_uniform_half,
+        __rsqrt_varying_double,
+        __rsqrt_varying_float,
+        __rsqrt_varying_half,
+        __saturating_add_i8,
+        __saturating_add_i16,
+        __saturating_add_i32,
+        __saturating_add_i64,
+        __saturating_add_ui8,
+        __saturating_add_ui16,
+        __saturating_add_ui32,
+        __saturating_add_ui64,
+        __saturating_mul_i8,
+        __saturating_mul_i16,
+        __saturating_mul_i32,
+        __saturating_mul_ui8,
+        __saturating_mul_ui16,
+        __saturating_mul_ui32,
+        __set_ftz_daz_flags,
+        __set_system_isa,
+        __sext_uniform_bool,
+        __sext_varying_bool,
+        __shift_double,
+        __shift_float,
+        __shift_half,
+        __shift_i16,
+        __shift_i32,
+        __shift_i64,
+        __shift_i8,
+        __shuffle2_double,
+        __shuffle2_float,
+        __shuffle2_half,
+        __shuffle2_i16,
+        __shuffle2_i32,
+        __shuffle2_i64,
+        __shuffle2_i8,
+        __shuffle_double,
+        __shuffle_float,
+        __shuffle_half,
+        __shuffle_i16,
+        __shuffle_i32,
+        __shuffle_i64,
+        __shuffle_i8,
+        __soa_to_aos2_double,
+        __soa_to_aos2_double1,
+        __soa_to_aos2_double16,
+        __soa_to_aos2_double32,
+        __soa_to_aos2_double4,
+        __soa_to_aos2_double64,
+        __soa_to_aos2_double8,
+        __soa_to_aos2_float,
+        __soa_to_aos2_float1,
+        __soa_to_aos2_float16,
+        __soa_to_aos2_float32,
+        __soa_to_aos2_float4,
+        __soa_to_aos2_float64,
+        __soa_to_aos2_float8,
+        __soa_to_aos3_double,
+        __soa_to_aos3_double1,
+        __soa_to_aos3_double16,
+        __soa_to_aos3_double32,
+        __soa_to_aos3_double4,
+        __soa_to_aos3_double64,
+        __soa_to_aos3_double8,
+        __soa_to_aos3_float,
+        __soa_to_aos3_float1,
+        __soa_to_aos3_float16,
+        __soa_to_aos3_float32,
+        __soa_to_aos3_float4,
+        __soa_to_aos3_float64,
+        __soa_to_aos3_float8,
+        __soa_to_aos4_double,
+        __soa_to_aos4_double1,
+        __soa_to_aos4_double16,
+        __soa_to_aos4_double32,
+        __soa_to_aos4_double4,
+        __soa_to_aos4_double64,
+        __soa_to_aos4_double8,
+        __soa_to_aos4_float,
+        __soa_to_aos4_float1,
+        __soa_to_aos4_float16,
+        __soa_to_aos4_float32,
+        __soa_to_aos4_float4,
+        __soa_to_aos4_float64,
+        __soa_to_aos4_float8,
+        __sqrt_uniform_double,
+        __sqrt_uniform_float,
+        __sqrt_uniform_half,
+        __sqrt_varying_double,
+        __sqrt_varying_float,
+        __sqrt_varying_half,
+        __stdlib_acosf,
+        __stdlib_asinf,
+        __stdlib_atan,
+        __stdlib_atan2,
+        __stdlib_atan2f,
+        __stdlib_atanf,
+        __stdlib_cos,
+        __stdlib_cosf,
+        __stdlib_exp,
+        __stdlib_expf,
+        __stdlib_log,
+        __stdlib_logf,
+        __stdlib_pow,
+        __stdlib_powf,
+        __stdlib_sin,
+        __stdlib_asin,
+        __stdlib_sincos,
+        __stdlib_sincosf,
+        __stdlib_sinf,
+        __stdlib_tan,
+        __stdlib_tanf,
+        __streaming_load_uniform_double,
+        __streaming_load_uniform_float,
+        __streaming_load_uniform_half,
+        __streaming_load_uniform_i8,
+        __streaming_load_uniform_i16,
+        __streaming_load_uniform_i32,
+        __streaming_load_uniform_i64,
+        __streaming_load_varying_double,
+        __streaming_load_varying_float,
+        __streaming_load_varying_half,
+        __streaming_load_varying_i8,
+        __streaming_load_varying_i16,
+        __streaming_load_varying_i32,
+        __streaming_load_varying_i64,
+        __streaming_store_uniform_double,
+        __streaming_store_uniform_float,
+        __streaming_store_uniform_half,
+        __streaming_store_uniform_i8,
+        __streaming_store_uniform_i16,
+        __streaming_store_uniform_i32,
+        __streaming_store_uniform_i64,
+        __streaming_store_varying_double,
+        __streaming_store_varying_float,
+        __streaming_store_varying_half,
+        __streaming_store_varying_i8,
+        __streaming_store_varying_i16,
+        __streaming_store_varying_i32,
+        __streaming_store_varying_i64,
+        __svml_sind,
+        __svml_asind,
+        __svml_cosd,
+        __svml_acosd,
+        __svml_sincosd,
+        __svml_tand,
+        __svml_atand,
+        __svml_atan2d,
+        __svml_expd,
+        __svml_logd,
+        __svml_powd,
+        __svml_sqrtd,
+        __svml_invsqrtd,
+        __svml_sinf,
+        __svml_asinf,
+        __svml_cosf,
+        __svml_acosf,
+        __svml_sincosf,
+        __svml_tanf,
+        __svml_atanf,
+        __svml_atan2f,
+        __svml_expf,
+        __svml_logf,
+        __svml_powf,
+        __svml_sqrtf,
+        __svml_invsqrtf,
+        __trunc_uniform_double,
+        __trunc_uniform_float,
+        __trunc_uniform_half,
+        __trunc_varying_double,
+        __trunc_varying_float,
+        __trunc_varying_half,
+        __log_uniform_half,
+        __log_varying_half,
+        __exp_uniform_half,
+        __exp_varying_half,
+        __pow_uniform_half,
+        __pow_varying_half,
+        __log_uniform_float,
+        __log_varying_float,
+        __exp_uniform_float,
+        __exp_varying_float,
+        __pow_uniform_float,
+        __pow_varying_float,
+        __log_uniform_double,
+        __log_varying_double,
+        __exp_uniform_double,
+        __exp_varying_double,
+        __pow_uniform_double,
+        __pow_varying_double,
+        __sin_varying_float,
+        __asin_varying_float,
+        __cos_varying_float,
+        __acos_varying_float,
+        __sincos_varying_float,
+        __tan_varying_float,
+        __atan_varying_float,
+        __atan2_varying_float,
+        __sin_uniform_float,
+        __asin_uniform_float,
+        __cos_uniform_float,
+        __acos_uniform_float,
+        __sincos_uniform_float,
+        __tan_uniform_float,
+        __atan_uniform_float,
+        __atan2_uniform_float,
+        __sin_varying_half,
+        __asin_varying_half,
+        __cos_varying_half,
+        __acos_varying_half,
+        __sincos_varying_half,
+        __tan_varying_half,
+        __atan_varying_half,
+        __atan2_varying_half,
+        __sin_uniform_half,
+        __asin_uniform_half,
+        __cos_uniform_half,
+        __acos_uniform_half,
+        __sincos_uniform_half,
+        __tan_uniform_half,
+        __atan_uniform_half,
+        __atan2_uniform_half,
+        __sin_varying_double,
+        __asin_varying_double,
+        __cos_varying_double,
+        __acos_varying_double,
+        __sincos_varying_double,
+        __tan_varying_double,
+        __atan_varying_double,
+        __atan2_varying_double,
+        __sin_uniform_double,
+        __asin_uniform_double,
+        __cos_uniform_double,
+        __acos_uniform_double,
+        __sincos_uniform_double,
+        __tan_uniform_double,
+        __atan_uniform_double,
+        __atan2_uniform_double,
+        __undef_uniform,
+        __undef_varying,
+        __vec4_add_float,
+        __vec4_add_int32,
+        __vselect_float,
+        __vselect_i32,
+        ISPCAlloc,
+        ISPCLaunch,
+        ISPCSync,
+        __task_index0,
+        __task_index1,
+        __task_index2,
+        __task_index,
+        __task_count0,
+        __task_count1,
+        __task_count2,
+        __task_count,
     };
     // clang-format on
     for (auto name : names) {
diff --git a/src/builtins.h b/src/builtins.h
index 55e250d31d..c28053985b 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2010-2023, Intel Corporation
+  Copyright (c) 2010-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -11,6 +11,7 @@
 
 #pragma once
 
+#include "builtins-decl.h"
 #include "ispc.h"
 
 namespace ispc {
diff --git a/src/ctx.cpp b/src/ctx.cpp
index 1bd3652b62..3a5a3aa397 100644
--- a/src/ctx.cpp
+++ b/src/ctx.cpp
@@ -9,6 +9,7 @@
 */
 
 #include "ctx.h"
+#include "builtins-decl.h"
 #include "expr.h"
 #include "func.h"
 #include "llvmutil.h"
@@ -1345,7 +1346,7 @@ void FunctionEmitContext::SetFunctionFTZ_DAZFlags() {
     if (functionFTZ_DAZValue == nullptr)
         return;
     std::vector<Symbol *> mm;
-    m->symbolTable->LookupFunction("__set_ftz_daz_flags", &mm);
+    m->symbolTable->LookupFunction(builtin::__set_ftz_daz_flags, &mm);
     AssertPos(currentPos, mm.size() >= 1);
     llvm::Function *fmm = mm[0]->function;
     std::vector<llvm::Value *> args;
@@ -1357,7 +1358,7 @@ void FunctionEmitContext::RestoreFunctionFTZ_DAZFlags() {
     if (functionFTZ_DAZValue == nullptr)
         return;
     std::vector<Symbol *> mm;
-    m->symbolTable->LookupFunction("__restore_ftz_daz_flags", &mm);
+    m->symbolTable->LookupFunction(builtin::__restore_ftz_daz_flags, &mm);
     AssertPos(currentPos, mm.size() >= 1);
     llvm::Function *fmm = mm[0]->function;
     llvm::Value *oldFTZ = LoadInst(functionFTZ_DAZValue);
@@ -1370,7 +1371,7 @@ llvm::Value *FunctionEmitContext::Any(llvm::Value *mask) {
     // Call the target-dependent any function to test that the mask is non-zero
 
     std::vector<Symbol *> mm;
-    m->symbolTable->LookupFunction("__any", &mm);
+    m->symbolTable->LookupFunction(builtin::__any, &mm);
     if (g->target->getMaskBitCount() == 1)
         AssertPos(currentPos, mm.size() == 1);
     else
@@ -1386,7 +1387,7 @@ llvm::Value *FunctionEmitContext::All(llvm::Value *mask) {
     // Call the target-dependent movmsk function to turn the vector mask
     // into an i64 value
     std::vector<Symbol *> mm;
-    m->symbolTable->LookupFunction("__all", &mm);
+    m->symbolTable->LookupFunction(builtin::__all, &mm);
     if (g->target->getMaskBitCount() == 1)
         AssertPos(currentPos, mm.size() == 1);
     else
@@ -1402,7 +1403,7 @@ llvm::Value *FunctionEmitContext::None(llvm::Value *mask) {
     // Call the target-dependent movmsk function to turn the vector mask
     // into an i64 value
     std::vector<Symbol *> mm;
-    m->symbolTable->LookupFunction("__none", &mm);
+    m->symbolTable->LookupFunction(builtin::__none, &mm);
     if (g->target->getMaskBitCount() == 1)
         AssertPos(currentPos, mm.size() == 1);
     else
@@ -1415,12 +1416,10 @@ llvm::Value *FunctionEmitContext::None(llvm::Value *mask) {
 }
 
 llvm::Value *FunctionEmitContext::LaneMask(llvm::Value *v) {
-    const char *__movmsk = "__movmsk";
-
     // Call the target-dependent movmsk function to turn the vector mask
     // into an i64 value
     std::vector<Symbol *> mm;
-    m->symbolTable->LookupFunction(__movmsk, &mm);
+    m->symbolTable->LookupFunction(builtin::__movmsk, &mm);
     if (g->target->getMaskBitCount() == 1)
         AssertPos(currentPos, mm.size() == 1);
     else
@@ -1600,8 +1599,14 @@ void FunctionEmitContext::EmitVariableDebugInfo(Symbol *sym) {
 
     llvm::DebugLoc diLoc =
         llvm::DILocation::get(scope->getContext(), sym->pos.first_line, sym->pos.first_column, scope, nullptr, false);
-    llvm::Instruction *declareInst = m->diBuilder->insertDeclare(sym->storageInfo->getPointer(), var,
-                                                                 m->diBuilder->createExpression(), diLoc, bblock);
+    llvm::Instruction *declareInst =
+#if ISPC_LLVM_VERSION >= ISPC_LLVM_19_0
+        llvm::cast<llvm::Instruction *>(m->diBuilder->insertDeclare(sym->storageInfo->getPointer(), var,
+                                                                    m->diBuilder->createExpression(), diLoc, bblock));
+#else
+        m->diBuilder->insertDeclare(sym->storageInfo->getPointer(), var, m->diBuilder->createExpression(), diLoc,
+                                    bblock);
+#endif
     AddDebugPos(declareInst, &sym->pos, scope);
 }
 
@@ -1618,8 +1623,14 @@ void FunctionEmitContext::EmitFunctionParameterDebugInfo(Symbol *sym, int argNum
 
     llvm::DebugLoc diLoc =
         llvm::DILocation::get(scope->getContext(), sym->pos.first_line, sym->pos.first_column, scope, nullptr, false);
-    llvm::Instruction *declareInst = m->diBuilder->insertDeclare(sym->storageInfo->getPointer(), var,
-                                                                 m->diBuilder->createExpression(), diLoc, bblock);
+    llvm::Instruction *declareInst =
+#if ISPC_LLVM_VERSION >= ISPC_LLVM_19_0
+        llvm::cast<llvm::Instruction *>(m->diBuilder->insertDeclare(sym->storageInfo->getPointer(), var,
+                                                                    m->diBuilder->createExpression(), diLoc, bblock));
+#else
+        m->diBuilder->insertDeclare(sym->storageInfo->getPointer(), var, m->diBuilder->createExpression(), diLoc,
+                                    bblock);
+#endif
     AddDebugPos(declareInst, &sym->pos, scope);
 }
 
@@ -2570,7 +2581,7 @@ llvm::Value *FunctionEmitContext::LoadInst(llvm::Value *ptr, llvm::Value *mask,
         // Call the target-dependent movmsk function to turn the vector mask
         // into an i64 value
         std::vector<Symbol *> mm;
-        m->symbolTable->LookupFunction("__movmsk", &mm);
+        m->symbolTable->LookupFunction(builtin::__movmsk, &mm);
         if (g->target->getMaskBitCount() == 1)
             AssertPos(currentPos, mm.size() == 1);
         else
@@ -2581,7 +2592,7 @@ llvm::Value *FunctionEmitContext::LoadInst(llvm::Value *ptr, llvm::Value *mask,
         llvm::Function *fmm = mm[0]->function;
         llvm::Value *int_mask = CallInst(fmm, nullptr, mask, llvm::Twine(mask->getName()) + "_movmsk");
         std::vector<Symbol *> lz;
-        m->symbolTable->LookupFunction("__count_trailing_zeros_i64", &lz);
+        m->symbolTable->LookupFunction(builtin::__count_trailing_zeros_i64, &lz);
         llvm::Function *flz = lz[0]->function;
         llvm::Value *elem_idx = CallInst(flz, nullptr, int_mask, llvm::Twine(mask->getName()) + "_clz");
         llvm::Value *elem = llvm::ExtractElementInst::Create(
@@ -2644,25 +2655,25 @@ llvm::Value *FunctionEmitContext::gather(llvm::Value *ptr, const PointerType *pt
     const PointerType *pt = CastType<PointerType>(returnType);
     const char *funcName = nullptr;
     if (pt != nullptr)
-        funcName = g->target->is32Bit() ? "__pseudo_gather32_i32" : "__pseudo_gather64_i64";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_gather32_i32 : builtin::__pseudo_gather64_i64;
     // bool type is stored as i8.
     else if (returnType->IsBoolType())
-        funcName = g->target->is32Bit() ? "__pseudo_gather32_i8" : "__pseudo_gather64_i8";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_gather32_i8 : builtin::__pseudo_gather64_i8;
     else if (llvmReturnType == LLVMTypes::DoubleVectorType)
-        funcName = g->target->is32Bit() ? "__pseudo_gather32_double" : "__pseudo_gather64_double";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_gather32_double : builtin::__pseudo_gather64_double;
     else if (llvmReturnType == LLVMTypes::Int64VectorType)
-        funcName = g->target->is32Bit() ? "__pseudo_gather32_i64" : "__pseudo_gather64_i64";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_gather32_i64 : builtin::__pseudo_gather64_i64;
     else if (llvmReturnType == LLVMTypes::FloatVectorType)
-        funcName = g->target->is32Bit() ? "__pseudo_gather32_float" : "__pseudo_gather64_float";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_gather32_float : builtin::__pseudo_gather64_float;
     else if (llvmReturnType == LLVMTypes::Float16VectorType)
-        funcName = g->target->is32Bit() ? "__pseudo_gather32_half" : "__pseudo_gather64_half";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_gather32_half : builtin::__pseudo_gather64_half;
     else if (llvmReturnType == LLVMTypes::Int32VectorType)
-        funcName = g->target->is32Bit() ? "__pseudo_gather32_i32" : "__pseudo_gather64_i32";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_gather32_i32 : builtin::__pseudo_gather64_i32;
     else if (llvmReturnType == LLVMTypes::Int16VectorType)
-        funcName = g->target->is32Bit() ? "__pseudo_gather32_i16" : "__pseudo_gather64_i16";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_gather32_i16 : builtin::__pseudo_gather64_i16;
     else {
         AssertPos(currentPos, llvmReturnType == LLVMTypes::Int8VectorType);
-        funcName = g->target->is32Bit() ? "__pseudo_gather32_i8" : "__pseudo_gather64_i8";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_gather32_i8 : builtin::__pseudo_gather64_i8;
     }
 
     llvm::Function *gatherFunc = m->module->getFunction(funcName);
@@ -2921,9 +2932,9 @@ void FunctionEmitContext::maskedStore(llvm::Value *value, llvm::Value *ptr, cons
         }
 
         if (g->target->is32Bit())
-            maskedStoreFunc = m->module->getFunction("__pseudo_masked_store_i32");
+            maskedStoreFunc = m->module->getFunction(builtin::__pseudo_masked_store_i32);
         else
-            maskedStoreFunc = m->module->getFunction("__pseudo_masked_store_i64");
+            maskedStoreFunc = m->module->getFunction(builtin::__pseudo_masked_store_i64);
     } else if (llvmValueType == LLVMTypes::Int1VectorType) {
         llvm::Value *notMask =
             BinaryOperator(llvm::Instruction::Xor, mask, LLVMMaskAllOn, WrapSemantics::None, "~mask");
@@ -2936,19 +2947,19 @@ void FunctionEmitContext::maskedStore(llvm::Value *value, llvm::Value *ptr, cons
         StoreInst(final, ptrInfo, valueType);
         return;
     } else if (llvmValueStorageType == LLVMTypes::DoubleVectorType) {
-        maskedStoreFunc = m->module->getFunction("__pseudo_masked_store_double");
+        maskedStoreFunc = m->module->getFunction(builtin::__pseudo_masked_store_double);
     } else if (llvmValueStorageType == LLVMTypes::Int64VectorType) {
-        maskedStoreFunc = m->module->getFunction("__pseudo_masked_store_i64");
+        maskedStoreFunc = m->module->getFunction(builtin::__pseudo_masked_store_i64);
     } else if (llvmValueStorageType == LLVMTypes::FloatVectorType) {
-        maskedStoreFunc = m->module->getFunction("__pseudo_masked_store_float");
+        maskedStoreFunc = m->module->getFunction(builtin::__pseudo_masked_store_float);
     } else if (llvmValueStorageType == LLVMTypes::Float16VectorType) {
-        maskedStoreFunc = m->module->getFunction("__pseudo_masked_store_half");
+        maskedStoreFunc = m->module->getFunction(builtin::__pseudo_masked_store_half);
     } else if (llvmValueStorageType == LLVMTypes::Int32VectorType) {
-        maskedStoreFunc = m->module->getFunction("__pseudo_masked_store_i32");
+        maskedStoreFunc = m->module->getFunction(builtin::__pseudo_masked_store_i32);
     } else if (llvmValueStorageType == LLVMTypes::Int16VectorType) {
-        maskedStoreFunc = m->module->getFunction("__pseudo_masked_store_i16");
+        maskedStoreFunc = m->module->getFunction(builtin::__pseudo_masked_store_i16);
     } else if (llvmValueStorageType == LLVMTypes::Int8VectorType) {
-        maskedStoreFunc = m->module->getFunction("__pseudo_masked_store_i8");
+        maskedStoreFunc = m->module->getFunction(builtin::__pseudo_masked_store_i8);
         value = SwitchBoolSize(value, llvmValueStorageType);
     }
     AssertPos(currentPos, maskedStoreFunc != nullptr);
@@ -3046,21 +3057,21 @@ void FunctionEmitContext::scatter(llvm::Value *value, llvm::Value *ptr, const Ty
     }
     const char *funcName = nullptr;
     if (pt != nullptr) {
-        funcName = g->target->is32Bit() ? "__pseudo_scatter32_i32" : "__pseudo_scatter64_i64";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_scatter32_i32 : builtin::__pseudo_scatter64_i64;
     } else if (llvmStorageType == LLVMTypes::DoubleVectorType) {
-        funcName = g->target->is32Bit() ? "__pseudo_scatter32_double" : "__pseudo_scatter64_double";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_scatter32_double : builtin::__pseudo_scatter64_double;
     } else if (llvmStorageType == LLVMTypes::Int64VectorType) {
-        funcName = g->target->is32Bit() ? "__pseudo_scatter32_i64" : "__pseudo_scatter64_i64";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_scatter32_i64 : builtin::__pseudo_scatter64_i64;
     } else if (llvmStorageType == LLVMTypes::FloatVectorType) {
-        funcName = g->target->is32Bit() ? "__pseudo_scatter32_float" : "__pseudo_scatter64_float";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_scatter32_float : builtin::__pseudo_scatter64_float;
     } else if (llvmStorageType == LLVMTypes::Float16VectorType) {
-        funcName = g->target->is32Bit() ? "__pseudo_scatter32_half" : "__pseudo_scatter64_half";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_scatter32_half : builtin::__pseudo_scatter64_half;
     } else if (llvmStorageType == LLVMTypes::Int32VectorType) {
-        funcName = g->target->is32Bit() ? "__pseudo_scatter32_i32" : "__pseudo_scatter64_i32";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_scatter32_i32 : builtin::__pseudo_scatter64_i32;
     } else if (llvmStorageType == LLVMTypes::Int16VectorType) {
-        funcName = g->target->is32Bit() ? "__pseudo_scatter32_i16" : "__pseudo_scatter64_i16";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_scatter32_i16 : builtin::__pseudo_scatter64_i16;
     } else if (llvmStorageType == LLVMTypes::Int8VectorType) {
-        funcName = g->target->is32Bit() ? "__pseudo_scatter32_i8" : "__pseudo_scatter64_i8";
+        funcName = g->target->is32Bit() ? builtin::__pseudo_scatter32_i8 : builtin::__pseudo_scatter64_i8;
     }
 
     llvm::Function *scatterFunc = m->module->getFunction(funcName);
@@ -3577,7 +3588,7 @@ llvm::Value *FunctionEmitContext::CallInst(llvm::Value *func, const FunctionType
             // Figure out the first lane that still needs its function
             // pointer to be called.
             llvm::Value *currentMask = LoadInst(maskPtrInfo);
-            llvm::Function *cttz = m->module->getFunction("__count_trailing_zeros_i64");
+            llvm::Function *cttz = m->module->getFunction(builtin::__count_trailing_zeros_i64);
             AssertPos(currentPos, cttz != nullptr);
             llvm::Value *firstLane64 = CallInst(cttz, nullptr, LaneMask(currentMask), "first_lane64");
             llvm::Value *firstLane = TruncInst(firstLane64, LLVMTypes::Int32Type, "first_lane32");
diff --git a/src/expr.cpp b/src/expr.cpp
index 6e3a8d7de1..70bdccf862 100644
--- a/src/expr.cpp
+++ b/src/expr.cpp
@@ -10,6 +10,7 @@
 
 #include "expr.h"
 #include "ast.h"
+#include "builtins-decl.h"
 #include "ctx.h"
 #include "func.h"
 #include "llvmutil.h"
@@ -31,6 +32,7 @@
 #include <algorithm>
 #include <list>
 #include <set>
+#include <sstream>
 #include <stdio.h>
 
 #include <llvm/ExecutionEngine/GenericValue.h>
@@ -1750,8 +1752,8 @@ bool lCreateBinaryOperatorCall(const BinaryExpr::Op bop, Expr *a0, Expr *a1, Exp
         std::vector<TemplateSymbol *> funcTempls;
         bool foundAny = m->symbolTable->LookupFunctionTemplate(opName.c_str(), &funcTempls);
         if (foundAny && funcTempls.size() > 0) {
-            std::vector<std::pair<const Type *, SourcePos>> vec;
-            FunctionSymbolExpr *functionSymbolExpr = new FunctionSymbolExpr(opName.c_str(), funcTempls, vec, sp);
+            TemplateArgs templArgs;
+            FunctionSymbolExpr *functionSymbolExpr = new FunctionSymbolExpr(opName.c_str(), funcTempls, templArgs, sp);
             Assert(functionSymbolExpr != nullptr);
             ExprList *args = new ExprList(sp);
             args->exprs.push_back(arg0);
@@ -5851,6 +5853,64 @@ llvm::Value *ConstExpr::GetValue(FunctionEmitContext *ctx) const {
     }
 }
 
+bool ConstExpr::IsEqual(const ConstExpr *ce) const {
+    if (ce == nullptr)
+        return false;
+
+    if (!Type::EqualIgnoringConst(type, ce->type))
+        return false;
+
+    for (int i = 0; i < Count(); ++i) {
+        switch (getBasicType()) {
+        case AtomicType::TYPE_BOOL:
+            if (boolVal[i] != ce->boolVal[i])
+                return false;
+            break;
+        case AtomicType::TYPE_INT8:
+            if (int8Val[i] != ce->int8Val[i])
+                return false;
+            break;
+        case AtomicType::TYPE_UINT8:
+            if (uint8Val[i] != ce->uint8Val[i])
+                return false;
+            break;
+        case AtomicType::TYPE_INT16:
+            if (int16Val[i] != ce->int16Val[i])
+                return false;
+            break;
+        case AtomicType::TYPE_UINT16:
+            if (uint16Val[i] != ce->uint16Val[i])
+                return false;
+            break;
+        case AtomicType::TYPE_INT32:
+            if (int32Val[i] != ce->int32Val[i])
+                return false;
+            break;
+        case AtomicType::TYPE_UINT32:
+            if (uint32Val[i] != ce->uint32Val[i])
+                return false;
+            break;
+        case AtomicType::TYPE_INT64:
+            if (int64Val[i] != ce->int64Val[i])
+                return false;
+            break;
+        case AtomicType::TYPE_UINT64:
+            if (uint64Val[i] != ce->uint64Val[i])
+                return false;
+            break;
+        case AtomicType::TYPE_FLOAT16:
+        case AtomicType::TYPE_FLOAT:
+        case AtomicType::TYPE_DOUBLE:
+            if (fpVal[i] != ce->fpVal[i])
+                return false;
+            break;
+        default:
+            FATAL("unimplemented const type");
+            return false;
+        }
+    }
+    return true;
+}
 /* Type conversion templates: take advantage of C++ function overloading
    rules to get the one we want to match. */
 
@@ -6176,56 +6236,59 @@ int ConstExpr::EstimateCost() const { return 0; }
 
 ConstExpr *ConstExpr::Instantiate(TemplateInstantiation &templInst) const { return new ConstExpr(this, pos); }
 
-void ConstExpr::Print(Indent &indent) const {
-    indent.Print("ConstExpr", pos);
-
-    printf("[%s] (", GetType()->GetString().c_str());
+std::string ConstExpr::GetValuesAsStr(const std::string &separator) const {
+    std::stringstream result;
     for (int i = 0; i < Count(); ++i) {
+        if (i != 0) {
+            result << separator;
+        }
         switch (getBasicType()) {
         case AtomicType::TYPE_BOOL:
-            printf("%s", boolVal[i] ? "true" : "false");
+            result << (boolVal[i] ? "true" : "false");
             break;
         case AtomicType::TYPE_INT8:
-            printf("%d", (int)int8Val[i]);
+            result << static_cast<int>(int8Val[i]);
             break;
         case AtomicType::TYPE_UINT8:
-            printf("%u", (int)uint8Val[i]);
+            result << static_cast<unsigned int>(uint8Val[i]);
             break;
         case AtomicType::TYPE_INT16:
-            printf("%d", (int)int16Val[i]);
+            result << static_cast<int>(int16Val[i]);
             break;
         case AtomicType::TYPE_UINT16:
-            printf("%u", (int)uint16Val[i]);
+            result << static_cast<unsigned int>(uint16Val[i]);
             break;
         case AtomicType::TYPE_INT32:
-            printf("%d", int32Val[i]);
+            result << int32Val[i];
             break;
         case AtomicType::TYPE_UINT32:
-            printf("%u", uint32Val[i]);
+            result << uint32Val[i];
             break;
         case AtomicType::TYPE_INT64:
-            printf("%" PRId64, int64Val[i]);
+            result << int64Val[i];
             break;
         case AtomicType::TYPE_UINT64:
-            printf("%" PRIu64, uint64Val[i]);
+            result << uint64Val[i];
             break;
-        case AtomicType::TYPE_FLOAT16: {
-            llvm::APFloat V(fpVal[i]);
-            printf("%f", V.convertToFloat());
-            break;
-        }
+        case AtomicType::TYPE_FLOAT16:
         case AtomicType::TYPE_FLOAT:
-            printf("%f", fpVal[i].convertToFloat());
+            result << std::to_string(fpVal[i].convertToFloat());
             break;
         case AtomicType::TYPE_DOUBLE:
-            printf("%f", fpVal[i].convertToDouble());
+            result << std::to_string(fpVal[i].convertToDouble());
             break;
         default:
             FATAL("unimplemented const type");
         }
-        if (i != Count() - 1)
-            printf(", ");
     }
+    return result.str();
+}
+
+void ConstExpr::Print(Indent &indent) const {
+    indent.Print("ConstExpr", pos);
+
+    printf("[%s] (", GetType()->GetString().c_str());
+    printf("%s", GetValuesAsStr((char *)", ").c_str());
     printf(")\n");
 
     indent.Done();
@@ -8242,17 +8305,15 @@ FunctionSymbolExpr::FunctionSymbolExpr(const char *n, const std::vector<Symbol *
 }
 
 FunctionSymbolExpr::FunctionSymbolExpr(const char *n, const std::vector<TemplateSymbol *> &candidates,
-                                       const std::vector<std::pair<const Type *, SourcePos>> &types, SourcePos p)
-    : Expr(p, FunctionSymbolExprID), name(n), candidateTemplateFunctions(candidates), templateArgs(types),
+                                       const TemplateArgs &templArgs, SourcePos p)
+    : Expr(p, FunctionSymbolExprID), name(n), candidateTemplateFunctions(candidates), templateArgs(templArgs),
       matchingFunc(nullptr), triedToResolve(false), unresolvedButDependent(false) {
     // Do template argument "normalization", i.e apply "varying type default":
     //
     // template <typename T> void foo(T t);
     // foo<int>(1); // T is assumed to be "varying int" here.
     for (auto &arg : templateArgs) {
-        if (arg.first->GetVariability() == Variability::Unbound) {
-            arg.first = arg.first->GetAsVaryingType();
-        }
+        arg.SetAsVaryingType();
     }
 }
 
@@ -8288,9 +8349,10 @@ FunctionSymbolExpr *FunctionSymbolExpr::Instantiate(TemplateInstantiation &templ
         Assert(candidateTemplateFunctions.size() == 0);
         return new FunctionSymbolExpr(name.c_str(), candidateFunctions, pos);
     }
-    std::vector<std::pair<const Type *, SourcePos>> instTemplateArgs;
+    TemplateArgs instTemplateArgs;
     for (auto &arg : templateArgs) {
-        instTemplateArgs.push_back(std::make_pair(arg.first->ResolveDependenceForTopType(templInst), arg.second));
+        instTemplateArgs.push_back(
+            arg.IsType() ? TemplateArg(arg.GetAsType()->ResolveDependenceForTopType(templInst), arg.GetPos()) : arg);
     }
     return new FunctionSymbolExpr(name.c_str(), candidateTemplateFunctions, instTemplateArgs, pos);
 }
@@ -8622,12 +8684,12 @@ FunctionSymbolExpr::getCandidateTemplateFunctions(const std::vector<const Type *
 
                     if (previousDeductionResult == nullptr) {
                         // This tempalte parameter was deducted for the first time. Add it to the map.
-                        inst.AddArgument(deduction.first, deduction.second);
+                        inst.AddArgument(deduction.first, TemplateArg(deduction.second, pos));
                     } else if (!Type::Equal(previousDeductionResult, deduction.second)) {
                         if (previousDeductionResult->IsUniformType() && deduction.second->IsVaryingType() &&
                             Type::Equal(previousDeductionResult->GetAsVaryingType(), deduction.second)) {
                             // override previous deduction with varying type
-                            inst.AddArgument(deduction.first, deduction.second);
+                            inst.AddArgument(deduction.first, TemplateArg(deduction.second, pos));
                         } else if (previousDeductionResult->IsVaryingType() && deduction.second->IsUniformType()) {
                             // That's fine, uniform will be broadcasted.
                         } else {
@@ -8651,7 +8713,7 @@ FunctionSymbolExpr::getCandidateTemplateFunctions(const std::vector<const Type *
         }
 
         // Build a complete vector of deduced template arguments.
-        std::vector<std::pair<const Type *, SourcePos>> deducedArgs;
+        TemplateArgs deducedArgs;
         for (int i = 0; i < templateParms->GetCount(); ++i) {
             if (i < templateArgs.size()) {
                 deducedArgs.push_back(templateArgs[i]);
@@ -8663,7 +8725,7 @@ FunctionSymbolExpr::getCandidateTemplateFunctions(const std::vector<const Type *
                     deductionFailed = true;
                     break;
                 }
-                deducedArgs.push_back(std::pair<const Type *, SourcePos>(deducedArg, pos));
+                deducedArgs.push_back(TemplateArg(deducedArg, pos));
             }
         }
         if (deductionFailed) {
@@ -9059,20 +9121,20 @@ llvm::Value *NewExpr::GetValue(FunctionEmitContext *ctx) const {
     llvm::Function *func;
     if (isVarying) {
         if (g->target->is32Bit()) {
-            func = m->module->getFunction("__new_varying32_32rt");
+            func = m->module->getFunction(builtin::__new_varying32_32rt);
         } else if (g->opt.force32BitAddressing) {
-            func = m->module->getFunction("__new_varying32_64rt");
+            func = m->module->getFunction(builtin::__new_varying32_64rt);
         } else {
-            func = m->module->getFunction("__new_varying64_64rt");
+            func = m->module->getFunction(builtin::__new_varying64_64rt);
         }
     } else {
         // FIXME: __new_uniform_32rt should take i32
         if (allocSize->getType() != LLVMTypes::Int64Type)
             allocSize = ctx->SExtInst(allocSize, LLVMTypes::Int64Type, "alloc_size64");
         if (g->target->is32Bit()) {
-            func = m->module->getFunction("__new_uniform_32rt");
+            func = m->module->getFunction(builtin::__new_uniform_32rt);
         } else {
-            func = m->module->getFunction("__new_uniform_64rt");
+            func = m->module->getFunction(builtin::__new_uniform_64rt);
         }
     }
     AssertPos(pos, func != nullptr);
diff --git a/src/expr.h b/src/expr.h
index 2079f961a1..7c2cc2770d 100644
--- a/src/expr.h
+++ b/src/expr.h
@@ -12,6 +12,7 @@
 
 #include "ast.h"
 #include "ctx.h"
+#include "func.h"
 #include "ispc.h"
 #include "type.h"
 
@@ -514,11 +515,17 @@ class ConstExpr : public Expr {
     int GetValues(uint64_t *, bool forceVarying = false) const;
     int GetValues(std::vector<llvm::APFloat> &) const;
 
+    /** Return the ConstExpr's values as a string. */
+    std::string GetValuesAsStr(const std::string &separator) const;
+
     /** Return the number of values in the ConstExpr; should be either 1,
         if it has uniform type, or the target's vector width if it's
         varying. */
     int Count() const;
 
+    /** Return true if the type and values of two ConstExpr are the same. */
+    bool IsEqual(const ConstExpr *ce) const;
+
   private:
     AtomicType::BasicType getBasicType() const;
 
@@ -737,8 +744,8 @@ class SymbolExpr : public Expr {
 class FunctionSymbolExpr : public Expr {
   public:
     FunctionSymbolExpr(const char *name, const std::vector<Symbol *> &candFuncs, SourcePos pos);
-    FunctionSymbolExpr(const char *name, const std::vector<TemplateSymbol *> &candFuncs,
-                       const std::vector<std::pair<const Type *, SourcePos>> &types, SourcePos pos);
+    FunctionSymbolExpr(const char *name, const std::vector<TemplateSymbol *> &candFuncs, const TemplateArgs &templArgs,
+                       SourcePos pos);
 
     static inline bool classof(FunctionSymbolExpr const *) { return true; }
     static inline bool classof(ASTNode const *N) { return N->getValueID() == FunctionSymbolExprID; }
@@ -784,7 +791,7 @@ class FunctionSymbolExpr : public Expr {
         overload is the best match. */
     std::vector<Symbol *> candidateFunctions;
     std::vector<TemplateSymbol *> candidateTemplateFunctions;
-    std::vector<std::pair<const Type *, SourcePos>> templateArgs;
+    TemplateArgs templateArgs;
 
     /** The actual matching function found after overload resolution. */
     Symbol *matchingFunc;
diff --git a/src/func.cpp b/src/func.cpp
index eeb1d4280b..47b599ab47 100644
--- a/src/func.cpp
+++ b/src/func.cpp
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2011-2023, Intel Corporation
+  Copyright (c) 2011-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -9,6 +9,7 @@
 */
 
 #include "func.h"
+#include "builtins-decl.h"
 #include "ctx.h"
 #include "expr.h"
 #include "llvmutil.h"
@@ -427,31 +428,31 @@ void Function::emitCode(FunctionEmitContext *ctx, llvm::Function *function, Sour
             // Assign threadIndex and threadCount to the result of calling of corresponding builtins.
             // On Xe threadIndex equals to taskIndex and threadCount to taskCount.
             threadIndexSym->storageInfo = ctx->AllocaInst(LLVMTypes::Int32Type, "threadIndex");
-            ctx->StoreInst(lXeGetTaskVariableValue(ctx, "__task_index"), threadIndexSym->storageInfo);
+            ctx->StoreInst(lXeGetTaskVariableValue(ctx, builtin::__task_index), threadIndexSym->storageInfo);
 
             threadCountSym->storageInfo = ctx->AllocaInst(LLVMTypes::Int32Type, "threadCount");
-            ctx->StoreInst(lXeGetTaskVariableValue(ctx, "__task_count"), threadCountSym->storageInfo);
+            ctx->StoreInst(lXeGetTaskVariableValue(ctx, builtin::__task_count), threadCountSym->storageInfo);
 
             // Assign taskIndex and taskCount to the result of calling of corresponding builtins.
             taskIndexSym->storageInfo = ctx->AllocaInst(LLVMTypes::Int32Type, "taskIndex");
-            ctx->StoreInst(lXeGetTaskVariableValue(ctx, "__task_index"), taskIndexSym->storageInfo);
+            ctx->StoreInst(lXeGetTaskVariableValue(ctx, builtin::__task_index), taskIndexSym->storageInfo);
 
             taskCountSym->storageInfo = ctx->AllocaInst(LLVMTypes::Int32Type, "taskCount");
-            ctx->StoreInst(lXeGetTaskVariableValue(ctx, "__task_count"), taskCountSym->storageInfo);
+            ctx->StoreInst(lXeGetTaskVariableValue(ctx, builtin::__task_count), taskCountSym->storageInfo);
 
             taskIndexSym0->storageInfo = ctx->AllocaInst(LLVMTypes::Int32Type, "taskIndex0");
-            ctx->StoreInst(lXeGetTaskVariableValue(ctx, "__task_index0"), taskIndexSym0->storageInfo);
+            ctx->StoreInst(lXeGetTaskVariableValue(ctx, builtin::__task_index0), taskIndexSym0->storageInfo);
             taskIndexSym1->storageInfo = ctx->AllocaInst(LLVMTypes::Int32Type, "taskIndex1");
-            ctx->StoreInst(lXeGetTaskVariableValue(ctx, "__task_index1"), taskIndexSym1->storageInfo);
+            ctx->StoreInst(lXeGetTaskVariableValue(ctx, builtin::__task_index1), taskIndexSym1->storageInfo);
             taskIndexSym2->storageInfo = ctx->AllocaInst(LLVMTypes::Int32Type, "taskIndex2");
-            ctx->StoreInst(lXeGetTaskVariableValue(ctx, "__task_index2"), taskIndexSym2->storageInfo);
+            ctx->StoreInst(lXeGetTaskVariableValue(ctx, builtin::__task_index2), taskIndexSym2->storageInfo);
 
             taskCountSym0->storageInfo = ctx->AllocaInst(LLVMTypes::Int32Type, "taskCount0");
-            ctx->StoreInst(lXeGetTaskVariableValue(ctx, "__task_count0"), taskCountSym0->storageInfo);
+            ctx->StoreInst(lXeGetTaskVariableValue(ctx, builtin::__task_count0), taskCountSym0->storageInfo);
             taskCountSym1->storageInfo = ctx->AllocaInst(LLVMTypes::Int32Type, "taskCount1");
-            ctx->StoreInst(lXeGetTaskVariableValue(ctx, "__task_count1"), taskCountSym1->storageInfo);
+            ctx->StoreInst(lXeGetTaskVariableValue(ctx, builtin::__task_count1), taskCountSym1->storageInfo);
             taskCountSym2->storageInfo = ctx->AllocaInst(LLVMTypes::Int32Type, "taskCount2");
-            ctx->StoreInst(lXeGetTaskVariableValue(ctx, "__task_count2"), taskCountSym2->storageInfo);
+            ctx->StoreInst(lXeGetTaskVariableValue(ctx, builtin::__task_count2), taskCountSym2->storageInfo);
         }
     }
 
@@ -778,16 +779,59 @@ void Function::GenerateIR() {
     }
 }
 
+///////////////////////////////////////////////////////////////////////////
+// TemplateParam
+
+TemplateParam::TemplateParam(const TemplateTypeParmType *p) : paramType(ParamType::Type), typeParam(p) {
+    name = p->GetName();
+    pos = p->GetSourcePos();
+}
+
+TemplateParam::TemplateParam(Symbol *s) : paramType(ParamType::NonType), nonTypeParam(s) {
+    name = s->name;
+    pos = s->pos;
+}
+
+bool TemplateParam::IsTypeParam() const { return paramType == ParamType::Type; }
+
+bool TemplateParam::IsNonTypeParam() const { return paramType == ParamType::NonType; }
+
+bool TemplateParam::IsEqual(const TemplateParam &other) const {
+    if (IsTypeParam()) {
+        return Type::Equal(typeParam, other.typeParam);
+    } else if (IsNonTypeParam()) {
+        return nonTypeParam->name == other.nonTypeParam->name &&
+               Type::Equal(nonTypeParam->type, other.nonTypeParam->type);
+    }
+    return false;
+}
+
+std::string TemplateParam::GetName() const { return name; }
+
+const TemplateTypeParmType *TemplateParam::GetTypeParam() const {
+    Assert(IsTypeParam());
+    return typeParam;
+}
+
+Symbol *TemplateParam::GetNonTypeParam() const {
+    Assert(IsNonTypeParam());
+    return nonTypeParam;
+}
+
+SourcePos TemplateParam::GetSourcePos() const { return pos; }
+
 ///////////////////////////////////////////////////////////////////////////
 // TemplateParms
 
 TemplateParms::TemplateParms() {}
 
-void TemplateParms::Add(const TemplateTypeParmType *p) { parms.push_back(p); }
+void TemplateParms::Add(const TemplateParam *p) { parms.push_back(p); }
 
 size_t TemplateParms::GetCount() const { return parms.size(); }
 
-const TemplateTypeParmType *TemplateParms::operator[](size_t i) const { return parms[i]; }
+const TemplateParam *TemplateParms::operator[](size_t i) const { return parms[i]; }
+
+const TemplateParam *TemplateParms::operator[](size_t i) { return parms[i]; }
 
 bool TemplateParms::IsEqual(const TemplateParms *p) const {
     if (p == nullptr) {
@@ -799,7 +843,8 @@ bool TemplateParms::IsEqual(const TemplateParms *p) const {
     }
 
     for (size_t i = 0; i < GetCount(); i++) {
-        if (!Type::Equal((*this)[i], (*p)[i])) {
+        const TemplateParam *other = (*p)[i];
+        if (!(parms[i]->IsEqual(*other))) {
             return false;
         }
     }
@@ -808,20 +853,97 @@ bool TemplateParms::IsEqual(const TemplateParms *p) const {
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// TemplateArgs
+// TemplateArg
+
+TemplateArg::TemplateArg(const Type *t, SourcePos pos) : argType(ArgType::Type), type(t), pos(pos) {}
+TemplateArg::TemplateArg(const Expr *c, SourcePos pos) : argType(ArgType::NonType), expr(c), pos(pos) {}
+
+const Type *TemplateArg::GetAsType() const {
+    switch (argType) {
+    case ArgType::Type:
+        return type;
+    case ArgType::NonType:
+        return expr->GetType();
+    default:
+        return nullptr;
+    }
+}
+
+const Expr *TemplateArg::GetAsExpr() const { return IsNonType() ? expr : nullptr; }
+
+SourcePos TemplateArg::GetPos() const { return pos; }
+
+std::string TemplateArg::GetString() const {
+    switch (argType) {
+    case ArgType::Type:
+        return type->GetString();
+    case ArgType::NonType:
+        if (const ConstExpr *constExpr = GetAsConstExpr()) {
+            return constExpr->GetValuesAsStr(", ");
+        }
+        return "Missing const expression";
+    default:
+        return "Unknown ArgType";
+    }
+}
+
+bool TemplateArg::IsNonType() const { return argType == ArgType::NonType; };
 
-TemplateArgs::TemplateArgs(const std::vector<std::pair<const Type *, SourcePos>> &a) : args(a) {}
+bool TemplateArg::IsType() const { return argType == ArgType::Type; }
 
-bool TemplateArgs::IsEqual(TemplateArgs &otherArgs) const {
-    if (args.size() != otherArgs.args.size()) {
+bool TemplateArg::operator==(const TemplateArg &other) const {
+    if (argType != other.argType)
+        return false;
+    switch (argType) {
+    case ArgType::Type:
+        return Type::Equal(type, other.type);
+    case ArgType::NonType: {
+        const ConstExpr *constExpr = GetAsConstExpr();
+        const ConstExpr *otherConstExpr = other.GetAsConstExpr();
+        if (constExpr && otherConstExpr) {
+            return constExpr->IsEqual(otherConstExpr);
+        }
         return false;
     }
-    for (int i = 0; i < args.size(); i++) {
-        if (!Type::Equal(args[i].first, otherArgs.args[i].first)) {
-            return false;
+    default:
+        return false;
+    }
+    return false;
+}
+
+std::string TemplateArg::Mangle() const {
+    switch (argType) {
+    case ArgType::Type:
+        return type->Mangle();
+    case ArgType::NonType: {
+        if (const ConstExpr *constExpr = GetAsConstExpr()) {
+            return GetAsType()->Mangle() + constExpr->GetValuesAsStr("_");
         }
+        return "Missing const expression";
     }
-    return true;
+    default:
+        return "Unknown ArgType";
+    }
+}
+
+void TemplateArg::SetAsVaryingType() {
+    if (IsType() && type->GetVariability() == Variability::Unbound) {
+        type = type->GetAsVaryingType();
+    }
+}
+
+const ConstExpr *TemplateArg::GetAsConstExpr() const {
+    if (IsNonType()) {
+        const ConstExpr *constExpr = llvm::dyn_cast<ConstExpr>(expr);
+        if (!constExpr) {
+            const SymbolExpr *symExpr = llvm::dyn_cast<SymbolExpr>(expr);
+            if (symExpr->GetBaseSymbol()->constValue) {
+                constExpr = llvm::dyn_cast<ConstExpr>(symExpr->GetBaseSymbol()->constValue);
+            }
+        }
+        return constExpr;
+    }
+    return nullptr;
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -919,7 +1041,10 @@ void FunctionTemplate::Print(Indent &indent) const {
             snprintf(buffer, BUFSIZE, "template param %d", i);
             indent.setNextLabel(buffer);
             if ((*typenames)[i]) {
-                indent.Print("TemplateTypeParmType", (*typenames)[i]->GetSourcePos());
+                indent.Print((*typenames)[i]->IsTypeParam()
+                                 ? "TemplateTypeParmType"
+                                 : (*typenames)[i]->GetNonTypeParam()->type->GetString().c_str(),
+                             (*typenames)[i]->GetSourcePos());
                 printf("\"%s\"\n", (*typenames)[i]->GetName().c_str());
                 indent.Done();
             } else {
@@ -936,10 +1061,10 @@ void FunctionTemplate::Print(Indent &indent) const {
 
     for (const auto &inst : instantiations) {
         std::string args;
-        for (size_t i = 0; i < inst.first->args.size(); i++) {
-            auto &arg = inst.first->args[i];
-            args += arg.first->GetString();
-            if (i + 1 < inst.first->args.size()) {
+        for (size_t i = 0; i < inst.first->size(); i++) {
+            const TemplateArg &arg = (*inst.first)[i];
+            args += arg.GetString();
+            if (i + 1 < inst.first->size()) {
                 args += ", ";
             }
         }
@@ -961,21 +1086,21 @@ bool FunctionTemplate::IsStdlibSymbol() const {
     return false;
 };
 
-Symbol *FunctionTemplate::LookupInstantiation(const std::vector<std::pair<const Type *, SourcePos>> &types) {
-    TemplateArgs argsToMatch(types);
+Symbol *FunctionTemplate::LookupInstantiation(const TemplateArgs &tArgs) {
+    TemplateArgs argsToMatch(tArgs);
     for (const auto &inst : instantiations) {
-        if (inst.first->IsEqual(argsToMatch)) {
+        if (*(inst.first) == argsToMatch) {
             return inst.second;
         }
     }
     return nullptr;
 }
 
-Symbol *FunctionTemplate::AddInstantiation(const std::vector<std::pair<const Type *, SourcePos>> &types,
-                                           TemplateInstantiationKind kind, bool isInline, bool isNoinline) {
+Symbol *FunctionTemplate::AddInstantiation(const TemplateArgs &tArgs, TemplateInstantiationKind kind, bool isInline,
+                                           bool isNoinline) {
     const TemplateParms *typenames = GetTemplateParms();
     Assert(typenames);
-    TemplateInstantiation templInst(*typenames, types, kind, isInline, isNoinline);
+    TemplateInstantiation templInst(*typenames, tArgs, kind, isInline, isNoinline);
 
     Symbol *instSym = templInst.InstantiateTemplateSymbol(sym);
     Symbol *instMaskSym = templInst.InstantiateSymbol(maskSymbol);
@@ -989,18 +1114,17 @@ Symbol *FunctionTemplate::AddInstantiation(const std::vector<std::pair<const Typ
 
     templInst.SetFunction(inst);
 
-    TemplateArgs *templArgs = new TemplateArgs(types);
+    TemplateArgs *templArgs = new TemplateArgs(tArgs);
     instantiations.push_back(std::make_pair(templArgs, instSym));
 
     return instSym;
 }
 
-Symbol *FunctionTemplate::AddSpecialization(const FunctionType *ftype,
-                                            const std::vector<std::pair<const Type *, SourcePos>> &types, bool isInline,
+Symbol *FunctionTemplate::AddSpecialization(const FunctionType *ftype, const TemplateArgs &tArgs, bool isInline,
                                             bool isNoInline, SourcePos pos) {
     const TemplateParms *typenames = GetTemplateParms();
     Assert(typenames);
-    TemplateInstantiation templInst(*typenames, types, TemplateInstantiationKind::Specialization, isInline, isNoInline);
+    TemplateInstantiation templInst(*typenames, tArgs, TemplateInstantiationKind::Specialization, isInline, isNoInline);
 
     // Create a function symbol
     Symbol *instSym = templInst.InstantiateTemplateSymbol(sym);
@@ -1011,10 +1135,10 @@ Symbol *FunctionTemplate::AddSpecialization(const FunctionType *ftype,
     instSym->pos = pos;
     instSym->storageClass = sym->storageClass;
 
-    TemplateArgs *templArgs = new TemplateArgs(types);
+    TemplateArgs *templArgs = new TemplateArgs(tArgs);
 
     // Check if we have previously declared specialization and we are about to define it.
-    Symbol *funcSym = LookupInstantiation(types);
+    Symbol *funcSym = LookupInstantiation(tArgs);
     if (funcSym != nullptr) {
         delete templArgs;
         return funcSym;
@@ -1027,28 +1151,29 @@ Symbol *FunctionTemplate::AddSpecialization(const FunctionType *ftype,
 ///////////////////////////////////////////////////////////////////////////
 // TemplateInstantiation
 
-TemplateInstantiation::TemplateInstantiation(const TemplateParms &typeParms,
-                                             const std::vector<std::pair<const Type *, SourcePos>> &typeArgs,
+TemplateInstantiation::TemplateInstantiation(const TemplateParms &typeParms, const TemplateArgs &tArgs,
                                              TemplateInstantiationKind k, bool ii, bool ini)
     : functionSym(nullptr), kind(k), isInline(ii), isNoInline(ini) {
-    Assert(typeArgs.size() <= typeParms.GetCount());
+    Assert(tArgs.size() <= typeParms.GetCount());
     // Create a mapping from the template parameters to the arguments.
     // Note we do that for all specified templates arguments, which number may be less than a number of template
     // parameters. In this case the rest of template parameters will be deduced later during template argumnet
     // deduction.
-    for (int i = 0; i < typeArgs.size(); i++) {
+    for (int i = 0; i < tArgs.size(); i++) {
         std::string name = typeParms[i]->GetName();
-        const Type *type = typeArgs[i].first;
-        argsMap[name] = type;
-        templateArgs.push_back(typeArgs[i].first);
+        const Type *type = tArgs[i].GetAsType();
+        argsTypeMap[name] = type;
+        templateArgs.push_back(tArgs[i]);
     }
 }
 
-void TemplateInstantiation::AddArgument(std::string paramName, const Type *argType) { argsMap[paramName] = argType; }
+void TemplateInstantiation::AddArgument(std::string paramName, TemplateArg argType) {
+    argsTypeMap[paramName] = argType.GetAsType();
+}
 
 const Type *TemplateInstantiation::InstantiateType(const std::string &name) {
-    auto t = argsMap.find(name);
-    if (t == argsMap.end()) {
+    auto t = argsTypeMap.find(name);
+    if (t == argsTypeMap.end()) {
         return nullptr;
     }
 
diff --git a/src/func.h b/src/func.h
index f834a90a18..3e580138b1 100644
--- a/src/func.h
+++ b/src/func.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2011-2023, Intel Corporation
+  Copyright (c) 2011-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -52,25 +52,96 @@ class Function {
     Symbol *taskIndexSym2, *taskCountSym2;
 };
 
-// A helper class to manage template parameters list.
+// Represents a single template parameter, which can either be a type (TemplateTypeParmType) or a non-type
+// (Symbol).
+class TemplateParam : public Traceable {
+  public:
+    enum class ParamType { Type, NonType };
+
+  private:
+    ParamType paramType;
+    union {
+        const TemplateTypeParmType *typeParam;
+        Symbol *nonTypeParam;
+    };
+
+    std::string name;
+    SourcePos pos;
+
+  public:
+    TemplateParam(const TemplateTypeParmType *tp);
+    TemplateParam(Symbol *ntp);
+
+    // Checks if the parameter is a type parameter.
+    bool IsTypeParam() const;
+    // Checks if the parameter is a non-type parameter.
+    bool IsNonTypeParam() const;
+    // Compares two `TemplateParam` instances for equality.
+    bool IsEqual(const TemplateParam &other) const;
+    // Gets the name of the parameter.
+    std::string GetName() const;
+    // Returns type parameter.
+    const TemplateTypeParmType *GetTypeParam() const;
+    // Returns type parameter.
+    Symbol *GetNonTypeParam() const;
+    // Returns the source position associated with this template parameter.
+    SourcePos GetSourcePos() const;
+};
+
+// A helper class to manage template parameters list and clean up allocated memory.
 class TemplateParms : public Traceable {
   public:
     TemplateParms();
-    void Add(const TemplateTypeParmType *);
+    void Add(const TemplateParam *);
     size_t GetCount() const;
-    const TemplateTypeParmType *operator[](size_t i) const;
+    const TemplateParam *operator[](size_t i) const;
+    const TemplateParam *operator[](size_t i);
     bool IsEqual(const TemplateParms *p) const;
 
   private:
-    std::vector<const TemplateTypeParmType *> parms;
+    std::vector<const TemplateParam *> parms;
 };
 
-class TemplateArgs {
+// Represents a single argument in a template instantiation. This can either be a type
+// or a non-type (constant or symbol expression).
+class TemplateArg : public Traceable {
   public:
-    TemplateArgs(const std::vector<std::pair<const Type *, SourcePos>> &args);
-    bool IsEqual(TemplateArgs &otherArgs) const;
+    enum class ArgType { Type, NonType };
 
-    std::vector<std::pair<const Type *, SourcePos>> args;
+  private:
+    ArgType argType;
+    union {
+        const Type *type;
+        const Expr *expr;
+    };
+    SourcePos pos;
+
+  public:
+    TemplateArg(const Type *t, SourcePos pos);
+    TemplateArg(const Expr *c, SourcePos pos);
+
+    // Returns ISPC type of the argument.
+    const Type *GetAsType() const;
+    // Returns const expression if this argument is a ConstExpr or SymbolExpr with constValue.
+    // Note that SymbolExpr may not have constValue until it has been instantiated during template function call.
+    // See: FunctionSymbolExpr::Instantiate()
+    const ConstExpr *GetAsConstExpr() const;
+    // Returns expression if this argument is a non-type, nullptr otherwise.
+    const Expr *GetAsExpr() const;
+    // Returns the source position associated with this template argument.
+    SourcePos GetPos() const;
+    // Produces a string representation of the argument.
+    std::string GetString() const;
+    // Returns `true` if this argument is a non-type.
+    bool IsNonType() const;
+    // Returns `true` if this argument is a Type.
+    bool IsType() const;
+    // Mangles the stored type to a string representation.
+    std::string Mangle() const;
+    // Transforms the stored type to its varying equivalent.
+    void SetAsVaryingType();
+    // Operator support
+    bool operator==(const TemplateArg &other) const;
 };
 
 enum class TemplateInstantiationKind { Implicit, Explicit, Specialization };
@@ -83,11 +154,10 @@ class FunctionTemplate {
     const FunctionType *GetFunctionType() const;
     StorageClass GetStorageClass();
 
-    Symbol *LookupInstantiation(const std::vector<std::pair<const Type *, SourcePos>> &types);
-    Symbol *AddInstantiation(const std::vector<std::pair<const Type *, SourcePos>> &types,
-                             TemplateInstantiationKind kind, bool isInline, bool isNoInline);
-    Symbol *AddSpecialization(const FunctionType *ftype, const std::vector<std::pair<const Type *, SourcePos>> &types,
-                              bool isInline, bool isNoInline, SourcePos pos);
+    Symbol *LookupInstantiation(const TemplateArgs &tArgs);
+    Symbol *AddInstantiation(const TemplateArgs &tArgs, TemplateInstantiationKind kind, bool isInline, bool isNoInline);
+    Symbol *AddSpecialization(const FunctionType *ftype, const TemplateArgs &tArgs, bool isInline, bool isNoInline,
+                              SourcePos pos);
 
     // Generate code for instantiations and specializations.
     void GenerateIR() const;
@@ -110,15 +180,14 @@ class FunctionTemplate {
 // - type instantiation
 class TemplateInstantiation {
   public:
-    TemplateInstantiation(const TemplateParms &typeParms,
-                          const std::vector<std::pair<const Type *, SourcePos>> &typeArgs,
-                          TemplateInstantiationKind kind, bool IsInline, bool IsNoInline);
+    TemplateInstantiation(const TemplateParms &typeParms, const TemplateArgs &tArgs, TemplateInstantiationKind kind,
+                          bool IsInline, bool IsNoInline);
     const Type *InstantiateType(const std::string &name);
     Symbol *InstantiateSymbol(Symbol *sym);
     Symbol *InstantiateTemplateSymbol(TemplateSymbol *sym);
     void SetFunction(Function *func);
 
-    void AddArgument(std::string paramName, const Type *argType);
+    void AddArgument(std::string paramName, TemplateArg argType);
 
   private:
     // Function Symbol of the instantiation.
@@ -126,9 +195,9 @@ class TemplateInstantiation {
     // Mapping of the symbols in the template to correspoding symbols in the instantiation.
     std::unordered_map<Symbol *, Symbol *> symMap;
     // Mapping of template parameter names to the types in the instantiation.
-    std::unordered_map<std::string, const Type *> argsMap;
+    std::unordered_map<std::string, const Type *> argsTypeMap;
     // Template arguments in the order of the template parameters.
-    std::vector<const Type *> templateArgs;
+    TemplateArgs templateArgs;
     // Kind of instantiation (explicit, implicit, specialization).
     TemplateInstantiationKind kind;
 
diff --git a/src/ispc.cpp b/src/ispc.cpp
index e0a4515105..04b5205711 100644
--- a/src/ispc.cpp
+++ b/src/ispc.cpp
@@ -51,6 +51,12 @@
 #include <llvm/Target/TargetMachine.h>
 #include <llvm/Target/TargetOptions.h>
 
+#if ISPC_LLVM_VERSION > ISPC_LLVM_17_0
+using CodegenOptLevel = llvm::CodeGenOptLevel;
+#else
+using CodegenOptLevel = llvm::CodeGenOpt::Level;
+#endif
+
 using namespace ispc;
 
 Globals *ispc::g;
@@ -1707,14 +1713,14 @@ Target::Target(Arch arch, const char *cpu, ISPCTarget ispc_target, bool pic, MCM
             // requested by user via ISPC Optimization Flag. Mapping is :
             // ISPC O0 -> Codegen O0
             // ISPC O1,O2,O3,default -> Codegen O3
-            llvm::CodeGenOpt::Level cOptLevel = llvm::CodeGenOpt::Level::Aggressive;
+            CodegenOptLevel cOptLevel = CodegenOptLevel::Aggressive;
             switch (g->codegenOptLevel) {
             case Globals::CodegenOptLevel::None:
-                cOptLevel = llvm::CodeGenOpt::Level::None;
+                cOptLevel = CodegenOptLevel::None;
                 break;
 
             case Globals::CodegenOptLevel::Aggressive:
-                cOptLevel = llvm::CodeGenOpt::Level::Aggressive;
+                cOptLevel = CodegenOptLevel::Aggressive;
                 break;
             }
             m_targetMachine->setOptLevel(cOptLevel);
diff --git a/src/ispc.h b/src/ispc.h
index edb1977172..a5827ccae7 100644
--- a/src/ispc.h
+++ b/src/ispc.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2010-2023, Intel Corporation
+  Copyright (c) 2010-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -86,11 +86,14 @@ class PointerType;
 class Stmt;
 class Symbol;
 class SymbolTable;
+class TemplateArg;
 class TemplateInstantiation;
+class TemplateParam;
 class TemplateParms;
 class TemplateSymbol;
 class Type;
 struct VariableDeclaration;
+typedef std::vector<TemplateArg> TemplateArgs;
 
 enum StorageClass { SC_NONE, SC_EXTERN, SC_STATIC, SC_TYPEDEF, SC_EXTERN_C, SC_EXTERN_SYCL };
 
diff --git a/src/ispc_version.h b/src/ispc_version.h
index d26129d864..6c343bbd41 100644
--- a/src/ispc_version.h
+++ b/src/ispc_version.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2015-2023, Intel Corporation
+  Copyright (c) 2015-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -19,10 +19,11 @@
 #define ISPC_LLVM_15_0 150000
 #define ISPC_LLVM_16_0 160000
 #define ISPC_LLVM_17_0 170000
-#define ISPC_LLVM_18_0 180000
+#define ISPC_LLVM_18_1 181000
+#define ISPC_LLVM_19_0 190000
 
 #define OLDEST_SUPPORTED_LLVM ISPC_LLVM_14_0
-#define LATEST_SUPPORTED_LLVM ISPC_LLVM_18_0
+#define LATEST_SUPPORTED_LLVM ISPC_LLVM_19_0
 
 #ifdef __ispc__xstr
 #undef __ispc__xstr
@@ -34,7 +35,7 @@
     __ispc__xstr(LLVM_VERSION_MAJOR) "." __ispc__xstr(LLVM_VERSION_MINOR) "." __ispc__xstr(LLVM_VERSION_PATCH)
 
 #if ISPC_LLVM_VERSION < OLDEST_SUPPORTED_LLVM || ISPC_LLVM_VERSION > LATEST_SUPPORTED_LLVM
-#error "Only LLVM 14.0 - 17.0 and 18.0 development branch are supported"
+#error "Only LLVM 14.0 - 18.1 and 19.0 development branch are supported"
 #endif
 
 #define ISPC_VERSION_STRING                                                                                            \
diff --git a/src/module.cpp b/src/module.cpp
index e2084d2e20..7a7e3c35e6 100644
--- a/src/module.cpp
+++ b/src/module.cpp
@@ -472,11 +472,26 @@ void Module::AddTypeDef(const std::string &name, const Type *type, SourcePos pos
 }
 
 // Construct ConstExpr as initializer for varying const value from given expression list if possible
+// T is bool* or std::vector<llvm::APFloat> or int8_t* (and others integer types) here.
+// Although, it looks like very unlogical this is the probably most reasonable
+// approach to unify usage of vals variable inside function.
+// Approach with T is bool, llvm::APFloat, int8_t, ... doesn't work because
+// 1) We can't dereference &vals[i++] when it is std::vector<bool>. The
+// specialization of vector with bool doesn't necessarily store its elements as
+// contiguous array.
+// 2) MSVC doesn't support VLAs, so T vals[N] is not an option.
+// 3) T vals[64] is not an option because llvm::APFloat doesn't have the
+// default constructor. Same applicable for std::array.
 template <class T>
 Expr *lCreateConstExpr(ExprList *exprList, const AtomicType::BasicType basicType, const Type *type,
                        const std::string &name, SourcePos pos) {
     const int N = g->target->getVectorWidth();
     bool canConstructConstExpr = true;
+    using ManagedType =
+        typename std::conditional<std::is_pointer<T>::value, std::unique_ptr<typename std::remove_pointer<T>::type[]>,
+                                  int // unused placeholder
+                                  >::type;
+    ManagedType managedMemory;
     T vals;
     if constexpr (std::is_same_v<T, std::vector<llvm::APFloat>>) {
         switch (basicType) {
@@ -494,8 +509,10 @@ Expr *lCreateConstExpr(ExprList *exprList, const AtomicType::BasicType basicType
         }
     } else {
         // T equals int8_t* and etc.
+        // We allocate PointToType[N] on the heap. It is managed by unique_ptr.
         using PointToType = typename std::remove_pointer<T>::type;
-        vals = (T)alloca(N * sizeof(PointToType));
+        managedMemory = std::make_unique<PointToType[]>(N);
+        vals = managedMemory.get();
         memset(vals, 0, N * sizeof(PointToType));
     }
 
@@ -1269,8 +1286,7 @@ void Module::AddFunctionTemplateDefinition(const TemplateParms *templateParmList
 }
 
 FunctionTemplate *Module::MatchFunctionTemplate(const std::string &name, const FunctionType *ftype,
-                                                std::vector<std::pair<const Type *, SourcePos>> &normTypes,
-                                                SourcePos pos) {
+                                                TemplateArgs &normTypes, SourcePos pos) {
     if (ftype == nullptr) {
         Assert(m->errorCount > 0);
         return nullptr;
@@ -1286,9 +1302,7 @@ FunctionTemplate *Module::MatchFunctionTemplate(const std::string &name, const F
     // template <typename T> void foo(T t);
     // foo<int>(1); // T is assumed to be "varying int" here.
     for (auto &arg : normTypes) {
-        if (arg.first->GetVariability() == Variability::Unbound) {
-            arg.first = arg.first->GetAsVaryingType();
-        }
+        arg.SetAsVaryingType();
     }
 
     FunctionTemplate *templ = nullptr;
@@ -1322,11 +1336,10 @@ FunctionTemplate *Module::MatchFunctionTemplate(const std::string &name, const F
     return templ;
 }
 
-void Module::AddFunctionTemplateInstantiation(const std::string &name,
-                                              const std::vector<std::pair<const Type *, SourcePos>> &types,
+void Module::AddFunctionTemplateInstantiation(const std::string &name, const TemplateArgs &tArgs,
                                               const FunctionType *ftype, StorageClass sc, bool isInline,
                                               bool isNoInline, SourcePos pos) {
-    std::vector<std::pair<const Type *, SourcePos>> normTypes(types);
+    TemplateArgs normTypes(tArgs);
     FunctionTemplate *templ = MatchFunctionTemplate(name, ftype, normTypes, pos);
     if (templ) {
         // If primary template has default storage class, but explicit instantiation has non-default storage class,
@@ -1356,9 +1369,8 @@ void Module::AddFunctionTemplateInstantiation(const std::string &name,
 }
 
 void Module::AddFunctionTemplateSpecializationDefinition(const std::string &name, const FunctionType *ftype,
-                                                         const std::vector<std::pair<const Type *, SourcePos>> &types,
-                                                         SourcePos pos, Stmt *code) {
-    std::vector<std::pair<const Type *, SourcePos>> normTypes(types);
+                                                         const TemplateArgs &tArgs, SourcePos pos, Stmt *code) {
+    TemplateArgs normTypes(tArgs);
     FunctionTemplate *templ = MatchFunctionTemplate(name, ftype, normTypes, pos);
     if (templ == nullptr) {
         Error(pos, "No matching function template found for specialization.");
@@ -1380,10 +1392,9 @@ void Module::AddFunctionTemplateSpecializationDefinition(const std::string &name
 }
 
 void Module::AddFunctionTemplateSpecializationDeclaration(const std::string &name, const FunctionType *ftype,
-                                                          const std::vector<std::pair<const Type *, SourcePos>> &types,
-                                                          StorageClass sc, bool isInline, bool isNoInline,
-                                                          SourcePos pos) {
-    std::vector<std::pair<const Type *, SourcePos>> normTypes(types);
+                                                          const TemplateArgs &tArgs, StorageClass sc, bool isInline,
+                                                          bool isNoInline, SourcePos pos) {
+    TemplateArgs normTypes(tArgs);
     FunctionTemplate *templ = MatchFunctionTemplate(name, ftype, normTypes, pos);
     if (templ == nullptr) {
         Error(pos, "No matching function template found for specialization.");
@@ -1757,9 +1768,15 @@ bool Module::writeObjectFileOrAssembly(llvm::TargetMachine *targetMachine, llvm:
                                        const char *outFileName) {
     // Figure out if we're generating object file or assembly output, and
     // set binary output for object files
+#if ISPC_LLVM_VERSION > ISPC_LLVM_17_0
+    llvm::CodeGenFileType fileType =
+        (outputType == Object) ? llvm::CodeGenFileType::ObjectFile : llvm::CodeGenFileType::AssemblyFile;
+    bool binary = (fileType == llvm::CodeGenFileType::ObjectFile);
+#else
     llvm::CodeGenFileType fileType = (outputType == Object) ? llvm::CGFT_ObjectFile : llvm::CGFT_AssemblyFile;
     bool binary = (fileType == llvm::CGFT_ObjectFile);
 
+#endif
     llvm::sys::fs::OpenFlags flags = binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_Text;
 
     std::error_code error;
@@ -3090,7 +3107,6 @@ static void lGetExportedFunctions(SymbolTable *symbolTable, std::map<std::string
 }
 
 static llvm::FunctionType *lGetVaryingDispatchType(FunctionTargetVariants &funcs) {
-    llvm::Type *ptrToInt8Ty = llvm::Type::getInt8PtrTy(*g->ctx);
     llvm::FunctionType *resultFuncTy = nullptr;
 
     for (int i = 0; i < Target::NUM_ISAS; ++i) {
@@ -3115,7 +3131,7 @@ static llvm::FunctionType *lGetVaryingDispatchType(FunctionTargetVariants &funcs
                     // For each varying type pointed to, swap the LLVM pointer type
                     // with i8 * (as close as we can get to void *)
                     if (baseType->IsVaryingType()) {
-                        ftype[j] = ptrToInt8Ty;
+                        ftype[j] = LLVMTypes::Int8PointerType;
                         foundVarying = true;
                     }
                 }
diff --git a/src/module.h b/src/module.h
index 4c2c524f71..5aa900410d 100644
--- a/src/module.h
+++ b/src/module.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2010-2023, Intel Corporation
+  Copyright (c) 2010-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -86,18 +86,15 @@ class Module {
     void AddFunctionTemplateDefinition(const TemplateParms *templateParmList, const std::string &name,
                                        const FunctionType *ftype, Stmt *code);
 
-    void AddFunctionTemplateInstantiation(const std::string &name,
-                                          const std::vector<std::pair<const Type *, SourcePos>> &types,
-                                          const FunctionType *ftype, StorageClass sc, bool isInline, bool isNoInline,
-                                          SourcePos pos);
+    void AddFunctionTemplateInstantiation(const std::string &name, const TemplateArgs &tArgs, const FunctionType *ftype,
+                                          StorageClass sc, bool isInline, bool isNoInline, SourcePos pos);
 
     void AddFunctionTemplateSpecializationDeclaration(const std::string &name, const FunctionType *ftype,
-                                                      const std::vector<std::pair<const Type *, SourcePos>> &types,
-                                                      StorageClass sc, bool isInline, bool isNoInline, SourcePos pos);
+                                                      const TemplateArgs &tArgs, StorageClass sc, bool isInline,
+                                                      bool isNoInline, SourcePos pos);
 
     void AddFunctionTemplateSpecializationDefinition(const std::string &name, const FunctionType *ftype,
-                                                     const std::vector<std::pair<const Type *, SourcePos>> &types,
-                                                     SourcePos pos, Stmt *code);
+                                                     const TemplateArgs &tArgs, SourcePos pos, Stmt *code);
 
     /** Adds the given type to the set of types that have their definitions
         included in automatically generated header files. */
@@ -112,8 +109,8 @@ class Module {
        template <typename T> void foo(T t);
        foo<int>(1); // T is assumed to be "varying int" here.
     */
-    FunctionTemplate *MatchFunctionTemplate(const std::string &name, const FunctionType *ftype,
-                                            std::vector<std::pair<const Type *, SourcePos>> &normTypes, SourcePos pos);
+    FunctionTemplate *MatchFunctionTemplate(const std::string &name, const FunctionType *ftype, TemplateArgs &normTypes,
+                                            SourcePos pos);
 
     /** After a source file has been compiled, output can be generated in a
         number of different formats. */
diff --git a/src/opt.cpp b/src/opt.cpp
index 3b92cfec57..19c52162f4 100644
--- a/src/opt.cpp
+++ b/src/opt.cpp
@@ -88,15 +88,6 @@
 #include <llvm/Transforms/Utils/Mem2Reg.h>
 #include <llvm/Transforms/Vectorize/LoadStoreVectorizer.h>
 
-#ifdef ISPC_HOST_IS_LINUX
-#include <alloca.h>
-#elif defined(ISPC_HOST_IS_WINDOWS)
-#include <malloc.h>
-#ifndef __MINGW32__
-#define alloca _alloca
-#endif
-#endif // ISPC_HOST_IS_WINDOWS
-
 #ifdef ISPC_XE_ENABLED
 #include <llvm/GenXIntrinsics/GenXSPIRVWriterAdaptor.h>
 #endif
@@ -194,7 +185,10 @@ class DebugModulePassManager {
     // Start a new group of loop passes
     void initLoopPassManager();
     // Add loop passes to the FunctionPassManager
-    void commitLoopToFunctionPassManager(bool memorySSA = false, bool blocksFreq = false);
+    void commitLoopToFunctionPassManager();
+
+    void setMemorySSA(bool v) { m_memorySSA = v; }
+    void setBlocksFreq(bool v) { m_blocksFreq = v; }
 
   private:
     llvm::TargetMachine *targetMachine;
@@ -222,6 +216,8 @@ class DebugModulePassManager {
 
     bool m_isFPMOpen{false};
     bool m_isLPMOpen{false};
+    bool m_memorySSA{false};
+    bool m_blocksFreq{false};
     int m_passNumber;
     int m_optLevel;
 
@@ -377,15 +373,14 @@ void DebugModulePassManager::initLoopPassManager() {
 }
 
 // Add loop passes to the FunctionPassManager
-void DebugModulePassManager::commitLoopToFunctionPassManager(bool memorySSA, bool useBlockFrequencyInfo) {
+void DebugModulePassManager::commitLoopToFunctionPassManager() {
     Assert(m_isLPMOpen && "LoopPassManager has not been initialized or already committed.");
     if (fpmVec.empty() || lpmVec.empty()) {
         return;
     }
     // Get the last element of lpmVec
     llvm::LoopPassManager *lastLPM = lpmVec.back().get();
-    fpmVec.back()->addPass(
-        llvm::createFunctionToLoopPassAdaptor(std::move(*lastLPM), memorySSA, useBlockFrequencyInfo));
+    fpmVec.back()->addPass(llvm::createFunctionToLoopPassAdaptor(std::move(*lastLPM), m_memorySSA, m_blocksFreq));
     m_isLPMOpen = false;
 }
 
@@ -516,9 +511,11 @@ void ispc::Optimize(llvm::Module *module, int optLevel) {
         optPM.addFunctionPass(llvm::SimplifyCFGPass(simplifyCFGopt));
         optPM.addFunctionPass(llvm::PromotePass());
         optPM.addFunctionPass(llvm::ReassociatePass());
+        optPM.setBlocksFreq(true);
         optPM.initLoopPassManager();
         optPM.addLoopPass(llvm::LoopFullUnrollPass());
-        optPM.commitLoopToFunctionPassManager(false, true);
+        optPM.commitLoopToFunctionPassManager();
+        optPM.setBlocksFreq(false);
         optPM.addFunctionPass(ReplaceStdlibShiftPass(), 229);
         optPM.addFunctionPass(llvm::InstCombinePass());
         optPM.addFunctionPass(llvm::SimplifyCFGPass(simplifyCFGopt));
@@ -642,6 +639,8 @@ void ispc::Optimize(llvm::Module *module, int optLevel) {
         // We provide the opt remark emitter pass for LICM to use.
         optPM.addFunctionPass(llvm::RequireAnalysisPass<llvm::OptimizationRemarkEmitterAnalysis, llvm::Function>());
 
+        optPM.setMemorySSA(true);
+        optPM.setBlocksFreq(true);
         optPM.initLoopPassManager();
         // Loop passes using MemorySSA
         optPM.addLoopPass(llvm::LoopRotatePass(), 291);
@@ -661,7 +660,9 @@ void ispc::Optimize(llvm::Module *module, int optLevel) {
             // Note: enable both trivial and non-trivial loop unswitching.
             optPM.addLoopPass(llvm::SimpleLoopUnswitchPass(true /* NonTrivial */, true /* Trivial */), 293);
         }
-        optPM.commitLoopToFunctionPassManager(true, true);
+        optPM.commitLoopToFunctionPassManager();
+        optPM.setMemorySSA(false);
+        optPM.setBlocksFreq(false);
 
         optPM.addFunctionPass(llvm::InstCombinePass());
         optPM.addFunctionPass(InstructionSimplifyPass());
diff --git a/src/opt/GatherCoalescePass.cpp b/src/opt/GatherCoalescePass.cpp
index bc5945b3cc..a81f247f02 100644
--- a/src/opt/GatherCoalescePass.cpp
+++ b/src/opt/GatherCoalescePass.cpp
@@ -1,10 +1,11 @@
 /*
-  Copyright (c) 2022-2023, Intel Corporation
+  Copyright (c) 2022-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
 
 #include "GatherCoalescePass.h"
+#include "builtins-decl.h"
 
 namespace ispc {
 
@@ -850,10 +851,10 @@ bool GatherCoalescePass::coalesceGathersFactored(llvm::BasicBlock &bb) {
     DEBUG_START_BB("GatherCoalescePass");
 
     llvm::Function *gatherFuncs[] = {
-        m->module->getFunction("__pseudo_gather_factored_base_offsets32_i32"),
-        m->module->getFunction("__pseudo_gather_factored_base_offsets32_float"),
-        m->module->getFunction("__pseudo_gather_factored_base_offsets64_i32"),
-        m->module->getFunction("__pseudo_gather_factored_base_offsets64_float"),
+        m->module->getFunction(builtin::__pseudo_gather_factored_base_offsets32_i32),
+        m->module->getFunction(builtin::__pseudo_gather_factored_base_offsets32_float),
+        m->module->getFunction(builtin::__pseudo_gather_factored_base_offsets64_i32),
+        m->module->getFunction(builtin::__pseudo_gather_factored_base_offsets64_float),
     };
     int nGatherFuncs = sizeof(gatherFuncs) / sizeof(gatherFuncs[0]);
 
diff --git a/src/opt/ISPCPass.h b/src/opt/ISPCPass.h
index f02eb42fe1..c1c413377e 100644
--- a/src/opt/ISPCPass.h
+++ b/src/opt/ISPCPass.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2022-2023, Intel Corporation
+  Copyright (c) 2022-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -37,7 +37,9 @@
 #include <llvm/Transforms/Instrumentation.h>
 #include <llvm/Transforms/Utils.h>
 #include <llvm/Transforms/Utils/BasicBlockUtils.h>
-#include <llvm/Transforms/Vectorize.h>
+#if ISPC_LLVM_VERSION > ISPC_LLVM_17_0
+#include <llvm/Transforms/Vectorize/LoadStoreVectorizer.h>
+#endif
 
 #ifdef ISPC_XE_ENABLED
 #include <llvm/GenXIntrinsics/GenXIntrOpts.h>
diff --git a/src/opt/ImproveMemoryOps.cpp b/src/opt/ImproveMemoryOps.cpp
index 0a26b75bce..519da088f3 100644
--- a/src/opt/ImproveMemoryOps.cpp
+++ b/src/opt/ImproveMemoryOps.cpp
@@ -1,13 +1,16 @@
 /*
-  Copyright (c) 2022-2023, Intel Corporation
+  Copyright (c) 2022-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
 
 #include "ImproveMemoryOps.h"
+#include "builtins-decl.h"
 
 namespace ispc {
 
+using namespace builtin;
+
 /** Check to make sure that this value is actually a pointer in the end.
     We need to make sure that given an expression like vec(offset) +
     ptr2int(ptr), lGetBasePointer() doesn't return vec(offset) for the base
@@ -543,115 +546,6 @@ static llvm::Value *lExtractOffsetVector248Scale(llvm::Value **vec) {
         return LLVMInt32(1);
 }
 
-#if 0
-static llvm::Value *
-lExtractUniforms(llvm::Value **vec, llvm::Instruction *insertBefore) {
-    fprintf(stderr, " lextract: ");
-    (*vec)->dump();
-    fprintf(stderr, "\n");
-
-    if (llvm::isa<llvm::ConstantVector>(*vec) ||
-        llvm::isa<llvm::ConstantDataVector>(*vec) ||
-        llvm::isa<llvm::ConstantAggregateZero>(*vec))
-        return nullptr;
-
-    llvm::SExtInst *sext = llvm::dyn_cast<llvm::SExtInst>(*vec);
-    if (sext != nullptr) {
-        llvm::Value *sextOp = sext->getOperand(0);
-        // Check the sext target.
-        llvm::Value *unif = lExtractUniforms(&sextOp, insertBefore);
-        if (unif == nullptr)
-            return nullptr;
-
-        // make a new sext instruction so that we end up with the right
-        // type
-        *vec = new llvm::SExtInst(sextOp, sext->getType(), "offset_sext", sext);
-        return unif;
-    }
-
-    if (LLVMVectorValuesAllEqual(*vec)) {
-        // FIXME: we may want to redo all of the expression here, in scalar
-        // form (if at all possible), for code quality...
-        llvm::Value *unif =
-            llvm::ExtractElementInst::Create(*vec, LLVMInt32(0),
-                                             "first_uniform", insertBefore);
-        *vec = nullptr;
-        return unif;
-    }
-
-    llvm::BinaryOperator *bop = llvm::dyn_cast<llvm::BinaryOperator>(*vec);
-    if (bop == nullptr)
-        return nullptr;
-
-    llvm::Value *op0 = bop->getOperand(0), *op1 = bop->getOperand(1);
-    if (bop->getOpcode() == llvm::Instruction::Add) {
-        llvm::Value *s0 = lExtractUniforms(&op0, insertBefore);
-        llvm::Value *s1 = lExtractUniforms(&op1, insertBefore);
-        if (s0 == nullptr && s1 == nullptr)
-            return nullptr;
-
-        if (op0 == nullptr)
-            *vec = op1;
-        else if (op1 == nullptr)
-            *vec = op0;
-        else
-            *vec = llvm::BinaryOperator::Create(llvm::Instruction::Add,
-                                                op0, op1, "new_add", insertBefore);
-
-        if (s0 == nullptr)
-            return s1;
-        else if (s1 == nullptr)
-            return s0;
-        else
-            return llvm::BinaryOperator::Create(llvm::Instruction::Add, s0, s1,
-                                                "add_unif", insertBefore);
-    }
-#if 0
-    else if (bop->getOpcode() == llvm::Instruction::Mul) {
-        // Check each operand for being one of the scale factors we care about.
-        int splat;
-        if (lIs248Splat(op0, &splat)) {
-            *vec = op1;
-            return LLVMInt32(splat);
-        }
-        else if (lIs248Splat(op1, &splat)) {
-            *vec = op0;
-            return LLVMInt32(splat);
-        }
-        else
-            return LLVMInt32(1);
-    }
-#endif
-    else
-        return nullptr;
-}
-
-
-static void
-lExtractUniformsFromOffset(llvm::Value **basePtr, llvm::Value **offsetVector,
-                           llvm::Value *offsetScale,
-                           llvm::Instruction *insertBefore) {
-#if 1
-    (*basePtr)->dump();
-    printf("\n");
-    (*offsetVector)->dump();
-    printf("\n");
-    offsetScale->dump();
-    printf("-----\n");
-#endif
-
-    llvm::Value *uniformDelta = lExtractUniforms(offsetVector, insertBefore);
-    if (uniformDelta == nullptr)
-        return;
-
-    *basePtr = LLVMGEPInst(*basePtr, arrayRef, "new_base", insertBefore);
-
-    // this should only happen if we have only uniforms, but that in turn
-    // shouldn't be a gather/scatter!
-    Assert(*offsetVector != nullptr);
-}
-#endif
-
 static bool lVectorIs32BitInts(llvm::Value *v) {
     int nElts;
     int64_t elts[ISPC_MAX_NVEC];
@@ -759,238 +653,157 @@ static bool lOffsets32BitSafe(llvm::Value **offsetPtr, llvm::Instruction *insert
         return false;
 }
 
-static llvm::CallInst *lGSToGSBaseOffsets(llvm::CallInst *callInst) {
-    struct GSInfo {
-        GSInfo(const char *pgFuncName, const char *pgboFuncName, const char *pgbo32FuncName, bool ig, bool ip)
-            : isGather(ig), isPrefetch(ip) {
-            func = m->module->getFunction(pgFuncName);
-            baseOffsetsFunc = m->module->getFunction(pgboFuncName);
-            baseOffsets32Func = m->module->getFunction(pgbo32FuncName);
-        }
-        llvm::Function *func;
-        llvm::Function *baseOffsetsFunc, *baseOffsets32Func;
-        const bool isGather;
-        const bool isPrefetch;
+// Contains a function call substitution info for gather/scatter/prefetch calls.
+// We construct this class objects in program constructors phase, i.e., before initialization of m->module, g->target
+// and any of LLVMTypes values. Moreover, g->target values are not same during multi-target compilation. Because of
+// that, we postpone evaluation of types, choosing the proper function before actual call replacement here and in
+// similar types across this file.
+struct GSInfo {
+    enum class Type {
+        Gather,
+        Scatter,
+        Prefetch,
     };
+    GSInfo(const char *pgbo64, const char *pgfbo64, const char *pgbo32, const char *pgfbo32, GSInfo::Type type)
+        : pgbo64(pgbo64), pgfbo64(pgfbo64), pgbo32(pgbo32), pgfbo32(pgfbo32), type(type) {}
+    GSInfo(const char *pgbo64, const char *pgfbo64, GSInfo::Type type)
+        : pgbo64(pgbo64), pgfbo64(pgfbo64), pgbo32(pgbo64), pgfbo32(pgfbo64), type(type) {}
+    static GSInfo Gather(const char *pgbo64, const char *pgfbo64, const char *pgbo32, const char *pgfbo32) {
+        return GSInfo(pgbo64, pgfbo64, pgbo32, pgfbo32, Type::Gather);
+    }
+    static GSInfo Gather(const char *pgbo64, const char *pgfbo64) { return GSInfo(pgbo64, pgfbo64, Type::Gather); }
+    static GSInfo Scatter(const char *pgbo64, const char *pgfbo64, const char *pgbo32, const char *pgfbo32) {
+        return GSInfo(pgbo64, pgfbo64, pgbo32, pgfbo32, Type::Scatter);
+    }
+    static GSInfo Scatter(const char *pgbo64, const char *pgfbo64) { return GSInfo(pgbo64, pgfbo64, Type::Scatter); }
+    static GSInfo Prefetch(const char *pgbo64, const char *pgfbo64) { return GSInfo(pgbo64, pgfbo64, Type::Prefetch); }
+    bool isGather() const { return type == GSInfo::Type::Gather; }
+    bool isScatter() const { return type == GSInfo::Type::Scatter; }
+    bool isPrefetch() const { return type == GSInfo::Type::Prefetch; }
+    llvm::Function *baseOffsets64Func() const {
+        const char *name = chooseBaseOrFactoredFunc() ? pgbo64 : pgfbo64;
+        return m->module->getFunction(name);
+    }
+    llvm::Function *baseOffsets32Func() const {
+        const char *name = chooseBaseOrFactoredFunc() ? pgbo32 : pgfbo32;
+        return m->module->getFunction(name);
+    }
 
-    GSInfo gsFuncs[] = {
-        GSInfo(
-            "__pseudo_gather32_i8",
-            g->target->useGather() ? "__pseudo_gather_base_offsets32_i8" : "__pseudo_gather_factored_base_offsets32_i8",
-            g->target->useGather() ? "__pseudo_gather_base_offsets32_i8" : "__pseudo_gather_factored_base_offsets32_i8",
-            true, false),
-        GSInfo("__pseudo_gather32_i16",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_i16"
-                                      : "__pseudo_gather_factored_base_offsets32_i16",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_i16"
-                                      : "__pseudo_gather_factored_base_offsets32_i16",
-               true, false),
-        GSInfo("__pseudo_gather32_half",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_half"
-                                      : "__pseudo_gather_factored_base_offsets32_half",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_half"
-                                      : "__pseudo_gather_factored_base_offsets32_half",
-               true, false),
-        GSInfo("__pseudo_gather32_i32",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_i32"
-                                      : "__pseudo_gather_factored_base_offsets32_i32",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_i32"
-                                      : "__pseudo_gather_factored_base_offsets32_i32",
-               true, false),
-        GSInfo("__pseudo_gather32_float",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_float"
-                                      : "__pseudo_gather_factored_base_offsets32_float",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_float"
-                                      : "__pseudo_gather_factored_base_offsets32_float",
-               true, false),
-        GSInfo("__pseudo_gather32_i64",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_i64"
-                                      : "__pseudo_gather_factored_base_offsets32_i64",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_i64"
-                                      : "__pseudo_gather_factored_base_offsets32_i64",
-               true, false),
-        GSInfo("__pseudo_gather32_double",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_double"
-                                      : "__pseudo_gather_factored_base_offsets32_double",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_double"
-                                      : "__pseudo_gather_factored_base_offsets32_double",
-               true, false),
-
-        GSInfo("__pseudo_scatter32_i8",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i8"
-                                       : "__pseudo_scatter_factored_base_offsets32_i8",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i8"
-                                       : "__pseudo_scatter_factored_base_offsets32_i8",
-               false, false),
-        GSInfo("__pseudo_scatter32_i16",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i16"
-                                       : "__pseudo_scatter_factored_base_offsets32_i16",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i16"
-                                       : "__pseudo_scatter_factored_base_offsets32_i16",
-               false, false),
-        GSInfo("__pseudo_scatter32_half",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_half"
-                                       : "__pseudo_scatter_factored_base_offsets32_half",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_half"
-                                       : "__pseudo_scatter_factored_base_offsets32_half",
-               false, false),
-        GSInfo("__pseudo_scatter32_i32",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i32"
-                                       : "__pseudo_scatter_factored_base_offsets32_i32",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i32"
-                                       : "__pseudo_scatter_factored_base_offsets32_i32",
-               false, false),
-        GSInfo("__pseudo_scatter32_float",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_float"
-                                       : "__pseudo_scatter_factored_base_offsets32_float",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_float"
-                                       : "__pseudo_scatter_factored_base_offsets32_float",
-               false, false),
-        GSInfo("__pseudo_scatter32_i64",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i64"
-                                       : "__pseudo_scatter_factored_base_offsets32_i64",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i64"
-                                       : "__pseudo_scatter_factored_base_offsets32_i64",
-               false, false),
-        GSInfo("__pseudo_scatter32_double",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_double"
-                                       : "__pseudo_scatter_factored_base_offsets32_double",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_double"
-                                       : "__pseudo_scatter_factored_base_offsets32_double",
-               false, false),
-
-        GSInfo(
-            "__pseudo_gather64_i8",
-            g->target->useGather() ? "__pseudo_gather_base_offsets64_i8" : "__pseudo_gather_factored_base_offsets64_i8",
-            g->target->useGather() ? "__pseudo_gather_base_offsets32_i8" : "__pseudo_gather_factored_base_offsets32_i8",
-            true, false),
-        GSInfo("__pseudo_gather64_i16",
-               g->target->useGather() ? "__pseudo_gather_base_offsets64_i16"
-                                      : "__pseudo_gather_factored_base_offsets64_i16",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_i16"
-                                      : "__pseudo_gather_factored_base_offsets32_i16",
-               true, false),
-        GSInfo("__pseudo_gather64_half",
-               g->target->useGather() ? "__pseudo_gather_base_offsets64_half"
-                                      : "__pseudo_gather_factored_base_offsets64_half",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_half"
-                                      : "__pseudo_gather_factored_base_offsets32_half",
-               true, false),
-        GSInfo("__pseudo_gather64_i32",
-               g->target->useGather() ? "__pseudo_gather_base_offsets64_i32"
-                                      : "__pseudo_gather_factored_base_offsets64_i32",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_i32"
-                                      : "__pseudo_gather_factored_base_offsets32_i32",
-               true, false),
-        GSInfo("__pseudo_gather64_float",
-               g->target->useGather() ? "__pseudo_gather_base_offsets64_float"
-                                      : "__pseudo_gather_factored_base_offsets64_float",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_float"
-                                      : "__pseudo_gather_factored_base_offsets32_float",
-               true, false),
-        GSInfo("__pseudo_gather64_i64",
-               g->target->useGather() ? "__pseudo_gather_base_offsets64_i64"
-                                      : "__pseudo_gather_factored_base_offsets64_i64",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_i64"
-                                      : "__pseudo_gather_factored_base_offsets32_i64",
-               true, false),
-        GSInfo("__pseudo_gather64_double",
-               g->target->useGather() ? "__pseudo_gather_base_offsets64_double"
-                                      : "__pseudo_gather_factored_base_offsets64_double",
-               g->target->useGather() ? "__pseudo_gather_base_offsets32_double"
-                                      : "__pseudo_gather_factored_base_offsets32_double",
-               true, false),
-
-        GSInfo("__pseudo_scatter64_i8",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets64_i8"
-                                       : "__pseudo_scatter_factored_base_offsets64_i8",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i8"
-                                       : "__pseudo_scatter_factored_base_offsets32_i8",
-               false, false),
-        GSInfo("__pseudo_scatter64_i16",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets64_i16"
-                                       : "__pseudo_scatter_factored_base_offsets64_i16",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i16"
-                                       : "__pseudo_scatter_factored_base_offsets32_i16",
-               false, false),
-        GSInfo("__pseudo_scatter64_half",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets64_half"
-                                       : "__pseudo_scatter_factored_base_offsets64_half",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_half"
-                                       : "__pseudo_scatter_factored_base_offsets32_half",
-               false, false),
-        GSInfo("__pseudo_scatter64_i32",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets64_i32"
-                                       : "__pseudo_scatter_factored_base_offsets64_i32",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i32"
-                                       : "__pseudo_scatter_factored_base_offsets32_i32",
-               false, false),
-        GSInfo("__pseudo_scatter64_float",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets64_float"
-                                       : "__pseudo_scatter_factored_base_offsets64_float",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_float"
-                                       : "__pseudo_scatter_factored_base_offsets32_float",
-               false, false),
-        GSInfo("__pseudo_scatter64_i64",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets64_i64"
-                                       : "__pseudo_scatter_factored_base_offsets64_i64",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i64"
-                                       : "__pseudo_scatter_factored_base_offsets32_i64",
-               false, false),
-        GSInfo("__pseudo_scatter64_double",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets64_double"
-                                       : "__pseudo_scatter_factored_base_offsets64_double",
-               g->target->useScatter() ? "__pseudo_scatter_base_offsets32_double"
-                                       : "__pseudo_scatter_factored_base_offsets32_double",
-               false, false),
-        GSInfo("__pseudo_prefetch_read_varying_1",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_1_native" : "__prefetch_read_varying_1",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_1_native" : "__prefetch_read_varying_1",
-               false, true),
-
-        GSInfo("__pseudo_prefetch_read_varying_2",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_2_native" : "__prefetch_read_varying_2",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_2_native" : "__prefetch_read_varying_2",
-               false, true),
-
-        GSInfo("__pseudo_prefetch_read_varying_3",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_3_native" : "__prefetch_read_varying_3",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_3_native" : "__prefetch_read_varying_3",
-               false, true),
-
-        GSInfo("__pseudo_prefetch_read_varying_nt",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_nt_native" : "__prefetch_read_varying_nt",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_nt_native" : "__prefetch_read_varying_nt",
-               false, true),
-
-        GSInfo("__pseudo_prefetch_write_varying_1",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_write_varying_1_native" : "__prefetch_write_varying_1",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_write_varying_1_native" : "__prefetch_write_varying_1",
-               false, true),
-        GSInfo("__pseudo_prefetch_write_varying_2",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_write_varying_2_native" : "__prefetch_write_varying_2",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_write_varying_2_native" : "__prefetch_write_varying_2",
-               false, true),
-
-        GSInfo("__pseudo_prefetch_write_varying_3",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_write_varying_3_native" : "__prefetch_write_varying_3",
-               g->target->hasVecPrefetch() ? "__pseudo_prefetch_write_varying_3_native" : "__prefetch_write_varying_3",
-               false, true),
-    };
+  private:
+    bool chooseBaseOrFactoredFunc() const {
+        switch (type) {
+        case GSInfo::Type::Gather:
+            return g->target->useGather();
+        case GSInfo::Type::Scatter:
+            return g->target->useScatter();
+        case GSInfo::Type::Prefetch:
+            return g->target->hasVecPrefetch();
+        }
+        return false;
+    }
+    const char *pgbo64;
+    const char *pgfbo64;
+    const char *pgbo32;
+    const char *pgfbo32;
+    GSInfo::Type type;
+};
 
-    int numGSFuncs = sizeof(gsFuncs) / sizeof(gsFuncs[0]);
-    for (int i = 0; i < numGSFuncs; ++i)
-        Assert(gsFuncs[i].func != nullptr && gsFuncs[i].baseOffsetsFunc != nullptr &&
-               gsFuncs[i].baseOffsets32Func != nullptr);
+static llvm::CallInst *lGSToGSBaseOffsets(llvm::CallInst *callInst) {
+    // A map for call replacement used in lGSToGSBaseOffsets.
+    static std::unordered_map<std::string, GSInfo> replacementRules = {
+        {__pseudo_gather32_i8,
+         GSInfo::Gather(__pseudo_gather_base_offsets32_i8, __pseudo_gather_factored_base_offsets32_i8)},
+        {__pseudo_gather32_i16,
+         GSInfo::Gather(__pseudo_gather_base_offsets32_i16, __pseudo_gather_factored_base_offsets32_i16)},
+        {__pseudo_gather32_half,
+         GSInfo::Gather(__pseudo_gather_base_offsets32_half, __pseudo_gather_factored_base_offsets32_half)},
+        {__pseudo_gather32_i32,
+         GSInfo::Gather(__pseudo_gather_base_offsets32_i32, __pseudo_gather_factored_base_offsets32_i32)},
+        {__pseudo_gather32_float,
+         GSInfo::Gather(__pseudo_gather_base_offsets32_float, __pseudo_gather_factored_base_offsets32_float)},
+        {__pseudo_gather32_i64,
+         GSInfo::Gather(__pseudo_gather_base_offsets32_i64, __pseudo_gather_factored_base_offsets32_i64)},
+        {__pseudo_gather32_double,
+         GSInfo::Gather(__pseudo_gather_base_offsets32_double, __pseudo_gather_factored_base_offsets32_double)},
+        {__pseudo_scatter32_i8,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets32_i8, __pseudo_scatter_factored_base_offsets32_i8)},
+        {__pseudo_scatter32_i16,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets32_i16, __pseudo_scatter_factored_base_offsets32_i16)},
+        {__pseudo_scatter32_half,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets32_half, __pseudo_scatter_factored_base_offsets32_half)},
+        {__pseudo_scatter32_i32,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets32_i32, __pseudo_scatter_factored_base_offsets32_i32)},
+        {__pseudo_scatter32_float,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets32_float, __pseudo_scatter_factored_base_offsets32_float)},
+        {__pseudo_scatter32_i64,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets32_i64, __pseudo_scatter_factored_base_offsets32_i64)},
+        {__pseudo_scatter32_double,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets32_double, __pseudo_scatter_factored_base_offsets32_double)},
+        {__pseudo_gather64_i8,
+         GSInfo::Gather(__pseudo_gather_base_offsets64_i8, __pseudo_gather_factored_base_offsets64_i8,
+                        __pseudo_gather_base_offsets32_i8, __pseudo_gather_factored_base_offsets32_i8)},
+        {__pseudo_gather64_i16,
+         GSInfo::Gather(__pseudo_gather_base_offsets64_i16, __pseudo_gather_factored_base_offsets64_i16,
+                        __pseudo_gather_base_offsets32_i16, __pseudo_gather_factored_base_offsets32_i16)},
+        {__pseudo_gather64_half,
+         GSInfo::Gather(__pseudo_gather_base_offsets64_half, __pseudo_gather_factored_base_offsets64_half,
+                        __pseudo_gather_base_offsets32_half, __pseudo_gather_factored_base_offsets32_half)},
+        {__pseudo_gather64_i32,
+         GSInfo::Gather(__pseudo_gather_base_offsets64_i32, __pseudo_gather_factored_base_offsets64_i32,
+                        __pseudo_gather_base_offsets32_i32, __pseudo_gather_factored_base_offsets32_i32)},
+        {__pseudo_gather64_float,
+         GSInfo::Gather(__pseudo_gather_base_offsets64_float, __pseudo_gather_factored_base_offsets64_float,
+                        __pseudo_gather_base_offsets32_float, __pseudo_gather_factored_base_offsets32_float)},
+        {__pseudo_gather64_i64,
+         GSInfo::Gather(__pseudo_gather_base_offsets64_i64, __pseudo_gather_factored_base_offsets64_i64,
+                        __pseudo_gather_base_offsets32_i64, __pseudo_gather_factored_base_offsets32_i64)},
+        {__pseudo_gather64_double,
+         GSInfo::Gather(__pseudo_gather_base_offsets64_double, __pseudo_gather_factored_base_offsets64_double,
+                        __pseudo_gather_base_offsets32_double, __pseudo_gather_factored_base_offsets32_double)},
+        {__pseudo_scatter64_i8,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets64_i8, __pseudo_scatter_factored_base_offsets64_i8,
+                         __pseudo_scatter_base_offsets32_i8, __pseudo_scatter_factored_base_offsets32_i8)},
+        {__pseudo_scatter64_i16,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets64_i16, __pseudo_scatter_factored_base_offsets64_i16,
+                         __pseudo_scatter_base_offsets32_i16, __pseudo_scatter_factored_base_offsets32_i16)},
+        {__pseudo_scatter64_half,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets64_half, __pseudo_scatter_factored_base_offsets64_half,
+                         __pseudo_scatter_base_offsets32_half, __pseudo_scatter_factored_base_offsets32_half)},
+        {__pseudo_scatter64_i32,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets64_i32, __pseudo_scatter_factored_base_offsets64_i32,
+                         __pseudo_scatter_base_offsets32_i32, __pseudo_scatter_factored_base_offsets32_i32)},
+        {__pseudo_scatter64_float,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets64_float, __pseudo_scatter_factored_base_offsets64_float,
+                         __pseudo_scatter_base_offsets32_float, __pseudo_scatter_factored_base_offsets32_float)},
+        {__pseudo_scatter64_i64,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets64_i64, __pseudo_scatter_factored_base_offsets64_i64,
+                         __pseudo_scatter_base_offsets32_i64, __pseudo_scatter_factored_base_offsets32_i64)},
+        {__pseudo_scatter64_double,
+         GSInfo::Scatter(__pseudo_scatter_base_offsets64_double, __pseudo_scatter_factored_base_offsets64_double,
+                         __pseudo_scatter_base_offsets32_double, __pseudo_scatter_factored_base_offsets32_double)},
+        {__pseudo_prefetch_read_varying_1,
+         GSInfo::Prefetch(__pseudo_prefetch_read_varying_1_native, __prefetch_read_varying_1)},
+        {__pseudo_prefetch_read_varying_2,
+         GSInfo::Prefetch(__pseudo_prefetch_read_varying_2_native, __prefetch_read_varying_2)},
+        {__pseudo_prefetch_read_varying_3,
+         GSInfo::Prefetch(__pseudo_prefetch_read_varying_3_native, __prefetch_read_varying_3)},
+        {__pseudo_prefetch_read_varying_nt,
+         GSInfo::Prefetch(__pseudo_prefetch_read_varying_nt_native, __prefetch_read_varying_nt)},
+        {__pseudo_prefetch_write_varying_1,
+         GSInfo::Prefetch(__pseudo_prefetch_write_varying_1_native, __prefetch_write_varying_1)},
+        {__pseudo_prefetch_write_varying_2,
+         GSInfo::Prefetch(__pseudo_prefetch_write_varying_2_native, __prefetch_write_varying_2)},
+        {__pseudo_prefetch_write_varying_3,
+         GSInfo::Prefetch(__pseudo_prefetch_write_varying_3_native, __prefetch_write_varying_3)},
+    };
 
-    GSInfo *info = nullptr;
-    for (int i = 0; i < numGSFuncs; ++i)
-        if (gsFuncs[i].func != nullptr && callInst->getCalledFunction() == gsFuncs[i].func) {
-            info = &gsFuncs[i];
-            break;
-        }
-    if (info == nullptr)
+    auto name = callInst->getCalledFunction()->getName().str();
+    auto it = replacementRules.find(name);
+    if (it == replacementRules.end()) {
+        // it is not a call of __pseudo function stored in replacementRules
         return nullptr;
+    }
+    GSInfo *info = &it->second;
 
     // Try to transform the array of pointers to a single base pointer
     // and an array of int32 offsets.  (All the hard work is done by
@@ -999,8 +812,7 @@ static llvm::CallInst *lGSToGSBaseOffsets(llvm::CallInst *callInst) {
     llvm::Value *offsetVector = nullptr;
     llvm::Value *basePtr = lGetBasePtrAndOffsets(ptrs, &offsetVector, callInst);
 
-    if (basePtr == nullptr || offsetVector == nullptr ||
-        (info->isGather == false && info->isPrefetch == true && g->target->hasVecPrefetch() == false)) {
+    if (basePtr == nullptr || offsetVector == nullptr || (info->isPrefetch() && !g->target->hasVecPrefetch())) {
         // It's actually a fully general gather/scatter with a varying
         // set of base pointers, so leave it as is and continune onward
         // to the next instruction...
@@ -1011,12 +823,11 @@ static llvm::CallInst *lGSToGSBaseOffsets(llvm::CallInst *callInst) {
     basePtr = new llvm::IntToPtrInst(basePtr, LLVMTypes::VoidPointerType, llvm::Twine(basePtr->getName()) + "_2void",
                                      callInst);
     LLVMCopyMetadata(basePtr, callInst);
-    llvm::Function *gatherScatterFunc = info->baseOffsetsFunc;
+    llvm::Function *gatherScatterFunc = info->baseOffsets64Func();
     llvm::CallInst *newCall = nullptr;
 
-    if ((info->isGather == true && g->target->useGather()) ||
-        (info->isGather == false && info->isPrefetch == false && g->target->useScatter()) ||
-        (info->isGather == false && info->isPrefetch == true && g->target->hasVecPrefetch())) {
+    if ((info->isGather() && g->target->useGather()) || (info->isScatter() && g->target->useScatter()) ||
+        (info->isPrefetch() && g->target->hasVecPrefetch())) {
 
         // See if the offsets are scaled by 2, 4, or 8.  If so,
         // extract that scale factor and rewrite the offsets to remove
@@ -1027,10 +838,10 @@ static llvm::CallInst *lGSToGSBaseOffsets(llvm::CallInst *callInst) {
         // will see if we can call one of the 32-bit variants of the pseudo
         // gather/scatter functions.
         if (g->opt.force32BitAddressing && lOffsets32BitSafe(&offsetVector, callInst)) {
-            gatherScatterFunc = info->baseOffsets32Func;
+            gatherScatterFunc = info->baseOffsets32Func();
         }
 
-        if (info->isGather || info->isPrefetch) {
+        if (info->isGather() || info->isPrefetch()) {
             llvm::Value *mask = callInst->getArgOperand(1);
 
             // Generate a new function call to the next pseudo gather
@@ -1078,10 +889,10 @@ static llvm::CallInst *lGSToGSBaseOffsets(llvm::CallInst *callInst) {
         // will see if we can call one of the 32-bit variants of the pseudo
         // gather/scatter functions.
         if (g->opt.force32BitAddressing && lOffsets32BitSafe(&variableOffset, &constOffset, callInst)) {
-            gatherScatterFunc = info->baseOffsets32Func;
+            gatherScatterFunc = info->baseOffsets32Func();
         }
 
-        if (info->isGather || info->isPrefetch) {
+        if (info->isGather() || info->isPrefetch()) {
             llvm::Value *mask = callInst->getArgOperand(1);
 
             // Generate a new function call to the next pseudo gather
@@ -1111,144 +922,95 @@ static llvm::CallInst *lGSToGSBaseOffsets(llvm::CallInst *callInst) {
 
 /** Try to improve the decomposition between compile-time constant and
     compile-time unknown offsets in calls to the __pseudo_*_base_offsets*
-    functions.  Other other optimizations have run, we will sometimes be
+    functions. After other optimizations have run, we will sometimes be
     able to pull more terms out of the unknown part and add them into the
     compile-time-known part.
  */
 static llvm::CallInst *lGSBaseOffsetsGetMoreConst(llvm::CallInst *callInst) {
-    struct GSBOInfo {
-        GSBOInfo(const char *pgboFuncName, const char *pgbo32FuncName, bool ig, bool ip)
-            : isGather(ig), isPrefetch(ip) {
-            baseOffsetsFunc = m->module->getFunction(pgboFuncName);
-            baseOffsets32Func = m->module->getFunction(pgbo32FuncName);
-        }
-        llvm::Function *baseOffsetsFunc, *baseOffsets32Func;
-        const bool isGather;
-        const bool isPrefetch;
-    };
-
-    GSBOInfo gsFuncs[] = {
-        GSBOInfo(
-            g->target->useGather() ? "__pseudo_gather_base_offsets64_i8" : "__pseudo_gather_factored_base_offsets64_i8",
-            g->target->useGather() ? "__pseudo_gather_base_offsets32_i8" : "__pseudo_gather_factored_base_offsets32_i8",
-            true, false),
-        GSBOInfo(g->target->useGather() ? "__pseudo_gather_base_offsets64_i16"
-                                        : "__pseudo_gather_factored_base_offsets64_i16",
-                 g->target->useGather() ? "__pseudo_gather_base_offsets32_i16"
-                                        : "__pseudo_gather_factored_base_offsets32_i16",
-                 true, false),
-        GSBOInfo(g->target->useGather() ? "__pseudo_gather_base_offsets64_half"
-                                        : "__pseudo_gather_factored_base_offsets64_half",
-                 g->target->useGather() ? "__pseudo_gather_base_offsets32_half"
-                                        : "__pseudo_gather_factored_base_offsets32_half",
-                 true, false),
-        GSBOInfo(g->target->useGather() ? "__pseudo_gather_base_offsets64_i32"
-                                        : "__pseudo_gather_factored_base_offsets64_i32",
-                 g->target->useGather() ? "__pseudo_gather_base_offsets32_i32"
-                                        : "__pseudo_gather_factored_base_offsets32_i32",
-                 true, false),
-        GSBOInfo(g->target->useGather() ? "__pseudo_gather_base_offsets64_float"
-                                        : "__pseudo_gather_factored_base_offsets64_float",
-                 g->target->useGather() ? "__pseudo_gather_base_offsets32_float"
-                                        : "__pseudo_gather_factored_base_offsets32_float",
-                 true, false),
-        GSBOInfo(g->target->useGather() ? "__pseudo_gather_base_offsets64_i64"
-                                        : "__pseudo_gather_factored_base_offsets64_i64",
-                 g->target->useGather() ? "__pseudo_gather_base_offsets32_i64"
-                                        : "__pseudo_gather_factored_base_offsets32_i64",
-                 true, false),
-        GSBOInfo(g->target->useGather() ? "__pseudo_gather_base_offsets64_double"
-                                        : "__pseudo_gather_factored_base_offsets64_double",
-                 g->target->useGather() ? "__pseudo_gather_base_offsets32_double"
-                                        : "__pseudo_gather_factored_base_offsets32_double",
-                 true, false),
-
-        GSBOInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_i8"
-                                         : "__pseudo_scatter_factored_base_offsets64_i8",
-                 g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i8"
-                                         : "__pseudo_scatter_factored_base_offsets32_i8",
-                 false, false),
-        GSBOInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_i16"
-                                         : "__pseudo_scatter_factored_base_offsets64_i16",
-                 g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i16"
-                                         : "__pseudo_scatter_factored_base_offsets32_i16",
-                 false, false),
-        GSBOInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_half"
-                                         : "__pseudo_scatter_factored_base_offsets64_half",
-                 g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i16"
-                                         : "__pseudo_scatter_factored_base_offsets32_half",
-                 false, false),
-        GSBOInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_i32"
-                                         : "__pseudo_scatter_factored_base_offsets64_i32",
-                 g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i32"
-                                         : "__pseudo_scatter_factored_base_offsets32_i32",
-                 false, false),
-        GSBOInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_float"
-                                         : "__pseudo_scatter_factored_base_offsets64_float",
-                 g->target->useScatter() ? "__pseudo_scatter_base_offsets32_float"
-                                         : "__pseudo_scatter_factored_base_offsets32_float",
-                 false, false),
-        GSBOInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_i64"
-                                         : "__pseudo_scatter_factored_base_offsets64_i64",
-                 g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i64"
-                                         : "__pseudo_scatter_factored_base_offsets32_i64",
-                 false, false),
-        GSBOInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_double"
-                                         : "__pseudo_scatter_factored_base_offsets64_double",
-                 g->target->useScatter() ? "__pseudo_scatter_base_offsets32_double"
-                                         : "__pseudo_scatter_factored_base_offsets32_double",
-                 false, false),
-
-        GSBOInfo(g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_1_native" : "__prefetch_read_varying_1",
-                 g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_1_native" : "__prefetch_read_varying_1",
-                 false, true),
-
-        GSBOInfo(g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_2_native" : "__prefetch_read_varying_2",
-                 g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_2_native" : "__prefetch_read_varying_2",
-                 false, true),
-
-        GSBOInfo(g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_3_native" : "__prefetch_read_varying_3",
-                 g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_3_native" : "__prefetch_read_varying_3",
-                 false, true),
-
-        GSBOInfo(
-            g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_nt_native" : "__prefetch_read_varying_nt",
-            g->target->hasVecPrefetch() ? "__pseudo_prefetch_read_varying_nt_native" : "__prefetch_read_varying_nt",
-            false, true),
-
-        GSBOInfo(
-            g->target->hasVecPrefetch() ? "__pseudo_prefetch_write_varying_1_native" : "__prefetch_write_varying_1",
-            g->target->hasVecPrefetch() ? "__pseudo_prefetch_write_varying_1_native" : "__prefetch_write_varying_1",
-            false, true),
-
-        GSBOInfo(
-            g->target->hasVecPrefetch() ? "__pseudo_prefetch_write_varying_2_native" : "__prefetch_write_varying_2",
-            g->target->hasVecPrefetch() ? "__pseudo_prefetch_write_varying_2_native" : "__prefetch_write_varying_2",
-            false, true),
-
-        GSBOInfo(
-            g->target->hasVecPrefetch() ? "__pseudo_prefetch_write_varying_3_native" : "__prefetch_write_varying_3",
-            g->target->hasVecPrefetch() ? "__pseudo_prefetch_write_varying_3_native" : "__prefetch_write_varying_3",
-            false, true),
+    static std::unordered_map<std::string, int> checksDecompositionOfArgs = {
+        {__pseudo_gather_base_offsets64_i8, 1},
+        {__pseudo_gather_base_offsets64_i16, 1},
+        {__pseudo_gather_base_offsets64_half, 1},
+        {__pseudo_gather_base_offsets64_i32, 1},
+        {__pseudo_gather_base_offsets64_float, 1},
+        {__pseudo_gather_base_offsets64_i64, 1},
+        {__pseudo_gather_base_offsets64_double, 1},
+        {__pseudo_gather_base_offsets32_i8, 1},
+        {__pseudo_gather_base_offsets32_i16, 1},
+        {__pseudo_gather_base_offsets32_half, 1},
+        {__pseudo_gather_base_offsets32_i32, 1},
+        {__pseudo_gather_base_offsets32_float, 1},
+        {__pseudo_gather_base_offsets32_i64, 1},
+        {__pseudo_gather_base_offsets32_double, 1},
+        {__pseudo_gather_factored_base_offsets64_i8, 1},
+        {__pseudo_gather_factored_base_offsets64_i16, 1},
+        {__pseudo_gather_factored_base_offsets64_half, 1},
+        {__pseudo_gather_factored_base_offsets64_i32, 1},
+        {__pseudo_gather_factored_base_offsets64_float, 1},
+        {__pseudo_gather_factored_base_offsets64_i64, 1},
+        {__pseudo_gather_factored_base_offsets64_double, 1},
+        {__pseudo_gather_factored_base_offsets32_i8, 1},
+        {__pseudo_gather_factored_base_offsets32_i16, 1},
+        {__pseudo_gather_factored_base_offsets32_half, 1},
+        {__pseudo_gather_factored_base_offsets32_i32, 1},
+        {__pseudo_gather_factored_base_offsets32_float, 1},
+        {__pseudo_gather_factored_base_offsets32_i64, 1},
+        {__pseudo_gather_factored_base_offsets32_double, 1},
+        {__pseudo_scatter_base_offsets64_i8, 1},
+        {__pseudo_scatter_base_offsets64_i16, 1},
+        {__pseudo_scatter_base_offsets64_half, 1},
+        {__pseudo_scatter_base_offsets64_i32, 1},
+        {__pseudo_scatter_base_offsets64_float, 1},
+        {__pseudo_scatter_base_offsets64_i64, 1},
+        {__pseudo_scatter_base_offsets64_double, 1},
+        {__pseudo_scatter_base_offsets32_i8, 1},
+        {__pseudo_scatter_base_offsets32_i16, 1},
+        {__pseudo_scatter_base_offsets32_half, 1},
+        {__pseudo_scatter_base_offsets32_i32, 1},
+        {__pseudo_scatter_base_offsets32_float, 1},
+        {__pseudo_scatter_base_offsets32_i64, 1},
+        {__pseudo_scatter_base_offsets32_double, 1},
+        {__pseudo_scatter_factored_base_offsets64_i8, 1},
+        {__pseudo_scatter_factored_base_offsets64_i16, 1},
+        {__pseudo_scatter_factored_base_offsets64_half, 1},
+        {__pseudo_scatter_factored_base_offsets64_i32, 1},
+        {__pseudo_scatter_factored_base_offsets64_float, 1},
+        {__pseudo_scatter_factored_base_offsets64_i64, 1},
+        {__pseudo_scatter_factored_base_offsets64_double, 1},
+        {__pseudo_scatter_factored_base_offsets32_i8, 1},
+        {__pseudo_scatter_factored_base_offsets32_i16, 1},
+        {__pseudo_scatter_factored_base_offsets32_half, 1},
+        {__pseudo_scatter_factored_base_offsets32_i32, 1},
+        {__pseudo_scatter_factored_base_offsets32_float, 1},
+        {__pseudo_scatter_factored_base_offsets32_i64, 1},
+        {__pseudo_scatter_factored_base_offsets32_double, 1},
+        {__pseudo_prefetch_read_varying_1_native, 1},
+        {__pseudo_prefetch_read_varying_2_native, 1},
+        {__pseudo_prefetch_read_varying_3_native, 1},
+        {__pseudo_prefetch_read_varying_nt_native, 1},
+        {__prefetch_read_varying_1, 1},
+        {__prefetch_read_varying_2, 1},
+        {__prefetch_read_varying_3, 1},
+        {__prefetch_read_varying_nt, 1},
+        {__pseudo_prefetch_write_varying_1_native, 1},
+        {__pseudo_prefetch_write_varying_2_native, 1},
+        {__pseudo_prefetch_write_varying_3_native, 1},
+        {__prefetch_write_varying_1, 1},
+        {__prefetch_write_varying_2, 1},
+        {__prefetch_write_varying_3, 1},
     };
 
-    int numGSFuncs = sizeof(gsFuncs) / sizeof(gsFuncs[0]);
-    for (int i = 0; i < numGSFuncs; ++i)
-        Assert(gsFuncs[i].baseOffsetsFunc != nullptr && gsFuncs[i].baseOffsets32Func != nullptr);
-
     llvm::Function *calledFunc = callInst->getCalledFunction();
     Assert(calledFunc != nullptr);
 
     // Is one of the gather/scatter functins that decompose into
     // base+offsets being called?
-    GSBOInfo *info = nullptr;
-    for (int i = 0; i < numGSFuncs; ++i)
-        if (calledFunc == gsFuncs[i].baseOffsetsFunc || calledFunc == gsFuncs[i].baseOffsets32Func) {
-            info = &gsFuncs[i];
-            break;
-        }
-    if (info == nullptr)
+    auto name = calledFunc->getName().str();
+    auto it = checksDecompositionOfArgs.find(name);
+    if (it == checksDecompositionOfArgs.end()) {
+        // it is not a call of function stored in checksDecompositionOfArgs
         return nullptr;
+    }
 
     // Grab the old variable offset
     llvm::Value *origVariableOffset = callInst->getArgOperand(1);
@@ -1322,6 +1084,55 @@ static llvm::Constant *lGetOffsetScaleVec(llvm::Value *offsetScale, llvm::Type *
     return llvm::ConstantVector::get(scales);
 }
 
+// alignment in bytes
+enum class Alignment : int {
+    A1 = 1,
+    A2 = 2,
+    A4 = 4,
+    A8 = 8,
+    A16 = 16,
+};
+
+struct GatherImpInfo {
+    GatherImpInfo(const char *lmName, const char *bmName, llvm::Type **st, Alignment a)
+        : load(lmName), blend(bmName), sType(st), alignment(a) {}
+    bool isFactored() const { return !g->target->useGather(); }
+    llvm::Function *loadMaskedFunc() const { return m->module->getFunction(load); }
+    llvm::Function *blendMaskedFunc() const { return m->module->getFunction(blend); }
+    llvm::Type *scalarType() const { return *sType; }
+    llvm::Type *baseType() const {
+        // Pseudo gather base pointer element type (the 1st argument of the intrinsic) is int8
+        // e.g. @__pseudo_gather_base_offsets32_i8(i8 *, i32, <WIDTH x i32>, <WIDTH x MASK>)
+        return LLVMTypes::Int8Type;
+    }
+    int align() const { return static_cast<int>(alignment); }
+
+  private:
+    const char *load;
+    const char *blend;
+    llvm::Type **sType;
+    const Alignment alignment;
+};
+
+struct ScatterImpInfo {
+    ScatterImpInfo(const char *msName, llvm::Type **vpt, Alignment a) : store(msName), vpType(vpt), alignment(a) {}
+    bool isFactored() const { return !g->target->useScatter(); }
+    llvm::Function *maskedStoreFunc() const { return m->module->getFunction(store); }
+    llvm::Type *vecPtrType() const { return *vpType; }
+    llvm::Type *baseType() const {
+        // Pseudo scatter base pointer element type (the 1st argument of the intrinsic) is int8
+        // e.g. @__pseudo_scatter_base_offsets32_i8(i8 * nocapture, i32, <WIDTH x i32>, <WIDTH x i8>, <WIDTH x
+        // MASK>)
+        return LLVMTypes::Int8Type;
+    }
+    int align() const { return static_cast<int>(alignment); }
+
+  private:
+    const char *store;
+    llvm::Type **vpType;
+    const Alignment alignment;
+};
+
 /** After earlier optimization passes have run, we are sometimes able to
     determine that gathers/scatters are actually accessing memory in a more
     regular fashion and then change the operation to something simpler and
@@ -1338,154 +1149,114 @@ static llvm::Constant *lGetOffsetScaleVec(llvm::Value *offsetScale, llvm::Type *
     vector loads with AVX, etc.
 */
 static llvm::Instruction *lGSToLoadStore(llvm::CallInst *callInst) {
-    struct GatherImpInfo {
-        GatherImpInfo(const char *pName, const char *lmName, const char *bmName, llvm::Type *st, int a)
-            : align(a), isFactored(!g->target->useGather()) {
-            pseudoFunc = m->module->getFunction(pName);
-            loadMaskedFunc = m->module->getFunction(lmName);
-            blendMaskedFunc = m->module->getFunction(bmName);
-            Assert(pseudoFunc != nullptr && loadMaskedFunc != nullptr);
-            scalarType = st;
-            // Pseudo gather base pointer element type (the 1st argument of the intrinsic) is int8
-            // e.g. @__pseudo_gather_base_offsets32_i8(i8 *, i32, <WIDTH x i32>, <WIDTH x MASK>)
-            baseType = LLVMTypes::Int8Type;
-        }
 
-        llvm::Function *pseudoFunc;
-        llvm::Function *loadMaskedFunc;
-        llvm::Function *blendMaskedFunc;
-        llvm::Type *scalarType;
-        llvm::Type *baseType;
-        const int align;
-        const bool isFactored;
+    static GatherImpInfo GII_i8 =
+        GatherImpInfo(__masked_load_i8, __masked_load_blend_i8, &LLVMTypes::Int8Type, Alignment::A1);
+    static GatherImpInfo GII_i16 =
+        GatherImpInfo(__masked_load_i16, __masked_load_blend_i16, &LLVMTypes::Int16Type, Alignment::A2);
+    static GatherImpInfo GII_half =
+        GatherImpInfo(__masked_load_half, __masked_load_blend_half, &LLVMTypes::Float16Type, Alignment::A2);
+    static GatherImpInfo GII_i32 =
+        GatherImpInfo(__masked_load_i32, __masked_load_blend_i32, &LLVMTypes::Int32Type, Alignment::A4);
+    static GatherImpInfo GII_float =
+        GatherImpInfo(__masked_load_float, __masked_load_blend_float, &LLVMTypes::FloatType, Alignment::A4);
+    static GatherImpInfo GII_i64 =
+        GatherImpInfo(__masked_load_i64, __masked_load_blend_i64, &LLVMTypes::Int64Type, Alignment::A8);
+    static GatherImpInfo GII_double =
+        GatherImpInfo(__masked_load_double, __masked_load_blend_double, &LLVMTypes::DoubleType, Alignment::A8);
+
+    static std::unordered_map<std::string, GatherImpInfo *> replGatherToLoad = {
+        {__pseudo_gather_base_offsets32_i8, &GII_i8},
+        {__pseudo_gather_factored_base_offsets32_i8, &GII_i8},
+        {__pseudo_gather_base_offsets32_i16, &GII_i16},
+        {__pseudo_gather_factored_base_offsets32_i16, &GII_i16},
+        {__pseudo_gather_base_offsets32_half, &GII_half},
+        {__pseudo_gather_factored_base_offsets32_half, &GII_half},
+        {__pseudo_gather_base_offsets32_i32, &GII_i32},
+        {__pseudo_gather_factored_base_offsets32_i32, &GII_i32},
+        {__pseudo_gather_base_offsets32_float, &GII_float},
+        {__pseudo_gather_factored_base_offsets32_float, &GII_float},
+        {__pseudo_gather_base_offsets32_i64, &GII_i64},
+        {__pseudo_gather_factored_base_offsets32_i64, &GII_i64},
+        {__pseudo_gather_base_offsets32_double, &GII_double},
+        {__pseudo_gather_factored_base_offsets32_double, &GII_double},
+        {__pseudo_gather_base_offsets64_i8, &GII_i8},
+        {__pseudo_gather_factored_base_offsets64_i8, &GII_i8},
+        {__pseudo_gather_base_offsets64_i16, &GII_i16},
+        {__pseudo_gather_factored_base_offsets64_i16, &GII_i16},
+        {__pseudo_gather_base_offsets64_half, &GII_half},
+        {__pseudo_gather_factored_base_offsets64_half, &GII_half},
+        {__pseudo_gather_base_offsets64_i32, &GII_i32},
+        {__pseudo_gather_factored_base_offsets64_i32, &GII_i32},
+        {__pseudo_gather_base_offsets64_float, &GII_float},
+        {__pseudo_gather_factored_base_offsets64_float, &GII_float},
+        {__pseudo_gather_base_offsets64_i64, &GII_i64},
+        {__pseudo_gather_factored_base_offsets64_i64, &GII_i64},
+        {__pseudo_gather_base_offsets64_double, &GII_double},
+        {__pseudo_gather_factored_base_offsets64_double, &GII_double},
     };
 
-    GatherImpInfo gInfo[] = {
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets32_i8"
-                                             : "__pseudo_gather_factored_base_offsets32_i8",
-                      "__masked_load_i8", "__masked_load_blend_i8", LLVMTypes::Int8Type, 1),
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets32_i16"
-                                             : "__pseudo_gather_factored_base_offsets32_i16",
-                      "__masked_load_i16", "__masked_load_blend_i16", LLVMTypes::Int16Type, 2),
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets32_half"
-                                             : "__pseudo_gather_factored_base_offsets32_half",
-                      "__masked_load_half", "__masked_load_blend_half", LLVMTypes::Float16Type, 2),
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets32_i32"
-                                             : "__pseudo_gather_factored_base_offsets32_i32",
-                      "__masked_load_i32", "__masked_load_blend_i32", LLVMTypes::Int32Type, 4),
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets32_float"
-                                             : "__pseudo_gather_factored_base_offsets32_float",
-                      "__masked_load_float", "__masked_load_blend_float", LLVMTypes::FloatType, 4),
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets32_i64"
-                                             : "__pseudo_gather_factored_base_offsets32_i64",
-                      "__masked_load_i64", "__masked_load_blend_i64", LLVMTypes::Int64Type, 8),
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets32_double"
-                                             : "__pseudo_gather_factored_base_offsets32_double",
-                      "__masked_load_double", "__masked_load_blend_double", LLVMTypes::DoubleType, 8),
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets64_i8"
-                                             : "__pseudo_gather_factored_base_offsets64_i8",
-                      "__masked_load_i8", "__masked_load_blend_i8", LLVMTypes::Int8Type, 1),
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets64_i16"
-                                             : "__pseudo_gather_factored_base_offsets64_i16",
-                      "__masked_load_i16", "__masked_load_blend_i16", LLVMTypes::Int16Type, 2),
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets64_half"
-                                             : "__pseudo_gather_factored_base_offsets64_half",
-                      "__masked_load_half", "__masked_load_blend_half", LLVMTypes::Float16Type, 2),
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets64_i32"
-                                             : "__pseudo_gather_factored_base_offsets64_i32",
-                      "__masked_load_i32", "__masked_load_blend_i32", LLVMTypes::Int32Type, 4),
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets64_float"
-                                             : "__pseudo_gather_factored_base_offsets64_float",
-                      "__masked_load_float", "__masked_load_blend_float", LLVMTypes::FloatType, 4),
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets64_i64"
-                                             : "__pseudo_gather_factored_base_offsets64_i64",
-                      "__masked_load_i64", "__masked_load_blend_i64", LLVMTypes::Int64Type, 8),
-        GatherImpInfo(g->target->useGather() ? "__pseudo_gather_base_offsets64_double"
-                                             : "__pseudo_gather_factored_base_offsets64_double",
-                      "__masked_load_double", "__masked_load_blend_double", LLVMTypes::DoubleType, 8),
+    static ScatterImpInfo SII_i8 =
+        ScatterImpInfo(__pseudo_masked_store_i8, &LLVMTypes::Int8VectorPointerType, Alignment::A1);
+    static ScatterImpInfo SII_i16 =
+        ScatterImpInfo(__pseudo_masked_store_i16, &LLVMTypes::Int16VectorPointerType, Alignment::A2);
+    static ScatterImpInfo SII_half =
+        ScatterImpInfo(__pseudo_masked_store_half, &LLVMTypes::Float16VectorPointerType, Alignment::A2);
+    static ScatterImpInfo SII_i32 =
+        ScatterImpInfo(__pseudo_masked_store_i32, &LLVMTypes::Int32VectorPointerType, Alignment::A4);
+    static ScatterImpInfo SII_float =
+        ScatterImpInfo(__pseudo_masked_store_float, &LLVMTypes::FloatVectorPointerType, Alignment::A4);
+    static ScatterImpInfo SII_i64 =
+        ScatterImpInfo(__pseudo_masked_store_i64, &LLVMTypes::Int64VectorPointerType, Alignment::A8);
+    static ScatterImpInfo SII_double =
+        ScatterImpInfo(__pseudo_masked_store_double, &LLVMTypes::DoubleVectorPointerType, Alignment::A8);
+
+    static std::unordered_map<std::string, ScatterImpInfo *> replScatterToStore = {
+        {__pseudo_scatter_base_offsets32_i8, &SII_i8},
+        {__pseudo_scatter_factored_base_offsets32_i8, &SII_i8},
+        {__pseudo_scatter_base_offsets32_i16, &SII_i16},
+        {__pseudo_scatter_factored_base_offsets32_i16, &SII_i16},
+        {__pseudo_scatter_base_offsets32_half, &SII_half},
+        {__pseudo_scatter_factored_base_offsets32_half, &SII_half},
+        {__pseudo_scatter_base_offsets32_i32, &SII_i32},
+        {__pseudo_scatter_factored_base_offsets32_i32, &SII_i32},
+        {__pseudo_scatter_base_offsets32_float, &SII_float},
+        {__pseudo_scatter_factored_base_offsets32_float, &SII_float},
+        {__pseudo_scatter_base_offsets32_i64, &SII_i64},
+        {__pseudo_scatter_factored_base_offsets32_i64, &SII_i64},
+        {__pseudo_scatter_base_offsets32_double, &SII_double},
+        {__pseudo_scatter_factored_base_offsets32_double, &SII_double},
+        {__pseudo_scatter_base_offsets64_i8, &SII_i8},
+        {__pseudo_scatter_factored_base_offsets64_i8, &SII_i8},
+        {__pseudo_scatter_base_offsets64_i16, &SII_i16},
+        {__pseudo_scatter_factored_base_offsets64_i16, &SII_i16},
+        {__pseudo_scatter_base_offsets64_half, &SII_half},
+        {__pseudo_scatter_factored_base_offsets64_half, &SII_half},
+        {__pseudo_scatter_base_offsets64_i32, &SII_i32},
+        {__pseudo_scatter_factored_base_offsets64_i32, &SII_i32},
+        {__pseudo_scatter_base_offsets64_float, &SII_float},
+        {__pseudo_scatter_factored_base_offsets64_float, &SII_float},
+        {__pseudo_scatter_base_offsets64_i64, &SII_i64},
+        {__pseudo_scatter_factored_base_offsets64_i64, &SII_i64},
+        {__pseudo_scatter_base_offsets64_double, &SII_double},
+        {__pseudo_scatter_factored_base_offsets64_double, &SII_double},
     };
 
-    struct ScatterImpInfo {
-        ScatterImpInfo(const char *pName, const char *msName, llvm::Type *vpt, int a)
-            : align(a), isFactored(!g->target->useScatter()) {
-            pseudoFunc = m->module->getFunction(pName);
-            maskedStoreFunc = m->module->getFunction(msName);
-            vecPtrType = vpt;
-            // Pseudo scatter base pointer element type (the 1st argument of the intrinsic) is int8
-            // e.g. @__pseudo_scatter_base_offsets32_i8(i8 * nocapture, i32, <WIDTH x i32>, <WIDTH x i8>, <WIDTH x
-            // MASK>)
-            baseType = LLVMTypes::Int8Type;
-            Assert(pseudoFunc != nullptr && maskedStoreFunc != nullptr);
-        }
-        llvm::Function *pseudoFunc;
-        llvm::Function *maskedStoreFunc;
-        llvm::Type *vecPtrType;
-        llvm::Type *baseType;
-        const int align;
-        const bool isFactored;
-    };
-
-    ScatterImpInfo sInfo[] = {
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i8"
-                                               : "__pseudo_scatter_factored_base_offsets32_i8",
-                       "__pseudo_masked_store_i8", LLVMTypes::Int8VectorPointerType, 1),
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i16"
-                                               : "__pseudo_scatter_factored_base_offsets32_i16",
-                       "__pseudo_masked_store_i16", LLVMTypes::Int16VectorPointerType, 2),
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets32_half"
-                                               : "__pseudo_scatter_factored_base_offsets32_half",
-                       "__pseudo_masked_store_half", LLVMTypes::Float16VectorPointerType, 2),
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i32"
-                                               : "__pseudo_scatter_factored_base_offsets32_i32",
-                       "__pseudo_masked_store_i32", LLVMTypes::Int32VectorPointerType, 4),
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets32_float"
-                                               : "__pseudo_scatter_factored_base_offsets32_float",
-                       "__pseudo_masked_store_float", LLVMTypes::FloatVectorPointerType, 4),
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets32_i64"
-                                               : "__pseudo_scatter_factored_base_offsets32_i64",
-                       "__pseudo_masked_store_i64", LLVMTypes::Int64VectorPointerType, 8),
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets32_double"
-                                               : "__pseudo_scatter_factored_base_offsets32_double",
-                       "__pseudo_masked_store_double", LLVMTypes::DoubleVectorPointerType, 8),
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_i8"
-                                               : "__pseudo_scatter_factored_base_offsets64_i8",
-                       "__pseudo_masked_store_i8", LLVMTypes::Int8VectorPointerType, 1),
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_i16"
-                                               : "__pseudo_scatter_factored_base_offsets64_i16",
-                       "__pseudo_masked_store_i16", LLVMTypes::Int16VectorPointerType, 2),
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_half"
-                                               : "__pseudo_scatter_factored_base_offsets64_half",
-                       "__pseudo_masked_store_half", LLVMTypes::Float16VectorPointerType, 2),
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_i32"
-                                               : "__pseudo_scatter_factored_base_offsets64_i32",
-                       "__pseudo_masked_store_i32", LLVMTypes::Int32VectorPointerType, 4),
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_float"
-                                               : "__pseudo_scatter_factored_base_offsets64_float",
-                       "__pseudo_masked_store_float", LLVMTypes::FloatVectorPointerType, 4),
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_i64"
-                                               : "__pseudo_scatter_factored_base_offsets64_i64",
-                       "__pseudo_masked_store_i64", LLVMTypes::Int64VectorPointerType, 8),
-        ScatterImpInfo(g->target->useScatter() ? "__pseudo_scatter_base_offsets64_double"
-                                               : "__pseudo_scatter_factored_base_offsets64_double",
-                       "__pseudo_masked_store_double", LLVMTypes::DoubleVectorPointerType, 8),
-    };
-
-    llvm::Function *calledFunc = callInst->getCalledFunction();
-
     GatherImpInfo *gatherInfo = nullptr;
     ScatterImpInfo *scatterInfo = nullptr;
-    for (unsigned int i = 0; i < sizeof(gInfo) / sizeof(gInfo[0]); ++i) {
-        if (gInfo[i].pseudoFunc != nullptr && calledFunc == gInfo[i].pseudoFunc) {
-            gatherInfo = &gInfo[i];
-            break;
-        }
+    llvm::Function *calledFunc = callInst->getCalledFunction();
+    auto name = calledFunc->getName().str();
+
+    auto itG = replGatherToLoad.find(name);
+    if (itG != replGatherToLoad.end()) {
+        gatherInfo = itG->second;
     }
-    for (unsigned int i = 0; i < sizeof(sInfo) / sizeof(sInfo[0]); ++i) {
-        if (sInfo[i].pseudoFunc != nullptr && calledFunc == sInfo[i].pseudoFunc) {
-            scatterInfo = &sInfo[i];
-            break;
-        }
+
+    auto itS = replScatterToStore.find(name);
+    if (itS != replScatterToStore.end()) {
+        scatterInfo = itS->second;
     }
+
     if (gatherInfo == nullptr && scatterInfo == nullptr)
         return nullptr;
 
@@ -1496,7 +1267,7 @@ static llvm::Instruction *lGSToLoadStore(llvm::CallInst *callInst) {
     llvm::Value *fullOffsets = nullptr;
     llvm::Value *storeValue = nullptr;
     llvm::Value *mask = nullptr;
-    if ((gatherInfo != nullptr && gatherInfo->isFactored) || (scatterInfo != nullptr && scatterInfo->isFactored)) {
+    if ((gatherInfo != nullptr && gatherInfo->isFactored()) || (scatterInfo != nullptr && scatterInfo->isFactored())) {
         llvm::Value *varyingOffsets = callInst->getArgOperand(1);
         llvm::Value *offsetScale = callInst->getArgOperand(2);
         llvm::Value *constOffsets = callInst->getArgOperand(3);
@@ -1526,7 +1297,7 @@ static llvm::Instruction *lGSToLoadStore(llvm::CallInst *callInst) {
 
     Debug(SourcePos(), "GSToLoadStore: %s.", fullOffsets->getName().str().c_str());
     llvm::Type *scalarType =
-        (gatherInfo != nullptr) ? gatherInfo->scalarType : scatterInfo->vecPtrType->getScalarType();
+        (gatherInfo != nullptr) ? gatherInfo->scalarType() : scatterInfo->vecPtrType()->getScalarType();
 
     if (LLVMVectorValuesAllEqual(fullOffsets)) {
         // If all the offsets are equal, then compute the single
@@ -1537,7 +1308,7 @@ static llvm::Instruction *lGSToLoadStore(llvm::CallInst *callInst) {
             // handled as a scalar load and broadcast across the lanes.
             Debug(pos, "Transformed gather to scalar load and broadcast!");
             llvm::Value *ptr;
-            ptr = lComputeCommonPointer(base, gatherInfo->baseType, fullOffsets, callInst);
+            ptr = lComputeCommonPointer(base, gatherInfo->baseType(), fullOffsets, callInst);
             ptr = new llvm::BitCastInst(ptr, llvm::PointerType::get(scalarType, 0), base->getName(), callInst);
 
             LLVMCopyMetadata(ptr, callInst);
@@ -1580,7 +1351,7 @@ static llvm::Instruction *lGSToLoadStore(llvm::CallInst *callInst) {
             return nullptr;
         }
     } else {
-        int step = gatherInfo ? gatherInfo->align : scatterInfo->align;
+        int step = gatherInfo ? gatherInfo->align() : scatterInfo->align();
         if (step > 0 && LLVMVectorIsLinear(fullOffsets, step)) {
             // We have a linear sequence of memory locations being accessed
             // starting with the location given by the offset from
@@ -1590,20 +1361,20 @@ static llvm::Instruction *lGSToLoadStore(llvm::CallInst *callInst) {
             llvm::Instruction *newCall = nullptr;
 
             if (gatherInfo != nullptr) {
-                ptr = lComputeCommonPointer(base, gatherInfo->baseType, fullOffsets, callInst);
+                ptr = lComputeCommonPointer(base, gatherInfo->baseType(), fullOffsets, callInst);
                 LLVMCopyMetadata(ptr, callInst);
                 Debug(pos, "Transformed gather to unaligned vector load!");
                 bool doBlendLoad = false;
 #ifdef ISPC_XE_ENABLED
                 doBlendLoad = g->target->isXeTarget() && g->opt.enableXeUnsafeMaskedLoad;
 #endif
-                newCall = LLVMCallInst(doBlendLoad ? gatherInfo->blendMaskedFunc : gatherInfo->loadMaskedFunc, ptr,
+                newCall = LLVMCallInst(doBlendLoad ? gatherInfo->blendMaskedFunc() : gatherInfo->loadMaskedFunc(), ptr,
                                        mask, llvm::Twine(ptr->getName()) + "_masked_load");
             } else {
                 Debug(pos, "Transformed scatter to unaligned vector store!");
-                ptr = lComputeCommonPointer(base, scatterInfo->baseType, fullOffsets, callInst);
-                ptr = new llvm::BitCastInst(ptr, scatterInfo->vecPtrType, "ptrcast", callInst);
-                newCall = LLVMCallInst(scatterInfo->maskedStoreFunc, ptr, storeValue, mask, "");
+                ptr = lComputeCommonPointer(base, scatterInfo->baseType(), fullOffsets, callInst);
+                ptr = new llvm::BitCastInst(ptr, scatterInfo->vecPtrType(), "ptrcast", callInst);
+                newCall = LLVMCallInst(scatterInfo->maskedStoreFunc(), ptr, storeValue, mask, "");
             }
             LLVMCopyMetadata(newCall, callInst);
             llvm::ReplaceInstWithInst(callInst, newCall);
@@ -1616,114 +1387,6 @@ static llvm::Instruction *lGSToLoadStore(llvm::CallInst *callInst) {
 ///////////////////////////////////////////////////////////////////////////
 // MaskedStoreOptPass
 
-#ifdef ISPC_XE_ENABLED
-static llvm::Function *lXeMaskedInst(llvm::Instruction *inst, bool isStore, llvm::Type *type) {
-    std::string maskedFuncName;
-    if (isStore) {
-        maskedFuncName = "masked_store_";
-    } else {
-        maskedFuncName = "masked_load_";
-    }
-    if (type == LLVMTypes::Int8Type)
-        maskedFuncName += "i8";
-    else if (type == LLVMTypes::Int16Type)
-        maskedFuncName += "i16";
-    else if (type == LLVMTypes::Int32Type)
-        maskedFuncName += "i32";
-    else if (type == LLVMTypes::Int64Type)
-        maskedFuncName += "i64";
-    else if (type == LLVMTypes::Float16Type)
-        maskedFuncName += "half";
-    else if (type == LLVMTypes::FloatType)
-        maskedFuncName += "float";
-    else if (type == LLVMTypes::DoubleType)
-        maskedFuncName += "double";
-
-    llvm::CallInst *callInst = llvm::dyn_cast<llvm::CallInst>(inst);
-    if (callInst != nullptr && callInst->getCalledFunction() != nullptr &&
-        callInst->getCalledFunction()->getName().contains(maskedFuncName)) {
-        return nullptr;
-    }
-    return m->module->getFunction("__" + maskedFuncName);
-}
-
-static llvm::CallInst *lXeStoreInst(llvm::Value *val, llvm::Value *ptr, llvm::Instruction *inst) {
-    Assert(g->target->isXeTarget());
-    Assert(llvm::isa<llvm::FixedVectorType>(val->getType()));
-    llvm::FixedVectorType *valVecType = llvm::dyn_cast<llvm::FixedVectorType>(val->getType());
-    Assert(llvm::isPowerOf2_32(valVecType->getNumElements()));
-
-    // The data write of svm store must have a size that is a power of two from 16 to 128
-    // bytes. However for int8 type and simd width = 8, the data write size is 8.
-    // So we use masked store function here instead of svm store which process int8 type
-    // correctly.
-    bool isMaskedStoreRequired = false;
-    if (valVecType->getPrimitiveSizeInBits() / 8 < 16) {
-        Assert(valVecType->getScalarType() == LLVMTypes::Int8Type && g->target->getVectorWidth() == 8);
-        isMaskedStoreRequired = true;
-    } else if (valVecType->getPrimitiveSizeInBits() / 8 > 8 * OWORD) {
-        // The data write of svm store must be less than 8 * OWORD. However for
-        // double or int64 types for simd32 targets it is bigger so use masked_store implementation
-        Assert((valVecType->getScalarType() == LLVMTypes::Int64Type ||
-                valVecType->getScalarType() == LLVMTypes::DoubleType) &&
-               g->target->getVectorWidth() == 32);
-        isMaskedStoreRequired = true;
-    }
-    if (isMaskedStoreRequired) {
-        if (llvm::Function *maskedFunc = lXeMaskedInst(inst, true, valVecType->getScalarType())) {
-            return llvm::dyn_cast<llvm::CallInst>(LLVMCallInst(maskedFunc, ptr, val, LLVMMaskAllOn, ""));
-        } else {
-            return nullptr;
-        }
-    }
-
-    llvm::Instruction *svm_st_zext = new llvm::PtrToIntInst(ptr, LLVMTypes::Int64Type, "svm_st_ptrtoint", inst);
-
-    llvm::Type *argTypes[] = {svm_st_zext->getType(), val->getType()};
-    auto Fn = llvm::GenXIntrinsic::getGenXDeclaration(m->module, llvm::GenXIntrinsic::genx_svm_block_st, argTypes);
-    return llvm::CallInst::Create(Fn, {svm_st_zext, val}, inst->getName());
-}
-
-static llvm::CallInst *lXeLoadInst(llvm::Value *ptr, llvm::Type *retType, llvm::Instruction *inst) {
-    Assert(llvm::isa<llvm::FixedVectorType>(retType));
-    llvm::FixedVectorType *retVecType = llvm::dyn_cast<llvm::FixedVectorType>(retType);
-    Assert(llvm::isPowerOf2_32(retVecType->getNumElements()));
-    Assert(retVecType->getPrimitiveSizeInBits());
-    // The data read of svm load must have a size that is a power of two from 16 to 128
-    // bytes. However for int8 type and simd width = 8, the data read size is 8.
-    // So we use masked load function here instead of svm load which process int8 type
-    // correctly.
-    bool isMaskedLoadRequired = false;
-    if (retVecType->getPrimitiveSizeInBits() / 8 < 16) {
-        Assert(retVecType->getScalarType() == LLVMTypes::Int8Type && g->target->getVectorWidth() == 8);
-        isMaskedLoadRequired = true;
-    } else if (retVecType->getPrimitiveSizeInBits() / 8 > 8 * OWORD) {
-        // The data write of svm store must be less than 8 * OWORD. However for
-        // double or int64 types for simd32 targets it is bigger so use masked_store implementation
-        Assert((retVecType->getScalarType() == LLVMTypes::Int64Type ||
-                retVecType->getScalarType() == LLVMTypes::DoubleType) &&
-               g->target->getVectorWidth() == 32);
-        isMaskedLoadRequired = true;
-    }
-
-    if (isMaskedLoadRequired) {
-        if (llvm::Function *maskedFunc = lXeMaskedInst(inst, false, retVecType->getScalarType())) {
-            // <WIDTH x $1> @__masked_load_i8(i8 *, <WIDTH x MASK> %mask)
-            // Cast pointer to i8*
-            ptr = new llvm::BitCastInst(ptr, LLVMTypes::Int8PointerType, "ptr_to_i8", inst);
-            return llvm::dyn_cast<llvm::CallInst>(LLVMCallInst(maskedFunc, ptr, LLVMMaskAllOn, "_masked_load_"));
-        } else {
-            return nullptr;
-        }
-    }
-    llvm::Value *svm_ld_ptrtoint = new llvm::PtrToIntInst(ptr, LLVMTypes::Int64Type, "svm_ld_ptrtoint", inst);
-
-    auto Fn = llvm::GenXIntrinsic::getGenXDeclaration(m->module, llvm::GenXIntrinsic::genx_svm_block_ld_unaligned,
-                                                      {retType, svm_ld_ptrtoint->getType()});
-
-    return llvm::CallInst::Create(Fn, svm_ld_ptrtoint, inst->getName());
-}
-#endif
 /** Masked stores are generally more complex than regular stores; for
     example, they require multiple instructions to simulate under SSE.
     This optimization detects cases where masked stores can be replaced
@@ -1731,53 +1394,43 @@ static llvm::CallInst *lXeLoadInst(llvm::Value *ptr, llvm::Type *retType, llvm::
     mask and an 'all off' mask, respectively.
 */
 static llvm::Value *lImproveMaskedStore(llvm::CallInst *callInst) {
-    struct MSInfo {
-        MSInfo(const char *name, const int a) : align(a) {
-            func = m->module->getFunction(name);
-            Assert(func != nullptr);
-        }
-        llvm::Function *func;
-        const int align;
+    static std::unordered_map<std::string, Alignment> maskedStoreAlign = {
+        {__pseudo_masked_store_i8, Alignment::A1},
+        {__pseudo_masked_store_i16, Alignment::A2},
+        {__pseudo_masked_store_half, Alignment::A2},
+        {__pseudo_masked_store_i32, Alignment::A4},
+        {__pseudo_masked_store_float, Alignment::A4},
+        {__pseudo_masked_store_i64, Alignment::A8},
+        {__pseudo_masked_store_double, Alignment::A8},
+        {__masked_store_blend_i8, Alignment::A1},
+        {__masked_store_blend_i16, Alignment::A2},
+        {__masked_store_blend_half, Alignment::A2},
+        {__masked_store_blend_i32, Alignment::A4},
+        {__masked_store_blend_float, Alignment::A4},
+        {__masked_store_blend_i64, Alignment::A8},
+        {__masked_store_blend_double, Alignment::A8},
+        {__masked_store_i8, Alignment::A1},
+        {__masked_store_i16, Alignment::A2},
+        {__masked_store_half, Alignment::A2},
+        {__masked_store_i32, Alignment::A4},
+        {__masked_store_float, Alignment::A4},
+        {__masked_store_i64, Alignment::A8},
+        {__masked_store_double, Alignment::A8},
     };
 
-    MSInfo msInfo[] = {MSInfo("__pseudo_masked_store_i8", 1),
-                       MSInfo("__pseudo_masked_store_i16", 2),
-                       MSInfo("__pseudo_masked_store_half", 2),
-                       MSInfo("__pseudo_masked_store_i32", 4),
-                       MSInfo("__pseudo_masked_store_float", 4),
-                       MSInfo("__pseudo_masked_store_i64", 8),
-                       MSInfo("__pseudo_masked_store_double", 8),
-                       MSInfo("__masked_store_blend_i8", 1),
-                       MSInfo("__masked_store_blend_i16", 2),
-                       MSInfo("__masked_store_blend_half", 2),
-                       MSInfo("__masked_store_blend_i32", 4),
-                       MSInfo("__masked_store_blend_float", 4),
-                       MSInfo("__masked_store_blend_i64", 8),
-                       MSInfo("__masked_store_blend_double", 8),
-                       MSInfo("__masked_store_i8", 1),
-                       MSInfo("__masked_store_i16", 2),
-                       MSInfo("__masked_store_half", 2),
-                       MSInfo("__masked_store_i32", 4),
-                       MSInfo("__masked_store_float", 4),
-                       MSInfo("__masked_store_i64", 8),
-                       MSInfo("__masked_store_double", 8)};
     llvm::Function *called = callInst->getCalledFunction();
-
-    int nMSFuncs = sizeof(msInfo) / sizeof(msInfo[0]);
-    MSInfo *info = nullptr;
-    for (int i = 0; i < nMSFuncs; ++i) {
-        if (msInfo[i].func != nullptr && called == msInfo[i].func) {
-            info = &msInfo[i];
-            break;
-        }
-    }
-    if (info == nullptr)
+    auto name = called->getName().str();
+    auto it = maskedStoreAlign.find(name);
+    if (it == maskedStoreAlign.end()) {
+        // it is not a call of function stored in maskedStoreAlign
         return nullptr;
+    }
 
     // Got one; grab the operands
     llvm::Value *lvalue = callInst->getArgOperand(0);
     llvm::Value *rvalue = callInst->getArgOperand(1);
     llvm::Value *mask = callInst->getArgOperand(2);
+    int align = static_cast<int>(it->second);
 
     MaskStatus maskStatus = GetMaskStatusFromValue(mask);
     if (maskStatus == MaskStatus::all_off) {
@@ -1797,8 +1450,7 @@ static llvm::Value *lImproveMaskedStore(llvm::CallInst *callInst) {
         LLVMCopyMetadata(lvalue, callInst);
         store = new llvm::StoreInst(
             rvalue, lvalue, false /* not volatile */,
-            llvm::MaybeAlign(g->opt.forceAlignedMemory ? g->target->getNativeVectorAlignment() : info->align)
-                .valueOrOne());
+            llvm::MaybeAlign(g->opt.forceAlignedMemory ? g->target->getNativeVectorAlignment() : align).valueOrOne());
 
         if (store != nullptr) {
             LLVMCopyMetadata(store, callInst);
@@ -1824,51 +1476,24 @@ static llvm::Value *lImproveMaskedStore(llvm::CallInst *callInst) {
 }
 
 static llvm::Value *lImproveMaskedLoad(llvm::CallInst *callInst, llvm::BasicBlock::iterator iter) {
-    struct MLInfo {
-        MLInfo(const char *name, const int a) : align(a) {
-            func = m->module->getFunction(name);
-            Assert(func != nullptr);
-        }
-        llvm::Function *func;
-        const int align;
+    static std::unordered_map<std::string, Alignment> maskedLoadAlign = {
+        {__masked_load_i8, Alignment::A1},        {__masked_load_i16, Alignment::A2},
+        {__masked_load_half, Alignment::A2},      {__masked_load_i32, Alignment::A4},
+        {__masked_load_float, Alignment::A4},     {__masked_load_i64, Alignment::A8},
+        {__masked_load_double, Alignment::A8},    {__masked_load_blend_i8, Alignment::A1},
+        {__masked_load_blend_i16, Alignment::A2}, {__masked_load_blend_half, Alignment::A2},
+        {__masked_load_blend_i32, Alignment::A4}, {__masked_load_blend_float, Alignment::A4},
+        {__masked_load_blend_i64, Alignment::A8}, {__masked_load_blend_double, Alignment::A8},
     };
 
     llvm::Function *called = callInst->getCalledFunction();
-    // TODO: we should use dynamic data structure for MLInfo and fill
-    // it differently for Xe and CPU targets. It will also help
-    // to avoid declaration of Xe intrinsics for CPU targets.
-    // It should be changed seamlessly here and in all similar places in this file.
-    MLInfo mlInfo[] = {MLInfo("__masked_load_i8", 1),    MLInfo("__masked_load_i16", 2),
-                       MLInfo("__masked_load_half", 2),  MLInfo("__masked_load_i32", 4),
-                       MLInfo("__masked_load_float", 4), MLInfo("__masked_load_i64", 8),
-                       MLInfo("__masked_load_double", 8)};
-    MLInfo xeInfo[] = {MLInfo("__masked_load_i8", 1),        MLInfo("__masked_load_i16", 2),
-                       MLInfo("__masked_load_half", 2),      MLInfo("__masked_load_i32", 4),
-                       MLInfo("__masked_load_float", 4),     MLInfo("__masked_load_i64", 8),
-                       MLInfo("__masked_load_double", 8),    MLInfo("__masked_load_blend_i8", 1),
-                       MLInfo("__masked_load_blend_i16", 2), MLInfo("__masked_load_blend_half", 2),
-                       MLInfo("__masked_load_blend_i32", 4), MLInfo("__masked_load_blend_float", 4),
-                       MLInfo("__masked_load_blend_i64", 8), MLInfo("__masked_load_blend_double", 8)};
-    MLInfo *info = nullptr;
-    if (g->target->isXeTarget()) {
-        int nFuncs = sizeof(xeInfo) / sizeof(xeInfo[0]);
-        for (int i = 0; i < nFuncs; ++i) {
-            if (xeInfo[i].func != nullptr && called == xeInfo[i].func) {
-                info = &xeInfo[i];
-                break;
-            }
-        }
-    } else {
-        int nFuncs = sizeof(mlInfo) / sizeof(mlInfo[0]);
-        for (int i = 0; i < nFuncs; ++i) {
-            if (mlInfo[i].func != nullptr && called == mlInfo[i].func) {
-                info = &mlInfo[i];
-                break;
-            }
-        }
-    }
-    if (info == nullptr)
+    auto name = called->getName().str();
+    auto it = maskedLoadAlign.find(name);
+    if (it == maskedLoadAlign.end()) {
+        // it is not a call of function stored in maskedLoadAlign
         return nullptr;
+    }
+    int align = static_cast<int>(it->second);
 
     // Got one; grab the operands
     llvm::Value *ptr = callInst->getArgOperand(0);
@@ -1888,8 +1513,7 @@ static llvm::Value *lImproveMaskedLoad(llvm::CallInst *callInst, llvm::BasicBloc
         Assert(llvm::isa<llvm::PointerType>(ptr->getType()));
         load = new llvm::LoadInst(
             callInst->getType(), ptr, callInst->getName(), false /* not volatile */,
-            llvm::MaybeAlign(g->opt.forceAlignedMemory ? g->target->getNativeVectorAlignment() : info->align)
-                .valueOrOne(),
+            llvm::MaybeAlign(g->opt.forceAlignedMemory ? g->target->getNativeVectorAlignment() : align).valueOrOne(),
             (llvm::Instruction *)NULL);
 
         if (load != nullptr) {
@@ -1948,6 +1572,14 @@ bool ImproveMemoryOpsPass::improveMemoryOps(llvm::BasicBlock &bb) {
 llvm::PreservedAnalyses ImproveMemoryOpsPass::run(llvm::Function &F, llvm::FunctionAnalysisManager &FAM) {
     llvm::TimeTraceScope FuncScope("ImproveMemoryOpsPass::run", F.getName());
     bool modifiedAny = false;
+
+    // Skip __keep_funcs_live because it breaks some assumptions used here.
+    // For example, lGSToLoadStore assumes that factored pseudo calls are
+    // generated only when gathers are not used (useGather == false).
+    if (F.getName().equals(__keep_funcs_live)) {
+        return llvm::PreservedAnalyses::all();
+    }
+
     for (llvm::BasicBlock &BB : F) {
         modifiedAny |= improveMemoryOps(BB);
     }
diff --git a/src/opt/InstructionSimplify.cpp b/src/opt/InstructionSimplify.cpp
index 17bf78d20a..08a8c77457 100644
--- a/src/opt/InstructionSimplify.cpp
+++ b/src/opt/InstructionSimplify.cpp
@@ -1,10 +1,11 @@
 /*
-  Copyright (c) 2022-2023, Intel Corporation
+  Copyright (c) 2022-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
 
 #include "InstructionSimplify.h"
+#include "builtins-decl.h"
 
 namespace ispc {
 
@@ -87,7 +88,7 @@ static bool lSimplifyCall(llvm::CallInst *callInst, llvm::BasicBlock::iterator i
 
     // Turn a __movmsk call with a compile-time constant vector into the
     // equivalent scalar value.
-    if (calledFunc == nullptr || calledFunc != m->module->getFunction("__movmsk"))
+    if (calledFunc == nullptr || calledFunc != m->module->getFunction(builtin::__movmsk))
         return false;
 
     uint64_t mask;
diff --git a/src/opt/IntrinsicsOptPass.cpp b/src/opt/IntrinsicsOptPass.cpp
index 0ac2ab71f4..eec8d178b7 100644
--- a/src/opt/IntrinsicsOptPass.cpp
+++ b/src/opt/IntrinsicsOptPass.cpp
@@ -1,10 +1,11 @@
 /*
-  Copyright (c) 2022-2023, Intel Corporation
+  Copyright (c) 2022-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
 
 #include "IntrinsicsOptPass.h"
+#include "builtins-decl.h"
 
 namespace ispc {
 
@@ -25,8 +26,8 @@ bool IntrinsicsOpt::optimizeIntrinsics(llvm::BasicBlock &bb) {
             m->module->getFunction(llvm::Intrinsic::getName(llvm::Intrinsic::x86_sse_movmsk_ps))) {
         maskInstructions.push_back(sseFloatMovmsk);
     }
-    if (llvm::Function *__movmsk = m->module->getFunction("__movmsk")) {
-        maskInstructions.push_back(__movmsk);
+    if (llvm::Function *movmsk = m->module->getFunction(builtin::__movmsk)) {
+        maskInstructions.push_back(movmsk);
     }
     if (llvm::Function *avxFloatMovmsk =
             m->module->getFunction(llvm::Intrinsic::getName(llvm::Intrinsic::x86_avx_movmsk_ps_256))) {
diff --git a/src/opt/IsCompileTimeConstant.cpp b/src/opt/IsCompileTimeConstant.cpp
index e74e4f82f6..492de20aee 100644
--- a/src/opt/IsCompileTimeConstant.cpp
+++ b/src/opt/IsCompileTimeConstant.cpp
@@ -1,19 +1,20 @@
 /*
-  Copyright (c) 2022-2023, Intel Corporation
+  Copyright (c) 2022-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
 
 #include "IsCompileTimeConstant.h"
+#include "builtins-decl.h"
 
 namespace ispc {
 
 bool IsCompileTimeConstantPass::lowerCompileTimeConstant(llvm::BasicBlock &bb) {
     DEBUG_START_BB("IsCompileTimeConstantPass");
 
-    llvm::Function *funcs[] = {m->module->getFunction("__is_compile_time_constant_mask"),
-                               m->module->getFunction("__is_compile_time_constant_uniform_int32"),
-                               m->module->getFunction("__is_compile_time_constant_varying_int32")};
+    llvm::Function *funcs[] = {m->module->getFunction(builtin::__is_compile_time_constant_mask),
+                               m->module->getFunction(builtin::__is_compile_time_constant_uniform_int32),
+                               m->module->getFunction(builtin::__is_compile_time_constant_varying_int32)};
 
     bool modifiedAny = false;
 
diff --git a/src/opt/MakeInternalFuncsStatic.cpp b/src/opt/MakeInternalFuncsStatic.cpp
index c86e1d042a..34e39e34a5 100644
--- a/src/opt/MakeInternalFuncsStatic.cpp
+++ b/src/opt/MakeInternalFuncsStatic.cpp
@@ -1,202 +1,203 @@
 /*
-  Copyright (c) 2022-2023, Intel Corporation
+  Copyright (c) 2022-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
 
 #include "MakeInternalFuncsStatic.h"
+#include "builtins-decl.h"
 
 namespace ispc {
 
+using namespace builtin;
+
 llvm::PreservedAnalyses MakeInternalFuncsStaticPass::run(llvm::Module &M, llvm::ModuleAnalysisManager &MAM) {
     const char *names[] = {
-        "__avg_up_uint8",
-        "__avg_up_int8",
-        "__avg_up_uint16",
-        "__avg_up_int16",
-        "__avg_down_uint8",
-        "__avg_down_int8",
-        "__avg_down_uint16",
-        "__avg_down_int16",
-        "__fast_masked_vload",
-        "__gather_factored_base_offsets32_i8",
-        "__gather_factored_base_offsets32_i16",
-        "__gather_factored_base_offsets32_i32",
-        "__gather_factored_base_offsets32_i64",
-        "__gather_factored_base_offsets32_half",
-        "__gather_factored_base_offsets32_float",
-        "__gather_factored_base_offsets32_double",
-        "__gather_factored_base_offsets64_i8",
-        "__gather_factored_base_offsets64_i16",
-        "__gather_factored_base_offsets64_i32",
-        "__gather_factored_base_offsets64_i64",
-        "__gather_factored_base_offsets64_half",
-        "__gather_factored_base_offsets64_float",
-        "__gather_factored_base_offsets64_double",
-        "__gather_base_offsets32_i8",
-        "__gather_base_offsets32_i16",
-        "__gather_base_offsets32_i32",
-        "__gather_base_offsets32_i64",
-        "__gather_base_offsets32_half",
-        "__gather_base_offsets32_float",
-        "__gather_base_offsets32_double",
-        "__gather_base_offsets64_i8",
-        "__gather_base_offsets64_i16",
-        "__gather_base_offsets64_i32",
-        "__gather_base_offsets64_i64",
-        "__gather_base_offsets64_half",
-        "__gather_base_offsets64_float",
-        "__gather_base_offsets64_double",
-        "__gather32_i8",
-        "__gather32_i16",
-        "__gather32_i32",
-        "__gather32_i64",
-        "__gather32_half",
-        "__gather32_float",
-        "__gather32_double",
-        "__gather32_generic_i8",
-        "__gather32_generic_i16",
-        "__gather32_generic_i32",
-        "__gather32_generic_i64",
-        "__gather32_generic_half",
-        "__gather32_generic_float",
-        "__gather32_generic_double",
-        "__gather64_i8",
-        "__gather64_i16",
-        "__gather64_i32",
-        "__gather64_i64",
-        "__gather64_half",
-        "__gather64_float",
-        "__gather64_double",
-        "__gather64_generic_i8",
-        "__gather64_generic_i16",
-        "__gather64_generic_i32",
-        "__gather64_generic_i64",
-        "__gather64_generic_half",
-        "__gather64_generic_float",
-        "__gather64_generic_double",
-        "__gather_elt32_i8",
-        "__gather_elt32_i16",
-        "__gather_elt32_i32",
-        "__gather_elt32_i64",
-        "__gather_elt32_half",
-        "__gather_elt32_float",
-        "__gather_elt32_double",
-        "__gather_elt64_i8",
-        "__gather_elt64_i16",
-        "__gather_elt64_i32",
-        "__gather_elt64_i64",
-        "__gather_elt64_half",
-        "__gather_elt64_float",
-        "__gather_elt64_double",
-        "__masked_load_i8",
-        "__masked_load_i16",
-        "__masked_load_i32",
-        "__masked_load_i64",
-        "__masked_load_half",
-        "__masked_load_float",
-        "__masked_load_double",
-        "__masked_store_i8",
-        "__masked_store_i16",
-        "__masked_store_i32",
-        "__masked_store_i64",
-        "__masked_store_half",
-        "__masked_store_float",
-        "__masked_store_double",
-        "__masked_store_blend_i8",
-        "__masked_store_blend_i16",
-        "__masked_store_blend_i32",
-        "__masked_store_blend_i64",
-        "__masked_store_blend_half",
-        "__masked_store_blend_float",
-        "__masked_store_blend_double",
-        "__scatter_factored_base_offsets32_i8",
-        "__scatter_factored_base_offsets32_i16",
-        "__scatter_factored_base_offsets32_i32",
-        "__scatter_factored_base_offsets32_i64",
-        "__scatter_factored_base_offsets32_half",
-        "__scatter_factored_base_offsets32_float",
-        "__scatter_factored_base_offsets32_double",
-        "__scatter_factored_base_offsets64_i8",
-        "__scatter_factored_base_offsets64_i16",
-        "__scatter_factored_base_offsets64_i32",
-        "__scatter_factored_base_offsets64_i64",
-        "__scatter_factored_base_offsets64_half",
-        "__scatter_factored_base_offsets64_float",
-        "__scatter_factored_base_offsets64_double",
-        "__scatter_base_offsets32_i8",
-        "__scatter_base_offsets32_i16",
-        "__scatter_base_offsets32_i32",
-        "__scatter_base_offsets32_i64",
-        "__scatter_base_offsets32_half",
-        "__scatter_base_offsets32_float",
-        "__scatter_base_offsets32_double",
-        "__scatter_base_offsets64_i8",
-        "__scatter_base_offsets64_i16",
-        "__scatter_base_offsets64_i32",
-        "__scatter_base_offsets64_i64",
-        "__scatter_base_offsets64_half",
-        "__scatter_base_offsets64_float",
-        "__scatter_base_offsets64_double",
-        "__scatter_elt32_i8",
-        "__scatter_elt32_i16",
-        "__scatter_elt32_i32",
-        "__scatter_elt32_i64",
-        "__scatter_elt32_half",
-        "__scatter_elt32_float",
-        "__scatter_elt32_double",
-        "__scatter_elt64_i8",
-        "__scatter_elt64_i16",
-        "__scatter_elt64_i32",
-        "__scatter_elt64_i64",
-        "__scatter_elt64_half",
-        "__scatter_elt64_float",
-        "__scatter_elt64_double",
-        "__scatter32_i8",
-        "__scatter32_i16",
-        "__scatter32_i32",
-        "__scatter32_i64",
-        "__scatter32_half",
-        "__scatter32_float",
-        "__scatter32_double",
-        "__scatter64_i8",
-        "__scatter64_i16",
-        "__scatter64_i32",
-        "__scatter64_i64",
-        "__scatter64_half",
-        "__scatter64_float",
-        "__scatter64_double",
-        "__scatter32_generic_i8",
-        "__scatter32_generic_i16",
-        "__scatter32_generic_i32",
-        "__scatter32_generic_i64",
-        "__scatter32_generic_half",
-        "__scatter32_generic_float",
-        "__scatter32_generic_double",
-        "__scatter64_generic_i8",
-        "__scatter64_generic_i16",
-        "__scatter64_generic_i32",
-        "__scatter64_generic_i64",
-        "__scatter64_generic_half",
-        "__scatter64_generic_float",
-        "__scatter64_generic_double",
-        "__prefetch_read_varying_1",
-        "__prefetch_read_varying_2",
-        "__prefetch_read_varying_3",
-        "__prefetch_read_varying_nt",
-        "__prefetch_write_varying_1",
-        "__prefetch_write_varying_2",
-        "__prefetch_write_varying_3",
-        "__keep_funcs_live",
-#ifdef ISPC_XE_ENABLED
-        "__masked_load_blend_i8",
-        "__masked_load_blend_i16",
-        "__masked_load_blend_i32",
-        "__masked_load_blend_i64",
-        "__masked_load_blend_half",
-        "__masked_load_blend_float",
-        "__masked_load_blend_double",
-#endif
+        __avg_up_uint8,
+        __avg_up_int8,
+        __avg_up_uint16,
+        __avg_up_int16,
+        __avg_down_uint8,
+        __avg_down_int8,
+        __avg_down_uint16,
+        __avg_down_int16,
+        __fast_masked_vload,
+        __gather_factored_base_offsets32_i8,
+        __gather_factored_base_offsets32_i16,
+        __gather_factored_base_offsets32_i32,
+        __gather_factored_base_offsets32_i64,
+        __gather_factored_base_offsets32_half,
+        __gather_factored_base_offsets32_float,
+        __gather_factored_base_offsets32_double,
+        __gather_factored_base_offsets64_i8,
+        __gather_factored_base_offsets64_i16,
+        __gather_factored_base_offsets64_i32,
+        __gather_factored_base_offsets64_i64,
+        __gather_factored_base_offsets64_half,
+        __gather_factored_base_offsets64_float,
+        __gather_factored_base_offsets64_double,
+        __gather_base_offsets32_i8,
+        __gather_base_offsets32_i16,
+        __gather_base_offsets32_i32,
+        __gather_base_offsets32_i64,
+        __gather_base_offsets32_half,
+        __gather_base_offsets32_float,
+        __gather_base_offsets32_double,
+        __gather_base_offsets64_i8,
+        __gather_base_offsets64_i16,
+        __gather_base_offsets64_i32,
+        __gather_base_offsets64_i64,
+        __gather_base_offsets64_half,
+        __gather_base_offsets64_float,
+        __gather_base_offsets64_double,
+        __gather32_i8,
+        __gather32_i16,
+        __gather32_i32,
+        __gather32_i64,
+        __gather32_half,
+        __gather32_float,
+        __gather32_double,
+        __gather32_generic_i8,
+        __gather32_generic_i16,
+        __gather32_generic_i32,
+        __gather32_generic_i64,
+        __gather32_generic_half,
+        __gather32_generic_float,
+        __gather32_generic_double,
+        __gather64_i8,
+        __gather64_i16,
+        __gather64_i32,
+        __gather64_i64,
+        __gather64_half,
+        __gather64_float,
+        __gather64_double,
+        __gather64_generic_i8,
+        __gather64_generic_i16,
+        __gather64_generic_i32,
+        __gather64_generic_i64,
+        __gather64_generic_half,
+        __gather64_generic_float,
+        __gather64_generic_double,
+        __gather_elt32_i8,
+        __gather_elt32_i16,
+        __gather_elt32_i32,
+        __gather_elt32_i64,
+        __gather_elt32_half,
+        __gather_elt32_float,
+        __gather_elt32_double,
+        __gather_elt64_i8,
+        __gather_elt64_i16,
+        __gather_elt64_i32,
+        __gather_elt64_i64,
+        __gather_elt64_half,
+        __gather_elt64_float,
+        __gather_elt64_double,
+        __masked_load_i8,
+        __masked_load_i16,
+        __masked_load_i32,
+        __masked_load_i64,
+        __masked_load_half,
+        __masked_load_float,
+        __masked_load_double,
+        __masked_store_i8,
+        __masked_store_i16,
+        __masked_store_i32,
+        __masked_store_i64,
+        __masked_store_half,
+        __masked_store_float,
+        __masked_store_double,
+        __masked_store_blend_i8,
+        __masked_store_blend_i16,
+        __masked_store_blend_i32,
+        __masked_store_blend_i64,
+        __masked_store_blend_half,
+        __masked_store_blend_float,
+        __masked_store_blend_double,
+        __scatter_factored_base_offsets32_i8,
+        __scatter_factored_base_offsets32_i16,
+        __scatter_factored_base_offsets32_i32,
+        __scatter_factored_base_offsets32_i64,
+        __scatter_factored_base_offsets32_half,
+        __scatter_factored_base_offsets32_float,
+        __scatter_factored_base_offsets32_double,
+        __scatter_factored_base_offsets64_i8,
+        __scatter_factored_base_offsets64_i16,
+        __scatter_factored_base_offsets64_i32,
+        __scatter_factored_base_offsets64_i64,
+        __scatter_factored_base_offsets64_half,
+        __scatter_factored_base_offsets64_float,
+        __scatter_factored_base_offsets64_double,
+        __scatter_base_offsets32_i8,
+        __scatter_base_offsets32_i16,
+        __scatter_base_offsets32_i32,
+        __scatter_base_offsets32_i64,
+        __scatter_base_offsets32_half,
+        __scatter_base_offsets32_float,
+        __scatter_base_offsets32_double,
+        __scatter_base_offsets64_i8,
+        __scatter_base_offsets64_i16,
+        __scatter_base_offsets64_i32,
+        __scatter_base_offsets64_i64,
+        __scatter_base_offsets64_half,
+        __scatter_base_offsets64_float,
+        __scatter_base_offsets64_double,
+        __scatter_elt32_i8,
+        __scatter_elt32_i16,
+        __scatter_elt32_i32,
+        __scatter_elt32_i64,
+        __scatter_elt32_half,
+        __scatter_elt32_float,
+        __scatter_elt32_double,
+        __scatter_elt64_i8,
+        __scatter_elt64_i16,
+        __scatter_elt64_i32,
+        __scatter_elt64_i64,
+        __scatter_elt64_half,
+        __scatter_elt64_float,
+        __scatter_elt64_double,
+        __scatter32_i8,
+        __scatter32_i16,
+        __scatter32_i32,
+        __scatter32_i64,
+        __scatter32_half,
+        __scatter32_float,
+        __scatter32_double,
+        __scatter64_i8,
+        __scatter64_i16,
+        __scatter64_i32,
+        __scatter64_i64,
+        __scatter64_half,
+        __scatter64_float,
+        __scatter64_double,
+        __scatter32_generic_i8,
+        __scatter32_generic_i16,
+        __scatter32_generic_i32,
+        __scatter32_generic_i64,
+        __scatter32_generic_half,
+        __scatter32_generic_float,
+        __scatter32_generic_double,
+        __scatter64_generic_i8,
+        __scatter64_generic_i16,
+        __scatter64_generic_i32,
+        __scatter64_generic_i64,
+        __scatter64_generic_half,
+        __scatter64_generic_float,
+        __scatter64_generic_double,
+        __prefetch_read_varying_1,
+        __prefetch_read_varying_2,
+        __prefetch_read_varying_3,
+        __prefetch_read_varying_nt,
+        __prefetch_write_varying_1,
+        __prefetch_write_varying_2,
+        __prefetch_write_varying_3,
+        __keep_funcs_live,
+        __masked_load_blend_i8,
+        __masked_load_blend_i16,
+        __masked_load_blend_i32,
+        __masked_load_blend_i64,
+        __masked_load_blend_half,
+        __masked_load_blend_float,
+        __masked_load_blend_double,
     };
 
     int count = sizeof(names) / sizeof(names[0]);
diff --git a/src/opt/PeepholePass.cpp b/src/opt/PeepholePass.cpp
index 4a7e838425..3072629099 100644
--- a/src/opt/PeepholePass.cpp
+++ b/src/opt/PeepholePass.cpp
@@ -1,10 +1,11 @@
 /*
-  Copyright (c) 2022-2023, Intel Corporation
+  Copyright (c) 2022-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
 
 #include "PeepholePass.h"
+#include "builtins-decl.h"
 
 namespace ispc {
 
@@ -154,7 +155,7 @@ static llvm::Instruction *lMatchAvgUpUInt8(llvm::Value *inst) {
         if (delta->isIntN(1) == false)
             return nullptr;
 
-        return lGetBinaryIntrinsic("__avg_up_uint8", opa, opb);
+        return lGetBinaryIntrinsic(builtin::__avg_up_uint8, opa, opb);
     }
     return nullptr;
 }
@@ -163,7 +164,7 @@ static llvm::Instruction *lMatchAvgDownUInt8(llvm::Value *inst) {
     // (unsigned int8)(((unsigned int16)a + (unsigned int16)b)/2)
     llvm::Value *opa, *opb;
     if (match(inst, m_Trunc16To8(m_UDiv2(m_Add(m_ZExt8To16(m_Value(opa)), m_ZExt8To16(m_Value(opb))))))) {
-        return lGetBinaryIntrinsic("__avg_down_uint8", opa, opb);
+        return lGetBinaryIntrinsic(builtin::__avg_down_uint8, opa, opb);
     }
     return nullptr;
 }
@@ -180,7 +181,7 @@ static llvm::Instruction *lMatchAvgUpUInt16(llvm::Value *inst) {
         if (delta->isIntN(1) == false)
             return nullptr;
 
-        return lGetBinaryIntrinsic("__avg_up_uint16", opa, opb);
+        return lGetBinaryIntrinsic(builtin::__avg_up_uint16, opa, opb);
     }
     return nullptr;
 }
@@ -189,7 +190,7 @@ static llvm::Instruction *lMatchAvgDownUInt16(llvm::Value *inst) {
     // (unsigned int16)(((unsigned int32)a + (unsigned int32)b)/2)
     llvm::Value *opa, *opb;
     if (match(inst, m_Trunc32To16(m_UDiv2(m_Add(m_ZExt16To32(m_Value(opa)), m_ZExt16To32(m_Value(opb))))))) {
-        return lGetBinaryIntrinsic("__avg_down_uint16", opa, opb);
+        return lGetBinaryIntrinsic(builtin::__avg_down_uint16, opa, opb);
     }
     return nullptr;
 }
@@ -205,7 +206,7 @@ static llvm::Instruction *lMatchAvgUpInt8(llvm::Value *inst) {
         if (delta->isIntN(1) == false)
             return nullptr;
 
-        return lGetBinaryIntrinsic("__avg_up_int8", opa, opb);
+        return lGetBinaryIntrinsic(builtin::__avg_up_int8, opa, opb);
     }
     return nullptr;
 }
@@ -214,7 +215,7 @@ static llvm::Instruction *lMatchAvgDownInt8(llvm::Value *inst) {
     // (int8)(((int16)a + (int16)b)/2)
     llvm::Value *opa, *opb;
     if (match(inst, m_Trunc16To8(m_SDiv2(m_Add(m_SExt8To16(m_Value(opa)), m_SExt8To16(m_Value(opb))))))) {
-        return lGetBinaryIntrinsic("__avg_down_int8", opa, opb);
+        return lGetBinaryIntrinsic(builtin::__avg_down_int8, opa, opb);
     }
     return nullptr;
 }
@@ -231,7 +232,7 @@ static llvm::Instruction *lMatchAvgUpInt16(llvm::Value *inst) {
         if (delta->isIntN(1) == false)
             return nullptr;
 
-        return lGetBinaryIntrinsic("__avg_up_int16", opa, opb);
+        return lGetBinaryIntrinsic(builtin::__avg_up_int16, opa, opb);
     }
     return nullptr;
 }
@@ -240,7 +241,7 @@ static llvm::Instruction *lMatchAvgDownInt16(llvm::Value *inst) {
     // (int16)(((int32)a + (int32)b)/2)
     llvm::Value *opa, *opb;
     if (match(inst, m_Trunc32To16(m_SDiv2(m_Add(m_SExt16To32(m_Value(opa)), m_SExt16To32(m_Value(opb))))))) {
-        return lGetBinaryIntrinsic("__avg_down_int16", opa, opb);
+        return lGetBinaryIntrinsic(builtin::__avg_down_int16, opa, opb);
     }
     return nullptr;
 }
@@ -298,4 +299,4 @@ llvm::PreservedAnalyses PeepholePass::run(llvm::Function &F, llvm::FunctionAnaly
     return PA;
 }
 
-} // namespace ispc
\ No newline at end of file
+} // namespace ispc
diff --git a/src/opt/ReplacePseudoMemoryOps.cpp b/src/opt/ReplacePseudoMemoryOps.cpp
index a5060d7ecd..4c98563968 100644
--- a/src/opt/ReplacePseudoMemoryOps.cpp
+++ b/src/opt/ReplacePseudoMemoryOps.cpp
@@ -1,13 +1,16 @@
 /*
-  Copyright (c) 2022-2023, Intel Corporation
+  Copyright (c) 2022-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
 
 #include "ReplacePseudoMemoryOps.h"
+#include "builtins-decl.h"
 
 namespace ispc {
 
+using namespace builtin;
+
 /** This routine attempts to determine if the given pointer in lvalue is
     pointing to stack-allocated memory.  It's conservative in that it
     should never return true for non-stack allocated memory, but may return
@@ -39,36 +42,34 @@ static bool lIsSafeToBlend(llvm::Value *lvalue) {
     }
 }
 
+struct LMSInfo {
+    LMSInfo(const char *bname, const char *msname) : blend(bname), store(msname) {}
+    llvm::Function *blendFunc() const { return m->module->getFunction(blend); }
+    llvm::Function *maskedStoreFunc() const { return m->module->getFunction(store); }
+
+  private:
+    const char *blend;
+    const char *store;
+};
+
 static bool lReplacePseudoMaskedStore(llvm::CallInst *callInst) {
-    struct LMSInfo {
-        LMSInfo(const char *pname, const char *bname, const char *msname) {
-            pseudoFunc = m->module->getFunction(pname);
-            blendFunc = m->module->getFunction(bname);
-            maskedStoreFunc = m->module->getFunction(msname);
-            Assert(pseudoFunc != nullptr && blendFunc != nullptr && maskedStoreFunc != nullptr);
-        }
-        llvm::Function *pseudoFunc;
-        llvm::Function *blendFunc;
-        llvm::Function *maskedStoreFunc;
+    static std::unordered_map<std::string, LMSInfo> replacementRules = {
+        {__pseudo_masked_store_i8, LMSInfo(__masked_store_blend_i8, __masked_store_i8)},
+        {__pseudo_masked_store_i16, LMSInfo(__masked_store_blend_i16, __masked_store_i16)},
+        {__pseudo_masked_store_half, LMSInfo(__masked_store_blend_half, __masked_store_half)},
+        {__pseudo_masked_store_i32, LMSInfo(__masked_store_blend_i32, __masked_store_i32)},
+        {__pseudo_masked_store_float, LMSInfo(__masked_store_blend_float, __masked_store_float)},
+        {__pseudo_masked_store_i64, LMSInfo(__masked_store_blend_i64, __masked_store_i64)},
+        {__pseudo_masked_store_double, LMSInfo(__masked_store_blend_double, __masked_store_double)},
     };
 
-    LMSInfo msInfo[] = {
-        LMSInfo("__pseudo_masked_store_i8", "__masked_store_blend_i8", "__masked_store_i8"),
-        LMSInfo("__pseudo_masked_store_i16", "__masked_store_blend_i16", "__masked_store_i16"),
-        LMSInfo("__pseudo_masked_store_half", "__masked_store_blend_half", "__masked_store_half"),
-        LMSInfo("__pseudo_masked_store_i32", "__masked_store_blend_i32", "__masked_store_i32"),
-        LMSInfo("__pseudo_masked_store_float", "__masked_store_blend_float", "__masked_store_float"),
-        LMSInfo("__pseudo_masked_store_i64", "__masked_store_blend_i64", "__masked_store_i64"),
-        LMSInfo("__pseudo_masked_store_double", "__masked_store_blend_double", "__masked_store_double")};
-    LMSInfo *info = nullptr;
-    for (unsigned int i = 0; i < sizeof(msInfo) / sizeof(msInfo[0]); ++i) {
-        if (msInfo[i].pseudoFunc != nullptr && callInst->getCalledFunction() == msInfo[i].pseudoFunc) {
-            info = &msInfo[i];
-            break;
-        }
-    }
-    if (info == nullptr)
+    auto name = callInst->getCalledFunction()->getName().str();
+    auto it = replacementRules.find(name);
+    if (it == replacementRules.end()) {
+        // it is not a call of __pseudo function stored in replacementRules
         return false;
+    }
+    LMSInfo *info = &it->second;
 
     llvm::Value *lvalue = callInst->getArgOperand(0);
     llvm::Value *rvalue = callInst->getArgOperand(1);
@@ -82,7 +83,7 @@ static bool lReplacePseudoMaskedStore(llvm::CallInst *callInst) {
 
     // Generate the call to the appropriate masked store function and
     // replace the __pseudo_* one with it.
-    llvm::Function *fms = doBlend ? info->blendFunc : info->maskedStoreFunc;
+    llvm::Function *fms = doBlend ? info->blendFunc() : info->maskedStoreFunc();
     llvm::Instruction *inst = LLVMCallInst(fms, lvalue, rvalue, mask, "", callInst);
     LLVMCopyMetadata(inst, callInst);
 
@@ -90,242 +91,185 @@ static bool lReplacePseudoMaskedStore(llvm::CallInst *callInst) {
     return true;
 }
 
-static bool lReplacePseudoGS(llvm::CallInst *callInst) {
-    struct LowerGSInfo {
-        LowerGSInfo(const char *pName, const char *aName, bool ig, bool ip) : isGather(ig), isPrefetch(ip) {
-            pseudoFunc = m->module->getFunction(pName);
-            actualFunc = m->module->getFunction(aName);
-        }
-        llvm::Function *pseudoFunc;
-        llvm::Function *actualFunc;
-        const bool isGather;
-        const bool isPrefetch;
+struct LowerGSInfo {
+    enum class Type {
+        Gather,
+        Scatter,
+        Prefetch,
     };
+    LowerGSInfo(const char *aName, Type type) : generic(aName), name(aName), type(type) {}
+    LowerGSInfo(const char *gName, const char *aName, Type type) : generic(gName), name(aName), type(type) {}
+    static LowerGSInfo Gather(const char *aName) { return LowerGSInfo(aName, Type::Gather); }
+    static LowerGSInfo Gather(const char *gName, const char *aName) { return LowerGSInfo(gName, aName, Type::Gather); }
+    static LowerGSInfo Scatter(const char *aName) { return LowerGSInfo(aName, Type::Scatter); }
+    static LowerGSInfo Scatter(const char *gName, const char *aName) {
+        return LowerGSInfo(gName, aName, Type::Scatter);
+    }
+    static LowerGSInfo Prefetch(const char *aName) { return LowerGSInfo(aName, Type::Prefetch); }
+    llvm::Function *actualFunc() const {
+        const char *func = name;
+        if (isGather()) {
+            func = g->target->hasGather() && g->opt.disableGathers ? generic : name;
+        }
+        if (isScatter()) {
+            func = g->target->hasScatter() && g->opt.disableScatters ? generic : name;
+        }
+        return m->module->getFunction(func);
+    }
+    bool isGather() const { return type == Type::Gather; }
+    bool isScatter() const { return type == Type::Scatter; }
+    bool isPrefetch() const { return type == Type::Prefetch; }
+
+  private:
+    const char *generic;
+    const char *name;
+    Type type;
+};
+
+static bool lReplacePseudoGS(llvm::CallInst *callInst) {
 
-    LowerGSInfo lgsInfo[] = {
-        LowerGSInfo("__pseudo_gather32_i8",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather32_generic_i8" : "__gather32_i8", true,
-                    false),
-        LowerGSInfo("__pseudo_gather32_i16",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather32_generic_i16" : "__gather32_i16", true,
-                    false),
-        LowerGSInfo("__pseudo_gather32_half",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather32_generic_half" : "__gather32_half",
-                    true, false),
-        LowerGSInfo("__pseudo_gather32_i32",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather32_generic_i32" : "__gather32_i32", true,
-                    false),
-        LowerGSInfo("__pseudo_gather32_float",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather32_generic_float" : "__gather32_float",
-                    true, false),
-        LowerGSInfo("__pseudo_gather32_i64",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather32_generic_i64" : "__gather32_i64", true,
-                    false),
-        LowerGSInfo("__pseudo_gather32_double",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather32_generic_double" : "__gather32_double",
-                    true, false),
-
-        LowerGSInfo("__pseudo_gather64_i8",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather64_generic_i8" : "__gather64_i8", true,
-                    false),
-        LowerGSInfo("__pseudo_gather64_i16",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather64_generic_i16" : "__gather64_i16", true,
-                    false),
-        LowerGSInfo("__pseudo_gather64_half",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather64_generic_half" : "__gather64_half",
-                    true, false),
-        LowerGSInfo("__pseudo_gather64_i32",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather64_generic_i32" : "__gather64_i32", true,
-                    false),
-        LowerGSInfo("__pseudo_gather64_float",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather64_generic_float" : "__gather64_float",
-                    true, false),
-        LowerGSInfo("__pseudo_gather64_i64",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather64_generic_i64" : "__gather64_i64", true,
-                    false),
-        LowerGSInfo("__pseudo_gather64_double",
-                    g->target->hasGather() && g->opt.disableGathers ? "__gather64_generic_double" : "__gather64_double",
-                    true, false),
-
-        LowerGSInfo("__pseudo_gather_factored_base_offsets32_i8", "__gather_factored_base_offsets32_i8", true, false),
-        LowerGSInfo("__pseudo_gather_factored_base_offsets32_i16", "__gather_factored_base_offsets32_i16", true, false),
-        LowerGSInfo("__pseudo_gather_factored_base_offsets32_half", "__gather_factored_base_offsets32_half", true,
-                    false),
-        LowerGSInfo("__pseudo_gather_factored_base_offsets32_i32", "__gather_factored_base_offsets32_i32", true, false),
-        LowerGSInfo("__pseudo_gather_factored_base_offsets32_float", "__gather_factored_base_offsets32_float", true,
-                    false),
-        LowerGSInfo("__pseudo_gather_factored_base_offsets32_i64", "__gather_factored_base_offsets32_i64", true, false),
-        LowerGSInfo("__pseudo_gather_factored_base_offsets32_double", "__gather_factored_base_offsets32_double", true,
-                    false),
-
-        LowerGSInfo("__pseudo_gather_factored_base_offsets64_i8", "__gather_factored_base_offsets64_i8", true, false),
-        LowerGSInfo("__pseudo_gather_factored_base_offsets64_i16", "__gather_factored_base_offsets64_i16", true, false),
-        LowerGSInfo("__pseudo_gather_factored_base_offsets64_half", "__gather_factored_base_offsets64_half", true,
-                    false),
-        LowerGSInfo("__pseudo_gather_factored_base_offsets64_i32", "__gather_factored_base_offsets64_i32", true, false),
-        LowerGSInfo("__pseudo_gather_factored_base_offsets64_float", "__gather_factored_base_offsets64_float", true,
-                    false),
-        LowerGSInfo("__pseudo_gather_factored_base_offsets64_i64", "__gather_factored_base_offsets64_i64", true, false),
-        LowerGSInfo("__pseudo_gather_factored_base_offsets64_double", "__gather_factored_base_offsets64_double", true,
-                    false),
-
-        LowerGSInfo("__pseudo_gather_base_offsets32_i8", "__gather_base_offsets32_i8", true, false),
-        LowerGSInfo("__pseudo_gather_base_offsets32_i16", "__gather_base_offsets32_i16", true, false),
-        LowerGSInfo("__pseudo_gather_base_offsets32_half", "__gather_base_offsets32_half", true, false),
-        LowerGSInfo("__pseudo_gather_base_offsets32_i32", "__gather_base_offsets32_i32", true, false),
-        LowerGSInfo("__pseudo_gather_base_offsets32_float", "__gather_base_offsets32_float", true, false),
-        LowerGSInfo("__pseudo_gather_base_offsets32_i64", "__gather_base_offsets32_i64", true, false),
-        LowerGSInfo("__pseudo_gather_base_offsets32_double", "__gather_base_offsets32_double", true, false),
-
-        LowerGSInfo("__pseudo_gather_base_offsets64_i8", "__gather_base_offsets64_i8", true, false),
-        LowerGSInfo("__pseudo_gather_base_offsets64_i16", "__gather_base_offsets64_i16", true, false),
-        LowerGSInfo("__pseudo_gather_base_offsets64_half", "__gather_base_offsets64_half", true, false),
-        LowerGSInfo("__pseudo_gather_base_offsets64_i32", "__gather_base_offsets64_i32", true, false),
-        LowerGSInfo("__pseudo_gather_base_offsets64_float", "__gather_base_offsets64_float", true, false),
-        LowerGSInfo("__pseudo_gather_base_offsets64_i64", "__gather_base_offsets64_i64", true, false),
-        LowerGSInfo("__pseudo_gather_base_offsets64_double", "__gather_base_offsets64_double", true, false),
-
-        LowerGSInfo("__pseudo_scatter32_i8",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter32_generic_i8" : "__scatter32_i8",
-                    false, false),
-        LowerGSInfo("__pseudo_scatter32_i16",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter32_generic_i16" : "__scatter32_i16",
-                    false, false),
-        LowerGSInfo("__pseudo_scatter32_half",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter32_generic_half" : "__scatter32_half",
-                    false, false),
-        LowerGSInfo("__pseudo_scatter32_i32",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter32_generic_i32" : "__scatter32_i32",
-                    false, false),
-        LowerGSInfo("__pseudo_scatter32_float",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter32_generic_float"
-                                                                      : "__scatter32_float",
-                    false, false),
-        LowerGSInfo("__pseudo_scatter32_i64",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter32_generic_i64" : "__scatter32_i64",
-                    false, false),
-        LowerGSInfo("__pseudo_scatter32_double",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter32_generic_double"
-                                                                      : "__scatter32_double",
-                    false, false),
-
-        LowerGSInfo("__pseudo_scatter64_i8",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter64_generic_i8" : "__scatter64_i8",
-                    false, false),
-        LowerGSInfo("__pseudo_scatter64_i16",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter64_generic_i16" : "__scatter64_i16",
-                    false, false),
-        LowerGSInfo("__pseudo_scatter64_half",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter64_generic_half" : "__scatter64_half",
-                    false, false),
-        LowerGSInfo("__pseudo_scatter64_i32",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter64_generic_i32" : "__scatter64_i32",
-                    false, false),
-        LowerGSInfo("__pseudo_scatter64_float",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter64_generic_float"
-                                                                      : "__scatter64_float",
-                    false, false),
-        LowerGSInfo("__pseudo_scatter64_i64",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter64_generic_i64" : "__scatter64_i64",
-                    false, false),
-        LowerGSInfo("__pseudo_scatter64_double",
-                    g->target->hasScatter() && g->opt.disableScatters ? "__scatter64_generic_double"
-                                                                      : "__scatter64_double",
-                    false, false),
-
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets32_i8", "__scatter_factored_base_offsets32_i8", false,
-                    false),
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets32_i16", "__scatter_factored_base_offsets32_i16", false,
-                    false),
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets32_half", "__scatter_factored_base_offsets32_half", false,
-                    false),
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets32_i32", "__scatter_factored_base_offsets32_i32", false,
-                    false),
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets32_float", "__scatter_factored_base_offsets32_float", false,
-                    false),
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets32_i64", "__scatter_factored_base_offsets32_i64", false,
-                    false),
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets32_double", "__scatter_factored_base_offsets32_double",
-                    false, false),
-
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets64_i8", "__scatter_factored_base_offsets64_i8", false,
-                    false),
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets64_i16", "__scatter_factored_base_offsets64_i16", false,
-                    false),
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets64_half", "__scatter_factored_base_offsets64_half", false,
-                    false),
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets64_i32", "__scatter_factored_base_offsets64_i32", false,
-                    false),
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets64_float", "__scatter_factored_base_offsets64_float", false,
-                    false),
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets64_i64", "__scatter_factored_base_offsets64_i64", false,
-                    false),
-        LowerGSInfo("__pseudo_scatter_factored_base_offsets64_double", "__scatter_factored_base_offsets64_double",
-                    false, false),
-
-        LowerGSInfo("__pseudo_scatter_base_offsets32_i8", "__scatter_base_offsets32_i8", false, false),
-        LowerGSInfo("__pseudo_scatter_base_offsets32_i16", "__scatter_base_offsets32_i16", false, false),
-        LowerGSInfo("__pseudo_scatter_base_offsets32_half", "__scatter_base_offsets32_half", false, false),
-        LowerGSInfo("__pseudo_scatter_base_offsets32_i32", "__scatter_base_offsets32_i32", false, false),
-        LowerGSInfo("__pseudo_scatter_base_offsets32_float", "__scatter_base_offsets32_float", false, false),
-        LowerGSInfo("__pseudo_scatter_base_offsets32_i64", "__scatter_base_offsets32_i64", false, false),
-        LowerGSInfo("__pseudo_scatter_base_offsets32_double", "__scatter_base_offsets32_double", false, false),
-
-        LowerGSInfo("__pseudo_scatter_base_offsets64_i8", "__scatter_base_offsets64_i8", false, false),
-        LowerGSInfo("__pseudo_scatter_base_offsets64_i16", "__scatter_base_offsets64_i16", false, false),
-        LowerGSInfo("__pseudo_scatter_base_offsets64_half", "__scatter_base_offsets64_half", false, false),
-        LowerGSInfo("__pseudo_scatter_base_offsets64_i32", "__scatter_base_offsets64_i32", false, false),
-        LowerGSInfo("__pseudo_scatter_base_offsets64_float", "__scatter_base_offsets64_float", false, false),
-        LowerGSInfo("__pseudo_scatter_base_offsets64_i64", "__scatter_base_offsets64_i64", false, false),
-        LowerGSInfo("__pseudo_scatter_base_offsets64_double", "__scatter_base_offsets64_double", false, false),
-
-        LowerGSInfo("__pseudo_prefetch_read_varying_1", "__prefetch_read_varying_1", false, true),
-        LowerGSInfo("__pseudo_prefetch_read_varying_1_native", "__prefetch_read_varying_1_native", false, true),
-
-        LowerGSInfo("__pseudo_prefetch_read_varying_2", "__prefetch_read_varying_2", false, true),
-        LowerGSInfo("__pseudo_prefetch_read_varying_2_native", "__prefetch_read_varying_2_native", false, true),
-
-        LowerGSInfo("__pseudo_prefetch_read_varying_3", "__prefetch_read_varying_3", false, true),
-        LowerGSInfo("__pseudo_prefetch_read_varying_3_native", "__prefetch_read_varying_3_native", false, true),
-
-        LowerGSInfo("__pseudo_prefetch_read_varying_nt", "__prefetch_read_varying_nt", false, true),
-        LowerGSInfo("__pseudo_prefetch_read_varying_nt_native", "__prefetch_read_varying_nt_native", false, true),
-
-        LowerGSInfo("__pseudo_prefetch_write_varying_1", "__prefetch_write_varying_1", false, true),
-        LowerGSInfo("__pseudo_prefetch_write_varying_1_native", "__prefetch_write_varying_1_native", false, true),
-
-        LowerGSInfo("__pseudo_prefetch_write_varying_2", "__prefetch_write_varying_2", false, true),
-        LowerGSInfo("__pseudo_prefetch_write_varying_2_native", "__prefetch_write_varying_2_native", false, true),
-
-        LowerGSInfo("__pseudo_prefetch_write_varying_3", "__prefetch_write_varying_3", false, true),
-        LowerGSInfo("__pseudo_prefetch_write_varying_3_native", "__prefetch_write_varying_3_native", false, true),
+    static std::unordered_map<std::string, LowerGSInfo> replacementRules = {
+        {__pseudo_gather32_i8, LowerGSInfo::Gather(__gather32_generic_i8, __gather32_i8)},
+        {__pseudo_gather32_i16, LowerGSInfo::Gather(__gather32_generic_i16, __gather32_i16)},
+        {__pseudo_gather32_half, LowerGSInfo::Gather(__gather32_generic_half, __gather32_half)},
+        {__pseudo_gather32_i32, LowerGSInfo::Gather(__gather32_generic_i32, __gather32_i32)},
+        {__pseudo_gather32_float, LowerGSInfo::Gather(__gather32_generic_float, __gather32_float)},
+        {__pseudo_gather32_i64, LowerGSInfo::Gather(__gather32_generic_i64, __gather32_i64)},
+        {__pseudo_gather32_double, LowerGSInfo::Gather(__gather32_generic_double, __gather32_double)},
+
+        {__pseudo_gather64_i8, LowerGSInfo::Gather(__gather64_generic_i8, __gather64_i8)},
+        {__pseudo_gather64_i16, LowerGSInfo::Gather(__gather64_generic_i16, __gather64_i16)},
+        {__pseudo_gather64_half, LowerGSInfo::Gather(__gather64_generic_half, __gather64_half)},
+        {__pseudo_gather64_i32, LowerGSInfo::Gather(__gather64_generic_i32, __gather64_i32)},
+        {__pseudo_gather64_float, LowerGSInfo::Gather(__gather64_generic_float, __gather64_float)},
+        {__pseudo_gather64_i64, LowerGSInfo::Gather(__gather64_generic_i64, __gather64_i64)},
+        {__pseudo_gather64_double, LowerGSInfo::Gather(__gather64_generic_double, __gather64_double)},
+
+        {__pseudo_gather_factored_base_offsets32_i8, LowerGSInfo::Gather(__gather_factored_base_offsets32_i8)},
+        {__pseudo_gather_factored_base_offsets32_i16, LowerGSInfo::Gather(__gather_factored_base_offsets32_i16)},
+        {__pseudo_gather_factored_base_offsets32_half, LowerGSInfo::Gather(__gather_factored_base_offsets32_half)},
+        {__pseudo_gather_factored_base_offsets32_i32, LowerGSInfo::Gather(__gather_factored_base_offsets32_i32)},
+        {__pseudo_gather_factored_base_offsets32_float, LowerGSInfo::Gather(__gather_factored_base_offsets32_float)},
+        {__pseudo_gather_factored_base_offsets32_i64, LowerGSInfo::Gather(__gather_factored_base_offsets32_i64)},
+        {__pseudo_gather_factored_base_offsets32_double, LowerGSInfo::Gather(__gather_factored_base_offsets32_double)},
+
+        {__pseudo_gather_factored_base_offsets64_i8, LowerGSInfo::Gather(__gather_factored_base_offsets64_i8)},
+        {__pseudo_gather_factored_base_offsets64_i16, LowerGSInfo::Gather(__gather_factored_base_offsets64_i16)},
+        {__pseudo_gather_factored_base_offsets64_half, LowerGSInfo::Gather(__gather_factored_base_offsets64_half)},
+        {__pseudo_gather_factored_base_offsets64_i32, LowerGSInfo::Gather(__gather_factored_base_offsets64_i32)},
+        {__pseudo_gather_factored_base_offsets64_float, LowerGSInfo::Gather(__gather_factored_base_offsets64_float)},
+        {__pseudo_gather_factored_base_offsets64_i64, LowerGSInfo::Gather(__gather_factored_base_offsets64_i64)},
+        {__pseudo_gather_factored_base_offsets64_double, LowerGSInfo::Gather(__gather_factored_base_offsets64_double)},
+
+        {__pseudo_gather_base_offsets32_i8, LowerGSInfo::Gather(__gather_base_offsets32_i8)},
+        {__pseudo_gather_base_offsets32_i16, LowerGSInfo::Gather(__gather_base_offsets32_i16)},
+        {__pseudo_gather_base_offsets32_half, LowerGSInfo::Gather(__gather_base_offsets32_half)},
+        {__pseudo_gather_base_offsets32_i32, LowerGSInfo::Gather(__gather_base_offsets32_i32)},
+        {__pseudo_gather_base_offsets32_float, LowerGSInfo::Gather(__gather_base_offsets32_float)},
+        {__pseudo_gather_base_offsets32_i64, LowerGSInfo::Gather(__gather_base_offsets32_i64)},
+        {__pseudo_gather_base_offsets32_double, LowerGSInfo::Gather(__gather_base_offsets32_double)},
+
+        {__pseudo_gather_base_offsets64_i8, LowerGSInfo::Gather(__gather_base_offsets64_i8)},
+        {__pseudo_gather_base_offsets64_i16, LowerGSInfo::Gather(__gather_base_offsets64_i16)},
+        {__pseudo_gather_base_offsets64_half, LowerGSInfo::Gather(__gather_base_offsets64_half)},
+        {__pseudo_gather_base_offsets64_i32, LowerGSInfo::Gather(__gather_base_offsets64_i32)},
+        {__pseudo_gather_base_offsets64_float, LowerGSInfo::Gather(__gather_base_offsets64_float)},
+        {__pseudo_gather_base_offsets64_i64, LowerGSInfo::Gather(__gather_base_offsets64_i64)},
+        {__pseudo_gather_base_offsets64_double, LowerGSInfo::Gather(__gather_base_offsets64_double)},
+
+        {__pseudo_scatter32_i8, LowerGSInfo::Scatter(__scatter32_generic_i8, __scatter32_i8)},
+        {__pseudo_scatter32_i16, LowerGSInfo::Scatter(__scatter32_generic_i16, __scatter32_i16)},
+        {__pseudo_scatter32_half, LowerGSInfo::Scatter(__scatter32_generic_half, __scatter32_half)},
+        {__pseudo_scatter32_i32, LowerGSInfo::Scatter(__scatter32_generic_i32, __scatter32_i32)},
+        {__pseudo_scatter32_float, LowerGSInfo::Scatter(__scatter32_generic_float, __scatter32_float)},
+        {__pseudo_scatter32_i64, LowerGSInfo::Scatter(__scatter32_generic_i64, __scatter32_i64)},
+        {__pseudo_scatter32_double, LowerGSInfo::Scatter(__scatter32_generic_double, __scatter32_double)},
+
+        {__pseudo_scatter64_i8, LowerGSInfo::Scatter(__scatter64_generic_i8, __scatter64_i8)},
+        {__pseudo_scatter64_i16, LowerGSInfo::Scatter(__scatter64_generic_i16, __scatter64_i16)},
+        {__pseudo_scatter64_half, LowerGSInfo::Scatter(__scatter64_generic_half, __scatter64_half)},
+        {__pseudo_scatter64_i32, LowerGSInfo::Scatter(__scatter64_generic_i32, __scatter64_i32)},
+        {__pseudo_scatter64_float, LowerGSInfo::Scatter(__scatter64_generic_float, __scatter64_float)},
+        {__pseudo_scatter64_i64, LowerGSInfo::Scatter(__scatter64_generic_i64, __scatter64_i64)},
+        {__pseudo_scatter64_double, LowerGSInfo::Scatter(__scatter64_generic_double, __scatter64_double)},
+
+        {__pseudo_scatter_factored_base_offsets32_i8, LowerGSInfo::Scatter(__scatter_factored_base_offsets32_i8)},
+        {__pseudo_scatter_factored_base_offsets32_i16, LowerGSInfo::Scatter(__scatter_factored_base_offsets32_i16)},
+        {__pseudo_scatter_factored_base_offsets32_half, LowerGSInfo::Scatter(__scatter_factored_base_offsets32_half)},
+        {__pseudo_scatter_factored_base_offsets32_i32, LowerGSInfo::Scatter(__scatter_factored_base_offsets32_i32)},
+        {__pseudo_scatter_factored_base_offsets32_float, LowerGSInfo::Scatter(__scatter_factored_base_offsets32_float)},
+        {__pseudo_scatter_factored_base_offsets32_i64, LowerGSInfo::Scatter(__scatter_factored_base_offsets32_i64)},
+        {__pseudo_scatter_factored_base_offsets32_double,
+         LowerGSInfo::Scatter(__scatter_factored_base_offsets32_double)},
+
+        {__pseudo_scatter_factored_base_offsets64_i8, LowerGSInfo::Scatter(__scatter_factored_base_offsets64_i8)},
+        {__pseudo_scatter_factored_base_offsets64_i16, LowerGSInfo::Scatter(__scatter_factored_base_offsets64_i16)},
+        {__pseudo_scatter_factored_base_offsets64_half, LowerGSInfo::Scatter(__scatter_factored_base_offsets64_half)},
+        {__pseudo_scatter_factored_base_offsets64_i32, LowerGSInfo::Scatter(__scatter_factored_base_offsets64_i32)},
+        {__pseudo_scatter_factored_base_offsets64_float, LowerGSInfo::Scatter(__scatter_factored_base_offsets64_float)},
+        {__pseudo_scatter_factored_base_offsets64_i64, LowerGSInfo::Scatter(__scatter_factored_base_offsets64_i64)},
+        {__pseudo_scatter_factored_base_offsets64_double,
+         LowerGSInfo::Scatter(__scatter_factored_base_offsets64_double)},
+
+        {__pseudo_scatter_base_offsets32_i8, LowerGSInfo::Scatter(__scatter_base_offsets32_i8)},
+        {__pseudo_scatter_base_offsets32_i16, LowerGSInfo::Scatter(__scatter_base_offsets32_i16)},
+        {__pseudo_scatter_base_offsets32_half, LowerGSInfo::Scatter(__scatter_base_offsets32_half)},
+        {__pseudo_scatter_base_offsets32_i32, LowerGSInfo::Scatter(__scatter_base_offsets32_i32)},
+        {__pseudo_scatter_base_offsets32_float, LowerGSInfo::Scatter(__scatter_base_offsets32_float)},
+        {__pseudo_scatter_base_offsets32_i64, LowerGSInfo::Scatter(__scatter_base_offsets32_i64)},
+        {__pseudo_scatter_base_offsets32_double, LowerGSInfo::Scatter(__scatter_base_offsets32_double)},
+
+        {__pseudo_scatter_base_offsets64_i8, LowerGSInfo::Scatter(__scatter_base_offsets64_i8)},
+        {__pseudo_scatter_base_offsets64_i16, LowerGSInfo::Scatter(__scatter_base_offsets64_i16)},
+        {__pseudo_scatter_base_offsets64_half, LowerGSInfo::Scatter(__scatter_base_offsets64_half)},
+        {__pseudo_scatter_base_offsets64_i32, LowerGSInfo::Scatter(__scatter_base_offsets64_i32)},
+        {__pseudo_scatter_base_offsets64_float, LowerGSInfo::Scatter(__scatter_base_offsets64_float)},
+        {__pseudo_scatter_base_offsets64_i64, LowerGSInfo::Scatter(__scatter_base_offsets64_i64)},
+        {__pseudo_scatter_base_offsets64_double, LowerGSInfo::Scatter(__scatter_base_offsets64_double)},
+
+        {__pseudo_prefetch_read_varying_1, LowerGSInfo::Prefetch(__prefetch_read_varying_1)},
+        {__pseudo_prefetch_read_varying_1_native, LowerGSInfo::Prefetch(__prefetch_read_varying_1_native)},
+
+        {__pseudo_prefetch_read_varying_2, LowerGSInfo::Prefetch(__prefetch_read_varying_2)},
+        {__pseudo_prefetch_read_varying_2_native, LowerGSInfo::Prefetch(__prefetch_read_varying_2_native)},
+
+        {__pseudo_prefetch_read_varying_3, LowerGSInfo::Prefetch(__prefetch_read_varying_3)},
+        {__pseudo_prefetch_read_varying_3_native, LowerGSInfo::Prefetch(__prefetch_read_varying_3_native)},
+
+        {__pseudo_prefetch_read_varying_nt, LowerGSInfo::Prefetch(__prefetch_read_varying_nt)},
+        {__pseudo_prefetch_read_varying_nt_native, LowerGSInfo::Prefetch(__prefetch_read_varying_nt_native)},
+
+        {__pseudo_prefetch_write_varying_1, LowerGSInfo::Prefetch(__prefetch_write_varying_1)},
+        {__pseudo_prefetch_write_varying_1_native, LowerGSInfo::Prefetch(__prefetch_write_varying_1_native)},
+
+        {__pseudo_prefetch_write_varying_2, LowerGSInfo::Prefetch(__prefetch_write_varying_2)},
+        {__pseudo_prefetch_write_varying_2_native, LowerGSInfo::Prefetch(__prefetch_write_varying_2_native)},
+
+        {__pseudo_prefetch_write_varying_3, LowerGSInfo::Prefetch(__prefetch_write_varying_3)},
+        {__pseudo_prefetch_write_varying_3_native, LowerGSInfo::Prefetch(__prefetch_write_varying_3_native)},
     };
 
     llvm::Function *calledFunc = callInst->getCalledFunction();
 
-    LowerGSInfo *info = nullptr;
-    for (unsigned int i = 0; i < sizeof(lgsInfo) / sizeof(lgsInfo[0]); ++i) {
-        if (lgsInfo[i].pseudoFunc != nullptr && calledFunc == lgsInfo[i].pseudoFunc) {
-            info = &lgsInfo[i];
-            break;
-        }
-    }
-    if (info == nullptr)
+    auto name = calledFunc->getName().str();
+    auto it = replacementRules.find(name);
+    if (it == replacementRules.end()) {
+        // it is not a call of __pseudo function stored in replacementRules
         return false;
-
-    Assert(info->actualFunc != nullptr);
+    }
+    LowerGSInfo *info = &it->second;
 
     // Get the source position from the metadata attached to the call
     // instruction so that we can issue PerformanceWarning()s below.
     SourcePos pos;
     bool gotPosition = LLVMGetSourcePosFromMetadata(callInst, &pos);
 
-    callInst->setCalledFunction(info->actualFunc);
+    callInst->setCalledFunction(info->actualFunc());
     // Check for alloca and if not alloca - generate __gather and change arguments
     if (gotPosition && (g->target->getVectorWidth() > 1) && (g->opt.level > 0)) {
-        if (info->isGather)
+        if (info->isGather())
             PerformanceWarning(pos, "Gather required to load value.");
-        else if (!info->isPrefetch)
+        else if (!info->isPrefetch())
             PerformanceWarning(pos, "Scatter required to store value.");
     }
     return true;
diff --git a/src/parse.yy b/src/parse.yy
index a341c59a11..9066e702bb 100644
--- a/src/parse.yy
+++ b/src/parse.yy
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2010-2023, Intel Corporation
+  Copyright (c) 2010-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -53,7 +53,7 @@ struct PragmaAttributes {
     int count;
 };
 
-typedef std::pair<Declarator *, std::vector<std::pair<const Type *, SourcePos>>*> SimpleTemplateIDType;
+typedef std::pair<Declarator *, TemplateArgs *> SimpleTemplateIDType;
 
 }
 
@@ -95,7 +95,7 @@ static void lSuggestParamListAlternates();
 
 static void lAddDeclaration(DeclSpecs *ds, Declarator *decl);
 static void lAddTemplateDeclaration(TemplateParms *templateParmList, DeclSpecs *ds, Declarator *decl);
-static void lAddTemplateSpecialization(const std::vector<std::pair<const Type *, SourcePos>> &types, DeclSpecs *ds, Declarator *decl);
+static void lAddTemplateSpecialization(const TemplateArgs &templArgs, DeclSpecs *ds, Declarator *decl);
 static void lAddFunctionParams(Declarator *decl);
 static void lAddMaskToSymbolTable(SourcePos pos);
 static void lAddThreadIndexCountToSymbolTable(SourcePos pos);
@@ -172,8 +172,11 @@ struct ForeachDimension {
     std::pair<std::string, SourcePos> *declspecPair;
     std::vector<std::pair<std::string, SourcePos> > *declspecList;
     PragmaAttributes *pragmaAttributes;
-    const TemplateTypeParmType *templateParm;
+    const TemplateArg *templateArg;
+    const TemplateArgs *templateArgs;
+    const TemplateParam *templateParm;
     TemplateParms *templateParmList;
+    const TemplateTypeParmType *templateTypeParm;
     TemplateSymbol *functionTemplateSym;
     SimpleTemplateIDType *simpleTemplateID;
 }
@@ -241,7 +244,7 @@ struct ForeachDimension {
 %type <structDeclarationList> struct_declaration_list
 
 %type <symbolList> enumerator_list
-%type <symbol> enumerator foreach_identifier foreach_active_identifier
+%type <symbol> enumerator foreach_identifier foreach_active_identifier template_int_parameter
 %type <enumType> enum_specifier
 
 %type <type> specifier_qualifier_list struct_or_union_specifier
@@ -269,9 +272,11 @@ struct ForeachDimension {
 %type <declspecList> declspec_specifier declspec_list
 
 %type <constCharPtr> template_identifier
-%type <typeList> template_argument_list
+%type <templateArg> template_argument
+%type <templateArgs> template_argument_list
 %type <simpleTemplateID> simple_template_id template_function_specialization_declaration
-%type <templateParm> template_type_parameter template_int_parameter template_parameter
+%type <templateTypeParm> template_type_parameter
+%type <templateParm> template_parameter
 %type <templateParmList> template_parameter_list template_head
 %type <functionTemplateSym> template_declaration
 
@@ -586,7 +591,7 @@ funcall_expression
           const std::string name = $1->first->name;
           m->symbolTable->LookupFunctionTemplate(name, &funcTempls);
           if (funcTempls.size() > 0) {
-              std::vector<std::pair<const Type *, SourcePos>> *templArgs = $1->second;
+              TemplateArgs *templArgs = $1->second;
               Assert(templArgs);
               functionSymbolExpr = new FunctionSymbolExpr(name.c_str(), funcTempls, *templArgs, @1);
               $$ = new FunctionCallExpr(functionSymbolExpr, new ExprList(Union(@1,@2)), Union(@1,@3));
@@ -606,7 +611,7 @@ funcall_expression
           const std::string name = $1->first->name;
           m->symbolTable->LookupFunctionTemplate(name, &funcTempls);
           if (funcTempls.size() > 0) {
-              std::vector<std::pair<const Type *, SourcePos>> *templArgs = $1->second;
+              TemplateArgs *templArgs = $1->second;
               Assert(templArgs);
               functionSymbolExpr = new FunctionSymbolExpr(name.c_str(), funcTempls, *templArgs, @1);
               $$ = new FunctionCallExpr(functionSymbolExpr, $3, Union(@1,@4));
@@ -2424,7 +2429,17 @@ template_int_parameter
 
 template_parameter
     : template_type_parameter
+      {
+        if ($1 != nullptr) {
+          $$ = new TemplateParam($1);
+        }
+      }
     | template_int_parameter
+      {
+        if ($1 != nullptr) {
+          $$ = new TemplateParam($1);
+        }
+      }
     ;
 
 template_parameter_list
@@ -2466,7 +2481,9 @@ template_declaration
           for(size_t i = 0; i < list->GetCount(); i++) {
               std::string name = (*list)[i]->GetName();
               SourcePos pos = (*list)[i]->GetSourcePos();
-              m->AddTypeDef(name, (*list)[i], pos);
+              if ((*list)[i]->IsTypeParam()) {
+                  m->AddTypeDef(name, (*list)[i]->GetTypeParam(), pos);
+              }
           }
       }
       declaration_specifiers declarator
@@ -2503,18 +2520,30 @@ template_function_declaration_or_definition
       }
     ;
 
-template_argument_list
+template_argument
     : rate_qualified_type_specifier
+    {
+        $$ = new TemplateArg($1, @1);
+    }
+    ;
+
+template_argument_list
+    : template_argument
       {
-          std::vector<std::pair<const Type *, SourcePos>> *vec = new std::vector<std::pair<const Type *, SourcePos>>;
-          vec->push_back(std::make_pair($1, @1));
-          $$ = vec;
+          TemplateArgs *templArgs = new TemplateArgs();
+          if ($1 != nullptr) {
+            templArgs->push_back(*$1);
+          }
+          $$ = templArgs;
+
       }
-    | template_argument_list ',' rate_qualified_type_specifier
+    | template_argument_list ',' template_argument
       {
-          std::vector<std::pair<const Type *, SourcePos>> *vec = (std::vector<std::pair<const Type *, SourcePos>> *) $1;
-          vec->push_back(std::make_pair($3, @3));
-          $$ = vec;
+          TemplateArgs *templArgs = (TemplateArgs *) $1;
+          if ($3 != nullptr) {
+            templArgs->push_back(*$3);
+          }
+          $$ = templArgs;
       }
     ;
 
@@ -2535,9 +2564,9 @@ simple_template_id
           // allocated by strdup in template_identifier
           free((char*)$1);
           // Arguments vector
-          std::vector<std::pair<const Type *, SourcePos>> *vec = (std::vector<std::pair<const Type *, SourcePos>> *) $3;
+          TemplateArgs *templArgs = (TemplateArgs *) $3;
           // Bundle template ID declarator and type list.
-          $$ = new std::pair(d, vec);
+          $$ = new std::pair(d, templArgs);
       }
     | template_identifier
       {
@@ -2547,9 +2576,9 @@ simple_template_id
           // allocated by strdup in template_identifier
           free((char*)$1);
           // Arguments vector
-          std::vector<std::pair<const Type *, SourcePos>> *vec = new std::vector<std::pair<const Type *, SourcePos>>;
+          TemplateArgs *templArgs = new TemplateArgs();
           // Bundle template ID declarator and empty type list.
-          $$ = new std::pair(d, vec);
+          $$ = new std::pair(d, templArgs);
       }
 
     ;
@@ -2624,7 +2653,7 @@ template_function_specialization_declaration
             // parameter_type_list returns vector of Declarations that is not needed anymore.
             delete $7;
         }
-        std::vector<std::pair<const Type *, SourcePos>> *templArgs = new std::vector<std::pair<const Type *, SourcePos>>(*$5->second);
+        TemplateArgs *templArgs = new TemplateArgs(*$5->second);
         Assert(templArgs);
         lAddTemplateSpecialization(*templArgs, $4, d);
         m->symbolTable->PushScope();
@@ -2639,7 +2668,7 @@ template_function_specialization_declaration
       {
         Declarator *d = new Declarator(DK_FUNCTION, Union(@1, @5));
         d->child = $5->first;
-        std::vector<std::pair<const Type *, SourcePos>> *templArgs = new std::vector<std::pair<const Type *, SourcePos>>(*$5->second);
+        TemplateArgs *templArgs = new TemplateArgs(*$5->second);
         Assert(templArgs);
         lAddTemplateSpecialization(*templArgs, $4, d);
         m->symbolTable->PushScope();
@@ -2704,7 +2733,7 @@ void lCleanUpString(std::string *s) {
 
 void lFreeSimpleTemplateID(void *p) {
     SimpleTemplateIDType *sid = (SimpleTemplateIDType*) p;
-    std::vector<std::pair<const Type *, SourcePos>> *templArgs = sid->second;
+    TemplateArgs *templArgs = sid->second;
     if (templArgs) {
         delete templArgs;
     }
@@ -2900,7 +2929,7 @@ lAddTemplateDeclaration(TemplateParms *templateParmList, DeclSpecs *ds, Declarat
 }
 
 static void
-lAddTemplateSpecialization(const std::vector<std::pair<const Type *, SourcePos>> &types, DeclSpecs *ds, Declarator *decl) {
+lAddTemplateSpecialization(const TemplateArgs &templArgs, DeclSpecs *ds, Declarator *decl) {
     if (ds == nullptr || decl == nullptr)
         // Error happened earlier during parsing
         return;
@@ -2913,7 +2942,7 @@ lAddTemplateSpecialization(const std::vector<std::pair<const Type *, SourcePos>>
         return;
     }
 
-    if (types.size() == 0) {
+    if (templArgs.size() == 0) {
         Error(decl->pos, "Template arguments deduction is not yet supported in template function specialization.");
         return;
     }
@@ -2922,7 +2951,7 @@ lAddTemplateSpecialization(const std::vector<std::pair<const Type *, SourcePos>>
     if (ftype != nullptr) {
         bool isInline = (ds->typeQualifiers & TYPEQUAL_INLINE);
         bool isNoInline = (ds->typeQualifiers & TYPEQUAL_NOINLINE);
-        m->AddFunctionTemplateSpecializationDeclaration(decl->name, ftype, types, ds->storageClass, 
+        m->AddFunctionTemplateSpecializationDeclaration(decl->name, ftype, templArgs, ds->storageClass,
                                                         isInline, isNoInline, decl->pos);
     }
     else {
diff --git a/src/stmt.cpp b/src/stmt.cpp
index b3f3722069..0c1d50e36d 100644
--- a/src/stmt.cpp
+++ b/src/stmt.cpp
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2010-2023, Intel Corporation
+  Copyright (c) 2010-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -9,6 +9,7 @@
 */
 
 #include "stmt.h"
+#include "builtins-decl.h"
 #include "builtins-info.h"
 #include "ctx.h"
 #include "expr.h"
@@ -2195,7 +2196,7 @@ void ForeachActiveStmt::EmitCode(FunctionEmitContext *ctx) const {
         llvm::Value *remainingBits = ctx->LoadInst(maskBitsPtrInfo, nullptr, "remaining_bits");
 
         // Find the index of the first set bit in the mask
-        llvm::Function *ctlzFunc = m->module->getFunction("__count_trailing_zeros_i64");
+        llvm::Function *ctlzFunc = m->module->getFunction(builtin::__count_trailing_zeros_i64);
         Assert(ctlzFunc != nullptr);
         llvm::Value *firstSet = ctx->CallInst(ctlzFunc, nullptr, remainingBits, "first_set");
 
@@ -2420,7 +2421,7 @@ void ForeachUniqueStmt::EmitCode(FunctionEmitContext *ctx) const {
         llvm::Value *remainingBits = ctx->LoadInst(maskBitsPtrInfo, nullptr, "remaining_bits");
 
         // Find the index of the first set bit in the mask
-        llvm::Function *ctlzFunc = m->module->getFunction("__count_trailing_zeros_i64");
+        llvm::Function *ctlzFunc = m->module->getFunction(builtin::__count_trailing_zeros_i64);
         Assert(ctlzFunc != nullptr);
         llvm::Value *firstSet = ctx->CallInst(ctlzFunc, nullptr, remainingBits, "first_set");
 
@@ -3280,7 +3281,7 @@ static ExprWithType lProcessPrintArgType(Expr *expr) {
 // Returns pointer to __do_print function
 static llvm::Function *getPrintImplFunc() {
     Assert(g->target->isXeTarget() == false);
-    llvm::Function *printImplFunc = m->module->getFunction("__do_print");
+    llvm::Function *printImplFunc = m->module->getFunction(builtin::__do_print);
     return printImplFunc;
 }
 
@@ -3803,8 +3804,8 @@ void AssertStmt::EmitAssertCode(FunctionEmitContext *ctx, const Type *type) cons
 
     // The actual functionality to do the check and then handle failure is
     // done via a builtin written in bitcode in builtins/util.m4.
-    llvm::Function *assertFunc =
-        isUniform ? m->module->getFunction("__do_assert_uniform") : m->module->getFunction("__do_assert_varying");
+    llvm::Function *assertFunc = isUniform ? m->module->getFunction(builtin::__do_assert_uniform)
+                                           : m->module->getFunction(builtin::__do_assert_varying);
     AssertPos(pos, assertFunc != nullptr);
 
     char *errorString;
@@ -3853,7 +3854,7 @@ void AssertStmt::EmitAssumeCode(FunctionEmitContext *ctx, const Type *type) cons
 
     // The actual functionality to insert an 'llvm.assume' intrinsic is
     // done via a builtin written in bitcode in builtins/util.m4.
-    llvm::Function *assumeFunc = m->module->getFunction("__do_assume_uniform");
+    llvm::Function *assumeFunc = m->module->getFunction(builtin::__do_assume_uniform);
     AssertPos(pos, assumeFunc != nullptr);
 
     llvm::Value *exprValue = expr->GetValue(ctx);
@@ -3950,9 +3951,9 @@ void DeleteStmt::EmitCode(FunctionEmitContext *ctx) const {
         exprValue = ctx->BitCastInst(exprValue, LLVMTypes::VoidPointerType, "ptr_to_void");
         llvm::Function *func;
         if (g->target->is32Bit()) {
-            func = m->module->getFunction("__delete_uniform_32rt");
+            func = m->module->getFunction(builtin::__delete_uniform_32rt);
         } else {
-            func = m->module->getFunction("__delete_uniform_64rt");
+            func = m->module->getFunction(builtin::__delete_uniform_64rt);
         }
         AssertPos(pos, func != nullptr);
 
@@ -3964,9 +3965,9 @@ void DeleteStmt::EmitCode(FunctionEmitContext *ctx) const {
         // calling it.
         llvm::Function *func;
         if (g->target->is32Bit()) {
-            func = m->module->getFunction("__delete_varying_32rt");
+            func = m->module->getFunction(builtin::__delete_varying_32rt);
         } else {
-            func = m->module->getFunction("__delete_varying_64rt");
+            func = m->module->getFunction(builtin::__delete_varying_64rt);
         }
         AssertPos(pos, func != nullptr);
         if (g->target->is32Bit())
diff --git a/src/type.cpp b/src/type.cpp
index f3ad52cf3e..6ba39beb8d 100644
--- a/src/type.cpp
+++ b/src/type.cpp
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2010-2023, Intel Corporation
+  Copyright (c) 2010-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -1013,7 +1013,11 @@ llvm::DIType *EnumType::GetDIType(llvm::DIScope *scope) const {
     llvm::DIType *underlyingType = AtomicType::UniformInt32->GetDIType(scope);
     llvm::DIType *diType =
         m->diBuilder->createEnumerationType(diSpace, GetString(), diFile, pos.first_line, 32 /* size in bits */,
-                                            32 /* align in bits */, elementArray, underlyingType, name);
+                                            32 /* align in bits */, elementArray, underlyingType,
+#if ISPC_LLVM_VERSION > ISPC_LLVM_17_0
+                                            0,
+#endif
+                                            name);
     switch (variability.type) {
     case Variability::Uniform:
         return diType;
@@ -2924,23 +2928,19 @@ const std::string FunctionType::GetReturnTypeString() const {
     return ret + returnType->GetString();
 }
 
-std::string FunctionType::mangleTemplateArgs(std::vector<const Type *> *templateArgs) const {
+std::string FunctionType::mangleTemplateArgs(TemplateArgs *templateArgs) const {
     if (templateArgs == nullptr) {
         return "";
     }
     std::string ret = "___";
-    for (const Type *arg : *templateArgs) {
-        if (arg) {
-            ret += arg->Mangle();
-        } else {
-            Assert(m->errorCount > 0);
-        }
+    for (const auto &arg : *templateArgs) {
+        ret += arg.Mangle();
     }
     return ret;
 }
 
 FunctionType::FunctionMangledName FunctionType::GetFunctionMangledName(bool appFunction,
-                                                                       std::vector<const Type *> *templateArgs) const {
+                                                                       TemplateArgs *templateArgs) const {
     FunctionMangledName mangle = {};
     // Mangle internal functions name.
     if (!(isExternC || isExternSYCL || appFunction)) {
diff --git a/src/type.h b/src/type.h
index fd1cd0fdac..9e487ade17 100644
--- a/src/type.h
+++ b/src/type.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2010-2023, Intel Corporation
+  Copyright (c) 2010-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -975,8 +975,7 @@ class FunctionType : public Type {
     /** This method returns the FunctionMangledName depending on Function type.
         The \c appFunction parameter indicates whether the function is generated for
         internal ISPC call or for external call from application.*/
-    FunctionMangledName GetFunctionMangledName(bool appFunction,
-                                               std::vector<const Type *> *templateArgs = nullptr) const;
+    FunctionMangledName GetFunctionMangledName(bool appFunction, TemplateArgs *templateArgs = nullptr) const;
 
     /** This method returns std::vector of LLVM types of function arguments.
         The \c disableMask parameter indicates whether the mask parameter should be
@@ -1037,7 +1036,7 @@ class FunctionType : public Type {
     int costOverride;
 
   private:
-    std::string mangleTemplateArgs(std::vector<const Type *> *templateArgs) const;
+    std::string mangleTemplateArgs(TemplateArgs *templateArgs) const;
 
     const Type *const returnType;
 
diff --git a/src/util.cpp b/src/util.cpp
index ebde480886..0feb16c72d 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2010-2023, Intel Corporation
+  Copyright (c) 2010-2024, Intel Corporation
 
   SPDX-License-Identifier: BSD-3-Clause
 */
@@ -47,12 +47,12 @@
 // See https://libcxx.llvm.org/UsingLibcxx.html#overriding-the-default-termination-handler
 // It is not quite clear why and where this symbol is used.
 void std::__libcpp_verbose_abort(char const *format, ...) {
-    std::va_list list;
+    va_list list;
     va_start(list, format);
-    std::vfprintf(stderr, format, list);
+    vfprintf(stderr, format, list);
     va_end(list);
 
-    std::abort();
+    abort();
 }
 #endif // ISPV_LLVM_17_0
 #endif // ISPC_HOST_IS_APPLE
diff --git a/tests/lit-tests/2752.ispc b/tests/lit-tests/2752.ispc
index d16ec46b55..625abb5a50 100644
--- a/tests/lit-tests/2752.ispc
+++ b/tests/lit-tests/2752.ispc
@@ -1,6 +1,8 @@
 // RUN: %{ispc} --target=host --nowrap --nostdlib -O2 --emit-llvm-text %s -o - | FileCheck %s --check-prefix=LLVM
 // RUN: %{ispc} --target=host --nowrap --nostdlib -O2 --emit-asm --x86-asm-syntax=intel %s -o - | FileCheck %s --check-prefix=ASM
 
+// REQUIRES: X86_ENABLED && !ARM_ENABLED
+
 // LLVM-LABEL: @set_ref(
 // LLVM-NEXT: allocas:
 // LLVM-NEXT: store i8 1, {{.*}} %result
diff --git a/tests/lit-tests/2753.ispc b/tests/lit-tests/2753.ispc
index 0571134644..6802bd3712 100644
--- a/tests/lit-tests/2753.ispc
+++ b/tests/lit-tests/2753.ispc
@@ -1,6 +1,8 @@
 // RUN: %{ispc} --target=host --nowrap --nostdlib -O2 --emit-asm --x86-asm-syntax=intel %s -o - | FileCheck %s --check-prefix=O2
 // RUN: %{ispc} --target=host --nowrap --nostdlib -O0 --emit-asm --x86-asm-syntax=intel %s -o - | FileCheck %s --check-prefix=O0
 
+// REQUIRES: X86_ENABLED && !ARM_ENABLED
+
 // O2-LABEL: set:
 // O2-NEXT:# %bb.0:
 // O2-NEXT:        mov     al, 1
diff --git a/tests/lit-tests/2754.ispc b/tests/lit-tests/2754.ispc
index a6ff7d1eed..187b53f3ae 100644
--- a/tests/lit-tests/2754.ispc
+++ b/tests/lit-tests/2754.ispc
@@ -10,7 +10,7 @@ varying float test_orig(uniform bool bCond, uniform float* uniform * uniform ptr
 // CHECK-LABEL: @test(
 // CHECK-NEXT: allocas:
 // CHECK-NEXT:   [[SELECT:%.*]] = select i1 %bCond, {{.*}} %a, {{.*}} %b
-// CHECK-NEXT:   [[PTR:%.*]] = getelementptr i32, {{.*}} [[SELECT]], i64 4
+// CHECK-NEXT:   [[PTR:%.*]] = getelementptr i{{(32|8)}}, {{.*}} [[SELECT]], i64 {{(4|16)}}
 // CHECK-NEXT:   [[LOAD:%.*]] = load i32, {{.*}} [[PTR]]
 // CHECK-NEXT:   ret i32 [[LOAD]]
 // CHECK-NEXT: }
diff --git a/tests/lit-tests/2777.ispc b/tests/lit-tests/2777.ispc
new file mode 100644
index 0000000000..ec7656629a
--- /dev/null
+++ b/tests/lit-tests/2777.ispc
@@ -0,0 +1,34 @@
+// RUN: %{ispc} %s --target=avx2-i32x8 --emit-asm -o - | FileCheck %s
+
+// REQUIRES: X86_ENABLED && LLVM_16_0+
+
+// XFAIL: *
+
+// CHECK-NOT: vmovd
+// CHECK-NOT: vpinsrd
+
+struct FVector4f
+{
+	float V[4];
+};
+
+// Extra vmovd, vpinsrd after 2x vmaxps
+inline uniform FVector4f VectorMax(const uniform FVector4f& V1, const uniform FVector4f& V2)
+{
+	varying float S0, S1, Result;
+	*((uniform FVector4f *uniform)&S0) = *((uniform FVector4f *uniform)&V1);
+	*((uniform FVector4f *uniform)&S1) = *((uniform FVector4f *uniform)&V2);
+
+	Result = max(S0, S1);
+
+	return *((uniform FVector4f *uniform)&Result);
+}
+
+export void foo(uniform float A[], uniform float B[])
+{
+
+	uniform FVector4f *uniform pA = (uniform FVector4f *uniform)A;
+	uniform FVector4f *uniform pB = (uniform FVector4f *uniform)B;
+
+        *pA = VectorMax(*pA, *pB);
+}
diff --git a/tests/lit-tests/bool-store-vector.ispc b/tests/lit-tests/bool-store-vector.ispc
index cc3eba94b6..676db4c207 100644
--- a/tests/lit-tests/bool-store-vector.ispc
+++ b/tests/lit-tests/bool-store-vector.ispc
@@ -1,5 +1,7 @@
 // RUN: %{ispc} --target=host --nowrap --nostdlib -O2 --emit-llvm-text %s -o - | FileCheck %s
 
+// REQUIRES: X86_ENABLED && !ARM_ENABLED
+
 uniform bool<4> x;
 
 // CHECK-LABEL: @foo___unT_3C_4_3E_unT_3C_4_3E_(
diff --git a/tests/lit-tests/ftz_daz_flags_x86.ispc b/tests/lit-tests/ftz_daz_flags_x86.ispc
index 98bbf604f6..8ab2e473bc 100644
--- a/tests/lit-tests/ftz_daz_flags_x86.ispc
+++ b/tests/lit-tests/ftz_daz_flags_x86.ispc
@@ -4,19 +4,19 @@
 // RUN: %{ispc} %s --target=avx2 --arch=x86 --nostdlib --emit-llvm-text --opt=reset-ftz-daz -o - | FileCheck %s
 // RUN: %{ispc} %s --target=avx2 --arch=x86 --nostdlib --emit-llvm-text -o - | FileCheck --check-prefixes=CHECK_NO_FTZ_DAZ %s
 
-// CHECK: define float @test_ftz_daz___
+// CHECK-LABEL: @test_ftz_daz___
 // CHECK-NOT: stmxcsr
 // CHECK-NOT: ldmxcsr
-// CHECK: define float @export_test_ftz_daz___
+// CHECK-LABEL: @export_test_ftz_daz___
 // CHECK-NOT: stmxcsr
 // CHECK-NOT: ldmxcsr
-// CHECK: define void @export_void_test_ftz_daz___
+// CHECK-LABEL: @export_void_test_ftz_daz___
 // CHECK-NOT: stmxcsr
 // CHECK-NOT: ldmxcsr
-// CHECK: define float @externC_test_ftz_daz()
+// CHECK-LABEL: @externC_test_ftz_daz()
 // CHECK: stmxcsr
 // CHECK-COUNT-2: ldmxcsr
-// CHECK: define float @export_test_ftz_daz(
+// CHECK-LABEL: @export_test_ftz_daz(
 // CHECK: stmxcsr
 // CHECK-COUNT-2: ldmxcsr
 
diff --git a/tests/lit-tests/ftz_daz_flags_x86_64.ispc b/tests/lit-tests/ftz_daz_flags_x86_64.ispc
index 36bc58fba8..e68ee0f011 100644
--- a/tests/lit-tests/ftz_daz_flags_x86_64.ispc
+++ b/tests/lit-tests/ftz_daz_flags_x86_64.ispc
@@ -4,19 +4,19 @@
 // RUN: %{ispc} %s --target=avx2 --arch=x86-64 --nostdlib --emit-llvm-text --opt=reset-ftz-daz -o - | FileCheck %s
 // RUN: %{ispc} %s --target=avx2 --arch=x86-64 --nostdlib --emit-llvm-text -o - | FileCheck --check-prefixes=CHECK_NO_FTZ_DAZ %s
 
-// CHECK: define float @test_ftz_daz___
+// CHECK-LABEL: @test_ftz_daz___
 // CHECK-NOT: stmxcsr
 // CHECK-NOT: ldmxcsr
-// CHECK: define float @export_test_ftz_daz___
+// CHECK-LABEL: @export_test_ftz_daz___
 // CHECK-NOT: stmxcsr
 // CHECK-NOT: ldmxcsr
-// CHECK: define void @export_void_test_ftz_daz___
+// CHECK-LABEL: @export_void_test_ftz_daz___
 // CHECK-NOT: stmxcsr
 // CHECK-NOT: ldmxcsr
-// CHECK: define float @externC_test_ftz_daz()
+// CHECK-LABEL: @externC_test_ftz_daz()
 // CHECK: stmxcsr
 // CHECK-COUNT-2: ldmxcsr
-// CHECK: define float @export_test_ftz_daz(
+// CHECK-LABEL: @export_test_ftz_daz(
 // CHECK: stmxcsr
 // CHECK-COUNT-2: ldmxcsr
 
