Better implementation of truncate. ISel matches it to a pseudo instruction

that gets emitted as movl (for r32 to i16, i8) or a movw (for r16 to i8). And
if the destination gets allocated a subregister of the source operand, then
the instruction will not be emitted at all.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@28119 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng 2006-05-05 05:40:20 +00:00
parent 55c63257f3
commit 8f7f7125e9
6 changed files with 162 additions and 240 deletions

View File

@ -108,13 +108,20 @@ void X86ATTAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
const MachineOperand &MO = MI->getOperand(OpNo);
const MRegisterInfo &RI = *TM.getRegisterInfo();
switch (MO.getType()) {
case MachineOperand::MO_Register:
case MachineOperand::MO_Register: {
assert(MRegisterInfo::isPhysicalRegister(MO.getReg()) &&
"Virtual registers should not make it this far!");
O << '%';
for (const char *Name = RI.get(MO.getReg()).Name; *Name; ++Name)
unsigned Reg = MO.getReg();
if (Modifier && strncmp(Modifier, "trunc", strlen("trunc")) == 0) {
MVT::ValueType VT = (strcmp(Modifier,"trunc16") == 0)
? MVT::i16 : MVT::i32;
Reg = getX86SubSuperRegister(Reg, VT);
}
for (const char *Name = RI.get(Reg).Name; *Name; ++Name)
O << (char)tolower(*Name);
return;
}
case MachineOperand::MO_Immediate:
if (!Modifier || strcmp(Modifier, "debug") != 0)
@ -263,116 +270,25 @@ bool X86ATTAsmPrinter::printAsmMRegister(const MachineOperand &MO,
const char Mode) {
const MRegisterInfo &RI = *TM.getRegisterInfo();
unsigned Reg = MO.getReg();
const char *Name = RI.get(Reg).Name;
switch (Mode) {
default: return true; // Unknown mode.
case 'b': // Print QImode register
switch (Reg) {
default: return true;
case X86::AH: case X86::AL: case X86::AX: case X86::EAX:
Name = "al";
break;
case X86::DH: case X86::DL: case X86::DX: case X86::EDX:
Name = "dl";
break;
case X86::CH: case X86::CL: case X86::CX: case X86::ECX:
Name = "cl";
break;
case X86::BH: case X86::BL: case X86::BX: case X86::EBX:
Name = "bl";
break;
case X86::ESI:
Name = "sil";
break;
case X86::EDI:
Name = "dil";
break;
case X86::EBP:
Name = "bpl";
break;
case X86::ESP:
Name = "spl";
break;
}
Reg = getX86SubSuperRegister(Reg, MVT::i8);
break;
case 'h': // Print QImode high register
switch (Reg) {
default: return true;
case X86::AH: case X86::AL: case X86::AX: case X86::EAX:
Name = "al";
break;
case X86::DH: case X86::DL: case X86::DX: case X86::EDX:
Name = "dl";
break;
case X86::CH: case X86::CL: case X86::CX: case X86::ECX:
Name = "cl";
break;
case X86::BH: case X86::BL: case X86::BX: case X86::EBX:
Name = "bl";
break;
}
Reg = getX86SubSuperRegister(Reg, MVT::i8, true);
break;
case 'w': // Print HImode register
switch (Reg) {
default: return true;
case X86::AH: case X86::AL: case X86::AX: case X86::EAX:
Name = "ax";
break;
case X86::DH: case X86::DL: case X86::DX: case X86::EDX:
Name = "dx";
break;
case X86::CH: case X86::CL: case X86::CX: case X86::ECX:
Name = "cx";
break;
case X86::BH: case X86::BL: case X86::BX: case X86::EBX:
Name = "bx";
break;
case X86::ESI:
Name = "si";
break;
case X86::EDI:
Name = "di";
break;
case X86::EBP:
Name = "bp";
break;
case X86::ESP:
Name = "sp";
break;
}
Reg = getX86SubSuperRegister(Reg, MVT::i16);
break;
case 'k': // Print SImode register
switch (Reg) {
default: return true;
case X86::AH: case X86::AL: case X86::AX: case X86::EAX:
Name = "eax";
break;
case X86::DH: case X86::DL: case X86::DX: case X86::EDX:
Name = "edx";
break;
case X86::CH: case X86::CL: case X86::CX: case X86::ECX:
Name = "ecx";
break;
case X86::BH: case X86::BL: case X86::BX: case X86::EBX:
Name = "ebx";
break;
case X86::ESI:
Name = "esi";
break;
case X86::EDI:
Name = "edi";
break;
case X86::EBP:
Name = "ebp";
break;
case X86::ESP:
Name = "esp";
break;
}
Reg = getX86SubSuperRegister(Reg, MVT::i32);
break;
}
O << '%' << Name;
O << '%';
for (const char *Name = RI.get(Reg).Name; *Name; ++Name)
O << (char)tolower(*Name);
return false;
}
@ -440,6 +356,26 @@ void X86ATTAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
}
}
// See if a truncate instruction can be turned into a nop.
switch (MI->getOpcode()) {
default: break;
case X86::TRUNC_R32_R16:
case X86::TRUNC_R32_R8:
case X86::TRUNC_R16_R8: {
const MachineOperand &MO0 = MI->getOperand(0);
const MachineOperand &MO1 = MI->getOperand(1);
unsigned Reg0 = MO0.getReg();
unsigned Reg1 = MO1.getReg();
if (MI->getOpcode() == X86::TRUNC_R16_R8)
Reg0 = getX86SubSuperRegister(Reg0, MVT::i16);
else
Reg0 = getX86SubSuperRegister(Reg0, MVT::i32);
if (Reg0 == Reg1)
O << CommentString << " TRUNCATE ";
break;
}
}
// Call the autogenerated instruction printer routines.
printInstruction(MI);
}

