[llvm-branch-commits] [mlir] 6c69d3d - [MLIR][SPIRV] Add initial support for OpSpecConstantOp.
Lei Zhang via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Dec 8 06:13:53 PST 2020
Author: ergawy
Date: 2020-12-08T09:07:52-05:00
New Revision: 6c69d3d68e9a4438b47422e49c0f2d69e2b8e1b7
URL: https://github.com/llvm/llvm-project/commit/6c69d3d68e9a4438b47422e49c0f2d69e2b8e1b7
DIFF: https://github.com/llvm/llvm-project/commit/6c69d3d68e9a4438b47422e49c0f2d69e2b8e1b7.diff
LOG: [MLIR][SPIRV] Add initial support for OpSpecConstantOp.
This commit adds initial support for SPIR-V OpSpecConstantOp
instruction. The following is introdcued:
- A new `spv.specConstantOperation` operation consisting of a single
region and of 2 operations within that regions (more details in the
docs of the op itself).
- A new `spv.yield` instruction that acts a terminator for
`spv.specConstantOperation`.
For now, the generic form of the new op is supported (i.e. no custom
parsing or printing). This will be done in a follow up patch.
Reviewed By: antiagainst
Differential Revision: https://reviews.llvm.org/D92232
Added:
Modified:
mlir/include/mlir/Dialect/SPIRV/SPIRVStructureOps.td
mlir/lib/Dialect/SPIRV/SPIRVOps.cpp
mlir/test/Dialect/SPIRV/structure-ops.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/SPIRV/SPIRVStructureOps.td b/mlir/include/mlir/Dialect/SPIRV/SPIRVStructureOps.td
index 0b1f6d294ac0..b8e76c3662ec 100644
--- a/mlir/include/mlir/Dialect/SPIRV/SPIRVStructureOps.td
+++ b/mlir/include/mlir/Dialect/SPIRV/SPIRVStructureOps.td
@@ -607,6 +607,130 @@ def SPV_SpecConstantCompositeOp : SPV_Op<"specConstantComposite", [InModuleScope
let autogenSerialization = 0;
}
+
+def SPV_YieldOp : SPV_Op<"mlir.yield", [NoSideEffect, Terminator]> {
+ let summary = "Yields the result computed in `spv.SpecConstantOperation`'s"
+ "region back to the parent op.";
+
+ let description = [{
+ This op is a special terminator whose only purpose is to terminate
+ an `spv.SpecConstantOperation`'s enclosed region. It accepts a
+ single operand produced by the preceeding (and only other) instruction
+ in its parent block (see SPV_SpecConstantOperation for further
+ details). This op has no corresponding SPIR-V instruction.
+
+ ```
+ spv.mlir.yield ::= `spv.mlir.yield` ssa-id : spirv-type
+ ```
+
+ #### Example:
+ ```mlir
+ %0 = ... (some op supported by SPIR-V OpSpecConstantOp)
+ spv.mlir.yield %0
+ ```
+ }];
+
+ let arguments = (ins AnyType:$operand);
+
+ let results = (outs);
+
+ let hasOpcode = 0;
+
+ let autogenSerialization = 0;
+
+ let assemblyFormat = "attr-dict $operand `:` type($operand)";
+}
+
+def SPV_SpecConstantOperationOp : SPV_Op<"SpecConstantOperation", [
+ InFunctionScope, NoSideEffect,
+ IsolatedFromAbove]> {
+ let summary = "Declare a new specialization constant that results from doing an operation.";
+
+ let description = [{
+ This op declares a SPIR-V specialization constant that results from
+ doing an operation on other constants (specialization or otherwise).
+
+ In the `spv` dialect, this op is modelled as follows:
+
+ ```
+ spv-spec-constant-operation-op ::= `"spv.SpecConstantOperation"`
+ `(`ssa-id (`, ` ssa-id)`)`
+ `({`
+ ssa-id = spirv-op
+ `spv.mlir.yield` ssa-id
+ `})` `:` function-type
+ ```
+
+ In particular, an `spv.SpecConstantOperation` contains exactly one
+ region. In turn, that region, contains exactly 2 instructions:
+ - One of SPIR-V's instructions that are allowed within an
+ OpSpecConstantOp.
+ - An `spv.mlir.yield` instruction as the terminator.
+
+ The following SPIR-V instructions are valid:
+ - OpSConvert,
+ - OpUConvert,
+ - OpFConvert,
+ - OpSNegate,
+ - OpNot,
+ - OpIAdd,
+ - OpISub,
+ - OpIMul,
+ - OpUDiv,
+ - OpSDiv,
+ - OpUMod,
+ - OpSRem,
+ - OpSMod
+ - OpShiftRightLogical,
+ - OpShiftRightArithmetic,
+ - OpShiftLeftLogical
+ - OpBitwiseOr,
+ - OpBitwiseXor,
+ - OpBitwiseAnd
+ - OpVectorShuffle,
+ - OpCompositeExtract,
+ - OpCompositeInsert
+ - OpLogicalOr,
+ - OpLogicalAnd,
+ - OpLogicalNot,
+ - OpLogicalEqual,
+ - OpLogicalNotEqual
+ - OpSelect
+ - OpIEqual,
+ - OpINotEqual
+ - OpULessThan,
+ - OpSLessThan
+ - OpUGreaterThan,
+ - OpSGreaterThan
+ - OpULessThanEqual,
+ - OpSLessThanEqual
+ - OpUGreaterThanEqual,
+ - OpSGreaterThanEqual
+
+ TODO Add capability-specific ops when supported.
+
+ #### Example:
+ ```mlir
+ %0 = spv.constant 1: i32
+
+ %1 = "spv.SpecConstantOperation"(%0) ({
+ %ret = spv.IAdd %0, %0 : i32
+ spv.mlir.yield %ret : i32
+ }) : (i32) -> i32
+ ```
+ }];
+
+ let arguments = (ins Variadic<AnyType>:$operands);
+
+ let results = (outs AnyType:$results);
+
+ let regions = (region SizedRegion<1>:$body);
+
+ let hasOpcode = 0;
+
+ let autogenSerialization = 0;
+}
+
// -----
#endif // SPIRV_STRUCTURE_OPS
diff --git a/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp b/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp
index 776fbdf11c80..19e0f98f26e9 100644
--- a/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp
+++ b/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp
@@ -3395,6 +3395,87 @@ static LogicalResult verify(spirv::SpecConstantCompositeOp constOp) {
return success();
}
+//===----------------------------------------------------------------------===//
+// spv.mlir.yield
+//===----------------------------------------------------------------------===//
+
+static LogicalResult verify(spirv::YieldOp yieldOp) {
+ Operation *parentOp = yieldOp.getParentOp();
+
+ if (!parentOp || !isa<spirv::SpecConstantOperationOp>(parentOp))
+ return yieldOp.emitOpError(
+ "expected parent op to be 'spv.SpecConstantOperation'");
+
+ Block &block = parentOp->getRegion(0).getBlocks().front();
+ Operation &enclosedOp = block.getOperations().front();
+
+ if (yieldOp.getOperand().getDefiningOp() != &enclosedOp)
+ return yieldOp.emitOpError(
+ "expected operand to be defined by preceeding op");
+
+ return success();
+}
+
+static ParseResult parseSpecConstantOperationOp(OpAsmParser &parser,
+ OperationState &state) {
+ // TODO: For now, only generic form is supported.
+ return failure();
+}
+
+static void print(spirv::SpecConstantOperationOp op, OpAsmPrinter &printer) {
+ // TODO
+ printer.printGenericOp(op);
+}
+
+static LogicalResult verify(spirv::SpecConstantOperationOp constOp) {
+ Block &block = constOp.getRegion().getBlocks().front();
+
+ if (block.getOperations().size() != 2)
+ return constOp.emitOpError("expected exactly 2 nested ops");
+
+ Operation &yieldOp = block.getOperations().back();
+
+ if (!isa<spirv::YieldOp>(yieldOp))
+ return constOp.emitOpError("expected terminator to be a yield op");
+
+ Operation &enclosedOp = block.getOperations().front();
+
+ // TODO Add a `UsableInSpecConstantOp` trait and mark ops from the list below
+ // with it instead.
+ if (!isa<spirv::SConvertOp, spirv::UConvertOp, spirv::FConvertOp,
+ spirv::SNegateOp, spirv::NotOp, spirv::IAddOp, spirv::ISubOp,
+ spirv::IMulOp, spirv::UDivOp, spirv::SDivOp, spirv::UModOp,
+ spirv::SRemOp, spirv::SModOp, spirv::ShiftRightLogicalOp,
+ spirv::ShiftRightArithmeticOp, spirv::ShiftLeftLogicalOp,
+ spirv::BitwiseOrOp, spirv::BitwiseXorOp, spirv::BitwiseAndOp,
+ spirv::CompositeExtractOp, spirv::CompositeInsertOp,
+ spirv::LogicalOrOp, spirv::LogicalAndOp, spirv::LogicalNotOp,
+ spirv::LogicalEqualOp, spirv::LogicalNotEqualOp, spirv::SelectOp,
+ spirv::IEqualOp, spirv::INotEqualOp, spirv::ULessThanOp,
+ spirv::SLessThanOp, spirv::UGreaterThanOp, spirv::SGreaterThanOp,
+ spirv::ULessThanEqualOp, spirv::SLessThanEqualOp,
+ spirv::UGreaterThanEqualOp, spirv::SGreaterThanEqualOp>(enclosedOp))
+ return constOp.emitOpError("invalid enclosed op");
+
+ if (enclosedOp.getNumOperands() != constOp.getOperands().size())
+ return constOp.emitOpError("invalid number of operands; expected ")
+ << enclosedOp.getNumOperands() << ", actual "
+ << constOp.getOperands().size();
+
+ if (enclosedOp.getNumOperands() != constOp.getRegion().getNumArguments())
+ return constOp.emitOpError("invalid number of region arguments; expected ")
+ << enclosedOp.getNumOperands() << ", actual "
+ << constOp.getRegion().getNumArguments();
+
+ for (auto operand : constOp.getOperands())
+ if (!isa<spirv::ConstantOp, spirv::SpecConstantOp,
+ spirv::SpecConstantCompositeOp, spirv::SpecConstantOperationOp>(
+ operand.getDefiningOp()))
+ return constOp.emitOpError("invalid operand");
+
+ return success();
+}
+
namespace mlir {
namespace spirv {
diff --git a/mlir/test/Dialect/SPIRV/structure-ops.mlir b/mlir/test/Dialect/SPIRV/structure-ops.mlir
index 9d0a476c4763..89a30e23dec9 100644
--- a/mlir/test/Dialect/SPIRV/structure-ops.mlir
+++ b/mlir/test/Dialect/SPIRV/structure-ops.mlir
@@ -757,3 +757,152 @@ spv.module Logical GLSL450 {
// expected-error @+1 {{unsupported composite type}}
spv.specConstantComposite @scc (@sc1) : !spv.coopmatrix<8x16xf32, Device>
}
+//===----------------------------------------------------------------------===//
+// spv.SpecConstantOperation
+//===----------------------------------------------------------------------===//
+
+// -----
+
+spv.module Logical GLSL450 {
+ spv.func @foo() -> i32 "None" {
+ %0 = spv.constant 1: i32
+ %2 = spv.constant 1: i32
+
+ %1 = "spv.SpecConstantOperation"(%0, %0) ({
+ ^bb(%lhs : i32, %rhs : i32):
+ %ret = spv.IAdd %lhs, %rhs : i32
+ spv.mlir.yield %ret : i32
+ }) : (i32, i32) -> i32
+
+ spv.ReturnValue %1 : i32
+ }
+}
+
+// -----
+
+spv.module Logical GLSL450 {
+ spv.func @foo() -> i32 "None" {
+ %0 = spv.constant 1: i32
+ %2 = spv.constant 1: i32
+
+ // expected-error @+1 {{invalid number of operands; expected 2, actual 1}}
+ %1 = "spv.SpecConstantOperation"(%0) ({
+ ^bb(%lhs : i32, %rhs : i32):
+ %ret = spv.IAdd %lhs, %rhs : i32
+ spv.mlir.yield %ret : i32
+ }) : (i32) -> i32
+
+ spv.ReturnValue %1 : i32
+ }
+}
+
+// -----
+
+spv.module Logical GLSL450 {
+ spv.func @foo() -> i32 "None" {
+ %0 = spv.constant 1: i32
+ %2 = spv.constant 1: i32
+
+ // expected-error @+1 {{invalid number of region arguments; expected 2, actual 1}}
+ %1 = "spv.SpecConstantOperation"(%0, %0) ({
+ ^bb(%lhs : i32):
+ %ret = spv.IAdd %lhs, %lhs : i32
+ spv.mlir.yield %ret : i32
+ }) : (i32, i32) -> i32
+
+ spv.ReturnValue %1 : i32
+ }
+}
+
+// -----
+
+spv.module Logical GLSL450 {
+ spv.func @foo() -> i32 "None" {
+ %0 = spv.constant 1: i32
+ // expected-error @+1 {{expected parent op to be 'spv.SpecConstantOperation'}}
+ spv.mlir.yield %0 : i32
+ }
+}
+
+// -----
+
+spv.module Logical GLSL450 {
+ spv.func @foo() -> i32 "None" {
+ %0 = spv.constant 1: i32
+
+ %1 = "spv.SpecConstantOperation"(%0, %0) ({
+ ^bb(%lhs : i32, %rhs : i32):
+ %ret = spv.ISub %lhs, %rhs : i32
+ // expected-error @+1 {{expected operand to be defined by preceeding op}}
+ spv.mlir.yield %lhs : i32
+ }) : (i32, i32) -> i32
+
+ spv.ReturnValue %1 : i32
+ }
+}
+
+// -----
+
+spv.module Logical GLSL450 {
+ spv.func @foo() -> i32 "None" {
+ %0 = spv.constant 1: i32
+
+ // expected-error @+1 {{expected exactly 2 nested ops}}
+ %1 = "spv.SpecConstantOperation"(%0, %0) ({
+ ^bb(%lhs : i32, %rhs : i32):
+ %ret = spv.IAdd %lhs, %rhs : i32
+ %ret2 = spv.IAdd %lhs, %rhs : i32
+ spv.mlir.yield %ret : i32
+ }) : (i32, i32) -> i32
+
+ spv.ReturnValue %1 : i32
+ }
+}
+
+// -----
+
+spv.module Logical GLSL450 {
+ spv.func @foo() -> i32 "None" {
+ %0 = spv.constant 1: i32
+
+ // expected-error @+1 {{expected terminator to be a yield op}}
+ %1 = "spv.SpecConstantOperation"(%0, %0) ({
+ ^bb(%lhs : i32, %rhs : i32):
+ %ret = spv.IAdd %lhs, %rhs : i32
+ spv.ReturnValue %ret : i32
+ }) : (i32, i32) -> i32
+
+ spv.ReturnValue %1 : i32
+ }
+}
+
+// -----
+
+spv.module Logical GLSL450 {
+ spv.func @foo() -> () "None" {
+ %0 = spv.Variable : !spv.ptr<i32, Function>
+
+ // expected-error @+1 {{invalid enclosed op}}
+ %2 = "spv.SpecConstantOperation"(%0) ({
+ ^bb(%arg0 : !spv.ptr<i32, Function>):
+ %ret = spv.Load "Function" %arg0 : i32
+ spv.mlir.yield %ret : i32
+ }) : (!spv.ptr<i32, Function>) -> i32
+ }
+}
+
+// -----
+
+spv.module Logical GLSL450 {
+ spv.func @foo() -> () "None" {
+ %0 = spv.Variable : !spv.ptr<i32, Function>
+ %1 = spv.Load "Function" %0 : i32
+
+ // expected-error @+1 {{invalid operand}}
+ %2 = "spv.SpecConstantOperation"(%1, %1) ({
+ ^bb(%lhs: i32, %rhs: i32):
+ %ret = spv.IAdd %lhs, %lhs : i32
+ spv.mlir.yield %ret : i32
+ }) : (i32, i32) -> i32
+ }
+}
More information about the llvm-branch-commits
mailing list