diff --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def b/clang/include/clang/Basic/BuiltinsWebAssembly.def --- a/clang/include/clang/Basic/BuiltinsWebAssembly.def +++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def @@ -146,6 +146,15 @@ TARGET_BUILTIN(__builtin_wasm_pmin_f64x2, "V2dV2dV2d", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_pmax_f64x2, "V2dV2dV2d", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_ceil_f32x4, "V4fV4f", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_floor_f32x4, "V4fV4f", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_trunc_f32x4, "V4fV4f", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_nearest_f32x4, "V4fV4f", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_ceil_f64x2, "V2dV2d", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_floor_f64x2, "V2dV2d", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_trunc_f64x2, "V2dV2d", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_nearest_f64x2, "V2dV2d", "nc", "simd128") + TARGET_BUILTIN(__builtin_wasm_dot_s_i32x4_i16x8, "V4iV8sV8s", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_sqrt_f32x4, "V4fV4f", "nc", "simd128") diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -15951,6 +15951,39 @@ CGM.getIntrinsic(Intrinsic::wasm_pmax, ConvertType(E->getType())); return Builder.CreateCall(Callee, {LHS, RHS}); } + case WebAssembly::BI__builtin_wasm_ceil_f32x4: + case WebAssembly::BI__builtin_wasm_floor_f32x4: + case WebAssembly::BI__builtin_wasm_trunc_f32x4: + case WebAssembly::BI__builtin_wasm_nearest_f32x4: + case WebAssembly::BI__builtin_wasm_ceil_f64x2: + case WebAssembly::BI__builtin_wasm_floor_f64x2: + case WebAssembly::BI__builtin_wasm_trunc_f64x2: + case WebAssembly::BI__builtin_wasm_nearest_f64x2: { + unsigned IntNo; + switch (BuiltinID) { + case WebAssembly::BI__builtin_wasm_ceil_f32x4: + case WebAssembly::BI__builtin_wasm_ceil_f64x2: + IntNo = Intrinsic::wasm_ceil; + break; + case WebAssembly::BI__builtin_wasm_floor_f32x4: + case WebAssembly::BI__builtin_wasm_floor_f64x2: + IntNo = Intrinsic::wasm_floor; + break; + case WebAssembly::BI__builtin_wasm_trunc_f32x4: + case WebAssembly::BI__builtin_wasm_trunc_f64x2: + IntNo = Intrinsic::wasm_trunc; + break; + case WebAssembly::BI__builtin_wasm_nearest_f32x4: + case WebAssembly::BI__builtin_wasm_nearest_f64x2: + IntNo = Intrinsic::wasm_nearest; + break; + default: + llvm_unreachable("unexpected builtin ID"); + } + Value *Value = EmitScalarExpr(E->getArg(0)); + Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType())); + return Builder.CreateCall(Callee, Value); + } case WebAssembly::BI__builtin_wasm_swizzle_v8x16: { Value *Src = EmitScalarExpr(E->getArg(0)); Value *Indices = EmitScalarExpr(E->getArg(1)); diff --git a/clang/test/CodeGen/builtins-wasm.c b/clang/test/CodeGen/builtins-wasm.c --- a/clang/test/CodeGen/builtins-wasm.c +++ b/clang/test/CodeGen/builtins-wasm.c @@ -621,6 +621,54 @@ // WEBASSEMBLY-NEXT: ret } +f32x4 ceil_f32x4(f32x4 x) { + return __builtin_wasm_ceil_f32x4(x); + // WEBASSEMBLY: call <4 x float> @llvm.wasm.ceil.v4f32(<4 x float> %x) + // WEBASSEMBLY: ret +} + +f32x4 floor_f32x4(f32x4 x) { + return __builtin_wasm_floor_f32x4(x); + // WEBASSEMBLY: call <4 x float> @llvm.wasm.floor.v4f32(<4 x float> %x) + // WEBASSEMBLY: ret +} + +f32x4 trunc_f32x4(f32x4 x) { + return __builtin_wasm_trunc_f32x4(x); + // WEBASSEMBLY: call <4 x float> @llvm.wasm.trunc.v4f32(<4 x float> %x) + // WEBASSEMBLY: ret +} + +f32x4 nearest_f32x4(f32x4 x) { + return __builtin_wasm_nearest_f32x4(x); + // WEBASSEMBLY: call <4 x float> @llvm.wasm.nearest.v4f32(<4 x float> %x) + // WEBASSEMBLY: ret +} + +f64x2 ceil_f64x2(f64x2 x) { + return __builtin_wasm_ceil_f64x2(x); + // WEBASSEMBLY: call <2 x double> @llvm.wasm.ceil.v2f64(<2 x double> %x) + // WEBASSEMBLY: ret +} + +f64x2 floor_f64x2(f64x2 x) { + return __builtin_wasm_floor_f64x2(x); + // WEBASSEMBLY: call <2 x double> @llvm.wasm.floor.v2f64(<2 x double> %x) + // WEBASSEMBLY: ret +} + +f64x2 trunc_f64x2(f64x2 x) { + return __builtin_wasm_trunc_f64x2(x); + // WEBASSEMBLY: call <2 x double> @llvm.wasm.trunc.v2f64(<2 x double> %x) + // WEBASSEMBLY: ret +} + +f64x2 nearest_f64x2(f64x2 x) { + return __builtin_wasm_nearest_f64x2(x); + // WEBASSEMBLY: call <2 x double> @llvm.wasm.nearest.v2f64(<2 x double> %x) + // WEBASSEMBLY: ret +} + f32x4 sqrt_f32x4(f32x4 x) { return __builtin_wasm_sqrt_f32x4(x); // WEBASSEMBLY: call <4 x float> @llvm.sqrt.v4f32(<4 x float> %x) diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td --- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td @@ -176,8 +176,7 @@ [llvm_anyvector_ty], [IntrNoMem, IntrSpeculatable]>; -// TODO: Replace these intrinsics with normal ISel patterns once the -// pmin/pmax instructions are merged to the spec proposal. +// TODO: Replace these intrinsics with normal ISel patterns def int_wasm_pmin : Intrinsic<[llvm_anyvector_ty], [LLVMMatchType<0>, LLVMMatchType<0>], @@ -187,6 +186,26 @@ [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem, IntrSpeculatable]>; +// TODO: Replace these instrinsics with normal ISel patterns once the +// rounding instructions are merged to the proposal +// (https://github.com/WebAssembly/simd/pull/232). +def int_wasm_ceil : + Intrinsic<[llvm_anyvector_ty], + [LLVMMatchType<0>], + [IntrNoMem, IntrSpeculatable]>; +def int_wasm_floor : + Intrinsic<[llvm_anyvector_ty], + [LLVMMatchType<0>], + [IntrNoMem, IntrSpeculatable]>; +def int_wasm_trunc : + Intrinsic<[llvm_anyvector_ty], + [LLVMMatchType<0>], + [IntrNoMem, IntrSpeculatable]>; +def int_wasm_nearest : + Intrinsic<[llvm_anyvector_ty], + [LLVMMatchType<0>], + [IntrNoMem, IntrSpeculatable]>; + //===----------------------------------------------------------------------===// // Bulk memory intrinsics //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td @@ -765,6 +765,16 @@ // Square root: sqrt defm SQRT : SIMDUnaryFP; +// Rounding: ceil, floor, trunc, nearest +defm CEIL : SIMDUnary; +defm FLOOR : SIMDUnary; +defm TRUNC: SIMDUnary; +defm NEAREST: SIMDUnary; +defm CEIL : SIMDUnary; +defm FLOOR : SIMDUnary; +defm TRUNC: SIMDUnary; +defm NEAREST: SIMDUnary; + //===----------------------------------------------------------------------===// // Floating-point binary arithmetic //===----------------------------------------------------------------------===// diff --git a/llvm/test/CodeGen/WebAssembly/simd-intrinsics.ll b/llvm/test/CodeGen/WebAssembly/simd-intrinsics.ll --- a/llvm/test/CodeGen/WebAssembly/simd-intrinsics.ll +++ b/llvm/test/CodeGen/WebAssembly/simd-intrinsics.ll @@ -521,6 +521,46 @@ ret <4 x float> %v } +; CHECK-LABEL: ceil_v4f32: +; SIMD128-NEXT: .functype ceil_v4f32 (v128) -> (v128){{$}} +; SIMD128-NEXT: f32x4.ceil $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <4 x float> @llvm.wasm.ceil.v4f32(<4 x float>) +define <4 x float> @ceil_v4f32(<4 x float> %a) { + %v = call <4 x float> @llvm.wasm.ceil.v4f32(<4 x float> %a) + ret <4 x float> %v +} + +; CHECK-LABEL: floor_v4f32: +; SIMD128-NEXT: .functype floor_v4f32 (v128) -> (v128){{$}} +; SIMD128-NEXT: f32x4.floor $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <4 x float> @llvm.wasm.floor.v4f32(<4 x float>) +define <4 x float> @floor_v4f32(<4 x float> %a) { + %v = call <4 x float> @llvm.wasm.floor.v4f32(<4 x float> %a) + ret <4 x float> %v +} + +; CHECK-LABEL: trunc_v4f32: +; SIMD128-NEXT: .functype trunc_v4f32 (v128) -> (v128){{$}} +; SIMD128-NEXT: f32x4.trunc $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <4 x float> @llvm.wasm.trunc.v4f32(<4 x float>) +define <4 x float> @trunc_v4f32(<4 x float> %a) { + %v = call <4 x float> @llvm.wasm.trunc.v4f32(<4 x float> %a) + ret <4 x float> %v +} + +; CHECK-LABEL: nearest_v4f32: +; SIMD128-NEXT: .functype nearest_v4f32 (v128) -> (v128){{$}} +; SIMD128-NEXT: f32x4.nearest $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <4 x float> @llvm.wasm.nearest.v4f32(<4 x float>) +define <4 x float> @nearest_v4f32(<4 x float> %a) { + %v = call <4 x float> @llvm.wasm.nearest.v4f32(<4 x float> %a) + ret <4 x float> %v +} + ; CHECK-LABEL: qfma_v4f32: ; SIMD128-NEXT: .functype qfma_v4f32 (v128, v128, v128) -> (v128){{$}} ; SIMD128-NEXT: f32x4.qfma $push[[R:[0-9]+]]=, $0, $1, $2{{$}} @@ -580,6 +620,46 @@ ret <2 x double> %v } +; CHECK-LABEL: ceil_v2f64: +; SIMD128-NEXT: .functype ceil_v2f64 (v128) -> (v128){{$}} +; SIMD128-NEXT: f64x2.ceil $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <2 x double> @llvm.wasm.ceil.v2f64(<2 x double>) +define <2 x double> @ceil_v2f64(<2 x double> %a) { + %v = call <2 x double> @llvm.wasm.ceil.v2f64(<2 x double> %a) + ret <2 x double> %v +} + +; CHECK-LABEL: floor_v2f64: +; SIMD128-NEXT: .functype floor_v2f64 (v128) -> (v128){{$}} +; SIMD128-NEXT: f64x2.floor $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <2 x double> @llvm.wasm.floor.v2f64(<2 x double>) +define <2 x double> @floor_v2f64(<2 x double> %a) { + %v = call <2 x double> @llvm.wasm.floor.v2f64(<2 x double> %a) + ret <2 x double> %v +} + +; CHECK-LABEL: trunc_v2f64: +; SIMD128-NEXT: .functype trunc_v2f64 (v128) -> (v128){{$}} +; SIMD128-NEXT: f64x2.trunc $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <2 x double> @llvm.wasm.trunc.v2f64(<2 x double>) +define <2 x double> @trunc_v2f64(<2 x double> %a) { + %v = call <2 x double> @llvm.wasm.trunc.v2f64(<2 x double> %a) + ret <2 x double> %v +} + +; CHECK-LABEL: nearest_v2f64: +; SIMD128-NEXT: .functype nearest_v2f64 (v128) -> (v128){{$}} +; SIMD128-NEXT: f64x2.nearest $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <2 x double> @llvm.wasm.nearest.v2f64(<2 x double>) +define <2 x double> @nearest_v2f64(<2 x double> %a) { + %v = call <2 x double> @llvm.wasm.nearest.v2f64(<2 x double> %a) + ret <2 x double> %v +} + ; CHECK-LABEL: qfma_v2f64: ; SIMD128-NEXT: .functype qfma_v2f64 (v128, v128, v128) -> (v128){{$}} ; SIMD128-NEXT: f64x2.qfma $push[[R:[0-9]+]]=, $0, $1, $2{{$}} diff --git a/llvm/test/MC/WebAssembly/simd-encodings.s b/llvm/test/MC/WebAssembly/simd-encodings.s --- a/llvm/test/MC/WebAssembly/simd-encodings.s +++ b/llvm/test/MC/WebAssembly/simd-encodings.s @@ -508,6 +508,30 @@ # CHECK: i64x2.mul # encoding: [0xfd,0xd5,0x01] i64x2.mul + # CHECK: f32x4.ceil # encoding: [0xfd,0xd8,0x01] + f32x4.ceil + + # CHECK: f32x4.floor # encoding: [0xfd,0xd9,0x01] + f32x4.floor + + # CHECK: f32x4.trunc # encoding: [0xfd,0xda,0x01] + f32x4.trunc + + # CHECK: f32x4.nearest # encoding: [0xfd,0xdb,0x01] + f32x4.nearest + + # CHECK: f64x2.ceil # encoding: [0xfd,0xdc,0x01] + f64x2.ceil + + # CHECK: f64x2.floor # encoding: [0xfd,0xdd,0x01] + f64x2.floor + + # CHECK: f64x2.trunc # encoding: [0xfd,0xde,0x01] + f64x2.trunc + + # CHECK: f64x2.nearest # encoding: [0xfd,0xdf,0x01] + f64x2.nearest + # CHECK: f32x4.abs # encoding: [0xfd,0xe0,0x01] f32x4.abs