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

Cheng Lingfei via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 28 23:36:10 PDT 2026


https://github.com/clingfei created https://github.com/llvm/llvm-project/pull/194794

Fix missed `bfi` selection when AArch64 packs multiple small integer arguments into a larger scalar return value. Previously, LLVM handled simple two-field cases, but larger patterns often lowered to extra and/lsl/orr instructions.

Closes https://github.com/llvm/llvm-project/issues/119093.

>From 7278682cb0e323adcc259050f9f2721e9d653325 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    | 258 ++++++++++++++++++
 .../CodeGen/AArch64/bitfield-insert-packed.ll | 239 ++++++++++++++++
 2 files changed, 497 insertions(+)
 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..82d539e4f670f 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,259 @@ 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;
+}
+
+static bool isPackedBitfieldGPRArgument(SelectionDAG *CurDAG, SDValue Op) {
+  if (Op.getOpcode() != ISD::CopyFromReg || Op.getResNo() != 0 ||
+      Op.getOperand(0).getOpcode() != ISD::EntryToken)
+    return false;
+
+  EVT VT = Op.getValueType();
+  if (VT != MVT::i32 && VT != MVT::i64)
+    return false;
+
+  auto *RegNode = dyn_cast<RegisterSDNode>(Op.getOperand(1));
+  if (!RegNode)
+    return false;
+
+  Register VReg = RegNode->getReg();
+  if (!VReg.isVirtual())
+    return false;
+
+  MCRegister PhysReg =
+      CurDAG->getMachineFunction().getRegInfo().getLiveInPhysReg(VReg);
+  return (AArch64::W0 <= PhysReg && PhysReg <= AArch64::W7) ||
+         (AArch64::X0 <= PhysReg && PhysReg <= AArch64::X7);
+}
+
+static bool isPackedBitfieldSource(SelectionDAG *CurDAG, SDValue Src) {
+  if (isPackedBitfieldGPRArgument(CurDAG, Src) ||
+      isPackedBitfieldFixedStackLoad(Src))
+    return true;
+
+  switch (Src.getOpcode()) {
+  case ISD::ANY_EXTEND:
+  case ISD::ZERO_EXTEND:
+    return isPackedBitfieldSource(CurDAG, Src.getOperand(0));
+  default:
+    break;
+  }
+
+  if (Src.isMachineOpcode() &&
+      Src.getMachineOpcode() == TargetOpcode::INSERT_SUBREG)
+    return isPackedBitfieldSource(CurDAG, Src.getOperand(1));
+
+  return false;
+}
+
+static bool getPackedLowBitfieldTerm(SelectionDAG *CurDAG, SDValue Op,
+                                     PackedBitfieldTerm &Term) {
+  EVT VT = Op.getValueType();
+  if (VT != MVT::i32 && VT != MVT::i64)
+    return false;
+
+  unsigned BitWidth = VT.getSizeInBits();
+  uint64_t MaskImm;
+  if (isOpcWithIntImmediate(Op.getNode(), ISD::AND, MaskImm) &&
+      isMask_64(MaskImm)) {
+    unsigned Width = llvm::countr_one(MaskImm);
+    if (Width == 0 || Width >= BitWidth)
+      return false;
+    Term = {Op.getOperand(0), 0, Width};
+    return true;
+  }
+
+  if (Op.getOpcode() == ISD::ZERO_EXTEND) {
+    KnownBits Known = CurDAG->computeKnownBits(Op);
+    APInt NonZero = ~Known.Zero;
+    if (!NonZero.isMask())
+      return false;
+
+    SDValue Src = Op.getOperand(0);
+    unsigned Width = NonZero.countr_one();
+    if (Width == 0 || Width >= BitWidth)
+      return false;
+    if (Src.getValueType() != VT) {
+      if (VT == MVT::i64 && Src.getValueType() == MVT::i32)
+        Src = Widen(CurDAG, Src);
+      else
+        Src = CurDAG->getNode(ISD::ANY_EXTEND, SDLoc(Op), VT, Src);
+    }
+    Term = {Src, 0, Width};
+    return true;
+  }
+
+  auto *Ld = dyn_cast<LoadSDNode>(Op);
+  if (isPackedBitfieldFixedStackLoad(Op)) {
+    unsigned Width = Ld->getMemoryVT().getScalarSizeInBits();
+    if (Width != 0 && Width < BitWidth) {
+      Term = {Op, 0, Width};
+      return true;
+    }
+  }
+
+  return false;
+}
+
+static bool isLowMaskAnd(SDValue Op, unsigned Width, SDValue &Base) {
+  uint64_t MaskImm;
+  if (!isOpcWithIntImmediate(Op.getNode(), ISD::AND, MaskImm) ||
+      !isMask_64(MaskImm))
+    return false;
+
+  if (static_cast<unsigned>(llvm::countr_one(MaskImm)) < Width)
+    return false;
+
+  Base = Op.getOperand(0);
+  return true;
+}
+
+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);
+}
+
+static SDValue stripPackedSourceMask(SelectionDAG *CurDAG, SDValue Src,
+                                     unsigned Width, EVT VT, SDLoc DL) {
+  SDValue Base;
+  if (isLowMaskAnd(Src, Width, Base))
+    return widenPackedSource(CurDAG, Base, VT, DL);
+
+  if ((Src.getOpcode() == ISD::ANY_EXTEND ||
+       Src.getOpcode() == ISD::ZERO_EXTEND) &&
+      isLowMaskAnd(Src.getOperand(0), Width, Base))
+    return widenPackedSource(CurDAG, Base, VT, DL);
+
+  return widenPackedSource(CurDAG, Src, VT, DL);
+}
+
+static bool getPackedBitfieldTerm(SelectionDAG *CurDAG, SDValue Op,
+                                  PackedBitfieldTerm &Term) {
+  if (getPackedLowBitfieldTerm(CurDAG, Op, Term))
+    return isPackedBitfieldSource(CurDAG, Term.Src);
+
+  if (Op.getOpcode() == ISD::ZERO_EXTEND && Op.getValueType() == MVT::i64 &&
+      Op.getOperand(0).getValueType() == MVT::i32) {
+    SDValue Src;
+    int DstLSB, Width;
+    if (isBitfieldPositioningOp(CurDAG, Op.getOperand(0),
+                                /*BiggerPattern=*/true, Src, DstLSB, Width)) {
+      if (DstLSB < 0 || Width <= 0)
+        return false;
+      Src = stripPackedSourceMask(CurDAG, Src, Width, MVT::i64, SDLoc(Op));
+      if (!isPackedBitfieldSource(CurDAG, Src))
+        return false;
+      Term = {Src, static_cast<unsigned>(DstLSB),
+              static_cast<unsigned>(Width)};
+      return true;
+    }
+  }
+
+  SDValue Src;
+  int DstLSB, Width;
+  if (!isBitfieldPositioningOp(CurDAG, Op, /*BiggerPattern=*/true, Src, DstLSB,
+                               Width))
+    return false;
+
+  if (DstLSB < 0 || Width <= 0)
+    return false;
+
+  EVT VT = Op.getValueType();
+  Src = stripPackedSourceMask(CurDAG, Src, Width, 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 +4220,10 @@ bool AArch64DAGToDAGISel::tryBitfieldInsertOp(SDNode *N) {
     return true;
   }
 
+  if (OptLevel != CodeGenOptLevel::None &&
+      tryPackedBitfieldInsertOp(N, CurDAG))
+    return true;
+
   if (tryBitfieldInsertOpFromOr(N, NUsefulBits, CurDAG))
     return true;
 
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..43ded2986741b
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/bitfield-insert-packed.ll
@@ -0,0 +1,239 @@
+; 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:       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:       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:       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:       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:       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,
+                        i8 %b4, i8 %b5, i8 %b6, i8 %b7) {
+; CHECK-LABEL: u8x8_to_u64:
+; CHECK:       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
+  %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:       bfi	x2, x3, #32, #32
+; CHECK-NEXT:  bfi	x0, x1, #32, #32
+; CHECK-NEXT:  mov	x1, x2
+; CHECK:       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,
+                                i16 %h4, i16 %h5, i16 %h6, i16 %h7) {
+; CHECK-LABEL: u16x8_to_u128:
+; CHECK:       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:       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
+  %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,
+                                i8 %b4, i8 %b5, i8 %b6, i8 %b7,
+                                i8 %b8, i8 %b9, i8 %b10, i8 %b11,
+                                i8 %b12, i8 %b13, i8 %b14, i8 %b15) {
+; CHECK-LABEL: u8x16_to_u128:
+; CHECK:       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:       ret
+  %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