|
@@ -828,7 +828,58 @@ SpirvEvalInfo SPIRVEmitter::loadIfGLValue(const Expr *expr,
|
|
|
valType =
|
|
|
typeTranslator.translateType(expr->getType(), info.getLayoutRule());
|
|
|
}
|
|
|
- return info.setResultId(theBuilder.createLoad(valType, info)).setRValue();
|
|
|
+
|
|
|
+ uint32_t loadedId = theBuilder.createLoad(valType, info);
|
|
|
+
|
|
|
+ // Special-case: According to the SPIR-V Spec: There is no physical size or
|
|
|
+ // bit pattern defined for boolean type. Therefore an unsigned integer is used
|
|
|
+ // to represent booleans when layout is required. In such cases, after loading
|
|
|
+ // the uint, we should perform a comparison.
|
|
|
+ {
|
|
|
+ uint32_t vecSize = 1, numRows = 0, numCols = 0;
|
|
|
+ if (info.getLayoutRule() != LayoutRule::Void &&
|
|
|
+ isBoolOrVecMatOfBoolType(expr->getType())) {
|
|
|
+ const auto exprType = expr->getType();
|
|
|
+ QualType uintType = astContext.UnsignedIntTy;
|
|
|
+ QualType boolType = astContext.BoolTy;
|
|
|
+ if (TypeTranslator::isScalarType(exprType) ||
|
|
|
+ TypeTranslator::isVectorType(exprType, nullptr, &vecSize)) {
|
|
|
+ const auto fromType =
|
|
|
+ vecSize == 1 ? uintType
|
|
|
+ : astContext.getExtVectorType(uintType, vecSize);
|
|
|
+ const auto toType =
|
|
|
+ vecSize == 1 ? boolType
|
|
|
+ : astContext.getExtVectorType(boolType, vecSize);
|
|
|
+ loadedId = castToBool(loadedId, fromType, toType);
|
|
|
+ } else {
|
|
|
+ const bool isMat =
|
|
|
+ TypeTranslator::isMxNMatrix(exprType, nullptr, &numRows, &numCols);
|
|
|
+ assert(isMat);
|
|
|
+ const auto uintRowQualType =
|
|
|
+ astContext.getExtVectorType(uintType, numCols);
|
|
|
+ const auto uintRowQualTypeId =
|
|
|
+ typeTranslator.translateType(uintRowQualType);
|
|
|
+ const auto boolRowQualType =
|
|
|
+ astContext.getExtVectorType(boolType, numCols);
|
|
|
+ const auto boolRowQualTypeId =
|
|
|
+ typeTranslator.translateType(boolRowQualType);
|
|
|
+ const uint32_t resultTypeId =
|
|
|
+ theBuilder.getMatType(boolType, boolRowQualTypeId, numRows);
|
|
|
+ llvm::SmallVector<uint32_t, 4> rows;
|
|
|
+ for (uint32_t i = 0; i < numRows; ++i) {
|
|
|
+ const auto row = theBuilder.createCompositeExtract(uintRowQualTypeId,
|
|
|
+ loadedId, {i});
|
|
|
+ rows.push_back(castToBool(row, uintRowQualType, boolRowQualType));
|
|
|
+ }
|
|
|
+ loadedId = theBuilder.createCompositeConstruct(resultTypeId, rows);
|
|
|
+ }
|
|
|
+ // Now that it is converted to Bool, it has no layout rule.
|
|
|
+ // This result-id should be evaluated as bool from here on out.
|
|
|
+ info.setLayoutRule(LayoutRule::Void);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return info.setResultId(loadedId).setRValue();
|
|
|
}
|
|
|
|
|
|
SpirvEvalInfo SPIRVEmitter::loadIfAliasVarRef(const Expr *expr) {
|
|
@@ -1165,7 +1216,7 @@ void SPIRVEmitter::doVarDecl(const VarDecl *decl) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- uint32_t varId = 0;
|
|
|
+ SpirvEvalInfo varId(0);
|
|
|
|
|
|
// The contents in externally visible variables can be updated via the
|
|
|
// pipeline. They should be handled differently from file and function scope
|
|
@@ -4181,9 +4232,11 @@ SpirvEvalInfo
|
|
|
SPIRVEmitter::doExtMatrixElementExpr(const ExtMatrixElementExpr *expr) {
|
|
|
const Expr *baseExpr = expr->getBase();
|
|
|
const auto baseInfo = doExpr(baseExpr);
|
|
|
+ const auto layoutRule = baseInfo.getLayoutRule();
|
|
|
+ const auto elemType = hlsl::GetHLSLMatElementType(baseExpr->getType());
|
|
|
const auto accessor = expr->getEncodedElementAccess();
|
|
|
- const uint32_t elemType = typeTranslator.translateType(
|
|
|
- hlsl::GetHLSLMatElementType(baseExpr->getType()));
|
|
|
+ const uint32_t elemTypeId =
|
|
|
+ typeTranslator.translateType(elemType, layoutRule);
|
|
|
|
|
|
uint32_t rowCount = 0, colCount = 0;
|
|
|
hlsl::GetHLSLMatRowColCount(baseExpr->getType(), rowCount, colCount);
|
|
@@ -4211,7 +4264,7 @@ SPIRVEmitter::doExtMatrixElementExpr(const ExtMatrixElementExpr *expr) {
|
|
|
indices[i] = theBuilder.getConstantInt32(indices[i]);
|
|
|
|
|
|
const uint32_t ptrType =
|
|
|
- theBuilder.getPointerType(elemType, baseInfo.getStorageClass());
|
|
|
+ theBuilder.getPointerType(elemTypeId, baseInfo.getStorageClass());
|
|
|
if (!indices.empty()) {
|
|
|
assert(!baseInfo.isRValue());
|
|
|
// Load the element via access chain
|
|
@@ -4221,19 +4274,32 @@ SPIRVEmitter::doExtMatrixElementExpr(const ExtMatrixElementExpr *expr) {
|
|
|
// be the source pointer.
|
|
|
elem = baseInfo;
|
|
|
}
|
|
|
- elem = theBuilder.createLoad(elemType, elem);
|
|
|
+ elem = theBuilder.createLoad(elemTypeId, elem);
|
|
|
} else { // e.g., (mat1 + mat2)._m11
|
|
|
- elem = theBuilder.createCompositeExtract(elemType, baseInfo, indices);
|
|
|
+ elem = theBuilder.createCompositeExtract(elemTypeId, baseInfo, indices);
|
|
|
}
|
|
|
elements.push_back(elem);
|
|
|
}
|
|
|
|
|
|
+ const auto size = elements.size();
|
|
|
auto valueId = elements.front();
|
|
|
- if (elements.size() > 1) {
|
|
|
- const uint32_t vecType = theBuilder.getVecType(elemType, elements.size());
|
|
|
+ if (size > 1) {
|
|
|
+ const uint32_t vecType = theBuilder.getVecType(elemTypeId, size);
|
|
|
valueId = theBuilder.createCompositeConstruct(vecType, elements);
|
|
|
}
|
|
|
|
|
|
+ // Note: Special-case: Booleans have no physical layout, and therefore when
|
|
|
+ // layout is required booleans are represented as unsigned integers.
|
|
|
+ // Therefore, after loading the uint we should convert it boolean.
|
|
|
+ if (elemType->isBooleanType() && layoutRule != LayoutRule::Void) {
|
|
|
+ const auto fromType =
|
|
|
+ size == 1 ? astContext.UnsignedIntTy
|
|
|
+ : astContext.getExtVectorType(astContext.UnsignedIntTy, size);
|
|
|
+ const auto toType =
|
|
|
+ size == 1 ? astContext.BoolTy
|
|
|
+ : astContext.getExtVectorType(astContext.BoolTy, size);
|
|
|
+ valueId = castToBool(valueId, fromType, toType);
|
|
|
+ }
|
|
|
return SpirvEvalInfo(valueId).setRValue();
|
|
|
}
|
|
|
|
|
@@ -4246,8 +4312,6 @@ SPIRVEmitter::doHLSLVectorElementExpr(const HLSLVectorElementExpr *expr) {
|
|
|
const QualType baseType = baseExpr->getType();
|
|
|
assert(hlsl::IsHLSLVecType(baseType));
|
|
|
const auto baseSize = hlsl::GetHLSLVecSize(baseType);
|
|
|
-
|
|
|
- const uint32_t type = typeTranslator.translateType(expr->getType());
|
|
|
const auto accessorSize = static_cast<size_t>(accessor.Count);
|
|
|
|
|
|
// Depending on the number of elements selected, we emit different
|
|
@@ -4273,18 +4337,28 @@ SPIRVEmitter::doHLSLVectorElementExpr(const HLSLVectorElementExpr *expr) {
|
|
|
// we should use composite extraction. We should check the immediate base
|
|
|
// instead of the original base here since we can have something like
|
|
|
// v.xyyz to turn a lvalue v into rvalue.
|
|
|
+ const auto type =
|
|
|
+ typeTranslator.translateType(expr->getType(), baseInfo.getLayoutRule());
|
|
|
if (!baseInfo.isRValue()) { // E.g., v.x;
|
|
|
const uint32_t ptrType =
|
|
|
theBuilder.getPointerType(type, baseInfo.getStorageClass());
|
|
|
const uint32_t index = theBuilder.getConstantInt32(accessor.Swz0);
|
|
|
// We need a lvalue here. Do not try to load.
|
|
|
- return theBuilder.createAccessChain(ptrType, baseInfo, {index});
|
|
|
+ return baseInfo.setResultId(
|
|
|
+ theBuilder.createAccessChain(ptrType, baseInfo, {index}));
|
|
|
} else { // E.g., (v + w).x;
|
|
|
// The original base vector may not be a rvalue. Need to load it if
|
|
|
// it is lvalue since ImplicitCastExpr (LValueToRValue) will be missing
|
|
|
// for that case.
|
|
|
- return baseInfo.setResultId(
|
|
|
- theBuilder.createCompositeExtract(type, baseInfo, {accessor.Swz0}));
|
|
|
+ auto result =
|
|
|
+ theBuilder.createCompositeExtract(type, baseInfo, {accessor.Swz0});
|
|
|
+ // Special-case: Booleans in SPIR-V do not have a physical layout. Uint is
|
|
|
+ // used to represent them when layout is required.
|
|
|
+ if (expr->getType()->isBooleanType() &&
|
|
|
+ baseInfo.getLayoutRule() != LayoutRule::Void)
|
|
|
+ result =
|
|
|
+ castToBool(result, astContext.UnsignedIntTy, astContext.BoolTy);
|
|
|
+ return baseInfo.setResultId(result);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -4292,6 +4366,8 @@ SPIRVEmitter::doHLSLVectorElementExpr(const HLSLVectorElementExpr *expr) {
|
|
|
// Selecting more than one element from a size-1 vector, for example,
|
|
|
// <scalar>.xx. Construct the vector.
|
|
|
auto info = loadIfGLValue(baseExpr);
|
|
|
+ const auto type =
|
|
|
+ typeTranslator.translateType(expr->getType(), info.getLayoutRule());
|
|
|
llvm::SmallVector<uint32_t, 4> components(accessorSize, info);
|
|
|
return info
|
|
|
.setResultId(theBuilder.createCompositeConstruct(type, components))
|
|
@@ -4313,6 +4389,8 @@ SPIRVEmitter::doHLSLVectorElementExpr(const HLSLVectorElementExpr *expr) {
|
|
|
return doExpr(baseExpr);
|
|
|
|
|
|
auto info = loadIfGLValue(baseExpr);
|
|
|
+ const auto type =
|
|
|
+ typeTranslator.translateType(expr->getType(), info.getLayoutRule());
|
|
|
// Use base for both vectors. But we are only selecting values from the
|
|
|
// first one.
|
|
|
return info.setResultId(
|
|
@@ -4604,6 +4682,7 @@ void SPIRVEmitter::storeValue(const SpirvEvalInfo &lhsPtr,
|
|
|
};
|
|
|
|
|
|
QualType matElemType = {};
|
|
|
+ QualType elemType = {};
|
|
|
uint32_t numRows = 0, numCols = 0;
|
|
|
const bool lhsIsMat =
|
|
|
typeTranslator.isMxNMatrix(lhsValType, &matElemType, &numRows, &numCols);
|
|
@@ -4612,7 +4691,27 @@ void SPIRVEmitter::storeValue(const SpirvEvalInfo &lhsPtr,
|
|
|
|
|
|
if (typeTranslator.isScalarType(lhsValType) ||
|
|
|
typeTranslator.isVectorType(lhsValType) || lhsIsFloatMat) {
|
|
|
- theBuilder.createStore(lhsPtr, rhsVal);
|
|
|
+ uint32_t rhsValId = rhsVal;
|
|
|
+
|
|
|
+ // Special-case: According to the SPIR-V Spec: There is no physical size
|
|
|
+ // or bit pattern defined for boolean type. Therefore an unsigned integer
|
|
|
+ // is used to represent booleans when layout is required. In such cases,
|
|
|
+ // we should cast the boolean to uint before creating OpStore.
|
|
|
+ if (isBoolOrVecOfBoolType(lhsValType) &&
|
|
|
+ lhsPtr.getLayoutRule() != LayoutRule::Void) {
|
|
|
+ uint32_t vecSize = 1;
|
|
|
+ const bool isVec =
|
|
|
+ TypeTranslator::isVectorType(lhsValType, nullptr, &vecSize);
|
|
|
+ const auto toType =
|
|
|
+ isVec ? astContext.getExtVectorType(astContext.UnsignedIntTy, vecSize)
|
|
|
+ : astContext.UnsignedIntTy;
|
|
|
+ const auto fromType =
|
|
|
+ isVec ? astContext.getExtVectorType(astContext.BoolTy, vecSize)
|
|
|
+ : astContext.BoolTy;
|
|
|
+ rhsValId = castToInt(rhsValId, fromType, toType, {});
|
|
|
+ }
|
|
|
+
|
|
|
+ theBuilder.createStore(lhsPtr, rhsValId);
|
|
|
} else if (TypeTranslator::isOpaqueType(lhsValType)) {
|
|
|
// Resource types are represented using RecordType in the AST.
|
|
|
// Handle them before the general RecordType.
|