Skip to content
Open
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 docs/DXIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3214,6 +3214,8 @@ INSTR.LINALGILLEGALKDIM %0 matrix K dimension out
INSTR.LINALGMATRIX2PARTSMUSTMATCH %0 matrix %1 '%2' must match %3 matrix %4 '%5'.
INSTR.LINALGMATRIXDIMKVECKMISMATCH %0 vector size '%1' must be %2 for input matrix with K '%3' and Type '%4'
INSTR.LINALGMATRIXDIMVECTORMISMATCH %0 vector size '%1' must match input matrix M dimension '%2'
INSTR.LINALGMATRIXGSMEMMUSTBELARGEENOUGH Groupshared memory holds '%0' scalars but must hold at least '%1' scalars.
INSTR.LINALGMATRIXGSMEMTYPEMUSTMATCH Groupshared memory inner type '%0' must match %1 matrix type '%2'.
INSTR.LINALGMATRIXLAYOUTREQSTRIDE %0 with layout '%1' requires stride 0.
INSTR.LINALGMATRIXLOADTHREADREQUIRESBAB Loading matrix with Thread scope requires ByteAddressBuffer.
INSTR.LINALGMATRIXMATRIXKDIMMUSTMATCH K dim of A matrix '%0' must match K dim of B matrix '%1'. %2 != %3.
Expand Down
61 changes: 61 additions & 0 deletions lib/DxilValidation/DxilValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#include <algorithm>
#include <deque>
#include <optional>
#include <string>
#include <unordered_set>

using namespace llvm;
Expand Down Expand Up @@ -1225,6 +1226,66 @@ static void ValidateLinAlgMatrixStoreToDescriptor(CallInst *CI,
static void ValidateLinAlgMatrixStoreToMemory(CallInst *CI,
ValidationContext &ValCtx) {
ValidateLinAlgOpParameters(CI, ValCtx);
DxilInst_LinAlgMatrixStoreToMemory Op(CI);
std::optional<LinAlgTargetType> Mat =
GetCheckedLATT(Op.get_matrix()->getType(), ValCtx);
if (!Mat)
return;

// Scope must be wave/threadgroup
if (Mat->Scope != DXIL::MatrixScope::Wave &&
Mat->Scope != DXIL::MatrixScope::ThreadGroup)
ValCtx.EmitInstrFormatError(
CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2,
{"Input", MatrixScopeToString(Mat->Scope), "Wave", "ThreadGroup"});

GEPOperator *GSGEP = cast<GEPOperator>(Op.get_memory());

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chris B (@llvm-beanz) I'm pretty sure there is a better way to pull the inner most type out from the memory operator here but I just wanted to get something written down to unblock progress.

Does this seem right or should I do something else here. also can we even assume its always a GEP? Copilot seems to say no but I'm not sure what else it would be

GlobalVariable *GSMem = cast<GlobalVariable>(GSGEP->getPointerOperand());
Comment on lines +1242 to +1243
Type *GSMemInnerTy = GSMem->getType();
unsigned GSScalarCount = 1;
if (PointerType *GSMemPtrTy = dyn_cast<PointerType>(GSMemInnerTy))
GSMemInnerTy = GSMemPtrTy->getPointerElementType();
if (ArrayType *GSMemArrTy = dyn_cast<ArrayType>(GSMemInnerTy)) {
GSMemInnerTy = GSMemArrTy->getArrayElementType();
GSScalarCount *= GSMemArrTy->getNumElements();
}
if (VectorType *GSMemVecTy = dyn_cast<VectorType>(GSMemInnerTy)) {
GSMemInnerTy = GSMemVecTy->getVectorElementType();
GSScalarCount *= GSMemVecTy->getNumElements();
}

// if gs memory inner type != i32 then matrix elem type must match it
if (!GSMemInnerTy->isIntegerTy(32) &&
!IsComponentTypeSameNativeType(Mat->Type, GSMemInnerTy))
ValCtx.EmitInstrFormatError(
CI, ValidationRule::InstrLinAlgMatrixGSMemTypeMustMatch,
{TypeToString(GSMemInnerTy), "input",
ComponentTypeToString(Mat->Type)});

// gs memory must be large enough for the write
unsigned ElementsPerScalar = ComponentTypeElementsPerScalar(Mat->Type);
unsigned ExpectedScalarCount =
(Mat->N + ElementsPerScalar - 1) / ElementsPerScalar * Mat->M;
if (ExpectedScalarCount > GSScalarCount)
Comment on lines +1266 to +1269
ValCtx.EmitInstrFormatError(
CI, ValidationRule::InstrLinAlgMatrixGSMemMustBeLargeEnough,
{std::to_string(GSScalarCount), std::to_string(ExpectedScalarCount)});

// if it is constant then offset must be 128-byte aligned
if (ConstantInt *OffsetV = dyn_cast<ConstantInt>(Op.get_offset())) {
unsigned Offset = OffsetV->getLimitedValue();
if (Offset % 128 != 0)
ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrParamMultiple,
{"Offset", "128", std::to_string(Offset)});
}

// if it is constant then stride must be 16-byte aligned
if (ConstantInt *StrideV = dyn_cast<ConstantInt>(Op.get_stride())) {
unsigned Stride = StrideV->getLimitedValue();
if (Stride % 16 != 0)
ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrParamMultiple,
{"Stride", "16", std::to_string(Stride)});
}
}

