[spirv] Fix vector swizzling on RWBuffer/RWTexture elements (#979)

For such vector swizzling, we cannot get the pointer and use OpStore
like normal vectors. Instead we should use OpImageWrite.
This commit is contained in:
Lei Zhang 2018-01-09 11:22:38 -05:00 коммит произвёл GitHub
Родитель 7ef612d3a4
Коммит ca1df7b35c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 111 добавлений и 17 удалений

Просмотреть файл

@ -4426,11 +4426,14 @@ SPIRVEmitter::tryToAssignToVectorElements(const Expr *lhs,
if (!lhsExpr)
return 0;
if (!isVectorShuffle(lhs)) {
// No vector shuffle needed to be generated for this assignment.
// Should fall back to the normal handling of assignment.
return 0;
}
// Special case for <scalar-value>.x, which will have an AST of
// HLSLVectorElementExpr whose base is an ImplicitCastExpr
// (CK_HLSLVectorSplat). We just need to assign to <scalar-value>
// for such case.
if (const auto *baseCast = dyn_cast<CastExpr>(lhsExpr->getBase()))
if (baseCast->getCastKind() == CastKind::CK_HLSLVectorSplat &&
hlsl::GetHLSLVecSize(baseCast->getType()) == 1)
return processAssignment(baseCast->getSubExpr(), rhs, false);
const Expr *base = nullptr;
hlsl::VectorMemberAccessPositions accessor;
@ -4438,12 +4441,50 @@ SPIRVEmitter::tryToAssignToVectorElements(const Expr *lhs,
const QualType baseType = base->getType();
assert(hlsl::IsHLSLVecType(baseType));
const auto baseSizse = hlsl::GetHLSLVecSize(baseType);
const uint32_t baseTypeId = typeTranslator.translateType(baseType);
const auto baseSize = hlsl::GetHLSLVecSize(baseType);
const auto accessorSize = accessor.Count;
// Whether selecting the whole original vector
bool isSelectOrigin = accessorSize == baseSize;
// Assigning to one component
if (accessorSize == 1) {
if (isBufferTextureIndexing(dyn_cast_or_null<CXXOperatorCallExpr>(base))) {
// Assigning to one component of a RWBuffer/RWTexture element
// We need to use OpImageWrite here.
// Compose the new vector value first
const uint32_t oldVec = doExpr(base);
const uint32_t newVec = theBuilder.createCompositeInsert(
baseTypeId, oldVec, {accessor.Swz0}, rhs);
const auto result = tryToAssignToRWBufferRWTexture(base, newVec);
assert(result); // Definitely RWBuffer/RWTexture assignment
return rhs; // TODO: incorrect for compound assignments
} else {
// Assigning to one normal vector component. Nothing special, just fall
// back to the normal CodeGen path.
return 0;
}
}
if (isSelectOrigin) {
for (uint32_t i = 0; i < accessorSize; ++i) {
uint32_t position;
accessor.GetPosition(i, &position);
if (position != i)
isSelectOrigin = false;
}
}
// Assigning to the original vector
if (isSelectOrigin) {
// Ignore this HLSLVectorElementExpr and dispatch to base
return processAssignment(base, rhs, false);
}
llvm::SmallVector<uint32_t, 4> selectors;
selectors.resize(baseSizse);
selectors.resize(baseSize);
// Assume we are selecting all original elements first.
for (uint32_t i = 0; i < baseSizse; ++i) {
for (uint32_t i = 0; i < baseSize; ++i) {
selectors[i] = i;
}
@ -4453,16 +4494,17 @@ SPIRVEmitter::tryToAssignToVectorElements(const Expr *lhs,
for (uint32_t i = 0; i < accessor.Count; ++i) {
uint32_t position;
accessor.GetPosition(i, &position);
selectors[position] = baseSizse + i;
selectors[position] = baseSize + i;
}
const uint32_t baseTypeId = typeTranslator.translateType(baseType);
const uint32_t vec1 = doExpr(base);
const uint32_t vec1Val = theBuilder.createLoad(baseTypeId, vec1);
const auto vec1 = doExpr(base);
const uint32_t vec1Val =
vec1.isRValue() ? vec1 : theBuilder.createLoad(baseTypeId, vec1);
const uint32_t shuffle =
theBuilder.createVectorShuffle(baseTypeId, vec1Val, rhs, selectors);
theBuilder.createStore(vec1, shuffle);
if (!tryToAssignToRWBufferRWTexture(base, shuffle))
theBuilder.createStore(vec1, shuffle);
// TODO: OK, this return value is incorrect for compound assignments, for
// which cases we should return lvalues. Should at least emit errors if

Просмотреть файл

@ -220,10 +220,6 @@ private:
/// Tries to emit instructions for assigning to the given vector element
/// accessing expression. Returns 0 if the trial fails and no instructions
/// are generated.
///
/// This method handles the cases that we are writing to neither one element
/// or all elements in their original order. For other cases, 0 will be
/// returned and the normal assignment process should be used.
SpirvEvalInfo tryToAssignToVectorElements(const Expr *lhs,
const SpirvEvalInfo &rhs);

Просмотреть файл

@ -0,0 +1,53 @@
// Run: %dxc -T vs_6_0 -E main
RWBuffer<uint> MyRWBuffer;
RWTexture2D<int> MyRWTexture;
RWBuffer<uint4> MyRWBuffer4;
RWTexture3D<uint3> MyRWTexture3;
// CHECK: [[c25:%\d+]] = OpConstantComposite %v3uint %uint_25 %uint_25 %uint_25
// CHECK: [[c26:%\d+]] = OpConstantComposite %v4uint %uint_26 %uint_26 %uint_26 %uint_26
// CHECK: [[c28:%\d+]] = OpConstantComposite %v2uint %uint_28 %uint_28
void main() {
// <scalar-value>.x
// CHECK: [[buf:%\d+]] = OpLoad %type_buffer_image %MyRWBuffer
// CHECK-NEXT: OpImageWrite [[buf]] %uint_1 %uint_15
MyRWBuffer[1].x = 15;
// <scalar-value>.x
// CHECK: [[tex:%\d+]] = OpLoad %type_2d_image %MyRWTexture
// CHECK-NEXT: OpImageWrite [[tex]] {{%\d+}} %int_16
MyRWTexture[uint2(2, 3)].x = 16;
// Out-of-order swizzling
// CHECK: [[buf:%\d+]] = OpLoad %type_buffer_image_0 %MyRWBuffer4
// CHECK-NEXT: [[old:%\d+]] = OpImageRead %v4uint [[buf]] %uint_4 None
// CHECK-NEXT: [[new:%\d+]] = OpVectorShuffle %v4uint [[old]] [[c25]] 6 1 4 5
// CHECK-NEXT: [[buf:%\d+]] = OpLoad %type_buffer_image_0 %MyRWBuffer4
// CHECK-NEXT: OpImageWrite [[buf]] %uint_4 [[new]]
MyRWBuffer4[4].zwx = 25;
// Swizzling resulting in the original vector
// CHECK: [[buf:%\d+]] = OpLoad %type_buffer_image_0 %MyRWBuffer4
// CHECK-NEXT: OpImageWrite [[buf]] %uint_4 [[c26]]
MyRWBuffer4[4].xyzw = 26;
// Selecting one element
// CHECK: [[tex:%\d+]] = OpLoad %type_3d_image %MyRWTexture3
// CHECK-NEXT: [[old:%\d+]] = OpImageRead %v4uint [[tex]] {{%\d+}} None
// CHECK-NEXT: [[v3:%\d+]] = OpVectorShuffle %v3uint [[old]] [[old]] 0 1 2
// CHECK-NEXT: [[new:%\d+]] = OpCompositeInsert %v3uint %uint_27 [[v3]] 1
// CHECK-NEXT: [[tex:%\d+]] = OpLoad %type_3d_image %MyRWTexture3
// CHECK-NEXT: OpImageWrite [[tex]] {{%\d+}} [[new]]
MyRWTexture3[uint3(5, 6, 7)].y = 27;
// In-order swizzling
// CHECK: [[tex:%\d+]] = OpLoad %type_3d_image %MyRWTexture3
// CHECK-NEXT: [[old:%\d+]] = OpImageRead %v4uint [[tex]] {{%\d+}} None
// CHECK-NEXT: [[v3:%\d+]] = OpVectorShuffle %v3uint [[old]] [[old]] 0 1 2
// CHECK-NEXT: [[new:%\d+]] = OpVectorShuffle %v3uint [[v3]] [[c28]] 3 4 2
// CHECK-NEXT: [[tex:%\d+]] = OpLoad %type_3d_image %MyRWTexture3
// CHECK-NEXT: OpImageWrite [[tex]] {{%\d+}} [[new]]
MyRWTexture3[uint3(8, 9, 10)].xy = 28;
}

Просмотреть файл

@ -156,6 +156,9 @@ TEST_F(FileTest, UnaryOpLogicalNot) {
// For assignments
TEST_F(FileTest, BinaryOpAssign) { runFileTest("binary-op.assign.hlsl"); }
TEST_F(FileTest, BinaryOpAssignVector) {
runFileTest("binary-op.assign.vector.hlsl");
}
TEST_F(FileTest, BinaryOpAssignComposite) {
runFileTest("binary-op.assign.composite.hlsl");
}