[llvm] [AArch64] Use `bfi` to combine registers (PR #194794)

Cheng Lingfei via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 11 21:52:35 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] [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
+}



More information about the llvm-commits mailing list