static void ValidateLinAlgMatVecMul(CallInst *CI, ValidationContext &ValCtx,
Expand Down
23 changes: 23 additions & 0 deletions lib/DxilValidation/DxilValidationUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -724,4 +724,27 @@ std::string TypeToString(llvm::Type *Ty) {
return OS.str();
}

bool IsComponentTypeSameNativeType(DXIL::ComponentType CT, llvm::Type *Ty) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chris B (@llvm-beanz) I think this is necessary since we don't really have a mapping for ComponentType to llvm::Type but figured I'd specifically highlight it since imo it's not trivially correct

switch (CT) {
case DXIL::ComponentType::I16:
case DXIL::ComponentType::U16:
return Ty->isIntegerTy(16);
case DXIL::ComponentType::I32:
case DXIL::ComponentType::U32:
return Ty->isIntegerTy(32);
case DXIL::ComponentType::I64:
case DXIL::ComponentType::U64:
return Ty->isIntegerTy(64);
case DXIL::ComponentType::F16:
return Ty->isHalfTy();
case DXIL::ComponentType::F32:
return Ty->isFloatTy();
case DXIL::ComponentType::F64:
return Ty->isDoubleTy();
// All other CTs cannot be represented in a native type
default:
return false;
}
}

} // namespace hlsl
2 changes: 2 additions & 0 deletions lib/DxilValidation/DxilValidationUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,6 @@ llvm::StringRef MatrixUseToString(DXIL::MatrixUse MU);
llvm::StringRef MatrixLayoutToString(DXIL::MatrixLayout ML);

std::string TypeToString(llvm::Type *Ty);

bool IsComponentTypeSameNativeType(DXIL::ComponentType CT, llvm::Type *Ty);
} // namespace hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ groupshared float SharedArr[64];
void main() {
// CHECK-LABEL: define void @main()

// CHECK: call void @dx.op.linAlgMatrixStoreToMemory.mC4M5N4U1S2.f32(i32 -2147483627,
// CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, float addrspace(3)* getelementptr
// CHECK: call void @dx.op.linAlgMatrixStoreToMemory.mC9M5N4U1S2.f32(i32 -2147483627,
// CHECK-SAME: %dx.types.LinAlgMatrixC9M5N4U1S2 %{{.*}}, float addrspace(3)* getelementptr
// CHECK-SAME: inbounds ([64 x float], [64 x float] addrspace(3)* @"\01?SharedArr@@3PAMA",
// CHECK-SAME: i32 0, i32 0), i32 1, i32 2, i32 3) ; LinAlgMatrixStoreToMemory(matrix,memory,offset,stride,layout)
// CHECK-SAME: i32 0, i32 0), i32 896, i32 48, i32 3) ; LinAlgMatrixStoreToMemory(matrix,memory,offset,stride,layout)

// CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M5N4U1S2, [64 x float] addrspace(3)*, i32, i32, i32)"
// CHECK2-SAME: (i32 410, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, [64 x float] addrspace(3)* @"\01?SharedArr@@3PAMA",
// CHECK2-SAME: i32 1, i32 2, i32 3)
__builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat;
// CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC9M5N4U1S2, [64 x float] addrspace(3)*, i32, i32, i32)"
// CHECK2-SAME: (i32 410, %dx.types.LinAlgMatrixC9M5N4U1S2 %{{.*}}, [64 x float] addrspace(3)* @"\01?SharedArr@@3PAMA",
// CHECK2-SAME: i32 896, i32 48, i32 3)
__builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(9, 5, 4, 1, 2)]] mat;
__builtin_LinAlg_FillMatrix(mat, 1);
__builtin_LinAlg_MatrixStoreToMemory(mat, SharedArr, 1, 2, 3);
__builtin_LinAlg_MatrixStoreToMemory(mat, SharedArr, 128 * 7, 16 * 3, 3);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ groupshared float4 SharedArr[64];
void main() {
// CHECK-LABEL: define void @main()

// CHECK: call void @dx.op.linAlgMatrixStoreToMemory.mC4M5N4U1S2.v4f32(i32 -2147483627,
// CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, <4 x float> addrspace(3)* getelementptr
// CHECK: call void @dx.op.linAlgMatrixStoreToMemory.mC9M5N4U1S2.v4f32(i32 -2147483627,
// CHECK-SAME: %dx.types.LinAlgMatrixC9M5N4U1S2 %{{.*}}, <4 x float> addrspace(3)* getelementptr
// CHECK-SAME: inbounds ([64 x <4 x float>], [64 x <4 x float>] addrspace(3)*
// CHECK-SAME: @"\01?SharedArr@@3PAV?$vector@M$03@@A", i32 0, i32 0), i32 1, i32 2, i32 3)
// CHECK-SAME: @"\01?SharedArr@@3PAV?$vector@M$03@@A", i32 0, i32 0), i32 128, i32 16, i32 3)
// CHECK-SAME: ; LinAlgMatrixStoreToMemory(matrix,memory,offset,stride,layout)

// CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M5N4U1S2, [64 x <4 x float>] addrspace(3)*,
// CHECK2-SAME: i32, i32, i32)"(i32 410, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, [64 x <4 x float>] addrspace(3)*
// CHECK2-SAME: @"\01?SharedArr@@3PAV?$vector@M$03@@A", i32 1, i32 2, i32 3)
__builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat;
// CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC9M5N4U1S2, [64 x <4 x float>] addrspace(3)*,
// CHECK2-SAME: i32, i32, i32)"(i32 410, %dx.types.LinAlgMatrixC9M5N4U1S2 %{{.*}}, [64 x <4 x float>] addrspace(3)*
// CHECK2-SAME: @"\01?SharedArr@@3PAV?$vector@M$03@@A", i32 128, i32 16, i32 3)
__builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(9, 5, 4, 1, 2)]] mat;
__builtin_LinAlg_FillMatrix(mat, 1);
__builtin_LinAlg_MatrixStoreToMemory(mat, SharedArr, 1, 2, 3);
__builtin_LinAlg_MatrixStoreToMemory(mat, SharedArr, 128, 16, 3);
}
Loading
Loading