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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/new-prs-labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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.*
Expand Down
6 changes: 0 additions & 6 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
15 changes: 15 additions & 0 deletions clang/include/clang/Basic/BuiltinsDirectX.td
Original file line number Diff line number Diff line change
@@ -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)";
}
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/Basic/TargetBuiltins.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ class SemaAVR;
class SemaBPF;
class SemaCodeCompletion;
class SemaCUDA;
class SemaDirectX;
class SemaHLSL;
class SemaHexagon;
class SemaLoongArch;
Expand Down Expand Up @@ -1074,6 +1075,11 @@ class Sema final : public SemaBase {
return *CUDAPtr;
}

SemaDirectX &DirectX() {
assert(DirectXPtr);
return *DirectXPtr;
}

SemaHLSL &HLSL() {
assert(HLSLPtr);
return *HLSLPtr;
Expand Down Expand Up @@ -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;
Expand Down
28 changes: 28 additions & 0 deletions clang/include/clang/Sema/SemaDirectX.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===----- 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
20 changes: 20 additions & 0 deletions clang/lib/Basic/Targets/DirectX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}};
}
4 changes: 1 addition & 3 deletions clang/lib/Basic/Targets/DirectX.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 ""; }

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 0 additions & 12 deletions clang/lib/CodeGen/CGHLSLBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
37 changes: 37 additions & 0 deletions clang/lib/CodeGen/TargetBuiltins/DirectX.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
4 changes: 2 additions & 2 deletions clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ add_clang_library(clangSema
SemaConsumer.cpp
SemaCoroutine.cpp
SemaCUDA.cpp
SemaDirectX.cpp
SemaDecl.cpp
SemaDeclAttr.cpp
SemaDeclCXX.cpp
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)),
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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:
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/Sema/SemaDirectX.cpp
Original file line number Diff line number Diff line change
@@ -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;
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.

}
} // namespace clang
23 changes: 23 additions & 0 deletions clang/test/CodeGenDirectX/Builtins/dot2add.c
Original file line number Diff line number Diff line change
@@ -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.


// 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); }
Loading