https://github.com/pedroclobo updated https://github.com/llvm/llvm-project/pull/229147
>From d1a3ebc08232b629252e93b7342e6e9a7cea8ed2 Mon Sep 17 00:00:00 2001 From: Pedro Lobo <[email protected]> Date: Mon, 5 Oct 2026 14:42:34 +0100 Subject: [PATCH 1/2] [InstCombine] Pre-commit tests for full-width `bitinsert`/`bitextract` --- .../InstCombine/bitinsert-bitextract.ll | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 llvm/test/Transforms/InstCombine/bitinsert-bitextract.ll diff --git a/llvm/test/Transforms/InstCombine/bitinsert-bitextract.ll b/llvm/test/Transforms/InstCombine/bitinsert-bitextract.ll new file mode 100644 index 0000000000000..8b2d825fa28c8 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/bitinsert-bitextract.ll @@ -0,0 +1,152 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +target datalayout = "p1:32:32" + +define i64 @bitextract_i64(b64 %x) { +; CHECK-LABEL: define i64 @bitextract_i64( +; CHECK-SAME: b64 [[X:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = bitextract i64, b64 [[X]], i32 0 +; CHECK-NEXT: ret i64 [[R]] +; + %r = bitextract i64, b64 %x, i32 0 + ret i64 %r +} + +define double @bitextract_double(b64 %x) { +; CHECK-LABEL: define double @bitextract_double( +; CHECK-SAME: b64 [[X:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = bitextract double, b64 [[X]], i32 0 +; CHECK-NEXT: ret double [[R]] +; + %r = bitextract double, b64 %x, i32 0 + ret double %r +} + +define ptr @bitextract_ptr(b64 %x) { +; CHECK-LABEL: define ptr @bitextract_ptr( +; CHECK-SAME: b64 [[X:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = bitextract ptr, b64 [[X]], i32 0 +; CHECK-NEXT: ret ptr [[R]] +; + %r = bitextract ptr, b64 %x, i32 0 + ret ptr %r +} + +define ptr addrspace(1) @bitextract_ptr_as1(b32 %x) { +; CHECK-LABEL: define ptr addrspace(1) @bitextract_ptr_as1( +; CHECK-SAME: b32 [[X:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = bitextract ptr addrspace(1), b32 [[X]], i32 0 +; CHECK-NEXT: ret ptr addrspace(1) [[R]] +; + %r = bitextract ptr addrspace(1), b32 %x, i32 0 + ret ptr addrspace(1) %r +} + +define b64 @bitinsert_i64(b64 %x, i64 %y) { +; CHECK-LABEL: define b64 @bitinsert_i64( +; CHECK-SAME: b64 [[X:%.*]], i64 [[Y:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = bitinsert b64 [[X]], i64 [[Y]], i32 0 +; CHECK-NEXT: ret b64 [[R]] +; + %r = bitinsert b64 %x, i64 %y, i32 0 + ret b64 %r +} + +define b32 @bitinsert_float(b32 %x, float %y) { +; CHECK-LABEL: define b32 @bitinsert_float( +; CHECK-SAME: b32 [[X:%.*]], float [[Y:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = bitinsert b32 [[X]], float [[Y]], i32 0 +; CHECK-NEXT: ret b32 [[R]] +; + %r = bitinsert b32 %x, float %y, i32 0 + ret b32 %r +} + +define b64 @bitinsert_ptr(b64 %x, ptr %y) { +; CHECK-LABEL: define b64 @bitinsert_ptr( +; CHECK-SAME: b64 [[X:%.*]], ptr [[Y:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = bitinsert b64 [[X]], ptr [[Y]], i32 0 +; CHECK-NEXT: ret b64 [[R]] +; + %r = bitinsert b64 %x, ptr %y, i32 0 + ret b64 %r +} + +define i8 @bitextract_bitinsert(b32 %x, i8 %y) { +; CHECK-LABEL: define i8 @bitextract_bitinsert( +; CHECK-SAME: b32 [[X:%.*]], i8 [[Y:%.*]]) { +; CHECK-NEXT: [[I:%.*]] = bitinsert b32 [[X]], i8 [[Y]], i32 8 +; CHECK-NEXT: [[R:%.*]] = bitextract i8, b32 [[I]], i32 8 +; CHECK-NEXT: ret i8 [[R]] +; + %i = bitinsert b32 %x, i8 %y, i32 8 + %r = bitextract i8, b32 %i, i32 8 + ret i8 %r +} + +; The result is narrower than the source. +define i32 @neg_bitextract_partial(b64 %x) { +; CHECK-LABEL: define i32 @neg_bitextract_partial( +; CHECK-SAME: b64 [[X:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = bitextract i32, b64 [[X]], i32 0 +; CHECK-NEXT: ret i32 [[R]] +; + %r = bitextract i32, b64 %x, i32 0 + ret i32 %r +} + +; The pointer is narrower than the source. +define ptr @neg_bitextract_ptr_narrow(b128 %x) { +; CHECK-LABEL: define ptr @neg_bitextract_ptr_narrow( +; CHECK-SAME: b128 [[X:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = bitextract ptr, b128 [[X]], i32 0 +; CHECK-NEXT: ret ptr [[R]] +; + %r = bitextract ptr, b128 %x, i32 0 + ret ptr %r +} + +; Pointers in addrspace(1) are 32 bits wide. +define ptr addrspace(1) @neg_bitextract_ptr_as1(b64 %x) { +; CHECK-LABEL: define ptr addrspace(1) @neg_bitextract_ptr_as1( +; CHECK-SAME: b64 [[X:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = bitextract ptr addrspace(1), b64 [[X]], i32 0 +; CHECK-NEXT: ret ptr addrspace(1) [[R]] +; + %r = bitextract ptr addrspace(1), b64 %x, i32 0 + ret ptr addrspace(1) %r +} + +; The offset may not be zero. +define i64 @neg_bitextract_variable_offset(b64 %x, i32 %n) { +; CHECK-LABEL: define i64 @neg_bitextract_variable_offset( +; CHECK-SAME: b64 [[X:%.*]], i32 [[N:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = bitextract i64, b64 [[X]], i32 [[N]] +; CHECK-NEXT: ret i64 [[R]] +; + %r = bitextract i64, b64 %x, i32 %n + ret i64 %r +} + +; The value is narrower than the base. +define b64 @neg_bitinsert_partial(b64 %x, i32 %y) { +; CHECK-LABEL: define b64 @neg_bitinsert_partial( +; CHECK-SAME: b64 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = bitinsert b64 [[X]], i32 [[Y]], i32 0 +; CHECK-NEXT: ret b64 [[R]] +; + %r = bitinsert b64 %x, i32 %y, i32 0 + ret b64 %r +} + +; The offset may not be zero. +define b64 @neg_bitinsert_variable_offset(b64 %x, i64 %y, i32 %n) { +; CHECK-LABEL: define b64 @neg_bitinsert_variable_offset( +; CHECK-SAME: b64 [[X:%.*]], i64 [[Y:%.*]], i32 [[N:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = bitinsert b64 [[X]], i64 [[Y]], i32 [[N]] +; CHECK-NEXT: ret b64 [[R]] +; + %r = bitinsert b64 %x, i64 %y, i32 %n + ret b64 %r +} >From 44d6fa4145133381491fc2a23ede7333e3b43ded Mon Sep 17 00:00:00 2001 From: Pedro Lobo <[email protected]> Date: Mon, 5 Oct 2026 14:57:32 +0100 Subject: [PATCH 2/2] [InstCombine] Fold full-width `bitinsert` and `bitextract` to `bitcast` --- .../InstCombine/InstCombineInternal.h | 2 ++ .../InstCombine/InstructionCombining.cpp | 31 +++++++++++++++++++ .../InstCombine/bitinsert-bitextract.ll | 18 +++++------ 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h index 07bc7e302c9ec..34a9da4ae9b2a 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -192,6 +192,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final Instruction *simplifyBinOpSplats(ShuffleVectorInst &SVI); Instruction *visitShuffleVectorInst(ShuffleVectorInst &SVI); Instruction *visitExtractValueInst(ExtractValueInst &EV); + Instruction *visitBitInsertInst(BitInsertInst &BI); + Instruction *visitBitExtractInst(BitExtractInst &BE); Instruction *visitLandingPadInst(LandingPadInst &LI); Instruction *visitVAEndInst(VAEndInst &I); Value *pushFreezeToPreventPoisonFromPropagating(FreezeInst &FI); diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 8d299bcbc4369..ac63e9476104f 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -4831,6 +4831,37 @@ Instruction *InstCombinerImpl::visitExtractValueInst(ExtractValueInst &EV) { return nullptr; } +Instruction *InstCombinerImpl::visitBitInsertInst(BitInsertInst &BI) { + Value *Base = BI.getOperand(0); + Value *Val = BI.getOperand(1); + Value *Offset = BI.getOperand(2); + if (Value *V = + simplifyBitInsertInst(Base, Val, Offset, SQ.getWithInstruction(&BI))) + return replaceInstUsesWith(BI, V); + + // bitinsert (bN x), (ty y), 0 -> bitcast y to bN, if ty is N bits wide + if (match(Offset, m_Zero()) && DL.getTypeSizeInBits(Val->getType()) == + DL.getTypeSizeInBits(Base->getType())) + return new BitCastInst(Val, Base->getType()); + + return nullptr; +} + +Instruction *InstCombinerImpl::visitBitExtractInst(BitExtractInst &BE) { + Value *Src = BE.getOperand(0); + Value *Offset = BE.getOperand(1); + if (Value *V = simplifyBitExtractInst(BE.getType(), Src, Offset, + SQ.getWithInstruction(&BE))) + return replaceInstUsesWith(BE, V); + + // bitextract ty, (bN x), 0 -> bitcast x to ty, if ty is N bits wide + if (match(Offset, m_Zero()) && DL.getTypeSizeInBits(BE.getType()) == + DL.getTypeSizeInBits(Src->getType())) + return new BitCastInst(Src, BE.getType()); + + return nullptr; +} + /// Return 'true' if the given typeinfo will match anything. static bool isCatchAll(EHPersonality Personality, Constant *TypeInfo) { switch (Personality) { diff --git a/llvm/test/Transforms/InstCombine/bitinsert-bitextract.ll b/llvm/test/Transforms/InstCombine/bitinsert-bitextract.ll index 8b2d825fa28c8..59aef89ea5d99 100644 --- a/llvm/test/Transforms/InstCombine/bitinsert-bitextract.ll +++ b/llvm/test/Transforms/InstCombine/bitinsert-bitextract.ll @@ -6,7 +6,7 @@ target datalayout = "p1:32:32" define i64 @bitextract_i64(b64 %x) { ; CHECK-LABEL: define i64 @bitextract_i64( ; CHECK-SAME: b64 [[X:%.*]]) { -; CHECK-NEXT: [[R:%.*]] = bitextract i64, b64 [[X]], i32 0 +; CHECK-NEXT: [[R:%.*]] = bitcast b64 [[X]] to i64 ; CHECK-NEXT: ret i64 [[R]] ; %r = bitextract i64, b64 %x, i32 0 @@ -16,7 +16,7 @@ define i64 @bitextract_i64(b64 %x) { define double @bitextract_double(b64 %x) { ; CHECK-LABEL: define double @bitextract_double( ; CHECK-SAME: b64 [[X:%.*]]) { -; CHECK-NEXT: [[R:%.*]] = bitextract double, b64 [[X]], i32 0 +; CHECK-NEXT: [[R:%.*]] = bitcast b64 [[X]] to double ; CHECK-NEXT: ret double [[R]] ; %r = bitextract double, b64 %x, i32 0 @@ -26,7 +26,7 @@ define double @bitextract_double(b64 %x) { define ptr @bitextract_ptr(b64 %x) { ; CHECK-LABEL: define ptr @bitextract_ptr( ; CHECK-SAME: b64 [[X:%.*]]) { -; CHECK-NEXT: [[R:%.*]] = bitextract ptr, b64 [[X]], i32 0 +; CHECK-NEXT: [[R:%.*]] = bitcast b64 [[X]] to ptr ; CHECK-NEXT: ret ptr [[R]] ; %r = bitextract ptr, b64 %x, i32 0 @@ -36,7 +36,7 @@ define ptr @bitextract_ptr(b64 %x) { define ptr addrspace(1) @bitextract_ptr_as1(b32 %x) { ; CHECK-LABEL: define ptr addrspace(1) @bitextract_ptr_as1( ; CHECK-SAME: b32 [[X:%.*]]) { -; CHECK-NEXT: [[R:%.*]] = bitextract ptr addrspace(1), b32 [[X]], i32 0 +; CHECK-NEXT: [[R:%.*]] = bitcast b32 [[X]] to ptr addrspace(1) ; CHECK-NEXT: ret ptr addrspace(1) [[R]] ; %r = bitextract ptr addrspace(1), b32 %x, i32 0 @@ -46,7 +46,7 @@ define ptr addrspace(1) @bitextract_ptr_as1(b32 %x) { define b64 @bitinsert_i64(b64 %x, i64 %y) { ; CHECK-LABEL: define b64 @bitinsert_i64( ; CHECK-SAME: b64 [[X:%.*]], i64 [[Y:%.*]]) { -; CHECK-NEXT: [[R:%.*]] = bitinsert b64 [[X]], i64 [[Y]], i32 0 +; CHECK-NEXT: [[R:%.*]] = bitcast i64 [[Y]] to b64 ; CHECK-NEXT: ret b64 [[R]] ; %r = bitinsert b64 %x, i64 %y, i32 0 @@ -56,7 +56,7 @@ define b64 @bitinsert_i64(b64 %x, i64 %y) { define b32 @bitinsert_float(b32 %x, float %y) { ; CHECK-LABEL: define b32 @bitinsert_float( ; CHECK-SAME: b32 [[X:%.*]], float [[Y:%.*]]) { -; CHECK-NEXT: [[R:%.*]] = bitinsert b32 [[X]], float [[Y]], i32 0 +; CHECK-NEXT: [[R:%.*]] = bitcast float [[Y]] to b32 ; CHECK-NEXT: ret b32 [[R]] ; %r = bitinsert b32 %x, float %y, i32 0 @@ -66,7 +66,7 @@ define b32 @bitinsert_float(b32 %x, float %y) { define b64 @bitinsert_ptr(b64 %x, ptr %y) { ; CHECK-LABEL: define b64 @bitinsert_ptr( ; CHECK-SAME: b64 [[X:%.*]], ptr [[Y:%.*]]) { -; CHECK-NEXT: [[R:%.*]] = bitinsert b64 [[X]], ptr [[Y]], i32 0 +; CHECK-NEXT: [[R:%.*]] = bitcast ptr [[Y]] to b64 ; CHECK-NEXT: ret b64 [[R]] ; %r = bitinsert b64 %x, ptr %y, i32 0 @@ -76,9 +76,7 @@ define b64 @bitinsert_ptr(b64 %x, ptr %y) { define i8 @bitextract_bitinsert(b32 %x, i8 %y) { ; CHECK-LABEL: define i8 @bitextract_bitinsert( ; CHECK-SAME: b32 [[X:%.*]], i8 [[Y:%.*]]) { -; CHECK-NEXT: [[I:%.*]] = bitinsert b32 [[X]], i8 [[Y]], i32 8 -; CHECK-NEXT: [[R:%.*]] = bitextract i8, b32 [[I]], i32 8 -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 [[Y]] ; %i = bitinsert b32 %x, i8 %y, i32 8 %r = bitextract i8, b32 %i, i32 8 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
