[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