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 @@ -179,5 +179,10 @@ TARGET_BUILTIN(__builtin_wasm_relaxed_min_f64x2, "V2dV2dV2d", "nc", "relaxed-simd") TARGET_BUILTIN(__builtin_wasm_relaxed_max_f64x2, "V2dV2dV2d", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_relaxed_trunc_s_i32x4_f32x4, "V4iV4f", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_relaxed_trunc_u_i32x4_f32x4, "V4iV4f", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_relaxed_trunc_zero_s_i32x4_f64x2, "V4iV2d", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_relaxed_trunc_zero_u_i32x4_f64x2, "V4UiV2d", "nc", "relaxed-simd") + #undef BUILTIN #undef TARGET_BUILTIN 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 @@ -18247,7 +18247,9 @@ return Builder.CreateCall(Callee, {Low, High}); } case WebAssembly::BI__builtin_wasm_trunc_sat_zero_s_f64x2_i32x4: - case WebAssembly::BI__builtin_wasm_trunc_sat_zero_u_f64x2_i32x4: { + case WebAssembly::BI__builtin_wasm_trunc_sat_zero_u_f64x2_i32x4: + case WebAssembly::BI__builtin_wasm_relaxed_trunc_zero_s_i32x4_f64x2: + case WebAssembly::BI__builtin_wasm_relaxed_trunc_zero_u_i32x4_f64x2: { Value *Vec = EmitScalarExpr(E->getArg(0)); unsigned IntNo; switch (BuiltinID) { @@ -18257,6 +18259,12 @@ case WebAssembly::BI__builtin_wasm_trunc_sat_zero_u_f64x2_i32x4: IntNo = Intrinsic::fptoui_sat; break; + case WebAssembly::BI__builtin_wasm_relaxed_trunc_zero_s_i32x4_f64x2: + IntNo = Intrinsic::wasm_relaxed_trunc_zero_signed; + break; + case WebAssembly::BI__builtin_wasm_relaxed_trunc_zero_u_i32x4_f64x2: + IntNo = Intrinsic::wasm_relaxed_trunc_zero_unsigned; + break; default: llvm_unreachable("unexpected builtin ID"); } @@ -18347,6 +18355,26 @@ Function *Callee = CGM.getIntrinsic(IntNo, LHS->getType()); return Builder.CreateCall(Callee, {LHS, RHS}); } + case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4: + case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4: { + Value *Vec = EmitScalarExpr(E->getArg(0)); + unsigned IntNo; + switch (BuiltinID) { + case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4: + IntNo = Intrinsic::wasm_relaxed_trunc_signed; + break; + case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4: + IntNo = Intrinsic::wasm_relaxed_trunc_unsigned; + break; + default: + llvm_unreachable("unexpected builtin ID"); + } + llvm::Type *SrcT = Vec->getType(); + llvm::Type *TruncT = + SrcT->getWithNewType(llvm::IntegerType::get(getLLVMContext(), 32)); + Function *Callee = CGM.getIntrinsic(IntNo, {TruncT, SrcT}); + return Builder.CreateCall(Callee, {Vec}); + } default: return nullptr; } 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 @@ -765,3 +765,34 @@ // WEBASSEMBLY-SAME: <2 x double> %a, <2 x double> %b) // WEBASSEMBLY-NEXT: ret } + +i32x4 relaxed_trunc_s_i32x4_f32x4(f32x4 f) { + return __builtin_wasm_relaxed_trunc_s_i32x4_f32x4(f); + // WEBASSEMBLY: call <4 x i32> @llvm.wasm.relaxed.trunc.signed.v4i32.v4f32(<4 x float> %f) + // WEBASSEMBLY-NEXT: ret +} + +i32x4 relaxed_trunc_u_i32x4_f32x4(f32x4 f) { + return __builtin_wasm_relaxed_trunc_u_i32x4_f32x4(f); + // WEBASSEMBLY: call <4 x i32> @llvm.wasm.relaxed.trunc.unsigned.v4i32.v4f32(<4 x float> %f) + // WEBASSEMBLY-NEXT: ret +} + +i32x4 relaxed_trunc_zero_s_i32x4_f64x2(f64x2 x) { + return __builtin_wasm_relaxed_trunc_zero_s_i32x4_f64x2(x); + // WEBASSEMBLY: %0 = tail call <2 x i32> @llvm.wasm.relaxed.trunc.zero.signed.v2i32.v2f64(<2 x double> %x) + // WEBASSEMBLY: %1 = shufflevector <2 x i32> %0, <2 x i32> zeroinitializer, <4 x i32> + // WEBASSEMBLY: ret <4 x i32> %1 +} + +u32x4 relaxed_trunc_zero_u_i32x4_f64x2(f64x2 x) { + return __builtin_wasm_relaxed_trunc_zero_u_i32x4_f64x2(x); + // WEBASSEMBLY: %0 = tail call <2 x i32> @llvm.wasm.relaxed.trunc.zero.unsigned.v2i32.v2f64(<2 x double> %x) + // WEBASSEMBLY: %1 = shufflevector <2 x i32> %0, <2 x i32> zeroinitializer, <4 x i32> + // WEBASSEMBLY: ret <4 x i32> %1 +} + + +/* i32x4 trunc_saturate_u_i32x4_f32x4(f32x4 f) { */ +/* return __builtin_wasm_trunc_saturate_u_i32x4_f32x4(f); */ +/* } */ 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 @@ -214,6 +214,27 @@ [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem, IntrSpeculatable]>; +def int_wasm_relaxed_trunc_signed: + Intrinsic<[llvm_anyvector_ty], + [llvm_anyvector_ty], + [IntrNoMem, IntrSpeculatable]>; + +def int_wasm_relaxed_trunc_unsigned: + Intrinsic<[llvm_anyvector_ty], + [llvm_anyvector_ty], + [IntrNoMem, IntrSpeculatable]>; + +def int_wasm_relaxed_trunc_zero_signed: + Intrinsic<[llvm_anyvector_ty], + [llvm_anyvector_ty], + [IntrNoMem, IntrSpeculatable]>; + +def int_wasm_relaxed_trunc_zero_unsigned: + Intrinsic<[llvm_anyvector_ty], + [llvm_anyvector_ty], + [IntrNoMem, IntrSpeculatable]>; + + //===----------------------------------------------------------------------===// // Thread-local storage intrinsics //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def --- a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def @@ -50,3 +50,7 @@ HANDLE_MEM_NODETYPE(GLOBAL_SET) HANDLE_MEM_NODETYPE(TABLE_GET) HANDLE_MEM_NODETYPE(TABLE_SET) + +// Relaxed SIMD proposal. +HANDLE_NODETYPE(RELAXED_TRUNC_ZERO_S) +HANDLE_NODETYPE(RELAXED_TRUNC_ZERO_U) 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 @@ -1392,3 +1392,20 @@ defm "" : SIMD_RELAXED_FMINMAX; defm "" : SIMD_RELAXED_FMINMAX; + +//===----------------------------------------------------------------------===// +// Relaxed floating-point to int conversions +//===----------------------------------------------------------------------===// + +multiclass SIMD_RELAXED_CONVERT simdop> { + defm op#_#vec : + RELAXED_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), + [(set (vec.vt V128:$dst), (vec.vt (op (arg.vt V128:$vec))))], + vec.prefix#"."#name#"\t$dst, $vec", vec.prefix#"."#name, simdop>; +} + +defm "" : SIMD_RELAXED_CONVERT; +defm "" : SIMD_RELAXED_CONVERT; + +defm "" : SIMD_RELAXED_CONVERT; +defm "" : SIMD_RELAXED_CONVERT; 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 @@ -466,6 +466,40 @@ ret <4 x i32> %a } +; CHECK-LABEL: relaxed_trunc_s_v4i32: +; NO-CHECK-NOT: f32x4 +; CHECK-NEXT: .functype relaxed_trunc_s_v4i32 (v128) -> (v128){{$}} +; CHECK-NEXT: i32x4.relaxed_trunc_f32x4_s $push[[R:[0-9]+]]=, $0 +; CHECK-NEXT: return $pop[[R]] +declare <4 x i32> @llvm.wasm.relaxed.trunc.signed.v4i32.v4f32(<4 x float>) +define <4 x i32> @relaxed_trunc_s_v4i32(<4 x float> %x) { + %a = call <4 x i32> @llvm.wasm.relaxed.trunc.signed.v4i32.v4f32(<4 x float> %x) + ret <4 x i32> %a +} + +; CHECK-LABEL: relaxed_trunc_u_v4i32: +; NO-CHECK-NOT: f32x4 +; CHECK-NEXT: .functype relaxed_trunc_u_v4i32 (v128) -> (v128){{$}} +; CHECK-NEXT: i32x4.relaxed_trunc_f32x4_u $push[[R:[0-9]+]]=, $0 +; CHECK-NEXT: return $pop[[R]] +declare <4 x i32> @llvm.wasm.relaxed.trunc.unsigned.v4i32.v4f32(<4 x float>) +define <4 x i32> @relaxed_trunc_u_v4i32(<4 x float> %x) { + %a = call <4 x i32> @llvm.wasm.relaxed.trunc.unsigned.v4i32.v4f32(<4 x float> %x) + ret <4 x i32> %a +} + +; CHECK-LABEL: relaxed_trunc_zero_s_v4i32: +; CHECK-NEXT: .functype relaxed_trunc_zero_s_v4i32 (v128) -> (v128){{$}} +; CHECK-NEXT: i32x4.relaxed_trunc_zero_f64x2_s $push[[R:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[R]]{{$}} +declare <2 x i32> @llvm.wasm.relaxed.trunc.zero.signed.v2i32.v2f64(<2 x double>) +define <4 x i32> @relaxed_trunc_zero_s_v4i32(<2 x double> %x) { + %v = call <2 x i32> @llvm.wasm.relaxed.trunc.zero.signed.v2i32.v2f64(<2 x double> %x) + %a = shufflevector <2 x i32> %v, <2 x i32> , + <4 x i32> + ret <4 x i32> %a +} + ; CHECK-LABEL: trunc_sat_zero_s_v4i32: ; CHECK-NEXT: .functype trunc_sat_zero_s_v4i32 (v128) -> (v128){{$}} ; CHECK-NEXT: i32x4.trunc_sat_zero_f64x2_s $push[[R:[0-9]+]]=, $0{{$}}