Skip to content

Commit 0ffd60a

Browse files
author
Greg Roth
authored
[SM6.9] Native vector load/store lowering (microsoft#7292)
Enables the declaration of long vector types for raw buffers, the lowering of those and traditional vectors in loads and stores maintaining the native types with new dxil ops along with validation and testing support of the same. Allow declaring long vector rawbuffer resources. Previously disallowed along with other global types, this provides a mechanism for indicating which buffers are raw and allowing them to contain long vectors, continuing to produce an error for other resource types verified by existing tests Introduce native vector DXIL load/store intrinsics. Add new raw buffer vector load/store intrinsics using the new vector overload types. Include them in validation associated with similar load/stores Lower native vector raw buffers load/stores into new ops. When the loaded/stored type is a vector of more than 1 element, the shader model is 6.9 or higher, and the operation is on a raw buffer, enable the generation of a native vector raw buffer load or store. Incidental removal of unused parameter in load translation and some refactoring of the lowering to flow better with the new resret types. add validation and compute shader tests Vector to scalar raw buffer load lowering pass Native vector loads and stores are generated for 6.9 targets and above. This includes the 6.x target used when compiling to libraries. This adds a pass run when linking that will lower the vector operations to scalar operations for shader models that don't have native vector support. This allows libraries compiled for supportive shader models to be linked to targets without support. Validate native vector loads and stores for properly defined parameters of the correct type. Add tests for both vector load/stores and the original scalar load/stores since they share a lot of validation code. Fixes microsoft#7118
1 parent e50f599 commit 0ffd60a

23 files changed

+2991
-142
lines changed

include/dxc/DXIL/DxilConstants.h

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -898,8 +898,11 @@ enum class OpCode : unsigned {
898898
GetDimensions = 72, // gets texture size information
899899
RawBufferLoad = 139, // reads from a raw buffer and structured buffer
900900
RawBufferStore = 140, // writes to a RWByteAddressBuffer or RWStructuredBuffer
901-
TextureLoad = 66, // reads texel data without any filtering or sampling
902-
TextureStore = 67, // reads texel data without any filtering or sampling
901+
RawBufferVectorLoad = 303, // reads from a raw buffer and structured buffer
902+
RawBufferVectorStore =
903+
304, // writes to a RWByteAddressBuffer or RWStructuredBuffer
904+
TextureLoad = 66, // reads texel data without any filtering or sampling
905+
TextureStore = 67, // reads texel data without any filtering or sampling
903906
TextureStoreSample = 225, // stores texel data at specified sample index
904907

905908
// Sampler Feedback
@@ -1044,7 +1047,7 @@ enum class OpCode : unsigned {
10441047
NumOpCodes_Dxil_1_7 = 226,
10451048
NumOpCodes_Dxil_1_8 = 258,
10461049

1047-
NumOpCodes = 303 // exclusive last value of enumeration
1050+
NumOpCodes = 305 // exclusive last value of enumeration
10481051
};
10491052
// OPCODE-ENUM:END
10501053

@@ -1278,6 +1281,8 @@ enum class OpCodeClass : unsigned {
12781281
GetDimensions,
12791282
RawBufferLoad,
12801283
RawBufferStore,
1284+
RawBufferVectorLoad,
1285+
RawBufferVectorStore,
12811286
TextureLoad,
12821287
TextureStore,
12831288
TextureStoreSample,
@@ -1356,7 +1361,7 @@ enum class OpCodeClass : unsigned {
13561361
NumOpClasses_Dxil_1_7 = 153,
13571362
NumOpClasses_Dxil_1_8 = 174,
13581363

1359-
NumOpClasses = 177 // exclusive last value of enumeration
1364+
NumOpClasses = 179 // exclusive last value of enumeration
13601365
};
13611366
// OPCODECLASS-ENUM:END
13621367

@@ -1415,6 +1420,12 @@ const unsigned kRawBufferLoadElementOffsetOpIdx = 3;
14151420
const unsigned kRawBufferLoadMaskOpIdx = 4;
14161421
const unsigned kRawBufferLoadAlignmentOpIdx = 5;
14171422

1423+
// RawBufferVectorLoad.
1424+
const unsigned kRawBufferVectorLoadHandleOpIdx = 1;
1425+
const unsigned kRawBufferVectorLoadIndexOpIdx = 2;
1426+
const unsigned kRawBufferVectorLoadElementOffsetOpIdx = 3;
1427+
const unsigned kRawBufferVectorLoadAlignmentOpIdx = 4;
1428+
14181429
// RawBufferStore
14191430
const unsigned kRawBufferStoreHandleOpIdx = 1;
14201431
const unsigned kRawBufferStoreIndexOpIdx = 2;
@@ -1424,7 +1435,14 @@ const unsigned kRawBufferStoreVal1OpIdx = 5;
14241435
const unsigned kRawBufferStoreVal2OpIdx = 6;
14251436
const unsigned kRawBufferStoreVal3OpIdx = 7;
14261437
const unsigned kRawBufferStoreMaskOpIdx = 8;
1427-
const unsigned kRawBufferStoreAlignmentOpIdx = 8;
1438+
const unsigned kRawBufferStoreAlignmentOpIdx = 9;
1439+
1440+
// RawBufferVectorStore
1441+
const unsigned kRawBufferVectorStoreHandleOpIdx = 1;
1442+
const unsigned kRawBufferVectorStoreIndexOpIdx = 2;
1443+
const unsigned kRawBufferVectorStoreElementOffsetOpIdx = 3;
1444+
const unsigned kRawBufferVectorStoreValOpIdx = 4;
1445+
const unsigned kRawBufferVectorStoreAlignmentOpIdx = 5;
14281446

14291447
// TextureStore.
14301448
const unsigned kTextureStoreHandleOpIdx = 1;

include/dxc/DXIL/DxilInstructions.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8923,5 +8923,98 @@ struct DxilInst_HitObject_MakeNop {
89238923
// Metadata
89248924
bool requiresUniformInputs() const { return false; }
89258925
};
8926+
8927+
/// This instruction reads from a raw buffer and structured buffer
8928+
struct DxilInst_RawBufferVectorLoad {
8929+
llvm::Instruction *Instr;
8930+
// Construction and identification
8931+
DxilInst_RawBufferVectorLoad(llvm::Instruction *pInstr) : Instr(pInstr) {}
8932+
operator bool() const {
8933+
return hlsl::OP::IsDxilOpFuncCallInst(
8934+
Instr, hlsl::OP::OpCode::RawBufferVectorLoad);
8935+
}
8936+
// Validation support
8937+
bool isAllowed() const { return true; }
8938+
bool isArgumentListValid() const {
8939+
if (5 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands())
8940+
return false;
8941+
return true;
8942+
}
8943+
// Metadata
8944+
bool requiresUniformInputs() const { return false; }
8945+
// Operand indexes
8946+
enum OperandIdx {
8947+
arg_buf = 1,
8948+
arg_index = 2,
8949+
arg_elementOffset = 3,
8950+
arg_alignment = 4,
8951+
};
8952+
// Accessors
8953+
llvm::Value *get_buf() const { return Instr->getOperand(1); }
8954+
void set_buf(llvm::Value *val) { Instr->setOperand(1, val); }
8955+
llvm::Value *get_index() const { return Instr->getOperand(2); }
8956+
void set_index(llvm::Value *val) { Instr->setOperand(2, val); }
8957+
llvm::Value *get_elementOffset() const { return Instr->getOperand(3); }
8958+
void set_elementOffset(llvm::Value *val) { Instr->setOperand(3, val); }
8959+
llvm::Value *get_alignment() const { return Instr->getOperand(4); }
8960+
void set_alignment(llvm::Value *val) { Instr->setOperand(4, val); }
8961+
int32_t get_alignment_val() const {
8962+
return (int32_t)(llvm::dyn_cast<llvm::ConstantInt>(Instr->getOperand(4))
8963+
->getZExtValue());
8964+
}
8965+
void set_alignment_val(int32_t val) {
8966+
Instr->setOperand(4, llvm::Constant::getIntegerValue(
8967+
llvm::IntegerType::get(Instr->getContext(), 32),
8968+
llvm::APInt(32, (uint64_t)val)));
8969+
}
8970+
};
8971+
8972+
/// This instruction writes to a RWByteAddressBuffer or RWStructuredBuffer
8973+
struct DxilInst_RawBufferVectorStore {
8974+
llvm::Instruction *Instr;
8975+
// Construction and identification
8976+
DxilInst_RawBufferVectorStore(llvm::Instruction *pInstr) : Instr(pInstr) {}
8977+
operator bool() const {
8978+
return hlsl::OP::IsDxilOpFuncCallInst(
8979+
Instr, hlsl::OP::OpCode::RawBufferVectorStore);
8980+
}
8981+
// Validation support
8982+
bool isAllowed() const { return true; }
8983+
bool isArgumentListValid() const {
8984+
if (6 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands())
8985+
return false;
8986+
return true;
8987+
}
8988+
// Metadata
8989+
bool requiresUniformInputs() const { return false; }
8990+
// Operand indexes
8991+
enum OperandIdx {
8992+
arg_uav = 1,
8993+
arg_index = 2,
8994+
arg_elementOffset = 3,
8995+
arg_value0 = 4,
8996+
arg_alignment = 5,
8997+
};
8998+
// Accessors
8999+
llvm::Value *get_uav() const { return Instr->getOperand(1); }
9000+
void set_uav(llvm::Value *val) { Instr->setOperand(1, val); }
9001+
llvm::Value *get_index() const { return Instr->getOperand(2); }
9002+
void set_index(llvm::Value *val) { Instr->setOperand(2, val); }
9003+
llvm::Value *get_elementOffset() const { return Instr->getOperand(3); }
9004+
void set_elementOffset(llvm::Value *val) { Instr->setOperand(3, val); }
9005+
llvm::Value *get_value0() const { return Instr->getOperand(4); }
9006+
void set_value0(llvm::Value *val) { Instr->setOperand(4, val); }
9007+
llvm::Value *get_alignment() const { return Instr->getOperand(5); }
9008+
void set_alignment(llvm::Value *val) { Instr->setOperand(5, val); }
9009+
int32_t get_alignment_val() const {
9010+
return (int32_t)(llvm::dyn_cast<llvm::ConstantInt>(Instr->getOperand(5))
9011+
->getZExtValue());
9012+
}
9013+
void set_alignment_val(int32_t val) {
9014+
Instr->setOperand(5, llvm::Constant::getIntegerValue(
9015+
llvm::IntegerType::get(Instr->getContext(), 32),
9016+
llvm::APInt(32, (uint64_t)val)));
9017+
}
9018+
};
89269019
// INSTR-HELPER:END
89279020
} // namespace hlsl

include/dxc/HLSL/DxilGenerationPass.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ ModulePass *createResumePassesPass();
8181
FunctionPass *createMatrixBitcastLowerPass();
8282
ModulePass *createDxilCleanupAddrSpaceCastPass();
8383
ModulePass *createDxilRenameResourcesPass();
84+
ModulePass *createDxilScalarizeVectorLoadStoresPass();
8485

8586
void initializeDxilLowerCreateHandleForLibPass(llvm::PassRegistry &);
8687
void initializeDxilAllocateResourcesForLibPass(llvm::PassRegistry &);
@@ -115,6 +116,7 @@ void initializeResumePassesPass(llvm::PassRegistry &);
115116
void initializeMatrixBitcastLowerPassPass(llvm::PassRegistry &);
116117
void initializeDxilCleanupAddrSpaceCastPass(llvm::PassRegistry &);
117118
void initializeDxilRenameResourcesPass(llvm::PassRegistry &);
119+
void initializeDxilScalarizeVectorLoadStoresPass(llvm::PassRegistry &);
118120

119121
ModulePass *createDxilValidateWaveSensitivityPass();
120122
void initializeDxilValidateWaveSensitivityPass(llvm::PassRegistry &);

lib/DXIL/DxilOperations.cpp

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2633,6 +2633,24 @@ const OP::OpCodeProperty OP::m_OpCodeProps[(unsigned)OP::OpCode::NumOpCodes] = {
26332633
0,
26342634
{},
26352635
{}}, // Overloads: v
2636+
2637+
// Resources
2638+
{OC::RawBufferVectorLoad,
2639+
"RawBufferVectorLoad",
2640+
OCC::RawBufferVectorLoad,
2641+
"rawBufferVectorLoad",
2642+
Attribute::ReadOnly,
2643+
1,
2644+
{{0x4e7}},
2645+
{{0xe7}}}, // Overloads: hfwidl<hfwidl
2646+
{OC::RawBufferVectorStore,
2647+
"RawBufferVectorStore",
2648+
OCC::RawBufferVectorStore,
2649+
"rawBufferVectorStore",
2650+
Attribute::None,
2651+
1,
2652+
{{0x4e7}},
2653+
{{0xe7}}}, // Overloads: hfwidl<hfwidl
26362654
};
26372655
// OPCODE-OLOADS:END
26382656

@@ -3390,8 +3408,9 @@ void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation,
33903408
}
33913409
return;
33923410
}
3393-
// Instructions: AllocateRayQuery2=258
3394-
if (op == 258) {
3411+
// Instructions: AllocateRayQuery2=258, RawBufferVectorLoad=303,
3412+
// RawBufferVectorStore=304
3413+
if (op == 258 || (303 <= op && op <= 304)) {
33953414
major = 6;
33963415
minor = 9;
33973416
return;
@@ -5739,6 +5758,25 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
57395758
A(pV);
57405759
A(pI32);
57415760
break;
5761+
5762+
// Resources
5763+
case OpCode::RawBufferVectorLoad:
5764+
RRT(pETy);
5765+
A(pI32);
5766+
A(pRes);
5767+
A(pI32);
5768+
A(pI32);
5769+
A(pI32);
5770+
break;
5771+
case OpCode::RawBufferVectorStore:
5772+
A(pV);
5773+
A(pI32);
5774+
A(pRes);
5775+
A(pI32);
5776+
A(pI32);
5777+
A(pETy);
5778+
A(pI32);
5779+
break;
57425780
// OPCODE-OLOAD-FUNCS:END
57435781
default:
57445782
DXASSERT(false, "otherwise unhandled case");
@@ -5888,6 +5926,7 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) {
58885926
case OpCode::StoreVertexOutput:
58895927
case OpCode::StorePrimitiveOutput:
58905928
case OpCode::DispatchMesh:
5929+
case OpCode::RawBufferVectorStore:
58915930
if (FT->getNumParams() <= 4)
58925931
return nullptr;
58935932
return FT->getParamType(4);
@@ -6134,7 +6173,8 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) {
61346173
case OpCode::TextureGatherRaw:
61356174
case OpCode::SampleCmpLevel:
61366175
case OpCode::SampleCmpGrad:
6137-
case OpCode::SampleCmpBias: {
6176+
case OpCode::SampleCmpBias:
6177+
case OpCode::RawBufferVectorLoad: {
61386178
StructType *ST = cast<StructType>(Ty);
61396179
return ST->getElementType(0);
61406180
}

lib/DxilValidation/DxilValidation.cpp

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,34 +1475,35 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode Opcode,
14751475
}
14761476
}
14771477
} break;
1478-
case DXIL::OpCode::RawBufferLoad: {
1478+
case DXIL::OpCode::RawBufferLoad:
14791479
if (!ValCtx.DxilMod.GetShaderModel()->IsSM63Plus()) {
14801480
Type *Ty = OP::GetOverloadType(DXIL::OpCode::RawBufferLoad,
14811481
CI->getCalledFunction());
1482-
if (ValCtx.DL.getTypeAllocSizeInBits(Ty) > 32) {
1482+
if (ValCtx.DL.getTypeAllocSizeInBits(Ty) > 32)
14831483
ValCtx.EmitInstrError(CI, ValidationRule::Sm64bitRawBufferLoadStore);
1484-
}
14851484
}
1486-
DxilInst_RawBufferLoad BufLd(CI);
1485+
LLVM_FALLTHROUGH;
1486+
case DXIL::OpCode::RawBufferVectorLoad: {
1487+
Value *Handle =
1488+
CI->getOperand(DXIL::OperandIndex::kRawBufferLoadHandleOpIdx);
14871489
DXIL::ComponentType CompTy;
14881490
DXIL::ResourceClass ResClass;
14891491
DXIL::ResourceKind ResKind =
1490-
GetResourceKindAndCompTy(BufLd.get_srv(), CompTy, ResClass, ValCtx);
1492+
GetResourceKindAndCompTy(Handle, CompTy, ResClass, ValCtx);
14911493

14921494
if (ResClass != DXIL::ResourceClass::SRV &&
1493-
ResClass != DXIL::ResourceClass::UAV) {
1495+
ResClass != DXIL::ResourceClass::UAV)
1496+
14941497
ValCtx.EmitInstrError(CI, ValidationRule::InstrResourceClassForLoad);
1495-
}
14961498

1497-
Value *Offset = BufLd.get_elementOffset();
1498-
Value *Align = BufLd.get_alignment();
1499-
unsigned AlignSize = 0;
1500-
if (!isa<ConstantInt>(Align)) {
1501-
ValCtx.EmitInstrError(CI,
1502-
ValidationRule::InstrCoordinateCountForRawTypedBuf);
1503-
} else {
1504-
AlignSize = BufLd.get_alignment_val();
1505-
}
1499+
unsigned AlignIdx = DXIL::OperandIndex::kRawBufferLoadAlignmentOpIdx;
1500+
if (DXIL::OpCode::RawBufferVectorLoad == Opcode)
1501+
AlignIdx = DXIL::OperandIndex::kRawBufferVectorLoadAlignmentOpIdx;
1502+
if (!isa<ConstantInt>(CI->getOperand(AlignIdx)))
1503+
ValCtx.EmitInstrError(CI, ValidationRule::InstrConstAlignForRawBuf);
1504+
1505+
Value *Offset =
1506+
CI->getOperand(DXIL::OperandIndex::kRawBufferLoadElementOffsetOpIdx);
15061507
switch (ResKind) {
15071508
case DXIL::ResourceKind::RawBuffer:
15081509
if (!isa<UndefValue>(Offset)) {
@@ -1526,38 +1527,44 @@ static void ValidateResourceDxilOp(CallInst *CI, DXIL::OpCode Opcode,
15261527
if (!ValCtx.DxilMod.GetShaderModel()->IsSM63Plus()) {
15271528
Type *Ty = OP::GetOverloadType(DXIL::OpCode::RawBufferStore,
15281529
CI->getCalledFunction());
1529-
if (ValCtx.DL.getTypeAllocSizeInBits(Ty) > 32) {
1530+
if (ValCtx.DL.getTypeAllocSizeInBits(Ty) > 32)
15301531
ValCtx.EmitInstrError(CI, ValidationRule::Sm64bitRawBufferLoadStore);
1531-
}
15321532
}
1533-
DxilInst_RawBufferStore BufSt(CI);
1534-
DXIL::ComponentType CompTy;
1535-
DXIL::ResourceClass ResClass;
1536-
DXIL::ResourceKind ResKind =
1537-
GetResourceKindAndCompTy(BufSt.get_uav(), CompTy, ResClass, ValCtx);
1538-
1539-
if (ResClass != DXIL::ResourceClass::UAV) {
1540-
ValCtx.EmitInstrError(CI, ValidationRule::InstrResourceClassForUAVStore);
1541-
}
1542-
1543-
ConstantInt *Mask = dyn_cast<ConstantInt>(BufSt.get_mask());
1533+
DxilInst_RawBufferStore bufSt(CI);
1534+
ConstantInt *Mask = dyn_cast<ConstantInt>(bufSt.get_mask());
15441535
unsigned StValMask =
1545-
StoreValueToMask({BufSt.get_value0(), BufSt.get_value1(),
1546-
BufSt.get_value2(), BufSt.get_value3()});
1536+
StoreValueToMask({bufSt.get_value0(), bufSt.get_value1(),
1537+
bufSt.get_value2(), bufSt.get_value3()});
15471538

15481539
if (!ValidateStorageMasks(CI, Opcode, Mask, StValMask, false /*IsTyped*/,
15491540
ValCtx))
15501541
return;
1542+
}
1543+
LLVM_FALLTHROUGH;
1544+
case DXIL::OpCode::RawBufferVectorStore: {
1545+
Value *Handle =
1546+
CI->getOperand(DXIL::OperandIndex::kRawBufferStoreHandleOpIdx);
1547+
DXIL::ComponentType CompTy;
1548+
DXIL::ResourceClass ResClass;
1549+
DXIL::ResourceKind ResKind =
1550+
GetResourceKindAndCompTy(Handle, CompTy, ResClass, ValCtx);
15511551

1552-
Value *Offset = BufSt.get_elementOffset();
1553-
Value *Align = BufSt.get_alignment();
1554-
unsigned AlignSize = 0;
1555-
if (!isa<ConstantInt>(Align)) {
1556-
ValCtx.EmitInstrError(CI,
1557-
ValidationRule::InstrCoordinateCountForRawTypedBuf);
1558-
} else {
1559-
AlignSize = BufSt.get_alignment_val();
1552+
if (ResClass != DXIL::ResourceClass::UAV)
1553+
ValCtx.EmitInstrError(CI, ValidationRule::InstrResourceClassForUAVStore);
1554+
1555+
unsigned AlignIdx = DXIL::OperandIndex::kRawBufferStoreAlignmentOpIdx;
1556+
if (DXIL::OpCode::RawBufferVectorStore == Opcode) {
1557+
AlignIdx = DXIL::OperandIndex::kRawBufferVectorStoreAlignmentOpIdx;
1558+
unsigned ValueIx = DXIL::OperandIndex::kRawBufferVectorStoreValOpIdx;
1559+
if (isa<UndefValue>(CI->getOperand(ValueIx)))
1560+
ValCtx.EmitInstrError(CI,
1561+
ValidationRule::InstrUndefinedValueForUAVStore);
15601562
}
1563+
if (!isa<ConstantInt>(CI->getOperand(AlignIdx)))
1564+
ValCtx.EmitInstrError(CI, ValidationRule::InstrConstAlignForRawBuf);
1565+
1566+
Value *Offset =
1567+
CI->getOperand(DXIL::OperandIndex::kRawBufferStoreElementOffsetOpIdx);
15611568
switch (ResKind) {
15621569
case DXIL::ResourceKind::RawBuffer:
15631570
if (!isa<UndefValue>(Offset)) {
@@ -1684,6 +1691,8 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI,
16841691
case DXIL::OpCode::CBufferLoadLegacy:
16851692
case DXIL::OpCode::RawBufferLoad:
16861693
case DXIL::OpCode::RawBufferStore:
1694+
case DXIL::OpCode::RawBufferVectorLoad:
1695+
case DXIL::OpCode::RawBufferVectorStore:
16871696
ValidateResourceDxilOp(CI, Opcode, ValCtx);
16881697
break;
16891698
// Input output.

0 commit comments

Comments
 (0)