/// constants.
uint32_t prepareConstant(Location loc, Type constType, Attribute valueAttr);
- /// Prepares bool ElementsAttr serialization. This method updates `opcode`
- /// with a proper OpConstant* instruction and pushes literal values for the
- /// constant to `operands`.
- LogicalResult prepareBoolVectorConstant(Location loc,
- DenseIntElementsAttr elementsAttr,
- spirv::Opcode &opcode,
- SmallVectorImpl<uint32_t> &operands);
-
- /// Prepares int ElementsAttr serialization. This method updates `opcode` with
- /// a proper OpConstant* instruction and pushes literal values for the
- /// constant to `operands`.
- LogicalResult prepareIntVectorConstant(Location loc,
- DenseIntElementsAttr elementsAttr,
- spirv::Opcode &opcode,
- SmallVectorImpl<uint32_t> &operands);
-
- /// Prepares float ElementsAttr serialization. This method updates `opcode`
- /// with a proper OpConstant* instruction and pushes literal values for the
- /// constant to `operands`.
- LogicalResult prepareFloatVectorConstant(Location loc,
- DenseFPElementsAttr elementsAttr,
- spirv::Opcode &opcode,
- SmallVectorImpl<uint32_t> &operands);
+ /// Prepares array attribute serialization. This method emits corresponding
+ /// OpConstant* and returns the result <id> associated with it. Returns 0 if
+ /// failed.
+ uint32_t prepareArrayConstant(Location loc, Type constType, ArrayAttr attr);
+
+ /// Prepares bool/int/float DenseElementsAttr serialization. This method
+ /// iterates the DenseElementsAttr to construct the constant array, and
+ /// returns the result <id> associated with it. Returns 0 if failed. Note
+ /// that the size of `index` must match the rank.
+ /// TODO(hanchung): Consider to enhance splat elements cases. For splat cases,
+ /// we don't need to loop over all elements, especially when the splat value
+ /// is zero. We can use OpConstantNull when the value is zero.
+ uint32_t prepareDenseElementsConstant(Location loc, Type constType,
+ DenseElementsAttr valueAttr, int dim,
+ MutableArrayRef<uint64_t> index);
/// Prepares scalar attribute serialization. This method emits corresponding
/// OpConstant* and returns the result <id> associated with it. Returns 0 if
if (auto id = prepareConstantScalar(loc, valueAttr)) {
return id;
}
+
// This is a composite literal. We need to handle each component separately
// and then emit an OpConstantComposite for the whole.
if (failed(processType(loc, constType, typeID))) {
return 0;
}
- auto resultID = getNextID();
-
- spirv::Opcode opcode = spirv::Opcode::OpNop;
- SmallVector<uint32_t, 4> operands;
- operands.push_back(typeID);
- operands.push_back(resultID);
- if (auto vectorAttr = valueAttr.dyn_cast<DenseIntElementsAttr>()) {
- if (vectorAttr.getType().getElementType().isInteger(1)) {
- if (failed(prepareBoolVectorConstant(loc, vectorAttr, opcode, operands)))
- return 0;
- } else if (failed(
- prepareIntVectorConstant(loc, vectorAttr, opcode, operands)))
- return 0;
- } else if (auto vectorAttr = valueAttr.dyn_cast<DenseFPElementsAttr>()) {
- if (failed(prepareFloatVectorConstant(loc, vectorAttr, opcode, operands)))
- return 0;
+ uint32_t resultID = 0;
+ if (auto attr = valueAttr.dyn_cast<DenseElementsAttr>()) {
+ int rank = attr.getType().dyn_cast<ShapedType>().getRank();
+ SmallVector<uint64_t, 4> index(rank);
+ resultID = prepareDenseElementsConstant(loc, constType, attr,
+ /*dim=*/0, index);
} else if (auto arrayAttr = valueAttr.dyn_cast<ArrayAttr>()) {
- opcode = spirv::Opcode::OpConstantComposite;
- operands.reserve(arrayAttr.size() + 2);
+ resultID = prepareArrayConstant(loc, constType, arrayAttr);
+ }
- auto elementType = constType.cast<spirv::ArrayType>().getElementType();
- for (Attribute elementAttr : arrayAttr)
- if (auto elementID = prepareConstant(loc, elementType, elementAttr)) {
- operands.push_back(elementID);
- } else {
- return 0;
- }
- } else {
+ if (resultID == 0) {
emitError(loc, "cannot serialize attribute: ") << valueAttr;
return 0;
}
- encodeInstructionInto(typesGlobalValues, opcode, operands);
constIDMap[valueAttr] = resultID;
return resultID;
}
-LogicalResult Serializer::prepareBoolVectorConstant(
- Location loc, DenseIntElementsAttr elementsAttr, spirv::Opcode &opcode,
- SmallVectorImpl<uint32_t> &operands) {
- auto type = elementsAttr.getType();
- assert(type.hasRank() && type.getRank() == 1 &&
- "spv.constant should have verified only vector literal uses "
- "ElementsAttr");
- assert(type.getElementType().isInteger(1) && "must be bool ElementsAttr");
- auto count = type.getNumElements();
-
- // Operands for constructing the SPIR-V OpConstant* instruction
- operands.reserve(count + 2);
-
- // For splat cases, we don't need to loop over all elements, especially when
- // the splat value is zero.
- if (elementsAttr.isSplat()) {
- // We can use OpConstantNull if this bool ElementsAttr is splatting false.
- if (!elementsAttr.getSplatValue<bool>()) {
- opcode = spirv::Opcode::OpConstantNull;
- return success();
- }
-
- if (auto id =
- prepareConstantBool(loc, elementsAttr.getSplatValue<BoolAttr>())) {
- opcode = spirv::Opcode::OpConstantComposite;
- operands.append(count, id);
- return success();
- }
-
- return failure();
+uint32_t Serializer::prepareArrayConstant(Location loc, Type constType,
+ ArrayAttr attr) {
+ uint32_t typeID = 0;
+ if (failed(processType(loc, constType, typeID))) {
+ return 0;
}
- // Otherwise, we need to process each element and compose them with
- // OpConstantComposite.
- opcode = spirv::Opcode::OpConstantComposite;
- for (auto boolAttr : elementsAttr.getValues<BoolAttr>()) {
- // We are constructing an BoolAttr for each value here. But given that
- // we only use ElementsAttr for vectors with no more than 4 elements, it
- // should be fine here.
- if (auto elementID = prepareConstantBool(loc, boolAttr)) {
+ uint32_t resultID = getNextID();
+ SmallVector<uint32_t, 4> operands = {typeID, resultID};
+ operands.reserve(attr.size() + 2);
+ auto elementType = constType.cast<spirv::ArrayType>().getElementType();
+ for (Attribute elementAttr : attr) {
+ if (auto elementID = prepareConstant(loc, elementType, elementAttr)) {
operands.push_back(elementID);
} else {
- return failure();
- }
- }
- return success();
-}
-
-LogicalResult Serializer::prepareIntVectorConstant(
- Location loc, DenseIntElementsAttr elementsAttr, spirv::Opcode &opcode,
- SmallVectorImpl<uint32_t> &operands) {
- auto type = elementsAttr.getType();
- assert(type.hasRank() && type.getRank() == 1 &&
- "spv.constant should have verified only vector literal uses "
- "ElementsAttr");
- assert(!type.getElementType().isInteger(1) &&
- "must be non-bool ElementsAttr");
- auto count = type.getNumElements();
-
- // Operands for constructing the SPIR-V OpConstant* instruction
- operands.reserve(count + 2);
-
- // For splat cases, we don't need to loop over all elements, especially when
- // the splat value is zero.
- if (elementsAttr.isSplat()) {
- auto splatAttr = elementsAttr.getSplatValue<IntegerAttr>();
-
- // We can use OpConstantNull if this int ElementsAttr is splatting 0.
- if (splatAttr.getValue().isNullValue()) {
- opcode = spirv::Opcode::OpConstantNull;
- return success();
- }
-
- if (auto id = prepareConstantInt(loc, splatAttr)) {
- opcode = spirv::Opcode::OpConstantComposite;
- operands.append(count, id);
- return success();
+ return 0;
}
- return failure();
}
+ spirv::Opcode opcode = spirv::Opcode::OpConstantComposite;
+ encodeInstructionInto(typesGlobalValues, opcode, operands);
- // Otherwise, we need to process each element and compose them with
- // OpConstantComposite.
- opcode = spirv::Opcode::OpConstantComposite;
- for (auto intAttr : elementsAttr.getValues<IntegerAttr>()) {
- // We are constructing an IntegerAttr for each value here. But given that
- // we only use ElementsAttr for vectors with no more than 4 elements, it
- // should be fine here.
- // TODO(antiagainst): revisit this if special extensions enabling large
- // vectors are supported.
- if (auto elementID = prepareConstantInt(loc, intAttr)) {
- operands.push_back(elementID);
- } else {
- return failure();
- }
- }
- return success();
+ return resultID;
}
-LogicalResult Serializer::prepareFloatVectorConstant(
- Location loc, DenseFPElementsAttr elementsAttr, spirv::Opcode &opcode,
- SmallVectorImpl<uint32_t> &operands) {
- auto type = elementsAttr.getType();
- assert(type.hasRank() && type.getRank() == 1 &&
- "spv.constant should have verified only vector literal uses "
- "ElementsAttr");
- auto count = type.getNumElements();
-
- operands.reserve(count + 2);
-
- if (elementsAttr.isSplat()) {
- FloatAttr splatAttr = elementsAttr.getSplatValue<FloatAttr>();
- if (splatAttr.getValue().isZero()) {
- opcode = spirv::Opcode::OpConstantNull;
- return success();
+// TODO(hanchung): Turn the below function into iterative function, instead of
+// recursive function.
+uint32_t
+Serializer::prepareDenseElementsConstant(Location loc, Type constType,
+ DenseElementsAttr valueAttr, int dim,
+ MutableArrayRef<uint64_t> index) {
+ auto shapedType = valueAttr.getType().dyn_cast<ShapedType>();
+ assert(dim <= shapedType.getRank());
+ if (shapedType.getRank() == dim) {
+ if (auto attr = valueAttr.dyn_cast<DenseIntElementsAttr>()) {
+ return attr.getType().getElementType().isInteger(1)
+ ? prepareConstantBool(loc, attr.getValue<BoolAttr>(index))
+ : prepareConstantInt(loc, attr.getValue<IntegerAttr>(index));
}
-
- if (auto id = prepareConstantFp(loc, splatAttr)) {
- opcode = spirv::Opcode::OpConstantComposite;
- operands.append(count, id);
- return success();
+ if (auto attr = valueAttr.dyn_cast<DenseFPElementsAttr>()) {
+ return prepareConstantFp(loc, attr.getValue<FloatAttr>(index));
}
+ return 0;
+ }
- return failure();
+ uint32_t typeID = 0;
+ if (failed(processType(loc, constType, typeID))) {
+ return 0;
}
- opcode = spirv::Opcode::OpConstantComposite;
- for (auto fpAttr : elementsAttr.getValues<FloatAttr>()) {
- if (auto elementID = prepareConstantFp(loc, fpAttr)) {
+ uint32_t resultID = getNextID();
+ SmallVector<uint32_t, 4> operands = {typeID, resultID};
+ operands.reserve(shapedType.getDimSize(dim) + 2);
+ auto elementType = constType.cast<spirv::CompositeType>().getElementType(0);
+ for (int i = 0; i < shapedType.getDimSize(dim); ++i) {
+ index[dim] = i;
+ if (auto elementID = prepareDenseElementsConstant(
+ loc, elementType, valueAttr, dim + 1, index)) {
operands.push_back(elementID);
} else {
- return failure();
+ return 0;
}
}
- return success();
+ spirv::Opcode opcode = spirv::Opcode::OpConstantComposite;
+ encodeInstructionInto(typesGlobalValues, opcode, operands);
+
+ return resultID;
}
uint32_t Serializer::prepareConstantScalar(Location loc, Attribute valueAttr,