mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-12 17:32:19 +00:00
Add an x86 peep that narrows TEST instructions to forms that use
a smaller encoding. These kinds of patterns are very frequent in sqlite3, for example. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79439 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
b7be0e8afc
commit
6a402dc952
@ -686,6 +686,11 @@ public:
|
|||||||
const std::vector<EVT> &ResultTys, const SDValue *Ops,
|
const std::vector<EVT> &ResultTys, const SDValue *Ops,
|
||||||
unsigned NumOps);
|
unsigned NumOps);
|
||||||
|
|
||||||
|
/// getTargetExtractSubreg - A convenience function for creating
|
||||||
|
/// TargetInstrInfo::EXTRACT_SUBREG nodes.
|
||||||
|
SDValue getTargetExtractSubreg(int SRIdx, DebugLoc DL, EVT VT,
|
||||||
|
SDValue Operand);
|
||||||
|
|
||||||
/// getNodeIfExists - Get the specified node if it's already available, or
|
/// getNodeIfExists - Get the specified node if it's already available, or
|
||||||
/// else return NULL.
|
/// else return NULL.
|
||||||
SDNode *getNodeIfExists(unsigned Opcode, SDVTList VTs,
|
SDNode *getNodeIfExists(unsigned Opcode, SDVTList VTs,
|
||||||
|
@ -4586,6 +4586,17 @@ SDNode *SelectionDAG::getTargetNode(unsigned Opcode, DebugLoc dl,
|
|||||||
return getNode(~Opcode, dl, ResultTys, Ops, NumOps).getNode();
|
return getNode(~Opcode, dl, ResultTys, Ops, NumOps).getNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// getTargetExtractSubreg - A convenience function for creating
|
||||||
|
/// TargetInstrInfo::EXTRACT_SUBREG nodes.
|
||||||
|
SDValue
|
||||||
|
SelectionDAG::getTargetExtractSubreg(int SRIdx, DebugLoc DL, EVT VT,
|
||||||
|
SDValue Operand) {
|
||||||
|
SDValue SRIdxVal = getTargetConstant(SRIdx, MVT::i32);
|
||||||
|
SDNode *Subreg = getTargetNode(TargetInstrInfo::EXTRACT_SUBREG, DL,
|
||||||
|
VT, Operand, SRIdxVal);
|
||||||
|
return SDValue(Subreg, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/// getNodeIfExists - Get the specified node if it's already available, or
|
/// getNodeIfExists - Get the specified node if it's already available, or
|
||||||
/// else return NULL.
|
/// else return NULL.
|
||||||
SDNode *SelectionDAG::getNodeIfExists(unsigned Opcode, SDVTList VTList,
|
SDNode *SelectionDAG::getNodeIfExists(unsigned Opcode, SDVTList VTList,
|
||||||
|
@ -1743,9 +1743,8 @@ SDNode *X86DAGToDAGISel::Select(SDValue N) {
|
|||||||
Result,
|
Result,
|
||||||
CurDAG->getTargetConstant(8, MVT::i8)), 0);
|
CurDAG->getTargetConstant(8, MVT::i8)), 0);
|
||||||
// Then truncate it down to i8.
|
// Then truncate it down to i8.
|
||||||
SDValue SRIdx = CurDAG->getTargetConstant(X86::SUBREG_8BIT, MVT::i32);
|
Result = CurDAG->getTargetExtractSubreg(X86::SUBREG_8BIT, dl,
|
||||||
Result = SDValue(CurDAG->getTargetNode(X86::EXTRACT_SUBREG, dl,
|
MVT::i8, Result);
|
||||||
MVT::i8, Result, SRIdx), 0);
|
|
||||||
} else {
|
} else {
|
||||||
Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
|
Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
|
||||||
HiReg, NVT, InFlag);
|
HiReg, NVT, InFlag);
|
||||||
@ -1919,9 +1918,8 @@ SDNode *X86DAGToDAGISel::Select(SDValue N) {
|
|||||||
CurDAG->getTargetConstant(8, MVT::i8)),
|
CurDAG->getTargetConstant(8, MVT::i8)),
|
||||||
0);
|
0);
|
||||||
// Then truncate it down to i8.
|
// Then truncate it down to i8.
|
||||||
SDValue SRIdx = CurDAG->getTargetConstant(X86::SUBREG_8BIT, MVT::i32);
|
Result = CurDAG->getTargetExtractSubreg(X86::SUBREG_8BIT, dl,
|
||||||
Result = SDValue(CurDAG->getTargetNode(X86::EXTRACT_SUBREG, dl,
|
MVT::i8, Result);
|
||||||
MVT::i8, Result, SRIdx), 0);
|
|
||||||
} else {
|
} else {
|
||||||
Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
|
Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
|
||||||
HiReg, NVT, InFlag);
|
HiReg, NVT, InFlag);
|
||||||
@ -1944,6 +1942,105 @@ SDNode *X86DAGToDAGISel::Select(SDValue N) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case X86ISD::CMP: {
|
||||||
|
if (getenv("NOCMP")) break;
|
||||||
|
SDValue N0 = Node->getOperand(0);
|
||||||
|
SDValue N1 = Node->getOperand(1);
|
||||||
|
|
||||||
|
// Look for (X86cmp (and $op, $imm), 0) and see if we can convert it to
|
||||||
|
// use a smaller encoding.
|
||||||
|
if (N0.getNode()->getOpcode() == ISD::AND && N0.getNode()->hasOneUse() &&
|
||||||
|
N0.getValueType() != MVT::i8 &&
|
||||||
|
X86::isZeroNode(N1)) {
|
||||||
|
ConstantSDNode *C = dyn_cast<ConstantSDNode>(N0.getNode()->getOperand(1));
|
||||||
|
if (!C) break;
|
||||||
|
|
||||||
|
// For example, convert "testl %eax, $8" to "testb %al, $8"
|
||||||
|
if ((C->getZExtValue() & ~UINT64_C(0xff)) == 0) {
|
||||||
|
SDValue Imm = CurDAG->getTargetConstant(C->getZExtValue(), MVT::i8);
|
||||||
|
SDValue Reg = N0.getNode()->getOperand(0);
|
||||||
|
|
||||||
|
// On x86-32, only the ABCD registers have 8-bit subregisters.
|
||||||
|
if (!Subtarget->is64Bit()) {
|
||||||
|
TargetRegisterClass *TRC = 0;
|
||||||
|
switch (N0.getValueType().getSimpleVT().SimpleTy) {
|
||||||
|
case MVT::i32: TRC = &X86::GR32_ABCDRegClass; break;
|
||||||
|
case MVT::i16: TRC = &X86::GR16_ABCDRegClass; break;
|
||||||
|
default: llvm_unreachable("Unsupported TEST operand type!");
|
||||||
|
}
|
||||||
|
SDValue RC = CurDAG->getTargetConstant(TRC->getID(), MVT::i32);
|
||||||
|
Reg = SDValue(CurDAG->getTargetNode(X86::COPY_TO_REGCLASS, dl,
|
||||||
|
Reg.getValueType(), Reg, RC), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the l-register.
|
||||||
|
SDValue Subreg = CurDAG->getTargetExtractSubreg(X86::SUBREG_8BIT, dl,
|
||||||
|
MVT::i8, Reg);
|
||||||
|
|
||||||
|
// Emit a testb.
|
||||||
|
return CurDAG->getTargetNode(X86::TEST8ri, dl, MVT::i32, Subreg, Imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For example, "testl %eax, $2048" to "testb %ah, $8".
|
||||||
|
if ((C->getZExtValue() & ~UINT64_C(0xff00)) == 0) {
|
||||||
|
// Shift the immediate right by 8 bits.
|
||||||
|
SDValue ShiftedImm = CurDAG->getTargetConstant(C->getZExtValue() >> 8,
|
||||||
|
MVT::i8);
|
||||||
|
SDValue Reg = N0.getNode()->getOperand(0);
|
||||||
|
|
||||||
|
// Put the value in an ABCD register.
|
||||||
|
TargetRegisterClass *TRC = 0;
|
||||||
|
switch (N0.getValueType().getSimpleVT().SimpleTy) {
|
||||||
|
case MVT::i64: TRC = &X86::GR64_ABCDRegClass; break;
|
||||||
|
case MVT::i32: TRC = &X86::GR32_ABCDRegClass; break;
|
||||||
|
case MVT::i16: TRC = &X86::GR16_ABCDRegClass; break;
|
||||||
|
default: llvm_unreachable("Unsupported TEST operand type!");
|
||||||
|
}
|
||||||
|
SDValue RC = CurDAG->getTargetConstant(TRC->getID(), MVT::i32);
|
||||||
|
Reg = SDValue(CurDAG->getTargetNode(X86::COPY_TO_REGCLASS, dl,
|
||||||
|
Reg.getValueType(), Reg, RC), 0);
|
||||||
|
|
||||||
|
// Extract the h-register.
|
||||||
|
SDValue Subreg = CurDAG->getTargetExtractSubreg(X86::SUBREG_8BIT_HI, dl,
|
||||||
|
MVT::i8, Reg);
|
||||||
|
|
||||||
|
// Emit a testb. No special NOREX tricks are needed since there's
|
||||||
|
// only one GPR operand!
|
||||||
|
return CurDAG->getTargetNode(X86::TEST8ri, dl, MVT::i32,
|
||||||
|
Subreg, ShiftedImm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For example, "testl %eax, $32776" to "testw %ax, $32776".
|
||||||
|
if ((C->getZExtValue() & ~UINT64_C(0xffff)) == 0 &&
|
||||||
|
N0.getValueType() != MVT::i16) {
|
||||||
|
SDValue Imm = CurDAG->getTargetConstant(C->getZExtValue(), MVT::i16);
|
||||||
|
SDValue Reg = N0.getNode()->getOperand(0);
|
||||||
|
|
||||||
|
// Extract the 16-bit subregister.
|
||||||
|
SDValue Subreg = CurDAG->getTargetExtractSubreg(X86::SUBREG_16BIT, dl,
|
||||||
|
MVT::i16, Reg);
|
||||||
|
|
||||||
|
// Emit a testw.
|
||||||
|
return CurDAG->getTargetNode(X86::TEST16ri, dl, MVT::i32, Subreg, Imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For example, "testq %rax, $268468232" to "testl %eax, $268468232".
|
||||||
|
if ((C->getZExtValue() & ~UINT64_C(0xffffffff)) == 0 &&
|
||||||
|
N0.getValueType() == MVT::i64) {
|
||||||
|
SDValue Imm = CurDAG->getTargetConstant(C->getZExtValue(), MVT::i32);
|
||||||
|
SDValue Reg = N0.getNode()->getOperand(0);
|
||||||
|
|
||||||
|
// Extract the 32-bit subregister.
|
||||||
|
SDValue Subreg = CurDAG->getTargetExtractSubreg(X86::SUBREG_32BIT, dl,
|
||||||
|
MVT::i32, Reg);
|
||||||
|
|
||||||
|
// Emit a testl.
|
||||||
|
return CurDAG->getTargetNode(X86::TEST32ri, dl, MVT::i32, Subreg, Imm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ISD::DECLARE: {
|
case ISD::DECLARE: {
|
||||||
// Handle DECLARE nodes here because the second operand may have been
|
// Handle DECLARE nodes here because the second operand may have been
|
||||||
// wrapped in X86ISD::Wrapper.
|
// wrapped in X86ISD::Wrapper.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
; RUN: llvm-as < %s | llc -march=x86-64 | grep testl
|
; RUN: llvm-as < %s | llc -march=x86-64 | grep {testb \[$\]1,}
|
||||||
|
|
||||||
; Make sure dagcombine doesn't eliminate the comparison due
|
; Make sure dagcombine doesn't eliminate the comparison due
|
||||||
; to an off-by-one bug with ComputeMaskedBits information.
|
; to an off-by-one bug with ComputeMaskedBits information.
|
||||||
|
158
test/CodeGen/X86/test-shrink.ll
Normal file
158
test/CodeGen/X86/test-shrink.ll
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
; RUN: llvm-as < %s | llc -march=x86-64 | FileCheck %s --check-prefix=CHECK-64
|
||||||
|
; RUN: llvm-as < %s | llc -march=x86 | FileCheck %s --check-prefix=CHECK-32
|
||||||
|
|
||||||
|
; CHECK-64: g64xh:
|
||||||
|
; CHECK-64: testb $8, %ah
|
||||||
|
; CHECK-64: ret
|
||||||
|
; CHECK-32: g64xh:
|
||||||
|
; CHECK-32: testb $8, %ah
|
||||||
|
; CHECK-32: ret
|
||||||
|
define void @g64xh(i64 inreg %x) nounwind {
|
||||||
|
%t = and i64 %x, 2048
|
||||||
|
%s = icmp eq i64 %t, 0
|
||||||
|
br i1 %s, label %yes, label %no
|
||||||
|
|
||||||
|
yes:
|
||||||
|
call void @bar()
|
||||||
|
ret void
|
||||||
|
no:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
; CHECK-64: g64xl:
|
||||||
|
; CHECK-64: testb $8, %dil
|
||||||
|
; CHECK-64: ret
|
||||||
|
; CHECK-32: g64xl:
|
||||||
|
; CHECK-32: testb $8, %al
|
||||||
|
; CHECK-32: ret
|
||||||
|
define void @g64xl(i64 inreg %x) nounwind {
|
||||||
|
%t = and i64 %x, 8
|
||||||
|
%s = icmp eq i64 %t, 0
|
||||||
|
br i1 %s, label %yes, label %no
|
||||||
|
|
||||||
|
yes:
|
||||||
|
call void @bar()
|
||||||
|
ret void
|
||||||
|
no:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
; CHECK-64: g32xh:
|
||||||
|
; CHECK-64: testb $8, %ah
|
||||||
|
; CHECK-64: ret
|
||||||
|
; CHECK-32: g32xh:
|
||||||
|
; CHECK-32: testb $8, %ah
|
||||||
|
; CHECK-32: ret
|
||||||
|
define void @g32xh(i32 inreg %x) nounwind {
|
||||||
|
%t = and i32 %x, 2048
|
||||||
|
%s = icmp eq i32 %t, 0
|
||||||
|
br i1 %s, label %yes, label %no
|
||||||
|
|
||||||
|
yes:
|
||||||
|
call void @bar()
|
||||||
|
ret void
|
||||||
|
no:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
; CHECK-64: g32xl:
|
||||||
|
; CHECK-64: testb $8, %dil
|
||||||
|
; CHECK-64: ret
|
||||||
|
; CHECK-32: g32xl:
|
||||||
|
; CHECK-32: testb $8, %al
|
||||||
|
; CHECK-32: ret
|
||||||
|
define void @g32xl(i32 inreg %x) nounwind {
|
||||||
|
%t = and i32 %x, 8
|
||||||
|
%s = icmp eq i32 %t, 0
|
||||||
|
br i1 %s, label %yes, label %no
|
||||||
|
|
||||||
|
yes:
|
||||||
|
call void @bar()
|
||||||
|
ret void
|
||||||
|
no:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
; CHECK-64: g16xh:
|
||||||
|
; CHECK-64: testb $8, %ah
|
||||||
|
; CHECK-64: ret
|
||||||
|
; CHECK-32: g16xh:
|
||||||
|
; CHECK-32: testb $8, %ah
|
||||||
|
; CHECK-32: ret
|
||||||
|
define void @g16xh(i16 inreg %x) nounwind {
|
||||||
|
%t = and i16 %x, 2048
|
||||||
|
%s = icmp eq i16 %t, 0
|
||||||
|
br i1 %s, label %yes, label %no
|
||||||
|
|
||||||
|
yes:
|
||||||
|
call void @bar()
|
||||||
|
ret void
|
||||||
|
no:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
; CHECK-64: g16xl:
|
||||||
|
; CHECK-64: testb $8, %dil
|
||||||
|
; CHECK-64: ret
|
||||||
|
; CHECK-32: g16xl:
|
||||||
|
; CHECK-32: testb $8, %al
|
||||||
|
; CHECK-32: ret
|
||||||
|
define void @g16xl(i16 inreg %x) nounwind {
|
||||||
|
%t = and i16 %x, 8
|
||||||
|
%s = icmp eq i16 %t, 0
|
||||||
|
br i1 %s, label %yes, label %no
|
||||||
|
|
||||||
|
yes:
|
||||||
|
call void @bar()
|
||||||
|
ret void
|
||||||
|
no:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
; CHECK-64: g64x16:
|
||||||
|
; CHECK-64: testw $32896, %di
|
||||||
|
; CHECK-64: ret
|
||||||
|
; CHECK-32: g64x16:
|
||||||
|
; CHECK-32: testw $32896, %ax
|
||||||
|
; CHECK-32: ret
|
||||||
|
define void @g64x16(i64 inreg %x) nounwind {
|
||||||
|
%t = and i64 %x, 32896
|
||||||
|
%s = icmp eq i64 %t, 0
|
||||||
|
br i1 %s, label %yes, label %no
|
||||||
|
|
||||||
|
yes:
|
||||||
|
call void @bar()
|
||||||
|
ret void
|
||||||
|
no:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
; CHECK-64: g32x16:
|
||||||
|
; CHECK-64: testw $32896, %di
|
||||||
|
; CHECK-64: ret
|
||||||
|
; CHECK-32: g32x16:
|
||||||
|
; CHECK-32: testw $32896, %ax
|
||||||
|
; CHECK-32: ret
|
||||||
|
define void @g32x16(i32 inreg %x) nounwind {
|
||||||
|
%t = and i32 %x, 32896
|
||||||
|
%s = icmp eq i32 %t, 0
|
||||||
|
br i1 %s, label %yes, label %no
|
||||||
|
|
||||||
|
yes:
|
||||||
|
call void @bar()
|
||||||
|
ret void
|
||||||
|
no:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
; CHECK-64: g64x32:
|
||||||
|
; CHECK-64: testl $268468352, %edi
|
||||||
|
; CHECK-64: ret
|
||||||
|
; CHECK-32: g64x32:
|
||||||
|
; CHECK-32: testl $268468352, %eax
|
||||||
|
; CHECK-32: ret
|
||||||
|
define void @g64x32(i64 inreg %x) nounwind {
|
||||||
|
%t = and i64 %x, 268468352
|
||||||
|
%s = icmp eq i64 %t, 0
|
||||||
|
br i1 %s, label %yes, label %no
|
||||||
|
|
||||||
|
yes:
|
||||||
|
call void @bar()
|
||||||
|
ret void
|
||||||
|
no:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @bar()
|
Loading…
x
Reference in New Issue
Block a user