From: Benjamin Kramer Date: Fri, 26 Jun 2015 14:51:36 +0000 (+0000) Subject: [DAGCombine] fold (X >>?,exact C1) << C2 --> X << (C2-C1) X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=3791d56da63baf5072fa6ecaa872ace6adbc6892;p=oota-llvm.git [DAGCombine] fold (X >>?,exact C1) << C2 --> X << (C2-C1) Instcombine also does this but many opportunities only become visible after GEPs are lowered. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@240787 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 8e0e0fe2822..8388a95b8cf 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -4362,6 +4362,22 @@ SDValue DAGCombiner::visitSHL(SDNode *N) { } } + // fold (shl (sr[la] exact X, C1), C2) -> (shl X, (C2-C1)) if C1 <= C2 + // fold (shl (sr[la] exact X, C1), C2) -> (sr[la] X, (C2-C1)) if C1 > C2 + if (N1C && (N0.getOpcode() == ISD::SRL || N0.getOpcode() == ISD::SRA) && + cast(N0)->Flags.hasExact()) { + if (ConstantSDNode *N0C1 = isConstOrConstSplat(N0.getOperand(1))) { + uint64_t C1 = N0C1->getZExtValue(); + uint64_t C2 = N1C->getZExtValue(); + SDLoc DL(N); + if (C1 <= C2) + return DAG.getNode(ISD::SHL, DL, VT, N0.getOperand(0), + DAG.getConstant(C2 - C1, DL, N1.getValueType())); + return DAG.getNode(N0.getOpcode(), DL, VT, N0.getOperand(0), + DAG.getConstant(C1 - C2, DL, N1.getValueType())); + } + } + // fold (shl (srl x, c1), c2) -> (and (shl x, (sub c2, c1), MASK) or // (and (srl x, (sub c1, c2), MASK) // Only fold this if the inner shift has no other uses -- if it does, folding diff --git a/test/CodeGen/X86/shift-combine.ll b/test/CodeGen/X86/shift-combine.ll index ec62bcdcdba..7fb19a6cad0 100644 --- a/test/CodeGen/X86/shift-combine.ll +++ b/test/CodeGen/X86/shift-combine.ll @@ -17,3 +17,52 @@ entry: ret i32 %tmp5 } +define i32* @test_exact1(i32 %a, i32 %b, i32* %x) { +; CHECK-LABEL: test_exact1: +; CHECK: sarl % + + %sub = sub i32 %b, %a + %shr = ashr exact i32 %sub, 3 + %gep = getelementptr inbounds i32, i32* %x, i32 %shr + ret i32* %gep +} + +define i32* @test_exact2(i32 %a, i32 %b, i32* %x) { +; CHECK-LABEL: test_exact2: +; CHECK: sarl % + + %sub = sub i32 %b, %a + %shr = ashr exact i32 %sub, 3 + %gep = getelementptr inbounds i32, i32* %x, i32 %shr + ret i32* %gep +} + +define i32* @test_exact4(i32 %a, i32 %b, i32* %x) { +; CHECK-LABEL: test_exact4: +; CHECK: shrl % + + %sub = sub i32 %b, %a + %shr = lshr exact i32 %sub, 3 + %gep = getelementptr inbounds i32, i32* %x, i32 %shr + ret i32* %gep +} + +define i32* @test_exact5(i32 %a, i32 %b, i32* %x) { +; CHECK-LABEL: test_exact5: +; CHECK: shrl % + + %sub = sub i32 %b, %a + %shr = lshr exact i32 %sub, 3 + %gep = getelementptr inbounds i32, i32* %x, i32 %shr + ret i32* %gep +} + +define i32* @test_exact6(i32 %a, i32 %b, i32* %x) { +; CHECK-LABEL: test_exact6: +; CHECK-NOT: shrl + + %sub = sub i32 %b, %a + %shr = lshr exact i32 %sub, 2 + %gep = getelementptr inbounds i32, i32* %x, i32 %shr + ret i32* %gep +}