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

Write and test example library for accessing TempRegLoad/TempRegStore #2951

Merged
merged 1 commit into from
Jun 8, 2020
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
18 changes: 18 additions & 0 deletions tools/clang/test/HLSLFileCheck/dxil/linker/TempReg.hlslh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Prototypes for wrappers to TempRegLoad/TempRegStore,
// overloaded for uint, int, and float
// link to TempReg.dxl (assembled from TempReg.ll)

#ifndef TEMPREG_H
#define TEMPREG_H

// Store values
void sreg(uint n, uint val);
void sreg(uint n, int val);
void sreg(uint n, float val);

// Load values
uint ureg(uint n);
int ireg(uint n);
float freg(uint n);

#endif // TEMPREG_H
126 changes: 126 additions & 0 deletions tools/clang/test/HLSLFileCheck/dxil/linker/TempReg.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
; RUN: %opt %s -dce -S | FileCheck %s
; Just run a pass that shouldn't do anything in order to pass through assembler

; dxa TempReg.ll -o TempReg.dxl

; CHECK: define void
; CHECK-SAME: sreg
; CHECK-SAME: i32 %n
; CHECK-SAME: i32 %val
; CHECK: call void @dx.op.tempRegStore.i32

; CHECK: define void
; CHECK-SAME: sreg
; CHECK-SAME: i32 %n
; CHECK-SAME: i32 %val
; CHECK: call void @dx.op.tempRegStore.i32

; CHECK: define void
; CHECK-SAME: sreg
; CHECK-SAME: i32 %n
; CHECK-SAME: float %val
; CHECK: call void @dx.op.tempRegStore.f32

; CHECK: define i32
; CHECK-SAME: ureg
; CHECK-SAME: i32 %n
; CHECK: call i32 @dx.op.tempRegLoad.i32

; CHECK: define i32
; CHECK-SAME: ireg
; CHECK-SAME: i32 %n
; CHECK: call i32 @dx.op.tempRegLoad.i32

; CHECK: define float
; CHECK-SAME: freg
; CHECK-SAME: i32 %n
; CHECK: call float @dx.op.tempRegLoad.f32

target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
target triple = "dxil-ms-dx"

; Function Attrs: alwaysinline nounwind
define void @"\01?sreg@@YAXII@Z"(i32 %n, i32 %val) #0 {
call void @dx.op.tempRegStore.i32(i32 1, i32 %n, i32 %val) ; TempRegStore(index,value)
ret void
}

; Function Attrs: alwaysinline nounwind
define void @"\01?sreg@@YAXIH@Z"(i32 %n, i32 %val) #0 {
call void @dx.op.tempRegStore.i32(i32 1, i32 %n, i32 %val) ; TempRegStore(index,value)
ret void
}

; Function Attrs: alwaysinline nounwind
define void @"\01?sreg@@YAXIM@Z"(i32 %n, float %val) #0 {
call void @dx.op.tempRegStore.f32(i32 1, i32 %n, float %val) ; TempRegStore(index,value)
ret void
}

; Function Attrs: alwaysinline nounwind readonly
define i32 @"\01?ureg@@YAII@Z"(i32 %n) #1 {
%r = call i32 @dx.op.tempRegLoad.i32(i32 0, i32 %n) ; TempRegLoad(index)
ret i32 %r
}

; Function Attrs: alwaysinline nounwind readonly
define i32 @"\01?ireg@@YAHI@Z"(i32 %n) #1 {
%r = call i32 @dx.op.tempRegLoad.i32(i32 0, i32 %n) ; TempRegLoad(index)
ret i32 %r
}

; Function Attrs: alwaysinline nounwind readonly
define float @"\01?freg@@YAMI@Z"(i32 %n) #1 {
%r = call float @dx.op.tempRegLoad.f32(i32 0, i32 %n) ; TempRegLoad(index)
ret float %r
}

; Function Attrs: nounwind
declare void @dx.op.tempRegStore.i32(i32, i32, i32) #2

; Function Attrs: nounwind
declare void @dx.op.tempRegStore.f32(i32, i32, float) #2

; Function Attrs: nounwind readonly
declare i32 @dx.op.tempRegLoad.i32(i32, i32) #3

; Function Attrs: nounwind readonly
declare float @dx.op.tempRegLoad.f32(i32, i32) #3

attributes #0 = { alwaysinline nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="0" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { alwaysinline nounwind readonly "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="0" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind }
attributes #3 = { nounwind readonly }

!llvm.ident = !{!0}
!dx.version = !{!1}
!dx.valver = !{!2}
!dx.shaderModel = !{!3}
!dx.resources = !{!4}
!dx.typeAnnotations = !{!5}
!dx.entryPoints = !{!23}

