diff --git a/clang/include/clang/Basic/BuiltinsAArch64.def b/clang/include/clang/Basic/BuiltinsAArch64.def --- a/clang/include/clang/Basic/BuiltinsAArch64.def +++ b/clang/include/clang/Basic/BuiltinsAArch64.def @@ -99,6 +99,16 @@ BUILTIN(__builtin_arm_tcancel, "vWUIi", "n") BUILTIN(__builtin_arm_ttest, "WUi", "nc") +// Armv8.5-A FP rounding intrinsics +BUILTIN(__builtin_arm_frint32zf, "ff", "") +BUILTIN(__builtin_arm_frint32z, "dd", "") +BUILTIN(__builtin_arm_frint64zf, "ff", "") +BUILTIN(__builtin_arm_frint64z, "dd", "") +BUILTIN(__builtin_arm_frint32xf, "ff", "") +BUILTIN(__builtin_arm_frint32x, "dd", "") +BUILTIN(__builtin_arm_frint64xf, "ff", "") +BUILTIN(__builtin_arm_frint64x, "dd", "") + // Armv8.7-A load/store 64-byte intrinsics BUILTIN(__builtin_arm_ld64b, "vvC*WUi*", "n") BUILTIN(__builtin_arm_st64b, "vv*WUiC*", "n") 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 @@ -9149,6 +9149,38 @@ "cls"); } + if (BuiltinID == AArch64::BI__builtin_arm_frint32zf || + BuiltinID == AArch64::BI__builtin_arm_frint32z) { + llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); + llvm::Type *Ty = Arg->getType(); + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_frint32z, Ty), + Arg, "frint32z"); + } + + if (BuiltinID == AArch64::BI__builtin_arm_frint64zf || + BuiltinID == AArch64::BI__builtin_arm_frint64z) { + llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); + llvm::Type *Ty = Arg->getType(); + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_frint64z, Ty), + Arg, "frint64z"); + } + + if (BuiltinID == AArch64::BI__builtin_arm_frint32xf || + BuiltinID == AArch64::BI__builtin_arm_frint32x) { + llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); + llvm::Type *Ty = Arg->getType(); + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_frint32x, Ty), + Arg, "frint32x"); + } + + if (BuiltinID == AArch64::BI__builtin_arm_frint64xf || + BuiltinID == AArch64::BI__builtin_arm_frint64x) { + llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); + llvm::Type *Ty = Arg->getType(); + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_frint64x, Ty), + Arg, "frint64x"); + } + if (BuiltinID == AArch64::BI__builtin_arm_jcvt) { assert((getContext().getTypeSize(E->getType()) == 32) && "__jcvt of unusual size!"); diff --git a/clang/lib/Headers/arm_acle.h b/clang/lib/Headers/arm_acle.h --- a/clang/lib/Headers/arm_acle.h +++ b/clang/lib/Headers/arm_acle.h @@ -639,6 +639,49 @@ } #endif +/* Armv8.5-A FP rounding intrinsics */ +#if __ARM_64BIT_STATE && defined(__ARM_FEATURE_FRINT) +static __inline__ float __attribute__((__always_inline__, __nodebug__)) +__frint32zf(float __a) { + return __builtin_arm_frint32zf(__a); +} + +static __inline__ double __attribute__((__always_inline__, __nodebug__)) +__frint32z(double __a) { + return __builtin_arm_frint32z(__a); +} + +static __inline__ float __attribute__((__always_inline__, __nodebug__)) +__frint64zf(float __a) { + return __builtin_arm_frint64zf(__a); +} + +static __inline__ double __attribute__((__always_inline__, __nodebug__)) +__frint64z(double __a) { + return __builtin_arm_frint64z(__a); +} + +static __inline__ float __attribute__((__always_inline__, __nodebug__)) +__frint32xf(float __a) { + return __builtin_arm_frint32xf(__a); +} + +static __inline__ double __attribute__((__always_inline__, __nodebug__)) +__frint32x(double __a) { + return __builtin_arm_frint32x(__a); +} + +static __inline__ float __attribute__((__always_inline__, __nodebug__)) +__frint64xf(float __a) { + return __builtin_arm_frint64xf(__a); +} + +static __inline__ double __attribute__((__always_inline__, __nodebug__)) +__frint64x(double __a) { + return __builtin_arm_frint64x(__a); +} +#endif + /* Armv8.7-A load/store 64-byte intrinsics */ #if __ARM_64BIT_STATE && defined(__ARM_FEATURE_LS64) typedef struct { diff --git a/clang/test/CodeGen/aarch64-v8.5a-scalar-frint3264-intrinsic.c b/clang/test/CodeGen/aarch64-v8.5a-scalar-frint3264-intrinsic.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/aarch64-v8.5a-scalar-frint3264-intrinsic.c @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +v8.5a\ +// RUN: -flax-vector-conversions=none -S -disable-O0-optnone -emit-llvm -o - %s \ +// RUN: | opt -S -mem2reg \ +// RUN: | FileCheck %s + +// REQUIRES: aarch64-registered-target + +#include + +// CHECK-LABEL: test_frint32zf +// CHECK: [[RND:%.*]] = call float @llvm.aarch64.frint32z.f32(float %a) +// CHECK: ret float [[RND]] +float test_frint32zf(float a) { + return __frint32zf(a); +} + +// CHECK-LABEL: test_frint32z +// CHECK: [[RND:%.*]] = call double @llvm.aarch64.frint32z.f64(double %a) +// CHECK: ret double [[RND]] +double test_frint32z(double a) { + return __frint32z(a); +} + +// CHECK-LABEL: test_frint64zf +// CHECK: [[RND:%.*]] = call float @llvm.aarch64.frint64z.f32(float %a) +// CHECK: ret float [[RND]] +float test_frint64zf(float a) { + return __frint64zf(a); +} + +// CHECK-LABEL: test_frint64z +// CHECK: [[RND:%.*]] = call double @llvm.aarch64.frint64z.f64(double %a) +// CHECK: ret double [[RND]] +double test_frint64z(double a) { + return __frint64z(a); +} + +// CHECK-LABEL: test_frint32xf +// CHECK: [[RND:%.*]] = call float @llvm.aarch64.frint32x.f32(float %a) +// CHECK: ret float [[RND]] +float test_frint32xf(float a) { + return __frint32xf(a); +} + +// CHECK-LABEL: test_frint32x +// CHECK: [[RND:%.*]] = call double @llvm.aarch64.frint32x.f64(double %a) +// CHECK: ret double [[RND]] +double test_frint32x(double a) { + return __frint32x(a); +} + +// CHECK-LABEL: test_frint64xf +// CHECK: [[RND:%.*]] = call float @llvm.aarch64.frint64x.f32(float %a) +// CHECK: ret float [[RND]] +float test_frint64xf(float a) { + return __frint64xf(a); +} + +// CHECK-LABEL: test_frint64x +// CHECK: [[RND:%.*]] = call double @llvm.aarch64.frint64x.f64(double %a) +// CHECK: ret double [[RND]] +double test_frint64x(double a) { + return __frint64x(a); +} diff --git a/llvm/include/llvm/IR/IntrinsicsAArch64.td b/llvm/include/llvm/IR/IntrinsicsAArch64.td --- a/llvm/include/llvm/IR/IntrinsicsAArch64.td +++ b/llvm/include/llvm/IR/IntrinsicsAArch64.td @@ -44,6 +44,19 @@ def int_aarch64_cls: DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>; def int_aarch64_cls64: DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i64_ty], [IntrNoMem]>; +def int_aarch64_frint32z + : DefaultAttrsIntrinsic<[ llvm_anyfloat_ty ], [ LLVMMatchType<0> ], + [ IntrNoMem ]>; +def int_aarch64_frint64z + : DefaultAttrsIntrinsic<[ llvm_anyfloat_ty ], [ LLVMMatchType<0> ], + [ IntrNoMem ]>; +def int_aarch64_frint32x + : DefaultAttrsIntrinsic<[ llvm_anyfloat_ty ], [ LLVMMatchType<0> ], + [ IntrNoMem ]>; +def int_aarch64_frint64x + : DefaultAttrsIntrinsic<[ llvm_anyfloat_ty ], [ LLVMMatchType<0> ], + [ IntrNoMem ]>; + //===----------------------------------------------------------------------===// // HINT diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -3805,10 +3805,10 @@ } let Predicates = [HasFRInt3264] in { - defm FRINT32Z : FRIntNNT<0b00, "frint32z">; - defm FRINT64Z : FRIntNNT<0b10, "frint64z">; - defm FRINT32X : FRIntNNT<0b01, "frint32x">; - defm FRINT64X : FRIntNNT<0b11, "frint64x">; + defm FRINT32Z : FRIntNNT<0b00, "frint32z", int_aarch64_frint32z>; + defm FRINT64Z : FRIntNNT<0b10, "frint64z", int_aarch64_frint64z>; + defm FRINT32X : FRIntNNT<0b01, "frint32x", int_aarch64_frint32x>; + defm FRINT64X : FRIntNNT<0b11, "frint64x", int_aarch64_frint64x>; } // HasFRInt3264 let Predicates = [HasFullFP16] in { diff --git a/llvm/test/CodeGen/AArch64/v8.5a-scalar-frint3264-intrinsic.ll b/llvm/test/CodeGen/AArch64/v8.5a-scalar-frint3264-intrinsic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/v8.5a-scalar-frint3264-intrinsic.ll @@ -0,0 +1,83 @@ +; RUN: llc < %s -mtriple=aarch64-eabi -mattr=+v8.5a | FileCheck %s + +declare float @llvm.aarch64.frint32z.f32(float) +declare double @llvm.aarch64.frint32z.f64(double) +declare float @llvm.aarch64.frint64z.f32(float) +declare double @llvm.aarch64.frint64z.f64(double) + +define dso_local float @t_frint32z(float %a) { +; CHECK-LABEL: t_frint32z: +; CHECK: frint32z s0, s0 +; CHECK-NEXT: ret +entry: + %val = tail call float @llvm.aarch64.frint32z.f32(float %a) + ret float %val +} + +define dso_local double @t_frint32zf(double %a) { +; CHECK-LABEL: t_frint32zf: +; CHECK: frint32z d0, d0 +; CHECK-NEXT: ret +entry: + %val = tail call double @llvm.aarch64.frint32z.f64(double %a) + ret double %val +} + +define dso_local float @t_frint64z(float %a) { +; CHECK-LABEL: t_frint64z: +; CHECK: frint64z s0, s0 +; CHECK-NEXT: ret +entry: + %val = tail call float @llvm.aarch64.frint64z.f32(float %a) + ret float %val +} + +define dso_local double @t_frint64zf(double %a) { +; CHECK-LABEL: t_frint64zf: +; CHECK: frint64z d0, d0 +; CHECK-NEXT: ret +entry: + %val = tail call double @llvm.aarch64.frint64z.f64(double %a) + ret double %val +} + +declare float @llvm.aarch64.frint32x.f32(float) +declare double @llvm.aarch64.frint32x.f64(double) +declare float @llvm.aarch64.frint64x.f32(float) +declare double @llvm.aarch64.frint64x.f64(double) + +define dso_local float @t_frint32x(float %a) { +; CHECK-LABEL: t_frint32x: +; CHECK: frint32x s0, s0 +; CHECK-NEXT: ret +entry: + %val = tail call float @llvm.aarch64.frint32x.f32(float %a) + ret float %val +} + +define dso_local double @t_frint32xf(double %a) { +; CHECK-LABEL: t_frint32xf: +; CHECK: frint32x d0, d0 +; CHECK-NEXT: ret +entry: + %val = tail call double @llvm.aarch64.frint32x.f64(double %a) + ret double %val +} + +define dso_local float @t_frint64x(float %a) { +; CHECK-LABEL: t_frint64x: +; CHECK: frint64x s0, s0 +; CHECK-NEXT: ret +entry: + %val = tail call float @llvm.aarch64.frint64x.f32(float %a) + ret float %val +} + +define dso_local double @t_frint64xf(double %a) { +; CHECK-LABEL: t_frint64xf: +; CHECK: frint64x d0, d0 +; CHECK-NEXT: ret +entry: + %val = tail call double @llvm.aarch64.frint64x.f64(double %a) + ret double %val +}