Add floating-point comparison operations to SPIR-V dialect.

Use the existing SPV_LogicalOp specification to add the floating-point
comparison operations (both ordered and unordered versions).
To make it easier to import the op-definitions automatically modify
the dialect generation script to update the different .td files based
on whether the operation is an arithmetic op, logical op, etc. Also
allow specification of multiple opcodes with define_inst.sh.
Since this reuses the SPV_LogicalOp framework, no tests specific to
the floating point comparison ops are added with this CL.

PiperOrigin-RevId: 266561634
This commit is contained in:
Mahesh Ravishankar 2019-08-31 09:52:18 -07:00 committed by A. Unique TensorFlower
parent 5a7014c390
commit 49c3e4a508
4 changed files with 571 additions and 110 deletions

View file

@ -72,70 +72,82 @@ class SPV_OpCode<string name, int val> {
// Begin opcode section. Generated from SPIR-V spec; DO NOT MODIFY!
def SPV_OC_OpNop : I32EnumAttrCase<"OpNop", 0>;
def SPV_OC_OpName : I32EnumAttrCase<"OpName", 5>;
def SPV_OC_OpExtension : I32EnumAttrCase<"OpExtension", 10>;
def SPV_OC_OpMemoryModel : I32EnumAttrCase<"OpMemoryModel", 14>;
def SPV_OC_OpEntryPoint : I32EnumAttrCase<"OpEntryPoint", 15>;
def SPV_OC_OpExecutionMode : I32EnumAttrCase<"OpExecutionMode", 16>;
def SPV_OC_OpCapability : I32EnumAttrCase<"OpCapability", 17>;
def SPV_OC_OpTypeVoid : I32EnumAttrCase<"OpTypeVoid", 19>;
def SPV_OC_OpTypeBool : I32EnumAttrCase<"OpTypeBool", 20>;
def SPV_OC_OpTypeInt : I32EnumAttrCase<"OpTypeInt", 21>;
def SPV_OC_OpTypeFloat : I32EnumAttrCase<"OpTypeFloat", 22>;
def SPV_OC_OpTypeVector : I32EnumAttrCase<"OpTypeVector", 23>;
def SPV_OC_OpTypeArray : I32EnumAttrCase<"OpTypeArray", 28>;
def SPV_OC_OpTypeStruct : I32EnumAttrCase<"OpTypeStruct", 30>;
def SPV_OC_OpTypePointer : I32EnumAttrCase<"OpTypePointer", 32>;
def SPV_OC_OpTypeFunction : I32EnumAttrCase<"OpTypeFunction", 33>;
def SPV_OC_OpConstantTrue : I32EnumAttrCase<"OpConstantTrue", 41>;
def SPV_OC_OpConstantFalse : I32EnumAttrCase<"OpConstantFalse", 42>;
def SPV_OC_OpConstant : I32EnumAttrCase<"OpConstant", 43>;
def SPV_OC_OpConstantComposite : I32EnumAttrCase<"OpConstantComposite", 44>;
def SPV_OC_OpConstantNull : I32EnumAttrCase<"OpConstantNull", 46>;
def SPV_OC_OpSpecConstantTrue : I32EnumAttrCase<"OpSpecConstantTrue", 48>;
def SPV_OC_OpSpecConstantFalse : I32EnumAttrCase<"OpSpecConstantFalse", 49>;
def SPV_OC_OpSpecConstant : I32EnumAttrCase<"OpSpecConstant", 50>;
def SPV_OC_OpSpecConstantComposite : I32EnumAttrCase<"OpSpecConstantComposite", 51>;
def SPV_OC_OpFunction : I32EnumAttrCase<"OpFunction", 54>;
def SPV_OC_OpFunctionParameter : I32EnumAttrCase<"OpFunctionParameter", 55>;
def SPV_OC_OpFunctionEnd : I32EnumAttrCase<"OpFunctionEnd", 56>;
def SPV_OC_OpVariable : I32EnumAttrCase<"OpVariable", 59>;
def SPV_OC_OpLoad : I32EnumAttrCase<"OpLoad", 61>;
def SPV_OC_OpStore : I32EnumAttrCase<"OpStore", 62>;
def SPV_OC_OpAccessChain : I32EnumAttrCase<"OpAccessChain", 65>;
def SPV_OC_OpDecorate : I32EnumAttrCase<"OpDecorate", 71>;
def SPV_OC_OpMemberDecorate : I32EnumAttrCase<"OpMemberDecorate", 72>;
def SPV_OC_OpCompositeExtract : I32EnumAttrCase<"OpCompositeExtract", 81>;
def SPV_OC_OpIAdd : I32EnumAttrCase<"OpIAdd", 128>;
def SPV_OC_OpFAdd : I32EnumAttrCase<"OpFAdd", 129>;
def SPV_OC_OpISub : I32EnumAttrCase<"OpISub", 130>;
def SPV_OC_OpFSub : I32EnumAttrCase<"OpFSub", 131>;
def SPV_OC_OpIMul : I32EnumAttrCase<"OpIMul", 132>;
def SPV_OC_OpFMul : I32EnumAttrCase<"OpFMul", 133>;
def SPV_OC_OpUDiv : I32EnumAttrCase<"OpUDiv", 134>;
def SPV_OC_OpSDiv : I32EnumAttrCase<"OpSDiv", 135>;
def SPV_OC_OpFDiv : I32EnumAttrCase<"OpFDiv", 136>;
def SPV_OC_OpUMod : I32EnumAttrCase<"OpUMod", 137>;
def SPV_OC_OpSRem : I32EnumAttrCase<"OpSRem", 138>;
def SPV_OC_OpSMod : I32EnumAttrCase<"OpSMod", 139>;
def SPV_OC_OpFRem : I32EnumAttrCase<"OpFRem", 140>;
def SPV_OC_OpFMod : I32EnumAttrCase<"OpFMod", 141>;
def SPV_OC_OpIEqual : I32EnumAttrCase<"OpIEqual", 170>;
def SPV_OC_OpINotEqual : I32EnumAttrCase<"OpINotEqual", 171>;
def SPV_OC_OpUGreaterThan : I32EnumAttrCase<"OpUGreaterThan", 172>;
def SPV_OC_OpSGreaterThan : I32EnumAttrCase<"OpSGreaterThan", 173>;
def SPV_OC_OpUGreaterThanEqual : I32EnumAttrCase<"OpUGreaterThanEqual", 174>;
def SPV_OC_OpSGreaterThanEqual : I32EnumAttrCase<"OpSGreaterThanEqual", 175>;
def SPV_OC_OpULessThan : I32EnumAttrCase<"OpULessThan", 176>;
def SPV_OC_OpSLessThan : I32EnumAttrCase<"OpSLessThan", 177>;
def SPV_OC_OpULessThanEqual : I32EnumAttrCase<"OpULessThanEqual", 178>;
def SPV_OC_OpSLessThanEqual : I32EnumAttrCase<"OpSLessThanEqual", 179>;
def SPV_OC_OpLabel : I32EnumAttrCase<"OpLabel", 248>;
def SPV_OC_OpBranch : I32EnumAttrCase<"OpBranch", 249>;
def SPV_OC_OpBranchConditional : I32EnumAttrCase<"OpBranchConditional", 250>;
def SPV_OC_OpReturn : I32EnumAttrCase<"OpReturn", 253>;
def SPV_OC_OpReturnValue : I32EnumAttrCase<"OpReturnValue", 254>;
def SPV_OC_OpNop : I32EnumAttrCase<"OpNop", 0>;
def SPV_OC_OpName : I32EnumAttrCase<"OpName", 5>;
def SPV_OC_OpExtension : I32EnumAttrCase<"OpExtension", 10>;
def SPV_OC_OpMemoryModel : I32EnumAttrCase<"OpMemoryModel", 14>;
def SPV_OC_OpEntryPoint : I32EnumAttrCase<"OpEntryPoint", 15>;
def SPV_OC_OpExecutionMode : I32EnumAttrCase<"OpExecutionMode", 16>;
def SPV_OC_OpCapability : I32EnumAttrCase<"OpCapability", 17>;
def SPV_OC_OpTypeVoid : I32EnumAttrCase<"OpTypeVoid", 19>;
def SPV_OC_OpTypeBool : I32EnumAttrCase<"OpTypeBool", 20>;
def SPV_OC_OpTypeInt : I32EnumAttrCase<"OpTypeInt", 21>;
def SPV_OC_OpTypeFloat : I32EnumAttrCase<"OpTypeFloat", 22>;
def SPV_OC_OpTypeVector : I32EnumAttrCase<"OpTypeVector", 23>;
def SPV_OC_OpTypeArray : I32EnumAttrCase<"OpTypeArray", 28>;
def SPV_OC_OpTypeStruct : I32EnumAttrCase<"OpTypeStruct", 30>;
def SPV_OC_OpTypePointer : I32EnumAttrCase<"OpTypePointer", 32>;
def SPV_OC_OpTypeFunction : I32EnumAttrCase<"OpTypeFunction", 33>;
def SPV_OC_OpConstantTrue : I32EnumAttrCase<"OpConstantTrue", 41>;
def SPV_OC_OpConstantFalse : I32EnumAttrCase<"OpConstantFalse", 42>;
def SPV_OC_OpConstant : I32EnumAttrCase<"OpConstant", 43>;
def SPV_OC_OpConstantComposite : I32EnumAttrCase<"OpConstantComposite", 44>;
def SPV_OC_OpConstantNull : I32EnumAttrCase<"OpConstantNull", 46>;
def SPV_OC_OpSpecConstantTrue : I32EnumAttrCase<"OpSpecConstantTrue", 48>;
def SPV_OC_OpSpecConstantFalse : I32EnumAttrCase<"OpSpecConstantFalse", 49>;
def SPV_OC_OpSpecConstant : I32EnumAttrCase<"OpSpecConstant", 50>;
def SPV_OC_OpSpecConstantComposite : I32EnumAttrCase<"OpSpecConstantComposite", 51>;
def SPV_OC_OpFunction : I32EnumAttrCase<"OpFunction", 54>;
def SPV_OC_OpFunctionParameter : I32EnumAttrCase<"OpFunctionParameter", 55>;
def SPV_OC_OpFunctionEnd : I32EnumAttrCase<"OpFunctionEnd", 56>;
def SPV_OC_OpVariable : I32EnumAttrCase<"OpVariable", 59>;
def SPV_OC_OpLoad : I32EnumAttrCase<"OpLoad", 61>;
def SPV_OC_OpStore : I32EnumAttrCase<"OpStore", 62>;
def SPV_OC_OpAccessChain : I32EnumAttrCase<"OpAccessChain", 65>;
def SPV_OC_OpDecorate : I32EnumAttrCase<"OpDecorate", 71>;
def SPV_OC_OpMemberDecorate : I32EnumAttrCase<"OpMemberDecorate", 72>;
def SPV_OC_OpCompositeExtract : I32EnumAttrCase<"OpCompositeExtract", 81>;
def SPV_OC_OpIAdd : I32EnumAttrCase<"OpIAdd", 128>;
def SPV_OC_OpFAdd : I32EnumAttrCase<"OpFAdd", 129>;
def SPV_OC_OpISub : I32EnumAttrCase<"OpISub", 130>;
def SPV_OC_OpFSub : I32EnumAttrCase<"OpFSub", 131>;
def SPV_OC_OpIMul : I32EnumAttrCase<"OpIMul", 132>;
def SPV_OC_OpFMul : I32EnumAttrCase<"OpFMul", 133>;
def SPV_OC_OpUDiv : I32EnumAttrCase<"OpUDiv", 134>;
def SPV_OC_OpSDiv : I32EnumAttrCase<"OpSDiv", 135>;
def SPV_OC_OpFDiv : I32EnumAttrCase<"OpFDiv", 136>;
def SPV_OC_OpUMod : I32EnumAttrCase<"OpUMod", 137>;
def SPV_OC_OpSRem : I32EnumAttrCase<"OpSRem", 138>;
def SPV_OC_OpSMod : I32EnumAttrCase<"OpSMod", 139>;
def SPV_OC_OpFRem : I32EnumAttrCase<"OpFRem", 140>;
def SPV_OC_OpFMod : I32EnumAttrCase<"OpFMod", 141>;
def SPV_OC_OpIEqual : I32EnumAttrCase<"OpIEqual", 170>;
def SPV_OC_OpINotEqual : I32EnumAttrCase<"OpINotEqual", 171>;
def SPV_OC_OpUGreaterThan : I32EnumAttrCase<"OpUGreaterThan", 172>;
def SPV_OC_OpSGreaterThan : I32EnumAttrCase<"OpSGreaterThan", 173>;
def SPV_OC_OpUGreaterThanEqual : I32EnumAttrCase<"OpUGreaterThanEqual", 174>;
def SPV_OC_OpSGreaterThanEqual : I32EnumAttrCase<"OpSGreaterThanEqual", 175>;
def SPV_OC_OpULessThan : I32EnumAttrCase<"OpULessThan", 176>;
def SPV_OC_OpSLessThan : I32EnumAttrCase<"OpSLessThan", 177>;
def SPV_OC_OpULessThanEqual : I32EnumAttrCase<"OpULessThanEqual", 178>;
def SPV_OC_OpSLessThanEqual : I32EnumAttrCase<"OpSLessThanEqual", 179>;
def SPV_OC_OpFOrdEqual : I32EnumAttrCase<"OpFOrdEqual", 180>;
def SPV_OC_OpFUnordEqual : I32EnumAttrCase<"OpFUnordEqual", 181>;
def SPV_OC_OpFOrdNotEqual : I32EnumAttrCase<"OpFOrdNotEqual", 182>;
def SPV_OC_OpFUnordNotEqual : I32EnumAttrCase<"OpFUnordNotEqual", 183>;
def SPV_OC_OpFOrdLessThan : I32EnumAttrCase<"OpFOrdLessThan", 184>;
def SPV_OC_OpFUnordLessThan : I32EnumAttrCase<"OpFUnordLessThan", 185>;
def SPV_OC_OpFOrdGreaterThan : I32EnumAttrCase<"OpFOrdGreaterThan", 186>;
def SPV_OC_OpFUnordGreaterThan : I32EnumAttrCase<"OpFUnordGreaterThan", 187>;
def SPV_OC_OpFOrdLessThanEqual : I32EnumAttrCase<"OpFOrdLessThanEqual", 188>;
def SPV_OC_OpFUnordLessThanEqual : I32EnumAttrCase<"OpFUnordLessThanEqual", 189>;
def SPV_OC_OpFOrdGreaterThanEqual : I32EnumAttrCase<"OpFOrdGreaterThanEqual", 190>;
def SPV_OC_OpFUnordGreaterThanEqual : I32EnumAttrCase<"OpFUnordGreaterThanEqual", 191>;
def SPV_OC_OpLabel : I32EnumAttrCase<"OpLabel", 248>;
def SPV_OC_OpBranch : I32EnumAttrCase<"OpBranch", 249>;
def SPV_OC_OpBranchConditional : I32EnumAttrCase<"OpBranchConditional", 250>;
def SPV_OC_OpReturn : I32EnumAttrCase<"OpReturn", 253>;
def SPV_OC_OpReturnValue : I32EnumAttrCase<"OpReturnValue", 254>;
def SPV_OpcodeAttr :
I32EnumAttr<"Opcode", "valid SPIR-V instructions", [
@ -156,7 +168,12 @@ def SPV_OpcodeAttr :
SPV_OC_OpINotEqual, SPV_OC_OpUGreaterThan, SPV_OC_OpSGreaterThan,
SPV_OC_OpUGreaterThanEqual, SPV_OC_OpSGreaterThanEqual, SPV_OC_OpULessThan,
SPV_OC_OpSLessThan, SPV_OC_OpULessThanEqual, SPV_OC_OpSLessThanEqual,
SPV_OC_OpLabel, SPV_OC_OpBranch, SPV_OC_OpBranchConditional, SPV_OC_OpReturn,
SPV_OC_OpFOrdEqual, SPV_OC_OpFUnordEqual, SPV_OC_OpFOrdNotEqual,
SPV_OC_OpFUnordNotEqual, SPV_OC_OpFOrdLessThan, SPV_OC_OpFUnordLessThan,
SPV_OC_OpFOrdGreaterThan, SPV_OC_OpFUnordGreaterThan,
SPV_OC_OpFOrdLessThanEqual, SPV_OC_OpFUnordLessThanEqual,
SPV_OC_OpFOrdGreaterThanEqual, SPV_OC_OpFUnordGreaterThanEqual, SPV_OC_OpLabel,
SPV_OC_OpBranch, SPV_OC_OpBranchConditional, SPV_OC_OpReturn,
SPV_OC_OpReturnValue
]> {
let returnType = "::mlir::spirv::Opcode";

View file

@ -42,6 +42,402 @@ class SPV_LogicalOp<string mnemonic, Type operandsType,
// -----
def SPV_FOrdEqualOp : SPV_LogicalOp<"FOrdEqual", SPV_Float, [Commutative]> {
let summary = "Floating-point comparison for being ordered and equal.";
let description = [{
Result Type must be a scalar or vector of Boolean type.
The type of Operand 1 and Operand 2 must be a scalar or vector of
floating-point type. They must have the same type, and they must have
the same number of components as Result Type.
Results are computed per component.
### Custom assembly form
``` {.ebnf}
float-scalar-vector-type ::= float-type |
`vector<` integer-literal `x` float-type `>`
fordequal-op ::= ssa-id `=` `spv.FOrdEqual` ssa-use, ssa-use
```
For example:
```
%4 = spv.FOrdEqual %0, %1 : f32
%5 = spv.FOrdEqual %2, %3 : vector<4xf32>
```
}];
}
// -----
def SPV_FOrdGreaterThanOp : SPV_LogicalOp<"FOrdGreaterThan", SPV_Float, []> {
let summary = [{
Floating-point comparison if operands are ordered and Operand 1 is
greater than Operand 2.
}];
let description = [{
Result Type must be a scalar or vector of Boolean type.
The type of Operand 1 and Operand 2 must be a scalar or vector of
floating-point type. They must have the same type, and they must have
the same number of components as Result Type.
Results are computed per component.
### Custom assembly form
``` {.ebnf}
float-scalar-vector-type ::= float-type |
`vector<` integer-literal `x` float-type `>`
fordgt-op ::= ssa-id `=` `spv.FOrdGreaterThan` ssa-use, ssa-use
```
For example:
```
%4 = spv.FOrdGreaterThan %0, %1 : f32
%5 = spv.FOrdGreaterThan %2, %3 : vector<4xf32>
```
}];
}
// -----
def SPV_FOrdGreaterThanEqualOp : SPV_LogicalOp<"FOrdGreaterThanEqual", SPV_Float, []> {
let summary = [{
Floating-point comparison if operands are ordered and Operand 1 is
greater than or equal to Operand 2.
}];
let description = [{
Result Type must be a scalar or vector of Boolean type.
The type of Operand 1 and Operand 2 must be a scalar or vector of
floating-point type. They must have the same type, and they must have
the same number of components as Result Type.
Results are computed per component.
### Custom assembly form
``` {.ebnf}
float-scalar-vector-type ::= float-type |
`vector<` integer-literal `x` float-type `>`
fordgte-op ::= ssa-id `=` `spv.FOrdGreaterThanEqual` ssa-use, ssa-use
```
For example:
```
%4 = spv.FOrdGreaterThanEqual %0, %1 : f32
%5 = spv.FOrdGreaterThanEqual %2, %3 : vector<4xf32>
```
}];
}
// -----
def SPV_FOrdLessThanOp : SPV_LogicalOp<"FOrdLessThan", SPV_Float, []> {
let summary = [{
Floating-point comparison if operands are ordered and Operand 1 is less
than Operand 2.
}];
let description = [{
Result Type must be a scalar or vector of Boolean type.
The type of Operand 1 and Operand 2 must be a scalar or vector of
floating-point type. They must have the same type, and they must have
the same number of components as Result Type.
Results are computed per component.
### Custom assembly form
``` {.ebnf}
float-scalar-vector-type ::= float-type |
`vector<` integer-literal `x` float-type `>`
fordlt-op ::= ssa-id `=` `spv.FOrdLessThan` ssa-use, ssa-use
```
For example:
```
%4 = spv.FOrdLessThan %0, %1 : f32
%5 = spv.FOrdLessThan %2, %3 : vector<4xf32>
```
}];
}
// -----
def SPV_FOrdLessThanEqualOp : SPV_LogicalOp<"FOrdLessThanEqual", SPV_Float, []> {
let summary = [{
Floating-point comparison if operands are ordered and Operand 1 is less
than or equal to Operand 2.
}];
let description = [{
Result Type must be a scalar or vector of Boolean type.
The type of Operand 1 and Operand 2 must be a scalar or vector of
floating-point type. They must have the same type, and they must have
the same number of components as Result Type.
Results are computed per component.
### Custom assembly form
``` {.ebnf}
float-scalar-vector-type ::= float-type |
`vector<` integer-literal `x` float-type `>`
fordlte-op ::= ssa-id `=` `spv.FOrdLessThanEqual` ssa-use, ssa-use
```
For example:
```
%4 = spv.FOrdLessThanEqual %0, %1 : f32
%5 = spv.FOrdLessThanEqual %2, %3 : vector<4xf32>
```
}];
}
// -----
def SPV_FOrdNotEqualOp : SPV_LogicalOp<"FOrdNotEqual", SPV_Float, [Commutative]> {
let summary = "Floating-point comparison for being ordered and not equal.";
let description = [{
Result Type must be a scalar or vector of Boolean type.
The type of Operand 1 and Operand 2 must be a scalar or vector of
floating-point type. They must have the same type, and they must have
the same number of components as Result Type.
Results are computed per component.
### Custom assembly form
``` {.ebnf}
float-scalar-vector-type ::= float-type |
`vector<` integer-literal `x` float-type `>`
fordneq-op ::= ssa-id `=` `spv.FOrdNotEqual` ssa-use, ssa-use
```
For example:
```
%4 = spv.FOrdNotEqual %0, %1 : f32
%5 = spv.FOrdNotEqual %2, %3 : vector<4xf32>
```
}];
}
// -----
def SPV_FUnordEqualOp : SPV_LogicalOp<"FUnordEqual", SPV_Float, [Commutative]> {
let summary = "Floating-point comparison for being unordered or equal.";
let description = [{
Result Type must be a scalar or vector of Boolean type.
The type of Operand 1 and Operand 2 must be a scalar or vector of
floating-point type. They must have the same type, and they must have
the same number of components as Result Type.
Results are computed per component.
### Custom assembly form
``` {.ebnf}
float-scalar-vector-type ::= float-type |
`vector<` integer-literal `x` float-type `>`
funordequal-op ::= ssa-id `=` `spv.FUnordEqual` ssa-use, ssa-use
```
For example:
```
%4 = spv.FUnordEqual %0, %1 : f32
%5 = spv.FUnordEqual %2, %3 : vector<4xf32>
```
}];
}
// -----
def SPV_FUnordGreaterThanOp : SPV_LogicalOp<"FUnordGreaterThan", SPV_Float, []> {
let summary = [{
Floating-point comparison if operands are unordered or Operand 1 is
greater than Operand 2.
}];
let description = [{
Result Type must be a scalar or vector of Boolean type.
The type of Operand 1 and Operand 2 must be a scalar or vector of
floating-point type. They must have the same type, and they must have
the same number of components as Result Type.
Results are computed per component.
### Custom assembly form
``` {.ebnf}
float-scalar-vector-type ::= float-type |
`vector<` integer-literal `x` float-type `>`
funordgt-op ::= ssa-id `=` `spv.FUnordGreaterThan` ssa-use, ssa-use
```
For example:
```
%4 = spv.FUnordGreaterThan %0, %1 : f32
%5 = spv.FUnordGreaterThan %2, %3 : vector<4xf32>
```
}];
}
// -----
def SPV_FUnordGreaterThanEqualOp : SPV_LogicalOp<"FUnordGreaterThanEqual", SPV_Float, []> {
let summary = [{
Floating-point comparison if operands are unordered or Operand 1 is
greater than or equal to Operand 2.
}];
let description = [{
Result Type must be a scalar or vector of Boolean type.
The type of Operand 1 and Operand 2 must be a scalar or vector of
floating-point type. They must have the same type, and they must have
the same number of components as Result Type.
Results are computed per component.
### Custom assembly form
``` {.ebnf}
float-scalar-vector-type ::= float-type |
`vector<` integer-literal `x` float-type `>`
funordgte-op ::= ssa-id `=` `spv.FUnordGreaterThanEqual` ssa-use, ssa-use
```
For example:
```
%4 = spv.FUnordGreaterThanEqual %0, %1 : f32
%5 = spv.FUnordGreaterThanEqual %2, %3 : vector<4xf32>
```
}];
}
// -----
def SPV_FUnordLessThanOp : SPV_LogicalOp<"FUnordLessThan", SPV_Float, []> {
let summary = [{
Floating-point comparison if operands are unordered or Operand 1 is less
than Operand 2.
}];
let description = [{
Result Type must be a scalar or vector of Boolean type.
The type of Operand 1 and Operand 2 must be a scalar or vector of
floating-point type. They must have the same type, and they must have
the same number of components as Result Type.
Results are computed per component.
### Custom assembly form
``` {.ebnf}
float-scalar-vector-type ::= float-type |
`vector<` integer-literal `x` float-type `>`
funordlt-op ::= ssa-id `=` `spv.FUnordLessThan` ssa-use, ssa-use
```
For example:
```
%4 = spv.FUnordLessThan %0, %1 : f32
%5 = spv.FUnordLessThan %2, %3 : vector<4xf32>
```
}];
}
// -----
def SPV_FUnordLessThanEqualOp : SPV_LogicalOp<"FUnordLessThanEqual", SPV_Float, []> {
let summary = [{
Floating-point comparison if operands are unordered or Operand 1 is less
than or equal to Operand 2.
}];
let description = [{
Result Type must be a scalar or vector of Boolean type.
The type of Operand 1 and Operand 2 must be a scalar or vector of
floating-point type. They must have the same type, and they must have
the same number of components as Result Type.
Results are computed per component.
### Custom assembly form
``` {.ebnf}
float-scalar-vector-type ::= float-type |
`vector<` integer-literal `x` float-type `>`
funordlte-op ::= ssa-id `=` `spv.FUnordLessThanEqual` ssa-use, ssa-use
```
For example:
```
%4 = spv.FUnordLessThanEqual %0, %1 : f32
%5 = spv.FUnordLessThanEqual %2, %3 : vector<4xf32>
```
}];
}
// -----
def SPV_FUnordNotEqualOp : SPV_LogicalOp<"FUnordNotEqual", SPV_Float, [Commutative]> {
let summary = "Floating-point comparison for being unordered or not equal.";
let description = [{
Result Type must be a scalar or vector of Boolean type.
The type of Operand 1 and Operand 2 must be a scalar or vector of
floating-point type. They must have the same type, and they must have
the same number of components as Result Type.
Results are computed per component.
### Custom assembly form
``` {.ebnf}
float-scalar-vector-type ::= float-type |
`vector<` integer-literal `x` float-type `>`
funordneq-op ::= ssa-id `=` `spv.FUnordNotEqual` ssa-use, ssa-use
```
For example:
```
%4 = spv.FUnordNotEqual %0, %1 : f32
%5 = spv.FUnordNotEqual %2, %3 : vector<4xf32>
```
}];
}
// -----
def SPV_IEqualOp : SPV_LogicalOp<"IEqual", SPV_Integer, [Commutative]> {
let summary = "Integer comparison for equality.";
@ -271,8 +667,7 @@ def SPV_UGreaterThanOp : SPV_LogicalOp<"UGreaterThan", SPV_Integer, []> {
// -----
def SPV_UGreaterThanEqualOp
: SPV_LogicalOp<"UGreaterThanEqual", SPV_Integer, []> {
def SPV_UGreaterThanEqualOp : SPV_LogicalOp<"UGreaterThanEqual", SPV_Integer, []> {
let summary = [{
Unsigned-integer comparison if Operand 1 is greater than or equal to
Operand 2.

View file

@ -17,20 +17,38 @@
# Script for defining a new op using SPIR-V spec from the Internet.
#
# Run as:
# ./define_inst.sh <opname>
# ./define_inst.sh <inst_category> (<opname>)*
# <inst_category> is required. It can be one of
# (Op|ArithmeticOp|LogicalOp|ControlFlowOp|StructureOp). Based on the
# inst_category the file SPIRV<inst_category>s.td is updated with the
# instruction definition. If <opname> is missing, this script updates existing
# ones in SPIRV<inst_category>s.td
# For example:
# ./define_inst.sh OpIAdd
#
# If <opname> is missing, this script updates existing ones.
# ./define_inst.sh ArithmeticOp OpIAdd
# ./define_inst.sh LogicalOp OpFOrdEqual
set -e
new_op=$1
inst_category=$1
case $inst_category in
Op | ArithmeticOp | LogicalOp | ControlFlowOp | StructureOp)
;;
*)
echo "Usage : " $0 " <inst_category> (<opname>)*"
echo "<inst_category> must be one of " \
"(Op|ArithmeticOp|LogicalOp|ControlFlowOp|StructureOp)"
exit 1;
;;
esac
shift
current_file="$(readlink -f "$0")"
current_dir="$(dirname "$current_file")"
python3 ${current_dir}/gen_spirv_dialect.py \
--op-td-path ${current_dir}/../../include/mlir/Dialect/SPIRV/SPIRVOps.td \
--new-inst "${new_op}"
--op-td-path \
${current_dir}/../../include/mlir/Dialect/SPIRV/SPIRV${inst_category}s.td \
--inst-category $inst_category --new-inst "$@"

View file

@ -360,7 +360,7 @@ def map_spec_operand_to_ods_argument(operand):
return '{}:${}'.format(arg_type, name)
def get_op_definition(instruction, doc, existing_info):
def get_op_definition(instruction, doc, existing_info, inst_category):
"""Generates the TableGen op definition for the given SPIR-V instruction.
Arguments:
@ -372,19 +372,22 @@ def get_op_definition(instruction, doc, existing_info):
Returns:
- A string containing the TableGen op definition
"""
fmt_str = 'def SPV_{opname}Op : SPV_Op<"{opname}", [{traits}]> {{\n'\
' let summary = {summary};\n\n'\
' let description = [{{\n'\
'{description}\n\n'\
' ### Custom assembly form\n'\
'{assembly}'\
'}}];\n\n'\
' let arguments = (ins{args});\n\n'\
' let results = (outs{results});\n'\
'{extras}'\
fmt_str = ('def SPV_{opname}Op : '
'SPV_{inst_category}<"{opname}"{category_args}[{traits}]> '
'{{\n let summary = {summary};\n\n let description = '
'[{{\n{description}\n\n ### Custom assembly '
'form\n{assembly}}}];\n')
if inst_category == 'Op':
fmt_str +='\n let arguments = (ins{args});\n\n'\
' let results = (outs{results});\n\n'
fmt_str +='{extras}'\
'}}\n'
opname = instruction['opname'][2:]
category_args = existing_info.get('category_args', None)
if category_args is None:
category_args = ', '
summary, description = doc.split('\n', 1)
wrapper = textwrap.TextWrapper(
@ -438,6 +441,8 @@ def get_op_definition(instruction, doc, existing_info):
return fmt_str.format(
opname=opname,
category_args=category_args,
inst_category=inst_category,
traits=existing_info.get('traits', ''),
summary=summary,
description=description,
@ -447,6 +452,29 @@ def get_op_definition(instruction, doc, existing_info):
extras=existing_info.get('extras', ''))
def get_string_between(base, start, end):
"""Extracts a substring with a specified start and end from a string.
Arguments:
- base: string to extract from.
- start: string to use as the start of the substring.
- end: string to use as the end of the substring.
Returns:
- The substring if found
- The part of the base after end of the substring. Is the base string itself
if the substring wasnt found.
"""
split = base.split(start, 1)
if len(split) == 2:
rest = split[1].split(end, 1)
assert len(rest) == 2, \
'cannot find end "{end}" while extracting substring '\
'starting with {start}'.format(start=start, end=end)
return rest[0].rstrip(end), rest[1]
return '', split[0]
def extract_td_op_info(op_def):
"""Extracts potentially manually specified sections in op's definition.
@ -461,39 +489,32 @@ def extract_td_op_info(op_def):
assert len(opname) == 1, 'more than one ops in the same section!'
opname = opname[0]
# Get category_args
op_tmpl_params = op_def.split('<', 1)[1].split('>', 1)[0]
opstringname, rest = get_string_between(op_tmpl_params, '"', '"')
category_args = rest.split('[', 1)[0]
# Get traits
op_tmpl_params = op_def.split('<', 1)[1].split('>', 1)[0].split(', ', 1)
if len(op_tmpl_params) == 1:
traits = ''
else:
traits = op_tmpl_params[1].strip('[]')
traits, _ = get_string_between(rest, '[', ']')
# Get custom assembly form
rest = op_def.split('### Custom assembly form\n')
assert len(rest) == 2, \
'{}: cannot find "### Custom assembly form"'.format(opname)
rest = rest[1].split(' let arguments = (ins')
assert len(rest) == 2, '{}: cannot find arguments'.format(opname)
assembly = rest[0].rstrip('}];\n')
assembly, rest = get_string_between(op_def, '### Custom assembly form\n',
'}];\n')
# Get arguments
rest = rest[1].split(' let results = (outs')
assert len(rest) == 2, '{}: cannot find results'.format(opname)
args = rest[0].rstrip(');\n')
args, rest = get_string_between(rest, ' let arguments = (ins', ');\n')
# Get results
rest = rest[1].split(');', 1)
assert len(rest) == 2, \
'{}: cannot find ");" ending results'.format(opname)
results = rest[0]
results, rest = get_string_between(rest, ' let results = (outs', ');\n')
extras = rest[1].strip(' }\n')
extras = rest.strip(' }\n')
if extras:
extras = '\n {}\n'.format(extras)
return {
# Prefix with 'Op' to make it consistent with SPIR-V spec
'opname': 'Op{}'.format(opname),
'category_args': category_args,
'traits': traits,
'assembly': assembly,
'arguments': args,
@ -502,7 +523,8 @@ def extract_td_op_info(op_def):
}
def update_td_op_definitions(path, instructions, docs, filter_list):
def update_td_op_definitions(path, instructions, docs, filter_list,
inst_category):
"""Updates SPIRVOps.td with newly generated op definition.
Arguments:
@ -541,7 +563,7 @@ def update_td_op_definitions(path, instructions, docs, filter_list):
inst for inst in instructions if inst['opname'] == opname)
op_defs.append(
get_op_definition(instruction, docs[opname],
op_info_dict.get(opname, {})))
op_info_dict.get(opname, {}), inst_category))
# Substitute the old op definitions
op_defs = [header] + op_defs + [footer]
@ -588,7 +610,16 @@ if __name__ == '__main__':
dest='new_inst',
type=str,
default=None,
help='SPIR-V instruction to be added to SPIRVOps.td')
nargs='*',
help='SPIR-V instruction to be added to ops file')
cli_parser.add_argument(
'--inst-category',
dest='inst_category',
type=str,
default='Op',
help='SPIR-V instruction category used for choosing '\
'a suitable .td file and TableGen common base '\
'class to define this op')
args = cli_parser.parse_args()
@ -608,9 +639,9 @@ if __name__ == '__main__':
# Define new op
if args.new_inst is not None:
assert args.op_td_path is not None
filter_list = [args.new_inst] if args.new_inst else []
docs = get_spirv_doc_from_html_spec()
update_td_op_definitions(args.op_td_path, instructions, docs, filter_list)
update_td_op_definitions(args.op_td_path, instructions, docs, args.new_inst,
args.inst_category)
print('Done. Note that this script just generates a template; ', end='')
print('please read the spec and update traits, arguments, and ', end='')
print('results accordingly.')