[mlir][spirv] Add basic support for SPV_EXT_replicated_composites (#147067)
This patch introduces two new ops to the SPIR-V dialect: - `spirv.EXT.ConstantCompositeReplicate` - `spirv.EXT.SpecConstantCompositeReplicate` These ops represent composite constants and specialization constants, respectively, constructed by replicating a single splat constant across all elements. They correspond to `SPV_EXT_replicated_composites` extension instructions: - `OpConstantCompositeReplicatedEXT` - `OpSpecConstantCompositeReplicatedEXT` No transformation to these new ops has been introduced in this patch. This approach is chosen as per the discussions on RFC https://discourse.llvm.org/t/rfc-basic-support-for-spv-ext-replicated-composites-in-mlir-spir-v-compile-time-constant-lowering-only/86987 --------- Signed-off-by: Mohammadreza Ameri Mahabadian <mohammadreza.amerimahabadian@arm.com>
This commit is contained in:
parent
612afab512
commit
94b15a1ece
@ -359,6 +359,7 @@ def SPV_EXT_shader_atomic_float_min_max : I32EnumAttrCase<"SPV_EXT_shader_atomi
|
|||||||
def SPV_EXT_shader_image_int64 : I32EnumAttrCase<"SPV_EXT_shader_image_int64", 1010>;
|
def SPV_EXT_shader_image_int64 : I32EnumAttrCase<"SPV_EXT_shader_image_int64", 1010>;
|
||||||
def SPV_EXT_shader_atomic_float16_add : I32EnumAttrCase<"SPV_EXT_shader_atomic_float16_add", 1011>;
|
def SPV_EXT_shader_atomic_float16_add : I32EnumAttrCase<"SPV_EXT_shader_atomic_float16_add", 1011>;
|
||||||
def SPV_EXT_mesh_shader : I32EnumAttrCase<"SPV_EXT_mesh_shader", 1012>;
|
def SPV_EXT_mesh_shader : I32EnumAttrCase<"SPV_EXT_mesh_shader", 1012>;
|
||||||
|
def SPV_EXT_replicated_composites : I32EnumAttrCase<"SPV_EXT_replicated_composites", 1013>;
|
||||||
|
|
||||||
def SPV_AMD_gpu_shader_half_float_fetch : I32EnumAttrCase<"SPV_AMD_gpu_shader_half_float_fetch", 2000>;
|
def SPV_AMD_gpu_shader_half_float_fetch : I32EnumAttrCase<"SPV_AMD_gpu_shader_half_float_fetch", 2000>;
|
||||||
def SPV_AMD_shader_ballot : I32EnumAttrCase<"SPV_AMD_shader_ballot", 2001>;
|
def SPV_AMD_shader_ballot : I32EnumAttrCase<"SPV_AMD_shader_ballot", 2001>;
|
||||||
@ -446,7 +447,7 @@ def SPIRV_ExtensionAttr :
|
|||||||
SPV_EXT_shader_stencil_export, SPV_EXT_shader_viewport_index_layer,
|
SPV_EXT_shader_stencil_export, SPV_EXT_shader_viewport_index_layer,
|
||||||
SPV_EXT_shader_atomic_float_add, SPV_EXT_shader_atomic_float_min_max,
|
SPV_EXT_shader_atomic_float_add, SPV_EXT_shader_atomic_float_min_max,
|
||||||
SPV_EXT_shader_image_int64, SPV_EXT_shader_atomic_float16_add,
|
SPV_EXT_shader_image_int64, SPV_EXT_shader_atomic_float16_add,
|
||||||
SPV_EXT_mesh_shader,
|
SPV_EXT_mesh_shader, SPV_EXT_replicated_composites,
|
||||||
SPV_ARM_tensors,
|
SPV_ARM_tensors,
|
||||||
SPV_AMD_gpu_shader_half_float_fetch, SPV_AMD_shader_ballot,
|
SPV_AMD_gpu_shader_half_float_fetch, SPV_AMD_shader_ballot,
|
||||||
SPV_AMD_shader_explicit_vertex_parameter, SPV_AMD_shader_fragment_mask,
|
SPV_AMD_shader_explicit_vertex_parameter, SPV_AMD_shader_fragment_mask,
|
||||||
@ -849,6 +850,12 @@ def SPIRV_C_CooperativeMatrixKHR : I32EnumAttrCase<"Coope
|
|||||||
MinVersion<SPIRV_V_1_6>
|
MinVersion<SPIRV_V_1_6>
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
def SPIRV_C_ReplicatedCompositesEXT : I32EnumAttrCase<"ReplicatedCompositesEXT", 6024> {
|
||||||
|
list<Availability> availability = [
|
||||||
|
Extension<[SPV_EXT_replicated_composites]>,
|
||||||
|
MinVersion<SPIRV_V_1_0>
|
||||||
|
];
|
||||||
|
}
|
||||||
def SPIRV_C_BitInstructions : I32EnumAttrCase<"BitInstructions", 6025> {
|
def SPIRV_C_BitInstructions : I32EnumAttrCase<"BitInstructions", 6025> {
|
||||||
list<Availability> availability = [
|
list<Availability> availability = [
|
||||||
Extension<[SPV_KHR_bit_instructions]>
|
Extension<[SPV_KHR_bit_instructions]>
|
||||||
@ -1500,7 +1507,7 @@ def SPIRV_CapabilityAttr :
|
|||||||
SPIRV_C_USMStorageClassesINTEL, SPIRV_C_IOPipesINTEL, SPIRV_C_BlockingPipesINTEL,
|
SPIRV_C_USMStorageClassesINTEL, SPIRV_C_IOPipesINTEL, SPIRV_C_BlockingPipesINTEL,
|
||||||
SPIRV_C_FPGARegINTEL, SPIRV_C_DotProductInputAll,
|
SPIRV_C_FPGARegINTEL, SPIRV_C_DotProductInputAll,
|
||||||
SPIRV_C_DotProductInput4x8BitPacked, SPIRV_C_DotProduct, SPIRV_C_RayCullMaskKHR,
|
SPIRV_C_DotProductInput4x8BitPacked, SPIRV_C_DotProduct, SPIRV_C_RayCullMaskKHR,
|
||||||
SPIRV_C_CooperativeMatrixKHR,
|
SPIRV_C_CooperativeMatrixKHR, SPIRV_C_ReplicatedCompositesEXT,
|
||||||
SPIRV_C_BitInstructions, SPIRV_C_AtomicFloat32AddEXT, SPIRV_C_AtomicFloat64AddEXT,
|
SPIRV_C_BitInstructions, SPIRV_C_AtomicFloat32AddEXT, SPIRV_C_AtomicFloat64AddEXT,
|
||||||
SPIRV_C_LongConstantCompositeINTEL, SPIRV_C_OptNoneINTEL,
|
SPIRV_C_LongConstantCompositeINTEL, SPIRV_C_OptNoneINTEL,
|
||||||
SPIRV_C_AtomicFloat16AddEXT, SPIRV_C_DebugInfoModuleINTEL, SPIRV_C_SplitBarrierINTEL,
|
SPIRV_C_AtomicFloat16AddEXT, SPIRV_C_DebugInfoModuleINTEL, SPIRV_C_SplitBarrierINTEL,
|
||||||
@ -4565,6 +4572,8 @@ def SPIRV_OC_OpCooperativeMatrixLoadKHR : I32EnumAttrCase<"OpCooperativeMa
|
|||||||
def SPIRV_OC_OpCooperativeMatrixStoreKHR : I32EnumAttrCase<"OpCooperativeMatrixStoreKHR", 4458>;
|
def SPIRV_OC_OpCooperativeMatrixStoreKHR : I32EnumAttrCase<"OpCooperativeMatrixStoreKHR", 4458>;
|
||||||
def SPIRV_OC_OpCooperativeMatrixMulAddKHR : I32EnumAttrCase<"OpCooperativeMatrixMulAddKHR", 4459>;
|
def SPIRV_OC_OpCooperativeMatrixMulAddKHR : I32EnumAttrCase<"OpCooperativeMatrixMulAddKHR", 4459>;
|
||||||
def SPIRV_OC_OpCooperativeMatrixLengthKHR : I32EnumAttrCase<"OpCooperativeMatrixLengthKHR", 4460>;
|
def SPIRV_OC_OpCooperativeMatrixLengthKHR : I32EnumAttrCase<"OpCooperativeMatrixLengthKHR", 4460>;
|
||||||
|
def SPIRV_OC_OpConstantCompositeReplicateEXT : I32EnumAttrCase<"OpConstantCompositeReplicateEXT", 4461>;
|
||||||
|
def SPIRV_OC_OpSpecConstantCompositeReplicateEXT : I32EnumAttrCase<"OpSpecConstantCompositeReplicateEXT", 4462>;
|
||||||
def SPIRV_OC_OpEmitMeshTasksEXT : I32EnumAttrCase<"OpEmitMeshTasksEXT", 5294>;
|
def SPIRV_OC_OpEmitMeshTasksEXT : I32EnumAttrCase<"OpEmitMeshTasksEXT", 5294>;
|
||||||
def SPIRV_OC_OpSetMeshOutputsEXT : I32EnumAttrCase<"OpSetMeshOutputsEXT", 5295>;
|
def SPIRV_OC_OpSetMeshOutputsEXT : I32EnumAttrCase<"OpSetMeshOutputsEXT", 5295>;
|
||||||
def SPIRV_OC_OpSubgroupBlockReadINTEL : I32EnumAttrCase<"OpSubgroupBlockReadINTEL", 5575>;
|
def SPIRV_OC_OpSubgroupBlockReadINTEL : I32EnumAttrCase<"OpSubgroupBlockReadINTEL", 5575>;
|
||||||
@ -4674,6 +4683,8 @@ def SPIRV_OpcodeAttr :
|
|||||||
SPIRV_OC_OpSUDotAccSat, SPIRV_OC_OpTypeCooperativeMatrixKHR,
|
SPIRV_OC_OpSUDotAccSat, SPIRV_OC_OpTypeCooperativeMatrixKHR,
|
||||||
SPIRV_OC_OpCooperativeMatrixLoadKHR, SPIRV_OC_OpCooperativeMatrixStoreKHR,
|
SPIRV_OC_OpCooperativeMatrixLoadKHR, SPIRV_OC_OpCooperativeMatrixStoreKHR,
|
||||||
SPIRV_OC_OpCooperativeMatrixMulAddKHR, SPIRV_OC_OpCooperativeMatrixLengthKHR,
|
SPIRV_OC_OpCooperativeMatrixMulAddKHR, SPIRV_OC_OpCooperativeMatrixLengthKHR,
|
||||||
|
SPIRV_OC_OpConstantCompositeReplicateEXT,
|
||||||
|
SPIRV_OC_OpSpecConstantCompositeReplicateEXT,
|
||||||
SPIRV_OC_OpEmitMeshTasksEXT, SPIRV_OC_OpSetMeshOutputsEXT,
|
SPIRV_OC_OpEmitMeshTasksEXT, SPIRV_OC_OpSetMeshOutputsEXT,
|
||||||
SPIRV_OC_OpSubgroupBlockReadINTEL, SPIRV_OC_OpSubgroupBlockWriteINTEL,
|
SPIRV_OC_OpSubgroupBlockReadINTEL, SPIRV_OC_OpSubgroupBlockWriteINTEL,
|
||||||
SPIRV_OC_OpAssumeTrueKHR, SPIRV_OC_OpAtomicFAddEXT,
|
SPIRV_OC_OpAssumeTrueKHR, SPIRV_OC_OpAtomicFAddEXT,
|
||||||
|
@ -135,6 +135,47 @@ def SPIRV_ConstantOp : SPIRV_Op<"Constant",
|
|||||||
let autogenSerialization = 0;
|
let autogenSerialization = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
def SPIRV_EXTConstantCompositeReplicateOp : SPIRV_ExtVendorOp<"ConstantCompositeReplicate", [Pure]> {
|
||||||
|
let summary = [{
|
||||||
|
Declare a new replicated composite constant op.
|
||||||
|
}];
|
||||||
|
|
||||||
|
let description = [{
|
||||||
|
Represents a splat composite constant i.e., all elements of composite constant
|
||||||
|
have the same value.
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
|
||||||
|
```mlir
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [1 : i32] : vector<2xi32>
|
||||||
|
%1 = spirv.EXT.ConstantCompositeReplicate [1 : i32] : !spirv.array<2 x vector<2xi32>>
|
||||||
|
%2 = spirv.EXT.ConstantCompositeReplicate [dense<[1, 2]> : vector<2xi32>] : !spirv.array<2 x vector<2xi32>>
|
||||||
|
```
|
||||||
|
}];
|
||||||
|
|
||||||
|
let availability = [
|
||||||
|
MinVersion<SPIRV_V_1_0>,
|
||||||
|
MaxVersion<SPIRV_V_1_6>,
|
||||||
|
Extension<[SPV_EXT_replicated_composites]>,
|
||||||
|
Capability<[SPIRV_C_ReplicatedCompositesEXT]>
|
||||||
|
];
|
||||||
|
|
||||||
|
let arguments = (ins
|
||||||
|
AnyAttr:$value
|
||||||
|
);
|
||||||
|
|
||||||
|
let results = (outs
|
||||||
|
SPIRV_Composite:$replicated_constant
|
||||||
|
);
|
||||||
|
|
||||||
|
let autogenSerialization = 0;
|
||||||
|
|
||||||
|
let assemblyFormat = "` ` `[` $value `]` `:` type($replicated_constant) attr-dict";
|
||||||
|
}
|
||||||
|
|
||||||
// -----
|
// -----
|
||||||
|
|
||||||
def SPIRV_EntryPointOp : SPIRV_Op<"EntryPoint", [InModuleScope]> {
|
def SPIRV_EntryPointOp : SPIRV_Op<"EntryPoint", [InModuleScope]> {
|
||||||
@ -689,6 +730,43 @@ def SPIRV_SpecConstantCompositeOp : SPIRV_Op<"SpecConstantComposite", [
|
|||||||
|
|
||||||
// -----
|
// -----
|
||||||
|
|
||||||
|
def SPIRV_EXTSpecConstantCompositeReplicateOp : SPIRV_ExtVendorOp<"SpecConstantCompositeReplicate", [InModuleScope, Symbol]> {
|
||||||
|
let summary = "Declare a new replicated composite specialization constant op.";
|
||||||
|
|
||||||
|
let description = [{
|
||||||
|
Represents a splat spec composite constant i.e., all elements of spec composite
|
||||||
|
constant have the same value. The splat value must come from a symbol reference
|
||||||
|
of spec constant instruction.
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
|
||||||
|
```mlir
|
||||||
|
spirv.SpecConstant @sc_i32_1 = 1 : i32
|
||||||
|
spirv.EXT.SpecConstantCompositeReplicate @scc_splat_array_of_i32 (@sc_i32_1) : !spirv.array<3 x i32>
|
||||||
|
spirv.EXT.SpecConstantCompositeReplicate @scc_splat_struct_of_i32 (@sc_i32_1) : !spirv.struct<(i32, i32, i32)>
|
||||||
|
```
|
||||||
|
}];
|
||||||
|
|
||||||
|
let availability = [
|
||||||
|
MinVersion<SPIRV_V_1_0>,
|
||||||
|
MaxVersion<SPIRV_V_1_6>,
|
||||||
|
Extension<[SPV_EXT_replicated_composites]>,
|
||||||
|
Capability<[SPIRV_C_ReplicatedCompositesEXT]>
|
||||||
|
];
|
||||||
|
|
||||||
|
let arguments = (ins
|
||||||
|
TypeAttr:$type,
|
||||||
|
StrAttr:$sym_name,
|
||||||
|
SymbolRefAttr:$constituent
|
||||||
|
);
|
||||||
|
|
||||||
|
let results = (outs);
|
||||||
|
|
||||||
|
let autogenSerialization = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
def SPIRV_SpecConstantOperationOp : SPIRV_Op<"SpecConstantOperation", [
|
def SPIRV_SpecConstantOperationOp : SPIRV_Op<"SpecConstantOperation", [
|
||||||
Pure, InFunctionScope,
|
Pure, InFunctionScope,
|
||||||
SingleBlockImplicitTerminator<"YieldOp">]> {
|
SingleBlockImplicitTerminator<"YieldOp">]> {
|
||||||
|
@ -763,6 +763,44 @@ void mlir::spirv::AddressOfOp::getAsmResultNames(
|
|||||||
setNameFn(getResult(), specialName.str());
|
setNameFn(getResult(), specialName.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// spirv.EXTConstantCompositeReplicate
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
LogicalResult spirv::EXTConstantCompositeReplicateOp::verify() {
|
||||||
|
Type valueType;
|
||||||
|
if (auto typedAttr = dyn_cast<TypedAttr>(getValue())) {
|
||||||
|
valueType = typedAttr.getType();
|
||||||
|
} else if (auto arrayAttr = dyn_cast<ArrayAttr>(getValue())) {
|
||||||
|
auto typedElemAttr = dyn_cast<TypedAttr>(arrayAttr[0]);
|
||||||
|
if (!typedElemAttr)
|
||||||
|
return emitError("value attribute is not typed");
|
||||||
|
valueType =
|
||||||
|
spirv::ArrayType::get(typedElemAttr.getType(), arrayAttr.size());
|
||||||
|
} else {
|
||||||
|
return emitError("unknown value attribute type");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto compositeType = dyn_cast<spirv::CompositeType>(getType());
|
||||||
|
if (!compositeType)
|
||||||
|
return emitError("result type is not a composite type");
|
||||||
|
|
||||||
|
Type compositeElementType = compositeType.getElementType(0);
|
||||||
|
|
||||||
|
SmallVector<Type, 3> possibleTypes = {compositeElementType};
|
||||||
|
while (auto type = dyn_cast<spirv::CompositeType>(compositeElementType)) {
|
||||||
|
compositeElementType = type.getElementType(0);
|
||||||
|
possibleTypes.push_back(compositeElementType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_contained(possibleTypes, valueType)) {
|
||||||
|
return emitError("expected value attribute type ")
|
||||||
|
<< interleaved(possibleTypes, " or ") << ", but got: " << valueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// spirv.ControlBarrierOp
|
// spirv.ControlBarrierOp
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -1864,6 +1902,69 @@ LogicalResult spirv::SpecConstantCompositeOp::verify() {
|
|||||||
return success();
|
return success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// spirv.EXTSpecConstantCompositeReplicateOp
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
ParseResult
|
||||||
|
spirv::EXTSpecConstantCompositeReplicateOp::parse(OpAsmParser &parser,
|
||||||
|
OperationState &result) {
|
||||||
|
StringAttr compositeName;
|
||||||
|
FlatSymbolRefAttr specConstRef;
|
||||||
|
const char *attrName = "spec_const";
|
||||||
|
NamedAttrList attrs;
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
if (parser.parseSymbolName(compositeName, SymbolTable::getSymbolAttrName(),
|
||||||
|
result.attributes) ||
|
||||||
|
parser.parseLParen() ||
|
||||||
|
parser.parseAttribute(specConstRef, Type(), attrName, attrs) ||
|
||||||
|
parser.parseRParen() || parser.parseColonType(type))
|
||||||
|
return failure();
|
||||||
|
|
||||||
|
StringAttr compositeSpecConstituentName =
|
||||||
|
spirv::EXTSpecConstantCompositeReplicateOp::getConstituentAttrName(
|
||||||
|
result.name);
|
||||||
|
result.addAttribute(compositeSpecConstituentName, specConstRef);
|
||||||
|
|
||||||
|
StringAttr typeAttrName =
|
||||||
|
spirv::EXTSpecConstantCompositeReplicateOp::getTypeAttrName(result.name);
|
||||||
|
result.addAttribute(typeAttrName, TypeAttr::get(type));
|
||||||
|
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
|
void spirv::EXTSpecConstantCompositeReplicateOp::print(OpAsmPrinter &printer) {
|
||||||
|
printer << " ";
|
||||||
|
printer.printSymbolName(getSymName());
|
||||||
|
printer << " (" << this->getConstituent() << ") : " << getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
LogicalResult spirv::EXTSpecConstantCompositeReplicateOp::verify() {
|
||||||
|
auto compositeType = dyn_cast<spirv::CompositeType>(getType());
|
||||||
|
if (!compositeType)
|
||||||
|
return emitError("result type must be a composite type, but provided ")
|
||||||
|
<< getType();
|
||||||
|
|
||||||
|
Operation *constituentOp = SymbolTable::lookupNearestSymbolFrom(
|
||||||
|
(*this)->getParentOp(), this->getConstituent());
|
||||||
|
if (!constituentOp)
|
||||||
|
return emitError(
|
||||||
|
"splat spec constant reference defining constituent not found");
|
||||||
|
|
||||||
|
auto constituentSpecConstOp = dyn_cast<spirv::SpecConstantOp>(constituentOp);
|
||||||
|
if (!constituentSpecConstOp)
|
||||||
|
return emitError("constituent is not a spec constant");
|
||||||
|
|
||||||
|
Type constituentType = constituentSpecConstOp.getDefaultValue().getType();
|
||||||
|
Type compositeElementType = compositeType.getElementType(0);
|
||||||
|
if (constituentType != compositeElementType)
|
||||||
|
return emitError("constituent has incorrect type: expected ")
|
||||||
|
<< compositeElementType << ", but provided " << constituentType;
|
||||||
|
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// spirv.SpecConstantOperation
|
// spirv.SpecConstantOperation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -45,6 +45,12 @@ Value spirv::Deserializer::getValue(uint32_t id) {
|
|||||||
return opBuilder.create<spirv::ConstantOp>(unknownLoc, constInfo->second,
|
return opBuilder.create<spirv::ConstantOp>(unknownLoc, constInfo->second,
|
||||||
constInfo->first);
|
constInfo->first);
|
||||||
}
|
}
|
||||||
|
if (std::optional<std::pair<Attribute, Type>> constCompositeReplicateInfo =
|
||||||
|
getConstantCompositeReplicate(id)) {
|
||||||
|
return opBuilder.create<spirv::EXTConstantCompositeReplicateOp>(
|
||||||
|
unknownLoc, constCompositeReplicateInfo->second,
|
||||||
|
constCompositeReplicateInfo->first);
|
||||||
|
}
|
||||||
if (auto varOp = getGlobalVariable(id)) {
|
if (auto varOp = getGlobalVariable(id)) {
|
||||||
auto addressOfOp = opBuilder.create<spirv::AddressOfOp>(
|
auto addressOfOp = opBuilder.create<spirv::AddressOfOp>(
|
||||||
unknownLoc, varOp.getType(), SymbolRefAttr::get(varOp.getOperation()));
|
unknownLoc, varOp.getType(), SymbolRefAttr::get(varOp.getOperation()));
|
||||||
@ -56,10 +62,18 @@ Value spirv::Deserializer::getValue(uint32_t id) {
|
|||||||
SymbolRefAttr::get(constOp.getOperation()));
|
SymbolRefAttr::get(constOp.getOperation()));
|
||||||
return referenceOfOp.getReference();
|
return referenceOfOp.getReference();
|
||||||
}
|
}
|
||||||
if (auto constCompositeOp = getSpecConstantComposite(id)) {
|
if (SpecConstantCompositeOp specConstCompositeOp =
|
||||||
|
getSpecConstantComposite(id)) {
|
||||||
auto referenceOfOp = opBuilder.create<spirv::ReferenceOfOp>(
|
auto referenceOfOp = opBuilder.create<spirv::ReferenceOfOp>(
|
||||||
unknownLoc, constCompositeOp.getType(),
|
unknownLoc, specConstCompositeOp.getType(),
|
||||||
SymbolRefAttr::get(constCompositeOp.getOperation()));
|
SymbolRefAttr::get(specConstCompositeOp.getOperation()));
|
||||||
|
return referenceOfOp.getReference();
|
||||||
|
}
|
||||||
|
if (auto specConstCompositeReplicateOp =
|
||||||
|
getSpecConstantCompositeReplicate(id)) {
|
||||||
|
auto referenceOfOp = opBuilder.create<spirv::ReferenceOfOp>(
|
||||||
|
unknownLoc, specConstCompositeReplicateOp.getType(),
|
||||||
|
SymbolRefAttr::get(specConstCompositeReplicateOp.getOperation()));
|
||||||
return referenceOfOp.getReference();
|
return referenceOfOp.getReference();
|
||||||
}
|
}
|
||||||
if (auto specConstOperationInfo = getSpecConstantOperation(id)) {
|
if (auto specConstOperationInfo = getSpecConstantOperation(id)) {
|
||||||
@ -175,8 +189,12 @@ LogicalResult spirv::Deserializer::processInstruction(
|
|||||||
return processConstant(operands, /*isSpec=*/true);
|
return processConstant(operands, /*isSpec=*/true);
|
||||||
case spirv::Opcode::OpConstantComposite:
|
case spirv::Opcode::OpConstantComposite:
|
||||||
return processConstantComposite(operands);
|
return processConstantComposite(operands);
|
||||||
|
case spirv::Opcode::OpConstantCompositeReplicateEXT:
|
||||||
|
return processConstantCompositeReplicateEXT(operands);
|
||||||
case spirv::Opcode::OpSpecConstantComposite:
|
case spirv::Opcode::OpSpecConstantComposite:
|
||||||
return processSpecConstantComposite(operands);
|
return processSpecConstantComposite(operands);
|
||||||
|
case spirv::Opcode::OpSpecConstantCompositeReplicateEXT:
|
||||||
|
return processSpecConstantCompositeReplicateEXT(operands);
|
||||||
case spirv::Opcode::OpSpecConstantOp:
|
case spirv::Opcode::OpSpecConstantOp:
|
||||||
return processSpecConstantOperation(operands);
|
return processSpecConstantOperation(operands);
|
||||||
case spirv::Opcode::OpConstantTrue:
|
case spirv::Opcode::OpConstantTrue:
|
||||||
|
@ -678,6 +678,14 @@ spirv::Deserializer::getConstant(uint32_t id) {
|
|||||||
return constIt->getSecond();
|
return constIt->getSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::pair<Attribute, Type>>
|
||||||
|
spirv::Deserializer::getConstantCompositeReplicate(uint32_t id) {
|
||||||
|
if (auto it = constantCompositeReplicateMap.find(id);
|
||||||
|
it != constantCompositeReplicateMap.end())
|
||||||
|
return it->second;
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<spirv::SpecConstOperationMaterializationInfo>
|
std::optional<spirv::SpecConstOperationMaterializationInfo>
|
||||||
spirv::Deserializer::getSpecConstantOperation(uint32_t id) {
|
spirv::Deserializer::getSpecConstantOperation(uint32_t id) {
|
||||||
auto constIt = specConstOperationMap.find(id);
|
auto constIt = specConstOperationMap.find(id);
|
||||||
@ -1554,15 +1562,63 @@ spirv::Deserializer::processConstantComposite(ArrayRef<uint32_t> operands) {
|
|||||||
return success();
|
return success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogicalResult spirv::Deserializer::processConstantCompositeReplicateEXT(
|
||||||
|
ArrayRef<uint32_t> operands) {
|
||||||
|
if (operands.size() != 3) {
|
||||||
|
return emitError(
|
||||||
|
unknownLoc,
|
||||||
|
"OpConstantCompositeReplicateEXT expects 3 operands but found ")
|
||||||
|
<< operands.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Type resultType = getType(operands[0]);
|
||||||
|
if (!resultType) {
|
||||||
|
return emitError(unknownLoc, "undefined result type from <id> ")
|
||||||
|
<< operands[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto compositeType = dyn_cast<CompositeType>(resultType);
|
||||||
|
if (!compositeType) {
|
||||||
|
return emitError(unknownLoc,
|
||||||
|
"result type from <id> is not a composite type")
|
||||||
|
<< operands[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t resultID = operands[1];
|
||||||
|
uint32_t constantID = operands[2];
|
||||||
|
|
||||||
|
std::optional<std::pair<Attribute, Type>> constantInfo =
|
||||||
|
getConstant(constantID);
|
||||||
|
if (constantInfo.has_value()) {
|
||||||
|
constantCompositeReplicateMap.try_emplace(
|
||||||
|
resultID, constantInfo.value().first, resultType);
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::pair<Attribute, Type>> replicatedConstantCompositeInfo =
|
||||||
|
getConstantCompositeReplicate(constantID);
|
||||||
|
if (replicatedConstantCompositeInfo.has_value()) {
|
||||||
|
constantCompositeReplicateMap.try_emplace(
|
||||||
|
resultID, replicatedConstantCompositeInfo.value().first, resultType);
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
|
return emitError(unknownLoc, "OpConstantCompositeReplicateEXT operand <id> ")
|
||||||
|
<< constantID
|
||||||
|
<< " must come from a normal constant or a "
|
||||||
|
"OpConstantCompositeReplicateEXT";
|
||||||
|
}
|
||||||
|
|
||||||
LogicalResult
|
LogicalResult
|
||||||
spirv::Deserializer::processSpecConstantComposite(ArrayRef<uint32_t> operands) {
|
spirv::Deserializer::processSpecConstantComposite(ArrayRef<uint32_t> operands) {
|
||||||
if (operands.size() < 2) {
|
if (operands.size() < 2) {
|
||||||
return emitError(unknownLoc,
|
return emitError(
|
||||||
"OpConstantComposite must have type <id> and result <id>");
|
unknownLoc,
|
||||||
|
"OpSpecConstantComposite must have type <id> and result <id>");
|
||||||
}
|
}
|
||||||
if (operands.size() < 3) {
|
if (operands.size() < 3) {
|
||||||
return emitError(unknownLoc,
|
return emitError(unknownLoc,
|
||||||
"OpConstantComposite must have at least 1 parameter");
|
"OpSpecConstantComposite must have at least 1 parameter");
|
||||||
}
|
}
|
||||||
|
|
||||||
Type resultType = getType(operands[0]);
|
Type resultType = getType(operands[0]);
|
||||||
@ -1589,6 +1645,41 @@ spirv::Deserializer::processSpecConstantComposite(ArrayRef<uint32_t> operands) {
|
|||||||
return success();
|
return success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogicalResult spirv::Deserializer::processSpecConstantCompositeReplicateEXT(
|
||||||
|
ArrayRef<uint32_t> operands) {
|
||||||
|
if (operands.size() != 3) {
|
||||||
|
return emitError(unknownLoc, "OpSpecConstantCompositeReplicateEXT expects "
|
||||||
|
"3 operands but found ")
|
||||||
|
<< operands.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Type resultType = getType(operands[0]);
|
||||||
|
if (!resultType) {
|
||||||
|
return emitError(unknownLoc, "undefined result type from <id> ")
|
||||||
|
<< operands[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto compositeType = dyn_cast<CompositeType>(resultType);
|
||||||
|
if (!compositeType) {
|
||||||
|
return emitError(unknownLoc,
|
||||||
|
"result type from <id> is not a composite type")
|
||||||
|
<< operands[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t resultID = operands[1];
|
||||||
|
|
||||||
|
auto symName = opBuilder.getStringAttr(getSpecConstantSymbol(resultID));
|
||||||
|
spirv::SpecConstantOp constituentSpecConstantOp =
|
||||||
|
getSpecConstant(operands[2]);
|
||||||
|
auto op = opBuilder.create<spirv::EXTSpecConstantCompositeReplicateOp>(
|
||||||
|
unknownLoc, TypeAttr::get(resultType), symName,
|
||||||
|
SymbolRefAttr::get(constituentSpecConstantOp));
|
||||||
|
|
||||||
|
specConstCompositeReplicateMap[resultID] = op;
|
||||||
|
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
LogicalResult
|
LogicalResult
|
||||||
spirv::Deserializer::processSpecConstantOperation(ArrayRef<uint32_t> operands) {
|
spirv::Deserializer::processSpecConstantOperation(ArrayRef<uint32_t> operands) {
|
||||||
if (operands.size() < 3)
|
if (operands.size() < 3)
|
||||||
|
@ -190,6 +190,11 @@ private:
|
|||||||
/// Gets the constant's attribute and type associated with the given <id>.
|
/// Gets the constant's attribute and type associated with the given <id>.
|
||||||
std::optional<std::pair<Attribute, Type>> getConstant(uint32_t id);
|
std::optional<std::pair<Attribute, Type>> getConstant(uint32_t id);
|
||||||
|
|
||||||
|
/// Gets the replicated composite constant's attribute and type associated
|
||||||
|
/// with the given <id>.
|
||||||
|
std::optional<std::pair<Attribute, Type>>
|
||||||
|
getConstantCompositeReplicate(uint32_t id);
|
||||||
|
|
||||||
/// Gets the info needed to materialize the spec constant operation op
|
/// Gets the info needed to materialize the spec constant operation op
|
||||||
/// associated with the given <id>.
|
/// associated with the given <id>.
|
||||||
std::optional<SpecConstOperationMaterializationInfo>
|
std::optional<SpecConstOperationMaterializationInfo>
|
||||||
@ -220,6 +225,13 @@ private:
|
|||||||
return specConstCompositeMap.lookup(id);
|
return specConstCompositeMap.lookup(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the replicated composite specialization constant with the given
|
||||||
|
/// result <id>.
|
||||||
|
spirv::EXTSpecConstantCompositeReplicateOp
|
||||||
|
getSpecConstantCompositeReplicate(uint32_t id) {
|
||||||
|
return specConstCompositeReplicateMap.lookup(id);
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a spirv::SpecConstantOp.
|
/// Creates a spirv::SpecConstantOp.
|
||||||
spirv::SpecConstantOp createSpecConstant(Location loc, uint32_t resultID,
|
spirv::SpecConstantOp createSpecConstant(Location loc, uint32_t resultID,
|
||||||
TypedAttr defaultValue);
|
TypedAttr defaultValue);
|
||||||
@ -313,10 +325,20 @@ private:
|
|||||||
/// `operands`.
|
/// `operands`.
|
||||||
LogicalResult processConstantComposite(ArrayRef<uint32_t> operands);
|
LogicalResult processConstantComposite(ArrayRef<uint32_t> operands);
|
||||||
|
|
||||||
|
/// Processes a SPIR-V OpConstantCompositeReplicateEXT instruction with
|
||||||
|
/// the given `operands`.
|
||||||
|
LogicalResult
|
||||||
|
processConstantCompositeReplicateEXT(ArrayRef<uint32_t> operands);
|
||||||
|
|
||||||
/// Processes a SPIR-V OpSpecConstantComposite instruction with the given
|
/// Processes a SPIR-V OpSpecConstantComposite instruction with the given
|
||||||
/// `operands`.
|
/// `operands`.
|
||||||
LogicalResult processSpecConstantComposite(ArrayRef<uint32_t> operands);
|
LogicalResult processSpecConstantComposite(ArrayRef<uint32_t> operands);
|
||||||
|
|
||||||
|
/// Processes a SPIR-V OpSpecConstantCompositeReplicateEXT instruction with
|
||||||
|
/// the given `operands`.
|
||||||
|
LogicalResult
|
||||||
|
processSpecConstantCompositeReplicateEXT(ArrayRef<uint32_t> operands);
|
||||||
|
|
||||||
/// Processes a SPIR-V OpSpecConstantOp instruction with the given
|
/// Processes a SPIR-V OpSpecConstantOp instruction with the given
|
||||||
/// `operands`.
|
/// `operands`.
|
||||||
LogicalResult processSpecConstantOperation(ArrayRef<uint32_t> operands);
|
LogicalResult processSpecConstantOperation(ArrayRef<uint32_t> operands);
|
||||||
@ -549,12 +571,28 @@ private:
|
|||||||
/// (and type) here. Later when it's used, we materialize the constant.
|
/// (and type) here. Later when it's used, we materialize the constant.
|
||||||
DenseMap<uint32_t, std::pair<Attribute, Type>> constantMap;
|
DenseMap<uint32_t, std::pair<Attribute, Type>> constantMap;
|
||||||
|
|
||||||
|
// Result <id> to replicated constant attribute and type mapping.
|
||||||
|
///
|
||||||
|
/// In the SPIR-V binary format, OpConstantCompositeReplicateEXT is placed in
|
||||||
|
/// the module and shared by instructions at module level and in subsequent
|
||||||
|
/// functions. But in the SPIR-V dialect, this is materialized to where
|
||||||
|
/// it's used in the function. So when seeing a
|
||||||
|
/// OpConstantCompositeReplicateEXT in the binary format, we don't immediately
|
||||||
|
/// emit a `spirv.EXT.ConstantCompositeReplicate` op into the module, we keep
|
||||||
|
/// the id of its value and type here. Later when it's used, we materialize
|
||||||
|
/// the `spirv.EXT.ConstantCompositeReplicate`.
|
||||||
|
DenseMap<uint32_t, std::pair<Attribute, Type>> constantCompositeReplicateMap;
|
||||||
|
|
||||||
// Result <id> to spec constant mapping.
|
// Result <id> to spec constant mapping.
|
||||||
DenseMap<uint32_t, spirv::SpecConstantOp> specConstMap;
|
DenseMap<uint32_t, spirv::SpecConstantOp> specConstMap;
|
||||||
|
|
||||||
// Result <id> to composite spec constant mapping.
|
// Result <id> to composite spec constant mapping.
|
||||||
DenseMap<uint32_t, spirv::SpecConstantCompositeOp> specConstCompositeMap;
|
DenseMap<uint32_t, spirv::SpecConstantCompositeOp> specConstCompositeMap;
|
||||||
|
|
||||||
|
// Result <id> to replicated composite spec constant mapping.
|
||||||
|
DenseMap<uint32_t, spirv::EXTSpecConstantCompositeReplicateOp>
|
||||||
|
specConstCompositeReplicateMap;
|
||||||
|
|
||||||
/// Result <id> to info needed to materialize an OpSpecConstantOp
|
/// Result <id> to info needed to materialize an OpSpecConstantOp
|
||||||
/// mapping.
|
/// mapping.
|
||||||
DenseMap<uint32_t, SpecConstOperationMaterializationInfo>
|
DenseMap<uint32_t, SpecConstOperationMaterializationInfo>
|
||||||
|
@ -66,6 +66,16 @@ LogicalResult Serializer::processConstantOp(spirv::ConstantOp op) {
|
|||||||
return failure();
|
return failure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogicalResult Serializer::processConstantCompositeReplicateOp(
|
||||||
|
spirv::EXTConstantCompositeReplicateOp op) {
|
||||||
|
if (uint32_t resultID = prepareConstantCompositeReplicate(
|
||||||
|
op.getLoc(), op.getType(), op.getValue())) {
|
||||||
|
valueIDMap[op.getResult()] = resultID;
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
return failure();
|
||||||
|
}
|
||||||
|
|
||||||
LogicalResult Serializer::processSpecConstantOp(spirv::SpecConstantOp op) {
|
LogicalResult Serializer::processSpecConstantOp(spirv::SpecConstantOp op) {
|
||||||
if (auto resultID = prepareConstantScalar(op.getLoc(), op.getDefaultValue(),
|
if (auto resultID = prepareConstantScalar(op.getLoc(), op.getDefaultValue(),
|
||||||
/*isSpec=*/true)) {
|
/*isSpec=*/true)) {
|
||||||
@ -118,6 +128,38 @@ Serializer::processSpecConstantCompositeOp(spirv::SpecConstantCompositeOp op) {
|
|||||||
return processName(resultID, op.getSymName());
|
return processName(resultID, op.getSymName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogicalResult Serializer::processSpecConstantCompositeReplicateOp(
|
||||||
|
spirv::EXTSpecConstantCompositeReplicateOp op) {
|
||||||
|
uint32_t typeID = 0;
|
||||||
|
if (failed(processType(op.getLoc(), op.getType(), typeID))) {
|
||||||
|
return failure();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto constituent = dyn_cast<FlatSymbolRefAttr>(op.getConstituent());
|
||||||
|
if (!constituent)
|
||||||
|
return op.emitError(
|
||||||
|
"expected flat symbol reference for constituent instead of ")
|
||||||
|
<< op.getConstituent();
|
||||||
|
|
||||||
|
StringRef constituentName = constituent.getValue();
|
||||||
|
uint32_t constituentID = getSpecConstID(constituentName);
|
||||||
|
if (!constituentID) {
|
||||||
|
return op.emitError("unknown result <id> for replicated spec constant ")
|
||||||
|
<< constituentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t resultID = getNextID();
|
||||||
|
uint32_t operands[] = {typeID, resultID, constituentID};
|
||||||
|
|
||||||
|
encodeInstructionInto(typesGlobalValues,
|
||||||
|
spirv::Opcode::OpSpecConstantCompositeReplicateEXT,
|
||||||
|
operands);
|
||||||
|
|
||||||
|
specConstIDMap[op.getSymName()] = resultID;
|
||||||
|
|
||||||
|
return processName(resultID, op.getSymName());
|
||||||
|
}
|
||||||
|
|
||||||
LogicalResult
|
LogicalResult
|
||||||
Serializer::processSpecConstantOperationOp(spirv::SpecConstantOperationOp op) {
|
Serializer::processSpecConstantOperationOp(spirv::SpecConstantOperationOp op) {
|
||||||
uint32_t typeID = 0;
|
uint32_t typeID = 0;
|
||||||
|
@ -1109,6 +1109,55 @@ uint32_t Serializer::prepareConstantFp(Location loc, FloatAttr floatAttr,
|
|||||||
return resultID;
|
return resultID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t Serializer::prepareConstantCompositeReplicate(Location loc,
|
||||||
|
Type resultType,
|
||||||
|
Attribute valueAttr) {
|
||||||
|
std::pair<Attribute, Type> valueTypePair{valueAttr, resultType};
|
||||||
|
if (uint32_t id = getConstantCompositeReplicateID(valueTypePair)) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t typeID = 0;
|
||||||
|
if (failed(processType(loc, resultType, typeID))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type valueType;
|
||||||
|
if (auto typedAttr = dyn_cast<TypedAttr>(valueAttr)) {
|
||||||
|
valueType = typedAttr.getType();
|
||||||
|
} else if (auto arrayAttr = dyn_cast<ArrayAttr>(valueAttr)) {
|
||||||
|
auto typedElemAttr = dyn_cast<TypedAttr>(arrayAttr[0]);
|
||||||
|
if (!typedElemAttr)
|
||||||
|
return 0;
|
||||||
|
valueType =
|
||||||
|
spirv::ArrayType::get(typedElemAttr.getType(), arrayAttr.size());
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto compositeType = dyn_cast<CompositeType>(resultType);
|
||||||
|
if (!compositeType)
|
||||||
|
return 0;
|
||||||
|
Type elementType = compositeType.getElementType(0);
|
||||||
|
|
||||||
|
uint32_t constandID;
|
||||||
|
if (elementType == valueType) {
|
||||||
|
constandID = prepareConstant(loc, elementType, valueAttr);
|
||||||
|
} else {
|
||||||
|
constandID = prepareConstantCompositeReplicate(loc, elementType, valueAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t resultID = getNextID();
|
||||||
|
uint32_t operands[] = {typeID, resultID, constandID};
|
||||||
|
|
||||||
|
encodeInstructionInto(typesGlobalValues,
|
||||||
|
spirv::Opcode::OpConstantCompositeReplicateEXT,
|
||||||
|
operands);
|
||||||
|
|
||||||
|
constCompositeReplicateIDMap[valueTypePair] = resultID;
|
||||||
|
return resultID;
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Control flow
|
// Control flow
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -1328,6 +1377,9 @@ LogicalResult Serializer::processOperation(Operation *opInst) {
|
|||||||
return processBranchConditionalOp(op);
|
return processBranchConditionalOp(op);
|
||||||
})
|
})
|
||||||
.Case([&](spirv::ConstantOp op) { return processConstantOp(op); })
|
.Case([&](spirv::ConstantOp op) { return processConstantOp(op); })
|
||||||
|
.Case([&](spirv::EXTConstantCompositeReplicateOp op) {
|
||||||
|
return processConstantCompositeReplicateOp(op);
|
||||||
|
})
|
||||||
.Case([&](spirv::FuncOp op) { return processFuncOp(op); })
|
.Case([&](spirv::FuncOp op) { return processFuncOp(op); })
|
||||||
.Case([&](spirv::GlobalVariableOp op) {
|
.Case([&](spirv::GlobalVariableOp op) {
|
||||||
return processGlobalVariableOp(op);
|
return processGlobalVariableOp(op);
|
||||||
@ -1339,6 +1391,9 @@ LogicalResult Serializer::processOperation(Operation *opInst) {
|
|||||||
.Case([&](spirv::SpecConstantCompositeOp op) {
|
.Case([&](spirv::SpecConstantCompositeOp op) {
|
||||||
return processSpecConstantCompositeOp(op);
|
return processSpecConstantCompositeOp(op);
|
||||||
})
|
})
|
||||||
|
.Case([&](spirv::EXTSpecConstantCompositeReplicateOp op) {
|
||||||
|
return processSpecConstantCompositeReplicateOp(op);
|
||||||
|
})
|
||||||
.Case([&](spirv::SpecConstantOperationOp op) {
|
.Case([&](spirv::SpecConstantOperationOp op) {
|
||||||
return processSpecConstantOperationOp(op);
|
return processSpecConstantOperationOp(op);
|
||||||
})
|
})
|
||||||
|
@ -108,11 +108,17 @@ private:
|
|||||||
|
|
||||||
LogicalResult processConstantOp(spirv::ConstantOp op);
|
LogicalResult processConstantOp(spirv::ConstantOp op);
|
||||||
|
|
||||||
|
LogicalResult processConstantCompositeReplicateOp(
|
||||||
|
spirv::EXTConstantCompositeReplicateOp op);
|
||||||
|
|
||||||
LogicalResult processSpecConstantOp(spirv::SpecConstantOp op);
|
LogicalResult processSpecConstantOp(spirv::SpecConstantOp op);
|
||||||
|
|
||||||
LogicalResult
|
LogicalResult
|
||||||
processSpecConstantCompositeOp(spirv::SpecConstantCompositeOp op);
|
processSpecConstantCompositeOp(spirv::SpecConstantCompositeOp op);
|
||||||
|
|
||||||
|
LogicalResult processSpecConstantCompositeReplicateOp(
|
||||||
|
spirv::EXTSpecConstantCompositeReplicateOp op);
|
||||||
|
|
||||||
LogicalResult
|
LogicalResult
|
||||||
processSpecConstantOperationOp(spirv::SpecConstantOperationOp op);
|
processSpecConstantOperationOp(spirv::SpecConstantOperationOp op);
|
||||||
|
|
||||||
@ -191,6 +197,11 @@ private:
|
|||||||
return constIDMap.lookup(value);
|
return constIDMap.lookup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t getConstantCompositeReplicateID(
|
||||||
|
std::pair<Attribute, Type> valueTypePair) const {
|
||||||
|
return constCompositeReplicateIDMap.lookup(valueTypePair);
|
||||||
|
}
|
||||||
|
|
||||||
/// Main dispatch method for processing a constant with the given `constType`
|
/// Main dispatch method for processing a constant with the given `constType`
|
||||||
/// and `valueAttr`. `constType` is needed here because we can interpret the
|
/// and `valueAttr`. `constType` is needed here because we can interpret the
|
||||||
/// `valueAttr` as a different type than the type of `valueAttr` itself; for
|
/// `valueAttr` as a different type than the type of `valueAttr` itself; for
|
||||||
@ -230,6 +241,12 @@ private:
|
|||||||
uint32_t prepareConstantFp(Location loc, FloatAttr floatAttr,
|
uint32_t prepareConstantFp(Location loc, FloatAttr floatAttr,
|
||||||
bool isSpec = false);
|
bool isSpec = false);
|
||||||
|
|
||||||
|
/// Prepares `spirv.EXTConstantCompositeReplicateOp` serialization. This
|
||||||
|
/// method emits OpConstantCompositeReplicateEXT and returns the result <id>
|
||||||
|
/// associated with it.
|
||||||
|
uint32_t prepareConstantCompositeReplicate(Location loc, Type resultType,
|
||||||
|
Attribute valueAttr);
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
// Control flow
|
// Control flow
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
@ -389,6 +406,9 @@ private:
|
|||||||
/// Map from constant values to their <id>s.
|
/// Map from constant values to their <id>s.
|
||||||
DenseMap<Attribute, uint32_t> constIDMap;
|
DenseMap<Attribute, uint32_t> constIDMap;
|
||||||
|
|
||||||
|
/// Map from a replicated composite constant's value and type to their <id>s.
|
||||||
|
DenseMap<std::pair<Attribute, Type>, uint32_t> constCompositeReplicateIDMap;
|
||||||
|
|
||||||
/// Map from specialization constant names to their <id>s.
|
/// Map from specialization constant names to their <id>s.
|
||||||
llvm::StringMap<uint32_t> specConstIDMap;
|
llvm::StringMap<uint32_t> specConstIDMap;
|
||||||
|
|
||||||
|
@ -292,3 +292,17 @@ func.func @set_mesh_outputs(%0 : i32, %1 : i32) -> () {
|
|||||||
spirv.EXT.SetMeshOutputs %0, %1 : i32, i32
|
spirv.EXT.SetMeshOutputs %0, %1 : i32, i32
|
||||||
spirv.Return
|
spirv.Return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Replicated Composite Constant op
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// CHECK-LABEL: constant_composite_replicate
|
||||||
|
func.func @constant_composite_replicate() -> () {
|
||||||
|
// CHECK: min version: v1.0
|
||||||
|
// CHECK: max version: v1.6
|
||||||
|
// CHECK: extensions: [ [SPV_EXT_replicated_composites] ]
|
||||||
|
// CHECK: capabilities: [ [ReplicatedCompositesEXT] ]
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [1 : i32] : vector<2xi32>
|
||||||
|
spirv.Return
|
||||||
|
}
|
||||||
|
@ -163,6 +163,51 @@ func.func @coop_matrix_const_wrong_type() -> () {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// spirv.EXT.ConstantCompositeReplicate
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
func.func @ccr_result_not_composite() -> () {
|
||||||
|
// expected-error @+1 {{op result #0 must be vector of bool or 8/16/32/64-bit integer or 16/32/64-bit float or BFloat16 values of length 2/3/4/8/16 or any SPIR-V array type or any SPIR-V runtime array type or any SPIR-V struct type or any SPIR-V cooperative matrix type or any SPIR-V matrix type or any SPIR-V tensorArm type, but got 'i32'}}
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [1 : i32] : i32
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
func.func @ccr_wrong_splat_type() -> () {
|
||||||
|
// expected-error @+1 {{expected value attribute type 'f32', but got: 'i32'}}
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [1 : i32] : vector<2xf32>
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
func.func @ccr_wrong_splat_type() -> () {
|
||||||
|
// expected-error @+1 {{expected value attribute type '!spirv.array<3 x i32>' or 'i32', but got: 'vector<2xi32>'}}
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [dense<[1, 2]> : vector<2xi32>] : !spirv.array<2 x !spirv.array<3 x i32>>
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
func.func @ccr_wrong_splat_type() -> () {
|
||||||
|
// expected-error @+1 {{expected value attribute type 'f32', but got: 'i32'}}
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [1 : i32] : !spirv.arm.tensor<2x3xf32>
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
func.func @ccr_wrong_splat_type() -> () {
|
||||||
|
// expected-error @+1 {{expected value attribute type 'vector<3xi32>' or 'i32', but got: 'vector<2xi32>'}}
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [dense<[1, 2]> : vector<2xi32>] : !spirv.array<2 x vector<3xi32>>
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----
|
// -----
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -854,6 +899,48 @@ spirv.module Logical GLSL450 {
|
|||||||
spirv.SpecConstantComposite @scc (@sc1) : !spirv.coopmatrix<8x16xf32, Device, MatrixA>
|
spirv.SpecConstantComposite @scc (@sc1) : !spirv.coopmatrix<8x16xf32, Device, MatrixA>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// spirv.EXT.SpecConstantCompositeReplicate
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
spirv.module Logical GLSL450 {
|
||||||
|
// expected-error @+1 {{result type must be a composite type, but provided 'i32'}}
|
||||||
|
spirv.EXT.SpecConstantCompositeReplicate @sccr (@sc_i32_1) : i32
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
spirv.module Logical GLSL450 {
|
||||||
|
// expected-error @+1 {{splat spec constant reference defining constituent not found}}
|
||||||
|
spirv.EXT.SpecConstantCompositeReplicate @sccr (@sc_f32_1) : !spirv.array<3 x i32>
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
spirv.module Logical GLSL450 {
|
||||||
|
spirv.SpecConstant @sc_f32_1 = 1.0 : f32
|
||||||
|
// expected-error @+1 {{constituent has incorrect type: expected 'i32', but provided 'f32'}}
|
||||||
|
spirv.EXT.SpecConstantCompositeReplicate @sccr (@sc_f32_1) : !spirv.array<3 x i32>
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
spirv.module Logical GLSL450 {
|
||||||
|
spirv.SpecConstant @sc_f32_1 = 1.0 : f32
|
||||||
|
// expected-error @+1 {{constituent has incorrect type: expected 'i32', but provided 'f32'}}
|
||||||
|
spirv.EXT.SpecConstantCompositeReplicate @sccr (@sc_f32_1) : !spirv.struct<(i32, i32, i32)>
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
spirv.module Logical GLSL450 {
|
||||||
|
spirv.SpecConstant @sc_f32_1 = 1.0 : f32
|
||||||
|
// expected-error @+1 {{constituent has incorrect type: expected 'i32', but provided 'f32'}}
|
||||||
|
spirv.EXT.SpecConstantCompositeReplicate @sccr (@sc_f32_1) : !spirv.arm.tensor<2x3xi32>
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// spirv.SpecConstantOperation
|
// spirv.SpecConstantOperation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// RUN: mlir-translate --no-implicit-module --test-spirv-roundtrip %s | FileCheck %s
|
// RUN: mlir-translate --no-implicit-module --split-input-file --test-spirv-roundtrip %s | FileCheck %s
|
||||||
|
|
||||||
spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader], []> {
|
spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader], []> {
|
||||||
// CHECK-LABEL: @bool_const
|
// CHECK-LABEL: @bool_const
|
||||||
@ -306,3 +306,106 @@ spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader], []> {
|
|||||||
spirv.ReturnValue %coop : !spirv.coopmatrix<16x16xi8, Subgroup, MatrixAcc>
|
spirv.ReturnValue %coop : !spirv.coopmatrix<16x16xi8, Subgroup, MatrixAcc>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, ReplicatedCompositesEXT], [SPV_EXT_replicated_composites]> {
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_vector_i32
|
||||||
|
spirv.func @splat_vector_i32() -> (vector<3xi32>) "None" {
|
||||||
|
// CHECK: spirv.EXT.ConstantCompositeReplicate [1 : i32] : vector<3xi32>
|
||||||
|
%1 = spirv.EXT.ConstantCompositeReplicate [1 : i32] : vector<3xi32>
|
||||||
|
spirv.ReturnValue %1 : vector<3xi32>
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_array_of_i32
|
||||||
|
spirv.func @splat_array_of_i32() -> (!spirv.array<3 x i32>) "None" {
|
||||||
|
// CHECK: spirv.EXT.ConstantCompositeReplicate [1 : i32] : !spirv.array<3 x i32>
|
||||||
|
%1 = spirv.EXT.ConstantCompositeReplicate [1 : i32] : !spirv.array<3 x i32>
|
||||||
|
spirv.ReturnValue %1 : !spirv.array<3 x i32>
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_array_of_vectors_of_i32
|
||||||
|
spirv.func @splat_array_of_vectors_of_i32() -> (!spirv.array<3 x vector<2xi32>>) "None" {
|
||||||
|
// CHECK: spirv.EXT.ConstantCompositeReplicate [dense<[1, 2]> : vector<2xi32>] : !spirv.array<3 x vector<2xi32>>
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [dense<[1, 2]> : vector<2xi32>] : !spirv.array<3 x vector<2xi32>>
|
||||||
|
spirv.ReturnValue %0 : !spirv.array<3 x vector<2xi32>>
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_array_of_splat_array_of_i32
|
||||||
|
spirv.func @splat_array_of_splat_array_of_i32() -> (!spirv.array<2 x !spirv.array<3 x i32>>) "None" {
|
||||||
|
// CHECK: %0 = spirv.EXT.ConstantCompositeReplicate [3 : i32] : !spirv.array<2 x !spirv.array<3 x i32>>
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [3 : i32] : !spirv.array<2 x !spirv.array<3 x i32>>
|
||||||
|
spirv.ReturnValue %0 : !spirv.array<2 x !spirv.array<3 x i32>>
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_array_of_non_splat_array_of_i32
|
||||||
|
spirv.func @splat_array_of_non_splat_array_of_i32() -> (!spirv.array<2 x !spirv.array<3 x i32>>) "None" {
|
||||||
|
// CHECK: %0 = spirv.EXT.ConstantCompositeReplicate {{\[}}[1 : i32, 2 : i32, 3 : i32]] : !spirv.array<2 x !spirv.array<3 x i32>>
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [[1 : i32, 2 : i32, 3 : i32]] : !spirv.array<2 x !spirv.array<3 x i32>>
|
||||||
|
spirv.ReturnValue %0 : !spirv.array<2 x !spirv.array<3 x i32>>
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_array_of_splat_vectors_of_i32
|
||||||
|
spirv.func @splat_array_of_splat_vectors_of_i32() -> (!spirv.array<2 x vector<2xi32>>) "None" {
|
||||||
|
// CHECK: spirv.EXT.ConstantCompositeReplicate [2 : i32] : !spirv.array<2 x vector<2xi32>>
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [2 : i32] : !spirv.array<2 x vector<2xi32>>
|
||||||
|
spirv.ReturnValue %0 : !spirv.array<2 x vector<2xi32>>
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_arm_tensor_of_i32
|
||||||
|
spirv.func @splat_arm_tensor_of_i32() -> (!spirv.arm.tensor<2x3xi32>) "None" {
|
||||||
|
// CHECK: spirv.EXT.ConstantCompositeReplicate [2 : i32] : !spirv.arm.tensor<2x3xi32>
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [2 : i32] : !spirv.arm.tensor<2x3xi32>
|
||||||
|
spirv.ReturnValue %0 : !spirv.arm.tensor<2x3xi32>
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_vector_f32
|
||||||
|
spirv.func @splat_vector_f32() -> (vector<3xf32>) "None" {
|
||||||
|
// CHECK: spirv.EXT.ConstantCompositeReplicate [1.000000e+00 : f32] : vector<3xf32>
|
||||||
|
%1 = spirv.EXT.ConstantCompositeReplicate [1.0 : f32] : vector<3xf32>
|
||||||
|
spirv.ReturnValue %1 : vector<3xf32>
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_array_of_f32
|
||||||
|
spirv.func @splat_array_of_f32() -> (!spirv.array<3 x f32>) "None" {
|
||||||
|
// CHECK: spirv.EXT.ConstantCompositeReplicate [1.000000e+00 : f32] : !spirv.array<3 x f32>
|
||||||
|
%1 = spirv.EXT.ConstantCompositeReplicate [1.0 : f32] : !spirv.array<3 x f32>
|
||||||
|
spirv.ReturnValue %1 : !spirv.array<3 x f32>
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_array_of_splat_array_of_f32
|
||||||
|
spirv.func @splat_array_of_splat_array_of_f32() -> (!spirv.array<2 x !spirv.array<3 x f32>>) "None" {
|
||||||
|
// CHECK: %0 = spirv.EXT.ConstantCompositeReplicate [3.000000e+00 : f32] : !spirv.array<2 x !spirv.array<3 x f32>>
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [3.0 : f32] : !spirv.array<2 x !spirv.array<3 x f32>>
|
||||||
|
spirv.ReturnValue %0 : !spirv.array<2 x !spirv.array<3 x f32>>
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_array_of_non_splat_array_of_f32
|
||||||
|
spirv.func @splat_array_of_non_splat_array_of_f32() -> (!spirv.array<2 x !spirv.array<3 x f32>>) "None" {
|
||||||
|
// CHECK: %0 = spirv.EXT.ConstantCompositeReplicate {{\[}}[1.000000e+00 : f32, 2.000000e+00 : f32, 3.000000e+00 : f32]] : !spirv.array<2 x !spirv.array<3 x f32>>
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [[1.0 : f32, 2.0 : f32, 3.0 : f32]] : !spirv.array<2 x !spirv.array<3 x f32>>
|
||||||
|
spirv.ReturnValue %0 : !spirv.array<2 x !spirv.array<3 x f32>>
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_array_of_vectors_of_f32
|
||||||
|
spirv.func @splat_array_of_vectors_of_f32() -> (!spirv.array<3 x vector<2xf32>>) "None" {
|
||||||
|
// CHECK: spirv.EXT.ConstantCompositeReplicate [dense<[1.000000e+00, 2.000000e+00]> : vector<2xf32>] : !spirv.array<3 x vector<2xf32>>
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [dense<[1.0, 2.0]> : vector<2xf32>] : !spirv.array<3 x vector<2xf32>>
|
||||||
|
spirv.ReturnValue %0 : !spirv.array<3 x vector<2xf32>>
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_array_of_splat_vectors_of_f32
|
||||||
|
spirv.func @splat_array_of_splat_vectors_of_f32() -> (!spirv.array<2 x vector<2xf32>>) "None" {
|
||||||
|
// CHECK: spirv.EXT.ConstantCompositeReplicate [2.000000e+00 : f32] : !spirv.array<2 x vector<2xf32>>
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [2.0 : f32] : !spirv.array<2 x vector<2xf32>>
|
||||||
|
spirv.ReturnValue %0 : !spirv.array<2 x vector<2xf32>>
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @splat_arm_tensor_of_f32
|
||||||
|
spirv.func @splat_arm_tensor_of_f32() -> (!spirv.arm.tensor<2x3xf32>) "None" {
|
||||||
|
// CHECK: spirv.EXT.ConstantCompositeReplicate [2.000000e+00 : f32] : !spirv.arm.tensor<2x3xf32>
|
||||||
|
%0 = spirv.EXT.ConstantCompositeReplicate [2.0 : f32] : !spirv.arm.tensor<2x3xf32>
|
||||||
|
spirv.ReturnValue %0 : !spirv.arm.tensor<2x3xf32>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -88,6 +88,33 @@ spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader], []> {
|
|||||||
|
|
||||||
// -----
|
// -----
|
||||||
|
|
||||||
|
spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, ReplicatedCompositesEXT], [SPV_EXT_replicated_composites]> {
|
||||||
|
|
||||||
|
spirv.SpecConstant @sc_i32_1 = 1 : i32
|
||||||
|
|
||||||
|
// CHECK: spirv.EXT.SpecConstantCompositeReplicate @scc_splat_array_of_i32 (@sc_i32_1) : !spirv.array<3 x i32>
|
||||||
|
spirv.EXT.SpecConstantCompositeReplicate @scc_splat_array_of_i32 (@sc_i32_1) : !spirv.array<3 x i32>
|
||||||
|
|
||||||
|
// CHECK: spirv.EXT.SpecConstantCompositeReplicate @scc_splat_struct_of_i32 (@sc_i32_1) : !spirv.struct<(i32, i32, i32)>
|
||||||
|
spirv.EXT.SpecConstantCompositeReplicate @scc_splat_struct_of_i32 (@sc_i32_1) : !spirv.struct<(i32, i32, i32)>
|
||||||
|
|
||||||
|
// CHECK: spirv.EXT.SpecConstantCompositeReplicate @scc_splat_vector_of_i32 (@sc_i32_1) : vector<3xi32>
|
||||||
|
spirv.EXT.SpecConstantCompositeReplicate @scc_splat_vector_of_i32 (@sc_i32_1) : vector<3 x i32>
|
||||||
|
|
||||||
|
spirv.SpecConstant @sc_f32_1 = 1.0 : f32
|
||||||
|
|
||||||
|
// CHECK: spirv.EXT.SpecConstantCompositeReplicate @scc_splat_array_of_f32 (@sc_f32_1) : !spirv.array<3 x f32>
|
||||||
|
spirv.EXT.SpecConstantCompositeReplicate @scc_splat_array_of_f32 (@sc_f32_1) : !spirv.array<3 x f32>
|
||||||
|
|
||||||
|
// CHECK: spirv.EXT.SpecConstantCompositeReplicate @scc_splat_struct_of_f32 (@sc_f32_1) : !spirv.struct<(f32, f32, f32)>
|
||||||
|
spirv.EXT.SpecConstantCompositeReplicate @scc_splat_struct_of_f32 (@sc_f32_1) : !spirv.struct<(f32, f32, f32)>
|
||||||
|
|
||||||
|
// CHECK: spirv.EXT.SpecConstantCompositeReplicate @scc_splat_vector_of_f32 (@sc_f32_1) : vector<3xf32>
|
||||||
|
spirv.EXT.SpecConstantCompositeReplicate @scc_splat_vector_of_f32 (@sc_f32_1) : vector<3 x f32>
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader], []> {
|
spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader], []> {
|
||||||
|
|
||||||
spirv.SpecConstant @sc_i32_1 = 1 : i32
|
spirv.SpecConstant @sc_i32_1 = 1 : i32
|
||||||
|
Loading…
x
Reference in New Issue
Block a user