Skip to content
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

[HLSL] Add handle initialization for simple resource declarations #111207

Merged
merged 9 commits into from
Oct 18, 2024
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/CGDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,11 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
if (Decls[i])
EmitRuntimeCall(Decls[i]);

if (getLangOpts().HLSL)
if (llvm::Function *ResInitFn =
CGM.getHLSLRuntime().createResourceBindingInitFn())
damyanp marked this conversation as resolved.
Show resolved Hide resolved
Builder.CreateCall(llvm::FunctionCallee(ResInitFn), {});

Scope.ForceCleanup();

if (ExitBlock) {
Expand Down
102 changes: 102 additions & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@
#include "TargetInfo.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Alignment.h"

#include "llvm/Support/FormatVariadic.h"

using namespace clang;
Expand Down Expand Up @@ -489,3 +494,100 @@ void CGHLSLRuntime::generateGlobalCtorDtorCalls() {
GV->eraseFromParent();
}
}

// Returns handle type of a resource, if the type is a resource
// or an array of resources
static const HLSLAttributedResourceType *findHandleTypeOnResource(QualType QT) {
// If the type is a resource class, the first field must
// be the resource handle of type HLSLAttributedResourceType
const clang::Type *Ty = QT->getUnqualifiedDesugaredType();
if (RecordDecl *RD = Ty->getAsCXXRecordDecl()) {
if (!RD->fields().empty()) {
const auto &FirstFD = RD->fields().begin();
return dyn_cast<HLSLAttributedResourceType>(
FirstFD->getType().getTypePtr());
}
}
return nullptr;
}
hekota marked this conversation as resolved.
Show resolved Hide resolved

void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
llvm::GlobalVariable *Var) {
// If the global variable has resource binding, add it to the list of globals
// that need resource binding initialization.
const HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
if (!RBA)
return;

if (!findHandleTypeOnResource(VD->getType()))
// FIXME: Only simple declarations of resources are supported for now.
// Arrays of resources or resources in user defined classes are
// not implemented yet.
damyanp marked this conversation as resolved.
Show resolved Hide resolved
return;

ResourcesToBind.emplace_back(std::make_pair(VD, Var));
hekota marked this conversation as resolved.
Show resolved Hide resolved
}

llvm::Function *CGHLSLRuntime::createResourceBindingInitFn() {
// No resources to bind
if (ResourcesToBind.empty())
return nullptr;

LLVMContext &Ctx = CGM.getLLVMContext();

llvm::Function *InitResBindingsFunc =
llvm::Function::Create(llvm::FunctionType::get(CGM.VoidTy, false),
llvm::GlobalValue::InternalLinkage,
"_init_resource_bindings", CGM.getModule());

llvm::BasicBlock *EntryBB =
llvm::BasicBlock::Create(Ctx, "entry", InitResBindingsFunc);
CGBuilderTy Builder(CGM, Ctx);
const DataLayout &DL = CGM.getModule().getDataLayout();
Builder.SetInsertPoint(EntryBB);

for (auto I : ResourcesToBind) {
hekota marked this conversation as resolved.
Show resolved Hide resolved
const VarDecl *VD = I.first;
llvm::GlobalVariable *Var = I.second;

for (Attr *A : VD->getAttrs()) {
HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
if (!RBA)
continue;

const HLSLAttributedResourceType *AttrResType =
findHandleTypeOnResource(VD->getType());
assert(AttrResType != nullptr &&
"Resource class must have a handle of HLSLAttributedResourceType");

llvm::Type *TargetTy =
CGM.getTargetCodeGenInfo().getHLSLType(CGM, AttrResType);
assert(TargetTy != nullptr &&
"Failed to convert resource handle to target type");

llvm::Value *Args[] = {
llvm::ConstantInt::get(CGM.IntTy,
RBA->getSpaceNumber()), /*RegisterSpace*/
llvm::ConstantInt::get(CGM.IntTy,
RBA->getSlotNumber()), /*RegisterSlot*/
// FIXME: resource arrays are not yet implemented
llvm::ConstantInt::get(CGM.IntTy, 1), /*Range*/
llvm::ConstantInt::get(CGM.IntTy, 0), /*Index*/
// FIXME: NonUniformResourceIndex bit is not yet implemented
llvm::ConstantInt::get(llvm::Type::getInt1Ty(Ctx),
hekota marked this conversation as resolved.
Show resolved Hide resolved
false) /*Non-uniform*/
};
hekota marked this conversation as resolved.
Show resolved Hide resolved
llvm::Value *CreateHandle = Builder.CreateIntrinsic(
/*ReturnType=*/TargetTy, getCreateHandleFromBindingIntrinsic(), Args,
nullptr, Twine(VD->getName()).concat("_h"));

llvm::Value *HandleRef =
Builder.CreateStructGEP(Var->getValueType(), Var, 0);
Builder.CreateAlignedStore(CreateHandle, HandleRef,
HandleRef->getPointerAlignment(DL));
}
}

Builder.CreateRetVoid();
return InitResBindingsFunc;
}
7 changes: 7 additions & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class CGHLSLRuntime {
GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot)
GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane)

GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding, handle_fromBinding)

//===----------------------------------------------------------------------===//
// End of reserved area for HLSL intrinsic getters.
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -135,6 +137,8 @@ class CGHLSLRuntime {

void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn);
void setHLSLFunctionAttributes(const FunctionDecl *FD, llvm::Function *Fn);
void handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Var);
llvm::Function *createResourceBindingInitFn();

private:
void addBufferResourceAnnotation(llvm::GlobalVariable *GV,
Expand All @@ -146,6 +150,9 @@ class CGHLSLRuntime {
void addBufferDecls(const DeclContext *DC, Buffer &CB);
llvm::Triple::ArchType getArch();
llvm::SmallVector<Buffer> Buffers;

llvm::SmallVector<std::pair<const VarDecl *, llvm::GlobalVariable *>>
ResourcesToBind;
};

} // namespace CodeGen
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5622,6 +5622,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
getCUDARuntime().handleVarRegistration(D, *GV);
}

if (LangOpts.HLSL)
getHLSLRuntime().handleGlobalVarDefinition(D, GV);
damyanp marked this conversation as resolved.
Show resolved Hide resolved

GV->setInitializer(Init);
if (emitter)
emitter->finalize(GV);
Expand Down
26 changes: 14 additions & 12 deletions clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=CHECK-SPIRV
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL
// RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV

hekota marked this conversation as resolved.
Show resolved Hide resolved
// XFAIL: *
// This expectedly fails because create.handle is no longer called
// from RWBuffer constructor and the replacement has not been
// implemented yet. This test should be updated to expect
// dx.create.handleFromBinding as part of issue #105076.
// NOTE: SPIRV codegen for resource types is not yet implemented

RWBuffer<float> Buf;
RWBuffer<float> Buf : register(u5, space3);

// CHECK: define linkonce_odr noundef ptr @"??0?$RWBuffer@M@hlsl@@QAA@XZ"
// CHECK-NEXT: entry:

// CHECK: %[[HandleRes:[0-9]+]] = call ptr @llvm.dx.create.handle(i8 1)
// CHECK: store ptr %[[HandleRes]], ptr %h, align 4
// CHECK: define internal void @_GLOBAL__sub_I_RWBuffer_constructor.hlsl()
// CHECK-NEXT: entry:
// CHECK-NEXT: call void @"??__EBuf@@YAXXZ"()
// CHECK-NEXT: call void @_init_resource_bindings()

// CHECK-SPIRV: %[[HandleRes:[0-9]+]] = call ptr @llvm.spv.create.handle(i8 1)
// CHECK-SPIRV: store ptr %[[HandleRes]], ptr %h, align 8
// CHECK: define internal void @_init_resource_bindings() {
// CHECK-NEXT: entry:
// CHECK-DXIL-NEXT: %Buf_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
// CHECK-DXIL-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %Buf_h, ptr @"?Buf@@3V?$RWBuffer@M@hlsl@@A", align 4
// CHECK-SPIRV-NEXT: %Buf_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.spv.handle.fromBinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
// CHECK-SPIRV-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %Buf_h, ptr @"?Buf@@3V?$RWBuffer@M@hlsl@@A", align 4
27 changes: 14 additions & 13 deletions clang/test/CodeGenHLSL/builtins/StructuredBuffer-constructor.hlsl
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=CHECK-SPIRV
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL
// RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV

// XFAIL: *
// This expectedly fails because create.handle is no longer invoked
// from StructuredBuffer constructor and the replacement has not been
// implemented yet. This test should be updated to expect
// dx.create.handleFromBinding as part of issue #105076.

StructuredBuffer<float> Buf;
// NOTE: SPIRV codegen for resource types is not yet implemented
StructuredBuffer<float> Buf : register(u10);

// CHECK: define linkonce_odr noundef ptr @"??0?$StructuredBuffer@M@hlsl@@QAA@XZ"
// CHECK-NEXT: entry:

// CHECK: %[[HandleRes:[0-9]+]] = call ptr @llvm.dx.create.handle(i8 1)
// CHECK: store ptr %[[HandleRes]], ptr %h, align 4
// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffer_constructor.hlsl()
// CHECK-NEXT: entry:
// CHECK-NEXT: call void @"??__EBuf@@YAXXZ"()
// CHECK-NEXT: call void @_init_resource_bindings()

// CHECK-SPIRV: %[[HandleRes:[0-9]+]] = call ptr @llvm.spv.create.handle(i8 1)
// CHECK-SPIRV: store ptr %[[HandleRes]], ptr %h, align 8
// CHECK: define internal void @_init_resource_bindings() {
// CHECK-NEXT: entry:
// CHECK-DXIL-NEXT: %Buf_h = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 10, i32 1, i32 0, i1 false)
// CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf_h, ptr @"?Buf@@3V?$StructuredBuffer@M@hlsl@@A", align 4
// CHECK-SPIRV-NEXT: %Buf_h = call target("dx.RawBuffer", float, 1, 0) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 10, i32 1, i32 0, i1 false)
// CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf_h, ptr @"?Buf@@3V?$StructuredBuffer@M@hlsl@@A", align 4
Loading