// -----
-def SPV_IAddOp : SPV_ArithmeticBinaryOp<"IAdd", SPV_Integer, [Commutative]> {
+def SPV_IAddOp : SPV_ArithmeticBinaryOp<"IAdd",
+ SPV_Integer,
+ [Commutative, UsableInSpecConstantOp]> {
let summary = "Integer addition of Operand 1 and Operand 2.";
let description = [{
// -----
-def SPV_IMulOp : SPV_ArithmeticBinaryOp<"IMul", SPV_Integer, [Commutative]> {
+def SPV_IMulOp : SPV_ArithmeticBinaryOp<"IMul",
+ SPV_Integer,
+ [Commutative, UsableInSpecConstantOp]> {
let summary = "Integer multiplication of Operand 1 and Operand 2.";
let description = [{
// -----
-def SPV_ISubOp : SPV_ArithmeticBinaryOp<"ISub", SPV_Integer, []> {
+def SPV_ISubOp : SPV_ArithmeticBinaryOp<"ISub",
+ SPV_Integer,
+ [UsableInSpecConstantOp]> {
let summary = "Integer subtraction of Operand 2 from Operand 1.";
let description = [{
// -----
-def SPV_SDivOp : SPV_ArithmeticBinaryOp<"SDiv", SPV_Integer, []> {
+def SPV_SDivOp : SPV_ArithmeticBinaryOp<"SDiv",
+ SPV_Integer,
+ [UsableInSpecConstantOp]> {
let summary = "Signed-integer division of Operand 1 divided by Operand 2.";
let description = [{
// -----
-def SPV_SModOp : SPV_ArithmeticBinaryOp<"SMod", SPV_Integer, []> {
+def SPV_SModOp : SPV_ArithmeticBinaryOp<"SMod",
+ SPV_Integer,
+ [UsableInSpecConstantOp]> {
let summary = [{
Signed remainder operation for the remainder whose sign matches the sign
of Operand 2.
// -----
-def SPV_SNegateOp : SPV_ArithmeticUnaryOp<"SNegate", SPV_Integer, []> {
+def SPV_SNegateOp : SPV_ArithmeticUnaryOp<"SNegate",
+ SPV_Integer,
+ [UsableInSpecConstantOp]> {
let summary = "Signed-integer subtract of Operand from zero.";
let description = [{
// -----
-def SPV_SRemOp : SPV_ArithmeticBinaryOp<"SRem", SPV_Integer, []> {
+def SPV_SRemOp : SPV_ArithmeticBinaryOp<"SRem",
+ SPV_Integer,
+ [UsableInSpecConstantOp]> {
let summary = [{
Signed remainder operation for the remainder whose sign matches the sign
of Operand 1.
// -----
-def SPV_UDivOp : SPV_ArithmeticBinaryOp<"UDiv", SPV_Integer, [UnsignedOp]> {
+def SPV_UDivOp : SPV_ArithmeticBinaryOp<"UDiv",
+ SPV_Integer,
+ [UnsignedOp, UsableInSpecConstantOp]> {
let summary = "Unsigned-integer division of Operand 1 divided by Operand 2.";
let description = [{
// -----
-def SPV_UModOp : SPV_ArithmeticBinaryOp<"UMod", SPV_Integer, [UnsignedOp]> {
+def SPV_UModOp : SPV_ArithmeticBinaryOp<"UMod",
+ SPV_Integer,
+ [UnsignedOp, UsableInSpecConstantOp]> {
let summary = "Unsigned modulo operation of Operand 1 modulo Operand 2.";
let description = [{
def UnsignedOp : NativeOpTrait<"spirv::UnsignedOp">;
+def UsableInSpecConstantOp : NativeOpTrait<"spirv::UsableInSpecConstantOp">;
+
//===----------------------------------------------------------------------===//
// SPIR-V opcode specification
//===----------------------------------------------------------------------===//
// -----
-def SPV_BitwiseAndOp : SPV_BitBinaryOp<"BitwiseAnd", [Commutative]> {
+def SPV_BitwiseAndOp : SPV_BitBinaryOp<"BitwiseAnd",
+ [Commutative, UsableInSpecConstantOp]> {
let summary = [{
Result is 1 if both Operand 1 and Operand 2 are 1. Result is 0 if either
Operand 1 or Operand 2 are 0.
// -----
-def SPV_BitwiseOrOp : SPV_BitBinaryOp<"BitwiseOr", [Commutative]> {
+def SPV_BitwiseOrOp : SPV_BitBinaryOp<"BitwiseOr",
+ [Commutative, UsableInSpecConstantOp]> {
let summary = [{
Result is 1 if either Operand 1 or Operand 2 is 1. Result is 0 if both
Operand 1 and Operand 2 are 0.
// -----
-def SPV_BitwiseXorOp : SPV_BitBinaryOp<"BitwiseXor", [Commutative]> {
+def SPV_BitwiseXorOp : SPV_BitBinaryOp<"BitwiseXor",
+ [Commutative, UsableInSpecConstantOp]> {
let summary = [{
Result is 1 if exactly one of Operand 1 or Operand 2 is 1. Result is 0
if Operand 1 and Operand 2 have the same value.
// -----
-def SPV_ShiftLeftLogicalOp : SPV_ShiftOp<"ShiftLeftLogical", []> {
+def SPV_ShiftLeftLogicalOp : SPV_ShiftOp<"ShiftLeftLogical",
+ [UsableInSpecConstantOp]> {
let summary = [{
Shift the bits in Base left by the number of bits specified in Shift.
The least-significant bits will be zero filled.
// -----
-def SPV_ShiftRightArithmeticOp : SPV_ShiftOp<"ShiftRightArithmetic", []> {
+def SPV_ShiftRightArithmeticOp : SPV_ShiftOp<"ShiftRightArithmetic",
+ [UsableInSpecConstantOp]> {
let summary = [{
Shift the bits in Base right by the number of bits specified in Shift.
The most-significant bits will be filled with the sign bit from Base.
// -----
-def SPV_ShiftRightLogicalOp : SPV_ShiftOp<"ShiftRightLogical", []> {
+def SPV_ShiftRightLogicalOp : SPV_ShiftOp<"ShiftRightLogical",
+ [UsableInSpecConstantOp]> {
let summary = [{
Shift the bits in Base right by the number of bits specified in Shift.
The most-significant bits will be zero filled.
// -----
-def SPV_NotOp : SPV_BitUnaryOp<"Not", []> {
+def SPV_NotOp : SPV_BitUnaryOp<"Not", [UsableInSpecConstantOp]> {
let summary = "Complement the bits of Operand.";
let description = [{
// -----
-def SPV_FConvertOp : SPV_CastOp<"FConvert", SPV_Float, SPV_Float, []> {
+def SPV_FConvertOp : SPV_CastOp<"FConvert",
+ SPV_Float,
+ SPV_Float,
+ [UsableInSpecConstantOp]> {
let summary = [{
Convert value numerically from one floating-point width to another
width.
// -----
-def SPV_SConvertOp : SPV_CastOp<"SConvert", SPV_Integer, SPV_Integer, []> {
+def SPV_SConvertOp : SPV_CastOp<"SConvert", SPV_Integer, SPV_Integer, [UsableInSpecConstantOp]> {
let summary = [{
Convert signed width. This is either a truncate or a sign extend.
}];
def SPV_UConvertOp : SPV_CastOp<"UConvert",
SPV_Integer,
SPV_Integer,
- [UnsignedOp]> {
+ [UnsignedOp, UsableInSpecConstantOp]> {
let summary = [{
Convert unsigned width. This is either a truncate or a zero extend.
}];
// -----
-def SPV_CompositeExtractOp : SPV_Op<"CompositeExtract", [NoSideEffect]> {
+def SPV_CompositeExtractOp : SPV_Op<"CompositeExtract",
+ [NoSideEffect, UsableInSpecConstantOp]> {
let summary = "Extract a part of a composite object.";
let description = [{
// -----
-def SPV_CompositeInsertOp : SPV_Op<"CompositeInsert", [NoSideEffect]> {
+def SPV_CompositeInsertOp : SPV_Op<"CompositeInsert",
+ [NoSideEffect, UsableInSpecConstantOp]> {
let summary = [{
Make a copy of a composite object, while modifying one part of it.
}];
// -----
-def SPV_IEqualOp : SPV_LogicalBinaryOp<"IEqual", SPV_Integer, [Commutative]> {
+def SPV_IEqualOp : SPV_LogicalBinaryOp<"IEqual",
+ SPV_Integer,
+ [Commutative, UsableInSpecConstantOp]> {
let summary = "Integer comparison for equality.";
let description = [{
// -----
-def SPV_INotEqualOp : SPV_LogicalBinaryOp<"INotEqual", SPV_Integer, [Commutative]> {
+def SPV_INotEqualOp : SPV_LogicalBinaryOp<"INotEqual",
+ SPV_Integer,
+ [Commutative, UsableInSpecConstantOp]> {
let summary = "Integer comparison for inequality.";
let description = [{
// -----
-def SPV_LogicalAndOp : SPV_LogicalBinaryOp<"LogicalAnd", SPV_Bool, [Commutative]> {
+def SPV_LogicalAndOp : SPV_LogicalBinaryOp<"LogicalAnd",
+ SPV_Bool,
+ [Commutative,
+ UsableInSpecConstantOp]> {
let summary = [{
Result is true if both Operand 1 and Operand 2 are true. Result is false
if either Operand 1 or Operand 2 are false.
// -----
-def SPV_LogicalEqualOp : SPV_LogicalBinaryOp<"LogicalEqual", SPV_Bool, [Commutative]> {
+def SPV_LogicalEqualOp : SPV_LogicalBinaryOp<"LogicalEqual",
+ SPV_Bool,
+ [Commutative,
+ UsableInSpecConstantOp]> {
let summary = [{
Result is true if Operand 1 and Operand 2 have the same value. Result is
false if Operand 1 and Operand 2 have different values.
// -----
-def SPV_LogicalNotOp : SPV_LogicalUnaryOp<"LogicalNot", SPV_Bool, []> {
+def SPV_LogicalNotOp : SPV_LogicalUnaryOp<"LogicalNot",
+ SPV_Bool,
+ [UsableInSpecConstantOp]> {
let summary = [{
Result is true if Operand is false. Result is false if Operand is true.
}];
// -----
-def SPV_LogicalNotEqualOp : SPV_LogicalBinaryOp<"LogicalNotEqual", SPV_Bool, [Commutative]> {
+def SPV_LogicalNotEqualOp : SPV_LogicalBinaryOp<"LogicalNotEqual",
+ SPV_Bool,
+ [Commutative,
+ UsableInSpecConstantOp]> {
let summary = [{
Result is true if Operand 1 and Operand 2 have different values. Result
is false if Operand 1 and Operand 2 have the same value.
// -----
-def SPV_LogicalOrOp : SPV_LogicalBinaryOp<"LogicalOr", SPV_Bool, [Commutative]> {
+def SPV_LogicalOrOp : SPV_LogicalBinaryOp<"LogicalOr",
+ SPV_Bool,
+ [Commutative,
+ UsableInSpecConstantOp]> {
let summary = [{
Result is true if either Operand 1 or Operand 2 is true. Result is false
if both Operand 1 and Operand 2 are false.
// -----
-def SPV_SGreaterThanOp : SPV_LogicalBinaryOp<"SGreaterThan", SPV_Integer, []> {
+def SPV_SGreaterThanOp : SPV_LogicalBinaryOp<"SGreaterThan",
+ SPV_Integer,
+ [UsableInSpecConstantOp]> {
let summary = [{
Signed-integer comparison if Operand 1 is greater than Operand 2.
}];
// -----
-def SPV_SGreaterThanEqualOp : SPV_LogicalBinaryOp<"SGreaterThanEqual", SPV_Integer, []> {
+def SPV_SGreaterThanEqualOp : SPV_LogicalBinaryOp<"SGreaterThanEqual",
+ SPV_Integer,
+ [UsableInSpecConstantOp]> {
let summary = [{
Signed-integer comparison if Operand 1 is greater than or equal to
Operand 2.
// -----
-def SPV_SLessThanOp : SPV_LogicalBinaryOp<"SLessThan", SPV_Integer, []> {
+def SPV_SLessThanOp : SPV_LogicalBinaryOp<"SLessThan",
+ SPV_Integer,
+ [UsableInSpecConstantOp]> {
let summary = [{
Signed-integer comparison if Operand 1 is less than Operand 2.
}];
// -----
-def SPV_SLessThanEqualOp : SPV_LogicalBinaryOp<"SLessThanEqual", SPV_Integer, []> {
+def SPV_SLessThanEqualOp : SPV_LogicalBinaryOp<"SLessThanEqual",
+ SPV_Integer,
+ [UsableInSpecConstantOp]> {
let summary = [{
Signed-integer comparison if Operand 1 is less than or equal to Operand
2.
// -----
def SPV_SelectOp : SPV_Op<"Select",
- [NoSideEffect, AllTypesMatch<["true_value", "false_value", "result"]>]> {
+ [NoSideEffect,
+ AllTypesMatch<["true_value", "false_value", "result"]>,
+ UsableInSpecConstantOp]> {
let summary = [{
Select between two objects. Before version 1.4, results are only
computed per component.
def SPV_UGreaterThanOp : SPV_LogicalBinaryOp<"UGreaterThan",
SPV_Integer,
- [UnsignedOp]> {
+ [UnsignedOp,
+ UsableInSpecConstantOp]> {
let summary = [{
Unsigned-integer comparison if Operand 1 is greater than Operand 2.
}];
def SPV_UGreaterThanEqualOp : SPV_LogicalBinaryOp<"UGreaterThanEqual",
SPV_Integer,
- [UnsignedOp]> {
+ [UnsignedOp,
+ UsableInSpecConstantOp]> {
let summary = [{
Unsigned-integer comparison if Operand 1 is greater than or equal to
Operand 2.
def SPV_ULessThanOp : SPV_LogicalBinaryOp<"ULessThan",
SPV_Integer,
- [UnsignedOp]> {
+ [UnsignedOp, UsableInSpecConstantOp]> {
let summary = [{
Unsigned-integer comparison if Operand 1 is less than Operand 2.
}];
// -----
-def SPV_ULessThanEqualOp :
- SPV_LogicalBinaryOp<"ULessThanEqual", SPV_Integer, [UnsignedOp]> {
+def SPV_ULessThanEqualOp : SPV_LogicalBinaryOp<"ULessThanEqual",
+ SPV_Integer,
+ [UnsignedOp,
+ UsableInSpecConstantOp]> {
let summary = [{
Unsigned-integer comparison if Operand 1 is less than or equal to
Operand 2.
template <typename ConcreteType>
class UnsignedOp : public TraitBase<ConcreteType, UnsignedOp> {};
+/// A trait to mark ops that can be enclosed/wrapped in a
+/// `SpecConstantOperation` op.
+template <typename ConcreteType>
+class UsableInSpecConstantOp
+ : public TraitBase<ConcreteType, UsableInSpecConstantOp> {};
+
} // namespace spirv
} // namespace OpTrait
} // namespace mlir
#include "mlir/Dialect/SPIRV/IR/ParserUtils.h"
#include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.h"
#include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h"
+#include "mlir/Dialect/SPIRV/IR/SPIRVOpTraits.h"
#include "mlir/Dialect/SPIRV/IR/SPIRVTypes.h"
#include "mlir/Dialect/SPIRV/IR/TargetAndABI.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/FunctionImplementation.h"
+#include "mlir/IR/OpDefinition.h"
#include "mlir/IR/OpImplementation.h"
#include "mlir/Interfaces/CallInterfaces.h"
#include "llvm/ADT/StringExtras.h"
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))
+ if (!enclosedOp.hasTrait<OpTrait::spirv::UsableInSpecConstantOp>())
return constOp.emitOpError("invalid enclosed op");
for (auto operand : enclosedOp.getOperands())