From ce358f9b37e7af3917907db723705353cb725c5e Mon Sep 17 00:00:00 2001 From: Denis Khalikov Date: Wed, 31 Jul 2019 11:10:17 -0700 Subject: [PATCH] [spirv] Add binary arithmetic operations tensorflow/mlir#2. Add binary operations such as: OpUdiv, OpSDiv, OpUMod, OpSRem, OpSMod. Closes tensorflow/mlir#56 COPYBARA_INTEGRATE_REVIEW=https://github.com/tensorflow/mlir/pull/56 from denis0x0D:sandbox/bin_ops_int 4959325a693b4658b978a8b97f79b8237eb39764 PiperOrigin-RevId: 260961681 --- mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td | 8 +- mlir/include/mlir/Dialect/SPIRV/SPIRVOps.td | 171 +++++++++++++++++++++ mlir/test/Dialect/SPIRV/Serialization/bin_ops.mlir | 25 +++ mlir/test/Dialect/SPIRV/ops.mlir | 60 ++++++++ 4 files changed, 263 insertions(+), 1 deletion(-) diff --git a/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td b/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td index a820c11..838d42e 100644 --- a/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td +++ b/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td @@ -105,7 +105,12 @@ 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_OpReturn : I32EnumAttrCase<"OpReturn", 253>; @@ -121,7 +126,8 @@ def SPV_OpcodeAttr : SPV_OC_OpFunctionEnd, SPV_OC_OpVariable, SPV_OC_OpLoad, SPV_OC_OpStore, SPV_OC_OpAccessChain, SPV_OC_OpDecorate, SPV_OC_OpCompositeExtract, SPV_OC_OpIAdd, SPV_OC_OpFAdd, SPV_OC_OpISub, SPV_OC_OpFSub, SPV_OC_OpIMul, - SPV_OC_OpFMul, SPV_OC_OpFDiv, SPV_OC_OpFRem, SPV_OC_OpFMod, SPV_OC_OpReturn + SPV_OC_OpFMul, SPV_OC_OpUDiv, SPV_OC_OpSDiv, SPV_OC_OpFDiv, SPV_OC_OpUMod, + SPV_OC_OpSRem, SPV_OC_OpSMod, SPV_OC_OpFRem, SPV_OC_OpFMod, SPV_OC_OpReturn ]> { let returnType = "::mlir::spirv::Opcode"; let convertFromStorage = "static_cast<::mlir::spirv::Opcode>($_self.getInt())"; diff --git a/mlir/include/mlir/Dialect/SPIRV/SPIRVOps.td b/mlir/include/mlir/Dialect/SPIRV/SPIRVOps.td index 8f97f78..b0f2809 100644 --- a/mlir/include/mlir/Dialect/SPIRV/SPIRVOps.td +++ b/mlir/include/mlir/Dialect/SPIRV/SPIRVOps.td @@ -623,6 +623,113 @@ def SPV_ReturnOp : SPV_Op<"Return", [Terminator]> { // ----- +def SPV_SDivOp : SPV_ArithmeticOp<"SDiv", SPV_Integer> { + let summary = "Signed-integer division of Operand 1 divided by Operand 2."; + + let description = [{ + Result Type must be a scalar or vector of integer type. + + The type of Operand 1 and Operand 2 must be a scalar or vector of + integer type. They must have the same number of components as Result + Type. They must have the same component width as Result Type. + + Results are computed per component. The resulting value is undefined + if Operand 2 is 0. + + ### Custom assembly form + ``` {.ebnf} + integer-scalar-vector-type ::= integer-type | + `vector<` integer-literal `x` integer-type `>` + sdiv-op ::= ssa-id `=` `spv.SDiv` ssa-use, ssa-use + `:` integer-scalar-vector-type + ``` + + For example: + + ``` + %4 = spv.SDiv %0, %1 : i32 + %5 = spv.SDiv %2, %3 : vector<4xi32> + + ``` + }]; +} + +// ----- + +def SPV_SModOp : SPV_ArithmeticOp<"SMod", SPV_Integer> { + let summary = [{ + Signed remainder operation for the remainder whose sign matches the sign + of Operand 2. + }]; + + let description = [{ + Result Type must be a scalar or vector of integer type. + + The type of Operand 1 and Operand 2 must be a scalar or vector of + integer type. They must have the same number of components as Result + Type. They must have the same component width as Result Type. + + Results are computed per component. The resulting value is undefined + if Operand 2 is 0. Otherwise, the result is the remainder r of Operand + 1 divided by Operand 2 where if r ≠ 0, the sign of r is the same as the + sign of Operand 2. + + ### Custom assembly form + ``` {.ebnf} + integer-scalar-vector-type ::= integer-type | + `vector<` integer-literal `x` integer-type `>` + smod-op ::= ssa-id `=` `spv.SMod` ssa-use, ssa-use + `:` integer-scalar-vector-type + ``` + For example: + + ``` + %4 = spv.SMod %0, %1 : i32 + %5 = spv.SMod %2, %3 : vector<4xi32> + + ``` + }]; +} + +// ----- + +def SPV_SRemOp : SPV_ArithmeticOp<"SRem", SPV_Integer> { + let summary = [{ + Signed remainder operation for the remainder whose sign matches the sign + of Operand 1. + }]; + + let description = [{ + Result Type must be a scalar or vector of integer type. + + The type of Operand 1 and Operand 2 must be a scalar or vector of + integer type. They must have the same number of components as Result + Type. They must have the same component width as Result Type. + + Results are computed per component. The resulting value is undefined + if Operand 2 is 0. Otherwise, the result is the remainder r of Operand + 1 divided by Operand 2 where if r ≠ 0, the sign of r is the same as the + sign of Operand 1. + + ### Custom assembly form + ``` {.ebnf} + integer-scalar-vector-type ::= integer-type | + `vector<` integer-literal `x` integer-type `>` + srem-op ::= ssa-id `=` `spv.SRem` ssa-use, ssa-use + `:` integer-scalar-vector-type + ``` + For example: + + ``` + %4 = spv.SRem %0, %1 : i32 + %5 = spv.SRem %2, %3 : vector<4xi32> + + ``` + }]; +} + +// ----- + def SPV_StoreOp : SPV_Op<"Store", []> { let summary = "Store through a pointer."; @@ -665,6 +772,70 @@ def SPV_StoreOp : SPV_Op<"Store", []> { // ----- +def SPV_UDivOp : SPV_ArithmeticOp<"UDiv", SPV_Integer> { + let summary = "Unsigned-integer division of Operand 1 divided by Operand 2."; + + let description = [{ + Result Type must be a scalar or vector of integer type, whose Signedness + operand is 0. + + The types of Operand 1 and Operand 2 both must be the same as Result + Type. + + Results are computed per component. The resulting value is undefined + if Operand 2 is 0. + + ### Custom assembly form + ``` {.ebnf} + integer-scalar-vector-type ::= integer-type | + `vector<` integer-literal `x` integer-type `>` + udiv-op ::= ssa-id `=` `spv.UDiv` ssa-use, ssa-use + `:` integer-scalar-vector-type + ``` + For example: + + ``` + %4 = spv.UDiv %0, %1 : i32 + %5 = spv.UDiv %2, %3 : vector<4xi32> + + ``` + }]; +} + +// ----- + +def SPV_UModOp : SPV_ArithmeticOp<"UMod", SPV_Integer> { + let summary = "Unsigned modulo operation of Operand 1 modulo Operand 2."; + + let description = [{ + Result Type must be a scalar or vector of integer type, whose Signedness + operand is 0. + + The types of Operand 1 and Operand 2 both must be the same as Result + Type. + + Results are computed per component. The resulting value is undefined + if Operand 2 is 0. + + ### Custom assembly form + ``` {.ebnf} + integer-scalar-vector-type ::= integer-type | + `vector<` integer-literal `x` integer-type `>` + umod-op ::= ssa-id `=` `spv.UMod` ssa-use, ssa-use + `:` integer-scalar-vector-type + ``` + For example: + + ``` + %4 = spv.UMod %0, %1 : i32 + %5 = spv.UMod %2, %3 : vector<4xi32> + + ``` + }]; +} + +// ----- + def SPV_VariableOp : SPV_Op<"Variable", []> { let summary = [{ Allocate an object in memory, resulting in a pointer to it, which can be diff --git a/mlir/test/Dialect/SPIRV/Serialization/bin_ops.mlir b/mlir/test/Dialect/SPIRV/Serialization/bin_ops.mlir index e7d5ac6..4996fb8 100644 --- a/mlir/test/Dialect/SPIRV/Serialization/bin_ops.mlir +++ b/mlir/test/Dialect/SPIRV/Serialization/bin_ops.mlir @@ -47,6 +47,31 @@ func @spirv_bin_ops() -> () { %0 = spv.IMul %arg0, %arg1 : vector<4xi32> spv.Return } + func @udiv(%arg0 : vector<4xi32>, %arg1 : vector<4xi32>) { + // CHECK: {{%.*}} = spv.UDiv {{%.*}}, {{%.*}} : vector<4xi32> + %0 = spv.UDiv %arg0, %arg1 : vector<4xi32> + spv.Return + } + func @umod(%arg0 : vector<4xi32>, %arg1 : vector<4xi32>) { + // CHECK: {{%.*}} = spv.UMod {{%.*}}, {{%.*}} : vector<4xi32> + %0 = spv.UMod %arg0, %arg1 : vector<4xi32> + spv.Return + } + func @sdiv(%arg0 : vector<4xi32>, %arg1 : vector<4xi32>) { + // CHECK: {{%.*}} = spv.SDiv {{%.*}}, {{%.*}} : vector<4xi32> + %0 = spv.SDiv %arg0, %arg1 : vector<4xi32> + spv.Return + } + func @smod(%arg0 : vector<4xi32>, %arg1 : vector<4xi32>) { + // CHECK: {{%.*}} = spv.SMod {{%.*}}, {{%.*}} : vector<4xi32> + %0 = spv.SMod %arg0, %arg1 : vector<4xi32> + spv.Return + } + func @srem(%arg0 : vector<4xi32>, %arg1 : vector<4xi32>) { + // CHECK: {{%.*}} = spv.SRem {{%.*}}, {{%.*}} : vector<4xi32> + %0 = spv.SRem %arg0, %arg1 : vector<4xi32> + spv.Return + } } return } diff --git a/mlir/test/Dialect/SPIRV/ops.mlir b/mlir/test/Dialect/SPIRV/ops.mlir index ebc5b6c..8ced513 100644 --- a/mlir/test/Dialect/SPIRV/ops.mlir +++ b/mlir/test/Dialect/SPIRV/ops.mlir @@ -660,6 +660,66 @@ spv.module "Logical" "VulkanKHR" { // ----- //===----------------------------------------------------------------------===// +// spv.SDiv +//===----------------------------------------------------------------------===// + +func @sdiv_scalar(%arg: i32) -> i32 { + // CHECK: spv.SDiv + %0 = spv.SDiv %arg, %arg : i32 + return %0 : i32 +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.SMod +//===----------------------------------------------------------------------===// + +func @smod_scalar(%arg: i32) -> i32 { + // CHECK: spv.SMod + %0 = spv.SMod %arg, %arg : i32 + return %0 : i32 +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.SRem +//===----------------------------------------------------------------------===// + +func @srem_scalar(%arg: i32) -> i32 { + // CHECK: spv.SRem + %0 = spv.SRem %arg, %arg : i32 + return %0 : i32 +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.UDiv +//===----------------------------------------------------------------------===// + +func @udiv_scalar(%arg: i32) -> i32 { + // CHECK: spv.UDiv + %0 = spv.UDiv %arg, %arg : i32 + return %0 : i32 +} + +// ----- + +//===----------------------------------------------------------------------===// +// spv.UMod +//===----------------------------------------------------------------------===// + +func @umod_scalar(%arg: i32) -> i32 { + // CHECK: spv.UMod + %0 = spv.UMod %arg, %arg : i32 + return %0 : i32 +} + +// ----- + +//===----------------------------------------------------------------------===// // spv.StoreOp //===----------------------------------------------------------------------===// -- 2.7.4