[clang] 7139d0b - [AArch64] Add intrinsic support for Fdot instr. (#189987)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 2 04:17:08 PDT 2026
Author: Lukacma
Date: 2026-06-02T12:17:02+01:00
New Revision: 7139d0b46f6d71334b74049bbd540ac4b18a1bc5
URL: https://github.com/llvm/llvm-project/commit/7139d0b46f6d71334b74049bbd540ac4b18a1bc5
DIFF: https://github.com/llvm/llvm-project/commit/7139d0b46f6d71334b74049bbd540ac4b18a1bc5.diff
LOG: [AArch64] Add intrinsic support for Fdot instr. (#189987)
This patch adds intrinsics for new NEON Fdot instruction variants. The
implementation is based on the
[proposal](https://github.com/ARM-software/acle/pull/428) and adds these
ACLE builtins:
```
float32x2_t vdot_f32_f16(float32x2_t r, float16x4_t a, float16x4_t b);
float32x4_t vdotq_f32_f16(float32x4_t r, float16x8_t a, float16x8_t b);
float32x2_t vdot_lane_f32_f16(float32x2_t r, float16x4_t a, float16x4_t b, const int lane);
float32x4_t vdotq_laneq_f32_f16(float32x4_t r, float16x8_t a, float16x8_t b, const int lane);
float32x2_t vdot_laneq_f32_f16(float32x2_t r, float16x4_t a, float16x8_t b, const int lane);
float32x4_t vdotq_lane_f32_f16(float32x4_t r, float16x8_t a, float16x4_t b, const int lane);
```
Added:
clang/test/CodeGen/AArch64/f16f32dot-intrinsics.c
llvm/test/CodeGen/AArch64/aarch64-f16f32dot-intrinsics.ll
Modified:
clang/include/clang/Basic/arm_neon.td
clang/lib/CodeGen/TargetBuiltins/ARM.cpp
clang/test/Sema/aarch64-neon-immediate-ranges/dotprod.c
llvm/include/llvm/IR/IntrinsicsAArch64.td
llvm/lib/Target/AArch64/AArch64InstrFormats.td
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/arm_neon.td b/clang/include/clang/Basic/arm_neon.td
index 9aad18c1b8750..3bf140ff953b9 100644
--- a/clang/include/clang/Basic/arm_neon.td
+++ b/clang/include/clang/Basic/arm_neon.td
@@ -1903,6 +1903,14 @@ let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "d
def UDOT_LANEQ : SOpInst<"vdot_laneq", "..(<<)(<<Q)I", "iUiQiQUi", OP_DOT_LNQ>;
}
+let ArchGuard = "defined(__aarch64__)", TargetGuard = "f16f32dot,neon" in {
+ def VDOT_F16 : SInst<"vdot_f32", ">>..", "hQh">;
+ def VDOT_LANE_F16 : SInst<"vdot_lane_f32", ">>.qI", "hQh",
+ [ImmCheck<3, ImmCheckLaneIndex, 2>]>;
+ def VDOT_LANEQ_F16 : SInst<"vdot_laneq_f32", ">>.QI", "hQh",
+ [ImmCheck<3, ImmCheckLaneIndex, 2>]>;
+}
+
// v8.2-A FP16 fused multiply-add long instructions.
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "fp16fml,neon" in {
def VFMLAL_LOW : SInst<"vfmlal_low", ">>..", "hQh">;
diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
index 8f78f3126f707..bd4001744b512 100644
--- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
@@ -7116,6 +7116,34 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
return EmitFP8NeonFDOTCall(Intrinsic::aarch64_neon_fp8_fdot4_lane,
ExtendLaneArg, FloatTy, Ops, E, "fdot4_lane");
+ case NEON::BI__builtin_neon_vdot_f32_f16:
+ case NEON::BI__builtin_neon_vdotq_f32_f16: {
+ llvm::Type *InputTy =
+ llvm::FixedVectorType::get(HalfTy, Ty->getPrimitiveSizeInBits() / 16);
+ llvm::Type *Tys[2] = {Ty, InputTy};
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_fdot, Tys),
+ Ops, "vdot");
+ }
+
+ case NEON::BI__builtin_neon_vdot_lane_f32_f16:
+ case NEON::BI__builtin_neon_vdot_laneq_f32_f16:
+ case NEON::BI__builtin_neon_vdotq_lane_f32_f16:
+ case NEON::BI__builtin_neon_vdotq_laneq_f32_f16: {
+ llvm::FixedVectorType *InputTy =
+ llvm::FixedVectorType::get(HalfTy, Ty->getPrimitiveSizeInBits() / 16);
+ llvm::FixedVectorType *LaneTy = llvm::FixedVectorType::get(
+ HalfTy, Ops[2]->getType()->getPrimitiveSizeInBits() / 16);
+ // Treat the lane argument as a splat and use non-lane version of the
+ // intrinsic.
+ Ops[2] = Builder.CreateBitCast(Ops[2], LaneTy);
+ Ops[2] = EmitNeonSplat(Ops[2], cast<ConstantInt>(Ops[3]),
+ InputTy->getElementCount());
+ llvm::Type *Tys[2] = {Ty, InputTy};
+ Ops.pop_back();
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_fdot, Tys),
+ Ops, "vdot");
+ }
+
case NEON::BI__builtin_neon_vmlalbq_f16_mf8_fpm:
return EmitFP8NeonCall(Intrinsic::aarch64_neon_fp8_fmlalb,
{llvm::FixedVectorType::get(HalfTy, 8)}, Ops, E,
diff --git a/clang/test/CodeGen/AArch64/f16f32dot-intrinsics.c b/clang/test/CodeGen/AArch64/f16f32dot-intrinsics.c
new file mode 100644
index 0000000000000..763a8228680f9
--- /dev/null
+++ b/clang/test/CodeGen/AArch64/f16f32dot-intrinsics.c
@@ -0,0 +1,112 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon -target-feature +f16f32dot -disable-O0-optnone -emit-llvm -o - %s | opt -S -passes=mem2reg,sroa,instcombine | FileCheck %s
+// RUN: %clang_cc1 -x c++ -triple aarch64-none-linux-gnu -target-feature +neon -target-feature +f16f32dot -disable-O0-optnone -emit-llvm -o - %s | opt -S -passes=mem2reg,sroa,instcombine | FileCheck %s -check-prefix CHECK-CXX
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon -target-feature +f16f32dot -O3 -S -o /dev/null %s
+
+// REQUIRES: aarch64-registered-target
+
+#include <arm_neon.h>
+
+// CHECK-LABEL: define dso_local <2 x float> @test_vdot_f32_f16(
+// CHECK-SAME: <2 x float> noundef [[R:%.*]], <4 x half> noundef [[A:%.*]], <4 x half> noundef [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[VDOT3_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fdot.v2f32.v4f16(<2 x float> [[R]], <4 x half> [[A]], <4 x half> [[B]])
+// CHECK-NEXT: ret <2 x float> [[VDOT3_I]]
+//
+// CHECK-CXX-LABEL: define dso_local noundef <2 x float> @_Z17test_vdot_f32_f1613__Float32x2_t13__Float16x4_tS0_(
+// CHECK-CXX-SAME: <2 x float> noundef [[R:%.*]], <4 x half> noundef [[A:%.*]], <4 x half> noundef [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-CXX-NEXT: [[ENTRY:.*:]]
+// CHECK-CXX-NEXT: [[VDOT3_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fdot.v2f32.v4f16(<2 x float> [[R]], <4 x half> [[A]], <4 x half> [[B]])
+// CHECK-CXX-NEXT: ret <2 x float> [[VDOT3_I]]
+//
+float32x2_t test_vdot_f32_f16(float32x2_t r, float16x4_t a, float16x4_t b) {
+ return vdot_f32_f16(r, a, b);
+}
+
+// CHECK-LABEL: define dso_local <4 x float> @test_vdotq_f32_f16(
+// CHECK-SAME: <4 x float> noundef [[R:%.*]], <8 x half> noundef [[A:%.*]], <8 x half> noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[VDOT3_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fdot.v4f32.v8f16(<4 x float> [[R]], <8 x half> [[A]], <8 x half> [[B]])
+// CHECK-NEXT: ret <4 x float> [[VDOT3_I]]
+//
+// CHECK-CXX-LABEL: define dso_local noundef <4 x float> @_Z18test_vdotq_f32_f1613__Float32x4_t13__Float16x8_tS0_(
+// CHECK-CXX-SAME: <4 x float> noundef [[R:%.*]], <8 x half> noundef [[A:%.*]], <8 x half> noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-CXX-NEXT: [[ENTRY:.*:]]
+// CHECK-CXX-NEXT: [[VDOT3_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fdot.v4f32.v8f16(<4 x float> [[R]], <8 x half> [[A]], <8 x half> [[B]])
+// CHECK-CXX-NEXT: ret <4 x float> [[VDOT3_I]]
+//
+float32x4_t test_vdotq_f32_f16(float32x4_t r, float16x8_t a, float16x8_t b) {
+ return vdotq_f32_f16(r, a, b);
+}
+
+// CHECK-LABEL: define dso_local <2 x float> @test_vdot_lane_f32_f16(
+// CHECK-SAME: <2 x float> noundef [[R:%.*]], <4 x half> noundef [[A:%.*]], <4 x half> noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[LANE:%.*]] = shufflevector <4 x half> [[B]], <4 x half> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT: [[VDOT2:%.*]] = call <2 x float> @llvm.aarch64.neon.fdot.v2f32.v4f16(<2 x float> [[R]], <4 x half> [[A]], <4 x half> [[LANE]])
+// CHECK-NEXT: ret <2 x float> [[VDOT2]]
+//
+// CHECK-CXX-LABEL: define dso_local noundef <2 x float> @_Z22test_vdot_lane_f32_f1613__Float32x2_t13__Float16x4_tS0_(
+// CHECK-CXX-SAME: <2 x float> noundef [[R:%.*]], <4 x half> noundef [[A:%.*]], <4 x half> noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-CXX-NEXT: [[ENTRY:.*:]]
+// CHECK-CXX-NEXT: [[LANE:%.*]] = shufflevector <4 x half> [[B]], <4 x half> poison, <4 x i32> zeroinitializer
+// CHECK-CXX-NEXT: [[VDOT2:%.*]] = call <2 x float> @llvm.aarch64.neon.fdot.v2f32.v4f16(<2 x float> [[R]], <4 x half> [[A]], <4 x half> [[LANE]])
+// CHECK-CXX-NEXT: ret <2 x float> [[VDOT2]]
+//
+float32x2_t test_vdot_lane_f32_f16(float32x2_t r, float16x4_t a, float16x4_t b) {
+ return vdot_lane_f32_f16(r, a, b, 0);
+}
+
+// CHECK-LABEL: define dso_local <2 x float> @test_vdot_laneq_f32_f16(
+// CHECK-SAME: <2 x float> noundef [[R:%.*]], <4 x half> noundef [[A:%.*]], <8 x half> noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[LANE:%.*]] = shufflevector <8 x half> [[B]], <8 x half> poison, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+// CHECK-NEXT: [[VDOT2:%.*]] = call <2 x float> @llvm.aarch64.neon.fdot.v2f32.v4f16(<2 x float> [[R]], <4 x half> [[A]], <4 x half> [[LANE]])
+// CHECK-NEXT: ret <2 x float> [[VDOT2]]
+//
+// CHECK-CXX-LABEL: define dso_local noundef <2 x float> @_Z23test_vdot_laneq_f32_f1613__Float32x2_t13__Float16x4_t13__Float16x8_t(
+// CHECK-CXX-SAME: <2 x float> noundef [[R:%.*]], <4 x half> noundef [[A:%.*]], <8 x half> noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-CXX-NEXT: [[ENTRY:.*:]]
+// CHECK-CXX-NEXT: [[LANE:%.*]] = shufflevector <8 x half> [[B]], <8 x half> poison, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+// CHECK-CXX-NEXT: [[VDOT2:%.*]] = call <2 x float> @llvm.aarch64.neon.fdot.v2f32.v4f16(<2 x float> [[R]], <4 x half> [[A]], <4 x half> [[LANE]])
+// CHECK-CXX-NEXT: ret <2 x float> [[VDOT2]]
+//
+float32x2_t test_vdot_laneq_f32_f16(float32x2_t r, float16x4_t a, float16x8_t b) {
+ return vdot_laneq_f32_f16(r, a, b, 3);
+}
+
+// CHECK-LABEL: define dso_local <4 x float> @test_vdotq_lane_f32_f16(
+// CHECK-SAME: <4 x float> noundef [[R:%.*]], <8 x half> noundef [[A:%.*]], <4 x half> noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[LANE:%.*]] = shufflevector <4 x half> [[B]], <4 x half> poison, <8 x i32> zeroinitializer
+// CHECK-NEXT: [[VDOT2:%.*]] = call <4 x float> @llvm.aarch64.neon.fdot.v4f32.v8f16(<4 x float> [[R]], <8 x half> [[A]], <8 x half> [[LANE]])
+// CHECK-NEXT: ret <4 x float> [[VDOT2]]
+//
+// CHECK-CXX-LABEL: define dso_local noundef <4 x float> @_Z23test_vdotq_lane_f32_f1613__Float32x4_t13__Float16x8_t13__Float16x4_t(
+// CHECK-CXX-SAME: <4 x float> noundef [[R:%.*]], <8 x half> noundef [[A:%.*]], <4 x half> noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-CXX-NEXT: [[ENTRY:.*:]]
+// CHECK-CXX-NEXT: [[LANE:%.*]] = shufflevector <4 x half> [[B]], <4 x half> poison, <8 x i32> zeroinitializer
+// CHECK-CXX-NEXT: [[VDOT2:%.*]] = call <4 x float> @llvm.aarch64.neon.fdot.v4f32.v8f16(<4 x float> [[R]], <8 x half> [[A]], <8 x half> [[LANE]])
+// CHECK-CXX-NEXT: ret <4 x float> [[VDOT2]]
+//
+float32x4_t test_vdotq_lane_f32_f16(float32x4_t r, float16x8_t a, float16x4_t b) {
+ return vdotq_lane_f32_f16(r, a, b, 0);
+}
+
+// CHECK-LABEL: define dso_local <4 x float> @test_vdotq_laneq_f32_f16(
+// CHECK-SAME: <4 x float> noundef [[R:%.*]], <8 x half> noundef [[A:%.*]], <8 x half> noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[LANE:%.*]] = shufflevector <8 x half> [[B]], <8 x half> poison, <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3>
+// CHECK-NEXT: [[VDOT2:%.*]] = call <4 x float> @llvm.aarch64.neon.fdot.v4f32.v8f16(<4 x float> [[R]], <8 x half> [[A]], <8 x half> [[LANE]])
+// CHECK-NEXT: ret <4 x float> [[VDOT2]]
+//
+// CHECK-CXX-LABEL: define dso_local noundef <4 x float> @_Z24test_vdotq_laneq_f32_f1613__Float32x4_t13__Float16x8_tS0_(
+// CHECK-CXX-SAME: <4 x float> noundef [[R:%.*]], <8 x half> noundef [[A:%.*]], <8 x half> noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-CXX-NEXT: [[ENTRY:.*:]]
+// CHECK-CXX-NEXT: [[LANE:%.*]] = shufflevector <8 x half> [[B]], <8 x half> poison, <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3>
+// CHECK-CXX-NEXT: [[VDOT2:%.*]] = call <4 x float> @llvm.aarch64.neon.fdot.v4f32.v8f16(<4 x float> [[R]], <8 x half> [[A]], <8 x half> [[LANE]])
+// CHECK-CXX-NEXT: ret <4 x float> [[VDOT2]]
+//
+float32x4_t test_vdotq_laneq_f32_f16(float32x4_t r, float16x8_t a, float16x8_t b) {
+ return vdotq_laneq_f32_f16(r, a, b, 3);
+}
diff --git a/clang/test/Sema/aarch64-neon-immediate-ranges/dotprod.c b/clang/test/Sema/aarch64-neon-immediate-ranges/dotprod.c
index 11f2c660a8ff2..c99d69d7caf41 100644
--- a/clang/test/Sema/aarch64-neon-immediate-ranges/dotprod.c
+++ b/clang/test/Sema/aarch64-neon-immediate-ranges/dotprod.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon -target-feature +v8.2a -target-feature +dotprod -ffreestanding -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon -target-feature +v8.2a -target-feature +dotprod -target-feature +f16f32dot -ffreestanding -fsyntax-only -verify %s
#include <arm_neon.h>
// REQUIRES: aarch64-registered-target
@@ -48,3 +48,25 @@ void test_dot_product_s32(int32x2_t arg_i32x2, int8x16_t arg_i8x16, int8x8_t arg
vdotq_lane_s32(arg_i32x4, arg_i8x16, arg_i8x8, 2); // expected-error-re {{argument value {{.*}} is outside the valid range}}
}
+
+void test_dot_product_f32_f16(float32x2_t r2, float32x4_t r4, float16x4_t h4, float16x8_t h8) {
+ (void)vdot_lane_f32_f16(r2, h4, h4, -1);
+// expected-error at -1 {{argument value -1 is outside the valid range [0, 1]}}
+ (void)vdot_lane_f32_f16(r2, h4, h4, 2);
+// expected-error at -1 {{argument value 2 is outside the valid range [0, 1]}}
+
+ (void)vdot_laneq_f32_f16(r2, h4, h8, -1);
+// expected-error at -1 {{argument value -1 is outside the valid range [0, 3]}}
+ (void)vdot_laneq_f32_f16(r2, h4, h8, 4);
+// expected-error at -1 {{argument value 4 is outside the valid range [0, 3]}}
+
+ (void)vdotq_lane_f32_f16(r4, h8, h4, -1);
+// expected-error at -1 {{argument value -1 is outside the valid range [0, 1]}}
+ (void)vdotq_lane_f32_f16(r4, h8, h4, 2);
+// expected-error at -1 {{argument value 2 is outside the valid range [0, 1]}}
+
+ (void)vdotq_laneq_f32_f16(r4, h8, h8, -1);
+// expected-error at -1 {{argument value -1 is outside the valid range [0, 3]}}
+ (void)vdotq_laneq_f32_f16(r4, h8, h8, 4);
+// expected-error at -1 {{argument value 4 is outside the valid range [0, 3]}}
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsAArch64.td b/llvm/include/llvm/IR/IntrinsicsAArch64.td
index 48c38fb2c2c9f..3298cf1c0ee56 100644
--- a/llvm/include/llvm/IR/IntrinsicsAArch64.td
+++ b/llvm/include/llvm/IR/IntrinsicsAArch64.td
@@ -515,6 +515,7 @@ let TargetPrefix = "aarch64" in {
def int_aarch64_neon_fmmla : AdvSIMD_MatMul_Intrinsic;
def int_aarch64_neon_usdot : AdvSIMD_Dot_Intrinsic;
def int_aarch64_neon_bfdot : AdvSIMD_Dot_Intrinsic;
+ def int_aarch64_neon_fdot : AdvSIMD_Dot_Intrinsic;
def int_aarch64_neon_bfmmla
: DefaultAttrsIntrinsic<[llvm_v4f32_ty],
[llvm_v4f32_ty, llvm_v8bf16_ty, llvm_v8bf16_ty],
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 381b83e1df4b8..67474aea6c537 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -6710,6 +6710,13 @@ multiclass SIMDThreeSameVectorFDot<string asm, SDPatternOperator OpNode = null_f
v2f32, v4f16, OpNode>;
def v8f16_v4f32 : BaseSIMDThreeSameVectorDot<1, 0, 0b10, 0b1111, asm, ".4s", ".8h", V128,
v4f32, v8f16, OpNode>;
+
+ def : Pat<(v2f32 (int_aarch64_neon_fdot (v2f32 V64:$Rd),
+ (v4f16 V64:$Rn), (v4f16 V64:$Rm))),
+ (!cast<Instruction>(NAME # "v4f16_v2f32") $Rd, $Rn, $Rm)>;
+ def : Pat<(v4f32 (int_aarch64_neon_fdot (v4f32 V128:$Rd),
+ (v8f16 V128:$Rn), (v8f16 V128:$Rm))),
+ (!cast<Instruction>(NAME # "v8f16_v4f32") $Rd, $Rn, $Rm)>;
}
// FP8 assembly/disassembly classes
@@ -9384,6 +9391,18 @@ multiclass SIMDThreeSameVectorFDOTIndex<string asm> {
V64, v2f32, v4f16, VectorIndexS, null_frag>;
def v8f16_v4f32 : BaseSIMDThreeSameVectorIndexS<0b1, 0b0, 0b01, 0b1001, asm, ".4s", ".8h",".2h",
V128, v4f32, v8f16, VectorIndexS, null_frag>;
+
+ def : Pat<(v2f32 (int_aarch64_neon_fdot
+ (v2f32 V64:$Rd), (v4f16 V64:$Rn),
+ (v4f16 (AArch64duplane16 (v8f16 V128:$Rm), VectorIndexS:$Idx)))),
+ (!cast<Instruction>(NAME # "v4f16_v2f32") $Rd, $Rn, $Rm,
+ VectorIndexS:$Idx)>;
+
+ def : Pat<(v4f32 (int_aarch64_neon_fdot
+ (v4f32 V128:$Rd), (v8f16 V128:$Rn),
+ (v8f16 (AArch64duplane16 (v8f16 V128:$Rm), VectorIndexS:$Idx)))),
+ (!cast<Instruction>(NAME # "v8f16_v4f32") $Rd, $Rn, $Rm,
+ VectorIndexS:$Idx)>;
}
//----------------------------------------------------------------------------
diff --git a/llvm/test/CodeGen/AArch64/aarch64-f16f32dot-intrinsics.ll b/llvm/test/CodeGen/AArch64/aarch64-f16f32dot-intrinsics.ll
new file mode 100644
index 0000000000000..7da0076ea9b4b
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-f16f32dot-intrinsics.ll
@@ -0,0 +1,62 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple aarch64 -mattr=+f16f32dot %s -o - | FileCheck %s
+
+define <2 x float> @test_vdot_f32(<2 x float> %r, <4 x half> %a, <4 x half> %b) {
+; CHECK-LABEL: test_vdot_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fdot v0.2s, v1.4h, v2.4h
+; CHECK-NEXT: ret
+ %res = call <2 x float> @llvm.aarch64.neon.fdot.v2f32.v4f16(<2 x float> %r, <4 x half> %a, <4 x half> %b)
+ ret <2 x float> %res
+}
+
+define <4 x float> @test_vdotq_f32(<4 x float> %r, <8 x half> %a, <8 x half> %b) {
+; CHECK-LABEL: test_vdotq_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fdot v0.4s, v1.8h, v2.8h
+; CHECK-NEXT: ret
+ %res = call <4 x float> @llvm.aarch64.neon.fdot.v4f32.v8f16(<4 x float> %r, <8 x half> %a, <8 x half> %b)
+ ret <4 x float> %res
+}
+
+define <2 x float> @test_vdot_lane_f32(<2 x float> %r, <4 x half> %a, <4 x half> %b) {
+; CHECK-LABEL: test_vdot_lane_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $d2 killed $d2 def $q2
+; CHECK-NEXT: fdot v0.2s, v1.4h, v2.2h[0]
+; CHECK-NEXT: ret
+ %lane = shufflevector <4 x half> %b, <4 x half> poison, <4 x i32> zeroinitializer
+ %res = call <2 x float> @llvm.aarch64.neon.fdot.v2f32.v4f16(<2 x float> %r, <4 x half> %a, <4 x half> %lane)
+ ret <2 x float> %res
+}
+
+define <4 x float> @test_vdotq_laneq_f32(<4 x float> %r, <8 x half> %a, <8 x half> %b) {
+; CHECK-LABEL: test_vdotq_laneq_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fdot v0.4s, v1.8h, v2.2h[3]
+; CHECK-NEXT: ret
+ %lane = shufflevector <8 x half> %b, <8 x half> poison, <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3>
+ %res = call <4 x float> @llvm.aarch64.neon.fdot.v4f32.v8f16(<4 x float> %r, <8 x half> %a, <8 x half> %lane)
+ ret <4 x float> %res
+}
+
+define <2 x float> @test_vdot_laneq_f32(<2 x float> %r, <4 x half> %a, <8 x half> %b) {
+; CHECK-LABEL: test_vdot_laneq_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fdot v0.2s, v1.4h, v2.2h[3]
+; CHECK-NEXT: ret
+ %lane = shufflevector <8 x half> %b, <8 x half> poison, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+ %res = call <2 x float> @llvm.aarch64.neon.fdot.v2f32.v4f16(<2 x float> %r, <4 x half> %a, <4 x half> %lane)
+ ret <2 x float> %res
+}
+
+define <4 x float> @test_vdotq_lane_f32(<4 x float> %r, <8 x half> %a, <4 x half> %b) {
+; CHECK-LABEL: test_vdotq_lane_f32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $d2 killed $d2 def $q2
+; CHECK-NEXT: fdot v0.4s, v1.8h, v2.2h[0]
+; CHECK-NEXT: ret
+ %lane = shufflevector <4 x half> %b, <4 x half> poison, <8 x i32> zeroinitializer
+ %res = call <4 x float> @llvm.aarch64.neon.fdot.v4f32.v8f16(<4 x float> %r, <8 x half> %a, <8 x half> %lane)
+ ret <4 x float> %res
+}
\ No newline at end of file
More information about the cfe-commits
mailing list