From 1314b00cf2edc49c24c814e66f3fad62a5da40e8 Mon Sep 17 00:00:00 2001 From: Evan Cheng Date: Thu, 13 Dec 2007 00:43:27 +0000 Subject: [PATCH] Fold some and + shift in x86 addressing mode. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@44970 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/X86ISelDAGToDAG.cpp | 50 ++++++++++++++++++++++++++---- lib/Target/X86/X86InstrInfo.td | 4 +++ test/CodeGen/X86/fold-and-shift.ll | 21 +++++++++++++ 3 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 test/CodeGen/X86/fold-and-shift.ll diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp index 35a5516c599..e0183c6e1ed 100644 --- a/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -582,7 +582,7 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM, } int id = N.Val->getNodeId(); - bool Available = isSelected(id); + bool AlreadySelected = isSelected(id); // Already selected, not yet replaced. switch (N.getOpcode()) { default: break; @@ -605,7 +605,7 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM, // If value is available in a register both base and index components have // been picked, we can't fit the result available in the register in the // addressing mode. Duplicate GlobalAddress or ConstantPool as displacement. - if (!Available || (AM.Base.Reg.Val && AM.IndexReg.Val)) { + if (!AlreadySelected || (AM.Base.Reg.Val && AM.IndexReg.Val)) { bool isStatic = TM.getRelocationModel() == Reloc::Static; SDOperand N0 = N.getOperand(0); // Mac OS X X86-64 lower 4G address is not available. @@ -653,7 +653,7 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM, break; case ISD::SHL: - if (Available || AM.IndexReg.Val != 0 || AM.Scale != 1) + if (AlreadySelected || AM.IndexReg.Val != 0 || AM.Scale != 1) break; if (ConstantSDNode *CN = dyn_cast(N.Val->getOperand(1))) { @@ -690,7 +690,7 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM, // FALL THROUGH case ISD::MUL: // X*[3,5,9] -> X+X*[2,4,8] - if (!Available && + if (!AlreadySelected && AM.BaseType == X86ISelAddressMode::RegBase && AM.Base.Reg.Val == 0 && AM.IndexReg.Val == 0) { @@ -725,7 +725,7 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM, break; case ISD::ADD: - if (!Available) { + if (!AlreadySelected) { X86ISelAddressMode Backup = AM; if (!MatchAddress(N.Val->getOperand(0), AM, false, Depth+1) && !MatchAddress(N.Val->getOperand(1), AM, false, Depth+1)) @@ -740,7 +740,7 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM, case ISD::OR: // Handle "X | C" as "X + C" iff X is known to have C bits clear. - if (Available) break; + if (AlreadySelected) break; if (ConstantSDNode *CN = dyn_cast(N.getOperand(1))) { X86ISelAddressMode Backup = AM; @@ -758,6 +758,44 @@ bool X86DAGToDAGISel::MatchAddress(SDOperand N, X86ISelAddressMode &AM, AM = Backup; } break; + + case ISD::AND: { + // Handle "(x << C1) & C2" as "(X & (C2>>C1)) << C1" if safe and if this + // allows us to fold the shift into this addressing mode. + if (AlreadySelected) break; + SDOperand Shift = N.getOperand(0); + if (Shift.getOpcode() != ISD::SHL) break; + + // Scale must not be used already. + if (AM.IndexReg.Val != 0 || AM.Scale != 1) break; + + ConstantSDNode *C2 = dyn_cast(N.getOperand(1)); + ConstantSDNode *C1 = dyn_cast(Shift.getOperand(1)); + if (!C1 || !C2) break; + + // Not likely to be profitable if either the AND or SHIFT node has more + // than one use (unless all uses are for address computation). Besides, + // isel mechanism requires their node ids to be reused. + if (!N.hasOneUse() || !Shift.hasOneUse()) + break; + + // Verify that the shift amount is something we can fold. + unsigned ShiftCst = C1->getValue(); + if (ShiftCst != 1 && ShiftCst != 2 && ShiftCst != 3) + break; + + // Get the new AND mask, this folds to a constant. + SDOperand NewANDMask = CurDAG->getNode(ISD::SRL, N.getValueType(), + SDOperand(C2, 0), SDOperand(C1, 0)); + SDOperand NewAND = CurDAG->getNode(ISD::AND, N.getValueType(), + Shift.getOperand(0), NewANDMask); + NewANDMask.Val->setNodeId(Shift.Val->getNodeId()); + NewAND.Val->setNodeId(N.Val->getNodeId()); + + AM.Scale = 1 << ShiftCst; + AM.IndexReg = NewAND; + return false; + } } return MatchAddressBase(N, AM, isRoot, Depth); diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 75be11ba08e..1fb162d0cb2 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -2613,6 +2613,10 @@ def : Pat<(i16 (anyext (loadi8 addr:$src))), (MOVZX16rm8 addr:$src)>; def : Pat<(i32 (anyext (loadi8 addr:$src))), (MOVZX32rm8 addr:$src)>; def : Pat<(i32 (anyext (loadi16 addr:$src))), (MOVZX32rm16 addr:$src)>; +// (and (i32 load), 255) -> (zextload i8) +def : Pat<(i32 (and (loadi32 addr:$src), (i32 255))), (MOVZX32rm8 addr:$src)>; +def : Pat<(i32 (and (loadi32 addr:$src), (i32 65535))),(MOVZX32rm16 addr:$src)>; + //===----------------------------------------------------------------------===// // Some peepholes //===----------------------------------------------------------------------===// diff --git a/test/CodeGen/X86/fold-and-shift.ll b/test/CodeGen/X86/fold-and-shift.ll new file mode 100644 index 00000000000..705b7954964 --- /dev/null +++ b/test/CodeGen/X86/fold-and-shift.ll @@ -0,0 +1,21 @@ +; RUN: llvm-as < %s | llc -march=x86 | not grep and + +define i32 @t1(i8* %X, i32 %i) { +entry: + %tmp2 = shl i32 %i, 2 ; [#uses=1] + %tmp4 = and i32 %tmp2, 1020 ; [#uses=1] + %tmp7 = getelementptr i8* %X, i32 %tmp4 ; [#uses=1] + %tmp78 = bitcast i8* %tmp7 to i32* ; [#uses=1] + %tmp9 = load i32* %tmp78, align 4 ; [#uses=1] + ret i32 %tmp9 +} + +define i32 @t2(i16* %X, i32 %i) { +entry: + %tmp2 = shl i32 %i, 1 ; [#uses=1] + %tmp4 = and i32 %tmp2, 131070 ; [#uses=1] + %tmp7 = getelementptr i16* %X, i32 %tmp4 ; [#uses=1] + %tmp78 = bitcast i16* %tmp7 to i32* ; [#uses=1] + %tmp9 = load i32* %tmp78, align 4 ; [#uses=1] + ret i32 %tmp9 +}