Commit a07019a2 authored by Thomas Lively's avatar Thomas Lively
Browse files

[WebAssembly] SIMD integer min and max instructions

Summary:
Introduces a clang builtins and LLVM intrinsics representing integer
min/max instructions. These instructions have not been merged to the
SIMD spec proposal yet, so they are currently opt-in only via builtins
and not produced by general pattern matching. If these instructions
are accepted into the spec proposal the builtins and intrinsics will
be replaced with normal pattern matching.

Defined in https://github.com/WebAssembly/simd/pull/27.

Reviewers: aheejin

Reviewed By: aheejin

Subscribers: dschuff, sbc100, jgravelle-google, hiraditya, sunfish, cfe-commits, llvm-commits

Tags: #clang, #llvm

Differential Revision: https://reviews.llvm.org/D69696
parent 10c1d0a4
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -98,6 +98,21 @@ TARGET_BUILTIN(__builtin_wasm_sub_saturate_u_i8x16, "V16cV16cV16c", "nc", "simd1
TARGET_BUILTIN(__builtin_wasm_sub_saturate_s_i16x8, "V8sV8sV8s", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_sub_saturate_u_i16x8, "V8sV8sV8s", "nc", "simd128")

// TODO: Remove builtins and rely on codegen patterns once these are officially
// merged to the spec proposal
TARGET_BUILTIN(__builtin_wasm_min_s_i8x16, "V16cV16cV16c", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_min_u_i8x16, "V16cV16cV16c", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_max_s_i8x16, "V16cV16cV16c", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_max_u_i8x16, "V16cV16cV16c", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_min_s_i16x8, "V8sV8sV8s", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_min_u_i16x8, "V8sV8sV8s", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_max_s_i16x8, "V8sV8sV8s", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_max_u_i16x8, "V8sV8sV8s", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_min_s_i32x4, "V4iV4iV4i", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_min_u_i32x4, "V4iV4iV4i", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_max_s_i32x4, "V4iV4iV4i", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_max_u_i32x4, "V4iV4iV4i", "nc", "simd128")

TARGET_BUILTIN(__builtin_wasm_bitselect, "V4iV4iV4iV4i", "nc", "simd128")

TARGET_BUILTIN(__builtin_wasm_any_true_i8x16, "iV16c", "nc", "simd128")
+42 −0
Original line number Diff line number Diff line
@@ -14318,6 +14318,48 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
                                     ConvertType(E->getType()));
    return Builder.CreateCall(Callee, {V1, V2, C});
  }
  case WebAssembly::BI__builtin_wasm_min_s_i8x16:
  case WebAssembly::BI__builtin_wasm_min_u_i8x16:
  case WebAssembly::BI__builtin_wasm_max_s_i8x16:
  case WebAssembly::BI__builtin_wasm_max_u_i8x16:
  case WebAssembly::BI__builtin_wasm_min_s_i16x8:
  case WebAssembly::BI__builtin_wasm_min_u_i16x8:
  case WebAssembly::BI__builtin_wasm_max_s_i16x8:
  case WebAssembly::BI__builtin_wasm_max_u_i16x8:
  case WebAssembly::BI__builtin_wasm_min_s_i32x4:
  case WebAssembly::BI__builtin_wasm_min_u_i32x4:
  case WebAssembly::BI__builtin_wasm_max_s_i32x4:
  case WebAssembly::BI__builtin_wasm_max_u_i32x4: {
    unsigned IntNo;
    switch (BuiltinID) {
    case WebAssembly::BI__builtin_wasm_min_s_i8x16:
    case WebAssembly::BI__builtin_wasm_min_s_i16x8:
    case WebAssembly::BI__builtin_wasm_min_s_i32x4:
      IntNo = Intrinsic::wasm_min_signed;
      break;
    case WebAssembly::BI__builtin_wasm_min_u_i8x16:
    case WebAssembly::BI__builtin_wasm_min_u_i16x8:
    case WebAssembly::BI__builtin_wasm_min_u_i32x4:
      IntNo = Intrinsic::wasm_min_unsigned;
      break;
    case WebAssembly::BI__builtin_wasm_max_s_i8x16:
    case WebAssembly::BI__builtin_wasm_max_s_i16x8:
    case WebAssembly::BI__builtin_wasm_max_s_i32x4:
      IntNo = Intrinsic::wasm_max_signed;
      break;
    case WebAssembly::BI__builtin_wasm_max_u_i8x16:
    case WebAssembly::BI__builtin_wasm_max_u_i16x8:
    case WebAssembly::BI__builtin_wasm_max_u_i32x4:
      IntNo = Intrinsic::wasm_max_unsigned;
      break;
    default:
      llvm_unreachable("unexpected builtin ID");
    }
    Value *LHS = EmitScalarExpr(E->getArg(0));
    Value *RHS = EmitScalarExpr(E->getArg(1));
    Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType()));
    return Builder.CreateCall(Callee, {LHS, RHS});
  }
  case WebAssembly::BI__builtin_wasm_any_true_i8x16:
  case WebAssembly::BI__builtin_wasm_any_true_i16x8:
  case WebAssembly::BI__builtin_wasm_any_true_i32x4:
