Add support for OpBitwiseOr, OpBitwiseXor, and OpBitwiseAnd in SPIR-V dialect.

PiperOrigin-RevId: 274935374
This commit is contained in:
Hanhan Wang 2019-10-15 18:42:10 -07:00 committed by A. Unique TensorFlower
parent 2fc29f1eab
commit 950979745a
4 changed files with 226 additions and 0 deletions

View File

@ -161,6 +161,9 @@ 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_OpBitwiseOr : I32EnumAttrCase<"OpBitwiseOr", 197>;
def SPV_OC_OpBitwiseXor : I32EnumAttrCase<"OpBitwiseXor", 198>;
def SPV_OC_OpBitwiseAnd : I32EnumAttrCase<"OpBitwiseAnd", 199>;
def SPV_OC_OpControlBarrier : I32EnumAttrCase<"OpControlBarrier", 224>;
def SPV_OC_OpMemoryBarrier : I32EnumAttrCase<"OpMemoryBarrier", 225>;
def SPV_OC_OpLoopMerge : I32EnumAttrCase<"OpLoopMerge", 246>;
@ -201,6 +204,7 @@ def SPV_OpcodeAttr :
SPV_OC_OpFOrdGreaterThan, SPV_OC_OpFUnordGreaterThan,
SPV_OC_OpFOrdLessThanEqual, SPV_OC_OpFUnordLessThanEqual,
SPV_OC_OpFOrdGreaterThanEqual, SPV_OC_OpFUnordGreaterThanEqual,
SPV_OC_OpBitwiseOr, SPV_OC_OpBitwiseXor, SPV_OC_OpBitwiseAnd,
SPV_OC_OpControlBarrier, SPV_OC_OpMemoryBarrier, SPV_OC_OpLoopMerge,
SPV_OC_OpSelectionMerge, SPV_OC_OpLabel, SPV_OC_OpBranch,
SPV_OC_OpBranchConditional, SPV_OC_OpReturn, SPV_OC_OpReturnValue,

View File

@ -0,0 +1,140 @@
//===-- SPIRVBitOps.td - MLIR SPIR-V Bit Ops -*- tablegen -*-===//
//
// Copyright 2019 The MLIR Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
//
// This file contains bit ops for the SPIR-V dialect. It corresponds
// to "3.32.13. Bit Instructions" of the SPIR-V specification.
//
//===----------------------------------------------------------------------===//
#ifdef SPIRV_BIT_OPS
#else
#define SPIRV_BIT_OPS
#ifdef SPIRV_BASE
#else
include "mlir/SPIRV/SPIRVBase.td"
#endif // SPIRV_BASE
class SPV_BitBinaryOp<string mnemonic, list<OpTrait> traits = []> :
// All the operands type used in bit instructions are SPV_Integer.
SPV_BinaryOp<mnemonic, SPV_Integer, SPV_Integer,
!listconcat(traits,
[NoSideEffect, SameOperandsAndResultType])>;
// -----
def SPV_BitwiseOrOp : SPV_BitBinaryOp<"BitwiseOr", [Commutative]> {
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.
}];
let description = [{
Results are computed per component, and within each component, per bit.
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.
### Custom assembly form
``` {.ebnf}
integer-scalar-vector-type ::= integer-type |
`vector<` integer-literal `x` integer-type `>`
bitwise-or-op ::= ssa-id `=` `spv.BitwiseOr` ssa-use, ssa-use
`:` integer-scalar-vector-type
```
For example:
```
%2 = spv.BitwiseOr %0, %1 : i32
%2 = spv.BitwiseOr %0, %1 : vector<4xi32>
```
}];
}
// -----
def SPV_BitwiseXorOp : SPV_BitBinaryOp<"BitwiseXor", [Commutative]> {
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.
}];
let description = [{
Results are computed per component, and within each component, per bit.
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.
### Custom assembly form
``` {.ebnf}
integer-scalar-vector-type ::= integer-type |
`vector<` integer-literal `x` integer-type `>`
bitwise-xor-op ::= ssa-id `=` `spv.BitwiseXor` ssa-use, ssa-use
`:` integer-scalar-vector-type
```
For example:
```
%2 = spv.BitwiseXor %0, %1 : i32
%2 = spv.BitwiseXor %0, %1 : vector<4xi32>
```
}];
}
// -----
def SPV_BitwiseAndOp : SPV_BitBinaryOp<"BitwiseAnd", [Commutative]> {
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.
}];
let description = [{
Results are computed per component, and within each component, per bit.
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.
### Custom assembly form
``` {.ebnf}
integer-scalar-vector-type ::= integer-type |
`vector<` integer-literal `x` integer-type `>`
bitwise-and-op ::= ssa-id `=` `spv.BitwiseAnd` ssa-use, ssa-use
`:` integer-scalar-vector-type
```
For example:
```
%2 = spv.BitwiseAnd %0, %1 : i32
%2 = spv.BitwiseAnd %0, %1 : vector<4xi32>
```
}];
}
#endif // SPIRV_BIT_OPS

