Skip to content

Instantly share code, notes, and snippets.

@benvanik
Created January 2, 2020 14:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benvanik/13c76ca68191870a7c6bee5b139ffed6 to your computer and use it in GitHub Desktop.
Save benvanik/13c76ca68191870a7c6bee5b139ffed6 to your computer and use it in GitHub Desktop.
// Copyright 2019 Google LLC
//
// 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
//
// https://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.
#ifdef SIMD_OPS
#else
#define SIMD_OPS
#ifdef OP_BASE
#else
include "third_party/llvm/llvm/projects/google_mlir/include/mlir/IR/OpBase.td"
#endif // OP_BASE
//===----------------------------------------------------------------------===//
// Types used in the SIMD dialect
//===----------------------------------------------------------------------===//
class SIMD_ElementsAttrBase<Pred predicate, int lanes> : ElementsAttrBase<And<[
predicate,
CPred<"$_self.cast<ElementsAttr>().getType().isa<ShapedType>() && "
"$_self.cast<ElementsAttr>().getType().hasRank() && "
"$_self.cast<ElementsAttr>().getType().getShape() == "
"llvm::ArrayRef<int64_t>({" # lanes # "})">]>,
lanes # "-lane elements attribute"> {
int lanes = lanes;
}
class SIMD_IntElementsAttr<int width, int lanes> : SIMD_ElementsAttrBase<
CPred<"$_self.isa<DenseIntElementsAttr>() &&"
"$_self.cast<DenseIntElementsAttr>().getType().getElementType()."
"isInteger(" # width # ")">,
width # "-bit integer elements attribute", lanes> {
int bitWidth = width;
}
class SIMD_FloatElementsAttr<int width, int lanes> : SIMD_ElementsAttrBase<
CPred<"$_self.isa<DenseFPElementsAttr>() &&"
"$_self.cast<DenseFPElementsAttr>().getType().getElementType()."
"isF" # width # "()">,
width # "-bit floating-point elements attribute", lanes> {
int bitWidth = width;
}
def SIMD_I8x16ElementsAttr : SIMD_IntElementsAttr<8, 16>;
def SIMD_I16x8ElementsAttr : SIMD_IntElementsAttr<16, 8>;
def SIMD_I32x4ElementsAttr : SIMD_IntElementsAttr<32, 4>;
def SIMD_I64x2ElementsAttr : SIMD_IntElementsAttr<64, 2>;
def SIMD_F32x4ElementsAttr : SIMD_FloatElementsAttr<32, 4>;
def SIMD_F64x2ElementsAttr : SIMD_FloatElementsAttr<64, 2>;
class SIMD_ImmLaneIdxAttr<int lanes> : TypedAttrBase<
I8, "IntegerAttr", And<[
CPred<"$_self.isa<IntegerAttr>()">,
CPred<"$_self.cast<IntegerAttr>().getType().isInteger(8)">,
CPred<"$_self.cast<IntegerAttr>().getValue().ult(" # lanes # ")">],
"lane index in bounds for " # lanes # " lanes"> {
int lanes = lanes;
let returnType = [{ APInt }];
}
def SIMD_ImmLaneIdx2Attr : SIMD_ImmLaneIdxAttr<2>;
def SIMD_ImmLaneIdx4Attr : SIMD_ImmLaneIdxAttr<4>;
def SIMD_ImmLaneIdx8Attr : SIMD_ImmLaneIdxAttr<8>;
def SIMD_ImmLaneIdx16Attr : SIMD_ImmLaneIdxAttr<16>;
def SIMD_ImmLaneIdx32Attr : SIMD_ImmLaneIdxAttr<32>;
class SIMD_ImmLaneIdxElementsAttr<int lanes, int count> : TypedAttrBase<
I8, "IntegerAttr", And<[
CPred<"$_self.isa<DenseIntElementsAttr>()">,
CPred<"$_self.cast<DenseIntElementsAttr>().getType().getElementType().isInteger(8)">,
CPred<"$_self.cast<DenseIntElementsAttr>().getType().hasRank() && "
"$_self.cast<DenseIntElementsAttr>().getType().getShape() == "
"llvm::ArrayRef<int64_t>({" # count # "})">,
CPred<"$_self.cast<DenseIntElementsAttr>().getValue({0}).ult(" # lanes # ")">],
count # " lane indices in bounds for " # lanes # " lanes"> {
int lanes = lanes;
int count = count;
let returnType = [{ APInt }];
}
def SIMD_ImmLaneIdx32x16Attr : SIMD_ImmLaneIdxElementsAttr<32, 16>;
//===----------------------------------------------------------------------===//
// Top-level SIMD dialect and templates
//===----------------------------------------------------------------------===//
def SIMD_Dialect : Dialect {
let name = "simd";
let cppNamespace = "SIMD";
let description = [{
A SIMD dialect for MLIR modeling the WebAssembly SIMD proposal.
}];
}
class SIMD_Op<string mnemonic, list<OpTrait> traits = []> :
Op<SIMD_Op, mnemonic, traits> {
// DO NOT SUBMIT
}
// DO NOT SUBMIT PureOp with NoSideEffect on it
class SIMD_V128_UnaryOp<string mnemonic, list<OpTrait> traits = []> :
SIMD_Op<mnemonic, !listconcat(traits, [NoSideEffect])> {
let arguments = (ins SIMD_V128:$a);
let results = (outs SIMD_V128:$result);
}
class SIMD_V128_BinaryOp<string mnemonic, list<OpTrait> traits = []> :
SIMD_Op<mnemonic, !listconcat(traits, [NoSideEffect])> {
let arguments = (ins SIMD_V128:$a, SIMD_V128:$b);
let results = (outs SIMD_V128:$result);
}
class SIMD_V128_LanewiseUnaryOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_Op<mnemonic, !listconcat(traits, [NoSideEffect])> {
let elementType = elementType;
let lanes = lanes;
let arguments = (ins SIMD_V128:$a);
let results = (outs SIMD_V128:$result);
}
class SIMD_V128_LanewiseBinaryOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_Op<mnemonic, !listconcat(traits, [NoSideEffect])> {
let elementType = elementType;
let lanes = lanes;
let arguments = (ins SIMD_V128:$a, SIMD_V128:$b);
let results = (outs SIMD_V128:$result);
}
//===----------------------------------------------------------------------===//
// Constructing SIMD values
//===----------------------------------------------------------------------===//
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#constructing-simd-values
def SIMD_V128_ConstOp : SIMD_Op<"v128.const", [NoSideEffect]> {
let summary = [{
Materializes a constant v128 SIMD value from the 16 immediate bytes.
}];
let description = [{
Materializes a constant v128 SIMD value from the 16 immediate bytes in the
immediate mode operand `imm`. The v128.const instruction is encoded with 16
immediate bytes which provide the bits of the vector directly.
```
v128.const(imm: ImmByte[16]) -> v128
```
}];
// TODO(benvanik): figure out how to verify 16-byte sum.
let arguments = (ins ElementsAttr:$imm);
let results = (outs SIMD_V128:$result);
let builders = [OpBuilder<[{Builder *builder, OperationState &state,
ElementsAttr imm}]>];
let parser = [{ return parseConst(parser, result); }];
let printer = [{ printConst(p, *this); }];
}
class SIMD_V128_SplatOp<string mnemonic, Type attrType,
list<OpTrait> traits = []> :
SIMD_Op<mnemonic, !listconcat(traits, [NoSideEffect])> {
let summary = [{
Construct a vector with `x` replicated to all lanes.
}];
let description = [{
```
def S.splat(x):
result = S.New()
for i in range(S.Lanes):
result[i] = x
return result
```
}];
let arguments = (ins attrType:$x);
let results = (outs SIMD_V128:$result);
let parser = "return parseSplat<" # attrType # ">(parser, result);";
let printer = "printSplat<" # attrType # ">(p, *this);";
}
def SIMD_I8x16_SplatOp : SIMD_V128_SplatOp<"i8x16.splat", SIMD_I8x16ElementsAttr> {}
def SIMD_I16x8_SplatOp : SIMD_V128_SplatOp<"i16x8.splat", SIMD_I16x8ElementsAttr> {}
def SIMD_I32x4_SplatOp : SIMD_V128_SplatOp<"i32x4.splat", SIMD_I32x4ElementsAttr> {}
def SIMD_I64x2_SplatOp : SIMD_V128_SplatOp<"i64x2.splat", SIMD_I64x2ElementsAttr> {}
def SIMD_F32x4_SplatOp : SIMD_V128_SplatOp<"f32x4.splat", SIMD_F32x4ElementsAttr> {}
def SIMD_F64x2_SplatOp : SIMD_V128_SplatOp<"f64x2.splat", SIMD_F64x2ElementsAttr> {}
//===----------------------------------------------------------------------===//
// Accessing lanes
//===----------------------------------------------------------------------===//
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#accessing-lanes
class SIMD_V128_ExtractLaneOp<string mnemonic, Type immType, Type elementType,
list<OpTrait> traits = []> :
SIMD_Op<mnemonic, !listconcat(traits, [NoSideEffect])> {
let summary = [{
Extracts the scalar value of lane specified.
}];
let description = [{
Extract the scalar value of lane specified in the immediate mode operand
`imm` in `a`. The `{interpretation}.extract_lane` instructions are encoded
with one immediate byte providing the index of the lane to extract.
```
def S.extract_lane(a, imm):
return a[imm]
```
}];
let arguments = (ins SIMD_V128:$a, immType:$imm);
let results = (outs elementType:$result);
let parser = "return parseExtractLane<" # immType # ", " # elementType # ">(parser, result);";
let printer = "printExtractLane<" # immType # ", " # elementType # ">(p, *this);";
}
def SIMD_I8x16_ExtractLaneOp : SIMD_V128_ExtractLaneOp<"i8x16.extract_lane", SIMD_ImmLaneIdx16Attr, I8> {}
def SIMD_I16x8_ExtractLaneOp : SIMD_V128_ExtractLaneOp<"i16x8.extract_lane", SIMD_ImmLaneIdx8Attr, I16> {}
def SIMD_I32x4_ExtractLaneOp : SIMD_V128_ExtractLaneOp<"i32x4.extract_lane", SIMD_ImmLaneIdx4Attr, I32> {}
def SIMD_I64x2_ExtractLaneOp : SIMD_V128_ExtractLaneOp<"i64x2.extract_lane", SIMD_ImmLaneIdx2Attr, I64> {}
def SIMD_F32x4_ExtractLaneOp : SIMD_V128_ExtractLaneOp<"f32x4.extract_lane", SIMD_ImmLaneIdx4Attr, F32> {}
def SIMD_F64x2_ExtractLaneOp : SIMD_V128_ExtractLaneOp<"f64x2.extract_lane", SIMD_ImmLaneIdx2Attr, F64> {}
class SIMD_V128_ReplaceLaneOp<string mnemonic, Type immType, Type elementType,
list<OpTrait> traits = []> :
SIMD_Op<mnemonic, !listconcat(traits, [NoSideEffect])> {
let summary = [{
Replaces the value of lane `imm` within `a` with `x`.
}];
let description = [{
Return a new vector with lanes identical to `a`, except for the lane
specified in the immediate mode operand `imm` which has the value `x`. The
`{interpretation}.replace_lane` instructions are encoded with an immediate
byte providing the index of the lane the value of which is to be replaced.
```
def S.replace_lane(a, imm, x):
result = S.New()
for j in range(S.Lanes):
result[j] = a[j]
result[imm] = x
return result
```
The input lane value, `x`, is interpreted the same way as for the splat
instructions. For the i8 and i16 lanes, the high bits of `x` are ignored.
}];
let arguments = (ins SIMD_V128:$a, immType:$imm, elementType:$x);
let results = (outs SIMD_V128:$result);
let parser = "return parseReplaceLane<" # immType # ", " # elementType # ">(parser, result);";
let printer = "printReplaceLane<" # immType # ", " # elementType # ">(p, *this);";
}
def SIMD_I8x16_ReplaceLaneOp : SIMD_V128_ReplaceLaneOp<"i8x16.replace_lane", SIMD_ImmLaneIdx16Attr, I8> {}
def SIMD_I16x8_ReplaceLaneOp : SIMD_V128_ReplaceLaneOp<"i16x8.replace_lane", SIMD_ImmLaneIdx8Attr, I16> {}
def SIMD_I32x4_ReplaceLaneOp : SIMD_V128_ReplaceLaneOp<"i32x4.replace_lane", SIMD_ImmLaneIdx4Attr, I32> {}
def SIMD_I64x2_ReplaceLaneOp : SIMD_V128_ReplaceLaneOp<"i64x2.replace_lane", SIMD_ImmLaneIdx2Attr, I64> {}
def SIMD_F32x4_ReplaceLaneOp : SIMD_V128_ReplaceLaneOp<"f32x4.replace_lane", SIMD_ImmLaneIdx4Attr, F32> {}
def SIMD_F64x2_ReplaceLaneOp : SIMD_V128_ReplaceLaneOp<"f64x2.replace_lane", SIMD_ImmLaneIdx2Attr, F64> {}
class SIMD_V128_ShuffleOp<string mnemonic, Type immType, int lanes,
list<OpTrait> traits = []> :
SIMD_Op<mnemonic, !listconcat(traits, [NoSideEffect])> {
let summary = [{
Shuffles a using immediate indicies.
}];
let description = [{
Returns a new vector with lanes selected from the lanes of the two input
vectors `a` and `b` specified in the 16 byte wide immediate mode operand
`imm`. This instruction is encoded with 16 bytes providing the indices of
the elements to return. The indices `i` in range `[0, 15]` select the `i`-th
element of `a`. The indices in range `[16, 31]` select the `i - 16`-th
element of `b`.
```
def S.shuffle(a, b, s):
result = S.New()
for i in range(S.Lanes):
if s[i] < S.lanes:
result[i] = a[s[i]]
else:
result[i] = b[s[i] - S.lanes]
return result
```
}];
let lanes = lanes;
let arguments = (ins SIMD_V128:$a, SIMD_V128:$b, immType:$imm);
let results = (outs SIMD_V128:$result);
let parser = "return parseShuffle<" # immType # ", " # lanes # ">(parser, result);";
let printer = "printShuffle<" # immType # ", " # lanes # ">(p, *this);";
}
def SIMD_V8x16_ShuffleOp :
SIMD_V128_ShuffleOp<"v8x16.shuffle", SIMD_ImmLaneIdx32Attr, 16> {}
class SIMD_V128_SwizzleOp<string mnemonic, int lanes,
list<OpTrait> traits = []> :
SIMD_Op<mnemonic, !listconcat(traits, [NoSideEffect])> {
let summary = [{
Shuffles a using variable indicies.
}];
let description = [{
Returns a new vector with lanes selected from the lanes of the first input
vector `a` specified in the second input vector `s`. The indices `i` in
range `[0, 15]` select the `i`-th element of `a`. For indices outside of the
range the resulting lane is 0.
```
def S.swizzle(a, s):
result = S.New()
for i in range(S.Lanes):
if s[i] < S.lanes:
result[i] = a[s[i]]
else:
result[i] = 0
return result
```
}];
let lanes = lanes;
let arguments = (ins SIMD_V128:$a, SIMD_V128:$s);
let results = (outs SIMD_V128:$result);
let parser = "return parseSwizzle<" # lanes # ">(parser, result);";
let printer = "parseSwizzle<" # lanes # ">(p, *this);";
}
def SIMD_V8x16_SwizzleOp : SIMD_V128_SwizzleOp<"v8x16.swizzle", 16> {}
//===----------------------------------------------------------------------===//
// Integer arithmetic
//===----------------------------------------------------------------------===//
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#integer-arithmetic
//
// Wrapping integer arithmetic discards the high bits of the result.
//
// ```
// def S.Reduce(x):
// bitmask = (1 << S.LaneBits) - 1
// return x & bitmask
// ```
//
// There is no integer division operation provided here. This operation is not
// commonly part of bit 128-bit SIMD ISAs.
class SIMD_V128_AddOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_V128_LanewiseBinaryOp<mnemonic, elementType, lanes, traits> {
let summary = [{
Lane-wise wrapping integer addition.
}];
let description = [{
```
def S.add(a, b):
def add(x, y):
return S.Reduce(x + y)
return S.lanewise_binary(add, a, b)
```
}];
let arguments = (ins SIMD_V128:$a, SIMD_V128:$b);
let results = (outs SIMD_V128:$result);
let parser = "return parseAdd<" # elementType # ", " # lanes # ">(parser, result);";
let printer = "parseAdd<" # elementType # ", " # lanes # ">(p, *this);";
}
def SIMD_I8x16_AddOp : SIMD_V128_AddOp<"i8x16.add", I8, 16> {}
def SIMD_I16x8_AddOp : SIMD_V128_AddOp<"i16x8.add", I16, 8> {}
def SIMD_I32x4_AddOp : SIMD_V128_AddOp<"i32x4.add", I32, 4> {}
def SIMD_I64x2_AddOp : SIMD_V128_AddOp<"i64x2.add", I64, 2> {}
class SIMD_V128_SubOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_V128_LanewiseBinaryOp<mnemonic, elementType, lanes, traits> {
let summary = [{
Lane-wise wrapping integer subtraction.
}];
let description = [{
```
def S.sub(a, b):
def sub(x, y):
return S.Reduce(x - y)
return S.lanewise_binary(sub, a, b)
```
}];
let arguments = (ins SIMD_V128:$a, SIMD_V128:$b);
let results = (outs SIMD_V128:$result);
let parser = "return parseSub<" # elementType # ", " # lanes # ">(parser, result);";
let printer = "parseSub<" # elementType # ", " # lanes # ">(p, *this);";
}
def SIMD_I8x16_SubOp : SIMD_V128_SubOp<"i8x16.sub", I8, 16> {}
def SIMD_I16x8_SubOp : SIMD_V128_SubOp<"i16x8.sub", I16, 8> {}
def SIMD_I32x4_SubOp : SIMD_V128_SubOp<"i32x4.sub", I32, 4> {}
def SIMD_I64x2_SubOp : SIMD_V128_SubOp<"i64x2.sub", I64, 2> {}
class SIMD_V128_MulOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_V128_LanewiseBinaryOp<mnemonic, elementType, lanes, traits> {
let summary = [{
Lane-wise wrapping integer multiplication.
}];
let description = [{
```
def S.mul(a, b):
def mul(x, y):
return S.Reduce(x * y)
return S.lanewise_binary(mul, a, b)
```
}];
let arguments = (ins SIMD_V128:$a, SIMD_V128:$b);
let results = (outs SIMD_V128:$result);
let parser = "return parseMul<" # elementType # ", " # lanes # ">(parser, result);";
let printer = "parseMul<" # elementType # ", " # lanes # ">(p, *this);";
}
def SIMD_I16x8_MulOp : SIMD_V128_MulOp<"i16x8.mul", I16, 8> {}
def SIMD_I32x4_MulOp : SIMD_V128_MulOp<"i32x4.mul", I32, 4> {}
def SIMD_I64x2_MulOp : SIMD_V128_MulOp<"i64x2.mul", I64, 2> {}
class SIMD_V128_NegOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_V128_LanewiseUnaryOp<mnemonic, elementType, lanes, traits> {
let summary = [{
Lane-wise wrapping integer negation.
}];
let description = [{
In wrapping arithmetic, `y = -x` is the unique value such that `x + y == 0`.
```
def S.neg(a):
def neg(x):
return S.Reduce(-x)
return S.lanewise_unary(neg, a)
```
}];
let arguments = (ins SIMD_V128:$a);
let results = (outs SIMD_V128:$result);
let parser = "return parseNeg<" # elementType # ", " # lanes # ">(parser, result);";
let printer = "parseNeg<" # elementType # ", " # lanes # ">(p, *this);";
}
def SIMD_I8x16_NegOp : SIMD_V128_NegOp<"i8x16.neg", I8, 16> {}
def SIMD_I16x8_NegOp : SIMD_V128_NegOp<"i16x8.neg", I16, 8> {}
def SIMD_I32x4_NegOp : SIMD_V128_NegOp<"i32x4.neg", I32, 4> {}
def SIMD_I64x2_NegOp : SIMD_V128_NegOp<"i64x2.neg", I64, 2> {}
//===----------------------------------------------------------------------===//
// Saturating integer arithmetic
//===----------------------------------------------------------------------===//
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#saturating-integer-arithmetic
//
// Saturating integer arithmetic behaves differently on signed and unsigned
// lanes. It is only defined here for 8-bit and 16-bit integer lanes.
//
// ```
// def S.SignedSaturate(x):
// if x < S.Smin:
// return S.Smin
// if x > S.Smax:
// return S.Smax
// return x
//
// def S.UnsignedSaturate(x):
// if x < 0:
// return 0
// if x > S.Umax:
// return S.Umax
// return x
// ```
class SIMD_V128_AddSaturateSOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_V128_LanewiseBinaryOp<mnemonic, elementType, lanes, traits> {
let summary = [{
Lane-wise wrapping integer addition.
}];
let description = [{
```
def S.add_saturate_s(a, b):
def addsat(x, y):
return S.SignedSaturate(x + y)
return S.lanewise_binary(addsat, S.AsSigned(a), S.AsSigned(b))
```
}];
let arguments = (ins SIMD_V128:$a, SIMD_V128:$b);
let results = (outs SIMD_V128:$result);
let parser = "return parseAddSaturate<true, " # elementType # ", " # lanes # ">(parser, result);";
let printer = "parseAddSaturate<true, " # elementType # ", " # lanes # ">(p, *this);";
}
def SIMD_I8x16_AddSaturateUOp : SIMD_V128_AddSaturateUOp<"i8x16.add_saturate_u", I8, 16> {}
def SIMD_I16x8_AddSaturateUOp : SIMD_V128_AddSaturateUOp<"i16x8.add_saturate_u", I16, 8> {}
class SIMD_V128_AddSaturateUOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_V128_LanewiseBinaryOp<mnemonic, elementType, lanes, traits> {
let summary = [{
Lane-wise wrapping integer addition.
}];
let description = [{
```
def S.add_saturate_u(a, b):
def addsat(x, y):
return S.UnsignedSaturate(x + y)
return S.lanewise_binary(addsat, S.AsUnsigned(a), S.AsUnsigned(b))
```
}];
let arguments = (ins SIMD_V128:$a, SIMD_V128:$b);
let results = (outs SIMD_V128:$result);
let parser = "return parseAddSaturate<false, " # elementType # ", " # lanes # ">(parser, result);";
let printer = "parseAddSaturate<false, " # elementType # ", " # lanes # ">(p, *this);";
}
def SIMD_I8x16_AddSaturateUOp : SIMD_V128_AddSaturateUOp<"i8x16.add_saturate_u", I8, 16> {}
def SIMD_I16x8_AddSaturateUOp : SIMD_V128_AddSaturateUOp<"i16x8.add_saturate_u", I16, 8> {}
class SIMD_V128_SubSaturateSOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_V128_LanewiseBinaryOp<mnemonic, elementType, lanes, traits> {
let summary = [{
Lane-wise wrapping integer addition.
}];
let description = [{
```
def S.sub_saturate_s(a, b):
def subsat(x, y):
return S.SignedSaturate(x - y)
return S.lanewise_binary(subsat, S.AsSigned(a), S.AsSigned(b))
```
}];
let arguments = (ins SIMD_V128:$a, SIMD_V128:$b);
let results = (outs SIMD_V128:$result);
let parser = "return parseSubSaturate<true, " # elementType # ", " # lanes # ">(parser, result);";
let printer = "parseSubSaturate<true, " # elementType # ", " # lanes # ">(p, *this);";
}
def SIMD_I8x16_SubSaturateUOp : SIMD_V128_SubSaturateUOp<"i8x16.sub_saturate_u", I8, 16> {}
def SIMD_I16x8_SubSaturateUOp : SIMD_V128_SubSaturateUOp<"i16x8.sub_saturate_u", I16, 8> {}
class SIMD_V128_SubSaturateUOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_V128_LanewiseBinaryOp<mnemonic, elementType, lanes, traits> {
let summary = [{
Lane-wise wrapping integer addition.
}];
let description = [{
```
def S.sub_saturate_u(a, b):
def subsat(x, y):
return S.UnsignedSaturate(x - y)
return S.lanewise_binary(subsat, S.AsUnsigned(a), S.AsUnsigned(b))
```
}];
let arguments = (ins SIMD_V128:$a, SIMD_V128:$b);
let results = (outs SIMD_V128:$result);
let parser = "return parseSubSaturate<false, " # elementType # ", " # lanes # ">(parser, result);";
let printer = "parseSubSaturate<false, " # elementType # ", " # lanes # ">(p, *this);";
}
def SIMD_I8x16_SubSaturateUOp : SIMD_V128_SubSaturateUOp<"i8x16.sub_saturate_u", I8, 16> {}
def SIMD_I16x8_SubSaturateUOp : SIMD_V128_SubSaturateUOp<"i16x8.sub_saturate_u", I16, 8> {}
//===----------------------------------------------------------------------===//
// Bit shifts
//===----------------------------------------------------------------------===//
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#bit-shifts
class SIMD_V128_ShlOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_Op<mnemonic, !listconcat(traits, [NoSideEffect])> {
let elementType = elementType;
let lanes = lanes;
let summary = [{
Lane-wise bit shift.
}];
let description = [{
Shift the bits in each lane to the left by the same amount. The shift count
is taken modulo lane width:
```
def S.shl(a, y):
# Number of bits to shift: 0 .. S.LaneBits - 1.
amount = y mod S.LaneBits
def shift(x):
return S.Reduce(x << amount)
return S.lanewise_unary(shift, a)
```
}];
let arguments = (ins SIMD_V128:$a, I32Attr:$y);
let results = (outs SIMD_V128:$result);
let parser = "return parseShl<" # elementType # ", " # lanes # ">(parser, result);";
let printer = "parseShl<" # elementType # ", " # lanes # ">(p, *this);";
}
def SIMD_I8x16_ShlOp : SIMD_V128_ShlOp<"i8x16.shl", I8, 16> {}
def SIMD_I16x8_ShlOp : SIMD_V128_ShlOp<"i16x8.shl", I16, 8> {}
def SIMD_I32x4_ShlOp : SIMD_V128_ShlOp<"i32x4.shl", I32, 4> {}
def SIMD_I64x2_ShlOp : SIMD_V128_ShlOp<"i64x2.shl", I64, 2> {}
class SIMD_V128_ShrSOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_Op<mnemonic, !listconcat(traits, [NoSideEffect])> {
let elementType = elementType;
let lanes = lanes;
let summary = [{
Lane-wise arithmetic right bit shift.
}];
let description = [{
Shift the bits in each lane to the right by the same amount. The shift count
is taken modulo lane width. This is an arithmetic right shift.
```
def S.shr_s(a, y):
# Number of bits to shift: 0 .. S.LaneBits - 1.
amount = y mod S.LaneBits
def shift(x):
return x >> amount
return S.lanewise_unary(shift, S.AsSigned(a))
```
}];
let arguments = (ins SIMD_V128:$a, I32Attr:$y);
let results = (outs SIMD_V128:$result);
let parser = "return parseShr<true, " # elementType # ", " # lanes # ">(parser, result);";
let printer = "parseShr<true, " # elementType # ", " # lanes # ">(p, *this);";
}
def SIMD_I8x16_ShrSOp : SIMD_V128_ShrSOp<"i8x16.shr_s", I8, 16> {}
def SIMD_I16x8_ShrSOp : SIMD_V128_ShrSOp<"i16x8.shr_s", I16, 8> {}
def SIMD_I32x4_ShrSOp : SIMD_V128_ShrSOp<"i32x4.shr_s", I32, 4> {}
def SIMD_I64x2_ShrSOp : SIMD_V128_ShrSOp<"i64x2.shr_s", I64, 2> {}
class SIMD_V128_ShrUOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_Op<mnemonic, !listconcat(traits, [NoSideEffect])> {
let elementType = elementType;
let lanes = lanes;
let summary = [{
Lane-wise logical right bit shift.
}];
let description = [{
Shift the bits in each lane to the right by the same amount. The shift count
is taken modulo lane width. This is a logical right shift.
```
def S.shr_u(a, y):
# Number of bits to shift: 0 .. S.LaneBits - 1.
amount = y mod S.LaneBits
def shift(x):
return x >> amount
return S.lanewise_unary(shift, S.AsUnsigned(a))
```
}];
let arguments = (ins SIMD_V128:$a, I32Attr:$y);
let results = (outs SIMD_V128:$result);
let parser = "return parseShr<false, " # elementType # ", " # lanes # ">(parser, result);";
let printer = "parseShr<false, " # elementType # ", " # lanes # ">(p, *this);";
}
def SIMD_I8x16_ShrUOp : SIMD_V128_ShrUOp<"i8x16.shr_u", I8, 16> {}
def SIMD_I16x8_ShrUOp : SIMD_V128_ShrUOp<"i16x8.shr_u", I16, 8> {}
def SIMD_I32x4_ShrUOp : SIMD_V128_ShrUOp<"i32x4.shr_u", I32, 4> {}
def SIMD_I64x2_ShrUOp : SIMD_V128_ShrUOp<"i64x2.shr_u", I64, 2> {}
//===----------------------------------------------------------------------===//
// Bitwise operations
//===----------------------------------------------------------------------===//
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#bitwise-operations
def SIMD_V128_AndOp : SIMD_V128_BinaryOp<"v128.and"> {
let summary = [{
Bit-wise AND of bits.
}];
let description = [{
Acts like C's `&` operator on an unsigned type.
}];
let parser = "return parseAnd(parser, result);";
let printer = "parseAnd(p, *this);";
}
def SIMD_V128_OrOp : SIMD_V128_BinaryOp<"v128.or"> {
let summary = [{
Bit-wise OR of bits.
}];
let description = [{
Acts like C's `|` operator on an unsigned type.
}];
let parser = "return parseOr(parser, result);";
let printer = "parseOr(p, *this);";
}
def SIMD_V128_XorOp : SIMD_V128_BinaryOp<"v128.xor"> {
let summary = [{
Bit-wise XOR of bits.
}];
let description = [{
Acts like C's `^` operator on an unsigned type.
}];
let parser = "return parseXor(parser, result);";
let printer = "parseXor(p, *this);";
}
def SIMD_V128_NotOp : SIMD_V128_UnaryOp<"v128.not"> {
let summary = [{
Bit-wise NOT of bits.
}];
let description = [{
Acts like C's `~` operator on an unsigned type.
}];
let parser = "return parseNot(parser, result);";
let printer = "parseNot(p, *this);";
}
def SIMD_V128_AndNotOp : SIMD_V128_BinaryOp<"v128.andnot"> {
let summary = [{
Bit-wise AND of bits and the logical inverse of the operand.
}];
let description = [{
Bitwise AND of bits of `a` and the logical inverse of bits of `b`. This
operation is equivalent to `v128.and(a, v128.not(b))`.
}];
let parser = "return parseAndNot(parser, result);";
let printer = "parseAndNot(p, *this);";
}
def SIMD_V128_BitSelectOp : SIMD_Op<"v128.bitselect", [NoSideEffect]> {
let summary = [{
Bit-wise select based on control bits.
}];
let description = [{
Use the bits in the control mask `c` to select the corresponding bit from
`v1` when 1 and `v2` when 0. This is the same as
`v128.or(v128.and(v1, c), v128.and(v2, v128.not(c)))`.
}];
let arguments = (ins SIMD_V128:$v1, SIMD_V128:$v2, SIMD_V128:$c);
let results = (outs SIMD_V128:$result);
let parser = "return parseBitSelect(parser, result);";
let printer = "parseBitSelect(p, *this);";
}
//===----------------------------------------------------------------------===//
// Boolean horizontal reductions
//===----------------------------------------------------------------------===//
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#boolean-horizontal-reductions
class SIMD_V128_AnyTrueOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_UnaryOp<mnemonic, !listconcat(traits, [NoSideEffect])> {
let elementType = elementType;
let lanes = lanes;
let summary = [{
Reduces all lanes to a single scalar of 0 or 1.
}];
let description = [{
Return 1 if any lane in `a` is non-zero, 0 otherwise.
```
def S.any_true(a):
for i in range(S.Lanes):
if a[i] != 0:
return 1
return 0
```
}];
let parser = "return parseAnyTrue<" # elementType # ", " # lanes # ">(parser, result);";
let printer = "parseAnyTrue<" # elementType # ", " # lanes # ">(p, *this);";
}
def SIMD_I8x16_AnyTrueOp : SIMD_V128_AnyTrueOp<"i8x16.any_true", I8, 16> {}
def SIMD_I16x8_AnyTrueOp : SIMD_V128_AnyTrueOp<"i16x8.any_true", I16, 8> {}
def SIMD_I32x4_AnyTrueOp : SIMD_V128_AnyTrueOp<"i32x4.any_true", I32, 4> {}
class SIMD_V128_AllTrueOp<string mnemonic, Type elementType, int lanes,
list<OpTrait> traits = []> :
SIMD_UnaryOp<mnemonic, !listconcat(traits, [NoSideEffect])> {
let elementType = elementType;
let lanes = lanes;
let summary = [{
Reduces all lanes to a single scalar of 0 or 1.
}];
let description = [{
Return 1 if all lanes in `a` is non-zero, 0 otherwise.
```
def S.any_true(a):
for i in range(S.Lanes):
if a[i] == 0:
return 0
return 1
```
}];
let parser = "return parseAllTrue<" # elementType # ", " # lanes # ">(parser, result);";
let printer = "parseAllTrue<" # elementType # ", " # lanes # ">(p, *this);";
}
def SIMD_I8x16_AllTrueOp : SIMD_V128_AllTrueOp<"i8x16.all_true", I8, 16> {}
def SIMD_I16x8_AllTrueOp : SIMD_V128_AllTrueOp<"i16x8.all_true", I16, 8> {}
def SIMD_I32x4_AllTrueOp : SIMD_V128_AllTrueOp<"i32x4.all_true", I32, 4> {}
//===----------------------------------------------------------------------===//
// Comparisons
//===----------------------------------------------------------------------===//
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#comparisons
// DO NOT SUBMIT
//===----------------------------------------------------------------------===//
// Load and store
//===----------------------------------------------------------------------===//
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#load-and-store
// DO NOT SUBMIT
//===----------------------------------------------------------------------===//
// Floating-point sign bit operations
//===----------------------------------------------------------------------===//
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#floating-point-sign-bit-operations
// DO NOT SUBMIT
//===----------------------------------------------------------------------===//
// Floating-point min and max
//===----------------------------------------------------------------------===//
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#floating-point-min-and-max
// DO NOT SUBMIT
//===----------------------------------------------------------------------===//
// Floating-point arithmetic
//===----------------------------------------------------------------------===//
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#floating-point-arithmetic
// DO NOT SUBMIT
//===----------------------------------------------------------------------===//
// Conversions
//===----------------------------------------------------------------------===//
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#conversions
// DO NOT SUBMIT
#endif // SIMD_OPS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment