Skip to content

[DirectX] Add target builtins #134439

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 7, 2025
Merged

Conversation

farzonl
Copy link
Member

@farzonl farzonl commented Apr 4, 2025

  • fixes [DirectX] Create DX target builtins #132303
  • Moves dot2add from a language builtin to a target builtin.
  • Sets the scaffolding for Sema checks for DX builtins
  • Setup DirectX backend as able to have target builtins
  • Adds a DX TargetBuiltins emitter in clang/lib/CodeGen/TargetBuiltins/DirectX.cpp

@llvmbot llvmbot added clang Clang issues not falling into any other category backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang:codegen IR generation bugs: mangling, exceptions, etc. backend:DirectX HLSL HLSL Language Support labels Apr 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 4, 2025

@llvm/pr-subscribers-hlsl

@llvm/pr-subscribers-backend-directx

Author: Farzon Lotfi (farzonl)

Changes
  • fixes #132303
  • Moves dot2add from a language builtin to a target builtin.
  • Sets the scaffolding for Sema checks for DX builtins
  • Setup DirectX backend as able to have target builtins
  • Adds a DX TargetBuiltins emitter in clang/lib/CodeGen/TargetBuiltins/DirectX.cpp

Full diff: https://github.com/llvm/llvm-project/pull/134439.diff

20 Files Affected:

  • (modified) .github/new-prs-labeler.yml (+6)
  • (modified) clang/include/clang/Basic/Builtins.td (-6)
  • (added) clang/include/clang/Basic/BuiltinsDirectX.td (+15)
  • (modified) clang/include/clang/Basic/CMakeLists.txt (+4)
  • (modified) clang/include/clang/Basic/TargetBuiltins.h (+11)
  • (modified) clang/include/clang/Sema/Sema.h (+7)
  • (added) clang/include/clang/Sema/SemaDirectX.h (+29)
  • (modified) clang/lib/Basic/Targets/DirectX.cpp (+20)
  • (modified) clang/lib/Basic/Targets/DirectX.h (+1-3)
  • (modified) clang/lib/CodeGen/CGBuiltin.cpp (+2)
  • (modified) clang/lib/CodeGen/CGHLSLBuiltins.cpp (-12)
  • (modified) clang/lib/CodeGen/CMakeLists.txt (+1)
  • (modified) clang/lib/CodeGen/CodeGenFunction.h (+1)
  • (added) clang/lib/CodeGen/TargetBuiltins/DirectX.cpp (+37)
  • (modified) clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h (+2-2)
  • (modified) clang/lib/Sema/CMakeLists.txt (+1)
  • (modified) clang/lib/Sema/Sema.cpp (+2)
  • (modified) clang/lib/Sema/SemaChecking.cpp (+3)
  • (added) clang/lib/Sema/SemaDirectX.cpp (+23)
  • (added) clang/test/CodeGenDirectX/Builtins/dot2add.c (+23)
diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml
index b93cdff8af345..c0c61748010d0 100644
--- a/.github/new-prs-labeler.yml
+++ b/.github/new-prs-labeler.yml
@@ -660,6 +660,12 @@ backend:DirectX:
   - '**/*dxil*/**'
   - '**/*DXContainer*'
   - '**/*DXContainer*/**'
