EXTRACT_SUBREG = 4,
INSERT_SUBREG = 5
};
+
+ // Target independent implict values for use with subreg insert. All targets
+ // that support insert_subreg support IMPL_VAL_UNDEF. Support for the other
+ // values is target dependent.
+ enum ImplictVal {
+ IMPL_VAL_UNDEF = 0,
+ IMPL_VAL_ZERO = 1,
+ LAST_IMPL_VAL = 3
+ };
unsigned getNumOpcodes() const { return NumOpcodes; }
return false;
}
-
/// convertToThreeAddress - This method must be implemented by targets that
/// set the M_CONVERTIBLE_TO_3_ADDR flag. When this flag is set, the target
/// may be able to convert a two-address instruction into one or more true
(MI->getOperand(2).isRegister() && MI->getOperand(2).isUse()) &&
MI->getOperand(3).isImmediate() && "Invalid insert_subreg");
+ // Check if we're inserting into an implicit undef value.
+ bool isImplicit = MI->getOperand(1).isImmediate();
unsigned DstReg = MI->getOperand(0).getReg();
- unsigned SrcReg = 0;
- // Check if we're inserting into an implicit value.
- if (MI->getOperand(1).isImmediate())
- SrcReg = DstReg;
- else
- SrcReg = MI->getOperand(1).getReg();
+ unsigned SrcReg = isImplicit ? DstReg : MI->getOperand(1).getReg();
unsigned InsReg = MI->getOperand(2).getReg();
unsigned SubIdx = MI->getOperand(3).getImm();
DOUT << "subreg: CONVERTING: " << *MI;
+ // Check whether the implict subreg copy has side affects or not. Only copies
+ // into an undef value have no side affects, that is they can be eliminated
+ // without changing the semantics of the program.
+ bool copyHasSideAffects = isImplicit?
+ MI->getOperand(1).getImm() != TargetInstrInfo::IMPL_VAL_UNDEF
+ : false;
+
// If the inserted register is already allocated into a subregister
// of the destination, we copy the subreg into the source
// However, this is only safe if the insert instruction is the kill
// of the source register
bool revCopyOrder = TRI.isSubRegister(DstReg, InsReg);
- if (revCopyOrder && InsReg != DstSubReg) {
- if (MI->getOperand(1).isKill()) {
+ if (revCopyOrder && (InsReg != DstSubReg || copyHasSideAffects)) {
+ if (isImplicit || MI->getOperand(1).isKill()) {
DstSubReg = TRI.getSubReg(SrcReg, SubIdx);
// Insert sub-register copy
const TargetRegisterClass *TRC1 = 0;
}
}
#ifndef NDEBUG
- if (InsReg == DstSubReg) {
+ if (InsReg == DstSubReg && !copyHasSideAffects) {
DOUT << "subreg: Eliminated subreg copy\n";
}
#endif
}
#endif
- if (!revCopyOrder && InsReg != DstSubReg) {
+ if (!revCopyOrder && (InsReg != DstSubReg || copyHasSideAffects)) {
// Insert sub-register copy
const TargetRegisterClass *TRC1 = 0;
if (TargetRegisterInfo::isPhysicalRegister(InsReg)) {
[SDTCisInt<0>, SDTCisInt<1>, SDTCisInt<2>]>;
def dwarf_loc : SDNode<"ISD::DEBUG_LOC", SDT_dwarf_loc,[SDNPHasChain]>;
-
+//===----------------------------------------------------------------------===//
+// Implict value insert subreg support.
+//
+// These should match the enum TargetInstrInfo::ImplictVal.
+def tii_impl_val_undef : PatLeaf<(i32 0)>;
+def tii_impl_val_zero : PatLeaf<(i32 1)>;
void X86ATTAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
++EmittedInsts;
- // See if a truncate instruction can be turned into a nop.
- switch (MI->getOpcode()) {
- default: break;
- case X86::PsMOVZX64rr32:
- O << TAI->getCommentString() << " ZERO-EXTEND " << "\n\t";
- break;
- }
-
// Call the autogenerated instruction printer routines.
printInstruction(MI);
}
AddToISelQueue(N0);
if (NVT == MVT::i64 || NVT == MVT::i32 || NVT == MVT::i16) {
SDOperand SRIdx;
- SDOperand ImplVal = CurDAG->getTargetConstant(X86::IMPL_VAL_UNDEF,
- MVT::i32);
switch(N0.getValueType()) {
case MVT::i32:
SRIdx = CurDAG->getTargetConstant(X86::SUBREG_32BIT, MVT::i32);
- // x86-64 zero extends 32-bit inserts int 64-bit registers
- if (Subtarget->is64Bit())
- ImplVal = CurDAG->getTargetConstant(X86::IMPL_VAL_ZERO, MVT::i32);
break;
case MVT::i16:
SRIdx = CurDAG->getTargetConstant(X86::SUBREG_16BIT, MVT::i32);
default: assert(0 && "Unknown any_extend!");
}
if (SRIdx.Val) {
+ SDOperand ImplVal =
+ CurDAG->getTargetConstant(X86InstrInfo::IMPL_VAL_UNDEF, MVT::i32);
SDNode *ResNode = CurDAG->getTargetNode(X86::INSERT_SUBREG,
NVT, ImplVal, N0, SRIdx);
// Alias Instructions
//===----------------------------------------------------------------------===//
-// Zero-extension
-// TODO: Remove this after proper i32 -> i64 zext support.
-def PsMOVZX64rr32: I<0x89, MRMDestReg, (outs GR64:$dst), (ins GR32:$src),
- "mov{l}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}",
- [(set GR64:$dst, (zext GR32:$src))]>;
-def PsMOVZX64rm32: I<0x8B, MRMSrcMem, (outs GR64:$dst), (ins i32mem:$src),
- "mov{l}\t{$src, ${dst:subreg32}|${dst:subreg32}, $src}",
- [(set GR64:$dst, (zextloadi64i32 addr:$src))]>;
-
-/// PsAND64rrFFFFFFFF - r = r & (2^32-1)
-def PsAND64rrFFFFFFFF
- : I<0x89, MRMDestReg, (outs GR64:$dst), (ins GR64:$src),
- "mov{l}\t{${src:subreg32}, ${dst:subreg32}|${dst:subreg32}, ${src:subreg32}}",
- [(set GR64:$dst, (and GR64:$src, i64immFFFFFFFF))]>;
-
-
// Alias instructions that map movr0 to xor. Use xorl instead of xorq; it's
// equivalent due to implicit zero-extending, and it sometimes has a smaller
// encoding.
def : Pat<(parallel (X86cmp GR64:$src1, 0), (implicit EFLAGS)),
(TEST64rr GR64:$src1, GR64:$src1)>;
+
+
+// Zero-extension
+def : Pat<(i64 (zext GR32:$src)), (INSERT_SUBREG tii_impl_val_zero,
+ GR32:$src, x86_subreg_32bit)>;
+
// zextload bool -> zextload byte
def : Pat<(zextloadi64i1 addr:$src), (MOVZX64rm8 addr:$src)>;
+def : Pat<(zextloadi64i32 addr:$src), (INSERT_SUBREG tii_impl_val_zero,
+ (MOV32rm addr:$src), x86_subreg_32bit)>;
+
// extload
def : Pat<(extloadi64i1 addr:$src), (MOVZX64rm8 addr:$src)>;
def : Pat<(extloadi64i8 addr:$src), (MOVZX64rm8 addr:$src)>;
def : Pat<(extloadi64i16 addr:$src), (MOVZX64rm16 addr:$src)>;
-def : Pat<(extloadi64i32 addr:$src), (PsMOVZX64rm32 addr:$src)>;
+def : Pat<(extloadi64i32 addr:$src), (INSERT_SUBREG tii_impl_val_undef,
+ (MOV32rm addr:$src), x86_subreg_32bit)>;
// anyext -> zext
def : Pat<(i64 (anyext GR8 :$src)), (MOVZX64rr8 GR8 :$src)>;
def : Pat<(i64 (anyext GR16:$src)), (MOVZX64rr16 GR16:$src)>;
-def : Pat<(i64 (anyext GR32:$src)), (PsMOVZX64rr32 GR32:$src)>;
+def : Pat<(i64 (anyext GR32:$src)), (INSERT_SUBREG tii_impl_val_undef,
+ GR32:$src, x86_subreg_32bit)>;
+
def : Pat<(i64 (anyext (loadi8 addr:$src))), (MOVZX64rm8 addr:$src)>;
def : Pat<(i64 (anyext (loadi16 addr:$src))), (MOVZX64rm16 addr:$src)>;
-def : Pat<(i64 (anyext (loadi32 addr:$src))), (PsMOVZX64rm32 addr:$src)>;
+def : Pat<(i64 (anyext (loadi32 addr:$src))), (INSERT_SUBREG tii_impl_val_undef,
+ (MOV32rm addr:$src),
+ x86_subreg_32bit)>;
//===----------------------------------------------------------------------===//
// Some peepholes
//===----------------------------------------------------------------------===//
+
+// r & (2^32-1) ==> mov32 + implicit zext
+def : Pat<(and GR64:$src, i64immFFFFFFFF),
+ (INSERT_SUBREG tii_impl_val_zero,
+ (MOV32rr (EXTRACT_SUBREG GR64:$src, x86_subreg_32bit)),
+ x86_subreg_32bit)>;
+
// (shl x, 1) ==> (add x, x)
def : Pat<(shl GR64:$src1, (i8 1)), (ADD64rr GR64:$src1, GR64:$src1)>;
{ X86::PSHUFDri, X86::PSHUFDmi },
{ X86::PSHUFHWri, X86::PSHUFHWmi },
{ X86::PSHUFLWri, X86::PSHUFLWmi },
- { X86::PsMOVZX64rr32, X86::PsMOVZX64rm32 },
{ X86::RCPPSr, X86::RCPPSm },
{ X86::RCPPSr_Int, X86::RCPPSm_Int },
{ X86::RSQRTPSr, X86::RSQRTPSm },
// Build and insert into an implicit UNDEF value. This is OK because
// well be shifting and then extracting the lower 16-bits.
MachineInstr *Ins =
- BuildMI(get(X86::INSERT_SUBREG),leaInReg).addImm(X86::IMPL_VAL_UNDEF)
- .addReg(Src).addImm(X86::SUBREG_16BIT);
+ BuildMI(get(X86::INSERT_SUBREG),leaInReg)
+ .addImm(X86InstrInfo::IMPL_VAL_UNDEF)
+ .addReg(Src).addImm(X86::SUBREG_16BIT);
NewMI = BuildMI(get(Opc), leaOutReg)
.addReg(0).addImm(1 << ShAmt).addReg(leaInReg).addImm(0);
COND_S = 15,
COND_INVALID
};
-
- // X86 specific implict values used for subregister inserts.
- // This can be used to model the fact that x86-64 by default
- // inserts 32-bit values into 64-bit registers implicitly containing zeros.
- enum ImplicitVal {
- IMPL_VAL_UNDEF = 0,
- IMPL_VAL_ZERO = 1
- };
-
+
// Turn condition code into conditional branch opcode.
unsigned GetCondBranchFromCond(CondCode CC);
// Branch targets have OtherVT type.
def brtarget : Operand<OtherVT>;
-// These should match the enum X86::ImplicitVal
-def x86_impl_val_undef : PatLeaf<(i32 0)>;
-def x86_impl_val_zero : PatLeaf<(i32 1)>;
-
//===----------------------------------------------------------------------===//
// X86 Complex Pattern Definitions.
//
void X86IntelAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
++EmittedInsts;
- // See if a truncate instruction can be turned into a nop.
- switch (MI->getOpcode()) {
- default: break;
- case X86::PsMOVZX64rr32:
- O << TAI->getCommentString() << " ZERO-EXTEND " << "\n\t";
- break;
- }
-
// Call the autogenerated instruction printer routines.
printInstruction(MI);
}
}
}
- // Generate MemOperandSDNodes nodes for each memory accesses covered by this
- // pattern.
- if (isRoot) {
+ // Generate MemOperandSDNodes nodes for each memory accesses covered by
+ // this pattern.
+ if (II.isSimpleLoad | II.mayLoad | II.mayStore) {
std::vector<std::string>::const_iterator mi, mie;
for (mi = LSI.begin(), mie = LSI.end(); mi != mie; ++mi) {
emitCode("SDOperand LSI_" + *mi + " = "
<< " SDOperand Tmp = CurDAG->getTargetConstant(C, MVT::i32);\n"
<< " AddToISelQueue(N1);\n"
<< " SDOperand Ops[] = { N0, N1, Tmp };\n"
- << " if (N0.getOpcode() == ISD::UNDEF) {\n"
- << " return CurDAG->getTargetNode(TargetInstrInfo::INSERT_SUBREG,\n"
- << " N.getValueType(), Ops+1, 2);\n"
- << " } else {\n"
- << " AddToISelQueue(N0);\n"
- << " return CurDAG->getTargetNode(TargetInstrInfo::INSERT_SUBREG,\n"
- << " N.getValueType(), Ops, 3);\n"
- << " }\n"
+ << " AddToISelQueue(N0);\n"
+ << " return CurDAG->getTargetNode(TargetInstrInfo::INSERT_SUBREG,\n"
+ << " N.getValueType(), Ops, 3);\n"
<< "}\n\n";
OS << "// The main instruction selector code.\n"