[llvm] [X86] Remove redundant TEST after shifts when count is non-zero (PR #169069)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 25 10:52:02 PST 2025
https://github.com/GrumpyPigSkin updated https://github.com/llvm/llvm-project/pull/169069
>From c43871f2418f28520b77adcdd5c4de5a25c9a821 Mon Sep 17 00:00:00 2001
From: GrumpyPigSkin <oliver61 at live.co.uk>
Date: Fri, 21 Nov 2025 16:52:26 +0000
Subject: [PATCH 01/10] [X86] Added new ISDX86 nodes for SHL/SHR/SAR opcodes.
---
llvm/lib/Target/X86/X86ISelLowering.h | 3 ++
llvm/lib/Target/X86/X86InstrShiftRotate.td | 49 ++++++++++++++++++++++
2 files changed, 52 insertions(+)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h
index b7151f65942b4..00830804213f7 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.h
+++ b/llvm/lib/Target/X86/X86ISelLowering.h
@@ -996,6 +996,9 @@ namespace llvm {
CLOAD,
CSTORE,
LAST_MEMORY_OPCODE = CSTORE,
+ SHL,
+ SRL,
+ SRA,
};
} // end namespace X86ISD
diff --git a/llvm/lib/Target/X86/X86InstrShiftRotate.td b/llvm/lib/Target/X86/X86InstrShiftRotate.td
index 2a5488847e648..e81bc33d3a459 100644
--- a/llvm/lib/Target/X86/X86InstrShiftRotate.td
+++ b/llvm/lib/Target/X86/X86InstrShiftRotate.td
@@ -689,3 +689,52 @@ let Predicates = [HasBMI2, HasEGPR] in {
defm SHRX : ShiftX_Pats<srl, "_EVEX">;
defm SHLX : ShiftX_Pats<shl, "_EVEX">;
}
+
+def SDTX86ShiftWithFlags : SDTypeProfile<2, 1, [
+ SDTCisSameAs<0, 2>,
+ SDTCisVT<1, i32>,
+]>;
+
+def X86shl : SDNode<"X86ISD::SHL", SDTX86ShiftWithFlags, [SDNPInGlue]>;
+def X86srl : SDNode<"X86ISD::SRL", SDTX86ShiftWithFlags, [SDNPInGlue]>;
+def X86sra : SDNode<"X86ISD::SRA", SDTX86ShiftWithFlags, [SDNPInGlue]>;
+
+let Predicates = [NoNDD] in {
+ // SHL
+ def : Pat<(X86shl GR8:$src1), (SHL8rCL GR8:$src1)>;
+ def : Pat<(X86shl GR16:$src1), (SHL16rCL GR16:$src1)>;
+ def : Pat<(X86shl GR32:$src1), (SHL32rCL GR32:$src1)>;
+ def : Pat<(X86shl GR64:$src1), (SHL64rCL GR64:$src1)>;
+
+ // SHR
+ def : Pat<(X86srl GR8:$src1), (SHR8rCL GR8:$src1)>;
+ def : Pat<(X86srl GR16:$src1), (SHR16rCL GR16:$src1)>;
+ def : Pat<(X86srl GR32:$src1), (SHR32rCL GR32:$src1)>;
+ def : Pat<(X86srl GR64:$src1), (SHR64rCL GR64:$src1)>;
+
+ // SAR
+ def : Pat<(X86sra GR8:$src1), (SAR8rCL GR8:$src1)>;
+ def : Pat<(X86sra GR16:$src1), (SAR16rCL GR16:$src1)>;
+ def : Pat<(X86sra GR32:$src1), (SAR32rCL GR32:$src1)>;
+ def : Pat<(X86sra GR64:$src1), (SAR64rCL GR64:$src1)>;
+}
+
+let Predicates = [HasNDD, In64BitMode] in {
+ // SHL
+ def : Pat<(X86shl GR8:$src1), (SHL8rCL_ND GR8:$src1)>;
+ def : Pat<(X86shl GR16:$src1), (SHL16rCL_ND GR16:$src1)>;
+ def : Pat<(X86shl GR32:$src1), (SHL32rCL_ND GR32:$src1)>;
+ def : Pat<(X86shl GR64:$src1), (SHL64rCL_ND GR64:$src1)>;
+
+ // SHR
+ def : Pat<(X86srl GR8:$src1), (SHR8rCL_ND GR8:$src1)>;
+ def : Pat<(X86srl GR16:$src1), (SHR16rCL_ND GR16:$src1)>;
+ def : Pat<(X86srl GR32:$src1), (SHR32rCL_ND GR32:$src1)>;
+ def : Pat<(X86srl GR64:$src1), (SHR64rCL_ND GR64:$src1)>;
+
+ // SAR
+ def : Pat<(X86sra GR8:$src1), (SAR8rCL_ND GR8:$src1)>;
+ def : Pat<(X86sra GR16:$src1), (SAR16rCL_ND GR16:$src1)>;
+ def : Pat<(X86sra GR32:$src1), (SAR32rCL_ND GR32:$src1)>;
+ def : Pat<(X86sra GR64:$src1), (SAR64rCL_ND GR64:$src1)>;
+}
>From 8e0c2675dbd4abbbb004e3ea039cc63847cf8681 Mon Sep 17 00:00:00 2001
From: GrumpyPigSkin <oliver61 at live.co.uk>
Date: Fri, 21 Nov 2025 16:54:53 +0000
Subject: [PATCH 02/10] [X86] Added check to allow the removal of test
instruction when the shift amt > 0
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 51 +++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index dc84025c166a3..87e637ee4c272 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -23625,6 +23625,54 @@ static SDValue EmitTest(SDValue Op, X86::CondCode X86CC, const SDLoc &dl,
return DAG.getNode(X86ISD::SUB, dl, VTs, Op->getOperand(0),
Op->getOperand(1)).getValue(1);
}
+ case ISD::SHL:
+ case ISD::SRL:
+ case ISD::SRA: {
+ SDValue Amt = ArithOp.getOperand(1);
+
+ // Skip Constants
+ if (isa<ConstantSDNode>(Amt))
+ break;
+
+ // Check we can make this optimization
+ if (ArithOp->getFlags().hasNoZero() || DAG.isKnownNeverZero(Amt)) {
+ SDLoc DL(ArithOp);
+
+ // CopyToReg(CL, Amt)
+ SDValue Chain = DAG.getEntryNode();
+ SDValue Glue;
+
+ Chain = DAG.getCopyToReg(Chain, DL, X86::CL, Amt, Glue);
+ Glue = Chain.getValue(1);
+
+ // Select Opcode
+ unsigned X86Opcode;
+ switch (ArithOp.getOpcode()) {
+ case ISD::SHL:
+ X86Opcode = X86ISD::SHL;
+ break;
+ case ISD::SRL:
+ X86Opcode = X86ISD::SRL;
+ break;
+ case ISD::SRA:
+ X86Opcode = X86ISD::SRA;
+ break;
+ default:
+ llvm_unreachable("Unexpected shift opcode");
+ }
+
+ // Create Node [ValueToShift, Glue]
+ SDVTList VTs = DAG.getVTList(ArithOp.getValueType(), MVT::i32);
+ SDValue Ops[] = {ArithOp.getOperand(0), Glue};
+
+ SDValue NewNode = DAG.getNode(X86Opcode, DL, VTs, Ops);
+
+ // Replace and Return
+ DAG.ReplaceAllUsesOfValueWith(ArithOp, NewNode.getValue(0));
+ return NewNode.getValue(1);
+ }
+ break;
+ }
default:
break;
}
@@ -35467,6 +35515,9 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(CVTTP2UIS)
NODE_NAME_CASE(MCVTTP2UIS)
NODE_NAME_CASE(POP_FROM_X87_REG)
+ NODE_NAME_CASE(SHL)
+ NODE_NAME_CASE(SRL)
+ NODE_NAME_CASE(SRA)
}
return nullptr;
#undef NODE_NAME_CASE
>From d44bb095654053ee5fba13759ddf7c8930a08910 Mon Sep 17 00:00:00 2001
From: GrumpyPigSkin <oliver61 at live.co.uk>
Date: Fri, 21 Nov 2025 16:57:25 +0000
Subject: [PATCH 03/10] [X86] Added new flag to SDNodeFlags to indicate when a
value isn't 0
---
llvm/include/llvm/CodeGen/SelectionDAGNodes.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
index cfc8a4243e894..082e7b4371d27 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
@@ -427,6 +427,7 @@ struct SDNodeFlags {
// implied by its producer as, e.g, operations between producer and PTRADD
// that affect the provenance may have been optimized away.
InBounds = 1 << 15,
+ NoZero = 1 << 16,
// NOTE: Please update LargestValue in LLVM_DECLARE_ENUM_AS_BITMASK below
// the class definition when adding new flags.
@@ -468,6 +469,7 @@ struct SDNodeFlags {
void setNoFPExcept(bool b) { setFlag<NoFPExcept>(b); }
void setUnpredictable(bool b) { setFlag<Unpredictable>(b); }
void setInBounds(bool b) { setFlag<InBounds>(b); }
+ void setNoZero(bool b) { setFlag<NoZero>(b); }
// These are accessors for each flag.
bool hasNoUnsignedWrap() const { return Flags & NoUnsignedWrap; }
@@ -486,6 +488,7 @@ struct SDNodeFlags {
bool hasNoFPExcept() const { return Flags & NoFPExcept; }
bool hasUnpredictable() const { return Flags & Unpredictable; }
bool hasInBounds() const { return Flags & InBounds; }
+ bool hasNoZero() const { return Flags & NoZero; }
bool operator==(const SDNodeFlags &Other) const {
return Flags == Other.Flags;
>From 9d2d01e28e28df17551cc3cc3b86fb0ecce586ab Mon Sep 17 00:00:00 2001
From: GrumpyPigSkin <oliver61 at live.co.uk>
Date: Fri, 21 Nov 2025 16:58:53 +0000
Subject: [PATCH 04/10] [X86] Added check for constant range to pass additional
information down to lowering.
---
.../SelectionDAG/SelectionDAGBuilder.cpp | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 985a54ca83256..51d3fc0d78975 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -3687,6 +3687,7 @@ void SelectionDAGBuilder::visitShift(const User &I, unsigned Opcode) {
bool nuw = false;
bool nsw = false;
bool exact = false;
+ bool noZero = false;
if (Opcode == ISD::SRL || Opcode == ISD::SRA || Opcode == ISD::SHL) {
@@ -3698,11 +3699,30 @@ void SelectionDAGBuilder::visitShift(const User &I, unsigned Opcode) {
if (const PossiblyExactOperator *ExactOp =
dyn_cast<const PossiblyExactOperator>(&I))
exact = ExactOp->isExact();
+
+ const Value *ShiftAmt = I.getOperand(1);
+
+ // Look through zext as computeConstantRange does not do this.
+ const Value *InnerVal = ShiftAmt;
+ if (auto *ZExt = dyn_cast<ZExtInst>(ShiftAmt)) {
+ InnerVal = ZExt->getOperand(0);
+ }
+
+ // Get the constant range and check it excludes 0
+ ConstantRange CR = llvm::computeConstantRange(
+ InnerVal, true, true, AC, dyn_cast<Instruction>(&I), nullptr);
+
+ if (!CR.isEmptySet() && !CR.contains(APInt(CR.getBitWidth(), 0))) {
+ // We can guarantee that that we will not be shifted by 0
+ noZero = true;
+ }
}
+
SDNodeFlags Flags;
Flags.setExact(exact);
Flags.setNoSignedWrap(nsw);
Flags.setNoUnsignedWrap(nuw);
+ Flags.setNoZero(noZero);
SDValue Res = DAG.getNode(Opcode, getCurSDLoc(), Op1.getValueType(), Op1, Op2,
Flags);
setValue(&I, Res);
>From 5cc8c2ca0f065a70c82f124795c969161db0915f Mon Sep 17 00:00:00 2001
From: GrumpyPigSkin <oliver61 at live.co.uk>
Date: Fri, 21 Nov 2025 17:00:54 +0000
Subject: [PATCH 05/10] [X86] Preserved some high level data when assumptions
are eliminated, allowing for future optimizations.
---
llvm/lib/CodeGen/CodeGenPrepare.cpp | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index 587c1372b19cb..b4b4879c515c5 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -786,8 +786,32 @@ bool CodeGenPrepare::eliminateAssumptions(Function &F) {
if (auto *Assume = dyn_cast<AssumeInst>(I)) {
MadeChange = true;
Value *Operand = Assume->getOperand(0);
+ if (ICmpInst *Cmp = dyn_cast<ICmpInst>(Operand)) {
+ // Check if we are comparing an Argument against a Constant
+ if (Argument *Arg = dyn_cast<Argument>(Cmp->getOperand(0))) {
+ if (ConstantInt *C = dyn_cast<ConstantInt>(Cmp->getOperand(1))) {
+ // We found "assume(Arg <pred> Constant)"
+ ConstantRange Constraint = ConstantRange::makeAllowedICmpRegion(
+ Cmp->getPredicate(), C->getValue());
+ // If the argument already has a range attribute, intersect with
+ // it
+ ConstantRange FinalRange = Constraint;
+ Attribute ExistingRangeAttr = Arg->getAttribute(Attribute::Range);
+ if (ExistingRangeAttr.isValid()) {
+ FinalRange =
+ FinalRange.intersectWith(ExistingRangeAttr.getRange());
+ }
+ // If the range provides new information (and isn't empty), save
+ // it.
+ if (!FinalRange.isFullSet() && !FinalRange.isEmptySet()) {
+ AttrBuilder AB(Arg->getContext());
+ AB.addRangeAttr(FinalRange);
+ Arg->addAttrs(AB);
+ }
+ }
+ }
+ }
Assume->eraseFromParent();
-
resetIteratorIfInvalidatedWhileCalling(&BB, [&]() {
RecursivelyDeleteTriviallyDeadInstructions(Operand, TLInfo, nullptr);
});
>From a9a6a0eafa36f178dfa6ac49a5e3f37decefbcbc Mon Sep 17 00:00:00 2001
From: GrumpyPigSkin <oliver61 at live.co.uk>
Date: Fri, 21 Nov 2025 17:01:09 +0000
Subject: [PATCH 06/10] [X86] Updated tests
---
llvm/test/CodeGen/X86/apx/shift-eflags.ll | 23 +++++++++++++++++------
llvm/test/CodeGen/X86/shift-eflags.ll | 23 +++++++++++++++++------
2 files changed, 34 insertions(+), 12 deletions(-)
diff --git a/llvm/test/CodeGen/X86/apx/shift-eflags.ll b/llvm/test/CodeGen/X86/apx/shift-eflags.ll
index 2659f8031ef77..01f4689369eac 100644
--- a/llvm/test/CodeGen/X86/apx/shift-eflags.ll
+++ b/llvm/test/CodeGen/X86/apx/shift-eflags.ll
@@ -265,7 +265,6 @@ define i32 @ashr_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
; CHECK-NEXT: movl %ecx, %eax
; CHECK-NEXT: orb $1, %sil, %cl
; CHECK-NEXT: sarl %cl, %edi
-; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: cmovel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -282,7 +281,6 @@ define i32 @lshr_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
; CHECK-NEXT: movl %ecx, %eax
; CHECK-NEXT: orb $1, %sil, %cl
; CHECK-NEXT: shrl %cl, %edi
-; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: cmovel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -299,7 +297,6 @@ define i32 @shl_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
; CHECK-NEXT: movl %ecx, %eax
; CHECK-NEXT: orb $1, %sil, %cl
; CHECK-NEXT: shll %cl, %edi
-; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: cmovel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -315,7 +312,6 @@ define i32 @ashr_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %
; CHECK: # %bb.0:
; CHECK-NEXT: orb $1, %sil, %cl
; CHECK-NEXT: shrl %cl, %edi, %eax
-; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: cmovnel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -331,7 +327,6 @@ define i32 @lshr_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %
; CHECK: # %bb.0:
; CHECK-NEXT: orb $1, %sil, %cl
; CHECK-NEXT: shrl %cl, %edi, %eax
-; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: cmovnel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -347,7 +342,6 @@ define i32 @shl_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a
; CHECK: # %bb.0:
; CHECK-NEXT: orb $1, %sil, %cl
; CHECK-NEXT: shrl %cl, %edi, %eax
-; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: cmovnel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -356,3 +350,20 @@ define i32 @shl_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a
%r = select i1 %c, i32 %s, i32 %a2
ret i32 %r
}
+
+define range(i8 0, 2) i8 @no_test_emitted_when_assume_shift_amt_gt_zero(i64 noundef %0, i32 noundef %1) {
+; CHECK-LABEL: no_test_emitted_when_assume_shift_amt_gt_zero:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %esi, %ecx
+; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT: shlq %cl, %rdi
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+ %3 = icmp sgt i32 %1, 0
+ tail call void @llvm.assume(i1 %3)
+ %4 = zext nneg i32 %1 to i64
+ %5 = shl i64 %0, %4
+ %6 = icmp eq i64 %5, 0
+ %7 = zext i1 %6 to i8
+ ret i8 %7
+}
diff --git a/llvm/test/CodeGen/X86/shift-eflags.ll b/llvm/test/CodeGen/X86/shift-eflags.ll
index 6eddf50ce5c9d..badcf5470ab64 100644
--- a/llvm/test/CodeGen/X86/shift-eflags.ll
+++ b/llvm/test/CodeGen/X86/shift-eflags.ll
@@ -282,7 +282,6 @@ define i32 @ashr_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
; CHECK-NEXT: orb $1, %cl
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: sarl %cl, %edi
-; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: cmovel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -301,7 +300,6 @@ define i32 @lshr_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
; CHECK-NEXT: orb $1, %cl
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: shrl %cl, %edi
-; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: cmovel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -320,7 +318,6 @@ define i32 @shl_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
; CHECK-NEXT: orb $1, %cl
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: shll %cl, %edi
-; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: cmovel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -339,7 +336,6 @@ define i32 @ashr_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %
; CHECK-NEXT: orb $1, %cl
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: shrl %cl, %eax
-; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: cmovnel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -358,7 +354,6 @@ define i32 @lshr_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %
; CHECK-NEXT: orb $1, %cl
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: shrl %cl, %eax
-; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: cmovnel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -377,7 +372,6 @@ define i32 @shl_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a
; CHECK-NEXT: orb $1, %cl
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: shrl %cl, %eax
-; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: cmovnel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -386,3 +380,20 @@ define i32 @shl_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a
%r = select i1 %c, i32 %s, i32 %a2
ret i32 %r
}
+
+define range(i8 0, 2) i8 @no_test_emitted_when_assume_shift_amt_gt_zero(i64 noundef %0, i32 noundef %1) {
+; CHECK-LABEL: no_test_emitted_when_assume_shift_amt_gt_zero:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %esi, %ecx
+; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT: shlq %cl, %rdi
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+ %3 = icmp sgt i32 %1, 0
+ tail call void @llvm.assume(i1 %3)
+ %4 = zext nneg i32 %1 to i64
+ %5 = shl i64 %0, %4
+ %6 = icmp eq i64 %5, 0
+ %7 = zext i1 %6 to i8
+ ret i8 %7
+}
>From 808c7713f9a2fe12224a366667bf4a8fa0f05081 Mon Sep 17 00:00:00 2001
From: GrumpyPigSkin <oliver61 at live.co.uk>
Date: Sat, 22 Nov 2025 21:49:04 +0000
Subject: [PATCH 07/10] [X86] Reverted change
---
llvm/include/llvm/CodeGen/SelectionDAGNodes.h | 3 ---
llvm/lib/CodeGen/CodeGenPrepare.cpp | 26 +------------------
.../SelectionDAG/SelectionDAGBuilder.cpp | 20 --------------
3 files changed, 1 insertion(+), 48 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
index 082e7b4371d27..cfc8a4243e894 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
@@ -427,7 +427,6 @@ struct SDNodeFlags {
// implied by its producer as, e.g, operations between producer and PTRADD
// that affect the provenance may have been optimized away.
InBounds = 1 << 15,
- NoZero = 1 << 16,
// NOTE: Please update LargestValue in LLVM_DECLARE_ENUM_AS_BITMASK below
// the class definition when adding new flags.
@@ -469,7 +468,6 @@ struct SDNodeFlags {
void setNoFPExcept(bool b) { setFlag<NoFPExcept>(b); }
void setUnpredictable(bool b) { setFlag<Unpredictable>(b); }
void setInBounds(bool b) { setFlag<InBounds>(b); }
- void setNoZero(bool b) { setFlag<NoZero>(b); }
// These are accessors for each flag.
bool hasNoUnsignedWrap() const { return Flags & NoUnsignedWrap; }
@@ -488,7 +486,6 @@ struct SDNodeFlags {
bool hasNoFPExcept() const { return Flags & NoFPExcept; }
bool hasUnpredictable() const { return Flags & Unpredictable; }
bool hasInBounds() const { return Flags & InBounds; }
- bool hasNoZero() const { return Flags & NoZero; }
bool operator==(const SDNodeFlags &Other) const {
return Flags == Other.Flags;
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index b4b4879c515c5..587c1372b19cb 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -786,32 +786,8 @@ bool CodeGenPrepare::eliminateAssumptions(Function &F) {
if (auto *Assume = dyn_cast<AssumeInst>(I)) {
MadeChange = true;
Value *Operand = Assume->getOperand(0);
- if (ICmpInst *Cmp = dyn_cast<ICmpInst>(Operand)) {
- // Check if we are comparing an Argument against a Constant
- if (Argument *Arg = dyn_cast<Argument>(Cmp->getOperand(0))) {
- if (ConstantInt *C = dyn_cast<ConstantInt>(Cmp->getOperand(1))) {
- // We found "assume(Arg <pred> Constant)"
- ConstantRange Constraint = ConstantRange::makeAllowedICmpRegion(
- Cmp->getPredicate(), C->getValue());
- // If the argument already has a range attribute, intersect with
- // it
- ConstantRange FinalRange = Constraint;
- Attribute ExistingRangeAttr = Arg->getAttribute(Attribute::Range);
- if (ExistingRangeAttr.isValid()) {
- FinalRange =
- FinalRange.intersectWith(ExistingRangeAttr.getRange());
- }
- // If the range provides new information (and isn't empty), save
- // it.
- if (!FinalRange.isFullSet() && !FinalRange.isEmptySet()) {
- AttrBuilder AB(Arg->getContext());
- AB.addRangeAttr(FinalRange);
- Arg->addAttrs(AB);
- }
- }
- }
- }
Assume->eraseFromParent();
+
resetIteratorIfInvalidatedWhileCalling(&BB, [&]() {
RecursivelyDeleteTriviallyDeadInstructions(Operand, TLInfo, nullptr);
});
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 51d3fc0d78975..985a54ca83256 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -3687,7 +3687,6 @@ void SelectionDAGBuilder::visitShift(const User &I, unsigned Opcode) {
bool nuw = false;
bool nsw = false;
bool exact = false;
- bool noZero = false;
if (Opcode == ISD::SRL || Opcode == ISD::SRA || Opcode == ISD::SHL) {
@@ -3699,30 +3698,11 @@ void SelectionDAGBuilder::visitShift(const User &I, unsigned Opcode) {
if (const PossiblyExactOperator *ExactOp =
dyn_cast<const PossiblyExactOperator>(&I))
exact = ExactOp->isExact();
-
- const Value *ShiftAmt = I.getOperand(1);
-
- // Look through zext as computeConstantRange does not do this.
- const Value *InnerVal = ShiftAmt;
- if (auto *ZExt = dyn_cast<ZExtInst>(ShiftAmt)) {
- InnerVal = ZExt->getOperand(0);
- }
-
- // Get the constant range and check it excludes 0
- ConstantRange CR = llvm::computeConstantRange(
- InnerVal, true, true, AC, dyn_cast<Instruction>(&I), nullptr);
-
- if (!CR.isEmptySet() && !CR.contains(APInt(CR.getBitWidth(), 0))) {
- // We can guarantee that that we will not be shifted by 0
- noZero = true;
- }
}
-
SDNodeFlags Flags;
Flags.setExact(exact);
Flags.setNoSignedWrap(nsw);
Flags.setNoUnsignedWrap(nuw);
- Flags.setNoZero(noZero);
SDValue Res = DAG.getNode(Opcode, getCurSDLoc(), Op1.getValueType(), Op1, Op2,
Flags);
setValue(&I, Res);
>From e94fc1740fb88f7763786e750bc1f28be26dbf6b Mon Sep 17 00:00:00 2001
From: GrumpyPigSkin <oliver61 at live.co.uk>
Date: Sat, 22 Nov 2025 23:09:30 +0000
Subject: [PATCH 08/10] [X86] Changed so test instruction is removed only when
targeting min size.
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 6 +-
llvm/test/CodeGen/X86/apx/shift-eflags.ll | 90 ++++++++++++++++++---
llvm/test/CodeGen/X86/shift-eflags.ll | 96 ++++++++++++++++++++---
3 files changed, 170 insertions(+), 22 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 87e637ee4c272..48cddbbd408a2 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -23634,8 +23634,10 @@ static SDValue EmitTest(SDValue Op, X86::CondCode X86CC, const SDLoc &dl,
if (isa<ConstantSDNode>(Amt))
break;
- // Check we can make this optimization
- if (ArithOp->getFlags().hasNoZero() || DAG.isKnownNeverZero(Amt)) {
+ // If optimising for size and can guarantee the shift amt is never zero
+ // the test.
+ bool OptForSize = DAG.getMachineFunction().getFunction().hasOptSize();
+ if (OptForSize && DAG.isKnownNeverZero(Amt)) {
SDLoc DL(ArithOp);
// CopyToReg(CL, Amt)
diff --git a/llvm/test/CodeGen/X86/apx/shift-eflags.ll b/llvm/test/CodeGen/X86/apx/shift-eflags.ll
index 01f4689369eac..f36bdc311c727 100644
--- a/llvm/test/CodeGen/X86/apx/shift-eflags.ll
+++ b/llvm/test/CodeGen/X86/apx/shift-eflags.ll
@@ -265,6 +265,7 @@ define i32 @ashr_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
; CHECK-NEXT: movl %ecx, %eax
; CHECK-NEXT: orb $1, %sil, %cl
; CHECK-NEXT: sarl %cl, %edi
+; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: cmovel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -281,6 +282,7 @@ define i32 @lshr_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
; CHECK-NEXT: movl %ecx, %eax
; CHECK-NEXT: orb $1, %sil, %cl
; CHECK-NEXT: shrl %cl, %edi
+; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: cmovel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -297,6 +299,7 @@ define i32 @shl_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
; CHECK-NEXT: movl %ecx, %eax
; CHECK-NEXT: orb $1, %sil, %cl
; CHECK-NEXT: shll %cl, %edi
+; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: cmovel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -312,6 +315,7 @@ define i32 @ashr_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %
; CHECK: # %bb.0:
; CHECK-NEXT: orb $1, %sil, %cl
; CHECK-NEXT: shrl %cl, %edi, %eax
+; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: cmovnel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -327,6 +331,7 @@ define i32 @lshr_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %
; CHECK: # %bb.0:
; CHECK-NEXT: orb $1, %sil, %cl
; CHECK-NEXT: shrl %cl, %edi, %eax
+; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: cmovnel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -342,6 +347,7 @@ define i32 @shl_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a
; CHECK: # %bb.0:
; CHECK-NEXT: orb $1, %sil, %cl
; CHECK-NEXT: shrl %cl, %edi, %eax
+; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: cmovnel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -351,19 +357,83 @@ define i32 @shl_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a
ret i32 %r
}
-define range(i8 0, 2) i8 @no_test_emitted_when_assume_shift_amt_gt_zero(i64 noundef %0, i32 noundef %1) {
-; CHECK-LABEL: no_test_emitted_when_assume_shift_amt_gt_zero:
+define i1 @shl_optsize_nonzero_removes_test(i32 %val, i32 %amt) optsize {
+; CHECK-LABEL: shl_optsize_nonzero_removes_test:
+; CHECK: # %bb.0:
+; CHECK-NEXT: orb $1, %sil, %cl
+; CHECK-NEXT: shll %cl, %edi
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+ %amt.nz = or i32 %amt, 1
+ %shl = shl i32 %val, %amt.nz
+ %cmp = icmp eq i32 %shl, 0
+ ret i1 %cmp
+}
+
+define i1 @shl_optsize_maybezero_keeps_test(i32 %val, i32 %amt) optsize {
+; CHECK-LABEL: shl_optsize_maybezero_keeps_test:
; CHECK: # %bb.0:
; CHECK-NEXT: movl %esi, %ecx
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
-; CHECK-NEXT: shlq %cl, %rdi
+; CHECK-NEXT: shll %cl, %edi
+; CHECK-NEXT: testl %edi, %edi
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+ %shl = shl i32 %val, %amt
+ %cmp = icmp eq i32 %shl, 0
+ ret i1 %cmp
+}
+
+define i1 @lshr_optsize_nonezero_removes_test(i32 %val, i32 %amt) optsize {
+; CHECK-LABEL: lshr_optsize_nonezero_removes_test:
+; CHECK: # %bb.0:
+; CHECK-NEXT: orb $1, %sil, %cl
+; CHECK-NEXT: shrl %cl, %edi
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+ %amt.nz = or i32 %amt, 1
+ %shr = lshr i32 %val, %amt.nz
+ %cmp = icmp eq i32 %shr, 0
+ ret i1 %cmp
+}
+
+define i1 @lshr_optsize_maybezero_keeps_test(i32 %val, i32 %amt) optsize {
+; CHECK-LABEL: lshr_optsize_maybezero_keeps_test:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %esi, %ecx
+; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT: shrl %cl, %edi
+; CHECK-NEXT: testl %edi, %edi
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+ %shr = lshr i32 %val, %amt
+ %cmp = icmp eq i32 %shr, 0
+ ret i1 %cmp
+}
+
+define i1 @ashr_optsize_nonezero_removes_test(i32 %val, i32 %amt) optsize {
+; CHECK-LABEL: ashr_optsize_nonezero_removes_test:
+; CHECK: # %bb.0:
+; CHECK-NEXT: orb $1, %sil, %cl
+; CHECK-NEXT: sarl %cl, %edi
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+ %amt.nz = or i32 %amt, 1
+ %sar = ashr i32 %val, %amt.nz
+ %cmp = icmp eq i32 %sar, 0
+ ret i1 %cmp
+}
+
+define i1 @ashr_optsize_maybezero_keeps_test(i32 %val, i32 %amt) optsize {
+; CHECK-LABEL: ashr_optsize_maybezero_keeps_test:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %esi, %ecx
+; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT: sarl %cl, %edi
+; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: sete %al
; CHECK-NEXT: retq
- %3 = icmp sgt i32 %1, 0
- tail call void @llvm.assume(i1 %3)
- %4 = zext nneg i32 %1 to i64
- %5 = shl i64 %0, %4
- %6 = icmp eq i64 %5, 0
- %7 = zext i1 %6 to i8
- ret i8 %7
+ %sar = ashr i32 %val, %amt
+ %cmp = icmp eq i32 %sar, 0
+ ret i1 %cmp
}
diff --git a/llvm/test/CodeGen/X86/shift-eflags.ll b/llvm/test/CodeGen/X86/shift-eflags.ll
index badcf5470ab64..d2968e64b4aa0 100644
--- a/llvm/test/CodeGen/X86/shift-eflags.ll
+++ b/llvm/test/CodeGen/X86/shift-eflags.ll
@@ -282,6 +282,7 @@ define i32 @ashr_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
; CHECK-NEXT: orb $1, %cl
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: sarl %cl, %edi
+; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: cmovel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -300,6 +301,7 @@ define i32 @lshr_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
; CHECK-NEXT: orb $1, %cl
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: shrl %cl, %edi
+; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: cmovel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -318,6 +320,7 @@ define i32 @shl_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
; CHECK-NEXT: orb $1, %cl
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: shll %cl, %edi
+; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: cmovel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -336,6 +339,7 @@ define i32 @ashr_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %
; CHECK-NEXT: orb $1, %cl
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: shrl %cl, %eax
+; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: cmovnel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -354,6 +358,7 @@ define i32 @lshr_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %
; CHECK-NEXT: orb $1, %cl
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: shrl %cl, %eax
+; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: cmovnel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -372,6 +377,7 @@ define i32 @shl_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a
; CHECK-NEXT: orb $1, %cl
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
; CHECK-NEXT: shrl %cl, %eax
+; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: cmovnel %edx, %eax
; CHECK-NEXT: retq
%a = or i32 %a1, 1
@@ -381,19 +387,89 @@ define i32 @shl_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a
ret i32 %r
}
-define range(i8 0, 2) i8 @no_test_emitted_when_assume_shift_amt_gt_zero(i64 noundef %0, i32 noundef %1) {
-; CHECK-LABEL: no_test_emitted_when_assume_shift_amt_gt_zero:
+define i1 @shl_optsize_nonzero_removes_test(i32 %val, i32 %amt) optsize {
+; CHECK-LABEL: shl_optsize_nonzero_removes_test:
; CHECK: # %bb.0:
; CHECK-NEXT: movl %esi, %ecx
+; CHECK-NEXT: orb $1, %cl
; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
-; CHECK-NEXT: shlq %cl, %rdi
+; CHECK-NEXT: shll %cl, %edi
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+ %amt.nz = or i32 %amt, 1
+ %shl = shl i32 %val, %amt.nz
+ %cmp = icmp eq i32 %shl, 0
+ ret i1 %cmp
+}
+
+define i1 @shl_optsize_maybezero_keeps_test(i32 %val, i32 %amt) optsize {
+; CHECK-LABEL: shl_optsize_maybezero_keeps_test:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %esi, %ecx
+; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT: shll %cl, %edi
+; CHECK-NEXT: testl %edi, %edi
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+ %shl = shl i32 %val, %amt
+ %cmp = icmp eq i32 %shl, 0
+ ret i1 %cmp
+}
+
+define i1 @lshr_optsize_nonezero_removes_test(i32 %val, i32 %amt) optsize {
+; CHECK-LABEL: lshr_optsize_nonezero_removes_test:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %esi, %ecx
+; CHECK-NEXT: orb $1, %cl
+; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT: shrl %cl, %edi
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+ %amt.nz = or i32 %amt, 1
+ %shr = lshr i32 %val, %amt.nz
+ %cmp = icmp eq i32 %shr, 0
+ ret i1 %cmp
+}
+
+define i1 @lshr_optsize_maybezero_keeps_test(i32 %val, i32 %amt) optsize {
+; CHECK-LABEL: lshr_optsize_maybezero_keeps_test:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %esi, %ecx
+; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT: shrl %cl, %edi
+; CHECK-NEXT: testl %edi, %edi
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+ %shr = lshr i32 %val, %amt
+ %cmp = icmp eq i32 %shr, 0
+ ret i1 %cmp
+}
+
+define i1 @ashr_optsize_nonezero_removes_test(i32 %val, i32 %amt) optsize {
+; CHECK-LABEL: ashr_optsize_nonezero_removes_test:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %esi, %ecx
+; CHECK-NEXT: orb $1, %cl
+; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT: sarl %cl, %edi
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+ %amt.nz = or i32 %amt, 1
+ %sar = ashr i32 %val, %amt.nz
+ %cmp = icmp eq i32 %sar, 0
+ ret i1 %cmp
+}
+
+define i1 @ashr_optsize_maybezero_keeps_test(i32 %val, i32 %amt) optsize {
+; CHECK-LABEL: ashr_optsize_maybezero_keeps_test:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %esi, %ecx
+; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT: sarl %cl, %edi
+; CHECK-NEXT: testl %edi, %edi
; CHECK-NEXT: sete %al
; CHECK-NEXT: retq
- %3 = icmp sgt i32 %1, 0
- tail call void @llvm.assume(i1 %3)
- %4 = zext nneg i32 %1 to i64
- %5 = shl i64 %0, %4
- %6 = icmp eq i64 %5, 0
- %7 = zext i1 %6 to i8
- ret i8 %7
+ %sar = ashr i32 %val, %amt
+ %cmp = icmp eq i32 %sar, 0
+ ret i1 %cmp
}
>From 95fadc5eaed7432651761a127c82c1e478d16033 Mon Sep 17 00:00:00 2001
From: GrumpyPigSkin <oliver61 at live.co.uk>
Date: Mon, 24 Nov 2025 21:46:49 +0000
Subject: [PATCH 09/10] [X86] Changes made for code review comments
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 64 ++++++++++++----------
llvm/lib/Target/X86/X86ISelLowering.h | 6 +-
llvm/lib/Target/X86/X86InstrFragments.td | 9 +++
llvm/lib/Target/X86/X86InstrShiftRotate.td | 9 ---
4 files changed, 46 insertions(+), 42 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 48cddbbd408a2..284e3e5853dad 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -23637,43 +23637,47 @@ static SDValue EmitTest(SDValue Op, X86::CondCode X86CC, const SDLoc &dl,
// If optimising for size and can guarantee the shift amt is never zero
// the test.
bool OptForSize = DAG.getMachineFunction().getFunction().hasOptSize();
- if (OptForSize && DAG.isKnownNeverZero(Amt)) {
- SDLoc DL(ArithOp);
- // CopyToReg(CL, Amt)
- SDValue Chain = DAG.getEntryNode();
- SDValue Glue;
+ if (!OptForSize)
+ break;
- Chain = DAG.getCopyToReg(Chain, DL, X86::CL, Amt, Glue);
- Glue = Chain.getValue(1);
+ if (!DAG.isKnownNeverZero(Amt))
+ break;
- // Select Opcode
- unsigned X86Opcode;
- switch (ArithOp.getOpcode()) {
- case ISD::SHL:
- X86Opcode = X86ISD::SHL;
- break;
- case ISD::SRL:
- X86Opcode = X86ISD::SRL;
- break;
- case ISD::SRA:
- X86Opcode = X86ISD::SRA;
- break;
- default:
- llvm_unreachable("Unexpected shift opcode");
- }
+ SDLoc DL(ArithOp);
- // Create Node [ValueToShift, Glue]
- SDVTList VTs = DAG.getVTList(ArithOp.getValueType(), MVT::i32);
- SDValue Ops[] = {ArithOp.getOperand(0), Glue};
+ // CopyToReg(CL, Amt)
+ SDValue Chain = DAG.getEntryNode();
+ SDValue Glue;
- SDValue NewNode = DAG.getNode(X86Opcode, DL, VTs, Ops);
+ Chain = DAG.getCopyToReg(Chain, DL, X86::CL, Amt, Glue);
+ Glue = Chain.getValue(1);
- // Replace and Return
- DAG.ReplaceAllUsesOfValueWith(ArithOp, NewNode.getValue(0));
- return NewNode.getValue(1);
+ // Select Opcode
+ unsigned X86Opcode;
+ switch (ArithOp.getOpcode()) {
+ case ISD::SHL:
+ X86Opcode = X86ISD::SHL;
+ break;
+ case ISD::SRL:
+ X86Opcode = X86ISD::SRL;
+ break;
+ case ISD::SRA:
+ X86Opcode = X86ISD::SRA;
+ break;
+ default:
+ llvm_unreachable("Unexpected shift opcode");
}
- break;
+
+ // Create Node [ValueToShift, Glue]
+ SDVTList VTs = DAG.getVTList(ArithOp.getValueType(), MVT::i32);
+ SDValue Ops[] = {ArithOp.getOperand(0), Glue};
+
+ SDValue NewNode = DAG.getNode(X86Opcode, DL, VTs, Ops);
+
+ // Replace and Return
+ DAG.ReplaceAllUsesOfValueWith(ArithOp, NewNode.getValue(0));
+ return NewNode.getValue(1);
}
default:
break;
diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h
index 00830804213f7..af8a63f120226 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.h
+++ b/llvm/lib/Target/X86/X86ISelLowering.h
@@ -425,6 +425,9 @@ namespace llvm {
OR,
XOR,
AND,
+ SHL,
+ SRL,
+ SRA,
// Bit field extract.
BEXTR,
@@ -996,9 +999,6 @@ namespace llvm {
CLOAD,
CSTORE,
LAST_MEMORY_OPCODE = CSTORE,
- SHL,
- SRL,
- SRA,
};
} // end namespace X86ISD
diff --git a/llvm/lib/Target/X86/X86InstrFragments.td b/llvm/lib/Target/X86/X86InstrFragments.td
index 116986a0fffea..3ea71ce24c7f7 100644
--- a/llvm/lib/Target/X86/X86InstrFragments.td
+++ b/llvm/lib/Target/X86/X86InstrFragments.td
@@ -276,6 +276,15 @@ def X86xor_flag : SDNode<"X86ISD::XOR", SDTBinaryArithWithFlags,
def X86and_flag : SDNode<"X86ISD::AND", SDTBinaryArithWithFlags,
[SDNPCommutative]>;
+def SDTX86ShiftWithFlags : SDTypeProfile<2, 1, [
+ SDTCisSameAs<0, 2>,
+ SDTCisVT<1, i32>,
+]>;
+
+def X86shl : SDNode<"X86ISD::SHL", SDTX86ShiftWithFlags, [SDNPInGlue]>;
+def X86srl : SDNode<"X86ISD::SRL", SDTX86ShiftWithFlags, [SDNPInGlue]>;
+def X86sra : SDNode<"X86ISD::SRA", SDTX86ShiftWithFlags, [SDNPInGlue]>;
+
def X86lock_add : SDNode<"X86ISD::LADD", SDTLockBinaryArithWithFlags,
[SDNPHasChain, SDNPMayStore, SDNPMayLoad,
SDNPMemOperand]>;
diff --git a/llvm/lib/Target/X86/X86InstrShiftRotate.td b/llvm/lib/Target/X86/X86InstrShiftRotate.td
index e81bc33d3a459..7a2cd3101b342 100644
--- a/llvm/lib/Target/X86/X86InstrShiftRotate.td
+++ b/llvm/lib/Target/X86/X86InstrShiftRotate.td
@@ -690,15 +690,6 @@ let Predicates = [HasBMI2, HasEGPR] in {
defm SHLX : ShiftX_Pats<shl, "_EVEX">;
}
-def SDTX86ShiftWithFlags : SDTypeProfile<2, 1, [
- SDTCisSameAs<0, 2>,
- SDTCisVT<1, i32>,
-]>;
-
-def X86shl : SDNode<"X86ISD::SHL", SDTX86ShiftWithFlags, [SDNPInGlue]>;
-def X86srl : SDNode<"X86ISD::SRL", SDTX86ShiftWithFlags, [SDNPInGlue]>;
-def X86sra : SDNode<"X86ISD::SRA", SDTX86ShiftWithFlags, [SDNPInGlue]>;
-
let Predicates = [NoNDD] in {
// SHL
def : Pat<(X86shl GR8:$src1), (SHL8rCL GR8:$src1)>;
>From 93a699f85e5cbdf6668962cc32e6d58a8ca4884c Mon Sep 17 00:00:00 2001
From: GrumpyPigSkin <oliver61 at live.co.uk>
Date: Tue, 25 Nov 2025 18:51:43 +0000
Subject: [PATCH 10/10] [X86] Additional code review comments
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 284e3e5853dad..b02c6d16337c0 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -23636,9 +23636,7 @@ static SDValue EmitTest(SDValue Op, X86::CondCode X86CC, const SDLoc &dl,
// If optimising for size and can guarantee the shift amt is never zero
// the test.
- bool OptForSize = DAG.getMachineFunction().getFunction().hasOptSize();
-
- if (!OptForSize)
+ if (!DAG.getMachineFunction().getFunction().hasOptSize())
break;
if (!DAG.isKnownNeverZero(Amt))
@@ -35223,6 +35221,9 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(OR)
NODE_NAME_CASE(XOR)
NODE_NAME_CASE(AND)
+ NODE_NAME_CASE(SHL)
+ NODE_NAME_CASE(SRL)
+ NODE_NAME_CASE(SRA)
NODE_NAME_CASE(BEXTR)
NODE_NAME_CASE(BEXTRI)
NODE_NAME_CASE(BZHI)
@@ -35521,9 +35522,6 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(CVTTP2UIS)
NODE_NAME_CASE(MCVTTP2UIS)
NODE_NAME_CASE(POP_FROM_X87_REG)
- NODE_NAME_CASE(SHL)
- NODE_NAME_CASE(SRL)
- NODE_NAME_CASE(SRA)
}
return nullptr;
#undef NODE_NAME_CASE
More information about the llvm-commits
mailing list