View File

@ -782,45 +782,6 @@ void X86DAGToDAGISel::Select(SDOperand &Result, SDOperand N) {
AddHandleReplacement(N1.Val, 1, Result.Val, 1);
}
#ifndef NDEBUG
DEBUG(std::cerr << std::string(Indent-2, ' '));
DEBUG(std::cerr << "== ");
DEBUG(Result.Val->dump(CurDAG));
DEBUG(std::cerr << "\n");
Indent -= 2;
#endif
return;
}
case ISD::TRUNCATE: {
unsigned Reg;
MVT::ValueType VT;
switch (Node->getOperand(0).getValueType()) {
default: assert(0 && "Unknown truncate!");
case MVT::i16: Reg = X86::AX; Opc = X86::MOV16rr; VT = MVT::i16; break;
case MVT::i32: Reg = X86::EAX; Opc = X86::MOV32rr; VT = MVT::i32; break;
}
SDOperand Tmp0, Tmp1;
Select(Tmp0, Node->getOperand(0));
Select(Tmp1, SDOperand(CurDAG->getTargetNode(Opc, VT, Tmp0), 0));
SDOperand InFlag = SDOperand(0,0);
Result = CurDAG->getCopyToReg(CurDAG->getEntryNode(), Reg, Tmp1, InFlag);
SDOperand Chain = Result.getValue(0);
InFlag = Result.getValue(1);
switch (NVT) {
default: assert(0 && "Unknown truncate!");
case MVT::i8: Reg = X86::AL; Opc = X86::MOV8rr; VT = MVT::i8; break;
case MVT::i16: Reg = X86::AX; Opc = X86::MOV16rr; VT = MVT::i16; break;
}
Result = CurDAG->getCopyFromReg(Chain, Reg, VT, InFlag);
if (N.Val->hasOneUse())
Result = CurDAG->SelectNodeTo(N.Val, Opc, VT, Result);
else
Result = CodeGenMap[N] =
SDOperand(CurDAG->getTargetNode(Opc, VT, Result), 0);
#ifndef NDEBUG
DEBUG(std::cerr << std::string(Indent-2, ' '));
DEBUG(std::cerr << "== ");

View File

@ -351,6 +351,17 @@ def IMPLICIT_DEF_R32 : I<0, Pseudo, (ops R32:$dst),
// Nop
def NOOP : I<0x90, RawFrm, (ops), "nop", []>;
// Truncate
def TRUNC_R32_R8 : I<0x89, MRMDestReg, (ops R8:$dst, R32:$src),
"mov{l} {$src, ${dst:trunc32}|${dst:trunc32}, $src}",
[(set R8:$dst, (trunc R32:$src))]>;
def TRUNC_R32_R16 : I<0x89, MRMDestReg, (ops R16:$dst, R32:$src),
"mov{l} {$src, ${dst:trunc32}|${dst:trunc32}, $src}",
[(set R16:$dst, (trunc R32:$src))]>;
def TRUNC_R16_R8 : I<0x89, MRMDestReg, (ops R8:$dst, R16:$src),
"mov{w} {$src, ${dst:trunc16}|${dst:trunc16}, $src}",
[(set R8:$dst, (trunc R16:$src))]>;
//===----------------------------------------------------------------------===//
// Control Flow Instructions...
//

View File

@ -101,9 +101,15 @@ void X86IntelAsmPrinter::printOp(const MachineOperand &MO,
const MRegisterInfo &RI = *TM.getRegisterInfo();
switch (MO.getType()) {
case MachineOperand::MO_Register:
if (MRegisterInfo::isPhysicalRegister(MO.getReg()))
O << RI.get(MO.getReg()).Name;
else
if (MRegisterInfo::isPhysicalRegister(MO.getReg())) {
unsigned Reg = MO.getReg();
if (Modifier && strncmp(Modifier, "trunc", strlen("trunc")) == 0) {
MVT::ValueType VT = (strcmp(Modifier,"trunc16") == 0)
? MVT::i16 : MVT::i32;
Reg = getX86SubSuperRegister(Reg, VT);
}
O << RI.get(Reg).Name;
} else
O << "reg" << MO.getReg();
return;
@ -240,116 +246,23 @@ bool X86IntelAsmPrinter::printAsmMRegister(const MachineOperand &MO,
const char Mode) {
const MRegisterInfo &RI = *TM.getRegisterInfo();
unsigned Reg = MO.getReg();
const char *Name = RI.get(Reg).Name;
switch (Mode) {
default: return true; // Unknown mode.
case 'b': // Print QImode register
switch (Reg) {
default: return true;
case X86::AH: case X86::AL: case X86::AX: case X86::EAX:
Name = "AL";
break;
case X86::DH: case X86::DL: case X86::DX: case X86::EDX:
Name = "DL";
break;
case X86::CH: case X86::CL: case X86::CX: case X86::ECX:
Name = "CL";
break;
case X86::BH: case X86::BL: case X86::BX: case X86::EBX:
Name = "BL";
break;
case X86::ESI:
Name = "SIL";
break;
case X86::EDI:
Name = "DIL";
break;
case X86::EBP:
Name = "BPL";
break;
case X86::ESP:
Name = "SPL";
break;
}
Reg = getX86SubSuperRegister(Reg, MVT::i8);
break;
case 'h': // Print QImode high register
switch (Reg) {
default: return true;
case X86::AH: case X86::AL: case X86::AX: case X86::EAX:
Name = "AL";
break;
case X86::DH: case X86::DL: case X86::DX: case X86::EDX:
Name = "DL";
break;
case X86::CH: case X86::CL: case X86::CX: case X86::ECX:
Name = "CL";
break;
case X86::BH: case X86::BL: case X86::BX: case X86::EBX:
Name = "BL";
break;
}
Reg = getX86SubSuperRegister(Reg, MVT::i8, true);
break;
case 'w': // Print HImode register
switch (Reg) {
default: return true;
case X86::AH: case X86::AL: case X86::AX: case X86::EAX:
Name = "AX";
break;
case X86::DH: case X86::DL: case X86::DX: case X86::EDX:
Name = "DX";
break;
case X86::CH: case X86::CL: case X86::CX: case X86::ECX:
Name = "CX";
break;
case X86::BH: case X86::BL: case X86::BX: case X86::EBX:
Name = "BX";
break;
case X86::ESI:
Name = "SI";
break;
case X86::EDI:
Name = "DI";
break;
case X86::EBP:
Name = "BP";
break;
case X86::ESP:
Name = "SP";
break;
}
Reg = getX86SubSuperRegister(Reg, MVT::i16);
break;
case 'k': // Print SImode register
switch (Reg) {
default: return true;
case X86::AH: case X86::AL: case X86::AX: case X86::EAX:
Name = "EAX";
break;
case X86::DH: case X86::DL: case X86::DX: case X86::EDX:
Name = "EDX";
break;
case X86::CH: case X86::CL: case X86::CX: case X86::ECX:
Name = "ECX";
break;
case X86::BH: case X86::BL: case X86::BX: case X86::EBX:
Name = "EBX";
break;
case X86::ESI:
Name = "ESI";
break;
case X86::EDI:
Name = "EDI";
break;
case X86::EBP:
Name = "EBP";
break;
case X86::ESP:
Name = "ESP";
break;
}
Reg = getX86SubSuperRegister(Reg, MVT::i32);
break;
}
O << Name;
O << '%' << RI.get(Reg).Name;
return false;
}
@ -392,6 +305,26 @@ bool X86IntelAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
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::TRUNC_R32_R16:
case X86::TRUNC_R32_R8:
case X86::TRUNC_R16_R8: {
const MachineOperand &MO0 = MI->getOperand(0);
const MachineOperand &MO1 = MI->getOperand(1);
unsigned Reg0 = MO0.getReg();
unsigned Reg1 = MO1.getReg();
if (MI->getOpcode() == X86::TRUNC_R16_R8)
Reg0 = getX86SubSuperRegister(Reg0, MVT::i16);
else
Reg0 = getX86SubSuperRegister(Reg0, MVT::i32);
if (Reg0 == Reg1)
O << CommentString << " TRUNCATE ";
break;
}
}
// Call the autogenerated instruction printer routines.
printInstruction(MI);
}

View File

@ -811,5 +811,81 @@ unsigned X86RegisterInfo::getFrameRegister(MachineFunction &MF) const {
return hasFP(MF) ? X86::EBP : X86::ESP;
}
namespace llvm {
unsigned getX86SubSuperRegister(unsigned Reg, MVT::ValueType VT, bool High) {
switch (VT) {
default: return Reg;
case MVT::i8:
if (High) {
switch (Reg) {
default: return Reg;
case X86::AH: case X86::AL: case X86::AX: case X86::EAX:
return X86::AH;
case X86::DH: case X86::DL: case X86::DX: case X86::EDX:
return X86::DH;
case X86::CH: case X86::CL: case X86::CX: case X86::ECX:
return X86::CH;
case X86::BH: case X86::BL: case X86::BX: case X86::EBX:
return X86::BH;
}
} else {
switch (Reg) {
default: return Reg;
case X86::AH: case X86::AL: case X86::AX: case X86::EAX:
return X86::AL;
case X86::DH: case X86::DL: case X86::DX: case X86::EDX:
return X86::DL;
case X86::CH: case X86::CL: case X86::CX: case X86::ECX:
return X86::CL;
case X86::BH: case X86::BL: case X86::BX: case X86::EBX:
return X86::BL;
}
}
case MVT::i16:
switch (Reg) {
default: return Reg;
case X86::AH: case X86::AL: case X86::AX: case X86::EAX:
return X86::AX;
case X86::DH: case X86::DL: case X86::DX: case X86::EDX:
return X86::DX;
case X86::CH: case X86::CL: case X86::CX: case X86::ECX:
return X86::CX;
case X86::BH: case X86::BL: case X86::BX: case X86::EBX:
return X86::BX;
case X86::ESI:
return X86::SI;
case X86::EDI:
return X86::DI;
case X86::EBP:
return X86::BP;
case X86::ESP:
return X86::SP;
}
case MVT::i32:
switch (Reg) {
default: return true;
case X86::AH: case X86::AL: case X86::AX: case X86::EAX:
return X86::EAX;
case X86::DH: case X86::DL: case X86::DX: case X86::EDX:
return X86::EDX;
case X86::CH: case X86::CL: case X86::CX: case X86::ECX:
return X86::ECX;
case X86::BH: case X86::BL: case X86::BX: case X86::EBX:
return X86::EBX;
case X86::SI:
return X86::ESI;
case X86::DI:
return X86::EDI;
case X86::BP:
return X86::EBP;
case X86::SP:
return X86::ESP;
}
}
return Reg;
}
}
#include "X86GenRegisterInfo.inc"

View File

@ -68,6 +68,11 @@ struct X86RegisterInfo : public X86GenRegisterInfo {
unsigned getFrameRegister(MachineFunction &MF) const;
};
// getX86SubSuperRegister - X86 utility function. It returns the sub or super
// register of a specific X86 register.
// e.g. getX86SubSuperRegister(X86::EAX, MVT::i16) return X86:AX
unsigned getX86SubSuperRegister(unsigned, MVT::ValueType, bool High=false);
} // End llvm namespace
#endif