313 lines · c
1//===----- CGHLSLRuntime.h - Interface to HLSL Runtimes -----*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This provides an abstract class for HLSL code generation. Concrete10// subclasses of this implement code generation for specific HLSL11// runtime libraries.12//13//===----------------------------------------------------------------------===//14 15#ifndef LLVM_CLANG_LIB_CODEGEN_CGHLSLRUNTIME_H16#define LLVM_CLANG_LIB_CODEGEN_CGHLSLRUNTIME_H17 18#include "Address.h"19#include "clang/AST/Attr.h"20#include "clang/AST/Decl.h"21#include "clang/Basic/Builtins.h"22#include "clang/Basic/HLSLRuntime.h"23#include "llvm/ADT/DenseMap.h"24#include "llvm/ADT/SmallVector.h"25#include "llvm/ADT/StringRef.h"26#include "llvm/Frontend/HLSL/HLSLResource.h"27#include "llvm/IR/IRBuilder.h"28#include "llvm/IR/Intrinsics.h"29#include "llvm/IR/IntrinsicsDirectX.h"30#include "llvm/IR/IntrinsicsSPIRV.h"31 32#include <optional>33#include <vector>34 35// A function generator macro for picking the right intrinsic36// for the target backend37#define GENERATE_HLSL_INTRINSIC_FUNCTION(FunctionName, IntrinsicPostfix) \38 llvm::Intrinsic::ID get##FunctionName##Intrinsic() { \39 llvm::Triple::ArchType Arch = getArch(); \40 switch (Arch) { \41 case llvm::Triple::dxil: \42 return llvm::Intrinsic::dx_##IntrinsicPostfix; \43 case llvm::Triple::spirv: \44 return llvm::Intrinsic::spv_##IntrinsicPostfix; \45 default: \46 llvm_unreachable("Intrinsic " #IntrinsicPostfix \47 " not supported by target architecture"); \48 } \49 }50 51using ResourceClass = llvm::dxil::ResourceClass;52 53namespace llvm {54class GlobalVariable;55class Function;56class StructType;57class Metadata;58} // namespace llvm59 60namespace clang {61class NamedDecl;62class VarDecl;63class ParmVarDecl;64class InitListExpr;65class HLSLBufferDecl;66class HLSLRootSignatureDecl;67class HLSLVkBindingAttr;68class HLSLResourceBindingAttr;69class Type;70class RecordType;71class DeclContext;72class HLSLPackOffsetAttr;73class ArraySubscriptExpr;74 75class FunctionDecl;76 77namespace CodeGen {78 79class CodeGenModule;80class CodeGenFunction;81class LValue;82 83class CGHLSLOffsetInfo {84 SmallVector<uint32_t> Offsets;85 86public:87 static const uint32_t Unspecified = ~0U;88 89 /// Iterates over all declarations in the HLSL buffer and based on the90 /// packoffset or register(c#) annotations it fills outs the Offsets vector91 /// with the user-specified layout offsets. The buffer offsets can be92 /// specified 2 ways: 1. declarations in cbuffer {} block can have a93 /// packoffset annotation (translates to HLSLPackOffsetAttr) 2. default94 /// constant buffer declarations at global scope can have register(c#)95 /// annotations (translates to HLSLResourceBindingAttr with RegisterType::C)96 /// It is not guaranteed that all declarations in a buffer have an annotation.97 /// For those where it is not specified a `~0U` value is added to the Offsets98 /// vector. In the final layout these declarations will be placed at the end99 /// of the HLSL buffer after all of the elements with specified offset.100 static CGHLSLOffsetInfo fromDecl(const HLSLBufferDecl &BufDecl);101 102 /// Comparison function for offsets received from `operator[]` suitable for103 /// use in a `stable_sort`. This will order implicit bindings after explicit104 /// offsets.105 static bool compareOffsets(uint32_t LHS, uint32_t RHS) { return LHS < RHS; }106 107 /// Get the given offset, or `~0U` if there is no offset for the member.108 uint32_t operator[](size_t I) const {109 if (Offsets.empty())110 return Unspecified;111 return Offsets[I];112 }113 114 bool empty() const { return Offsets.empty(); }115};116 117class CGHLSLRuntime {118public:119 //===----------------------------------------------------------------------===//120 // Start of reserved area for HLSL intrinsic getters.121 //===----------------------------------------------------------------------===//122 123 GENERATE_HLSL_INTRINSIC_FUNCTION(All, all)124 GENERATE_HLSL_INTRINSIC_FUNCTION(Any, any)125 GENERATE_HLSL_INTRINSIC_FUNCTION(Cross, cross)126 GENERATE_HLSL_INTRINSIC_FUNCTION(Degrees, degrees)127 GENERATE_HLSL_INTRINSIC_FUNCTION(Frac, frac)128 GENERATE_HLSL_INTRINSIC_FUNCTION(FlattenedThreadIdInGroup,129 flattened_thread_id_in_group)130 GENERATE_HLSL_INTRINSIC_FUNCTION(IsInf, isinf)131 GENERATE_HLSL_INTRINSIC_FUNCTION(IsNaN, isnan)132 GENERATE_HLSL_INTRINSIC_FUNCTION(Lerp, lerp)133 GENERATE_HLSL_INTRINSIC_FUNCTION(Normalize, normalize)134 GENERATE_HLSL_INTRINSIC_FUNCTION(Rsqrt, rsqrt)135 GENERATE_HLSL_INTRINSIC_FUNCTION(Saturate, saturate)136 GENERATE_HLSL_INTRINSIC_FUNCTION(Sign, sign)137 GENERATE_HLSL_INTRINSIC_FUNCTION(Step, step)138 GENERATE_HLSL_INTRINSIC_FUNCTION(Radians, radians)139 GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id)140 GENERATE_HLSL_INTRINSIC_FUNCTION(GroupThreadId, thread_id_in_group)141 GENERATE_HLSL_INTRINSIC_FUNCTION(GroupId, group_id)142 GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot)143 GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot)144 GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot)145 GENERATE_HLSL_INTRINSIC_FUNCTION(Dot4AddI8Packed, dot4add_i8packed)146 GENERATE_HLSL_INTRINSIC_FUNCTION(Dot4AddU8Packed, dot4add_u8packed)147 GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAllTrue, wave_all)148 GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_any)149 GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveCountBits, wave_active_countbits)150 GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane)151 GENERATE_HLSL_INTRINSIC_FUNCTION(WaveGetLaneCount, wave_get_lane_count)152 GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane)153 GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitUHigh, firstbituhigh)154 GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitSHigh, firstbitshigh)155 GENERATE_HLSL_INTRINSIC_FUNCTION(FirstBitLow, firstbitlow)156 GENERATE_HLSL_INTRINSIC_FUNCTION(NClamp, nclamp)157 GENERATE_HLSL_INTRINSIC_FUNCTION(SClamp, sclamp)158 GENERATE_HLSL_INTRINSIC_FUNCTION(UClamp, uclamp)159 160 GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceGetPointer,161 resource_getpointer)162 GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding,163 resource_handlefrombinding)164 GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromImplicitBinding,165 resource_handlefromimplicitbinding)166 GENERATE_HLSL_INTRINSIC_FUNCTION(NonUniformResourceIndex,167 resource_nonuniformindex)168 GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, resource_updatecounter)169 GENERATE_HLSL_INTRINSIC_FUNCTION(GroupMemoryBarrierWithGroupSync,170 group_memory_barrier_with_group_sync)171 GENERATE_HLSL_INTRINSIC_FUNCTION(GetDimensionsX, resource_getdimensions_x)172 GENERATE_HLSL_INTRINSIC_FUNCTION(DdxCoarse, ddx_coarse)173 GENERATE_HLSL_INTRINSIC_FUNCTION(DdyCoarse, ddy_coarse)174 175 //===----------------------------------------------------------------------===//176 // End of reserved area for HLSL intrinsic getters.177 //===----------------------------------------------------------------------===//178 179protected:180 CodeGenModule &CGM;181 182 llvm::Value *emitSystemSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,183 const clang::DeclaratorDecl *Decl,184 HLSLAppliedSemanticAttr *Semantic,185 std::optional<unsigned> Index);186 187 void emitSystemSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,188 const clang::DeclaratorDecl *Decl,189 HLSLAppliedSemanticAttr *Semantic,190 std::optional<unsigned> Index);191 192 llvm::Value *handleScalarSemanticLoad(llvm::IRBuilder<> &B,193 const FunctionDecl *FD,194 llvm::Type *Type,195 const clang::DeclaratorDecl *Decl,196 HLSLAppliedSemanticAttr *Semantic);197 198 void handleScalarSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD,199 llvm::Value *Source,200 const clang::DeclaratorDecl *Decl,201 HLSLAppliedSemanticAttr *Semantic);202 203 std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>204 handleStructSemanticLoad(205 llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Type *Type,206 const clang::DeclaratorDecl *Decl,207 specific_attr_iterator<HLSLAppliedSemanticAttr> begin,208 specific_attr_iterator<HLSLAppliedSemanticAttr> end);209 210 specific_attr_iterator<HLSLAppliedSemanticAttr> handleStructSemanticStore(211 llvm::IRBuilder<> &B, const FunctionDecl *FD, llvm::Value *Source,212 const clang::DeclaratorDecl *Decl,213 specific_attr_iterator<HLSLAppliedSemanticAttr> AttrBegin,214 specific_attr_iterator<HLSLAppliedSemanticAttr> AttrEnd);215 216 std::pair<llvm::Value *, specific_attr_iterator<HLSLAppliedSemanticAttr>>217 handleSemanticLoad(llvm::IRBuilder<> &B, const FunctionDecl *FD,218 llvm::Type *Type, const clang::DeclaratorDecl *Decl,219 specific_attr_iterator<HLSLAppliedSemanticAttr> begin,220 specific_attr_iterator<HLSLAppliedSemanticAttr> end);221 222 specific_attr_iterator<HLSLAppliedSemanticAttr>223 handleSemanticStore(llvm::IRBuilder<> &B, const FunctionDecl *FD,224 llvm::Value *Source, const clang::DeclaratorDecl *Decl,225 specific_attr_iterator<HLSLAppliedSemanticAttr> AttrBegin,226 specific_attr_iterator<HLSLAppliedSemanticAttr> AttrEnd);227 228public:229 CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {}230 virtual ~CGHLSLRuntime() {}231 232 llvm::Type *convertHLSLSpecificType(const Type *T,233 const CGHLSLOffsetInfo &OffsetInfo);234 llvm::Type *convertHLSLSpecificType(const Type *T) {235 return convertHLSLSpecificType(T, CGHLSLOffsetInfo());236 }237 238 void generateGlobalCtorDtorCalls();239 240 void addBuffer(const HLSLBufferDecl *D);241 void addRootSignature(const HLSLRootSignatureDecl *D);242 void finishCodeGen();243 244 void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn);245 246 void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn);247 void setHLSLFunctionAttributes(const FunctionDecl *FD, llvm::Function *Fn);248 void handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Var);249 250 llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB);251 252 llvm::StructType *getHLSLBufferLayoutType(const RecordType *LayoutStructTy);253 void addHLSLBufferLayoutType(const RecordType *LayoutStructTy,254 llvm::StructType *LayoutTy);255 void emitInitListOpaqueValues(CodeGenFunction &CGF, InitListExpr *E);256 257 std::optional<LValue>258 emitResourceArraySubscriptExpr(const ArraySubscriptExpr *E,259 CodeGenFunction &CGF);260 261 std::optional<LValue> emitBufferArraySubscriptExpr(262 const ArraySubscriptExpr *E, CodeGenFunction &CGF,263 llvm::function_ref<llvm::Value *(bool Promote)> EmitIdxAfterBase);264 265 bool emitBufferCopy(CodeGenFunction &CGF, Address DestPtr, Address SrcPtr,266 QualType CType);267 268 LValue emitBufferMemberExpr(CodeGenFunction &CGF, const MemberExpr *E);269 270private:271 void emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,272 llvm::GlobalVariable *BufGV,273 const CGHLSLOffsetInfo &OffsetInfo);274 void initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,275 llvm::GlobalVariable *GV);276 void initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,277 llvm::GlobalVariable *GV,278 HLSLResourceBindingAttr *RBA);279 280 llvm::Value *emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,281 HLSLAppliedSemanticAttr *Semantic,282 std::optional<unsigned> Index);283 llvm::Value *emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,284 HLSLAppliedSemanticAttr *Semantic,285 std::optional<unsigned> Index);286 llvm::Value *emitUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,287 const clang::DeclaratorDecl *Decl,288 HLSLAppliedSemanticAttr *Semantic,289 std::optional<unsigned> Index);290 291 void emitSPIRVUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,292 HLSLAppliedSemanticAttr *Semantic,293 std::optional<unsigned> Index);294 void emitDXILUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,295 HLSLAppliedSemanticAttr *Semantic,296 std::optional<unsigned> Index);297 void emitUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,298 const clang::DeclaratorDecl *Decl,299 HLSLAppliedSemanticAttr *Semantic,300 std::optional<unsigned> Index);301 302 llvm::Triple::ArchType getArch();303 304 llvm::DenseMap<const clang::RecordType *, llvm::StructType *> LayoutTypes;305 unsigned SPIRVLastAssignedInputSemanticLocation = 0;306 unsigned SPIRVLastAssignedOutputSemanticLocation = 0;307};308 309} // namespace CodeGen310} // namespace clang311 312#endif313