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 @@ -49,6 +49,16 @@ BUILTIN(__builtin_wasm_atomic_wait_i64, "iLLi*LLiLLi", "n") BUILTIN(__builtin_wasm_atomic_notify, "Uii*Ui", "n") +// Trapping fp-to-int conversions +BUILTIN(__builtin_wasm_trunc_s_i32_f32, "if", "nc") +BUILTIN(__builtin_wasm_trunc_u_i32_f32, "if", "nc") +BUILTIN(__builtin_wasm_trunc_s_i32_f64, "id", "nc") +BUILTIN(__builtin_wasm_trunc_u_i32_f64, "id", "nc") +BUILTIN(__builtin_wasm_trunc_s_i64_f32, "LLif", "nc") +BUILTIN(__builtin_wasm_trunc_u_i64_f32, "LLif", "nc") +BUILTIN(__builtin_wasm_trunc_s_i64_f64, "LLid", "nc") +BUILTIN(__builtin_wasm_trunc_u_i64_f64, "LLid", "nc") + // Saturating fp-to-int conversions TARGET_BUILTIN(__builtin_wasm_trunc_saturate_s_i32_f32, "if", "nc", "nontrapping-fptoint") TARGET_BUILTIN(__builtin_wasm_trunc_saturate_u_i32_f32, "if", "nc", "nontrapping-fptoint") 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 @@ -14024,6 +14024,26 @@ Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_atomic_notify); return Builder.CreateCall(Callee, {Addr, Count}); } + case WebAssembly::BI__builtin_wasm_trunc_s_i32_f32: + case WebAssembly::BI__builtin_wasm_trunc_s_i32_f64: + case WebAssembly::BI__builtin_wasm_trunc_s_i64_f32: + case WebAssembly::BI__builtin_wasm_trunc_s_i64_f64: { + Value *Src = EmitScalarExpr(E->getArg(0)); + llvm::Type *ResT = ConvertType(E->getType()); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_trunc_signed, {ResT, Src->getType()}); + return Builder.CreateCall(Callee, {Src}); + } + case WebAssembly::BI__builtin_wasm_trunc_u_i32_f32: + case WebAssembly::BI__builtin_wasm_trunc_u_i32_f64: + case WebAssembly::BI__builtin_wasm_trunc_u_i64_f32: + case WebAssembly::BI__builtin_wasm_trunc_u_i64_f64: { + Value *Src = EmitScalarExpr(E->getArg(0)); + llvm::Type *ResT = ConvertType(E->getType()); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_trunc_unsigned, + {ResT, Src->getType()}); + return Builder.CreateCall(Callee, {Src}); + } case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f32: case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f64: case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f32: 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 @@ -85,6 +85,54 @@ // WEBASSEMBLY64: call i32 @llvm.wasm.atomic.notify(i32* %{{.*}}, i32 %{{.*}}) } +int trunc_s_i32_f32(float f) { + return __builtin_wasm_trunc_s_i32_f32(f); + // WEBASSEMBLY: call i32 @llvm.wasm.trunc.signed.i32.f32(float %f) + // WEBASSEMBLY-NEXT: ret +} + +int trunc_u_i32_f32(float f) { + return __builtin_wasm_trunc_u_i32_f32(f); + // WEBASSEMBLY: call i32 @llvm.wasm.trunc.unsigned.i32.f32(float %f) + // WEBASSEMBLY-NEXT: ret +} + +int trunc_s_i32_f64(double f) { + return __builtin_wasm_trunc_s_i32_f64(f); + // WEBASSEMBLY: call i32 @llvm.wasm.trunc.signed.i32.f64(double %f) + // WEBASSEMBLY-NEXT: ret +} + +int trunc_u_i32_f64(double f) { + return __builtin_wasm_trunc_u_i32_f64(f); + // WEBASSEMBLY: call i32 @llvm.wasm.trunc.unsigned.i32.f64(double %f) + // WEBASSEMBLY-NEXT: ret +} + +long long trunc_s_i64_f32(float f) { + return __builtin_wasm_trunc_s_i64_f32(f); + // WEBASSEMBLY: call i64 @llvm.wasm.trunc.signed.i64.f32(float %f) + // WEBASSEMBLY-NEXT: ret +} + +long long trunc_u_i64_f32(float f) { + return __builtin_wasm_trunc_u_i64_f32(f); + // WEBASSEMBLY: call i64 @llvm.wasm.trunc.unsigned.i64.f32(float %f) + // WEBASSEMBLY-NEXT: ret +} + +long long trunc_s_i64_f64(double f) { + return __builtin_wasm_trunc_s_i64_f64(f); + // WEBASSEMBLY: call i64 @llvm.wasm.trunc.signed.i64.f64(double %f) + // WEBASSEMBLY-NEXT: ret +} + +long long trunc_u_i64_f64(double f) { + return __builtin_wasm_trunc_u_i64_f64(f); + // WEBASSEMBLY: call i64 @llvm.wasm.trunc.unsigned.i64.f64(double %f) + // WEBASSEMBLY-NEXT: ret +} + int trunc_saturate_s_i32_f32(float f) { return __builtin_wasm_trunc_saturate_s_i32_f32(f); // WEBASSEMBLY: call i32 @llvm.wasm.trunc.saturate.signed.i32.f32(float %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 @@ -23,6 +23,17 @@ [llvm_i32_ty, LLVMMatchType<0>], []>; +//===----------------------------------------------------------------------===// +// Trapping float-to-int conversions +//===----------------------------------------------------------------------===// + +def int_wasm_trunc_signed : Intrinsic<[llvm_anyint_ty], + [llvm_anyfloat_ty], + [IntrNoMem]>; +def int_wasm_trunc_unsigned : Intrinsic<[llvm_anyint_ty], + [llvm_anyfloat_ty], + [IntrNoMem]>; + //===----------------------------------------------------------------------===// // Saturating float-to-int conversions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrConv.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrConv.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrConv.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrConv.td @@ -171,6 +171,23 @@ 0xb1>; } // hasSideEffects = 1 +def : Pat<(int_wasm_trunc_signed F32:$src), + (I32_TRUNC_S_F32 F32:$src)>; +def : Pat<(int_wasm_trunc_unsigned F32:$src), + (I32_TRUNC_U_F32 F32:$src)>; +def : Pat<(int_wasm_trunc_signed F64:$src), + (I32_TRUNC_S_F64 F64:$src)>; +def : Pat<(int_wasm_trunc_unsigned F64:$src), + (I32_TRUNC_U_F64 F64:$src)>; +def : Pat<(int_wasm_trunc_signed F32:$src), + (I64_TRUNC_S_F32 F32:$src)>; +def : Pat<(int_wasm_trunc_unsigned F32:$src), + (I64_TRUNC_U_F32 F32:$src)>; +def : Pat<(int_wasm_trunc_signed F64:$src), + (I64_TRUNC_S_F64 F64:$src)>; +def : Pat<(int_wasm_trunc_unsigned F64:$src), + (I64_TRUNC_U_F64 F64:$src)>; + defm F32_CONVERT_S_I32 : I<(outs F32:$dst), (ins I32:$src), (outs), (ins), [(set F32:$dst, (sint_to_fp I32:$src))], "f32.convert_i32_s\t$dst, $src", "f32.convert_i32_s", diff --git a/llvm/test/CodeGen/WebAssembly/conv-trap.ll b/llvm/test/CodeGen/WebAssembly/conv-trap.ll --- a/llvm/test/CodeGen/WebAssembly/conv-trap.ll +++ b/llvm/test/CodeGen/WebAssembly/conv-trap.ll @@ -165,3 +165,83 @@ %a = fptoui double %x to i64 ret i64 %a } + +; CHECK-LABEL: llvm_wasm_trunc_signed_i32_f32: +; CHECK-NEXT: .functype llvm_wasm_trunc_signed_i32_f32 (f32) -> (i32) +; CHECK-NEXT: i32.trunc_f32_s $push[[L0:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[L0]]{{$}} +declare i32 @llvm.wasm.trunc.signed.i32.f32(float) +define i32 @llvm_wasm_trunc_signed_i32_f32(float %f) { + %a = call i32 @llvm.wasm.trunc.signed.i32.f32(float %f) + ret i32 %a +} + +; CHECK-LABEL: llvm_wasm_trunc_unsigned_i32_f32: +; CHECK-NEXT: .functype llvm_wasm_trunc_unsigned_i32_f32 (f32) -> (i32) +; CHECK-NEXT: i32.trunc_f32_u $push[[L0:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[L0]]{{$}} +declare i32 @llvm.wasm.trunc.unsigned.i32.f32(float) +define i32 @llvm_wasm_trunc_unsigned_i32_f32(float %f) { + %a = call i32 @llvm.wasm.trunc.unsigned.i32.f32(float %f) + ret i32 %a +} + +; CHECK-LABEL: llvm_wasm_trunc_signed_i32_f64: +; CHECK-NEXT: .functype llvm_wasm_trunc_signed_i32_f64 (f64) -> (i32) +; CHECK-NEXT: i32.trunc_f64_s $push[[L0:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[L0]]{{$}} +declare i32 @llvm.wasm.trunc.signed.i32.f64(double) +define i32 @llvm_wasm_trunc_signed_i32_f64(double %f) { + %a = call i32 @llvm.wasm.trunc.signed.i32.f64(double %f) + ret i32 %a +} + +; CHECK-LABEL: llvm_wasm_trunc_unsigned_i32_f64: +; CHECK-NEXT: .functype llvm_wasm_trunc_unsigned_i32_f64 (f64) -> (i32) +; CHECK-NEXT: i32.trunc_f64_u $push[[L0:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[L0]]{{$}} +declare i32 @llvm.wasm.trunc.unsigned.i32.f64(double) +define i32 @llvm_wasm_trunc_unsigned_i32_f64(double %f) { + %a = call i32 @llvm.wasm.trunc.unsigned.i32.f64(double %f) + ret i32 %a +} + +; CHECK-LABEL: llvm_wasm_trunc_signed_i64_f32: +; CHECK-NEXT: .functype llvm_wasm_trunc_signed_i64_f32 (f32) -> (i64) +; CHECK-NEXT: i64.trunc_f32_s $push[[L0:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[L0]]{{$}} +declare i64 @llvm.wasm.trunc.signed.i64.f32(float) +define i64 @llvm_wasm_trunc_signed_i64_f32(float %f) { + %a = call i64 @llvm.wasm.trunc.signed.i64.f32(float %f) + ret i64 %a +} + +; CHECK-LABEL: llvm_wasm_trunc_unsigned_i64_f32: +; CHECK-NEXT: .functype llvm_wasm_trunc_unsigned_i64_f32 (f32) -> (i64) +; CHECK-NEXT: i64.trunc_f32_u $push[[L0:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[L0]]{{$}} +declare i64 @llvm.wasm.trunc.unsigned.i64.f32(float) +define i64 @llvm_wasm_trunc_unsigned_i64_f32(float %f) { + %a = call i64 @llvm.wasm.trunc.unsigned.i64.f32(float %f) + ret i64 %a +} + +; CHECK-LABEL: llvm_wasm_trunc_signed_i64_f64: +; CHECK-NEXT: .functype llvm_wasm_trunc_signed_i64_f64 (f64) -> (i64) +; CHECK-NEXT: i64.trunc_f64_s $push[[L0:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[L0]]{{$}} +declare i64 @llvm.wasm.trunc.signed.i64.f64(double) +define i64 @llvm_wasm_trunc_signed_i64_f64(double %f) { + %a = call i64 @llvm.wasm.trunc.signed.i64.f64(double %f) + ret i64 %a +} + +; CHECK-LABEL: llvm_wasm_trunc_unsigned_i64_f64: +; CHECK-NEXT: .functype llvm_wasm_trunc_unsigned_i64_f64 (f64) -> (i64) +; CHECK-NEXT: i64.trunc_f64_u $push[[L0:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[L0]]{{$}} +declare i64 @llvm.wasm.trunc.unsigned.i64.f64(double) +define i64 @llvm_wasm_trunc_unsigned_i64_f64(double %f) { + %a = call i64 @llvm.wasm.trunc.unsigned.i64.f64(double %f) + ret i64 %a +}