mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-19 19:29:31 +00:00
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:
parent
55c63257f3
commit
8f7f7125e9
@ -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);
|
||||
}
|
||||
|
@ -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 << "== ");
|
||||
|
@ -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...
|
||||
//
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user