-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[AArch64] Implement NEON vamin/vamax intrinsics #99041
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-backend-aarch64 @llvm/pr-subscribers-clang Author: Momchil Velikov (momchil-velikov) ChangesThis patch implements the intrinsics of the form
as defined in ARM-software/acle#324 Full diff: https://github.com/llvm/llvm-project/pull/99041.diff 7 Files Affected:
diff --git a/clang/include/clang/Basic/arm_neon.td b/clang/include/clang/Basic/arm_neon.td
index 6390ba3f9fe5e..3746b3667ad99 100644
--- a/clang/include/clang/Basic/arm_neon.td
+++ b/clang/include/clang/Basic/arm_neon.td
@@ -2096,3 +2096,8 @@ let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "r
def VLDAP1_LANE : WInst<"vldap1_lane", ".(c*!).I", "QUlQlUlldQdPlQPl">;
def VSTL1_LANE : WInst<"vstl1_lane", "v*(.!)I", "QUlQlUlldQdPlQPl">;
}
+
+let ArchGuard = "defined(__aarch64__)", TargetGuard = "faminmax" in {
+ def FAMIN : WInst<"vamin", "...", "fhQdQfQh">;
+ def FAMAX : WInst<"vamax", "...", "fhQdQfQh">;
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a54fa7bf87aad..bb6094aa31805 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -13398,6 +13398,23 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Int = Intrinsic::aarch64_neon_suqadd;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vuqadd");
}
+
+ case NEON::BI__builtin_neon_vamin_f16:
+ case NEON::BI__builtin_neon_vaminq_f16:
+ case NEON::BI__builtin_neon_vamin_f32:
+ case NEON::BI__builtin_neon_vaminq_f32:
+ case NEON::BI__builtin_neon_vaminq_f64: {
+ Int = Intrinsic::aarch64_neon_famin;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "famin");
+ }
+ case NEON::BI__builtin_neon_vamax_f16:
+ case NEON::BI__builtin_neon_vamaxq_f16:
+ case NEON::BI__builtin_neon_vamax_f32:
+ case NEON::BI__builtin_neon_vamaxq_f32:
+ case NEON::BI__builtin_neon_vamaxq_f64: {
+ Int = Intrinsic::aarch64_neon_famax;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "famax");
+ }
}
}
diff --git a/clang/test/CodeGen/aarch64-neon-faminmax-intrinsics.c b/clang/test/CodeGen/aarch64-neon-faminmax-intrinsics.c
new file mode 100644
index 0000000000000..631e9738b85c5
--- /dev/null
+++ b/clang/test/CodeGen/aarch64-neon-faminmax-intrinsics.c
@@ -0,0 +1,112 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+#include <arm_neon.h>
+
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon -target-feature +faminmax -O3 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon -target-feature +faminmax -S -O3 -Werror -Wall -o /dev/null %s
+
+// CHECK-LABEL: define dso_local <4 x half> @test_vamin_f16(
+// CHECK-SAME: <4 x half> noundef [[VN:%.*]], <4 x half> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <4 x half> @llvm.aarch64.neon.famin.v4f16(<4 x half> [[VN]], <4 x half> [[VM]])
+// CHECK-NEXT: ret <4 x half> [[FAMIN2_I]]
+//
+float16x4_t test_vamin_f16(float16x4_t vn, float16x4_t vm) {
+ return vamin_f16(vn, vm);
+}
+
+// CHECK-LABEL: define dso_local <8 x half> @test_vaminq_f16(
+// CHECK-SAME: <8 x half> noundef [[VN:%.*]], <8 x half> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <8 x half> @llvm.aarch64.neon.famin.v8f16(<8 x half> [[VN]], <8 x half> [[VM]])
+// CHECK-NEXT: ret <8 x half> [[FAMIN2_I]]
+//
+float16x8_t test_vaminq_f16(float16x8_t vn, float16x8_t vm) {
+ return vaminq_f16(vn, vm);
+
+}
+
+// CHECK-LABEL: define dso_local <2 x float> @test_vamin_f32(
+// CHECK-SAME: <2 x float> noundef [[VN:%.*]], <2 x float> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <2 x float> @llvm.aarch64.neon.famin.v2f32(<2 x float> [[VN]], <2 x float> [[VM]])
+// CHECK-NEXT: ret <2 x float> [[FAMIN2_I]]
+//
+float32x2_t test_vamin_f32(float32x2_t vn, float32x2_t vm) {
+ return vamin_f32(vn, vm);
+
+}
+
+// CHECK-LABEL: define dso_local <4 x float> @test_vaminq_f32(
+// CHECK-SAME: <4 x float> noundef [[VN:%.*]], <4 x float> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <4 x float> @llvm.aarch64.neon.famin.v4f32(<4 x float> [[VN]], <4 x float> [[VM]])
+// CHECK-NEXT: ret <4 x float> [[FAMIN2_I]]
+//
+float32x4_t test_vaminq_f32(float32x4_t vn, float32x4_t vm) {
+ return vaminq_f32(vn, vm);
+
+}
+
+// CHECK-LABEL: define dso_local <2 x double> @test_vaminq_f64(
+// CHECK-SAME: <2 x double> noundef [[VN:%.*]], <2 x double> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <2 x double> @llvm.aarch64.neon.famin.v2f64(<2 x double> [[VN]], <2 x double> [[VM]])
+// CHECK-NEXT: ret <2 x double> [[FAMIN2_I]]
+//
+float64x2_t test_vaminq_f64(float64x2_t vn, float64x2_t vm) {
+ return vaminq_f64(vn, vm);
+}
+
+
+// CHECK-LABEL: define dso_local <4 x half> @test_vamax_f16(
+// CHECK-SAME: <4 x half> noundef [[VN:%.*]], <4 x half> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <4 x half> @llvm.aarch64.neon.famax.v4f16(<4 x half> [[VN]], <4 x half> [[VM]])
+// CHECK-NEXT: ret <4 x half> [[FAMAX2_I]]
+//
+float16x4_t test_vamax_f16(float16x4_t vn, float16x4_t vm) {
+ return vamax_f16(vn, vm);
+}
+
+// CHECK-LABEL: define dso_local <8 x half> @test_vamaxq_f16(
+// CHECK-SAME: <8 x half> noundef [[VN:%.*]], <8 x half> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <8 x half> @llvm.aarch64.neon.famax.v8f16(<8 x half> [[VN]], <8 x half> [[VM]])
+// CHECK-NEXT: ret <8 x half> [[FAMAX2_I]]
+//
+float16x8_t test_vamaxq_f16(float16x8_t vn, float16x8_t vm) {
+ return vamaxq_f16(vn, vm);
+
+}
+
+// CHECK-LABEL: define dso_local <2 x float> @test_vamax_f32(
+// CHECK-SAME: <2 x float> noundef [[VN:%.*]], <2 x float> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <2 x float> @llvm.aarch64.neon.famax.v2f32(<2 x float> [[VN]], <2 x float> [[VM]])
+// CHECK-NEXT: ret <2 x float> [[FAMAX2_I]]
+//
+float32x2_t test_vamax_f32(float32x2_t vn, float32x2_t vm) {
+ return vamax_f32(vn, vm);
+
+}
+
+// CHECK-LABEL: define dso_local <4 x float> @test_vamaxq_f32(
+// CHECK-SAME: <4 x float> noundef [[VN:%.*]], <4 x float> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <4 x float> @llvm.aarch64.neon.famax.v4f32(<4 x float> [[VN]], <4 x float> [[VM]])
+// CHECK-NEXT: ret <4 x float> [[FAMAX2_I]]
+//
+float32x4_t test_vamaxq_f32(float32x4_t vn, float32x4_t vm) {
+ return vamaxq_f32(vn, vm);
+
+}
+
+// CHECK-LABEL: define dso_local <2 x double> @test_vamaxq_f64(
+// CHECK-SAME: <2 x double> noundef [[VN:%.*]], <2 x double> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <2 x double> @llvm.aarch64.neon.famax.v2f64(<2 x double> [[VN]], <2 x double> [[VM]])
+// CHECK-NEXT: ret <2 x double> [[FAMAX2_I]]
+//
+float64x2_t test_vamaxq_f64(float64x2_t vn, float64x2_t vm) {
+ return vamaxq_f64(vn, vm);
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsAArch64.td b/llvm/include/llvm/IR/IntrinsicsAArch64.td
index 3735bf5222fce..f778973880703 100644
--- a/llvm/include/llvm/IR/IntrinsicsAArch64.td
+++ b/llvm/include/llvm/IR/IntrinsicsAArch64.td
@@ -3730,3 +3730,6 @@ def int_aarch64_sve_pmov_to_vector_lane_zeroing : SVE2_Pred_1VectorArg_Intrinsic
def int_aarch64_sme_mopa_nonwide : SME_OuterProduct_Intrinsic;
def int_aarch64_sme_mops_nonwide : SME_OuterProduct_Intrinsic;
+// Neon absolute maximum and minimum
+def int_aarch64_neon_famax : AdvSIMD_2VectorArg_Intrinsic;
+def int_aarch64_neon_famin : AdvSIMD_2VectorArg_Intrinsic;
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index e1ecc5a57dd26..3cbc41d943eba 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -5985,6 +5985,26 @@ multiclass SIMDThreeSameVectorFP<bit U, bit S, bits<3> opc,
[(set (v2f64 V128:$Rd), (OpNode (v2f64 V128:$Rn), (v2f64 V128:$Rm)))]>;
}
+let mayRaiseFPException = 1, Uses = [FPCR] in
+multiclass SIMDThreeVectorFP<bit U, bit S, bits<3> opc,
+ string asm, SDPatternOperator OpNode> {
+ def v4f16 : BaseSIMDThreeSameVector<0, U, {S,0b10}, {0b00,opc}, V64,
+ asm, ".4h",
+ [(set (v4f16 V64:$Rd), (OpNode (v4f16 V64:$Rn), (v4i16 V64:$Rm)))]>;
+ def v8f16 : BaseSIMDThreeSameVector<1, U, {S,0b10}, {0b00,opc}, V128,
+ asm, ".8h",
+ [(set (v8f16 V128:$Rd), (OpNode (v8f16 V128:$Rn), (v8i16 V128:$Rm)))]>;
+ def v2f32 : BaseSIMDThreeSameVector<0, U, {S,0b01}, {0b11,opc}, V64,
+ asm, ".2s",
+ [(set (v2f32 V64:$Rd), (OpNode (v2f32 V64:$Rn), (v2i32 V64:$Rm)))]>;
+ def v4f32 : BaseSIMDThreeSameVector<1, U, {S,0b01}, {0b11,opc}, V128,
+ asm, ".4s",
+ [(set (v4f32 V128:$Rd), (OpNode (v4f32 V128:$Rn), (v4i32 V128:$Rm)))]>;
+ def v2f64 : BaseSIMDThreeSameVector<1, U, {S,0b11}, {0b11,opc}, V128,
+ asm, ".2d",
+ [(set (v2f64 V128:$Rd), (OpNode (v2f64 V128:$Rn), (v2i64 V128:$Rm)))]>;
+}
+
let mayRaiseFPException = 1, Uses = [FPCR] in
multiclass SIMDThreeSameVectorFPCmp<bit U, bit S, bits<3> opc,
string asm,
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index dd11f74882115..6a9b7256e31bd 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -10016,8 +10016,8 @@ let Predicates = [HasFP8] in {
} // End let Predicates = [HasFP8]
let Predicates = [HasFAMINMAX] in {
- defm FAMAX : SIMDThreeSameVectorFP<0b0, 0b1, 0b011, "famax", null_frag>;
- defm FAMIN : SIMDThreeSameVectorFP<0b1, 0b1, 0b011, "famin", null_frag>;
+ defm FAMAX : SIMDThreeSameVectorFP<0b0, 0b1, 0b011, "famax", int_aarch64_neon_famax>;
+ defm FAMIN : SIMDThreeSameVectorFP<0b1, 0b1, 0b011, "famin", int_aarch64_neon_famin>;
} // End let Predicates = [HasFAMAXMIN]
let Predicates = [HasFP8FMA] in {
diff --git a/llvm/test/CodeGen/AArch64/neon-famin-famax.ll b/llvm/test/CodeGen/AArch64/neon-famin-famax.ll
new file mode 100644
index 0000000000000..97fb0a0891452
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/neon-famin-famax.ll
@@ -0,0 +1,96 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s | FileCheck %s
+
+target triple = "aarch64-linux"
+
+define <4 x half> @test_famin_f16(<4 x half> %vn, <4 x half> %vm) #0 {
+; CHECK-LABEL: test_famin_f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famin v0.4h, v0.4h, v1.4h
+; CHECK-NEXT: ret
+ %res = call <4 x half> @llvm.aarch64.neon.famin.v4f16(<4 x half> %vn, <4 x half> %vm)
+ ret <4 x half> %res
+}
+
+define <8 x half> @test_famin2_f16(<8 x half> %vn, <8 x half> %vm) #0 {
+; CHECK-LABEL: test_famin2_f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famin v0.8h, v0.8h, v1.8h
+; CHECK-NEXT: ret
+ %res = call <8 x half> @llvm.aarch64.neon.famin.v8f16(<8 x half> %vn, <8 x half> %vm)
+ ret <8 x half> %res
+}
+
+define <2 x float> @test_famin_f32(<2 x float> %vn, <2 x float> %vm) #0 {
+; CHECK-LABEL: test_famin_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famin v0.2s, v0.2s, v1.2s
+; CHECK-NEXT: ret
+ %res = call <2 x float> @llvm.aarch64.neon.famin.v2f32(<2 x float> %vn, <2 x float> %vm)
+ ret <2 x float> %res
+}
+
+define <4 x float> @test_famin2_f32(<4 x float> %vn, <4 x float> %vm) #0 {
+; CHECK-LABEL: test_famin2_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famin v0.4s, v0.4s, v1.4s
+; CHECK-NEXT: ret
+ %res = call <4 x float> @llvm.aarch64.neon.famin.v4f32(<4 x float> %vn, <4 x float> %vm)
+ ret <4 x float> %res
+}
+
+define <2 x double> @test_famin_f64(<2 x double> %vn, <2 x double> %vm) #0 {
+; CHECK-LABEL: test_famin_f64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famin v0.2d, v0.2d, v1.2d
+; CHECK-NEXT: ret
+ %res = call <2 x double> @llvm.aarch64.neon.famin.v2f64(<2 x double> %vn, <2 x double> %vm)
+ ret <2 x double> %res
+}
+
+define <4 x half> @test_famax_f16(<4 x half> %vn, <4 x half> %vm) #0 {
+; CHECK-LABEL: test_famax_f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famax v0.4h, v0.4h, v1.4h
+; CHECK-NEXT: ret
+ %res = call <4 x half> @llvm.aarch64.neon.famax.v4f16(<4 x half> %vn, <4 x half> %vm)
+ ret <4 x half> %res
+}
+
+define <8 x half> @test_famax2_f16(<8 x half> %vn, <8 x half> %vm) #0 {
+; CHECK-LABEL: test_famax2_f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famax v0.8h, v0.8h, v1.8h
+; CHECK-NEXT: ret
+ %res = call <8 x half> @llvm.aarch64.neon.famax.v8f16(<8 x half> %vn, <8 x half> %vm)
+ ret <8 x half> %res
+}
+
+define <2 x float> @test_famax_f32(<2 x float> %vn, <2 x float> %vm) #0 {
+; CHECK-LABEL: test_famax_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famax v0.2s, v0.2s, v1.2s
+; CHECK-NEXT: ret
+ %res = call <2 x float> @llvm.aarch64.neon.famax.v2f32(<2 x float> %vn, <2 x float> %vm)
+ ret <2 x float> %res
+}
+
+define <4 x float> @test_famax2_f32(<4 x float> %vn, <4 x float> %vm) #0 {
+; CHECK-LABEL: test_famax2_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famax v0.4s, v0.4s, v1.4s
+; CHECK-NEXT: ret
+ %res = call <4 x float> @llvm.aarch64.neon.famax.v4f32(<4 x float> %vn, <4 x float> %vm)
+ ret <4 x float> %res
+}
+
+define <2 x double> @test_famax_f64(<2 x double> %vn, <2 x double> %vm) #0 {
+; CHECK-LABEL: test_famax_f64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famax v0.2d, v0.2d, v1.2d
+; CHECK-NEXT: ret
+ %res = call <2 x double> @llvm.aarch64.neon.famax.v2f64(<2 x double> %vn, <2 x double> %vm)
+ ret <2 x double> %res
+}
+
+attributes #0 = { "target-features"="+neon,+faminmax" }
|
@llvm/pr-subscribers-clang-codegen Author: Momchil Velikov (momchil-velikov) ChangesThis patch implements the intrinsics of the form
as defined in ARM-software/acle#324 Full diff: https://github.com/llvm/llvm-project/pull/99041.diff 7 Files Affected:
diff --git a/clang/include/clang/Basic/arm_neon.td b/clang/include/clang/Basic/arm_neon.td
index 6390ba3f9fe5e..3746b3667ad99 100644
--- a/clang/include/clang/Basic/arm_neon.td
+++ b/clang/include/clang/Basic/arm_neon.td
@@ -2096,3 +2096,8 @@ let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "r
def VLDAP1_LANE : WInst<"vldap1_lane", ".(c*!).I", "QUlQlUlldQdPlQPl">;
def VSTL1_LANE : WInst<"vstl1_lane", "v*(.!)I", "QUlQlUlldQdPlQPl">;
}
+
+let ArchGuard = "defined(__aarch64__)", TargetGuard = "faminmax" in {
+ def FAMIN : WInst<"vamin", "...", "fhQdQfQh">;
+ def FAMAX : WInst<"vamax", "...", "fhQdQfQh">;
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a54fa7bf87aad..bb6094aa31805 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -13398,6 +13398,23 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Int = Intrinsic::aarch64_neon_suqadd;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vuqadd");
}
+
+ case NEON::BI__builtin_neon_vamin_f16:
+ case NEON::BI__builtin_neon_vaminq_f16:
+ case NEON::BI__builtin_neon_vamin_f32:
+ case NEON::BI__builtin_neon_vaminq_f32:
+ case NEON::BI__builtin_neon_vaminq_f64: {
+ Int = Intrinsic::aarch64_neon_famin;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "famin");
+ }
+ case NEON::BI__builtin_neon_vamax_f16:
+ case NEON::BI__builtin_neon_vamaxq_f16:
+ case NEON::BI__builtin_neon_vamax_f32:
+ case NEON::BI__builtin_neon_vamaxq_f32:
+ case NEON::BI__builtin_neon_vamaxq_f64: {
+ Int = Intrinsic::aarch64_neon_famax;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "famax");
+ }
}
}
diff --git a/clang/test/CodeGen/aarch64-neon-faminmax-intrinsics.c b/clang/test/CodeGen/aarch64-neon-faminmax-intrinsics.c
new file mode 100644
index 0000000000000..631e9738b85c5
--- /dev/null
+++ b/clang/test/CodeGen/aarch64-neon-faminmax-intrinsics.c
@@ -0,0 +1,112 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+#include <arm_neon.h>
+
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon -target-feature +faminmax -O3 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon -target-feature +faminmax -S -O3 -Werror -Wall -o /dev/null %s
+
+// CHECK-LABEL: define dso_local <4 x half> @test_vamin_f16(
+// CHECK-SAME: <4 x half> noundef [[VN:%.*]], <4 x half> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <4 x half> @llvm.aarch64.neon.famin.v4f16(<4 x half> [[VN]], <4 x half> [[VM]])
+// CHECK-NEXT: ret <4 x half> [[FAMIN2_I]]
+//
+float16x4_t test_vamin_f16(float16x4_t vn, float16x4_t vm) {
+ return vamin_f16(vn, vm);
+}
+
+// CHECK-LABEL: define dso_local <8 x half> @test_vaminq_f16(
+// CHECK-SAME: <8 x half> noundef [[VN:%.*]], <8 x half> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <8 x half> @llvm.aarch64.neon.famin.v8f16(<8 x half> [[VN]], <8 x half> [[VM]])
+// CHECK-NEXT: ret <8 x half> [[FAMIN2_I]]
+//
+float16x8_t test_vaminq_f16(float16x8_t vn, float16x8_t vm) {
+ return vaminq_f16(vn, vm);
+
+}
+
+// CHECK-LABEL: define dso_local <2 x float> @test_vamin_f32(
+// CHECK-SAME: <2 x float> noundef [[VN:%.*]], <2 x float> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <2 x float> @llvm.aarch64.neon.famin.v2f32(<2 x float> [[VN]], <2 x float> [[VM]])
+// CHECK-NEXT: ret <2 x float> [[FAMIN2_I]]
+//
+float32x2_t test_vamin_f32(float32x2_t vn, float32x2_t vm) {
+ return vamin_f32(vn, vm);
+
+}
+
+// CHECK-LABEL: define dso_local <4 x float> @test_vaminq_f32(
+// CHECK-SAME: <4 x float> noundef [[VN:%.*]], <4 x float> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <4 x float> @llvm.aarch64.neon.famin.v4f32(<4 x float> [[VN]], <4 x float> [[VM]])
+// CHECK-NEXT: ret <4 x float> [[FAMIN2_I]]
+//
+float32x4_t test_vaminq_f32(float32x4_t vn, float32x4_t vm) {
+ return vaminq_f32(vn, vm);
+
+}
+
+// CHECK-LABEL: define dso_local <2 x double> @test_vaminq_f64(
+// CHECK-SAME: <2 x double> noundef [[VN:%.*]], <2 x double> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <2 x double> @llvm.aarch64.neon.famin.v2f64(<2 x double> [[VN]], <2 x double> [[VM]])
+// CHECK-NEXT: ret <2 x double> [[FAMIN2_I]]
+//
+float64x2_t test_vaminq_f64(float64x2_t vn, float64x2_t vm) {
+ return vaminq_f64(vn, vm);
+}
+
+
+// CHECK-LABEL: define dso_local <4 x half> @test_vamax_f16(
+// CHECK-SAME: <4 x half> noundef [[VN:%.*]], <4 x half> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <4 x half> @llvm.aarch64.neon.famax.v4f16(<4 x half> [[VN]], <4 x half> [[VM]])
+// CHECK-NEXT: ret <4 x half> [[FAMAX2_I]]
+//
+float16x4_t test_vamax_f16(float16x4_t vn, float16x4_t vm) {
+ return vamax_f16(vn, vm);
+}
+
+// CHECK-LABEL: define dso_local <8 x half> @test_vamaxq_f16(
+// CHECK-SAME: <8 x half> noundef [[VN:%.*]], <8 x half> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <8 x half> @llvm.aarch64.neon.famax.v8f16(<8 x half> [[VN]], <8 x half> [[VM]])
+// CHECK-NEXT: ret <8 x half> [[FAMAX2_I]]
+//
+float16x8_t test_vamaxq_f16(float16x8_t vn, float16x8_t vm) {
+ return vamaxq_f16(vn, vm);
+
+}
+
+// CHECK-LABEL: define dso_local <2 x float> @test_vamax_f32(
+// CHECK-SAME: <2 x float> noundef [[VN:%.*]], <2 x float> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <2 x float> @llvm.aarch64.neon.famax.v2f32(<2 x float> [[VN]], <2 x float> [[VM]])
+// CHECK-NEXT: ret <2 x float> [[FAMAX2_I]]
+//
+float32x2_t test_vamax_f32(float32x2_t vn, float32x2_t vm) {
+ return vamax_f32(vn, vm);
+
+}
+
+// CHECK-LABEL: define dso_local <4 x float> @test_vamaxq_f32(
+// CHECK-SAME: <4 x float> noundef [[VN:%.*]], <4 x float> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <4 x float> @llvm.aarch64.neon.famax.v4f32(<4 x float> [[VN]], <4 x float> [[VM]])
+// CHECK-NEXT: ret <4 x float> [[FAMAX2_I]]
+//
+float32x4_t test_vamaxq_f32(float32x4_t vn, float32x4_t vm) {
+ return vamaxq_f32(vn, vm);
+
+}
+
+// CHECK-LABEL: define dso_local <2 x double> @test_vamaxq_f64(
+// CHECK-SAME: <2 x double> noundef [[VN:%.*]], <2 x double> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <2 x double> @llvm.aarch64.neon.famax.v2f64(<2 x double> [[VN]], <2 x double> [[VM]])
+// CHECK-NEXT: ret <2 x double> [[FAMAX2_I]]
+//
+float64x2_t test_vamaxq_f64(float64x2_t vn, float64x2_t vm) {
+ return vamaxq_f64(vn, vm);
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsAArch64.td b/llvm/include/llvm/IR/IntrinsicsAArch64.td
index 3735bf5222fce..f778973880703 100644
--- a/llvm/include/llvm/IR/IntrinsicsAArch64.td
+++ b/llvm/include/llvm/IR/IntrinsicsAArch64.td
@@ -3730,3 +3730,6 @@ def int_aarch64_sve_pmov_to_vector_lane_zeroing : SVE2_Pred_1VectorArg_Intrinsic
def int_aarch64_sme_mopa_nonwide : SME_OuterProduct_Intrinsic;
def int_aarch64_sme_mops_nonwide : SME_OuterProduct_Intrinsic;
+// Neon absolute maximum and minimum
+def int_aarch64_neon_famax : AdvSIMD_2VectorArg_Intrinsic;
+def int_aarch64_neon_famin : AdvSIMD_2VectorArg_Intrinsic;
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index e1ecc5a57dd26..3cbc41d943eba 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -5985,6 +5985,26 @@ multiclass SIMDThreeSameVectorFP<bit U, bit S, bits<3> opc,
[(set (v2f64 V128:$Rd), (OpNode (v2f64 V128:$Rn), (v2f64 V128:$Rm)))]>;
}
+let mayRaiseFPException = 1, Uses = [FPCR] in
+multiclass SIMDThreeVectorFP<bit U, bit S, bits<3> opc,
+ string asm, SDPatternOperator OpNode> {
+ def v4f16 : BaseSIMDThreeSameVector<0, U, {S,0b10}, {0b00,opc}, V64,
+ asm, ".4h",
+ [(set (v4f16 V64:$Rd), (OpNode (v4f16 V64:$Rn), (v4i16 V64:$Rm)))]>;
+ def v8f16 : BaseSIMDThreeSameVector<1, U, {S,0b10}, {0b00,opc}, V128,
+ asm, ".8h",
+ [(set (v8f16 V128:$Rd), (OpNode (v8f16 V128:$Rn), (v8i16 V128:$Rm)))]>;
+ def v2f32 : BaseSIMDThreeSameVector<0, U, {S,0b01}, {0b11,opc}, V64,
+ asm, ".2s",
+ [(set (v2f32 V64:$Rd), (OpNode (v2f32 V64:$Rn), (v2i32 V64:$Rm)))]>;
+ def v4f32 : BaseSIMDThreeSameVector<1, U, {S,0b01}, {0b11,opc}, V128,
+ asm, ".4s",
+ [(set (v4f32 V128:$Rd), (OpNode (v4f32 V128:$Rn), (v4i32 V128:$Rm)))]>;
+ def v2f64 : BaseSIMDThreeSameVector<1, U, {S,0b11}, {0b11,opc}, V128,
+ asm, ".2d",
+ [(set (v2f64 V128:$Rd), (OpNode (v2f64 V128:$Rn), (v2i64 V128:$Rm)))]>;
+}
+
let mayRaiseFPException = 1, Uses = [FPCR] in
multiclass SIMDThreeSameVectorFPCmp<bit U, bit S, bits<3> opc,
string asm,
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index dd11f74882115..6a9b7256e31bd 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -10016,8 +10016,8 @@ let Predicates = [HasFP8] in {
} // End let Predicates = [HasFP8]
let Predicates = [HasFAMINMAX] in {
- defm FAMAX : SIMDThreeSameVectorFP<0b0, 0b1, 0b011, "famax", null_frag>;
- defm FAMIN : SIMDThreeSameVectorFP<0b1, 0b1, 0b011, "famin", null_frag>;
+ defm FAMAX : SIMDThreeSameVectorFP<0b0, 0b1, 0b011, "famax", int_aarch64_neon_famax>;
+ defm FAMIN : SIMDThreeSameVectorFP<0b1, 0b1, 0b011, "famin", int_aarch64_neon_famin>;
} // End let Predicates = [HasFAMAXMIN]
let Predicates = [HasFP8FMA] in {
diff --git a/llvm/test/CodeGen/AArch64/neon-famin-famax.ll b/llvm/test/CodeGen/AArch64/neon-famin-famax.ll
new file mode 100644
index 0000000000000..97fb0a0891452
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/neon-famin-famax.ll
@@ -0,0 +1,96 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s | FileCheck %s
+
+target triple = "aarch64-linux"
+
+define <4 x half> @test_famin_f16(<4 x half> %vn, <4 x half> %vm) #0 {
+; CHECK-LABEL: test_famin_f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famin v0.4h, v0.4h, v1.4h
+; CHECK-NEXT: ret
+ %res = call <4 x half> @llvm.aarch64.neon.famin.v4f16(<4 x half> %vn, <4 x half> %vm)
+ ret <4 x half> %res
+}
+
+define <8 x half> @test_famin2_f16(<8 x half> %vn, <8 x half> %vm) #0 {
+; CHECK-LABEL: test_famin2_f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famin v0.8h, v0.8h, v1.8h
+; CHECK-NEXT: ret
+ %res = call <8 x half> @llvm.aarch64.neon.famin.v8f16(<8 x half> %vn, <8 x half> %vm)
+ ret <8 x half> %res
+}
+
+define <2 x float> @test_famin_f32(<2 x float> %vn, <2 x float> %vm) #0 {
+; CHECK-LABEL: test_famin_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famin v0.2s, v0.2s, v1.2s
+; CHECK-NEXT: ret
+ %res = call <2 x float> @llvm.aarch64.neon.famin.v2f32(<2 x float> %vn, <2 x float> %vm)
+ ret <2 x float> %res
+}
+
+define <4 x float> @test_famin2_f32(<4 x float> %vn, <4 x float> %vm) #0 {
+; CHECK-LABEL: test_famin2_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famin v0.4s, v0.4s, v1.4s
+; CHECK-NEXT: ret
+ %res = call <4 x float> @llvm.aarch64.neon.famin.v4f32(<4 x float> %vn, <4 x float> %vm)
+ ret <4 x float> %res
+}
+
+define <2 x double> @test_famin_f64(<2 x double> %vn, <2 x double> %vm) #0 {
+; CHECK-LABEL: test_famin_f64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famin v0.2d, v0.2d, v1.2d
+; CHECK-NEXT: ret
+ %res = call <2 x double> @llvm.aarch64.neon.famin.v2f64(<2 x double> %vn, <2 x double> %vm)
+ ret <2 x double> %res
+}
+
+define <4 x half> @test_famax_f16(<4 x half> %vn, <4 x half> %vm) #0 {
+; CHECK-LABEL: test_famax_f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famax v0.4h, v0.4h, v1.4h
+; CHECK-NEXT: ret
+ %res = call <4 x half> @llvm.aarch64.neon.famax.v4f16(<4 x half> %vn, <4 x half> %vm)
+ ret <4 x half> %res
+}
+
+define <8 x half> @test_famax2_f16(<8 x half> %vn, <8 x half> %vm) #0 {
+; CHECK-LABEL: test_famax2_f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famax v0.8h, v0.8h, v1.8h
+; CHECK-NEXT: ret
+ %res = call <8 x half> @llvm.aarch64.neon.famax.v8f16(<8 x half> %vn, <8 x half> %vm)
+ ret <8 x half> %res
+}
+
+define <2 x float> @test_famax_f32(<2 x float> %vn, <2 x float> %vm) #0 {
+; CHECK-LABEL: test_famax_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famax v0.2s, v0.2s, v1.2s
+; CHECK-NEXT: ret
+ %res = call <2 x float> @llvm.aarch64.neon.famax.v2f32(<2 x float> %vn, <2 x float> %vm)
+ ret <2 x float> %res
+}
+
+define <4 x float> @test_famax2_f32(<4 x float> %vn, <4 x float> %vm) #0 {
+; CHECK-LABEL: test_famax2_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famax v0.4s, v0.4s, v1.4s
+; CHECK-NEXT: ret
+ %res = call <4 x float> @llvm.aarch64.neon.famax.v4f32(<4 x float> %vn, <4 x float> %vm)
+ ret <4 x float> %res
+}
+
+define <2 x double> @test_famax_f64(<2 x double> %vn, <2 x double> %vm) #0 {
+; CHECK-LABEL: test_famax_f64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: famax v0.2d, v0.2d, v1.2d
+; CHECK-NEXT: ret
+ %res = call <2 x double> @llvm.aarch64.neon.famax.v2f64(<2 x double> %vn, <2 x double> %vm)
+ ret <2 x double> %res
+}
+
+attributes #0 = { "target-features"="+neon,+faminmax" }
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you consider emitting llvm.fmin(llvm.fabs(x), llvm.fabs(y))
?
Nope. I'll have a look. |
bb30d80
to
f9ae5f3
Compare
Ping? |
f9ae5f3
to
fcbbb80
Compare
This patch implements the intrinsics of the form floatNxM_t vamin[q]_fN(floatNxM_t vn, floatNxM_t vm); floatNxM_t vamax[q]_fN(floatNxM_t vn, floatNxM_t vm); as defined in ARM-software/acle#324 Co-authored-by: Hassnaa Hamdi <[email protected]>
986eed8
to
65101a0
Compare
This patch implements the intrinsics of the form
as defined in ARM-software/acle#324