Skip to content
Closed
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
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticFrontendKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,8 @@ def err_hlsl_semantic_missing : Error<"semantic annotations must be present "
"for all input and outputs of an entry "
"function or patch constant function">;

def note_hlsl_semantic_used_here : Note<"%0 used here">;

// ClangIR frontend errors
def err_cir_to_cir_transform_failed : Error<
"CIR-to-CIR transformation failed">, DefaultFatal;
Expand Down
64 changes: 61 additions & 3 deletions clang/lib/CodeGen/CGHLSLRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -619,11 +619,51 @@ CGHLSLRuntime::handleScalarSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
return emitSystemSemanticLoad(B, Type, Decl, ActiveSemantic);
}

llvm::Value *
CGHLSLRuntime::handleStructSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
const clang::DeclaratorDecl *Decl,
SemanticInfo &ActiveSemantic) {
const llvm::StructType *ST = cast<StructType>(Type);
const clang::RecordDecl *RD = Decl->getType()->getAsRecordDecl();

assert(std::distance(RD->field_begin(), RD->field_end()) ==
ST->getNumElements());

if (!ActiveSemantic.Semantic) {
ActiveSemantic.Semantic = Decl->getAttr<HLSLSemanticAttr>();
ActiveSemantic.Index = ActiveSemantic.Semantic
? ActiveSemantic.Semantic->getSemanticIndex()
: 0;
}

llvm::Value *Aggregate = llvm::PoisonValue::get(Type);
auto FieldDecl = RD->field_begin();
for (unsigned I = 0; I < ST->getNumElements(); ++I) {
SemanticInfo Info = ActiveSemantic;
llvm::Value *ChildValue =
handleSemanticLoad(B, ST->getElementType(I), *FieldDecl, Info);
if (!ChildValue) {
CGM.getDiags().Report(Decl->getInnerLocStart(),
diag::note_hlsl_semantic_used_here)
<< Decl;
return nullptr;
}
if (ActiveSemantic.Semantic)
ActiveSemantic = Info;

Aggregate = B.CreateInsertValue(Aggregate, ChildValue, I);
++FieldDecl;
}

return Aggregate;
}

llvm::Value *
CGHLSLRuntime::handleSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
const clang::DeclaratorDecl *Decl,
SemanticInfo &ActiveSemantic) {
assert(!Type->isStructTy());
if (Type->isStructTy())
return handleStructSemanticLoad(B, Type, Decl, ActiveSemantic);
return handleScalarSemanticLoad(B, Type, Decl, ActiveSemantic);
}

Expand Down Expand Up @@ -671,8 +711,26 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
}

const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
SemanticInfo ActiveSemantic = {nullptr, 0};
Args.push_back(handleSemanticLoad(B, Param.getType(), PD, ActiveSemantic));
llvm::Value *SemanticValue = nullptr;
if ([[maybe_unused]] HLSLParamModifierAttr *MA =
PD->getAttr<HLSLParamModifierAttr>()) {
llvm_unreachable("Not handled yet");
} else {
llvm::Type *ParamType =
Param.hasByValAttr() ? Param.getParamByValType() : Param.getType();
SemanticInfo ActiveSemantic = {nullptr, 0};
SemanticValue = handleSemanticLoad(B, ParamType, PD, ActiveSemantic);
if (!SemanticValue)
return;
if (Param.hasByValAttr()) {
llvm::Value *Var = B.CreateAlloca(Param.getParamByValType());
B.CreateStore(SemanticValue, Var);
SemanticValue = Var;
}
}

assert(SemanticValue);
Args.push_back(SemanticValue);
}

CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ class CGHLSLRuntime {
const clang::DeclaratorDecl *Decl,
SemanticInfo &ActiveSemantic);

llvm::Value *handleStructSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
const clang::DeclaratorDecl *Decl,
SemanticInfo &ActiveSemantic);

llvm::Value *handleSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
const clang::DeclaratorDecl *Decl,
SemanticInfo &ActiveSemantic);
Expand Down
23 changes: 23 additions & 0 deletions clang/test/CodeGenHLSL/semantics/semantic-struct-1.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx
// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv


struct Input {
uint Idx : SV_DispatchThreadID;

};

// Make sure SV_DispatchThreadID translated into dx.thread.id.

// CHECK: define void @foo()
// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
// CHECK: %[[#TMP:]] = insertvalue %struct.Input poison, i32 %[[#ID]], 0
// CHECK: %[[#VAR:]] = alloca %struct.Input, align 8
// CHECK: store %struct.Input %[[#TMP]], ptr %[[#VAR]], align 4
// CHECK-DXIL: call void @{{.*}}foo{{.*}}(ptr %[[#VAR]])
// CHECK-SPIRV: call spir_func void @{{.*}}foo{{.*}}(ptr %[[#VAR]])
[shader("compute")]
[numthreads(8,8,1)]
void foo(Input input) {}

25 changes: 25 additions & 0 deletions clang/test/CodeGenHLSL/semantics/semantic-struct-2.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx
// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv


struct Input {
uint Idx : SV_DispatchThreadID;
uint Gid : SV_GroupID;
};

// Make sure SV_DispatchThreadID translated into dx.thread.id.

