From 8f7f7125e95e4fce29a4b8acbc88f708e7fae42f Mon Sep 17 00:00:00 2001 From: Evan Cheng Date: Fri, 5 May 2006 05:40:20 +0000 Subject: [PATCH] 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 --- lib/Target/X86/X86ATTAsmPrinter.cpp | 136 +++++++------------------- lib/Target/X86/X86ISelDAGToDAG.cpp | 39 -------- lib/Target/X86/X86InstrInfo.td | 11 +++ lib/Target/X86/X86IntelAsmPrinter.cpp | 135 +++++++------------------ lib/Target/X86/X86RegisterInfo.cpp | 76 ++++++++++++++ lib/Target/X86/X86RegisterInfo.h | 5 + 6 files changed, 162 insertions(+), 240 deletions(-) diff --git a/lib/Target/X86/X86ATTAsmPrinter.cpp b/lib/Target/X86/X86ATTAsmPrinter.cpp index 92e22945b7a..326251ccc2e 100755 --- a/lib/Target/X86/X86ATTAsmPrinter.cpp +++ b/lib/Target/X86/X86ATTAsmPrinter.cpp @@ -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); } diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp index 48132505888..c0c9704c04f 100644 --- a/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -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 << "== "); diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 77c167242c3..2bae9f79bcd 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -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... // diff --git a/lib/Target/X86/X86IntelAsmPrinter.cpp b/lib/Target/X86/X86IntelAsmPrinter.cpp index af58df1e956..a63be04b5b0 100755 --- a/lib/Target/X86/X86IntelAsmPrinter.cpp +++ b/lib/Target/X86/X86IntelAsmPrinter.cpp @@ -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); } diff --git a/lib/Target/X86/X86RegisterInfo.cpp b/lib/Target/X86/X86RegisterInfo.cpp index a3ed62fab6f..dac71a02f12 100644 --- a/lib/Target/X86/X86RegisterInfo.cpp +++ b/lib/Target/X86/X86RegisterInfo.cpp @@ -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" diff --git a/lib/Target/X86/X86RegisterInfo.h b/lib/Target/X86/X86RegisterInfo.h index 1cfd2730d86..5d4a66e12fd 100644 --- a/lib/Target/X86/X86RegisterInfo.h +++ b/lib/Target/X86/X86RegisterInfo.h @@ -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