!0 = !{!"clang version 3.7 (tags/RELEASE_370/final)"}
!1 = !{i32 1, i32 6}
!2 = !{i32 0, i32 0}
!3 = !{!"lib", i32 6, i32 3}
!4 = !{null, null, null, null}
!5 = !{i32 1, void (i32, i32)* @"\01?sreg@@YAXII@Z", !6, void (i32, i32)* @"\01?sreg@@YAXIH@Z", !11, void (i32, float)* @"\01?sreg@@YAXIM@Z", !14, i32 (i32)* @"\01?ureg@@YAII@Z", !17, i32 (i32)* @"\01?ireg@@YAHI@Z", !19, float (i32)* @"\01?freg@@YAMI@Z", !21}
!6 = !{!7, !9, !9}
!7 = !{i32 1, !8, !8}
!8 = !{}
!9 = !{i32 0, !10, !8}
!10 = !{i32 7, i32 5}
!11 = !{!7, !9, !12}
!12 = !{i32 0, !13, !8}
!13 = !{i32 7, i32 4}
!14 = !{!7, !9, !15}
!15 = !{i32 0, !16, !8}
!16 = !{i32 7, i32 9}
!17 = !{!18, !9}
!18 = !{i32 1, !10, !8}
!19 = !{!20, !9}
!20 = !{i32 1, !13, !8}
!21 = !{!22, !9}
!22 = !{i32 1, !16, !8}
!23 = !{null, !"", null, !4, null}
21 changes: 21 additions & 0 deletions tools/clang/test/HLSLFileCheck/dxil/linker/use-TempReg.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// RUN: %dxc -T lib_6_3 %s | FileCheck %s

// CHECK: define void @main()
// CHECK: call i32 @dx.op.loadInput.i32
// CHECK: call void
// CHECK-SAME: sreg
// CHECK: call i32
// CHECK-SAME: ureg
// CHECK: call void @dx.op.storeOutput.i32

// dxc -T lib_6_3 -Fo use-TempReg.dxl
// dxl -E=main -T vs_6_0 -Fo shader.dxo TempReg.dxl;use-TempReg.dxl

#include "TempReg.hlslh"

[shader("vertex")]
uint main(uint In : IN) : OUT {
sreg(0, In);
return ureg(0);
}

53 changes: 50 additions & 3 deletions tools/clang/unittests/HLSL/LinkerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class LinkerTest
TEST_METHOD(RunLinkToLibWithNoExports);
TEST_METHOD(RunLinkWithPotentialIntrinsicNameCollisions);
TEST_METHOD(RunLinkWithValidatorVersion);
TEST_METHOD(RunLinkWithTempReg);


dxc::DxcDllSupport m_dllSupport;
Expand All @@ -83,17 +84,33 @@ class LinkerTest
VERIFY_SUCCEEDED(
pLibrary->CreateBlobFromFile(fullPath.c_str(), nullptr, &pSource));

CComPtr<IDxcIncludeHandler> pIncludeHandler;
VERIFY_SUCCEEDED(pLibrary->CreateIncludeHandler(&pIncludeHandler));

CComPtr<IDxcCompiler> pCompiler;
CComPtr<IDxcOperationResult> pResult;
CComPtr<IDxcBlob> pProgram;

VERIFY_SUCCEEDED(
m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"", pShaderTarget,
VERIFY_SUCCEEDED(pCompiler->Compile(pSource, fullPath.c_str(), L"", pShaderTarget,
const_cast<LPCWSTR*>(pArguments.data()), pArguments.size(),
nullptr, 0,
nullptr, &pResult));
VERIFY_SUCCEEDED(pResult->GetResult(pResultBlob));
pIncludeHandler, &pResult));
CheckOperationSucceeded(pResult, pResultBlob);
}

void AssembleLib(LPCWSTR filename, IDxcBlob **pResultBlob) {
std::wstring fullPath = hlsl_test::GetPathToHlslDataFile(filename);
CComPtr<IDxcLibrary> pLibrary;
VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
CComPtr<IDxcBlobEncoding> pSource;
VERIFY_SUCCEEDED(pLibrary->CreateBlobFromFile(fullPath.c_str(), nullptr, &pSource));
CComPtr<IDxcAssembler> pAssembler;
VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
CComPtr<IDxcOperationResult> pResult;
VERIFY_SUCCEEDED(pAssembler->AssembleToContainer(pSource, &pResult));
CheckOperationSucceeded(pResult, pResultBlob);
}

void RegisterDxcModule(LPCWSTR pLibName, IDxcBlob *pBlob,
Expand Down Expand Up @@ -662,3 +679,33 @@ TEST_F(LinkerTest, RunLinkWithValidatorVersion) {
{"!dx.valver = !{(![0-9]+)}.*\n\\1 = !{i32 1, i32 3}"},
{}, {L"-validator-version", L"1.3"}, /*regex*/ true);
}

TEST_F(LinkerTest, RunLinkWithTempReg) {
// TempRegLoad/TempRegStore not normally usable from HLSL.
// This assembly library exposes these through overloaded wrapper functions
// void sreg(uint index, <type> value) to store register, overloaded for uint, int, and float
// uint ureg(uint index) to load register as uint
// int ireg(int index) to load register as int
// float freg(uint index) to load register as float

// This test verifies this scenario works, by assembling this library,
// compiling a library with an entry point that uses sreg/ureg,
// then linking these to a final standard vs_6_0 DXIL shader.

CComPtr<IDxcBlob> pTempRegLib;
AssembleLib(L"..\\HLSLFileCheck\\dxil\\linker\\TempReg.ll", &pTempRegLib);
CComPtr<IDxcBlob> pEntryLib;
CompileLib(L"..\\HLSLFileCheck\\dxil\\linker\\use-TempReg.hlsl", &pEntryLib, {}, L"lib_6_3");
CComPtr<IDxcLinker> pLinker;
CreateLinker(&pLinker);
LPCWSTR libName = L"entry";
RegisterDxcModule(libName, pEntryLib, pLinker);

LPCWSTR libResName = L"TempReg";
RegisterDxcModule(libResName, pTempRegLib, pLinker);

Link(L"main", L"vs_6_0", pLinker, {libResName, libName}, {
"call void @dx.op.tempRegStore.i32",
"call i32 @dx.op.tempRegLoad.i32"
} ,{});
}