|
@@ -13,6 +13,9 @@
|
|
|
|
|
|
#include "InitListHandler.h"
|
|
#include "InitListHandler.h"
|
|
|
|
|
|
|
|
+#include <algorithm>
|
|
|
|
+#include <iterator>
|
|
|
|
+
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
|
|
namespace clang {
|
|
namespace clang {
|
|
@@ -28,12 +31,18 @@ uint32_t InitListHandler::process(const InitListExpr *expr) {
|
|
scalars.clear();
|
|
scalars.clear();
|
|
|
|
|
|
flatten(expr);
|
|
flatten(expr);
|
|
|
|
+ // Reverse the whole initializer list so we can manipulate the list at the
|
|
|
|
+ // tail of the vector. This is more efficient than using a deque.
|
|
|
|
+ std::reverse(std::begin(initializers), std::end(initializers));
|
|
|
|
|
|
const uint32_t init = createInitForType(expr->getType());
|
|
const uint32_t init = createInitForType(expr->getType());
|
|
|
|
|
|
- /// We should have consumed all initializers and scalars extracted from them.
|
|
|
|
- assert(initializers.empty());
|
|
|
|
- assert(scalars.empty());
|
|
|
|
|
|
+ if (init) {
|
|
|
|
+ // For successful translation, we should have consumed all initializers and
|
|
|
|
+ // scalars extracted from them.
|
|
|
|
+ assert(initializers.empty());
|
|
|
|
+ assert(scalars.empty());
|
|
|
|
+ }
|
|
|
|
|
|
return init;
|
|
return init;
|
|
}
|
|
}
|
|
@@ -64,22 +73,80 @@ void InitListHandler::decompose(const Expr *expr) {
|
|
const uint32_t vec = theEmitter.loadIfGLValue(expr);
|
|
const uint32_t vec = theEmitter.loadIfGLValue(expr);
|
|
const QualType elemType = hlsl::GetHLSLVecElementType(type);
|
|
const QualType elemType = hlsl::GetHLSLVecElementType(type);
|
|
const auto size = hlsl::GetHLSLVecSize(type);
|
|
const auto size = hlsl::GetHLSLVecSize(type);
|
|
- if (size == 1) {
|
|
|
|
- // Decomposing of size-1 vector just results in the vector itself.
|
|
|
|
- scalars.emplace_back(vec, elemType);
|
|
|
|
|
|
+
|
|
|
|
+ decomposeVector(vec, elemType, size);
|
|
|
|
+ } else if (hlsl::IsHLSLMatType(type)) {
|
|
|
|
+ const uint32_t mat = theEmitter.loadIfGLValue(expr);
|
|
|
|
+ const QualType elemType = hlsl::GetHLSLMatElementType(type);
|
|
|
|
+
|
|
|
|
+ uint32_t rowCount = 0, colCount = 0;
|
|
|
|
+ hlsl::GetHLSLMatRowColCount(type, rowCount, colCount);
|
|
|
|
+
|
|
|
|
+ if (rowCount == 1 || colCount == 1) {
|
|
|
|
+ // This also handles the scalar case
|
|
|
|
+ decomposeVector(mat, elemType, rowCount == 1 ? colCount : rowCount);
|
|
} else {
|
|
} else {
|
|
const uint32_t elemTypeId = typeTranslator.translateType(elemType);
|
|
const uint32_t elemTypeId = typeTranslator.translateType(elemType);
|
|
- for (uint32_t i = 0; i < size; ++i) {
|
|
|
|
- const uint32_t element =
|
|
|
|
- theBuilder.createCompositeExtract(elemTypeId, vec, {i});
|
|
|
|
- scalars.emplace_back(element, elemType);
|
|
|
|
- }
|
|
|
|
|
|
+ for (uint32_t i = 0; i < rowCount; ++i)
|
|
|
|
+ for (uint32_t j = 0; j < colCount; ++j) {
|
|
|
|
+ const uint32_t element =
|
|
|
|
+ theBuilder.createCompositeExtract(elemTypeId, mat, {i, j});
|
|
|
|
+ scalars.emplace_back(element, elemType);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+ } else if (type->isStructureType()) {
|
|
|
|
+ llvm_unreachable("struct initializer should already been handled");
|
|
} else {
|
|
} else {
|
|
emitError("decomposing type %0 in initializer list unimplemented") << type;
|
|
emitError("decomposing type %0 in initializer list unimplemented") << type;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void InitListHandler::decomposeVector(uint32_t vec, QualType elemType,
|
|
|
|
+ uint32_t size) {
|
|
|
|
+ if (size == 1) {
|
|
|
|
+ // Decomposing of size-1 vector just results in the vector itself.
|
|
|
|
+ scalars.emplace_back(vec, elemType);
|
|
|
|
+ } else {
|
|
|
|
+ const uint32_t elemTypeId = typeTranslator.translateType(elemType);
|
|
|
|
+ for (uint32_t i = 0; i < size; ++i) {
|
|
|
|
+ const uint32_t element =
|
|
|
|
+ theBuilder.createCompositeExtract(elemTypeId, vec, {i});
|
|
|
|
+ scalars.emplace_back(element, elemType);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void InitListHandler::tryToSplitStruct() {
|
|
|
|
+ if (initializers.empty())
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ auto *init = const_cast<Expr *>(initializers.back());
|
|
|
|
+ const QualType initType = init->getType();
|
|
|
|
+ if (!initType->isStructureType())
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ // We are certain the current intializer will be replaced by now.
|
|
|
|
+ initializers.pop_back();
|
|
|
|
+
|
|
|
|
+ const auto &context = theEmitter.getASTContext();
|
|
|
|
+ const auto *structDecl = initType->getAsStructureType()->getDecl();
|
|
|
|
+
|
|
|
|
+ // Create MemberExpr for each field of the struct
|
|
|
|
+ llvm::SmallVector<const Expr *, 4> fields;
|
|
|
|
+ for (auto *field : structDecl->fields()) {
|
|
|
|
+ fields.push_back(MemberExpr::Create(
|
|
|
|
+ context, init, /*isarraw*/ false, /*OperatorLoc*/ {},
|
|
|
|
+ /*QualifierLoc*/ {}, /*TemplateKWLoc*/ {}, field,
|
|
|
|
+ DeclAccessPair::make(field, AS_none),
|
|
|
|
+ DeclarationNameInfo(field->getDeclName(), /*NameLoc*/ {}),
|
|
|
|
+ /*TemplateArgumentListInfo*/ nullptr, field->getType(),
|
|
|
|
+ init->getValueKind(), OK_Ordinary));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Push in the reverse order
|
|
|
|
+ initializers.insert(initializers.end(), fields.rbegin(), fields.rend());
|
|
|
|
+}
|
|
|
|
+
|
|
uint32_t InitListHandler::createInitForType(QualType type) {
|
|
uint32_t InitListHandler::createInitForType(QualType type) {
|
|
type = type.getCanonicalType();
|
|
type = type.getCanonicalType();
|
|
|
|
|
|
@@ -98,6 +165,9 @@ uint32_t InitListHandler::createInitForType(QualType type) {
|
|
return createInitForMatrixType(elemType, rowCount, colCount);
|
|
return createInitForMatrixType(elemType, rowCount, colCount);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (type->isStructureType())
|
|
|
|
+ return createInitForStructType(type);
|
|
|
|
+
|
|
emitError("unimplemented initializer for type '%0'") << type;
|
|
emitError("unimplemented initializer for type '%0'") << type;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -111,8 +181,10 @@ uint32_t InitListHandler::createInitForBuiltinType(QualType type) {
|
|
return theEmitter.castToType(init.first, init.second, type);
|
|
return theEmitter.castToType(init.first, init.second, type);
|
|
}
|
|
}
|
|
|
|
|
|
- const Expr *init = initializers.front();
|
|
|
|
- initializers.pop_front();
|
|
|
|
|
|
+ tryToSplitStruct();
|
|
|
|
+
|
|
|
|
+ const Expr *init = initializers.back();
|
|
|
|
+ initializers.pop_back();
|
|
|
|
|
|
if (!init->getType()->isBuiltinType()) {
|
|
if (!init->getType()->isBuiltinType()) {
|
|
decompose(init);
|
|
decompose(init);
|
|
@@ -130,11 +202,14 @@ uint32_t InitListHandler::createInitForVectorType(QualType elemType,
|
|
// directly. For all other cases, we need to construct a new vector as the
|
|
// directly. For all other cases, we need to construct a new vector as the
|
|
// initializer.
|
|
// initializer.
|
|
if (scalars.empty()) {
|
|
if (scalars.empty()) {
|
|
- const Expr *init = initializers.front();
|
|
|
|
|
|
+ // A struct may contain a whole vector.
|
|
|
|
+ tryToSplitStruct();
|
|
|
|
+
|
|
|
|
+ const Expr *init = initializers.back();
|
|
|
|
|
|
if (hlsl::IsHLSLVecType(init->getType()) &&
|
|
if (hlsl::IsHLSLVecType(init->getType()) &&
|
|
hlsl::GetHLSLVecSize(init->getType()) == count) {
|
|
hlsl::GetHLSLVecSize(init->getType()) == count) {
|
|
- initializers.pop_front();
|
|
|
|
|
|
+ initializers.pop_back();
|
|
/// HLSL vector types are parameterized templates and we cannot
|
|
/// HLSL vector types are parameterized templates and we cannot
|
|
/// construct them. So we construct an ExtVectorType here instead.
|
|
/// construct them. So we construct an ExtVectorType here instead.
|
|
/// This is unfortunate since it means we need to handle ExtVectorType
|
|
/// This is unfortunate since it means we need to handle ExtVectorType
|
|
@@ -169,14 +244,17 @@ uint32_t InitListHandler::createInitForMatrixType(QualType elemType,
|
|
// Same as the vector case, first try to see if we already have a matrix at
|
|
// Same as the vector case, first try to see if we already have a matrix at
|
|
// the beginning of the initializer queue.
|
|
// the beginning of the initializer queue.
|
|
if (scalars.empty()) {
|
|
if (scalars.empty()) {
|
|
- const Expr *init = initializers.front();
|
|
|
|
|
|
+ // A struct may contain a whole matrix.
|
|
|
|
+ tryToSplitStruct();
|
|
|
|
+
|
|
|
|
+ const Expr *init = initializers.back();
|
|
|
|
|
|
if (hlsl::IsHLSLMatType(init->getType())) {
|
|
if (hlsl::IsHLSLMatType(init->getType())) {
|
|
uint32_t initRowCount = 0, initColCount = 0;
|
|
uint32_t initRowCount = 0, initColCount = 0;
|
|
hlsl::GetHLSLMatRowColCount(init->getType(), initRowCount, initColCount);
|
|
hlsl::GetHLSLMatRowColCount(init->getType(), initRowCount, initColCount);
|
|
|
|
|
|
if (rowCount == initRowCount && colCount == initColCount) {
|
|
if (rowCount == initRowCount && colCount == initColCount) {
|
|
- initializers.pop_front();
|
|
|
|
|
|
+ initializers.pop_back();
|
|
// TODO: We only support FP matrices now. Do type cast here after
|
|
// TODO: We only support FP matrices now. Do type cast here after
|
|
// adding more matrix types.
|
|
// adding more matrix types.
|
|
return theEmitter.loadIfGLValue(init);
|
|
return theEmitter.loadIfGLValue(init);
|
|
@@ -204,5 +282,32 @@ uint32_t InitListHandler::createInitForMatrixType(QualType elemType,
|
|
return theBuilder.createCompositeConstruct(matType, vectors);
|
|
return theBuilder.createCompositeConstruct(matType, vectors);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+uint32_t InitListHandler::createInitForStructType(QualType type) {
|
|
|
|
+ // Same as the vector case, first try to see if we already have a struct at
|
|
|
|
+ // the beginning of the initializer queue.
|
|
|
|
+ if (scalars.empty()) {
|
|
|
|
+ const Expr *init = initializers.back();
|
|
|
|
+ // We can only avoid decomposing and reconstructing when the type is
|
|
|
|
+ // exactly the same.
|
|
|
|
+ if (type.getCanonicalType() == init->getType().getCanonicalType()) {
|
|
|
|
+ initializers.pop_back();
|
|
|
|
+ return theEmitter.loadIfGLValue(init);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Otherwise, if the next initializer is a struct, it is not of the same
|
|
|
|
+ // type as we expected. Split it.
|
|
|
|
+ tryToSplitStruct();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ llvm::SmallVector<uint32_t, 4> fields;
|
|
|
|
+ const RecordDecl *structDecl = type->getAsStructureType()->getDecl();
|
|
|
|
+ for (const auto *field : structDecl->fields())
|
|
|
|
+ fields.push_back(createInitForType(field->getType()));
|
|
|
|
+
|
|
|
|
+ const uint32_t typeId = typeTranslator.translateType(type);
|
|
|
|
+ // TODO: use OpConstantComposite when all components are constants
|
|
|
|
+ return theBuilder.createCompositeConstruct(typeId, fields);
|
|
|
|
+}
|
|
|
|
+
|
|
} // end namespace spirv
|
|
} // end namespace spirv
|
|
} // end namespace clang
|
|
} // end namespace clang
|