+84 −0
Original line number Diff line number Diff line
@@ -352,6 +352,90 @@ i16x8 sub_saturate_u_i16x8(i16x8 x, i16x8 y) {
  // WEBASSEMBLY-NEXT: ret
}

i8x16 min_s_i8x16(i8x16 x, i8x16 y) {
  return __builtin_wasm_min_s_i8x16(x, y);
  // WEBASSEMBLY: call <16 x i8> @llvm.wasm.min.signed.v16i8(
  // WEBASSEMBLY-SAME: <16 x i8> %x, <16 x i8> %y)
  // WEBASSEMBLY-NEXT: ret
}

i8x16 min_u_i8x16(i8x16 x, i8x16 y) {
  return __builtin_wasm_min_u_i8x16(x, y);
  // WEBASSEMBLY: call <16 x i8> @llvm.wasm.min.unsigned.v16i8(
  // WEBASSEMBLY-SAME: <16 x i8> %x, <16 x i8> %y)
  // WEBASSEMBLY-NEXT: ret
}

i8x16 max_s_i8x16(i8x16 x, i8x16 y) {
  return __builtin_wasm_max_s_i8x16(x, y);
  // WEBASSEMBLY: call <16 x i8> @llvm.wasm.max.signed.v16i8(
  // WEBASSEMBLY-SAME: <16 x i8> %x, <16 x i8> %y)
  // WEBASSEMBLY-NEXT: ret
}

i8x16 max_u_i8x16(i8x16 x, i8x16 y) {
  return __builtin_wasm_max_u_i8x16(x, y);
  // WEBASSEMBLY: call <16 x i8> @llvm.wasm.max.unsigned.v16i8(
  // WEBASSEMBLY-SAME: <16 x i8> %x, <16 x i8> %y)
  // WEBASSEMBLY-NEXT: ret
}

i16x8 min_s_i16x8(i16x8 x, i16x8 y) {
  return __builtin_wasm_min_s_i16x8(x, y);
  // WEBASSEMBLY: call <8 x i16> @llvm.wasm.min.signed.v8i16(
  // WEBASSEMBLY-SAME: <8 x i16> %x, <8 x i16> %y)
  // WEBASSEMBLY-NEXT: ret
}

i16x8 min_u_i16x8(i16x8 x, i16x8 y) {
  return __builtin_wasm_min_u_i16x8(x, y);
  // WEBASSEMBLY: call <8 x i16> @llvm.wasm.min.unsigned.v8i16(
  // WEBASSEMBLY-SAME: <8 x i16> %x, <8 x i16> %y)
  // WEBASSEMBLY-NEXT: ret
}

i16x8 max_s_i16x8(i16x8 x, i16x8 y) {
  return __builtin_wasm_max_s_i16x8(x, y);
  // WEBASSEMBLY: call <8 x i16> @llvm.wasm.max.signed.v8i16(
  // WEBASSEMBLY-SAME: <8 x i16> %x, <8 x i16> %y)
  // WEBASSEMBLY-NEXT: ret
}

i16x8 max_u_i16x8(i16x8 x, i16x8 y) {
  return __builtin_wasm_max_u_i16x8(x, y);
  // WEBASSEMBLY: call <8 x i16> @llvm.wasm.max.unsigned.v8i16(
  // WEBASSEMBLY-SAME: <8 x i16> %x, <8 x i16> %y)
  // WEBASSEMBLY-NEXT: ret
}