View File

@ -40,6 +40,11 @@ include "mlir/Dialect/SPIRV/SPIRVBase.td"
include "mlir/Dialect/SPIRV/SPIRVArithmeticOps.td"
#endif // SPIRV_ARITHMETIC_OPS
#ifdef SPIRV_BIT_OPS
#else
include "mlir/Dialect/SPIRV/SPIRVBitOps.td"
#endif // SPIRV_BIT_OPS
#ifdef SPIRV_CONTROLFLOW_OPS
#else
include "mlir/Dialect/SPIRV/SPIRVControlFlowOps.td"

View File

@ -0,0 +1,77 @@
// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s
//===----------------------------------------------------------------------===//
// spv.BitwiseOr
//===----------------------------------------------------------------------===//
func @bitwise_or_scalar(%arg: i32) -> i32 {
// CHECK: spv.BitwiseOr
%0 = spv.BitwiseOr %arg, %arg : i32
return %0 : i32
}
func @bitwise_or_vector(%arg: vector<4xi32>) -> vector<4xi32> {
// CHECK: spv.BitwiseOr
%0 = spv.BitwiseOr %arg, %arg : vector<4xi32>
return %0 : vector<4xi32>
}
// -----
func @bitwise_or_float(%arg0: f16, %arg1: f16) -> f16 {
// expected-error @+1 {{operand #0 must be 8/16/32/64-bit integer or vector of 8/16/32/64-bit integer values of length 2/3/4}}
%0 = spv.BitwiseOr %arg0, %arg1 : f16
return %0 : f16
}
// -----
//===----------------------------------------------------------------------===//
// spv.BitwiseXor
//===----------------------------------------------------------------------===//
func @bitwise_xor_scalar(%arg: i32) -> i32 {
// CHECK: spv.BitwiseXor
%0 = spv.BitwiseXor %arg, %arg : i32
return %0 : i32
}
func @bitwise_xor_vector(%arg: vector<4xi32>) -> vector<4xi32> {
// CHECK: spv.BitwiseXor
%0 = spv.BitwiseXor %arg, %arg : vector<4xi32>
return %0 : vector<4xi32>
}
// -----
func @bitwise_xor_float(%arg0: f16, %arg1: f16) -> f16 {
// expected-error @+1 {{operand #0 must be 8/16/32/64-bit integer or vector of 8/16/32/64-bit integer values of length 2/3/4}}
%0 = spv.BitwiseXor %arg0, %arg1 : f16
return %0 : f16
}
// -----
//===----------------------------------------------------------------------===//
// spv.BitwiseAnd
//===----------------------------------------------------------------------===//
func @bitwise_and_scalar(%arg: i32) -> i32 {
// CHECK: spv.BitwiseAnd
%0 = spv.BitwiseAnd %arg, %arg : i32
return %0 : i32
}
func @bitwise_and_vector(%arg: vector<4xi32>) -> vector<4xi32> {
// CHECK: spv.BitwiseAnd
%0 = spv.BitwiseAnd %arg, %arg : vector<4xi32>
return %0 : vector<4xi32>
}
// -----
func @bitwise_and_float(%arg0: f16, %arg1: f16) -> f16 {
// expected-error @+1 {{operand #0 must be 8/16/32/64-bit integer or vector of 8/16/32/64-bit integer values of length 2/3/4}}
%0 = spv.BitwiseAnd %arg0, %arg1 : f16
return %0 : f16
}