// CHECK: define void @foo()
// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
// CHECK: %[[#TMP1:]] = insertvalue %struct.Input poison, i32 %[[#ID]], 0
// CHECK-DXIL: %[[#GID:]] = call i32 @llvm.[[TARGET]].group.id(i32 0)
// CHECK-SPIRV:%[[#GID:]] = call i32 @llvm.[[TARGET]].group.id.i32(i32 0)
// CHECK: %[[#TMP2:]] = insertvalue %struct.Input %[[#TMP1]], i32 %[[#GID]], 1
// CHECK: %[[#VAR:]] = alloca %struct.Input, align 8
// CHECK: store %struct.Input %[[#TMP2]], ptr %[[#VAR]], align 4
// CHECK-DXIL: call void @{{.*}}foo{{.*}}(ptr %[[#VAR]])
// CHECK-SPIRV: call spir_func void @{{.*}}foo{{.*}}(ptr %[[#VAR]])
[shader("compute")]
[numthreads(8,8,1)]
void foo(Input input) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx
// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv


struct Inner {
uint Gid;
};

struct Input {
uint Idx : SV_DispatchThreadID;
Inner inner : SV_GroupIndex;
};

// Make sure SV_DispatchThreadID translated into dx.thread.id.

// CHECK: define void @foo()
// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
// CHECK: %[[#TMP1:]] = insertvalue %struct.Input poison, i32 %[[#ID]], 0
// CHECK-DXIL: %[[#GID:]] = call i32 @llvm.dx.flattened.thread.id.in.group()
// CHECK-SPIRV:%[[#GID:]] = call i32 @llvm.spv.flattened.thread.id.in.group()
// CHECK: %[[#TMP2:]] = insertvalue %struct.Inner poison, i32 %[[#GID]], 0
// CHECK: %[[#TMP3:]] = insertvalue %struct.Input %[[#TMP1]], %struct.Inner %[[#TMP2]], 1
// CHECK: %[[#VAR:]] = alloca %struct.Input, align 8
// CHECK: store %struct.Input %[[#TMP3]], ptr %[[#VAR]], align 4
// CHECK-DXIL: call void @{{.*}}foo{{.*}}(ptr %[[#VAR]])
// CHECK-SPIRV: call spir_func void @{{.*}}foo{{.*}}(ptr %[[#VAR]])
[shader("compute")]
[numthreads(8,8,1)]
void foo(Input input) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx
// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv


struct Inner {
uint Gid : SV_GroupID;
};

struct Input {
uint Idx : SV_DispatchThreadID;
Inner inner : SV_GroupIndex;
};

// Make sure SV_DispatchThreadID translated into dx.thread.id.

// CHECK: define void @foo()
// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
// CHECK: %[[#TMP1:]] = insertvalue %struct.Input poison, i32 %[[#ID]], 0
// CHECK-DXIL: %[[#GID:]] = call i32 @llvm.dx.flattened.thread.id.in.group()
// CHECK-SPIRV:%[[#GID:]] = call i32 @llvm.spv.flattened.thread.id.in.group()
// CHECK: %[[#TMP2:]] = insertvalue %struct.Inner poison, i32 %[[#GID]], 0
// CHECK: %[[#TMP3:]] = insertvalue %struct.Input %[[#TMP1]], %struct.Inner %[[#TMP2]], 1
// CHECK: %[[#VAR:]] = alloca %struct.Input, align 8
// CHECK: store %struct.Input %[[#TMP3]], ptr %[[#VAR]], align 4
// CHECK-DXIL: call void @{{.*}}foo{{.*}}(ptr %[[#VAR]])
// CHECK-SPIRV: call spir_func void @{{.*}}foo{{.*}}(ptr %[[#VAR]])
[shader("compute")]
[numthreads(8,8,1)]
void foo(Input input) {}
30 changes: 30 additions & 0 deletions clang/test/CodeGenHLSL/semantics/semantic-struct-nested.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx
// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv


struct Inner {
uint Gid : SV_GroupID;
};

struct Input {
uint Idx : SV_DispatchThreadID;
Inner inner;
};

// Make sure SV_DispatchThreadID translated into dx.thread.id.

// CHECK: define void @foo()
// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
// CHECK: %[[#TMP1:]] = insertvalue %struct.Input poison, i32 %[[#ID]], 0
// CHECK-DXIL: %[[#GID:]] = call i32 @llvm.[[TARGET]].group.id(i32 0)
// CHECK-SPIRV:%[[#GID:]] = call i32 @llvm.[[TARGET]].group.id.i32(i32 0)
// CHECK: %[[#TMP2:]] = insertvalue %struct.Inner poison, i32 %[[#GID]], 0
// CHECK: %[[#TMP3:]] = insertvalue %struct.Input %[[#TMP1]], %struct.Inner %[[#TMP2]], 1
// CHECK: %[[#VAR:]] = alloca %struct.Input, align 8
// CHECK: store %struct.Input %[[#TMP3]], ptr %[[#VAR]], align 4
// CHECK-DXIL: call void @{{.*}}foo{{.*}}(ptr %[[#VAR]])
// CHECK-SPIRV: call spir_func void @{{.*}}foo{{.*}}(ptr %[[#VAR]])
[shader("compute")]
[numthreads(8,8,1)]
void foo(Input input) {}