[llvm] Legalize 128-bit types for FABS (PR #104753)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 19 02:49:23 PDT 2024
https://github.com/Him188 created https://github.com/llvm/llvm-project/pull/104753
Generate `and x8, x8, #0x7fffffffffffffff` to reset the sign bit. Vectors are scalarized.
This approach is different than what SDAG is doing. SDAG stores the value onto stack, clears the sign bit in the most significant byte, and loads the value back into register. This involves multiple memory ops and sounds slower.
>From 20289978ee6948ec35165afffcd35d282c373481 Mon Sep 17 00:00:00 2001
From: Tianyi Guan <tguan at nvidia.com>
Date: Tue, 30 Jul 2024 12:19:52 +0100
Subject: [PATCH 1/2] [AArch64][GlobalISel] Add test cases for 128-bit fabs.
(NFC)
---
llvm/test/CodeGen/AArch64/fabs-fp128.ll | 58 +++++++++++++++++++++++++
1 file changed, 58 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/fabs-fp128.ll
diff --git a/llvm/test/CodeGen/AArch64/fabs-fp128.ll b/llvm/test/CodeGen/AArch64/fabs-fp128.ll
new file mode 100644
index 00000000000000..0232397ffc7c67
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/fabs-fp128.ll
@@ -0,0 +1,58 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-SD
+; RUN: llc -mtriple=aarch64 -global-isel=1 -global-isel-abort=2 -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-GI
+
+; CHECK: warning: Instruction selection used fallback path for fabs_f128
+; CHECK-NEXT: warning: Instruction selection used fallback path for fabs_v1f128
+; CHECK-NEXT: warning: Instruction selection used fallback path for fabs_v2f128
+
+define fp128 @fabs_f128(fp128 %a) {
+; CHECK-LABEL: fabs_f128:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: str q0, [sp, #-16]!
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: ldrb w8, [sp, #15]
+; CHECK-NEXT: and w8, w8, #0x7f
+; CHECK-NEXT: strb w8, [sp, #15]
+; CHECK-NEXT: ldr q0, [sp], #16
+; CHECK-NEXT: ret
+entry:
+ %c = call fp128 @llvm.fabs.f128(fp128 %a)
+ ret fp128 %c
+}
+
+define <1 x fp128> @fabs_v1f128(<1 x fp128> %a) {
+; CHECK-LABEL: fabs_v1f128:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: str q0, [sp, #-16]!
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: ldrb w8, [sp, #15]
+; CHECK-NEXT: and w8, w8, #0x7f
+; CHECK-NEXT: strb w8, [sp, #15]
+; CHECK-NEXT: ldr q0, [sp], #16
+; CHECK-NEXT: ret
+entry:
+ %c = call <1 x fp128> @llvm.fabs.v1f128(<1 x fp128> %a)
+ ret <1 x fp128> %c
+}
+
+define <2 x fp128> @fabs_v2f128(<2 x fp128> %a) {
+; CHECK-LABEL: fabs_v2f128:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: stp q0, q1, [sp, #-32]!
+; CHECK-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NEXT: ldrb w8, [sp, #15]
+; CHECK-NEXT: and w8, w8, #0x7f
+; CHECK-NEXT: strb w8, [sp, #15]
+; CHECK-NEXT: ldrb w8, [sp, #31]
+; CHECK-NEXT: and w8, w8, #0x7f
+; CHECK-NEXT: strb w8, [sp, #31]
+; CHECK-NEXT: ldp q0, q1, [sp], #32
+; CHECK-NEXT: ret
+entry:
+ %c = call <2 x fp128> @llvm.fabs.v2f128(<2 x fp128> %a)
+ ret <2 x fp128> %c
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-GI: {{.*}}
+; CHECK-SD: {{.*}}
>From bd6ca428987defcfbb2e567ed270fc5205bdf396 Mon Sep 17 00:00:00 2001
From: Tianyi Guan <tguan at nvidia.com>
Date: Tue, 30 Jul 2024 12:19:52 +0100
Subject: [PATCH 2/2] [AArch64][GlobalISel] Legalize 128-bit types for FABS
- Generate AND to clear sign bit for s128
- Vectors are scalarized
---
.../AArch64/GISel/AArch64LegalizerInfo.cpp | 41 ++++++-
.../AArch64/GISel/AArch64LegalizerInfo.h | 2 +
llvm/test/CodeGen/AArch64/fabs-fp128.ll | 100 +++++++++++-------
3 files changed, 102 insertions(+), 41 deletions(-)
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index d42d5511a82422..cae0ce1f4567f2 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -241,9 +241,9 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
.widenScalarToNextPow2(0);
getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FNEG,
- G_FABS, G_FSQRT, G_FMAXNUM, G_FMINNUM,
- G_FMAXIMUM, G_FMINIMUM, G_FCEIL, G_FFLOOR,
- G_FRINT, G_FNEARBYINT, G_INTRINSIC_TRUNC,
+ G_FSQRT, G_FMAXNUM, G_FMINNUM, G_FMAXIMUM,
+ G_FMINIMUM, G_FCEIL, G_FFLOOR, G_FRINT,
+ G_FNEARBYINT, G_INTRINSIC_TRUNC,
G_INTRINSIC_ROUND, G_INTRINSIC_ROUNDEVEN})
.legalFor({MinFPScalar, s32, s64, v2s32, v4s32, v2s64})
.legalIf([=](const LegalityQuery &Query) {
@@ -257,6 +257,20 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
.clampNumElements(0, v2s64, v2s64)
.moreElementsToNextPow2(0);
+ getActionDefinitionsBuilder(G_FABS)
+ .legalFor({MinFPScalar, s32, s64, v2s32, v4s32, v2s64})
+ .legalIf([=](const LegalityQuery &Query) {
+ const auto &Ty = Query.Types[0];
+ return (Ty == v8s16 || Ty == v4s16) && HasFP16;
+ })
+ .customFor({s128})
+ .scalarizeIf(scalarOrEltWiderThan(0, 64), 0)
+ .minScalarOrElt(0, MinFPScalar)
+ .clampNumElements(0, v4s16, v8s16)
+ .clampNumElements(0, v2s32, v4s32)
+ .clampNumElements(0, v2s64, v2s64)
+ .moreElementsToNextPow2(0);
+
getActionDefinitionsBuilder(G_FREM)
.libcallFor({s32, s64})
.minScalar(0, s32)
@@ -1336,6 +1350,8 @@ bool AArch64LegalizerInfo::legalizeCustom(
return legalizePrefetch(MI, Helper);
case TargetOpcode::G_ABS:
return Helper.lowerAbsToCNeg(MI);
+ case TargetOpcode::G_FABS:
+ return legalizeFABS(MI, MRI, MIRBuilder);
case TargetOpcode::G_ICMP:
return legalizeICMP(MI, MRI, MIRBuilder);
}
@@ -1396,6 +1412,25 @@ bool AArch64LegalizerInfo::legalizeFunnelShift(MachineInstr &MI,
return true;
}
+bool AArch64LegalizerInfo::legalizeFABS(MachineInstr &MI,
+ MachineRegisterInfo &MRI,
+ MachineIRBuilder &MIRBuilder) const {
+ Register SrcReg = MI.getOperand(1).getReg();
+ Register DstReg = MI.getOperand(0).getReg();
+
+ constexpr LLT S128 = LLT::scalar(128);
+ if (MRI.getType(SrcReg) != S128 || MRI.getType(DstReg) != S128)
+ return false;
+
+ MIRBuilder.buildAnd(
+ DstReg, SrcReg,
+ MIRBuilder.buildConstant(
+ S128, APInt::getSignedMaxValue(128)));
+
+ MI.eraseFromParent();
+ return true;
+}
+
bool AArch64LegalizerInfo::legalizeICMP(MachineInstr &MI,
MachineRegisterInfo &MRI,
MachineIRBuilder &MIRBuilder) const {
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h
index 00d85a36e4b2ca..8bf642d1745aa9 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.h
@@ -50,6 +50,8 @@ class AArch64LegalizerInfo : public LegalizerInfo {
LegalizerHelper &Helper) const;
bool legalizeRotate(MachineInstr &MI, MachineRegisterInfo &MRI,
LegalizerHelper &Helper) const;
+ bool legalizeFABS(MachineInstr &MI, MachineRegisterInfo &MRI,
+ MachineIRBuilder &MIRBuilder) const;
bool legalizeICMP(MachineInstr &MI, MachineRegisterInfo &MRI,
MachineIRBuilder &MIRBuilder) const;
bool legalizeFunnelShift(MachineInstr &MI, MachineRegisterInfo &MRI,
diff --git a/llvm/test/CodeGen/AArch64/fabs-fp128.ll b/llvm/test/CodeGen/AArch64/fabs-fp128.ll
index 0232397ffc7c67..131af5e0a3281e 100644
--- a/llvm/test/CodeGen/AArch64/fabs-fp128.ll
+++ b/llvm/test/CodeGen/AArch64/fabs-fp128.ll
@@ -1,58 +1,82 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
-; RUN: llc -mtriple=aarch64 -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-SD
-; RUN: llc -mtriple=aarch64 -global-isel=1 -global-isel-abort=2 -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-GI
-
-; CHECK: warning: Instruction selection used fallback path for fabs_f128
-; CHECK-NEXT: warning: Instruction selection used fallback path for fabs_v1f128
-; CHECK-NEXT: warning: Instruction selection used fallback path for fabs_v2f128
+; RUN: llc -mtriple=aarch64-unknown-linux-gnu -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-SD
+; RUN: llc -mtriple=aarch64-unknown-linux-gnu -global-isel=1 -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-GI
define fp128 @fabs_f128(fp128 %a) {
-; CHECK-LABEL: fabs_f128:
-; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: str q0, [sp, #-16]!
-; CHECK-NEXT: .cfi_def_cfa_offset 16
-; CHECK-NEXT: ldrb w8, [sp, #15]
-; CHECK-NEXT: and w8, w8, #0x7f
-; CHECK-NEXT: strb w8, [sp, #15]
-; CHECK-NEXT: ldr q0, [sp], #16
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: fabs_f128:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: str q0, [sp, #-16]!
+; CHECK-SD-NEXT: .cfi_def_cfa_offset 16
+; CHECK-SD-NEXT: ldrb w8, [sp, #15]
+; CHECK-SD-NEXT: and w8, w8, #0x7f
+; CHECK-SD-NEXT: strb w8, [sp, #15]
+; CHECK-SD-NEXT: ldr q0, [sp], #16
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: fabs_f128:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: mov x8, v0.d[1]
+; CHECK-GI-NEXT: mov v0.d[0], v0.d[0]
+; CHECK-GI-NEXT: and x8, x8, #0x7fffffffffffffff
+; CHECK-GI-NEXT: mov v0.d[1], x8
+; CHECK-GI-NEXT: ret
entry:
%c = call fp128 @llvm.fabs.f128(fp128 %a)
ret fp128 %c
}
define <1 x fp128> @fabs_v1f128(<1 x fp128> %a) {
-; CHECK-LABEL: fabs_v1f128:
-; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: str q0, [sp, #-16]!
-; CHECK-NEXT: .cfi_def_cfa_offset 16
-; CHECK-NEXT: ldrb w8, [sp, #15]
-; CHECK-NEXT: and w8, w8, #0x7f
-; CHECK-NEXT: strb w8, [sp, #15]
-; CHECK-NEXT: ldr q0, [sp], #16
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: fabs_v1f128:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: str q0, [sp, #-16]!
+; CHECK-SD-NEXT: .cfi_def_cfa_offset 16
+; CHECK-SD-NEXT: ldrb w8, [sp, #15]
+; CHECK-SD-NEXT: and w8, w8, #0x7f
+; CHECK-SD-NEXT: strb w8, [sp, #15]
+; CHECK-SD-NEXT: ldr q0, [sp], #16
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: fabs_v1f128:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: mov x8, v0.d[1]
+; CHECK-GI-NEXT: mov v0.d[0], v0.d[0]
+; CHECK-GI-NEXT: and x8, x8, #0x7fffffffffffffff
+; CHECK-GI-NEXT: mov v0.d[1], x8
+; CHECK-GI-NEXT: ret
entry:
%c = call <1 x fp128> @llvm.fabs.v1f128(<1 x fp128> %a)
ret <1 x fp128> %c
}
define <2 x fp128> @fabs_v2f128(<2 x fp128> %a) {
-; CHECK-LABEL: fabs_v2f128:
-; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: stp q0, q1, [sp, #-32]!
-; CHECK-NEXT: .cfi_def_cfa_offset 32
-; CHECK-NEXT: ldrb w8, [sp, #15]
-; CHECK-NEXT: and w8, w8, #0x7f
-; CHECK-NEXT: strb w8, [sp, #15]
-; CHECK-NEXT: ldrb w8, [sp, #31]
-; CHECK-NEXT: and w8, w8, #0x7f
-; CHECK-NEXT: strb w8, [sp, #31]
-; CHECK-NEXT: ldp q0, q1, [sp], #32
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: fabs_v2f128:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: stp q0, q1, [sp, #-32]!
+; CHECK-SD-NEXT: .cfi_def_cfa_offset 32
+; CHECK-SD-NEXT: ldrb w8, [sp, #15]
+; CHECK-SD-NEXT: and w8, w8, #0x7f
+; CHECK-SD-NEXT: strb w8, [sp, #15]
+; CHECK-SD-NEXT: ldrb w8, [sp, #31]
+; CHECK-SD-NEXT: and w8, w8, #0x7f
+; CHECK-SD-NEXT: strb w8, [sp, #31]
+; CHECK-SD-NEXT: ldp q0, q1, [sp], #32
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: fabs_v2f128:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: mov x8, v0.d[1]
+; CHECK-GI-NEXT: mov x9, v1.d[1]
+; CHECK-GI-NEXT: mov v0.d[0], v0.d[0]
+; CHECK-GI-NEXT: mov v1.d[0], v1.d[0]
+; CHECK-GI-NEXT: and x8, x8, #0x7fffffffffffffff
+; CHECK-GI-NEXT: and x9, x9, #0x7fffffffffffffff
+; CHECK-GI-NEXT: mov v0.d[1], x8
+; CHECK-GI-NEXT: mov v1.d[1], x9
+; CHECK-GI-NEXT: ret
entry:
%c = call <2 x fp128> @llvm.fabs.v2f128(<2 x fp128> %a)
ret <2 x fp128> %c
}
+
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK-GI: {{.*}}
-; CHECK-SD: {{.*}}
+; CHECK: {{.*}}
More information about the llvm-commits
mailing list