+  - clang/lib/Sema/SemaDirectX.cpp
+  - clang/include/clang/Sema/SemaDirectX.h
+  - clang/include/clang/Basic/BuiltinsDirectX.td
+  - clang/lib/CodeGen/TargetBuiltins/DirectX.cpp
+  - clang/test/CodeGenDirectX/**
+  - clang/test/SemaDirectX/**
 
 backend:SPIR-V:
   - clang/lib/Driver/ToolChains/SPIRV.*
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index c7ca607e4b3d2..b2c7ddb43de55 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4891,12 +4891,6 @@ def HLSLDotProduct : LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void(...)";
 }
 
-def HLSLDot2Add : LangBuiltin<"HLSL_LANG"> {
-  let Spellings = ["__builtin_hlsl_dot2add"];
-  let Attributes = [NoThrow, Const];
-  let Prototype = "float(_ExtVector<2, _Float16>, _ExtVector<2, _Float16>, float)";
-}
-
 def HLSLDot4AddI8Packed : LangBuiltin<"HLSL_LANG"> {
   let Spellings = ["__builtin_hlsl_dot4add_i8packed"];
   let Attributes = [NoThrow, Const];
diff --git a/clang/include/clang/Basic/BuiltinsDirectX.td b/clang/include/clang/Basic/BuiltinsDirectX.td
new file mode 100644
index 0000000000000..444532ab2874a
--- /dev/null
+++ b/clang/include/clang/Basic/BuiltinsDirectX.td
@@ -0,0 +1,15 @@
+//===--- BuiltinsDirectX.td - DirectX Builtin function database -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+include "clang/Basic/BuiltinsBase.td"
+
+def DxDot2Add : Builtin { 
+  let Spellings = ["__builtin_dx_dot2add"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "float(_ExtVector<2, _Float16>, _ExtVector<2, _Float16>, float)";
+}
diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt
index 6be6d063c20b4..4d5e1eaa3facb 100644
--- a/clang/include/clang/Basic/CMakeLists.txt
+++ b/clang/include/clang/Basic/CMakeLists.txt
@@ -82,6 +82,10 @@ clang_tablegen(BuiltinsBPF.inc -gen-clang-builtins
   SOURCE BuiltinsBPF.td
   TARGET ClangBuiltinsBPF)
 
+clang_tablegen(BuiltinsDirectX.inc -gen-clang-builtins
+  SOURCE BuiltinsDirectX.td
+  TARGET ClangBuiltinsDirectX)
+
 clang_tablegen(BuiltinsHexagon.inc -gen-clang-builtins
   SOURCE BuiltinsHexagon.td
   TARGET ClangBuiltinsHexagon)
diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h
index c1ba65064f159..4e490d87ee8d6 100644
--- a/clang/include/clang/Basic/TargetBuiltins.h
+++ b/clang/include/clang/Basic/TargetBuiltins.h
@@ -141,6 +141,17 @@ namespace clang {
   };
   }
 
+  /// DirectX builtins
+  namespace DirectX {
+  enum {
+    LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
+#define GET_BUILTIN_ENUMERATORS
+#include "clang/Basic/BuiltinsDirectX.inc"
+#undef GET_BUILTIN_ENUMERATORS
+    LastTSBuiltin
+  };
+  } // namespace DirectX
+
   /// SPIRV builtins
   namespace SPIRV {
   enum {
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6bf1caf6bdd18..30917e7ca0310 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -160,6 +160,7 @@ class SemaAVR;
 class SemaBPF;
 class SemaCodeCompletion;
 class SemaCUDA;
+class SemaDirectX;
 class SemaHLSL;
 class SemaHexagon;
 class SemaLoongArch;
@@ -1074,6 +1075,11 @@ class Sema final : public SemaBase {
     return *CUDAPtr;
   }
 
+  SemaDirectX &DirectX() {
+    assert(DirectXPtr);
+    return *DirectXPtr;
+  }
+
   SemaHLSL &HLSL() {
     assert(HLSLPtr);
     return *HLSLPtr;
@@ -1212,6 +1218,7 @@ class Sema final : public SemaBase {
   std::unique_ptr<SemaBPF> BPFPtr;
   std::unique_ptr<SemaCodeCompletion> CodeCompletionPtr;
   std::unique_ptr<SemaCUDA> CUDAPtr;
+  std::unique_ptr<SemaDirectX> DirectXPtr;
   std::unique_ptr<SemaHLSL> HLSLPtr;
   std::unique_ptr<SemaHexagon> HexagonPtr;
   std::unique_ptr<SemaLoongArch> LoongArchPtr;
diff --git a/clang/include/clang/Sema/SemaDirectX.h b/clang/include/clang/Sema/SemaDirectX.h
new file mode 100644
index 0000000000000..ae9cd61318714
--- /dev/null
+++ b/clang/include/clang/Sema/SemaDirectX.h
@@ -0,0 +1,29 @@
+//===----- SemaDirectX.h ----- Semantic Analysis for DirectX
+// constructs--------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares semantic analysis for DirectX constructs.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_SEMADIRECTX_H
+#define LLVM_CLANG_SEMA_SEMADIRECTX_H
+
+#include "clang/AST/ASTFwd.h"
+#include "clang/Sema/SemaBase.h"
+
+namespace clang {
+class SemaDirectX : public SemaBase {
+public:
+  SemaDirectX(Sema &S);
+
+  bool CheckDirectXBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SEMADIRECTX_H
\ No newline at end of file
diff --git a/clang/lib/Basic/Targets/DirectX.cpp b/clang/lib/Basic/Targets/DirectX.cpp
index 0dd27e6e93b33..ff0c062e80947 100644
--- a/clang/lib/Basic/Targets/DirectX.cpp
+++ b/clang/lib/Basic/Targets/DirectX.cpp
@@ -12,11 +12,31 @@
 
 #include "DirectX.h"
 #include "Targets.h"
+#include "clang/Basic/TargetBuiltins.h"
 
 using namespace clang;
 using namespace clang::targets;
 
+static constexpr int NumBuiltins =
+    clang::DirectX::LastTSBuiltin - Builtin::FirstTSBuiltin;
+
+#define GET_BUILTIN_STR_TABLE
+#include "clang/Basic/BuiltinsDirectX.inc"
+#undef GET_BUILTIN_STR_TABLE
+
+static constexpr Builtin::Info BuiltinInfos[] = {
+#define GET_BUILTIN_INFOS
+#include "clang/Basic/BuiltinsDirectX.inc"
+#undef GET_BUILTIN_INFOS
+};
+static_assert(std::size(BuiltinInfos) == NumBuiltins);
+
 void DirectXTargetInfo::getTargetDefines(const LangOptions &Opts,
                                          MacroBuilder &Builder) const {
   DefineStd(Builder, "DIRECTX", Opts);
 }
+
+llvm::SmallVector<Builtin::InfosShard>
+DirectXTargetInfo::getTargetBuiltins() const {
+  return {{&BuiltinStrings, BuiltinInfos}};
+}
\ No newline at end of file
diff --git a/clang/lib/Basic/Targets/DirectX.h b/clang/lib/Basic/Targets/DirectX.h
index 6e3ddad626341..0e88a37e32493 100644
--- a/clang/lib/Basic/Targets/DirectX.h
+++ b/clang/lib/Basic/Targets/DirectX.h
@@ -73,9 +73,7 @@ class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo {
     return Feature == "directx";
   }
 
-  llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override {
-    return {};
-  }
+  llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;
 
   std::string_view getClobbers() const override { return ""; }
 
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 310addebd50e9..fe55dfffc1cbe 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -70,6 +70,8 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
   case llvm::Triple::bpfeb:
   case llvm::Triple::bpfel:
     return CGF->EmitBPFBuiltinExpr(BuiltinID, E);
+  case llvm::Triple::dxil:
+    return CGF->EmitDirectXBuiltinExpr(BuiltinID, E);
   case llvm::Triple::x86:
   case llvm::Triple::x86_64:
     return CGF->EmitX86BuiltinExpr(BuiltinID, E);
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 27d1c69439944..99c62808c323d 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -380,18 +380,6 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
         getDotProductIntrinsic(CGM.getHLSLRuntime(), VecTy0->getElementType()),
         ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.dot");
   }
-  case Builtin::BI__builtin_hlsl_dot2add: {
-    assert(CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil &&
-           "Intrinsic dot2add is only allowed for dxil architecture");
-    Value *A = EmitScalarExpr(E->getArg(0));
-    Value *B = EmitScalarExpr(E->getArg(1));
-    Value *C = EmitScalarExpr(E->getArg(2));
-
-    Intrinsic::ID ID = llvm ::Intrinsic::dx_dot2add;
-    return Builder.CreateIntrinsic(
-        /*ReturnType=*/C->getType(), ID, ArrayRef<Value *>{A, B, C}, nullptr,
-        "dx.dot2add");
-  }
   case Builtin::BI__builtin_hlsl_dot4add_i8packed: {
     Value *A = EmitScalarExpr(E->getArg(0));
     Value *B = EmitScalarExpr(E->getArg(1));
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index ebe2fbd7db295..dc5b2a35583b4 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -118,6 +118,7 @@ add_clang_library(clangCodeGen
   SwiftCallingConv.cpp
   TargetBuiltins/ARM.cpp
   TargetBuiltins/AMDGPU.cpp
+  TargetBuiltins/DirectX.cpp
   TargetBuiltins/Hexagon.cpp
   TargetBuiltins/NVPTX.cpp
   TargetBuiltins/PPC.cpp
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index af9798b30fbcf..34dee6df9dcfc 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4809,6 +4809,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
   llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
                                    ReturnValueSlot ReturnValue);
+  llvm::Value *EmitDirectXBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
   llvm::Value *EmitSPIRVBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
   llvm::Value *EmitScalarOrConstFoldImmArg(unsigned ICEArguments, unsigned Idx,
                                            const CallExpr *E);
diff --git a/clang/lib/CodeGen/TargetBuiltins/DirectX.cpp b/clang/lib/CodeGen/TargetBuiltins/DirectX.cpp
new file mode 100644
index 0000000000000..202601e257036
--- /dev/null
+++ b/clang/lib/CodeGen/TargetBuiltins/DirectX.cpp
@@ -0,0 +1,37 @@
+//===--------- DirectX.cpp - Emit LLVM Code for builtins ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Builtin calls as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGHLSLRuntime.h"
+#include "CodeGenFunction.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/IR/Intrinsics.h"
+
+using namespace clang;
+using namespace CodeGen;
+using namespace llvm;
+
+Value *CodeGenFunction::EmitDirectXBuiltinExpr(unsigned BuiltinID,
+                                               const CallExpr *E) {
+  switch (BuiltinID) {
+  case DirectX::BI__builtin_dx_dot2add: {
+    Value *A = EmitScalarExpr(E->getArg(0));
+    Value *B = EmitScalarExpr(E->getArg(1));
+    Value *C = EmitScalarExpr(E->getArg(2));
+
+    Intrinsic::ID ID = llvm ::Intrinsic::dx_dot2add;
+    return Builder.CreateIntrinsic(
+        /*ReturnType=*/C->getType(), ID, ArrayRef<Value *>{A, B, C}, nullptr,
+        "dx.dot2add");
+  }
+  }
+  return nullptr;
+}
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
index 3c15f2b38d80f..a8f025b1b5f5f 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
@@ -46,8 +46,8 @@ distance_vec_impl(vector<T, N> X, vector<T, N> Y) {
 }
 
 constexpr float dot2add_impl(half2 a, half2 b, float c) {
-#if defined(__DIRECTX__)
-  return __builtin_hlsl_dot2add(a, b, c);
+#if (__has_builtin(__builtin_dx_dot2add))
+  return __builtin_dx_dot2add(a, b, c);
 #else
   return dot(a, b) + c;
 #endif
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index d3fe80f659f69..cc7921fc32254 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -47,6 +47,7 @@ add_clang_library(clangSema
   SemaConsumer.cpp
   SemaCoroutine.cpp
   SemaCUDA.cpp
+  SemaDirectX.cpp
   SemaDecl.cpp
   SemaDeclAttr.cpp
   SemaDeclCXX.cpp
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 64f5633f380ec..32d7744be9229 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -47,6 +47,7 @@
 #include "clang/Sema/SemaCUDA.h"
 #include "clang/Sema/SemaCodeCompletion.h"
 #include "clang/Sema/SemaConsumer.h"
+#include "clang/Sema/SemaDirectX.h"
 #include "clang/Sema/SemaHLSL.h"
 #include "clang/Sema/SemaHexagon.h"
 #include "clang/Sema/SemaLoongArch.h"
@@ -226,6 +227,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
       CodeCompletionPtr(
           std::make_unique<SemaCodeCompletion>(*this, CodeCompleter)),
       CUDAPtr(std::make_unique<SemaCUDA>(*this)),
+      DirectXPtr(std::make_unique<SemaDirectX>(*this)),
       HLSLPtr(std::make_unique<SemaHLSL>(*this)),
       HexagonPtr(std::make_unique<SemaHexagon>(*this)),
       LoongArchPtr(std::make_unique<SemaLoongArch>(*this)),
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 5a4fa97366809..674aa07992785 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -61,6 +61,7 @@
 #include "clang/Sema/SemaAMDGPU.h"
 #include "clang/Sema/SemaARM.h"
 #include "clang/Sema/SemaBPF.h"
+#include "clang/Sema/SemaDirectX.h"
 #include "clang/Sema/SemaHLSL.h"
 #include "clang/Sema/SemaHexagon.h"
 #include "clang/Sema/SemaLoongArch.h"
@@ -1930,6 +1931,8 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
   case llvm::Triple::bpfeb:
   case llvm::Triple::bpfel:
     return BPF().CheckBPFBuiltinFunctionCall(BuiltinID, TheCall);
+  case llvm::Triple::dxil:
+    return DirectX().CheckDirectXBuiltinFunctionCall(BuiltinID, TheCall);
   case llvm::Triple::hexagon:
     return Hexagon().CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall);
   case llvm::Triple::mips:
diff --git a/clang/lib/Sema/SemaDirectX.cpp b/clang/lib/Sema/SemaDirectX.cpp
new file mode 100644
index 0000000000000..eaac24cdc710e
--- /dev/null
+++ b/clang/lib/Sema/SemaDirectX.cpp
@@ -0,0 +1,23 @@
+//===- SemaDirectX.cpp - Semantic Analysis for DirectX constructs----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This implements Semantic Analysis for DirectX constructs.
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaDirectX.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Sema/Sema.h"
+
+namespace clang {
+
+SemaDirectX::SemaDirectX(Sema &S) : SemaBase(S) {}
+
+bool SemaDirectX::CheckDirectXBuiltinFunctionCall(unsigned BuiltinID,
+                                                  CallExpr *TheCall) {
+  return false;
+}
+} // namespace clang
diff --git a/clang/test/CodeGenDirectX/Builtins/dot2add.c b/clang/test/CodeGenDirectX/Builtins/dot2add.c
new file mode 100644
index 0000000000000..181f61fea1544
--- /dev/null
+++ b/clang/test/CodeGenDirectX/Builtins/dot2add.c
@@ -0,0 +1,23 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -o - | FileCheck %s
+
+typedef _Float16 half;
+typedef half half2 __attribute__((ext_vector_type(2)));
+
+// CHECK-LABEL: define float @test_dot2add(
+// CHECK-SAME: <2 x half> noundef [[X:%.*]], <2 x half> noundef [[Y:%.*]], float noundef [[Z:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[X_ADDR:%.*]] = alloca <2 x half>, align 4
+// CHECK-NEXT:    [[Y_ADDR:%.*]] = alloca <2 x half>, align 4
+// CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT:    store <2 x half> [[X]], ptr [[X_ADDR]], align 4
+// CHECK-NEXT:    store <2 x half> [[Y]], ptr [[Y_ADDR]], align 4
+// CHECK-NEXT:    store float [[Z]], ptr [[Z_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load <2 x half>, ptr [[X_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load <2 x half>, ptr [[Y_ADDR]], align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = load float, ptr [[Z_ADDR]], align 4
+// CHECK-NEXT:    [[DX_DOT2ADD:%.*]] = call float @llvm.dx.dot2add.v2f16(<2 x half> [[TMP0]], <2 x half> [[TMP1]], float [[TMP2]])
+// CHECK-NEXT:    ret float [[DX_DOT2ADD]]
+//
+float test_dot2add(half2 X, half2 Y, float Z) { return __builtin_dx_dot2add(X, Y, Z); }

@llvmbot
Copy link
Member

llvmbot commented Apr 4, 2025

@llvm/pr-subscribers-backend-x86

Author: Farzon Lotfi (farzonl)

Changes
  • fixes #132303
  • Moves dot2add from a language builtin to a target builtin.
  • Sets the scaffolding for Sema checks for DX builtins
  • Setup DirectX backend as able to have target builtins
  • Adds a DX TargetBuiltins emitter in clang/lib/CodeGen/TargetBuiltins/DirectX.cpp

Full diff: https://github.com/llvm/llvm-project/pull/134439.diff

20 Files Affected:

  • (modified) .github/new-prs-labeler.yml (+6)
  • (modified) clang/include/clang/Basic/Builtins.td (-6)
  • (added) clang/include/clang/Basic/BuiltinsDirectX.td (+15)
  • (modified) clang/include/clang/Basic/CMakeLists.txt (+4)
  • (modified) clang/include/clang/Basic/TargetBuiltins.h (+11)
  • (modified) clang/include/clang/Sema/Sema.h (+7)
  • (added) clang/include/clang/Sema/SemaDirectX.h (+29)
  • (modified) clang/lib/Basic/Targets/DirectX.cpp (+20)
  • (modified) clang/lib/Basic/Targets/DirectX.h (+1-3)
  • (modified) clang/lib/CodeGen/CGBuiltin.cpp (+2)
  • (modified) clang/lib/CodeGen/CGHLSLBuiltins.cpp (-12)
  • (modified) clang/lib/CodeGen/CMakeLists.txt (+1)
  • (modified) clang/lib/CodeGen/CodeGenFunction.h (+1)
  • (added) clang/lib/CodeGen/TargetBuiltins/DirectX.cpp (+37)
  • (modified) clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h (+2-2)
  • (modified) clang/lib/Sema/CMakeLists.txt (+1)
  • (modified) clang/lib/Sema/Sema.cpp (+2)
  • (modified) clang/lib/Sema/SemaChecking.cpp (+3)
  • (added) clang/lib/Sema/SemaDirectX.cpp (+23)
  • (added) clang/test/CodeGenDirectX/Builtins/dot2add.c (+23)
diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml
index b93cdff8af345..c0c61748010d0 100644
--- a/.github/new-prs-labeler.yml
+++ b/.github/new-prs-labeler.yml
@@ -660,6 +660,12 @@ backend:DirectX:
   - '**/*dxil*/**'
   - '**/*DXContainer*'
   - '**/*DXContainer*/**'
+  - clang/lib/Sema/SemaDirectX.cpp
+  - clang/include/clang/Sema/SemaDirectX.h
+  - clang/include/clang/Basic/BuiltinsDirectX.td
+  - clang/lib/CodeGen/TargetBuiltins/DirectX.cpp
+  - clang/test/CodeGenDirectX/**
+  - clang/test/SemaDirectX/**
 
 backend:SPIR-V:
   - clang/lib/Driver/ToolChains/SPIRV.*
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index c7ca607e4b3d2..b2c7ddb43de55 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4891,12 +4891,6 @@ def HLSLDotProduct : LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void(...)";
 }
 
-def HLSLDot2Add : LangBuiltin<"HLSL_LANG"> {
-  let Spellings = ["__builtin_hlsl_dot2add"];
-  let Attributes = [NoThrow, Const];
-  let Prototype = "float(_ExtVector<2, _Float16>, _ExtVector<2, _Float16>, float)";
-}
-
 def HLSLDot4AddI8Packed : LangBuiltin<"HLSL_LANG"> {
   let Spellings = ["__builtin_hlsl_dot4add_i8packed"];
   let Attributes = [NoThrow, Const];
diff --git a/clang/include/clang/Basic/BuiltinsDirectX.td b/clang/include/clang/Basic/BuiltinsDirectX.td
new file mode 100644
index 0000000000000..444532ab2874a
--- /dev/null
+++ b/clang/include/clang/Basic/BuiltinsDirectX.td
@@ -0,0 +1,15 @@
+//===--- BuiltinsDirectX.td - DirectX Builtin function database -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+include "clang/Basic/BuiltinsBase.td"
+
+def DxDot2Add : Builtin { 
+  let Spellings = ["__builtin_dx_dot2add"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "float(_ExtVector<2, _Float16>, _ExtVector<2, _Float16>, float)";
+}
diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt
index 6be6d063c20b4..4d5e1eaa3facb 100644
--- a/clang/include/clang/Basic/CMakeLists.txt
+++ b/clang/include/clang/Basic/CMakeLists.txt
@@ -82,6 +82,10 @@ clang_tablegen(BuiltinsBPF.inc -gen-clang-builtins
   SOURCE BuiltinsBPF.td
   TARGET ClangBuiltinsBPF)
 
+clang_tablegen(BuiltinsDirectX.inc -gen-clang-builtins
+  SOURCE BuiltinsDirectX.td
+  TARGET ClangBuiltinsDirectX)
+
 clang_tablegen(BuiltinsHexagon.inc -gen-clang-builtins
   SOURCE BuiltinsHexagon.td
   TARGET ClangBuiltinsHexagon)
diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h
index c1ba65064f159..4e490d87ee8d6 100644
--- a/clang/include/clang/Basic/TargetBuiltins.h
+++ b/clang/include/clang/Basic/TargetBuiltins.h
@@ -141,6 +141,17 @@ namespace clang {
   };
   }
 
+  /// DirectX builtins
+  namespace DirectX {
+  enum {
+    LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
+#define GET_BUILTIN_ENUMERATORS
+#include "clang/Basic/BuiltinsDirectX.inc"
+#undef GET_BUILTIN_ENUMERATORS
+    LastTSBuiltin
+  };
+  } // namespace DirectX
+
   /// SPIRV builtins
   namespace SPIRV {
   enum {
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6bf1caf6bdd18..30917e7ca0310 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -160,6 +160,7 @@ class SemaAVR;
 class SemaBPF;
 class SemaCodeCompletion;
 class SemaCUDA;
+class SemaDirectX;
 class SemaHLSL;
 class SemaHexagon;
 class SemaLoongArch;
@@ -1074,6 +1075,11 @@ class Sema final : public SemaBase {
     return *CUDAPtr;
   }
 
+  SemaDirectX &DirectX() {
+    assert(DirectXPtr);
+    return *DirectXPtr;
+  }
+
   SemaHLSL &HLSL() {
     assert(HLSLPtr);
     return *HLSLPtr;
@@ -1212,6 +1218,7 @@ class Sema final : public SemaBase {
   std::unique_ptr<SemaBPF> BPFPtr;
   std::unique_ptr<SemaCodeCompletion> CodeCompletionPtr;
   std::unique_ptr<SemaCUDA> CUDAPtr;
+  std::unique_ptr<SemaDirectX> DirectXPtr;
   std::unique_ptr<SemaHLSL> HLSLPtr;
   std::unique_ptr<SemaHexagon> HexagonPtr;
   std::unique_ptr<SemaLoongArch> LoongArchPtr;
diff --git a/clang/include/clang/Sema/SemaDirectX.h b/clang/include/clang/Sema/SemaDirectX.h
new file mode 100644
index 0000000000000..ae9cd61318714
--- /dev/null
+++ b/clang/include/clang/Sema/SemaDirectX.h
@@ -0,0 +1,29 @@
+//===----- SemaDirectX.h ----- Semantic Analysis for DirectX
+// constructs--------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares semantic analysis for DirectX constructs.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_SEMADIRECTX_H
+#define LLVM_CLANG_SEMA_SEMADIRECTX_H
+
+#include "clang/AST/ASTFwd.h"
+#include "clang/Sema/SemaBase.h"
+
+namespace clang {
+class SemaDirectX : public SemaBase {
+public:
+  SemaDirectX(Sema &S);
+
+  bool CheckDirectXBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SEMADIRECTX_H
\ No newline at end of file
diff --git a/clang/lib/Basic/Targets/DirectX.cpp b/clang/lib/Basic/Targets/DirectX.cpp
index 0dd27e6e93b33..ff0c062e80947 100644
--- a/clang/lib/Basic/Targets/DirectX.cpp
+++ b/clang/lib/Basic/Targets/DirectX.cpp
@@ -12,11 +12,31 @@
 
 #include "DirectX.h"
 #include "Targets.h"
+#include "clang/Basic/TargetBuiltins.h"
 
 using namespace clang;
 using namespace clang::targets;
 
+static constexpr int NumBuiltins =
+    clang::DirectX::LastTSBuiltin - Builtin::FirstTSBuiltin;
+
+#define GET_BUILTIN_STR_TABLE
+#include "clang/Basic/BuiltinsDirectX.inc"
+#undef GET_BUILTIN_STR_TABLE
+
+static constexpr Builtin::Info BuiltinInfos[] = {
+#define GET_BUILTIN_INFOS
+#include "clang/Basic/BuiltinsDirectX.inc"
+#undef GET_BUILTIN_INFOS
+};
+static_assert(std::size(BuiltinInfos) == NumBuiltins);
+
 void DirectXTargetInfo::getTargetDefines(const LangOptions &Opts,
                                          MacroBuilder &Builder) const {
   DefineStd(Builder, "DIRECTX", Opts);
 }
+
+llvm::SmallVector<Builtin::InfosShard>
+DirectXTargetInfo::getTargetBuiltins() const {
+  return {{&BuiltinStrings, BuiltinInfos}};
+}
\ No newline at end of file
diff --git a/clang/lib/Basic/Targets/DirectX.h b/clang/lib/Basic/Targets/DirectX.h
index 6e3ddad626341..0e88a37e32493 100644
--- a/clang/lib/Basic/Targets/DirectX.h
+++ b/clang/lib/Basic/Targets/DirectX.h
@@ -73,9 +73,7 @@ class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo {
     return Feature == "directx";
   }
 
-  llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override {
-    return {};
-  }
+  llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;
 
   std::string_view getClobbers() const override { return ""; }
 
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 310addebd50e9..fe55dfffc1cbe 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -70,6 +70,8 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
   case llvm::Triple::bpfeb:
   case llvm::Triple::bpfel:
     return CGF->EmitBPFBuiltinExpr(BuiltinID, E);
+  case llvm::Triple::dxil:
+    return CGF->EmitDirectXBuiltinExpr(BuiltinID, E);
   case llvm::Triple::x86:
   case llvm::Triple::x86_64:
     return CGF->EmitX86BuiltinExpr(BuiltinID, E);
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 27d1c69439944..99c62808c323d 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -380,18 +380,6 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
         getDotProductIntrinsic(CGM.getHLSLRuntime(), VecTy0->getElementType()),
         ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.dot");
   }
-  case Builtin::BI__builtin_hlsl_dot2add: {
-    assert(CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil &&
-           "Intrinsic dot2add is only allowed for dxil architecture");
-    Value *A = EmitScalarExpr(E->getArg(0));
-    Value *B = EmitScalarExpr(E->getArg(1));
-    Value *C = EmitScalarExpr(E->getArg(2));
-
-    Intrinsic::ID ID = llvm ::Intrinsic::dx_dot2add;
-    return Builder.CreateIntrinsic(
-        /*ReturnType=*/C->getType(), ID, ArrayRef<Value *>{A, B, C}, nullptr,
-        "dx.dot2add");
-  }
   case Builtin::BI__builtin_hlsl_dot4add_i8packed: {
     Value *A = EmitScalarExpr(E->getArg(0));
     Value *B = EmitScalarExpr(E->getArg(1));
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index ebe2fbd7db295..dc5b2a35583b4 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -118,6 +118,7 @@ add_clang_library(clangCodeGen
   SwiftCallingConv.cpp
   TargetBuiltins/ARM.cpp
   TargetBuiltins/AMDGPU.cpp
+  TargetBuiltins/DirectX.cpp
   TargetBuiltins/Hexagon.cpp
   TargetBuiltins/NVPTX.cpp
   TargetBuiltins/PPC.cpp
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index af9798b30fbcf..34dee6df9dcfc 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4809,6 +4809,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
   llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
                                    ReturnValueSlot ReturnValue);
+  llvm::Value *EmitDirectXBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
   llvm::Value *EmitSPIRVBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
   llvm::Value *EmitScalarOrConstFoldImmArg(unsigned ICEArguments, unsigned Idx,
                                            const CallExpr *E);
diff --git a/clang/lib/CodeGen/TargetBuiltins/DirectX.cpp b/clang/lib/CodeGen/TargetBuiltins/DirectX.cpp
new file mode 100644
index 0000000000000..202601e257036
--- /dev/null
+++ b/clang/lib/CodeGen/TargetBuiltins/DirectX.cpp
@@ -0,0 +1,37 @@
+//===--------- DirectX.cpp - Emit LLVM Code for builtins ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Builtin calls as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGHLSLRuntime.h"
+#include "CodeGenFunction.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/IR/Intrinsics.h"
+
+using namespace clang;
+using namespace CodeGen;
+using namespace llvm;
+
+Value *CodeGenFunction::EmitDirectXBuiltinExpr(unsigned BuiltinID,
+                                               const CallExpr *E) {
+  switch (BuiltinID) {
+  case DirectX::BI__builtin_dx_dot2add: {
+    Value *A = EmitScalarExpr(E->getArg(0));
+    Value *B = EmitScalarExpr(E->getArg(1));
+    Value *C = EmitScalarExpr(E->getArg(2));
+
+    Intrinsic::ID ID = llvm ::Intrinsic::dx_dot2add;
+    return Builder.CreateIntrinsic(
+        /*ReturnType=*/C->getType(), ID, ArrayRef<Value *>{A, B, C}, nullptr,
+        "dx.dot2add");
+  }
+  }
+  return nullptr;
+}
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
index 3c15f2b38d80f..a8f025b1b5f5f 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
@@ -46,8 +46,8 @@ distance_vec_impl(vector<T, N> X, vector<T, N> Y) {
 }
 
 constexpr float dot2add_impl(half2 a, half2 b, float c) {
-#if defined(__DIRECTX__)
-  return __builtin_hlsl_dot2add(a, b, c);
+#if (__has_builtin(__builtin_dx_dot2add))
+  return __builtin_dx_dot2add(a, b, c);
 #else
   return dot(a, b) + c;
 #endif
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index d3fe80f659f69..cc7921fc32254 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -47,6 +47,7 @@ add_clang_library(clangSema
   SemaConsumer.cpp
   SemaCoroutine.cpp
   SemaCUDA.cpp
+  SemaDirectX.cpp
   SemaDecl.cpp
   SemaDeclAttr.cpp
   SemaDeclCXX.cpp
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 64f5633f380ec..32d7744be9229 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -47,6 +47,7 @@
 #include "clang/Sema/SemaCUDA.h"
 #include "clang/Sema/SemaCodeCompletion.h"
 #include "clang/Sema/SemaConsumer.h"
+#include "clang/Sema/SemaDirectX.h"
 #include "clang/Sema/SemaHLSL.h"
 #include "clang/Sema/SemaHexagon.h"
 #include "clang/Sema/SemaLoongArch.h"
@@ -226,6 +227,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
       CodeCompletionPtr(
           std::make_unique<SemaCodeCompletion>(*this, CodeCompleter)),
       CUDAPtr(std::make_unique<SemaCUDA>(*this)),
+      DirectXPtr(std::make_unique<SemaDirectX>(*this)),
       HLSLPtr(std::make_unique<SemaHLSL>(*this)),
       HexagonPtr(std::make_unique<SemaHexagon>(*this)),
       LoongArchPtr(std::make_unique<SemaLoongArch>(*this)),
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 5a4fa97366809..674aa07992785 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -61,6 +61,7 @@
 #include "clang/Sema/SemaAMDGPU.h"
 #include "clang/Sema/SemaARM.h"
 #include "clang/Sema/SemaBPF.h"
+#include "clang/Sema/SemaDirectX.h"
 #include "clang/Sema/SemaHLSL.h"
 #include "clang/Sema/SemaHexagon.h"
 #include "clang/Sema/SemaLoongArch.h"
@@ -1930,6 +1931,8 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
   case llvm::Triple::bpfeb:
   case llvm::Triple::bpfel:
     return BPF().CheckBPFBuiltinFunctionCall(BuiltinID, TheCall);
+  case llvm::Triple::dxil:
+    return DirectX().CheckDirectXBuiltinFunctionCall(BuiltinID, TheCall);
   case llvm::Triple::hexagon:
     return Hexagon().CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall);
   case llvm::Triple::mips:
diff --git a/clang/lib/Sema/SemaDirectX.cpp b/clang/lib/Sema/SemaDirectX.cpp
new file mode 100644
index 0000000000000..eaac24cdc710e
--- /dev/null
+++ b/clang/lib/Sema/SemaDirectX.cpp
@@ -0,0 +1,23 @@
+//===- SemaDirectX.cpp - Semantic Analysis for DirectX constructs----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This implements Semantic Analysis for DirectX constructs.
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaDirectX.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Sema/Sema.h"
+
+namespace clang {
+
+SemaDirectX::SemaDirectX(Sema &S) : SemaBase(S) {}
+
+bool SemaDirectX::CheckDirectXBuiltinFunctionCall(unsigned BuiltinID,
+                                                  CallExpr *TheCall) {
+  return false;
+}
+} // namespace clang
diff --git a/clang/test/CodeGenDirectX/Builtins/dot2add.c b/clang/test/CodeGenDirectX/Builtins/dot2add.c
new file mode 100644
index 0000000000000..181f61fea1544
--- /dev/null
+++ b/clang/test/CodeGenDirectX/Builtins/dot2add.c
@@ -0,0 +1,23 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -o - | FileCheck %s
+
+typedef _Float16 half;
+typedef half half2 __attribute__((ext_vector_type(2)));
+
+// CHECK-LABEL: define float @test_dot2add(
+// CHECK-SAME: <2 x half> noundef [[X:%.*]], <2 x half> noundef [[Y:%.*]], float noundef [[Z:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[X_ADDR:%.*]] = alloca <2 x half>, align 4
+// CHECK-NEXT:    [[Y_ADDR:%.*]] = alloca <2 x half>, align 4
+// CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT:    store <2 x half> [[X]], ptr [[X_ADDR]], align 4
+// CHECK-NEXT:    store <2 x half> [[Y]], ptr [[Y_ADDR]], align 4
+// CHECK-NEXT:    store float [[Z]], ptr [[Z_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load <2 x half>, ptr [[X_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load <2 x half>, ptr [[Y_ADDR]], align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = load float, ptr [[Z_ADDR]], align 4
+// CHECK-NEXT:    [[DX_DOT2ADD:%.*]] = call float @llvm.dx.dot2add.v2f16(<2 x half> [[TMP0]], <2 x half> [[TMP1]], float [[TMP2]])
+// CHECK-NEXT:    ret float [[DX_DOT2ADD]]
+//
+float test_dot2add(half2 X, half2 Y, float Z) { return __builtin_dx_dot2add(X, Y, Z); }

@llvmbot
Copy link
Member

llvmbot commented Apr 4, 2025

@llvm/pr-subscribers-clang-codegen

Author: Farzon Lotfi (farzonl)

Changes
  • fixes #132303
  • Moves dot2add from a language builtin to a target builtin.
  • Sets the scaffolding for Sema checks for DX builtins
  • Setup DirectX backend as able to have target builtins
  • Adds a DX TargetBuiltins emitter in clang/lib/CodeGen/TargetBuiltins/DirectX.cpp

Full diff: https://github.com/llvm/llvm-project/pull/134439.diff

20 Files Affected:

  • (modified) .github/new-prs-labeler.yml (+6)
  • (modified) clang/include/clang/Basic/Builtins.td (-6)
  • (added) clang/include/clang/Basic/BuiltinsDirectX.td (+15)
  • (modified) clang/include/clang/Basic/CMakeLists.txt (+4)
  • (modified) clang/include/clang/Basic/TargetBuiltins.h (+11)
  • (modified) clang/include/clang/Sema/Sema.h (+7)
  • (added) clang/include/clang/Sema/SemaDirectX.h (+29)
  • (modified) clang/lib/Basic/Targets/DirectX.cpp (+20)
  • (modified) clang/lib/Basic/Targets/DirectX.h (+1-3)
  • (modified) clang/lib/CodeGen/CGBuiltin.cpp (+2)
  • (modified) clang/lib/CodeGen/CGHLSLBuiltins.cpp (-12)
  • (modified) clang/lib/CodeGen/CMakeLists.txt (+1)
  • (modified) clang/lib/CodeGen/CodeGenFunction.h (+1)
  • (added) clang/lib/CodeGen/TargetBuiltins/DirectX.cpp (+37)
  • (modified) clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h (+2-2)
  • (modified) clang/lib/Sema/CMakeLists.txt (+1)
  • (modified) clang/lib/Sema/Sema.cpp (+2)
  • (modified) clang/lib/Sema/SemaChecking.cpp (+3)
  • (added) clang/lib/Sema/SemaDirectX.cpp (+23)
  • (added) clang/test/CodeGenDirectX/Builtins/dot2add.c (+23)
diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml
index b93cdff8af345..c0c61748010d0 100644
--- a/.github/new-prs-labeler.yml
+++ b/.github/new-prs-labeler.yml
@@ -660,6 +660,12 @@ backend:DirectX:
   - '**/*dxil*/**'
   - '**/*DXContainer*'
   - '**/*DXContainer*/**'
+  - clang/lib/Sema/SemaDirectX.cpp
+  - clang/include/clang/Sema/SemaDirectX.h
+  - clang/include/clang/Basic/BuiltinsDirectX.td
+  - clang/lib/CodeGen/TargetBuiltins/DirectX.cpp
+  - clang/test/CodeGenDirectX/**
+  - clang/test/SemaDirectX/**
 
 backend:SPIR-V:
   - clang/lib/Driver/ToolChains/SPIRV.*
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index c7ca607e4b3d2..b2c7ddb43de55 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4891,12 +4891,6 @@ def HLSLDotProduct : LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void(...)";
 }
 
-def HLSLDot2Add : LangBuiltin<"HLSL_LANG"> {
-  let Spellings = ["__builtin_hlsl_dot2add"];
-  let Attributes = [NoThrow, Const];
-  let Prototype = "float(_ExtVector<2, _Float16>, _ExtVector<2, _Float16>, float)";
-}
-
 def HLSLDot4AddI8Packed : LangBuiltin<"HLSL_LANG"> {
   let Spellings = ["__builtin_hlsl_dot4add_i8packed"];
   let Attributes = [NoThrow, Const];
diff --git a/clang/include/clang/Basic/BuiltinsDirectX.td b/clang/include/clang/Basic/BuiltinsDirectX.td
new file mode 100644
index 0000000000000..444532ab2874a
--- /dev/null
+++ b/clang/include/clang/Basic/BuiltinsDirectX.td
@@ -0,0 +1,15 @@
+//===--- BuiltinsDirectX.td - DirectX Builtin function database -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+include "clang/Basic/BuiltinsBase.td"
+
+def DxDot2Add : Builtin { 
+  let Spellings = ["__builtin_dx_dot2add"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "float(_ExtVector<2, _Float16>, _ExtVector<2, _Float16>, float)";
+}
diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt
index 6be6d063c20b4..4d5e1eaa3facb 100644
--- a/clang/include/clang/Basic/CMakeLists.txt
+++ b/clang/include/clang/Basic/CMakeLists.txt
@@ -82,6 +82,10 @@ clang_tablegen(BuiltinsBPF.inc -gen-clang-builtins
   SOURCE BuiltinsBPF.td
   TARGET ClangBuiltinsBPF)
 
+clang_tablegen(BuiltinsDirectX.inc -gen-clang-builtins
+  SOURCE BuiltinsDirectX.td
+  TARGET ClangBuiltinsDirectX)
+
 clang_tablegen(BuiltinsHexagon.inc -gen-clang-builtins
   SOURCE BuiltinsHexagon.td
   TARGET ClangBuiltinsHexagon)
diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h
index c1ba65064f159..4e490d87ee8d6 100644
--- a/clang/include/clang/Basic/TargetBuiltins.h
+++ b/clang/include/clang/Basic/TargetBuiltins.h
@@ -141,6 +141,17 @@ namespace clang {
   };
   }
 
+  /// DirectX builtins
+  namespace DirectX {
+  enum {
+    LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
+#define GET_BUILTIN_ENUMERATORS
+#include "clang/Basic/BuiltinsDirectX.inc"
+#undef GET_BUILTIN_ENUMERATORS
+    LastTSBuiltin
+  };
+  } // namespace DirectX
+
   /// SPIRV builtins
   namespace SPIRV {
   enum {
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6bf1caf6bdd18..30917e7ca0310 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -160,6 +160,7 @@ class SemaAVR;
 class SemaBPF;
 class SemaCodeCompletion;
 class SemaCUDA;
+class SemaDirectX;
 class SemaHLSL;
 class SemaHexagon;
 class SemaLoongArch;
@@ -1074,6 +1075,11 @@ class Sema final : public SemaBase {
     return *CUDAPtr;
   }
 
+  SemaDirectX &DirectX() {
+    assert(DirectXPtr);
+    return *DirectXPtr;
+  }
+
   SemaHLSL &HLSL() {
     assert(HLSLPtr);
     return *HLSLPtr;
@@ -1212,6 +1218,7 @@ class Sema final : public SemaBase {
   std::unique_ptr<SemaBPF> BPFPtr;
   std::unique_ptr<SemaCodeCompletion> CodeCompletionPtr;
   std::unique_ptr<SemaCUDA> CUDAPtr;
+  std::unique_ptr<SemaDirectX> DirectXPtr;
   std::unique_ptr<SemaHLSL> HLSLPtr;
   std::unique_ptr<SemaHexagon> HexagonPtr;
   std::unique_ptr<SemaLoongArch> LoongArchPtr;
diff --git a/clang/include/clang/Sema/SemaDirectX.h b/clang/include/clang/Sema/SemaDirectX.h
new file mode 100644
index 0000000000000..ae9cd61318714
--- /dev/null
+++ b/clang/include/clang/Sema/SemaDirectX.h
@@ -0,0 +1,29 @@
+//===----- SemaDirectX.h ----- Semantic Analysis for DirectX
+// constructs--------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares semantic analysis for DirectX constructs.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_SEMADIRECTX_H
+#define LLVM_CLANG_SEMA_SEMADIRECTX_H
+
+#include "clang/AST/ASTFwd.h"
+#include "clang/Sema/SemaBase.h"
+
+namespace clang {
+class SemaDirectX : public SemaBase {
+public:
+  SemaDirectX(Sema &S);
+
+  bool CheckDirectXBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SEMADIRECTX_H
\ No newline at end of file
diff --git a/clang/lib/Basic/Targets/DirectX.cpp b/clang/lib/Basic/Targets/DirectX.cpp
index 0dd27e6e93b33..ff0c062e80947 100644
--- a/clang/lib/Basic/Targets/DirectX.cpp
+++ b/clang/lib/Basic/Targets/DirectX.cpp
@@ -12,11 +12,31 @@
 
 #include "DirectX.h"
 #include "Targets.h"
+#include "clang/Basic/TargetBuiltins.h"
 
 using namespace clang;
 using namespace clang::targets;
 
+static constexpr int NumBuiltins =
+    clang::DirectX::LastTSBuiltin - Builtin::FirstTSBuiltin;
+
+#define GET_BUILTIN_STR_TABLE
+#include "clang/Basic/BuiltinsDirectX.inc"
+#undef GET_BUILTIN_STR_TABLE
+
+static constexpr Builtin::Info BuiltinInfos[] = {
+#define GET_BUILTIN_INFOS
+#include "clang/Basic/BuiltinsDirectX.inc"
+#undef GET_BUILTIN_INFOS
+};
+static_assert(std::size(BuiltinInfos) == NumBuiltins);
+
 void DirectXTargetInfo::getTargetDefines(const LangOptions &Opts,
                                          MacroBuilder &Builder) const {
   DefineStd(Builder, "DIRECTX", Opts);
 }
+
+llvm::SmallVector<Builtin::InfosShard>
+DirectXTargetInfo::getTargetBuiltins() const {
+  return {{&BuiltinStrings, BuiltinInfos}};
+}
\ No newline at end of file
diff --git a/clang/lib/Basic/Targets/DirectX.h b/clang/lib/Basic/Targets/DirectX.h
index 6e3ddad626341..0e88a37e32493 100644
--- a/clang/lib/Basic/Targets/DirectX.h
+++ b/clang/lib/Basic/Targets/DirectX.h
@@ -73,9 +73,7 @@ class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo {
     return Feature == "directx";
   }
 
-  llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override {
-    return {};
-  }
+  llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;
 
   std::string_view getClobbers() const override { return ""; }
 
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 310addebd50e9..fe55dfffc1cbe 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -70,6 +70,8 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
   case llvm::Triple::bpfeb:
   case llvm::Triple::bpfel:
     return CGF->EmitBPFBuiltinExpr(BuiltinID, E);
+  case llvm::Triple::dxil:
+    return CGF->EmitDirectXBuiltinExpr(BuiltinID, E);
   case llvm::Triple::x86:
   case llvm::Triple::x86_64:
     return CGF->EmitX86BuiltinExpr(BuiltinID, E);
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 27d1c69439944..99c62808c323d 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -380,18 +380,6 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
         getDotProductIntrinsic(CGM.getHLSLRuntime(), VecTy0->getElementType()),
         ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.dot");
   }
-  case Builtin::BI__builtin_hlsl_dot2add: {
-    assert(CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil &&
-           "Intrinsic dot2add is only allowed for dxil architecture");
-    Value *A = EmitScalarExpr(E->getArg(0));
-    Value *B = EmitScalarExpr(E->getArg(1));
-    Value *C = EmitScalarExpr(E->getArg(2));
-
-    Intrinsic::ID ID = llvm ::Intrinsic::dx_dot2add;
-    return Builder.CreateIntrinsic(
-        /*ReturnType=*/C->getType(), ID, ArrayRef<Value *>{A, B, C}, nullptr,
-        "dx.dot2add");
-  }
   case Builtin::BI__builtin_hlsl_dot4add_i8packed: {
     Value *A = EmitScalarExpr(E->getArg(0));
     Value *B = EmitScalarExpr(E->getArg(1));
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index ebe2fbd7db295..dc5b2a35583b4 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -118,6 +118,7 @@ add_clang_library(clangCodeGen
   SwiftCallingConv.cpp
   TargetBuiltins/ARM.cpp
   TargetBuiltins/AMDGPU.cpp
+  TargetBuiltins/DirectX.cpp
   TargetBuiltins/Hexagon.cpp
   TargetBuiltins/NVPTX.cpp
   TargetBuiltins/PPC.cpp
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index af9798b30fbcf..34dee6df9dcfc 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4809,6 +4809,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
   llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
                                    ReturnValueSlot ReturnValue);
+  llvm::Value *EmitDirectXBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
   llvm::Value *EmitSPIRVBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
   llvm::Value *EmitScalarOrConstFoldImmArg(unsigned ICEArguments, unsigned Idx,
                                            const CallExpr *E);
diff --git a/clang/lib/CodeGen/TargetBuiltins/DirectX.cpp b/clang/lib/CodeGen/TargetBuiltins/DirectX.cpp
new file mode 100644
index 0000000000000..202601e257036
--- /dev/null
+++ b/clang/lib/CodeGen/TargetBuiltins/DirectX.cpp
@@ -0,0 +1,37 @@
+//===--------- DirectX.cpp - Emit LLVM Code for builtins ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Builtin calls as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGHLSLRuntime.h"
+#include "CodeGenFunction.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/IR/Intrinsics.h"
+
+using namespace clang;
+using namespace CodeGen;
+using namespace llvm;
+
+Value *CodeGenFunction::EmitDirectXBuiltinExpr(unsigned BuiltinID,
+                                               const CallExpr *E) {
+  switch (BuiltinID) {
+  case DirectX::BI__builtin_dx_dot2add: {
+    Value *A = EmitScalarExpr(E->getArg(0));
+    Value *B = EmitScalarExpr(E->getArg(1));
+    Value *C = EmitScalarExpr(E->getArg(2));
+
+    Intrinsic::ID ID = llvm ::Intrinsic::dx_dot2add;
+    return Builder.CreateIntrinsic(
+        /*ReturnType=*/C->getType(), ID, ArrayRef<Value *>{A, B, C}, nullptr,
+        "dx.dot2add");
+  }
+  }
+  return nullptr;
+}
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
index 3c15f2b38d80f..a8f025b1b5f5f 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
@@ -46,8 +46,8 @@ distance_vec_impl(vector<T, N> X, vector<T, N> Y) {
 }
 
 constexpr float dot2add_impl(half2 a, half2 b, float c) {
-#if defined(__DIRECTX__)
-  return __builtin_hlsl_dot2add(a, b, c);
+#if (__has_builtin(__builtin_dx_dot2add))
+  return __builtin_dx_dot2add(a, b, c);
 #else
   return dot(a, b) + c;
 #endif
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index d3fe80f659f69..cc7921fc32254 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -47,6 +47,7 @@ add_clang_library(clangSema
   SemaConsumer.cpp
   SemaCoroutine.cpp
   SemaCUDA.cpp
+  SemaDirectX.cpp
   SemaDecl.cpp
   SemaDeclAttr.cpp
   SemaDeclCXX.cpp
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 64f5633f380ec..32d7744be9229 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -47,6 +47,7 @@
 #include "clang/Sema/SemaCUDA.h"
 #include "clang/Sema/SemaCodeCompletion.h"
 #include "clang/Sema/SemaConsumer.h"
+#include "clang/Sema/SemaDirectX.h"
 #include "clang/Sema/SemaHLSL.h"
 #include "clang/Sema/SemaHexagon.h"
 #include "clang/Sema/SemaLoongArch.h"
@@ -226,6 +227,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
       CodeCompletionPtr(
           std::make_unique<SemaCodeCompletion>(*this, CodeCompleter)),
       CUDAPtr(std::make_unique<SemaCUDA>(*this)),
+      DirectXPtr(std::make_unique<SemaDirectX>(*this)),
       HLSLPtr(std::make_unique<SemaHLSL>(*this)),
       HexagonPtr(std::make_unique<SemaHexagon>(*this)),
       LoongArchPtr(std::make_unique<SemaLoongArch>(*this)),
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 5a4fa97366809..674aa07992785 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -61,6 +61,7 @@
 #include "clang/Sema/SemaAMDGPU.h"
 #include "clang/Sema/SemaARM.h"
 #include "clang/Sema/SemaBPF.h"
+#include "clang/Sema/SemaDirectX.h"
 #include "clang/Sema/SemaHLSL.h"
 #include "clang/Sema/SemaHexagon.h"
 #include "clang/Sema/SemaLoongArch.h"
@@ -1930,6 +1931,8 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
   case llvm::Triple::bpfeb:
   case llvm::Triple::bpfel:
     return BPF().CheckBPFBuiltinFunctionCall(BuiltinID, TheCall);
+  case llvm::Triple::dxil:
+    return DirectX().CheckDirectXBuiltinFunctionCall(BuiltinID, TheCall);
   case llvm::Triple::hexagon:
     return Hexagon().CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall);
   case llvm::Triple::mips:
diff --git a/clang/lib/Sema/SemaDirectX.cpp b/clang/lib/Sema/SemaDirectX.cpp
new file mode 100644
index 0000000000000..eaac24cdc710e
--- /dev/null
+++ b/clang/lib/Sema/SemaDirectX.cpp
@@ -0,0 +1,23 @@
+//===- SemaDirectX.cpp - Semantic Analysis for DirectX constructs----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This implements Semantic Analysis for DirectX constructs.
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaDirectX.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Sema/Sema.h"
+
+namespace clang {
+
+SemaDirectX::SemaDirectX(Sema &S) : SemaBase(S) {}
+
+bool SemaDirectX::CheckDirectXBuiltinFunctionCall(unsigned BuiltinID,
+                                                  CallExpr *TheCall) {
+  return false;
+}
+} // namespace clang
diff --git a/clang/test/CodeGenDirectX/Builtins/dot2add.c b/clang/test/CodeGenDirectX/Builtins/dot2add.c
new file mode 100644
index 0000000000000..181f61fea1544
--- /dev/null
+++ b/clang/test/CodeGenDirectX/Builtins/dot2add.c
@@ -0,0 +1,23 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -o - | FileCheck %s
+
+typedef _Float16 half;
+typedef half half2 __attribute__((ext_vector_type(2)));
+
+// CHECK-LABEL: define float @test_dot2add(
+// CHECK-SAME: <2 x half> noundef [[X:%.*]], <2 x half> noundef [[Y:%.*]], float noundef [[Z:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[X_ADDR:%.*]] = alloca <2 x half>, align 4
+// CHECK-NEXT:    [[Y_ADDR:%.*]] = alloca <2 x half>, align 4
+// CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT:    store <2 x half> [[X]], ptr [[X_ADDR]], align 4
+// CHECK-NEXT:    store <2 x half> [[Y]], ptr [[Y_ADDR]], align 4
+// CHECK-NEXT:    store float [[Z]], ptr [[Z_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load <2 x half>, ptr [[X_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load <2 x half>, ptr [[Y_ADDR]], align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = load float, ptr [[Z_ADDR]], align 4
+// CHECK-NEXT:    [[DX_DOT2ADD:%.*]] = call float @llvm.dx.dot2add.v2f16(<2 x half> [[TMP0]], <2 x half> [[TMP1]], float [[TMP2]])
+// CHECK-NEXT:    ret float [[DX_DOT2ADD]]
+//
+float test_dot2add(half2 X, half2 Y, float Z) { return __builtin_dx_dot2add(X, Y, Z); }

@farzonl farzonl force-pushed the directX-target-builtin branch from a44ad52 to a420186 Compare April 4, 2025 19:40
Copy link
Member

@hekota hekota left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Just a few comments.

@@ -0,0 +1,23 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filename should probably be dot2add.hlsl.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No this is a c only test. Since we are exposing the backend api as a target any frontend is technically suppose to be able to access it. This test is to confirm that we aren't gating the directX backend.

Comment on lines 1 to 2
//===----- SemaDirectX.h ----- Semantic Analysis for DirectX
// constructs--------===//
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to be on 2 lines?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch. no this should be one line


bool SemaDirectX::CheckDirectXBuiltinFunctionCall(unsigned BuiltinID,
CallExpr *TheCall) {
return false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there really no checking needed for the __builtin_dx_dot2add call? Maybe add an empty switch to make that explicit?

Suggested change
return false;
switch (BuiltinID) {
case DirectX::BI__builtin_dx_dot2add:
return false;
}
return false;

Copy link
Member Author

@farzonl farzonl Apr 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the Prototype for __builtin_dx_dot2add defines the types for the arguments and return type the semantic rules are handled via language rules. It felt weird to explicitly return false when that was going to happen any ways. I decided to do nothing because a similar case in __builtin_hlsl_wave_active_all_true we also did not explicitly handle it. I don't have a strong opinion here and could be convinced to do this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, I think that if we want to add empty switch cases for this then it should be a separate PR to change it for all other the other builtins at once.

Copy link
Member Author

@farzonl farzonl Apr 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plan right now is that we do target builtins when one of our two targets has an opcode and the other does not. Im not aware of another case right now for directx. The problem i have with removing sema scaffolding when i don’t have another candidate in mind is it feel like we have incomplete support for target builtins if we strip out all the sema changes.

Copy link
Contributor

@Icohedron Icohedron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this change. It helps make implementing builtins more consistent between SPIR-V and DirectX/DXIL


bool SemaDirectX::CheckDirectXBuiltinFunctionCall(unsigned BuiltinID,
CallExpr *TheCall) {
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, I think that if we want to add empty switch cases for this then it should be a separate PR to change it for all other the other builtins at once.

@farzonl farzonl merged commit 16c84c4 into llvm:main Apr 7, 2025
8 of 11 checks passed
@pranavk pranavk mentioned this pull request Apr 7, 2025
pranavk added a commit to pranavk/llvm-project that referenced this pull request Apr 7, 2025
Fixes fallback from llvm#134439
pranavk added a commit that referenced this pull request Apr 7, 2025
@damyanp damyanp moved this to Closed in HLSL Support Apr 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:DirectX backend:X86 clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang Clang issues not falling into any other category HLSL HLSL Language Support
Projects
Status: Closed
Development

Successfully merging this pull request may close these issues.

[DirectX] Create DX target builtins
4 participants