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
diff --git a/third_party/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td b/third_party/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td
index df15b92..e90e816 100644
--- a/third_party/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td
+++ b/third_party/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td
@@ -72,70 +72,82 @@
 
 // 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 @@
       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";
diff --git a/third_party/mlir/include/mlir/Dialect/SPIRV/SPIRVLogicalOps.td b/third_party/mlir/include/mlir/Dialect/SPIRV/SPIRVLogicalOps.td
index c563234..51781d8 100644
--- a/third_party/mlir/include/mlir/Dialect/SPIRV/SPIRVLogicalOps.td
+++ b/third_party/mlir/include/mlir/Dialect/SPIRV/SPIRVLogicalOps.td
@@ -42,6 +42,402 @@
 
 // -----
 
+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_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.
diff --git a/third_party/mlir/utils/spirv/define_inst.sh b/third_party/mlir/utils/spirv/define_inst.sh
index 49b5e8d..55e2fa0 100755
--- a/third_party/mlir/utils/spirv/define_inst.sh
+++ b/third_party/mlir/utils/spirv/define_inst.sh
@@ -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 "$@"
diff --git a/third_party/mlir/utils/spirv/gen_spirv_dialect.py b/third_party/mlir/utils/spirv/gen_spirv_dialect.py
index e34945d4..e74a40e 100755
--- a/third_party/mlir/utils/spirv/gen_spirv_dialect.py
+++ b/third_party/mlir/utils/spirv/gen_spirv_dialect.py
@@ -360,7 +360,7 @@
   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 @@
   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 @@
 
   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 @@
       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 @@
   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 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 @@
         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 @@
       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 @@
   # 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.')