diff options
author | Farzon Lotfi <farzonlotfi@microsoft.com> | 2025-01-06 11:37:20 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-06 11:37:20 -0500 |
commit | 21edac25f09faee23015c6a69d95fcbda287efe2 (patch) | |
tree | 94f291efe78f308c189981c0695de48bc58c5d5a /clang | |
parent | ca603d2536f039194141bf3a01e9ee7f60e37406 (diff) | |
download | llvm-21edac25f09faee23015c6a69d95fcbda287efe2.zip llvm-21edac25f09faee23015c6a69d95fcbda287efe2.tar.gz llvm-21edac25f09faee23015c6a69d95fcbda287efe2.tar.bz2 |
[SPIRV] Add Target Builtins using Distance ext as an example (#121598)
- Update pr labeler so new SPIRV files get properly labeled.
- Add distance target builtin to BuiltinsSPIRV.td.
- Update TargetBuiltins.h to account for spirv builtins.
- Update clang basic CMakeLists.txt to build spirv builtin tablegen.
- Hook up sema for SPIRV in Sema.h|cpp, SemaSPIRV.h|cpp, and
SemaChecking.cpp.
- Hookup sprv target builtins to SPIR.h|SPIR.cpp target.
- Update GBuiltin.cpp to emit spirv intrinsics when we get the expected
spirv target builtin.
Consensus was reach in this RFC to add both target builtins and pattern
matching:
https://discourse.llvm.org/t/rfc-add-targetbuiltins-for-spirv-to-support-hlsl/83329.
pattern matching will come in a separate pr this one just sets up the
groundwork to do target builtins for spirv.
partially resolves
[#99107](https://github.com/llvm/llvm-project/issues/99107)
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Basic/BuiltinsSPIRV.td | 15 | ||||
-rw-r--r-- | clang/include/clang/Basic/CMakeLists.txt | 4 | ||||
-rw-r--r-- | clang/include/clang/Basic/TargetBuiltins.h | 10 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 7 | ||||
-rw-r--r-- | clang/include/clang/Sema/SemaSPIRV.h | 28 | ||||
-rw-r--r-- | clang/lib/Basic/Targets/SPIR.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Basic/Targets/SPIR.h | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGBuiltin.cpp | 22 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 1 | ||||
-rw-r--r-- | clang/lib/Sema/CMakeLists.txt | 1 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaSPIRV.cpp | 57 | ||||
-rw-r--r-- | clang/test/CodeGenSPIRV/Builtins/distance.c | 31 | ||||
-rw-r--r-- | clang/test/SemaSPIRV/BuiltIns/distance-errors.c | 23 |
15 files changed, 218 insertions, 1 deletions
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td new file mode 100644 index 0000000..195c135 --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsSPIRV.td @@ -0,0 +1,15 @@ +//===--- BuiltinsSPIRV.td - SPIRV Builtin function database ---------*- C++ -*-===// +// +// 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 HLSLDistance : Builtin { + let Spellings = ["__builtin_spirv_distance"]; + let Attributes = [NoThrow, Const]; + let Prototype = "void(...)"; +} diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt index 1ccc738..897a610 100644 --- a/clang/include/clang/Basic/CMakeLists.txt +++ b/clang/include/clang/Basic/CMakeLists.txt @@ -60,6 +60,10 @@ clang_tablegen(BuiltinsRISCV.inc -gen-clang-builtins SOURCE BuiltinsRISCV.td TARGET ClangBuiltinsRISCV) +clang_tablegen(BuiltinsSPIRV.inc -gen-clang-builtins + SOURCE BuiltinsSPIRV.td + TARGET ClangBuiltinsSPIRV) + clang_tablegen(BuiltinsX86.inc -gen-clang-builtins SOURCE BuiltinsX86.td TARGET ClangBuiltinsX86) diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h index 914be36..4dc8b24 100644 --- a/clang/include/clang/Basic/TargetBuiltins.h +++ b/clang/include/clang/Basic/TargetBuiltins.h @@ -119,6 +119,16 @@ namespace clang { }; } + /// SPIRV builtins + namespace SPIRV { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsSPIRV.inc" + LastTSBuiltin + }; + } // namespace SPIRV + /// X86 builtins namespace X86 { enum { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index af59b7f..18fd95f 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -173,6 +173,7 @@ class SemaOpenMP; class SemaPPC; class SemaPseudoObject; class SemaRISCV; +class SemaSPIRV; class SemaSYCL; class SemaSwift; class SemaSystemZ; @@ -1142,6 +1143,11 @@ public: return *RISCVPtr; } + SemaSPIRV &SPIRV() { + assert(SPIRVPtr); + return *SPIRVPtr; + } + SemaSYCL &SYCL() { assert(SYCLPtr); return *SYCLPtr; @@ -1219,6 +1225,7 @@ private: std::unique_ptr<SemaPPC> PPCPtr; std::unique_ptr<SemaPseudoObject> PseudoObjectPtr; std::unique_ptr<SemaRISCV> RISCVPtr; + std::unique_ptr<SemaSPIRV> SPIRVPtr; std::unique_ptr<SemaSYCL> SYCLPtr; std::unique_ptr<SemaSwift> SwiftPtr; std::unique_ptr<SemaSystemZ> SystemZPtr; diff --git a/clang/include/clang/Sema/SemaSPIRV.h b/clang/include/clang/Sema/SemaSPIRV.h new file mode 100644 index 0000000..b26b861 --- /dev/null +++ b/clang/include/clang/Sema/SemaSPIRV.h @@ -0,0 +1,28 @@ +//===----- SemaSPIRV.h ----- Semantic Analysis for SPIRV 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 SPIRV constructs. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMASPIRV_H +#define LLVM_CLANG_SEMA_SEMASPIRV_H + +#include "clang/AST/ASTFwd.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { +class SemaSPIRV : public SemaBase { +public: + SemaSPIRV(Sema &S); + + bool CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); +}; +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMASPIRV_H diff --git a/clang/lib/Basic/Targets/SPIR.cpp b/clang/lib/Basic/Targets/SPIR.cpp index 0403039..f242fed 100644 --- a/clang/lib/Basic/Targets/SPIR.cpp +++ b/clang/lib/Basic/Targets/SPIR.cpp @@ -13,11 +13,24 @@ #include "SPIR.h" #include "AMDGPU.h" #include "Targets.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" #include "llvm/TargetParser/TargetParser.h" using namespace clang; using namespace clang::targets; +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#include "clang/Basic/BuiltinsSPIRV.inc" +}; + +ArrayRef<Builtin::Info> SPIRVTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, + clang::SPIRV::LastTSBuiltin - Builtin::FirstTSBuiltin); +} + void SPIRTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { DefineStd(Builder, "SPIR", Opts); diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h index 85e4bd9..5a328b9c 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -313,7 +313,7 @@ public: resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-" "v256:256-v512:512-v1024:1024-n8:16:32:64-G1"); } - + ArrayRef<Builtin::Info> getTargetBuiltins() const override; void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; }; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index c419fb0..5cd893d 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -6797,6 +6797,8 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF, case llvm::Triple::riscv32: case llvm::Triple::riscv64: return CGF->EmitRISCVBuiltinExpr(BuiltinID, E, ReturnValue); + case llvm::Triple::spirv: + return CGF->EmitSPIRVBuiltinExpr(BuiltinID, E); case llvm::Triple::spirv64: if (CGF->getTarget().getTriple().getOS() != llvm::Triple::OSType::AMDHSA) return nullptr; @@ -20480,6 +20482,26 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, } } +Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID, + const CallExpr *E) { + switch (BuiltinID) { + case SPIRV::BI__builtin_spirv_distance: { + Value *X = EmitScalarExpr(E->getArg(0)); + Value *Y = EmitScalarExpr(E->getArg(1)); + assert(E->getArg(0)->getType()->hasFloatingRepresentation() && + E->getArg(1)->getType()->hasFloatingRepresentation() && + "Distance operands must have a float representation"); + assert(E->getArg(0)->getType()->isVectorType() && + E->getArg(1)->getType()->isVectorType() && + "Distance operands must be a vector"); + return Builder.CreateIntrinsic( + /*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_distance, + ArrayRef<Value *>{X, Y}, nullptr, "spv.distance"); + } + } + return nullptr; +} + /// Handle a SystemZ function in which the final argument is a pointer /// to an int that receives the post-instruction CC value. At the LLVM level /// this is represented as a function that returns a {result, cc} pair. diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 46f2679..b38c009 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4756,6 +4756,7 @@ public: llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue); + llvm::Value *EmitSPIRVBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitScalarOrConstFoldImmArg(unsigned ICEArguments, unsigned Idx, const CallExpr *E); llvm::Value *EmitSystemZBuiltinExpr(unsigned BuiltinID, const CallExpr *E); diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 719c3a9..3241cb5 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -79,6 +79,7 @@ add_clang_library(clangSema SemaStmt.cpp SemaStmtAsm.cpp SemaStmtAttr.cpp + SemaSPIRV.cpp SemaSYCL.cpp SemaSwift.cpp SemaSystemZ.cpp diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index d651751..abb46d3 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -61,6 +61,7 @@ #include "clang/Sema/SemaPPC.h" #include "clang/Sema/SemaPseudoObject.h" #include "clang/Sema/SemaRISCV.h" +#include "clang/Sema/SemaSPIRV.h" #include "clang/Sema/SemaSYCL.h" #include "clang/Sema/SemaSwift.h" #include "clang/Sema/SemaSystemZ.h" @@ -239,6 +240,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, PPCPtr(std::make_unique<SemaPPC>(*this)), PseudoObjectPtr(std::make_unique<SemaPseudoObject>(*this)), RISCVPtr(std::make_unique<SemaRISCV>(*this)), + SPIRVPtr(std::make_unique<SemaSPIRV>(*this)), SYCLPtr(std::make_unique<SemaSYCL>(*this)), SwiftPtr(std::make_unique<SemaSwift>(*this)), SystemZPtr(std::make_unique<SemaSystemZ>(*this)), diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index ce846ae..28dcfaa 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -70,6 +70,7 @@ #include "clang/Sema/SemaOpenCL.h" #include "clang/Sema/SemaPPC.h" #include "clang/Sema/SemaRISCV.h" +#include "clang/Sema/SemaSPIRV.h" #include "clang/Sema/SemaSystemZ.h" #include "clang/Sema/SemaWasm.h" #include "clang/Sema/SemaX86.h" @@ -1934,6 +1935,8 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case llvm::Triple::mips64: case llvm::Triple::mips64el: return MIPS().CheckMipsBuiltinFunctionCall(TI, BuiltinID, TheCall); + case llvm::Triple::spirv: + return SPIRV().CheckSPIRVBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::systemz: return SystemZ().CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::x86: diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp new file mode 100644 index 0000000..d2de648 --- /dev/null +++ b/clang/lib/Sema/SemaSPIRV.cpp @@ -0,0 +1,57 @@ +//===- SemaSPIRV.cpp - Semantic Analysis for SPIRV 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 SPIRV constructs. +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaSPIRV.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Sema/Sema.h" + +namespace clang { + +SemaSPIRV::SemaSPIRV(Sema &S) : SemaBase(S) {} + +bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + switch (BuiltinID) { + case SPIRV::BI__builtin_spirv_distance: { + if (SemaRef.checkArgCount(TheCall, 2)) + return true; + + ExprResult A = TheCall->getArg(0); + QualType ArgTyA = A.get()->getType(); + auto *VTyA = ArgTyA->getAs<VectorType>(); + if (VTyA == nullptr) { + SemaRef.Diag(A.get()->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << ArgTyA + << SemaRef.Context.getVectorType(ArgTyA, 2, VectorKind::Generic) << 1 + << 0 << 0; + return true; + } + + ExprResult B = TheCall->getArg(1); + QualType ArgTyB = B.get()->getType(); + auto *VTyB = ArgTyB->getAs<VectorType>(); + if (VTyB == nullptr) { + SemaRef.Diag(A.get()->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << ArgTyB + << SemaRef.Context.getVectorType(ArgTyB, 2, VectorKind::Generic) << 1 + << 0 << 0; + return true; + } + + QualType RetTy = VTyA->getElementType(); + TheCall->setType(RetTy); + break; + } + } + return false; +} +} // namespace clang diff --git a/clang/test/CodeGenSPIRV/Builtins/distance.c b/clang/test/CodeGenSPIRV/Builtins/distance.c new file mode 100644 index 0000000..76c684b --- /dev/null +++ b/clang/test/CodeGenSPIRV/Builtins/distance.c @@ -0,0 +1,31 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 + +// RUN: %clang_cc1 -O1 -triple spirv-pc-vulkan-compute %s -emit-llvm -o - | FileCheck %s + +typedef float float2 __attribute__((ext_vector_type(2))); +typedef float float3 __attribute__((ext_vector_type(3))); +typedef float float4 __attribute__((ext_vector_type(4))); + +// CHECK-LABEL: define spir_func float @test_distance_float2( +// CHECK-SAME: <2 x float> noundef [[X:%.*]], <2 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SPV_DISTANCE:%.*]] = tail call float @llvm.spv.distance.v2f32(<2 x float> [[X]], <2 x float> [[Y]]) +// CHECK-NEXT: ret float [[SPV_DISTANCE]] +// +float test_distance_float2(float2 X, float2 Y) { return __builtin_spirv_distance(X, Y); } + +// CHECK-LABEL: define spir_func float @test_distance_float3( +// CHECK-SAME: <3 x float> noundef [[X:%.*]], <3 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SPV_DISTANCE:%.*]] = tail call float @llvm.spv.distance.v3f32(<3 x float> [[X]], <3 x float> [[Y]]) +// CHECK-NEXT: ret float [[SPV_DISTANCE]] +// +float test_distance_float3(float3 X, float3 Y) { return __builtin_spirv_distance(X, Y); } + +// CHECK-LABEL: define spir_func float @test_distance_float4( +// CHECK-SAME: <4 x float> noundef [[X:%.*]], <4 x float> noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SPV_DISTANCE:%.*]] = tail call float @llvm.spv.distance.v4f32(<4 x float> [[X]], <4 x float> [[Y]]) +// CHECK-NEXT: ret float [[SPV_DISTANCE]] +// +float test_distance_float4(float4 X, float4 Y) { return __builtin_spirv_distance(X, Y); } diff --git a/clang/test/SemaSPIRV/BuiltIns/distance-errors.c b/clang/test/SemaSPIRV/BuiltIns/distance-errors.c new file mode 100644 index 0000000..17ea25d --- /dev/null +++ b/clang/test/SemaSPIRV/BuiltIns/distance-errors.c @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 %s -triple spirv-pc-vulkan-compute -verify + +typedef float float2 __attribute__((ext_vector_type(2))); + +float test_no_second_arg(float2 p0) { + return __builtin_spirv_distance(p0); + // expected-error@-1 {{too few arguments to function call, expected 2, have 1}} +} + +float test_too_many_arg(float2 p0) { + return __builtin_spirv_distance(p0, p0, p0); + // expected-error@-1 {{too many arguments to function call, expected 2, have 3}} +} + +float test_double_scalar_inputs(double p0, double p1) { + return __builtin_spirv_distance(p0, p1); + // expected-error@-1 {{passing 'double' to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(double)))) double' (vector of 2 'double' values)}} +} + +float test_int_scalar_inputs(int p0, int p1) { + return __builtin_spirv_distance(p0, p1); + // expected-error@-1 {{passing 'int' to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}} +} |