i32x4 min_s_i32x4(i32x4 x, i32x4 y) {
  return __builtin_wasm_min_s_i32x4(x, y);
  // WEBASSEMBLY: call <4 x i32> @llvm.wasm.min.signed.v4i32(
  // WEBASSEMBLY-SAME: <4 x i32> %x, <4 x i32> %y)
  // WEBASSEMBLY-NEXT: ret
}

i32x4 min_u_i32x4(i32x4 x, i32x4 y) {
  return __builtin_wasm_min_u_i32x4(x, y);
  // WEBASSEMBLY: call <4 x i32> @llvm.wasm.min.unsigned.v4i32(
  // WEBASSEMBLY-SAME: <4 x i32> %x, <4 x i32> %y)
  // WEBASSEMBLY-NEXT: ret
}

i32x4 max_s_i32x4(i32x4 x, i32x4 y) {
  return __builtin_wasm_max_s_i32x4(x, y);
  // WEBASSEMBLY: call <4 x i32> @llvm.wasm.max.signed.v4i32(
  // WEBASSEMBLY-SAME: <4 x i32> %x, <4 x i32> %y)
  // WEBASSEMBLY-NEXT: ret
}

i32x4 max_u_i32x4(i32x4 x, i32x4 y) {
  return __builtin_wasm_max_u_i32x4(x, y);
  // WEBASSEMBLY: call <4 x i32> @llvm.wasm.max.unsigned.v4i32(
  // WEBASSEMBLY-SAME: <4 x i32> %x, <4 x i32> %y)
  // WEBASSEMBLY-NEXT: ret
}

i32x4 bitselect(i32x4 x, i32x4 y, i32x4 c) {
  return __builtin_wasm_bitselect(x, y, c);
  // WEBASSEMBLY: call <4 x i32> @llvm.wasm.bitselect.v4i32(
+20 −0
Original line number Diff line number Diff line
@@ -112,6 +112,26 @@ def int_wasm_sub_saturate_unsigned :
  Intrinsic<[llvm_anyvector_ty],
            [LLVMMatchType<0>, LLVMMatchType<0>],
            [IntrNoMem, IntrSpeculatable]>;

// TODO: Remove intrinsics and rely on codegen patterns once these are
// officially merged to the spec proposal
def int_wasm_min_signed :
  Intrinsic<[llvm_anyvector_ty],
            [LLVMMatchType<0>, LLVMMatchType<0>],
            [IntrNoMem, IntrSpeculatable]>;
def int_wasm_min_unsigned :
  Intrinsic<[llvm_anyvector_ty],
            [LLVMMatchType<0>, LLVMMatchType<0>],
            [IntrNoMem, IntrSpeculatable]>;
def int_wasm_max_signed :
  Intrinsic<[llvm_anyvector_ty],
            [LLVMMatchType<0>, LLVMMatchType<0>],
            [IntrNoMem, IntrSpeculatable]>;
def int_wasm_max_unsigned :
  Intrinsic<[llvm_anyvector_ty],
            [LLVMMatchType<0>, LLVMMatchType<0>],
            [IntrNoMem, IntrSpeculatable]>;

def int_wasm_bitselect :
  Intrinsic<[llvm_anyvector_ty],
            [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>],
+9 −0
Original line number Diff line number Diff line
@@ -727,8 +727,17 @@ defm SUB_SAT_U :
  SIMDBinaryIntSmall<int_wasm_sub_saturate_unsigned, "sub_saturate_u", 92>;

// Integer multiplication: mul
let isCommutable = 1 in
defm MUL : SIMDBinaryIntNoI64x2<mul, "mul", 93>;

// Integer min_s / min_u / max_s / max_u
let isCommutable = 1 in {
defm MIN_S : SIMDBinaryIntNoI64x2<int_wasm_min_signed, "min_s", 94>;
defm MIN_U : SIMDBinaryIntNoI64x2<int_wasm_min_unsigned, "min_u", 95>;
defm MAX_S : SIMDBinaryIntNoI64x2<int_wasm_max_signed, "max_s", 96>;
defm MAX_U : SIMDBinaryIntNoI64x2<int_wasm_max_unsigned, "max_u", 97>;
} // isCommutable = 1

//===----------------------------------------------------------------------===//
// Floating-point unary arithmetic
//===----------------------------------------------------------------------===//
Loading