[llvm] [AArch64] Use `bfi` to combine registers (PR #194794)
Cheng Lingfei via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 30 20:04:30 PDT 2026
https://github.com/clingfei updated https://github.com/llvm/llvm-project/pull/194794
>From 6a69fcc5ca1bf912cf450ef6f0669fb778fe21b7 Mon Sep 17 00:00:00 2001
From: clingfei <1599101385 at qq.com>
Date: Wed, 29 Apr 2026 14:21:29 +0800
Subject: [PATCH 1/2] [AArch64] Optmize: use bfi to combine registers
---
.../Target/AArch64/AArch64ISelDAGToDAG.cpp | 217 ++++++++++++-
.../CodeGen/AArch64/bitfield-insert-packed.ll | 285 ++++++++++++++++++
2 files changed, 500 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/bitfield-insert-packed.ll
diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 64ccf606b4ef7..9ffddc975de77 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -15,6 +15,7 @@
#include "MCTargetDesc/AArch64AddressingModes.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/CodeGen/ISDOpcodes.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/IR/Function.h" // To access function attributes.
#include "llvm/IR/GlobalValue.h"
@@ -3514,6 +3515,215 @@ static bool isShiftedMask(uint64_t Mask, EVT VT) {
return isShiftedMask_64(Mask);
}
+struct PackedBitfieldTerm {
+ SDValue Src;
+ unsigned LSB;
+ unsigned Width;
+};
+
+static bool isPackedBitfieldFixedStackLoad(SDValue Op) {
+ auto *Ld = dyn_cast<LoadSDNode>(Op);
+ return Ld && Op.getResNo() == 0 &&
+ Ld->getBasePtr().getOpcode() == ISD::FrameIndex &&
+ Ld->getExtensionType() != ISD::SEXTLOAD;
+}
+
+// A packed-bitfield source is a value cheap enough that inserting it with a BFM
+// is worthwhile: an incoming integer argument in W0-W7/X0-X7, or a narrow load
+// from a fixed stack slot, possibly behind extends or an INSERT_SUBREG.
+static bool isPackedBitfieldSource(SelectionDAG *CurDAG, SDValue Src) {
+ if (Src.getOpcode() == ISD::ANY_EXTEND || Src.getOpcode() == ISD::ZERO_EXTEND)
+ return isPackedBitfieldSource(CurDAG, Src.getOperand(0));
+
+ if (Src.isMachineOpcode() &&
+ Src.getMachineOpcode() == TargetOpcode::INSERT_SUBREG)
+ return isPackedBitfieldSource(CurDAG, Src.getOperand(1));
+
+ if (isPackedBitfieldFixedStackLoad(Src))
+ return true;
+
+ // The only other accepted leaf is a CopyFromReg of a live-in argument
+ // register.
+ if (Src.getOpcode() != ISD::CopyFromReg || Src.getResNo() != 0 ||
+ Src.getOperand(0).getOpcode() != ISD::EntryToken)
+ return false;
+
+ EVT VT = Src.getValueType();
+ if (VT != MVT::i32 && VT != MVT::i64)
+ return false;
+
+ auto *RegNode = dyn_cast<RegisterSDNode>(Src.getOperand(1));
+ if (!RegNode || !RegNode->getReg().isVirtual())
+ return false;
+
+ MCRegister PhysReg =
+ CurDAG->getMachineFunction().getRegInfo().getLiveInPhysReg(
+ RegNode->getReg());
+ return (AArch64::W0 <= PhysReg && PhysReg <= AArch64::W7) ||
+ (AArch64::X0 <= PhysReg && PhysReg <= AArch64::X7);
+}
+
+static SDValue widenPackedSource(SelectionDAG *CurDAG, SDValue Src, EVT VT,
+ SDLoc DL) {
+ if (Src.getValueType() == VT)
+ return Src;
+ if (VT == MVT::i64 && Src.getValueType() == MVT::i32)
+ return Widen(CurDAG, Src);
+ return CurDAG->getNode(ISD::ANY_EXTEND, DL, VT, Src);
+}
+
+// Match a single OR operand as a bitfield to insert, recording its source
+// value, destination LSB and width in \p Term. Two shapes are recognized:
+// values that occupy the low bits (DstLSB == 0) via a low-mask AND, a
+// zero-extend, or a narrow stack load; and values placed at a non-zero offset
+// via isBitfieldPositioningOp. In every case the underlying value must be a
+// packed-bitfield source.
+static bool getPackedBitfieldTerm(SelectionDAG *CurDAG, SDValue Op,
+ PackedBitfieldTerm &Term) {
+ EVT VT = Op.getValueType();
+ if (VT != MVT::i32 && VT != MVT::i64)
+ return false;
+ unsigned BitWidth = VT.getSizeInBits();
+
+ // Low-mask AND: the masked value sits in the low Width bits as-is.
+ uint64_t MaskImm;
+ if (isOpcWithIntImmediate(Op.getNode(), ISD::AND, MaskImm) &&
+ isMask_64(MaskImm)) {
+ unsigned Width = llvm::countr_one(MaskImm);
+ if (Width != 0 && Width < BitWidth) {
+ Term = {Op.getOperand(0), 0, Width};
+ return isPackedBitfieldSource(CurDAG, Term.Src);
+ }
+ }
+
+ // Zero-extend whose known bits form a contiguous low mask.
+ if (Op.getOpcode() == ISD::ZERO_EXTEND) {
+ APInt NonZero = ~CurDAG->computeKnownBits(Op).Zero;
+ unsigned Width = NonZero.countr_one();
+ if (NonZero.isMask() && Width != 0 && Width < BitWidth) {
+ Term = {widenPackedSource(CurDAG, Op.getOperand(0), VT, SDLoc(Op)), 0,
+ Width};
+ return isPackedBitfieldSource(CurDAG, Term.Src);
+ }
+ }
+
+ // Narrow load from a fixed stack slot.
+ if (isPackedBitfieldFixedStackLoad(Op)) {
+ unsigned Width = cast<LoadSDNode>(Op)->getMemoryVT().getScalarSizeInBits();
+ if (Width != 0 && Width < BitWidth) {
+ Term = {Op, 0, Width};
+ return isPackedBitfieldSource(CurDAG, Term.Src);
+ }
+ }
+
+ // Otherwise the value is positioned at a non-zero offset. A zero-extend from
+ // i32 to i64 is positioned within the narrow i32 value.
+ SDValue PosOp = Op;
+ if (Op.getOpcode() == ISD::ZERO_EXTEND && VT == MVT::i64 &&
+ Op.getOperand(0).getValueType() == MVT::i32)
+ PosOp = Op.getOperand(0);
+
+ SDValue Src;
+ int DstLSB, Width;
+ if (!isBitfieldPositioningOp(CurDAG, PosOp, /*BiggerPattern=*/true, Src,
+ DstLSB, Width))
+ return false;
+ if (DstLSB < 0 || Width <= 0)
+ return false;
+
+ // A BFM only consumes the low Width bits of Src, so an AND that keeps at
+ // least those bits is redundant; drop it (looking through one extend) and
+ // widen the surviving value to VT.
+ SDValue Unmasked = Src;
+ if (Unmasked.getOpcode() == ISD::ANY_EXTEND ||
+ Unmasked.getOpcode() == ISD::ZERO_EXTEND)
+ Unmasked = Unmasked.getOperand(0);
+ uint64_t AndImm;
+ if (isOpcWithIntImmediate(Unmasked.getNode(), ISD::AND, AndImm) &&
+ isMask_64(AndImm) &&
+ static_cast<unsigned>(llvm::countr_one(AndImm)) >=
+ static_cast<unsigned>(Width))
+ Src = Unmasked.getOperand(0);
+
+ Src = widenPackedSource(CurDAG, Src, VT, SDLoc(Op));
+ if (!isPackedBitfieldSource(CurDAG, Src))
+ return false;
+ Term = {Src, static_cast<unsigned>(DstLSB), static_cast<unsigned>(Width)};
+ return true;
+}
+
+static bool
+collectPackedBitfieldTerms(SelectionDAG *CurDAG, SDValue Op,
+ SmallVectorImpl<PackedBitfieldTerm> &Terms,
+ bool IsRoot = false) {
+ if (Op.getOpcode() == ISD::OR) {
+ if (!IsRoot && !Op.hasOneUse())
+ return false;
+ return collectPackedBitfieldTerms(CurDAG, Op.getOperand(0), Terms) &&
+ collectPackedBitfieldTerms(CurDAG, Op.getOperand(1), Terms);
+ }
+
+ if (!Op.hasOneUse())
+ return false;
+
+ PackedBitfieldTerm Term;
+ if (!getPackedBitfieldTerm(CurDAG, Op, Term))
+ return false;
+
+ Terms.push_back(Term);
+ return true;
+}
+
+static bool tryPackedBitfieldInsertOp(SDNode *N, SelectionDAG *CurDAG) {
+ assert(N->getOpcode() == ISD::OR && "Expect a OR operation");
+
+ EVT VT = N->getValueType(0);
+ if (VT != MVT::i32 && VT != MVT::i64)
+ return false;
+
+ SmallVector<PackedBitfieldTerm, 8> Terms;
+ if (!collectPackedBitfieldTerms(CurDAG, SDValue(N, 0), Terms,
+ /*IsRoot=*/true))
+ return false;
+ if (Terms.size() < 2)
+ return false;
+
+ llvm::sort(Terms,
+ [](const PackedBitfieldTerm &LHS, const PackedBitfieldTerm &RHS) {
+ return LHS.LSB < RHS.LSB;
+ });
+
+ unsigned BitWidth = VT.getSizeInBits();
+ unsigned Offset = 0;
+ for (const PackedBitfieldTerm &Term : Terms) {
+ if (Term.LSB != Offset || Term.Width == 0 ||
+ Term.LSB + Term.Width > BitWidth)
+ return false;
+ Offset += Term.Width;
+ }
+ if (Offset != BitWidth)
+ return false;
+
+ SDLoc DL(N);
+ SDValue Result = Terms.front().Src;
+ unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri;
+
+ for (unsigned I = 1, E = Terms.size(); I != E; ++I) {
+ const PackedBitfieldTerm &Term = Terms[I];
+ unsigned ImmR = (BitWidth - Term.LSB) % BitWidth;
+ unsigned ImmS = Term.Width - 1;
+ SDValue Ops[] = {Result, Term.Src, CurDAG->getTargetConstant(ImmR, DL, VT),
+ CurDAG->getTargetConstant(ImmS, DL, VT)};
+ if (I == E - 1) {
+ CurDAG->SelectNodeTo(N, Opc, VT, Ops);
+ return true;
+ }
+ Result = SDValue(CurDAG->getMachineNode(Opc, DL, VT, Ops), 0);
+ }
+
+ llvm_unreachable("expected at least one inserted term");
+}
+
// Generate a BFI/BFXIL from 'or (and X, MaskImm), OrImm' iff the value being
// inserted only sets known zero bits.
static bool tryBitfieldInsertOpFromOrAndImm(SDNode *N, SelectionDAG *CurDAG) {
@@ -3966,6 +4176,9 @@ bool AArch64DAGToDAGISel::tryBitfieldInsertOp(SDNode *N) {
return true;
}
+ if (OptLevel != CodeGenOptLevel::None && tryPackedBitfieldInsertOp(N, CurDAG))
+ return true;
+
if (tryBitfieldInsertOpFromOr(N, NUsefulBits, CurDAG))
return true;
@@ -4260,8 +4473,8 @@ static int getIntOperandFromRegisterString(StringRef RegString) {
// Need to combine the integer fields of the string into a single value
// based on the bit encoding of MRS/MSR instruction.
- return (Ops[0] << 14) | (Ops[1] << 11) | (Ops[2] << 7) |
- (Ops[3] << 3) | (Ops[4]);
+ return (Ops[0] << 14) | (Ops[1] << 11) | (Ops[2] << 7) | (Ops[3] << 3) |
+ (Ops[4]);
}
// Lower the read_register intrinsic to an MRS instruction node if the special
diff --git a/llvm/test/CodeGen/AArch64/bitfield-insert-packed.ll b/llvm/test/CodeGen/AArch64/bitfield-insert-packed.ll
new file mode 100644
index 0000000000000..948bd2962997a
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/bitfield-insert-packed.ll
@@ -0,0 +1,285 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s
+
+define i16 @u8x2_to_u16(i8 %b0, i8 %b1) {
+; CHECK-LABEL: u8x2_to_u16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: bfi w0, w1, #8, #24
+; CHECK-NEXT: ret
+ %z0 = zext i8 %b0 to i16
+ %z1 = zext i8 %b1 to i16
+ %s1 = shl i16 %z1, 8
+ %res = or i16 %s1, %z0
+ ret i16 %res
+}
+
+define i32 @u16x2_to_u32(i16 %h0, i16 %h1) {
+; CHECK-LABEL: u16x2_to_u32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: bfi w0, w1, #16, #16
+; CHECK-NEXT: ret
+ %z0 = zext i16 %h0 to i32
+ %z1 = zext i16 %h1 to i32
+ %s1 = shl i32 %z1, 16
+ %res = or i32 %s1, %z0
+ ret i32 %res
+}
+
+define i64 @u32x2_to_u64(i32 %w0, i32 %w1) {
+; CHECK-LABEL: u32x2_to_u64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT: bfi x0, x1, #32, #32
+; CHECK-NEXT: ret
+ %z0 = zext i32 %w0 to i64
+ %z1 = zext i32 %w1 to i64
+ %s1 = shl i64 %z1, 32
+ %res = or i64 %s1, %z0
+ ret i64 %res
+}
+
+define i32 @u8x4_to_u32(i8 %b0, i8 %b1, i8 %b2, i8 %b3) {
+; CHECK-LABEL: u8x4_to_u32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: bfi w0, w1, #8, #8
+; CHECK-NEXT: bfi w0, w2, #16, #8
+; CHECK-NEXT: bfi w0, w3, #24, #8
+; CHECK-NEXT: ret
+ %z0 = zext i8 %b0 to i32
+ %z1 = zext i8 %b1 to i32
+ %z2 = zext i8 %b2 to i32
+ %z3 = zext i8 %b3 to i32
+ %s1 = shl i32 %z1, 8
+ %s2 = shl i32 %z2, 16
+ %s3 = shl i32 %z3, 24
+ %or1 = or i32 %s3, %s2
+ %or2 = or i32 %or1, %s1
+ %res = or i32 %or2, %z0
+ ret i32 %res
+}
+
+define i64 @u16x4_to_u64(i16 %h0, i16 %h1, i16 %h2, i16 %h3) {
+; CHECK-LABEL: u16x4_to_u64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2
+; CHECK-NEXT: // kill: def $w3 killed $w3 def $x3
+; CHECK-NEXT: bfi x0, x1, #16, #16
+; CHECK-NEXT: bfi x0, x2, #32, #16
+; CHECK-NEXT: bfi x0, x3, #48, #16
+; CHECK-NEXT: ret
+ %z0 = zext i16 %h0 to i64
+ %z1 = zext i16 %h1 to i64
+ %z2 = zext i16 %h2 to i64
+ %z3 = zext i16 %h3 to i64
+ %s1 = shl i64 %z1, 16
+ %s2 = shl i64 %z2, 32
+ %s3 = shl i64 %z3, 48
+ %or1 = or i64 %s3, %s2
+ %or2 = or i64 %or1, %s1
+ %res = or i64 %or2, %z0
+ ret i64 %res
+}
+
+define i64 @u8x8_to_u64(i8 %b0, i8 %b1, i8 %b2, i8 %b3,
+; CHECK-LABEL: u8x8_to_u64:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2
+; CHECK-NEXT: // kill: def $w3 killed $w3 def $x3
+; CHECK-NEXT: // kill: def $w4 killed $w4 def $x4
+; CHECK-NEXT: // kill: def $w5 killed $w5 def $x5
+; CHECK-NEXT: // kill: def $w6 killed $w6 def $x6
+; CHECK-NEXT: // kill: def $w7 killed $w7 def $x7
+; CHECK-NEXT: bfi x0, x1, #8, #8
+; CHECK-NEXT: bfi x0, x2, #16, #8
+; CHECK-NEXT: bfi x0, x3, #24, #8
+; CHECK-NEXT: bfi x0, x4, #32, #8
+; CHECK-NEXT: bfi x0, x5, #40, #8
+; CHECK-NEXT: bfi x0, x6, #48, #8
+; CHECK-NEXT: bfi x0, x7, #56, #8
+; CHECK-NEXT: ret
+ i8 %b4, i8 %b5, i8 %b6, i8 %b7) {
+ %z0 = zext i8 %b0 to i64
+ %z1 = zext i8 %b1 to i64
+ %z2 = zext i8 %b2 to i64
+ %z3 = zext i8 %b3 to i64
+ %z4 = zext i8 %b4 to i64
+ %z5 = zext i8 %b5 to i64
+ %z6 = zext i8 %b6 to i64
+ %z7 = zext i8 %b7 to i64
+ %s1 = shl i64 %z1, 8
+ %s2 = shl i64 %z2, 16
+ %s3 = shl i64 %z3, 24
+ %s4 = shl i64 %z4, 32
+ %s5 = shl i64 %z5, 40
+ %s6 = shl i64 %z6, 48
+ %s7 = shl i64 %z7, 56
+ %or1 = or i64 %s7, %s6
+ %or2 = or i64 %or1, %s5
+ %or3 = or i64 %or2, %s4
+ %or4 = or i64 %or3, %s3
+ %or5 = or i64 %or4, %s2
+ %or6 = or i64 %or5, %s1
+ %res = or i64 %or6, %z0
+ ret i64 %res
+}
+
+define [2 x i64] @u32x4_to_u128(i32 %w0, i32 %w1, i32 %w2, i32 %w3) {
+; CHECK-LABEL: u32x4_to_u128:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2
+; CHECK-NEXT: // kill: def $w3 killed $w3 def $x3
+; CHECK-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT: bfi x2, x3, #32, #32
+; CHECK-NEXT: bfi x0, x1, #32, #32
+; CHECK-NEXT: mov x1, x2
+; CHECK-NEXT: ret
+ %z0 = zext i32 %w0 to i64
+ %z1 = zext i32 %w1 to i64
+ %s1 = shl i64 %z1, 32
+ %lo = or i64 %s1, %z0
+ %z2 = zext i32 %w2 to i64
+ %z3 = zext i32 %w3 to i64
+ %s3 = shl i64 %z3, 32
+ %hi = or i64 %s3, %z2
+ %r0 = insertvalue [2 x i64] poison, i64 %lo, 0
+ %r1 = insertvalue [2 x i64] %r0, i64 %hi, 1
+ ret [2 x i64] %r1
+}
+
+define [2 x i64] @u16x8_to_u128(i16 %h0, i16 %h1, i16 %h2, i16 %h3,
+; CHECK-LABEL: u16x8_to_u128:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $w4 killed $w4 def $x4
+; CHECK-NEXT: // kill: def $w5 killed $w5 def $x5
+; CHECK-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT: // kill: def $w6 killed $w6 def $x6
+; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2
+; CHECK-NEXT: // kill: def $w7 killed $w7 def $x7
+; CHECK-NEXT: // kill: def $w3 killed $w3 def $x3
+; CHECK-NEXT: bfi x4, x5, #16, #16
+; CHECK-NEXT: bfi x0, x1, #16, #16
+; CHECK-NEXT: bfi x4, x6, #32, #16
+; CHECK-NEXT: bfi x0, x2, #32, #16
+; CHECK-NEXT: bfi x4, x7, #48, #16
+; CHECK-NEXT: bfi x0, x3, #48, #16
+; CHECK-NEXT: mov x1, x4
+; CHECK-NEXT: ret
+ i16 %h4, i16 %h5, i16 %h6, i16 %h7) {
+ %z0 = zext i16 %h0 to i64
+ %z1 = zext i16 %h1 to i64
+ %z2 = zext i16 %h2 to i64
+ %z3 = zext i16 %h3 to i64
+ %s1 = shl i64 %z1, 16
+ %s2 = shl i64 %z2, 32
+ %s3 = shl i64 %z3, 48
+ %lo1 = or i64 %s3, %s2
+ %lo2 = or i64 %lo1, %s1
+ %lo = or i64 %lo2, %z0
+ %z4 = zext i16 %h4 to i64
+ %z5 = zext i16 %h5 to i64
+ %z6 = zext i16 %h6 to i64
+ %z7 = zext i16 %h7 to i64
+ %s5 = shl i64 %z5, 16
+ %s6 = shl i64 %z6, 32
+ %s7 = shl i64 %z7, 48
+ %hi1 = or i64 %s7, %s6
+ %hi2 = or i64 %hi1, %s5
+ %hi = or i64 %hi2, %z4
+ %r0 = insertvalue [2 x i64] poison, i64 %lo, 0
+ %r1 = insertvalue [2 x i64] %r0, i64 %hi, 1
+ ret [2 x i64] %r1
+}
+
+define [2 x i64] @u8x16_to_u128(i8 %b0, i8 %b1, i8 %b2, i8 %b3,
+; CHECK-LABEL: u8x16_to_u128:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ldrb w9, [sp, #8]
+; CHECK-NEXT: ldrb w8, [sp]
+; CHECK-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2
+; CHECK-NEXT: // kill: def $w3 killed $w3 def $x3
+; CHECK-NEXT: // kill: def $w4 killed $w4 def $x4
+; CHECK-NEXT: // kill: def $w5 killed $w5 def $x5
+; CHECK-NEXT: // kill: def $w6 killed $w6 def $x6
+; CHECK-NEXT: // kill: def $w7 killed $w7 def $x7
+; CHECK-NEXT: ldrb w10, [sp, #16]
+; CHECK-NEXT: bfi x0, x1, #8, #8
+; CHECK-NEXT: bfi x8, x9, #8, #8
+; CHECK-NEXT: ldrb w9, [sp, #24]
+; CHECK-NEXT: bfi x0, x2, #16, #8
+; CHECK-NEXT: bfi x8, x10, #16, #8
+; CHECK-NEXT: ldrb w10, [sp, #32]
+; CHECK-NEXT: bfi x0, x3, #24, #8
+; CHECK-NEXT: bfi x8, x9, #24, #8
+; CHECK-NEXT: ldrb w9, [sp, #40]
+; CHECK-NEXT: bfi x0, x4, #32, #8
+; CHECK-NEXT: bfi x8, x10, #32, #8
+; CHECK-NEXT: ldrb w10, [sp, #48]
+; CHECK-NEXT: bfi x0, x5, #40, #8
+; CHECK-NEXT: bfi x8, x9, #40, #8
+; CHECK-NEXT: ldrb w9, [sp, #56]
+; CHECK-NEXT: bfi x0, x6, #48, #8
+; CHECK-NEXT: bfi x8, x10, #48, #8
+; CHECK-NEXT: bfi x0, x7, #56, #8
+; CHECK-NEXT: bfi x8, x9, #56, #8
+; CHECK-NEXT: mov x1, x8
+; CHECK-NEXT: ret
+ i8 %b4, i8 %b5, i8 %b6, i8 %b7,
+ i8 %b8, i8 %b9, i8 %b10, i8 %b11,
+ i8 %b12, i8 %b13, i8 %b14, i8 %b15) {
+ %z0 = zext i8 %b0 to i64
+ %z1 = zext i8 %b1 to i64
+ %z2 = zext i8 %b2 to i64
+ %z3 = zext i8 %b3 to i64
+ %z4 = zext i8 %b4 to i64
+ %z5 = zext i8 %b5 to i64
+ %z6 = zext i8 %b6 to i64
+ %z7 = zext i8 %b7 to i64
+ %s1 = shl i64 %z1, 8
+ %s2 = shl i64 %z2, 16
+ %s3 = shl i64 %z3, 24
+ %s4 = shl i64 %z4, 32
+ %s5 = shl i64 %z5, 40
+ %s6 = shl i64 %z6, 48
+ %s7 = shl i64 %z7, 56
+ %lo1 = or i64 %s7, %s6
+ %lo2 = or i64 %lo1, %s5
+ %lo3 = or i64 %lo2, %s4
+ %lo4 = or i64 %lo3, %s3
+ %lo5 = or i64 %lo4, %s2
+ %lo6 = or i64 %lo5, %s1
+ %lo = or i64 %lo6, %z0
+ %z8 = zext i8 %b8 to i64
+ %z9 = zext i8 %b9 to i64
+ %z10 = zext i8 %b10 to i64
+ %z11 = zext i8 %b11 to i64
+ %z12 = zext i8 %b12 to i64
+ %z13 = zext i8 %b13 to i64
+ %z14 = zext i8 %b14 to i64
+ %z15 = zext i8 %b15 to i64
+ %s9 = shl i64 %z9, 8
+ %s10 = shl i64 %z10, 16
+ %s11 = shl i64 %z11, 24
+ %s12 = shl i64 %z12, 32
+ %s13 = shl i64 %z13, 40
+ %s14 = shl i64 %z14, 48
+ %s15 = shl i64 %z15, 56
+ %hi1 = or i64 %s15, %s14
+ %hi2 = or i64 %hi1, %s13
+ %hi3 = or i64 %hi2, %s12
+ %hi4 = or i64 %hi3, %s11
+ %hi5 = or i64 %hi4, %s10
+ %hi6 = or i64 %hi5, %s9
+ %hi = or i64 %hi6, %z8
+ %r0 = insertvalue [2 x i64] poison, i64 %lo, 0
+ %r1 = insertvalue [2 x i64] %r0, i64 %hi, 1
+ ret [2 x i64] %r1
+}
>From ef66f1669e413a44158a451c58e9b316f1a8168a Mon Sep 17 00:00:00 2001
From: clingfei <chenglingfei at foxmail.com>
Date: Wed, 1 Jul 2026 11:04:14 +0800
Subject: [PATCH 2/2] Remove check on physical registers
---
.../lib/Target/AArch64/AArch64ISelDAGToDAG.cpp | 18 ++++--------------
1 file changed, 4 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 9ffddc975de77..ffe65b13bd32e 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -15,7 +15,6 @@
#include "MCTargetDesc/AArch64AddressingModes.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/CodeGen/ISDOpcodes.h"
-#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/IR/Function.h" // To access function attributes.
#include "llvm/IR/GlobalValue.h"
@@ -3529,8 +3528,8 @@ static bool isPackedBitfieldFixedStackLoad(SDValue Op) {
}
// A packed-bitfield source is a value cheap enough that inserting it with a BFM
-// is worthwhile: an incoming integer argument in W0-W7/X0-X7, or a narrow load
-// from a fixed stack slot, possibly behind extends or an INSERT_SUBREG.
+// is worthwhile: any register-passed value or a narrow load from a fixed stack
+// slot, possibly behind extends or an INSERT_SUBREG.
static bool isPackedBitfieldSource(SelectionDAG *CurDAG, SDValue Src) {
if (Src.getOpcode() == ISD::ANY_EXTEND || Src.getOpcode() == ISD::ZERO_EXTEND)
return isPackedBitfieldSource(CurDAG, Src.getOperand(0));
@@ -3542,8 +3541,7 @@ static bool isPackedBitfieldSource(SelectionDAG *CurDAG, SDValue Src) {
if (isPackedBitfieldFixedStackLoad(Src))
return true;
- // The only other accepted leaf is a CopyFromReg of a live-in argument
- // register.
+ // The only other accepted leaf is a CopyFromReg of a live-in register.
if (Src.getOpcode() != ISD::CopyFromReg || Src.getResNo() != 0 ||
Src.getOperand(0).getOpcode() != ISD::EntryToken)
return false;
@@ -3552,15 +3550,7 @@ static bool isPackedBitfieldSource(SelectionDAG *CurDAG, SDValue Src) {
if (VT != MVT::i32 && VT != MVT::i64)
return false;
- auto *RegNode = dyn_cast<RegisterSDNode>(Src.getOperand(1));
- if (!RegNode || !RegNode->getReg().isVirtual())
- return false;
-
- MCRegister PhysReg =
- CurDAG->getMachineFunction().getRegInfo().getLiveInPhysReg(
- RegNode->getReg());
- return (AArch64::W0 <= PhysReg && PhysReg <= AArch64::W7) ||
- (AArch64::X0 <= PhysReg && PhysReg <= AArch64::X7);
+ return true;
}
static SDValue widenPackedSource(SelectionDAG *CurDAG, SDValue Src, EVT VT,
More information about the llvm-commits
mailing list