https://github.com/yairbenavraham updated https://github.com/llvm/llvm-project/pull/218307
>From fb3a027ecef08e1740ed35a91d8d1978c1154a74 Mon Sep 17 00:00:00 2001 From: Yair Ben Avraham <[email protected]> Date: Thu, 20 Aug 2026 07:38:56 +0300 Subject: [PATCH 1/6] [CIR][AArch64] Handle constrained Neon FMA and sqrt Propagate expression FP options through AArch64 builtin emission and attach the active constrained FP environment to CIR FMA and sqrt operations. Unconstrained FMA/sqrt coverage already lives under CodeGen/AArch64/neon. Add command-line strict coverage there, plus CIR and CIR-to-LLVM coverage to the existing test where a pragma overrides a command-line maytrap setting. Check that lowering does not fall back to generic CIR calls or unconstrained LLVM intrinsics. Assisted-by: Codex Follow-up to #213800 --- .../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp | 13 +++++- clang/test/CodeGen/AArch64/neon/fullfp16.c | 10 +++++ .../AArch64/neon/fused-multiple-fullfp16.c | 2 +- .../CodeGen/AArch64/neon/fused-multiply.c | 18 ++++++++ clang/test/CodeGen/AArch64/neon/intrinsics.c | 6 +++ .../v8.2a-neon-intrinsics-constrained.c | 41 +++++++++++++++++++ 6 files changed, 88 insertions(+), 2 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp index 7f504c3f717f2..e71c3e24af2a3 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp @@ -204,6 +204,16 @@ emitNeonCallToOp(CIRGenModule &cgm, CIRGenBuilderTy &builder, builder.getStringAttr(intrinsicName.value()), funcResTy, args) .getResult(); + } else if constexpr (std::is_same_v<Operation, cir::FMAOp>) { + assert(args.size() == 3 && "fma expects three operands"); + return Operation::create(builder, loc, funcResTy, args[0], args[1], args[2], + builder.getConstrainedFPAttr()) + .getResult(); + } else if constexpr (std::is_same_v<Operation, cir::SqrtOp>) { + assert(args.size() == 1 && "sqrt expects one operand"); + return Operation::create(builder, loc, funcResTy, args[0], + builder.getConstrainedFPAttr()) + .getResult(); } else { return Operation::create(builder, loc, funcResTy, args).getResult(); } @@ -2487,6 +2497,8 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr, // evaluation. assert(!cir::MissingFeatures::msvcBuiltins()); + CIRGenFPOptionsRAII fpOptsRAII(*this, expr); + // Some intrinsics are equivalent - if they are use the base intrinsic ID. auto it = llvm::find_if(neonEquivalentIntrinsicMap, [builtinID](auto &p) { return p.first == builtinID; @@ -3386,7 +3398,6 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr, } case NEON::BI__builtin_neon_vsqrt_v: case NEON::BI__builtin_neon_vsqrtq_v: - assert(!cir::MissingFeatures::emitConstrainedFPCall()); return emitNeonCallToOp<cir::SqrtOp>(cgm, builder, {ty}, ops, std::nullopt, ty, loc); case NEON::BI__builtin_neon_vrbit_v: diff --git a/clang/test/CodeGen/AArch64/neon/fullfp16.c b/clang/test/CodeGen/AArch64/neon/fullfp16.c index c17518eb813de..ffab85ee93fbb 100644 --- a/clang/test/CodeGen/AArch64/neon/fullfp16.c +++ b/clang/test/CodeGen/AArch64/neon/fullfp16.c @@ -3,6 +3,8 @@ // RUN: %clang_cc1_cg_arm64_neon -target-feature +fullfp16 -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg | FileCheck %s --check-prefixes=ALL,LLVM // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -target-feature +fullfp16 -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,simplifycfg | FileCheck %s --check-prefixes=ALL,LLVM %} // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -target-feature +fullfp16 -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefixes=ALL,CIR %} +// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -target-feature +fullfp16 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,simplifycfg | FileCheck %s --check-prefix=LLVM-STRICT --implicit-check-not=' @llvm.fma.' --implicit-check-not=' @llvm.sqrt.' %} +// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -target-feature +fullfp16 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefix=CIR-STRICT --implicit-check-not='cir.call_llvm_intrinsic "fma"' --implicit-check-not='cir.call_llvm_intrinsic "sqrt"' %} //============================================================================= // NOTES @@ -309,6 +311,10 @@ float16_t test_vrndxh_f16(float16_t a) { //===------------------------------------------------------===// // 2.5.1.4. Square root //===------------------------------------------------------===// +// LLVM-STRICT-LABEL: @test_vsqrth_f16( +// LLVM-STRICT: call half @llvm.experimental.constrained.sqrt.f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// CIR-STRICT-LABEL: cir.func {{.*}}@test_vsqrth_f16( +// CIR-STRICT: cir.sqrt %{{.*}} : !cir.f16 {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} // ALL-LABEL: test_vsqrth_f16 float16_t test_vsqrth_f16(float16_t a) { // CIR: cir.sqrt @@ -335,6 +341,10 @@ float16_t test_vnegh_f16(float16_t a) { //===------------------------------------------------------===// // 2.5.1.9.3 Fused multiply-accumulate //===------------------------------------------------------===// +// LLVM-STRICT-LABEL: @test_vfmah_f16( +// LLVM-STRICT: call half @llvm.experimental.constrained.fma.f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// CIR-STRICT-LABEL: cir.func {{.*}}@test_vfmah_f16( +// CIR-STRICT: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.f16 {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} // ALL-LABEL: test_vfmah_f16 float16_t test_vfmah_f16(float16_t a, float16_t b, float16_t c) { // CIR: cir.fma {{.*}} : !cir.f16 diff --git a/clang/test/CodeGen/AArch64/neon/fused-multiple-fullfp16.c b/clang/test/CodeGen/AArch64/neon/fused-multiple-fullfp16.c index 7231a1108a94f..30188ad3517b9 100644 --- a/clang/test/CodeGen/AArch64/neon/fused-multiple-fullfp16.c +++ b/clang/test/CodeGen/AArch64/neon/fused-multiple-fullfp16.c @@ -2,7 +2,7 @@ // RUN: %clang_cc1_cg_arm64_neon -target-feature +fullfp16 -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefixes=ALL,LLVM // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -target-feature +fullfp16 -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefixes=ALL,LLVM %} -// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -target-feature +fullfp16 -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefixes=ALL,CIR %} +// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -target-feature +fullfp16 -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefixes=ALL,CIR --implicit-check-not='cir.call_llvm_intrinsic "fma"' %} // ALL: {{[Mm]}}odule diff --git a/clang/test/CodeGen/AArch64/neon/fused-multiply.c b/clang/test/CodeGen/AArch64/neon/fused-multiply.c index 5d501d3f61734..bd1d842d7868a 100644 --- a/clang/test/CodeGen/AArch64/neon/fused-multiply.c +++ b/clang/test/CodeGen/AArch64/neon/fused-multiply.c @@ -3,6 +3,8 @@ // RUN: %clang_cc1_cg_arm64_neon -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefixes=ALL,LLVM // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefixes=ALL,LLVM %} // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefixes=ALL,CIR %} +// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefix=LLVM-STRICT --implicit-check-not=' @llvm.fma.' %} +// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefix=CIR-STRICT --implicit-check-not='cir.call_llvm_intrinsic "fma"' %} // ALL: {{[Mm]}}odule @@ -50,7 +52,11 @@ float32x2_t test_vfma_f32(float32x2_t a, float32x2_t b, float32x2_t c) { } // LLVM-LABEL: @test_vfma_f64( +// LLVM-STRICT-LABEL: @test_vfma_f64( +// LLVM-STRICT: call <1 x double> @llvm.experimental.constrained.fma.v1f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") // CIR-LABEL: @vfma_f64( +// CIR-STRICT-LABEL: cir.func {{.*}}@vfma_f64( +// CIR-STRICT: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<1 x !cir.double> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} float64x1_t test_vfma_f64(float64x1_t a, float64x1_t b, float64x1_t c) { // CIR: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<1 x !cir.double> @@ -222,6 +228,10 @@ float32x2_t test_vfma_laneq_f32(float32x2_t a, float32x2_t b, float32x4_t v) { } // ALL-LABEL: @test_vfma_laneq_f64( +// LLVM-STRICT-LABEL: @test_vfma_laneq_f64( +// LLVM-STRICT: call double @llvm.experimental.constrained.fma.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// CIR-STRICT-LABEL: cir.func {{.*}}@test_vfma_laneq_f64( +// CIR-STRICT: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} float64x1_t test_vfma_laneq_f64(float64x1_t a, float64x1_t b, float64x2_t v) { // CIR: [[LANE:%.*]] = cir.vec.extract %{{.*}}[%{{.*}} : !u64i] : !cir.vector<2 x !cir.double> @@ -291,6 +301,10 @@ float32x4_t test_vfmaq_laneq_f32(float32x4_t a, float32x4_t b, } // ALL-LABEL: @test_vfmaq_laneq_f64( +// LLVM-STRICT-LABEL: @test_vfmaq_laneq_f64( +// LLVM-STRICT: call <2 x double> @llvm.experimental.constrained.fma.v2f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// CIR-STRICT-LABEL: cir.func {{.*}}@test_vfmaq_laneq_f64( +// CIR-STRICT: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<2 x !cir.double> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} float64x2_t test_vfmaq_laneq_f64(float64x2_t a, float64x2_t b, float64x2_t v) { // CIR: [[LANE:%.*]] = cir.vec.shuffle(%{{.*}}, %{{.*}} : !cir.vector<2 x !cir.double>) [#cir.int<1> : !s32i, #cir.int<1> : !s32i] : !cir.vector<2 x !cir.double> @@ -357,6 +371,10 @@ float64x2_t test_vfmaq_laneq_f64_0(float64x2_t a, float64x2_t b, } // ALL-LABEL: @test_vfmas_lane_f32( +// LLVM-STRICT-LABEL: @test_vfmas_lane_f32( +// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// CIR-STRICT-LABEL: cir.func {{.*}}@test_vfmas_lane_f32( +// CIR-STRICT: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} float32_t test_vfmas_lane_f32(float32_t a, float32_t b, float32x2_t c) { // CIR: [[LANE:%.*]] = cir.vec.extract %{{.*}}[%{{.*}} : !u64i] : !cir.vector<2 x !cir.float> // CIR: cir.fma %{{.*}}, [[LANE]], %{{.*}} : !cir.float diff --git a/clang/test/CodeGen/AArch64/neon/intrinsics.c b/clang/test/CodeGen/AArch64/neon/intrinsics.c index 1393296648283..862572501eba1 100644 --- a/clang/test/CodeGen/AArch64/neon/intrinsics.c +++ b/clang/test/CodeGen/AArch64/neon/intrinsics.c @@ -3,6 +3,8 @@ // RUN: %clang_cc1_cg_arm64_neon -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefixes=ALL,LLVM // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefixes=ALL,LLVM %} // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefixes=ALL,CIR %} +// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefix=LLVM-STRICT --implicit-check-not=' @llvm.sqrt.' %} +// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefix=CIR-STRICT --implicit-check-not='cir.call_llvm_intrinsic "sqrt"' %} //============================================================================= // NOTES @@ -1790,7 +1792,11 @@ float64x1_t test_vsqrt_f64(float64x1_t a) { } // LLVM-LABEL: @test_vsqrtq_f64( +// LLVM-STRICT-LABEL: @test_vsqrtq_f64( +// LLVM-STRICT: call <2 x double> @llvm.experimental.constrained.sqrt.v2f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") // CIR-LABEL: @vsqrtq_f64( +// CIR-STRICT-LABEL: cir.func {{.*}}@vsqrtq_f64( +// CIR-STRICT: cir.sqrt %{{.*}} : !cir.vector<2 x !cir.double> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} float64x2_t test_vsqrtq_f64(float64x2_t a) { // CIR: cir.sqrt %{{.*}} : !cir.vector<2 x !cir.double> diff --git a/clang/test/CodeGen/AArch64/v8.2a-neon-intrinsics-constrained.c b/clang/test/CodeGen/AArch64/v8.2a-neon-intrinsics-constrained.c index dac8b931ff210..fb41b7012cf8f 100644 --- a/clang/test/CodeGen/AArch64/v8.2a-neon-intrinsics-constrained.c +++ b/clang/test/CodeGen/AArch64/v8.2a-neon-intrinsics-constrained.c @@ -8,6 +8,15 @@ // RUN: -flax-vector-conversions=none -disable-O0-optnone -emit-llvm -o - %s \ // RUN: | opt -S -passes=mem2reg,sroa \ // RUN: | FileCheck --check-prefix=CONSTRAINED --implicit-check-not=fpexcept.maytrap %s +// RUN: %if cir-enabled %{%clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -target-feature +fullfp16 -target-feature +v8.2a \ +// RUN: -fexperimental-strict-floating-point -ffp-exception-behavior=maytrap -DEXCEPT=1 \ +// RUN: -flax-vector-conversions=none -disable-O0-optnone -fclangir -emit-cir -o - %s \ +// RUN: | FileCheck --check-prefix=CIR --implicit-check-not='cir.call_llvm_intrinsic "fma"' --implicit-check-not='cir.call_llvm_intrinsic "sqrt"' %s %} +// RUN: %if cir-enabled %{%clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -target-feature +fullfp16 -target-feature +v8.2a \ +// RUN: -fexperimental-strict-floating-point -ffp-exception-behavior=maytrap -DEXCEPT=1 \ +// RUN: -flax-vector-conversions=none -disable-O0-optnone -fclangir -emit-llvm -o - %s \ +// RUN: | opt -S -passes=mem2reg,sroa \ +// RUN: | FileCheck --check-prefix=LLVM --implicit-check-not=fpexcept.maytrap --implicit-check-not=' @llvm.fma.' --implicit-check-not=' @llvm.sqrt.' %s %} // REQUIRES: aarch64-registered-target @@ -39,6 +48,10 @@ // CONSTRAINED-NEXT: [[VSQRT_I:%.*]] = call <4 x half> @llvm.experimental.constrained.sqrt.v4f16(<4 x half> [[TMP2]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2:[0-9]+]] // CONSTRAINED-NEXT: ret <4 x half> [[VSQRT_I]] // +// CIR-LABEL: cir.func {{.*}}@vsqrt_f16( +// CIR: cir.sqrt %{{.*}} : !cir.vector<4 x !cir.f16> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +// LLVM-LABEL: @test_vsqrt_f16( +// LLVM: call <4 x half> @llvm.experimental.constrained.sqrt.v4f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") float16x4_t test_vsqrt_f16(float16x4_t a) { return vsqrt_f16(a); } @@ -61,6 +74,10 @@ float16x4_t test_vsqrt_f16(float16x4_t a) { // CONSTRAINED-NEXT: [[VSQRT_I:%.*]] = call <8 x half> @llvm.experimental.constrained.sqrt.v8f16(<8 x half> [[TMP2]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]] // CONSTRAINED-NEXT: ret <8 x half> [[VSQRT_I]] // +// CIR-LABEL: cir.func {{.*}}@vsqrtq_f16( +// CIR: cir.sqrt %{{.*}} : !cir.vector<8 x !cir.f16> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +// LLVM-LABEL: @test_vsqrtq_f16( +// LLVM: call <8 x half> @llvm.experimental.constrained.sqrt.v8f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") float16x8_t test_vsqrtq_f16(float16x8_t a) { return vsqrtq_f16(a); } @@ -95,6 +112,10 @@ float16x8_t test_vsqrtq_f16(float16x8_t a) { // CONSTRAINED-NEXT: [[TMP9:%.*]] = call <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half> [[TMP7]], <4 x half> [[TMP8]], <4 x half> [[TMP6]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]] // CONSTRAINED-NEXT: ret <4 x half> [[TMP9]] // +// CIR-LABEL: cir.func {{.*}}@vfma_f16( +// CIR: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<4 x !cir.f16> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +// LLVM-LABEL: @test_vfma_f16( +// LLVM: call <4 x half> @llvm.experimental.constrained.fma.v4f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") float16x4_t test_vfma_f16(float16x4_t a, float16x4_t b, float16x4_t c) { return vfma_f16(a, b, c); } @@ -129,6 +150,10 @@ float16x4_t test_vfma_f16(float16x4_t a, float16x4_t b, float16x4_t c) { // CONSTRAINED-NEXT: [[TMP9:%.*]] = call <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half> [[TMP7]], <8 x half> [[TMP8]], <8 x half> [[TMP6]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]] // CONSTRAINED-NEXT: ret <8 x half> [[TMP9]] // +// CIR-LABEL: cir.func {{.*}}@vfmaq_f16( +// CIR: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<8 x !cir.f16> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +// LLVM-LABEL: @test_vfmaq_f16( +// LLVM: call <8 x half> @llvm.experimental.constrained.fma.v8f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") float16x8_t test_vfmaq_f16(float16x8_t a, float16x8_t b, float16x8_t c) { return vfmaq_f16(a, b, c); } @@ -237,6 +262,10 @@ float16x8_t test_vfmsq_f16(float16x8_t a, float16x8_t b, float16x8_t c) { // CONSTRAINED-NEXT: [[FMLA2:%.*]] = call <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half> [[FMLA]], <4 x half> [[LANE]], <4 x half> [[FMLA1]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]] // CONSTRAINED-NEXT: ret <4 x half> [[FMLA2]] // +// CIR-LABEL: cir.func {{.*}}@test_vfma_lane_f16( +// CIR: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<4 x !cir.f16> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +// LLVM-LABEL: @test_vfma_lane_f16( +// LLVM: call <4 x half> @llvm.experimental.constrained.fma.v4f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") float16x4_t test_vfma_lane_f16(float16x4_t a, float16x4_t b, float16x4_t c) { return vfma_lane_f16(a, b, c, 3); } @@ -309,6 +338,10 @@ float16x8_t test_vfmaq_lane_f16(float16x8_t a, float16x8_t b, float16x4_t c) { // CONSTRAINED-NEXT: [[TMP9:%.*]] = call <4 x half> @llvm.experimental.constrained.fma.v4f16(<4 x half> [[LANE]], <4 x half> [[TMP7]], <4 x half> [[TMP6]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]] // CONSTRAINED-NEXT: ret <4 x half> [[TMP9]] // +// CIR-LABEL: cir.func {{.*}}@test_vfma_laneq_f16( +// CIR: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<4 x !cir.f16> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +// LLVM-LABEL: @test_vfma_laneq_f16( +// LLVM: call <4 x half> @llvm.experimental.constrained.fma.v4f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") float16x4_t test_vfma_laneq_f16(float16x4_t a, float16x4_t b, float16x8_t c) { return vfma_laneq_f16(a, b, c, 7); } @@ -345,6 +378,10 @@ float16x4_t test_vfma_laneq_f16(float16x4_t a, float16x4_t b, float16x8_t c) { // CONSTRAINED-NEXT: [[TMP9:%.*]] = call <8 x half> @llvm.experimental.constrained.fma.v8f16(<8 x half> [[LANE]], <8 x half> [[TMP7]], <8 x half> [[TMP6]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]] // CONSTRAINED-NEXT: ret <8 x half> [[TMP9]] // +// CIR-LABEL: cir.func {{.*}}@test_vfmaq_laneq_f16( +// CIR: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<8 x !cir.f16> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +// LLVM-LABEL: @test_vfmaq_laneq_f16( +// LLVM: call <8 x half> @llvm.experimental.constrained.fma.v8f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") float16x8_t test_vfmaq_laneq_f16(float16x8_t a, float16x8_t b, float16x8_t c) { return vfmaq_laneq_f16(a, b, c, 7); } @@ -455,6 +492,10 @@ float16x8_t test_vfmaq_n_f16(float16x8_t a, float16x8_t b, float16_t c) { // CONSTRAINED-NEXT: [[TMP0:%.*]] = call half @llvm.experimental.constrained.fma.f16(half [[B]], half [[EXTRACT]], half [[A]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]] // CONSTRAINED-NEXT: ret half [[TMP0]] // +// CIR-LABEL: cir.func {{.*}}@test_vfmah_lane_f16( +// CIR: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.f16 {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +// LLVM-LABEL: @test_vfmah_lane_f16( +// LLVM: call half @llvm.experimental.constrained.fma.f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") float16_t test_vfmah_lane_f16(float16_t a, float16_t b, float16x4_t c) { return vfmah_lane_f16(a, b, c, 3); } >From 2b220b7c2d1cce3cbdda8820f9ceb2acd50065ad Mon Sep 17 00:00:00 2001 From: Yair Ben Avraham <[email protected]> Date: Wed, 26 Aug 2026 10:40:03 +0300 Subject: [PATCH 2/6] [CIR][AArch64] Avoid else after return --- clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp index e71c3e24af2a3..63013e0163f0f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp @@ -204,19 +204,23 @@ emitNeonCallToOp(CIRGenModule &cgm, CIRGenBuilderTy &builder, builder.getStringAttr(intrinsicName.value()), funcResTy, args) .getResult(); - } else if constexpr (std::is_same_v<Operation, cir::FMAOp>) { + } + if constexpr (std::is_same_v<Operation, cir::FMAOp>) { assert(args.size() == 3 && "fma expects three operands"); return Operation::create(builder, loc, funcResTy, args[0], args[1], args[2], builder.getConstrainedFPAttr()) .getResult(); - } else if constexpr (std::is_same_v<Operation, cir::SqrtOp>) { + } + if constexpr (std::is_same_v<Operation, cir::SqrtOp>) { assert(args.size() == 1 && "sqrt expects one operand"); return Operation::create(builder, loc, funcResTy, args[0], builder.getConstrainedFPAttr()) .getResult(); - } else { - return Operation::create(builder, loc, funcResTy, args).getResult(); } + if constexpr (!std::is_same_v<Operation, cir::LLVMIntrinsicCallOp> && + !std::is_same_v<Operation, cir::FMAOp> && + !std::is_same_v<Operation, cir::SqrtOp>) + return Operation::create(builder, loc, funcResTy, args).getResult(); } // TODO(cir): Remove `cgm` from the list of arguments once all NYI(s) are gone. >From 2e3b3dc80d1e175cf0d292acaef62765569d5b54 Mon Sep 17 00:00:00 2001 From: Yair Ben Avraham <[email protected]> Date: Wed, 26 Aug 2026 10:47:40 +0300 Subject: [PATCH 3/6] [CIR][AArch64] Move vfmas_lane_f32 constrained coverage Reuse the existing scalar indexed constrained test for CIR coverage. --- .../AArch64/neon-scalar-x-indexed-elem-constrained.c | 12 ++++++++++++ clang/test/CodeGen/AArch64/neon/fused-multiply.c | 4 ---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/clang/test/CodeGen/AArch64/neon-scalar-x-indexed-elem-constrained.c b/clang/test/CodeGen/AArch64/neon-scalar-x-indexed-elem-constrained.c index 944929ccb5f42..e4e16e4f9876c 100644 --- a/clang/test/CodeGen/AArch64/neon-scalar-x-indexed-elem-constrained.c +++ b/clang/test/CodeGen/AArch64/neon-scalar-x-indexed-elem-constrained.c @@ -6,6 +6,14 @@ // RUN: -ffp-exception-behavior=strict \ // RUN: -disable-O0-optnone -emit-llvm -o - %s | opt -S -passes=mem2reg,sroa \ // RUN: | FileCheck --check-prefix=CONSTRAINED %s +// RUN: %if cir-enabled %{%clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -target-cpu cyclone \ +// RUN: -fexperimental-strict-floating-point -ffp-exception-behavior=strict \ +// RUN: -disable-O0-optnone -fclangir -emit-llvm -o - %s | opt -S -passes=mem2reg,sroa \ +// RUN: | FileCheck --check-prefix=LLVM --implicit-check-not=' @llvm.fma.' %s %} +// RUN: %if cir-enabled %{%clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -target-cpu cyclone \ +// RUN: -fexperimental-strict-floating-point -ffp-exception-behavior=strict \ +// RUN: -disable-O0-optnone -fclangir -emit-cir -o - %s \ +// RUN: | FileCheck --check-prefix=CIR --implicit-check-not='cir.call_llvm_intrinsic "fma"' %s %} // REQUIRES: aarch64-registered-target @@ -27,6 +35,10 @@ // CONSTRAINED-NEXT: [[TMP0:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[B]], float [[EXTRACT]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2:[0-9]+]] // CONSTRAINED-NEXT: ret float [[TMP0]] // +// CIR-LABEL: cir.func {{.*}}@test_vfmas_lane_f32( +// CIR: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +// LLVM-LABEL: @test_vfmas_lane_f32( +// LLVM: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") float32_t test_vfmas_lane_f32(float32_t a, float32_t b, float32x2_t c) { return vfmas_lane_f32(a, b, c, 1); } diff --git a/clang/test/CodeGen/AArch64/neon/fused-multiply.c b/clang/test/CodeGen/AArch64/neon/fused-multiply.c index bd1d842d7868a..e5320d7172353 100644 --- a/clang/test/CodeGen/AArch64/neon/fused-multiply.c +++ b/clang/test/CodeGen/AArch64/neon/fused-multiply.c @@ -371,10 +371,6 @@ float64x2_t test_vfmaq_laneq_f64_0(float64x2_t a, float64x2_t b, } // ALL-LABEL: @test_vfmas_lane_f32( -// LLVM-STRICT-LABEL: @test_vfmas_lane_f32( -// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") -// CIR-STRICT-LABEL: cir.func {{.*}}@test_vfmas_lane_f32( -// CIR-STRICT: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} float32_t test_vfmas_lane_f32(float32_t a, float32_t b, float32x2_t c) { // CIR: [[LANE:%.*]] = cir.vec.extract %{{.*}}[%{{.*}} : !u64i] : !cir.vector<2 x !cir.float> // CIR: cir.fma %{{.*}}, [[LANE]], %{{.*}} : !cir.float >From fece847dd13c3396c92953fcfd619484f20e6e5e Mon Sep 17 00:00:00 2001 From: Yair Ben Avraham <[email protected]> Date: Fri, 28 Aug 2026 13:20:46 +0300 Subject: [PATCH 4/6] [CIR][AArch64] Move laneq FMA constrained coverage Reuse the existing scalar indexed constrained test for the remaining f64 laneq FMA coverage. --- .../neon-scalar-x-indexed-elem-constrained.c | 46 ++++++++++++++++++- .../CodeGen/AArch64/neon/fused-multiply.c | 8 ---- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/clang/test/CodeGen/AArch64/neon-scalar-x-indexed-elem-constrained.c b/clang/test/CodeGen/AArch64/neon-scalar-x-indexed-elem-constrained.c index e4e16e4f9876c..c8aab578b110a 100644 --- a/clang/test/CodeGen/AArch64/neon-scalar-x-indexed-elem-constrained.c +++ b/clang/test/CodeGen/AArch64/neon-scalar-x-indexed-elem-constrained.c @@ -223,10 +223,55 @@ float64x1_t test_vfms_lane_f64(float64x1_t a, float64x1_t b, float64x1_t v) { // CONSTRAINED-NEXT: [[TMP10:%.*]] = bitcast double [[TMP9]] to <1 x double> // CONSTRAINED-NEXT: ret <1 x double> [[TMP10]] // +// CIR-LABEL: cir.func {{.*}}@test_vfma_laneq_f64( +// CIR: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +// LLVM-LABEL: @test_vfma_laneq_f64( +// LLVM: call double @llvm.experimental.constrained.fma.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") float64x1_t test_vfma_laneq_f64(float64x1_t a, float64x1_t b, float64x2_t v) { return vfma_laneq_f64(a, b, v, 0); } +// UNCONSTRAINED-LABEL: define dso_local <2 x double> @test_vfmaq_laneq_f64( +// UNCONSTRAINED-SAME: <2 x double> noundef [[A:%.*]], <2 x double> noundef [[B:%.*]], <2 x double> noundef [[V:%.*]]) #[[ATTR0]] { +// UNCONSTRAINED-NEXT: [[ENTRY:.*:]] +// UNCONSTRAINED-NEXT: [[TMP0:%.*]] = bitcast <2 x double> [[A]] to <2 x i64> +// UNCONSTRAINED-NEXT: [[TMP1:%.*]] = bitcast <2 x double> [[B]] to <2 x i64> +// UNCONSTRAINED-NEXT: [[TMP2:%.*]] = bitcast <2 x double> [[V]] to <2 x i64> +// UNCONSTRAINED-NEXT: [[TMP3:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8> +// UNCONSTRAINED-NEXT: [[TMP4:%.*]] = bitcast <2 x i64> [[TMP1]] to <16 x i8> +// UNCONSTRAINED-NEXT: [[TMP5:%.*]] = bitcast <2 x i64> [[TMP2]] to <16 x i8> +// UNCONSTRAINED-NEXT: [[TMP6:%.*]] = bitcast <16 x i8> [[TMP3]] to <2 x double> +// UNCONSTRAINED-NEXT: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <2 x double> +// UNCONSTRAINED-NEXT: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <2 x double> +// UNCONSTRAINED-NEXT: [[LANE:%.*]] = shufflevector <2 x double> [[TMP8]], <2 x double> [[TMP8]], <2 x i32> <i32 1, i32 1> +// UNCONSTRAINED-NEXT: [[TMP9:%.*]] = call <2 x double> @llvm.fma.v2f64(<2 x double> [[LANE]], <2 x double> [[TMP7]], <2 x double> [[TMP6]]) +// UNCONSTRAINED-NEXT: ret <2 x double> [[TMP9]] +// +// CONSTRAINED-LABEL: define dso_local <2 x double> @test_vfmaq_laneq_f64( +// CONSTRAINED-SAME: <2 x double> noundef [[A:%.*]], <2 x double> noundef [[B:%.*]], <2 x double> noundef [[V:%.*]]) #[[ATTR0]] { +// CONSTRAINED-NEXT: [[ENTRY:.*:]] +// CONSTRAINED-NEXT: [[TMP0:%.*]] = bitcast <2 x double> [[A]] to <2 x i64> +// CONSTRAINED-NEXT: [[TMP1:%.*]] = bitcast <2 x double> [[B]] to <2 x i64> +// CONSTRAINED-NEXT: [[TMP2:%.*]] = bitcast <2 x double> [[V]] to <2 x i64> +// CONSTRAINED-NEXT: [[TMP3:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8> +// CONSTRAINED-NEXT: [[TMP4:%.*]] = bitcast <2 x i64> [[TMP1]] to <16 x i8> +// CONSTRAINED-NEXT: [[TMP5:%.*]] = bitcast <2 x i64> [[TMP2]] to <16 x i8> +// CONSTRAINED-NEXT: [[TMP6:%.*]] = bitcast <16 x i8> [[TMP3]] to <2 x double> +// CONSTRAINED-NEXT: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <2 x double> +// CONSTRAINED-NEXT: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <2 x double> +// CONSTRAINED-NEXT: [[LANE:%.*]] = shufflevector <2 x double> [[TMP8]], <2 x double> [[TMP8]], <2 x i32> <i32 1, i32 1> +// CONSTRAINED-NEXT: [[TMP9:%.*]] = call <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double> [[LANE]], <2 x double> [[TMP7]], <2 x double> [[TMP6]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]] +// CONSTRAINED-NEXT: ret <2 x double> [[TMP9]] +// +// CIR-LABEL: cir.func {{.*}}@test_vfmaq_laneq_f64( +// CIR: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<2 x !cir.double> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +// LLVM-LABEL: @test_vfmaq_laneq_f64( +// LLVM: call <2 x double> @llvm.experimental.constrained.fma.v2f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +float64x2_t test_vfmaq_laneq_f64(float64x2_t a, float64x2_t b, + float64x2_t v) { + return vfmaq_laneq_f64(a, b, v, 1); +} + // UNCONSTRAINED-LABEL: define dso_local <1 x double> @test_vfms_laneq_f64( // UNCONSTRAINED-SAME: <1 x double> noundef [[A:%.*]], <1 x double> noundef [[B:%.*]], <2 x double> noundef [[V:%.*]]) #[[ATTR0]] { // UNCONSTRAINED-NEXT: [[ENTRY:.*:]] @@ -270,4 +315,3 @@ float64x1_t test_vfma_laneq_f64(float64x1_t a, float64x1_t b, float64x2_t v) { float64x1_t test_vfms_laneq_f64(float64x1_t a, float64x1_t b, float64x2_t v) { return vfms_laneq_f64(a, b, v, 0); } - diff --git a/clang/test/CodeGen/AArch64/neon/fused-multiply.c b/clang/test/CodeGen/AArch64/neon/fused-multiply.c index e5320d7172353..4873abfd96eab 100644 --- a/clang/test/CodeGen/AArch64/neon/fused-multiply.c +++ b/clang/test/CodeGen/AArch64/neon/fused-multiply.c @@ -228,10 +228,6 @@ float32x2_t test_vfma_laneq_f32(float32x2_t a, float32x2_t b, float32x4_t v) { } // ALL-LABEL: @test_vfma_laneq_f64( -// LLVM-STRICT-LABEL: @test_vfma_laneq_f64( -// LLVM-STRICT: call double @llvm.experimental.constrained.fma.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") -// CIR-STRICT-LABEL: cir.func {{.*}}@test_vfma_laneq_f64( -// CIR-STRICT: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} float64x1_t test_vfma_laneq_f64(float64x1_t a, float64x1_t b, float64x2_t v) { // CIR: [[LANE:%.*]] = cir.vec.extract %{{.*}}[%{{.*}} : !u64i] : !cir.vector<2 x !cir.double> @@ -301,10 +297,6 @@ float32x4_t test_vfmaq_laneq_f32(float32x4_t a, float32x4_t b, } // ALL-LABEL: @test_vfmaq_laneq_f64( -// LLVM-STRICT-LABEL: @test_vfmaq_laneq_f64( -// LLVM-STRICT: call <2 x double> @llvm.experimental.constrained.fma.v2f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") -// CIR-STRICT-LABEL: cir.func {{.*}}@test_vfmaq_laneq_f64( -// CIR-STRICT: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<2 x !cir.double> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} float64x2_t test_vfmaq_laneq_f64(float64x2_t a, float64x2_t b, float64x2_t v) { // CIR: [[LANE:%.*]] = cir.vec.shuffle(%{{.*}}, %{{.*}} : !cir.vector<2 x !cir.double>) [#cir.int<1> : !s32i, #cir.int<1> : !s32i] : !cir.vector<2 x !cir.double> >From 771593b25077966836baea86ddc794f6fc351e1c Mon Sep 17 00:00:00 2001 From: Yair Ben Avraham <[email protected]> Date: Fri, 28 Aug 2026 13:33:51 +0300 Subject: [PATCH 5/6] [CIR][AArch64] Move scalar FP16 constrained coverage Reuse the existing v8.2a Neon constrained test for strict scalar FP16 FMA and square-root coverage. --- clang/test/CodeGen/AArch64/neon/fullfp16.c | 10 ---- .../v8.2a-neon-intrinsics-constrained.c | 50 +++++++++++++++++++ 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/clang/test/CodeGen/AArch64/neon/fullfp16.c b/clang/test/CodeGen/AArch64/neon/fullfp16.c index ffab85ee93fbb..c17518eb813de 100644 --- a/clang/test/CodeGen/AArch64/neon/fullfp16.c +++ b/clang/test/CodeGen/AArch64/neon/fullfp16.c @@ -3,8 +3,6 @@ // RUN: %clang_cc1_cg_arm64_neon -target-feature +fullfp16 -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg | FileCheck %s --check-prefixes=ALL,LLVM // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -target-feature +fullfp16 -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,simplifycfg | FileCheck %s --check-prefixes=ALL,LLVM %} // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -target-feature +fullfp16 -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefixes=ALL,CIR %} -// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -target-feature +fullfp16 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,simplifycfg | FileCheck %s --check-prefix=LLVM-STRICT --implicit-check-not=' @llvm.fma.' --implicit-check-not=' @llvm.sqrt.' %} -// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -target-feature +fullfp16 -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefix=CIR-STRICT --implicit-check-not='cir.call_llvm_intrinsic "fma"' --implicit-check-not='cir.call_llvm_intrinsic "sqrt"' %} //============================================================================= // NOTES @@ -311,10 +309,6 @@ float16_t test_vrndxh_f16(float16_t a) { //===------------------------------------------------------===// // 2.5.1.4. Square root //===------------------------------------------------------===// -// LLVM-STRICT-LABEL: @test_vsqrth_f16( -// LLVM-STRICT: call half @llvm.experimental.constrained.sqrt.f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") -// CIR-STRICT-LABEL: cir.func {{.*}}@test_vsqrth_f16( -// CIR-STRICT: cir.sqrt %{{.*}} : !cir.f16 {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} // ALL-LABEL: test_vsqrth_f16 float16_t test_vsqrth_f16(float16_t a) { // CIR: cir.sqrt @@ -341,10 +335,6 @@ float16_t test_vnegh_f16(float16_t a) { //===------------------------------------------------------===// // 2.5.1.9.3 Fused multiply-accumulate //===------------------------------------------------------===// -// LLVM-STRICT-LABEL: @test_vfmah_f16( -// LLVM-STRICT: call half @llvm.experimental.constrained.fma.f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") -// CIR-STRICT-LABEL: cir.func {{.*}}@test_vfmah_f16( -// CIR-STRICT: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.f16 {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} // ALL-LABEL: test_vfmah_f16 float16_t test_vfmah_f16(float16_t a, float16_t b, float16_t c) { // CIR: cir.fma {{.*}} : !cir.f16 diff --git a/clang/test/CodeGen/AArch64/v8.2a-neon-intrinsics-constrained.c b/clang/test/CodeGen/AArch64/v8.2a-neon-intrinsics-constrained.c index fb41b7012cf8f..e9aece9dfa75f 100644 --- a/clang/test/CodeGen/AArch64/v8.2a-neon-intrinsics-constrained.c +++ b/clang/test/CodeGen/AArch64/v8.2a-neon-intrinsics-constrained.c @@ -17,6 +17,15 @@ // RUN: -flax-vector-conversions=none -disable-O0-optnone -fclangir -emit-llvm -o - %s \ // RUN: | opt -S -passes=mem2reg,sroa \ // RUN: | FileCheck --check-prefix=LLVM --implicit-check-not=fpexcept.maytrap --implicit-check-not=' @llvm.fma.' --implicit-check-not=' @llvm.sqrt.' %s %} +// RUN: %if cir-enabled %{%clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -target-feature +fullfp16 -target-feature +v8.2a \ +// RUN: -fexperimental-strict-floating-point -ffp-exception-behavior=strict \ +// RUN: -flax-vector-conversions=none -disable-O0-optnone -fclangir -emit-cir -o - %s \ +// RUN: | FileCheck --check-prefix=CIR --implicit-check-not='cir.call_llvm_intrinsic "fma"' --implicit-check-not='cir.call_llvm_intrinsic "sqrt"' %s %} +// RUN: %if cir-enabled %{%clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -target-feature +fullfp16 -target-feature +v8.2a \ +// RUN: -fexperimental-strict-floating-point -ffp-exception-behavior=strict \ +// RUN: -flax-vector-conversions=none -disable-O0-optnone -fclangir -emit-llvm -o - %s \ +// RUN: | opt -S -passes=mem2reg,sroa \ +// RUN: | FileCheck --check-prefix=LLVM --implicit-check-not=' @llvm.fma.' --implicit-check-not=' @llvm.sqrt.' %s %} // REQUIRES: aarch64-registered-target @@ -28,8 +37,29 @@ #pragma float_control(except, on) #endif +#include <arm_fp16.h> #include <arm_neon.h> +// UNCONSTRAINED-LABEL: define dso_local half @test_vsqrth_f16( +// UNCONSTRAINED-SAME: half noundef [[A:%.*]]) #[[ATTR0:[0-9]+]] { +// UNCONSTRAINED-NEXT: [[ENTRY:.*:]] +// UNCONSTRAINED-NEXT: [[SQR:%.*]] = call half @llvm.sqrt.f16(half [[A]]) +// UNCONSTRAINED-NEXT: ret half [[SQR]] +// +// CONSTRAINED-LABEL: define dso_local half @test_vsqrth_f16( +// CONSTRAINED-SAME: half noundef [[A:%.*]]) #[[ATTR0:[0-9]+]] { +// CONSTRAINED-NEXT: [[ENTRY:.*:]] +// CONSTRAINED-NEXT: [[SQR:%.*]] = call half @llvm.experimental.constrained.sqrt.f16(half [[A]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2:[0-9]+]] +// CONSTRAINED-NEXT: ret half [[SQR]] +// +// CIR-LABEL: cir.func {{.*}}@test_vsqrth_f16( +// CIR: cir.sqrt %{{.*}} : !cir.f16 {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +// LLVM-LABEL: @test_vsqrth_f16( +// LLVM: call half @llvm.experimental.constrained.sqrt.f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +float16_t test_vsqrth_f16(float16_t a) { + return vsqrth_f16(a); +} + // UNCONSTRAINED-LABEL: define dso_local <4 x half> @test_vsqrt_f16( // UNCONSTRAINED-SAME: <4 x half> noundef [[A:%.*]]) #[[ATTR0:[0-9]+]] { // UNCONSTRAINED-NEXT: [[ENTRY:.*:]] @@ -158,6 +188,26 @@ float16x8_t test_vfmaq_f16(float16x8_t a, float16x8_t b, float16x8_t c) { return vfmaq_f16(a, b, c); } +// UNCONSTRAINED-LABEL: define dso_local half @test_vfmah_f16( +// UNCONSTRAINED-SAME: half noundef [[A:%.*]], half noundef [[B:%.*]], half noundef [[C:%.*]]) #[[ATTR0]] { +// UNCONSTRAINED-NEXT: [[ENTRY:.*:]] +// UNCONSTRAINED-NEXT: [[FMA:%.*]] = call half @llvm.fma.f16(half [[B]], half [[C]], half [[A]]) +// UNCONSTRAINED-NEXT: ret half [[FMA]] +// +// CONSTRAINED-LABEL: define dso_local half @test_vfmah_f16( +// CONSTRAINED-SAME: half noundef [[A:%.*]], half noundef [[B:%.*]], half noundef [[C:%.*]]) #[[ATTR0]] { +// CONSTRAINED-NEXT: [[ENTRY:.*:]] +// CONSTRAINED-NEXT: [[FMA:%.*]] = call half @llvm.experimental.constrained.fma.f16(half [[B]], half [[C]], half [[A]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]] +// CONSTRAINED-NEXT: ret half [[FMA]] +// +// CIR-LABEL: cir.func {{.*}}@test_vfmah_f16( +// CIR: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.f16 {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +// LLVM-LABEL: @test_vfmah_f16( +// LLVM: call half @llvm.experimental.constrained.fma.f16({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +float16_t test_vfmah_f16(float16_t a, float16_t b, float16_t c) { + return vfmah_f16(a, b, c); +} + // UNCONSTRAINED-LABEL: define dso_local <4 x half> @test_vfms_f16( // UNCONSTRAINED-SAME: <4 x half> noundef [[A:%.*]], <4 x half> noundef [[B:%.*]], <4 x half> noundef [[C:%.*]]) #[[ATTR0]] { // UNCONSTRAINED-NEXT: [[ENTRY:.*:]] >From 8cbe19fc19d2490e2c362f568e695cbfeacc8590 Mon Sep 17 00:00:00 2001 From: Yair Ben Avraham <[email protected]> Date: Fri, 28 Aug 2026 13:48:02 +0300 Subject: [PATCH 6/6] [CIR][AArch64] Move FMA and sqrt constrained coverage Move strict vfma_f64 and vsqrtq_f64 CIR coverage out of the ordinary Neon tests and into a focused constrained test. The existing legacy constrained files cannot run through CIR as a whole because they contain unrelated AArch64 builtins that CIR does not yet lower. --- .../AArch64/neon/fma-sqrt-constrained.c | 22 +++++++++++++++++++ .../CodeGen/AArch64/neon/fused-multiply.c | 6 ----- clang/test/CodeGen/AArch64/neon/intrinsics.c | 6 ----- 3 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 clang/test/CodeGen/AArch64/neon/fma-sqrt-constrained.c diff --git a/clang/test/CodeGen/AArch64/neon/fma-sqrt-constrained.c b/clang/test/CodeGen/AArch64/neon/fma-sqrt-constrained.c new file mode 100644 index 0000000000000..8665bc39226d7 --- /dev/null +++ b/clang/test/CodeGen/AArch64/neon/fma-sqrt-constrained.c @@ -0,0 +1,22 @@ +// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefix=LLVM --implicit-check-not=' @llvm.fma.' --implicit-check-not=' @llvm.sqrt.' %} +// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefix=CIR --implicit-check-not='cir.call_llvm_intrinsic "fma"' --implicit-check-not='cir.call_llvm_intrinsic "sqrt"' %} + +// REQUIRES: aarch64-registered-target + +#include <arm_neon.h> + +// LLVM-LABEL: @test_vfma_f64( +// LLVM: call <1 x double> @llvm.experimental.constrained.fma.v1f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// CIR-LABEL: cir.func {{.*}}@test_vfma_f64( +// CIR: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<1 x !cir.double> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +float64x1_t test_vfma_f64(float64x1_t a, float64x1_t b, float64x1_t c) { + return vfma_f64(a, b, c); +} + +// LLVM-LABEL: @test_vsqrtq_f64( +// LLVM: call <2 x double> @llvm.experimental.constrained.sqrt.v2f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") +// CIR-LABEL: cir.func {{.*}}@test_vsqrtq_f64( +// CIR: cir.sqrt %{{.*}} : !cir.vector<2 x !cir.double> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} +float64x2_t test_vsqrtq_f64(float64x2_t a) { + return vsqrtq_f64(a); +} diff --git a/clang/test/CodeGen/AArch64/neon/fused-multiply.c b/clang/test/CodeGen/AArch64/neon/fused-multiply.c index 4873abfd96eab..5d501d3f61734 100644 --- a/clang/test/CodeGen/AArch64/neon/fused-multiply.c +++ b/clang/test/CodeGen/AArch64/neon/fused-multiply.c @@ -3,8 +3,6 @@ // RUN: %clang_cc1_cg_arm64_neon -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefixes=ALL,LLVM // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefixes=ALL,LLVM %} // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefixes=ALL,CIR %} -// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefix=LLVM-STRICT --implicit-check-not=' @llvm.fma.' %} -// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefix=CIR-STRICT --implicit-check-not='cir.call_llvm_intrinsic "fma"' %} // ALL: {{[Mm]}}odule @@ -52,11 +50,7 @@ float32x2_t test_vfma_f32(float32x2_t a, float32x2_t b, float32x2_t c) { } // LLVM-LABEL: @test_vfma_f64( -// LLVM-STRICT-LABEL: @test_vfma_f64( -// LLVM-STRICT: call <1 x double> @llvm.experimental.constrained.fma.v1f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") // CIR-LABEL: @vfma_f64( -// CIR-STRICT-LABEL: cir.func {{.*}}@vfma_f64( -// CIR-STRICT: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<1 x !cir.double> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} float64x1_t test_vfma_f64(float64x1_t a, float64x1_t b, float64x1_t c) { // CIR: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<1 x !cir.double> diff --git a/clang/test/CodeGen/AArch64/neon/intrinsics.c b/clang/test/CodeGen/AArch64/neon/intrinsics.c index 862572501eba1..1393296648283 100644 --- a/clang/test/CodeGen/AArch64/neon/intrinsics.c +++ b/clang/test/CodeGen/AArch64/neon/intrinsics.c @@ -3,8 +3,6 @@ // RUN: %clang_cc1_cg_arm64_neon -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefixes=ALL,LLVM // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefixes=ALL,LLVM %} // RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefixes=ALL,CIR %} -// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-llvm %s -disable-O0-optnone | opt -S -passes=mem2reg,sroa | FileCheck %s --check-prefix=LLVM-STRICT --implicit-check-not=' @llvm.sqrt.' %} -// RUN: %if cir-enabled %{%clang_cc1_cg_arm64_neon -fexperimental-strict-floating-point -ffp-exception-behavior=strict -fclangir -emit-cir %s -disable-O0-optnone | FileCheck %s --check-prefix=CIR-STRICT --implicit-check-not='cir.call_llvm_intrinsic "sqrt"' %} //============================================================================= // NOTES @@ -1792,11 +1790,7 @@ float64x1_t test_vsqrt_f64(float64x1_t a) { } // LLVM-LABEL: @test_vsqrtq_f64( -// LLVM-STRICT-LABEL: @test_vsqrtq_f64( -// LLVM-STRICT: call <2 x double> @llvm.experimental.constrained.sqrt.v2f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") // CIR-LABEL: @vsqrtq_f64( -// CIR-STRICT-LABEL: cir.func {{.*}}@vsqrtq_f64( -// CIR-STRICT: cir.sqrt %{{.*}} : !cir.vector<2 x !cir.double> {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>} float64x2_t test_vsqrtq_f64(float64x2_t a) { // CIR: cir.sqrt %{{.*}} : !cir.vector<2 x !cir.double> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
