From 427aeb476f80adb1dbc7ab93210a8ae6e7bf7df8 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 11 Apr 2004 19:21:59 +0000 Subject: [PATCH] Two changes: 1. If an incoming argument is dead, don't load it from the stack 2. Do not code gen noop copies at all (ie, cast int -> uint), not even to a move. This should reduce register pressure for allocators that are unable to coallesce away these copies in some cases. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@12835 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/InstSelectSimple.cpp | 154 ++++++++++++++++------------ lib/Target/X86/X86ISelSimple.cpp | 154 ++++++++++++++++------------ 2 files changed, 176 insertions(+), 132 deletions(-) diff --git a/lib/Target/X86/InstSelectSimple.cpp b/lib/Target/X86/InstSelectSimple.cpp index 98587829fd0..8dbf61ed7c5 100644 --- a/lib/Target/X86/InstSelectSimple.cpp +++ b/lib/Target/X86/InstSelectSimple.cpp @@ -35,6 +35,43 @@ using namespace llvm; namespace { Statistic<> NumFPKill("x86-codegen", "Number of FP_REG_KILL instructions added"); + + /// TypeClass - Used by the X86 backend to group LLVM types by their basic X86 + /// Representation. + /// + enum TypeClass { + cByte, cShort, cInt, cFP, cLong + }; +} + +/// getClass - Turn a primitive type into a "class" number which is based on the +/// size of the type, and whether or not it is floating point. +/// +static inline TypeClass getClass(const Type *Ty) { + switch (Ty->getPrimitiveID()) { + case Type::SByteTyID: + case Type::UByteTyID: return cByte; // Byte operands are class #0 + case Type::ShortTyID: + case Type::UShortTyID: return cShort; // Short operands are class #1 + case Type::IntTyID: + case Type::UIntTyID: + case Type::PointerTyID: return cInt; // Int's and pointers are class #2 + + case Type::FloatTyID: + case Type::DoubleTyID: return cFP; // Floating Point is #3 + + case Type::LongTyID: + case Type::ULongTyID: return cLong; // Longs are class #4 + default: + assert(0 && "Invalid type to getClass!"); + return cByte; // not reached + } +} + +// getClassB - Just like getClass, but treat boolean values as bytes. +static inline TypeClass getClassB(const Type *Ty) { + if (Ty == Type::BoolTy) return cByte; + return getClass(Ty); } namespace { @@ -315,22 +352,28 @@ namespace { } unsigned getReg(Value *V, MachineBasicBlock *MBB, MachineBasicBlock::iterator IPt) { - unsigned &Reg = RegMap[V]; - if (Reg == 0) { - Reg = makeAnotherReg(V->getType()); - RegMap[V] = Reg; - } - // If this operand is a constant, emit the code to copy the constant into // the register here... // if (Constant *C = dyn_cast(V)) { + unsigned Reg = makeAnotherReg(V->getType()); copyConstantToRegister(MBB, IPt, C, Reg); - RegMap.erase(V); // Assign a new name to this constant if ref'd again + return Reg; } else if (GlobalValue *GV = dyn_cast(V)) { + unsigned Reg = makeAnotherReg(V->getType()); // Move the address of the global into the register BuildMI(*MBB, IPt, X86::MOV32ri, 1, Reg).addGlobalAddress(GV); - RegMap.erase(V); // Assign a new name to this address if ref'd again + return Reg; + } else if (CastInst *CI = dyn_cast(V)) { + // Do not emit noop casts at all. + if (getClassB(CI->getType()) == getClassB(CI->getOperand(0)->getType())) + return getReg(CI->getOperand(0), MBB, IPt); + } + + unsigned &Reg = RegMap[V]; + if (Reg == 0) { + Reg = makeAnotherReg(V->getType()); + RegMap[V] = Reg; } return Reg; @@ -338,44 +381,6 @@ namespace { }; } -/// TypeClass - Used by the X86 backend to group LLVM types by their basic X86 -/// Representation. -/// -enum TypeClass { - cByte, cShort, cInt, cFP, cLong -}; - -/// getClass - Turn a primitive type into a "class" number which is based on the -/// size of the type, and whether or not it is floating point. -/// -static inline TypeClass getClass(const Type *Ty) { - switch (Ty->getPrimitiveID()) { - case Type::SByteTyID: - case Type::UByteTyID: return cByte; // Byte operands are class #0 - case Type::ShortTyID: - case Type::UShortTyID: return cShort; // Short operands are class #1 - case Type::IntTyID: - case Type::UIntTyID: - case Type::PointerTyID: return cInt; // Int's and pointers are class #2 - - case Type::FloatTyID: - case Type::DoubleTyID: return cFP; // Floating Point is #3 - - case Type::LongTyID: - case Type::ULongTyID: return cLong; // Longs are class #4 - default: - assert(0 && "Invalid type to getClass!"); - return cByte; // not reached - } -} - -// getClassB - Just like getClass, but treat boolean values as bytes. -static inline TypeClass getClassB(const Type *Ty) { - if (Ty == Type::BoolTy) return cByte; - return getClass(Ty); -} - - /// copyConstantToRegister - Output the instructions required to put the /// specified constant into the specified register. /// @@ -511,39 +516,51 @@ void ISel::LoadArgumentsToVirtualRegs(Function &Fn) { MachineFrameInfo *MFI = F->getFrameInfo(); for (Function::aiterator I = Fn.abegin(), E = Fn.aend(); I != E; ++I) { - unsigned Reg = getReg(*I); - + bool ArgLive = !I->use_empty(); + unsigned Reg = ArgLive ? getReg(*I) : 0; int FI; // Frame object index + switch (getClassB(I->getType())) { case cByte: - FI = MFI->CreateFixedObject(1, ArgOffset); - addFrameReference(BuildMI(BB, X86::MOV8rm, 4, Reg), FI); + if (ArgLive) { + FI = MFI->CreateFixedObject(1, ArgOffset); + addFrameReference(BuildMI(BB, X86::MOV8rm, 4, Reg), FI); + } break; case cShort: - FI = MFI->CreateFixedObject(2, ArgOffset); - addFrameReference(BuildMI(BB, X86::MOV16rm, 4, Reg), FI); + if (ArgLive) { + FI = MFI->CreateFixedObject(2, ArgOffset); + addFrameReference(BuildMI(BB, X86::MOV16rm, 4, Reg), FI); + } break; case cInt: - FI = MFI->CreateFixedObject(4, ArgOffset); - addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg), FI); + if (ArgLive) { + FI = MFI->CreateFixedObject(4, ArgOffset); + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg), FI); + } break; case cLong: - FI = MFI->CreateFixedObject(8, ArgOffset); - addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg), FI); - addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg+1), FI, 4); + if (ArgLive) { + FI = MFI->CreateFixedObject(8, ArgOffset); + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg), FI); + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg+1), FI, 4); + } ArgOffset += 4; // longs require 4 additional bytes break; case cFP: - unsigned Opcode; - if (I->getType() == Type::FloatTy) { - Opcode = X86::FLD32m; - FI = MFI->CreateFixedObject(4, ArgOffset); - } else { - Opcode = X86::FLD64m; - FI = MFI->CreateFixedObject(8, ArgOffset); - ArgOffset += 4; // doubles require 4 additional bytes + if (ArgLive) { + unsigned Opcode; + if (I->getType() == Type::FloatTy) { + Opcode = X86::FLD32m; + FI = MFI->CreateFixedObject(4, ArgOffset); + } else { + Opcode = X86::FLD64m; + FI = MFI->CreateFixedObject(8, ArgOffset); + } + addFrameReference(BuildMI(BB, Opcode, 4, Reg), FI); } - addFrameReference(BuildMI(BB, Opcode, 4, Reg), FI); + if (I->getType() == Type::DoubleTy) + ArgOffset += 4; // doubles require 4 additional bytes break; default: assert(0 && "Unhandled argument type!"); @@ -2525,6 +2542,11 @@ void ISel::visitStoreInst(StoreInst &I) { /// void ISel::visitCastInst(CastInst &CI) { Value *Op = CI.getOperand(0); + + // Noop casts are not even emitted. + if (getClassB(CI.getType()) == getClassB(Op->getType())) + return; + // If this is a cast from a 32-bit integer to a Long type, and the only uses // of the case are GEP instructions, then the cast does not need to be // generated explicitly, it will be folded into the GEP. diff --git a/lib/Target/X86/X86ISelSimple.cpp b/lib/Target/X86/X86ISelSimple.cpp index 98587829fd0..8dbf61ed7c5 100644 --- a/lib/Target/X86/X86ISelSimple.cpp +++ b/lib/Target/X86/X86ISelSimple.cpp @@ -35,6 +35,43 @@ using namespace llvm; namespace { Statistic<> NumFPKill("x86-codegen", "Number of FP_REG_KILL instructions added"); + + /// TypeClass - Used by the X86 backend to group LLVM types by their basic X86 + /// Representation. + /// + enum TypeClass { + cByte, cShort, cInt, cFP, cLong + }; +} + +/// getClass - Turn a primitive type into a "class" number which is based on the +/// size of the type, and whether or not it is floating point. +/// +static inline TypeClass getClass(const Type *Ty) { + switch (Ty->getPrimitiveID()) { + case Type::SByteTyID: + case Type::UByteTyID: return cByte; // Byte operands are class #0 + case Type::ShortTyID: + case Type::UShortTyID: return cShort; // Short operands are class #1 + case Type::IntTyID: + case Type::UIntTyID: + case Type::PointerTyID: return cInt; // Int's and pointers are class #2 + + case Type::FloatTyID: + case Type::DoubleTyID: return cFP; // Floating Point is #3 + + case Type::LongTyID: + case Type::ULongTyID: return cLong; // Longs are class #4 + default: + assert(0 && "Invalid type to getClass!"); + return cByte; // not reached + } +} + +// getClassB - Just like getClass, but treat boolean values as bytes. +static inline TypeClass getClassB(const Type *Ty) { + if (Ty == Type::BoolTy) return cByte; + return getClass(Ty); } namespace { @@ -315,22 +352,28 @@ namespace { } unsigned getReg(Value *V, MachineBasicBlock *MBB, MachineBasicBlock::iterator IPt) { - unsigned &Reg = RegMap[V]; - if (Reg == 0) { - Reg = makeAnotherReg(V->getType()); - RegMap[V] = Reg; - } - // If this operand is a constant, emit the code to copy the constant into // the register here... // if (Constant *C = dyn_cast(V)) { + unsigned Reg = makeAnotherReg(V->getType()); copyConstantToRegister(MBB, IPt, C, Reg); - RegMap.erase(V); // Assign a new name to this constant if ref'd again + return Reg; } else if (GlobalValue *GV = dyn_cast(V)) { + unsigned Reg = makeAnotherReg(V->getType()); // Move the address of the global into the register BuildMI(*MBB, IPt, X86::MOV32ri, 1, Reg).addGlobalAddress(GV); - RegMap.erase(V); // Assign a new name to this address if ref'd again + return Reg; + } else if (CastInst *CI = dyn_cast(V)) { + // Do not emit noop casts at all. + if (getClassB(CI->getType()) == getClassB(CI->getOperand(0)->getType())) + return getReg(CI->getOperand(0), MBB, IPt); + } + + unsigned &Reg = RegMap[V]; + if (Reg == 0) { + Reg = makeAnotherReg(V->getType()); + RegMap[V] = Reg; } return Reg; @@ -338,44 +381,6 @@ namespace { }; } -/// TypeClass - Used by the X86 backend to group LLVM types by their basic X86 -/// Representation. -/// -enum TypeClass { - cByte, cShort, cInt, cFP, cLong -}; - -/// getClass - Turn a primitive type into a "class" number which is based on the -/// size of the type, and whether or not it is floating point. -/// -static inline TypeClass getClass(const Type *Ty) { - switch (Ty->getPrimitiveID()) { - case Type::SByteTyID: - case Type::UByteTyID: return cByte; // Byte operands are class #0 - case Type::ShortTyID: - case Type::UShortTyID: return cShort; // Short operands are class #1 - case Type::IntTyID: - case Type::UIntTyID: - case Type::PointerTyID: return cInt; // Int's and pointers are class #2 - - case Type::FloatTyID: - case Type::DoubleTyID: return cFP; // Floating Point is #3 - - case Type::LongTyID: - case Type::ULongTyID: return cLong; // Longs are class #4 - default: - assert(0 && "Invalid type to getClass!"); - return cByte; // not reached - } -} - -// getClassB - Just like getClass, but treat boolean values as bytes. -static inline TypeClass getClassB(const Type *Ty) { - if (Ty == Type::BoolTy) return cByte; - return getClass(Ty); -} - - /// copyConstantToRegister - Output the instructions required to put the /// specified constant into the specified register. /// @@ -511,39 +516,51 @@ void ISel::LoadArgumentsToVirtualRegs(Function &Fn) { MachineFrameInfo *MFI = F->getFrameInfo(); for (Function::aiterator I = Fn.abegin(), E = Fn.aend(); I != E; ++I) { - unsigned Reg = getReg(*I); - + bool ArgLive = !I->use_empty(); + unsigned Reg = ArgLive ? getReg(*I) : 0; int FI; // Frame object index + switch (getClassB(I->getType())) { case cByte: - FI = MFI->CreateFixedObject(1, ArgOffset); - addFrameReference(BuildMI(BB, X86::MOV8rm, 4, Reg), FI); + if (ArgLive) { + FI = MFI->CreateFixedObject(1, ArgOffset); + addFrameReference(BuildMI(BB, X86::MOV8rm, 4, Reg), FI); + } break; case cShort: - FI = MFI->CreateFixedObject(2, ArgOffset); - addFrameReference(BuildMI(BB, X86::MOV16rm, 4, Reg), FI); + if (ArgLive) { + FI = MFI->CreateFixedObject(2, ArgOffset); + addFrameReference(BuildMI(BB, X86::MOV16rm, 4, Reg), FI); + } break; case cInt: - FI = MFI->CreateFixedObject(4, ArgOffset); - addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg), FI); + if (ArgLive) { + FI = MFI->CreateFixedObject(4, ArgOffset); + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg), FI); + } break; case cLong: - FI = MFI->CreateFixedObject(8, ArgOffset); - addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg), FI); - addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg+1), FI, 4); + if (ArgLive) { + FI = MFI->CreateFixedObject(8, ArgOffset); + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg), FI); + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Reg+1), FI, 4); + } ArgOffset += 4; // longs require 4 additional bytes break; case cFP: - unsigned Opcode; - if (I->getType() == Type::FloatTy) { - Opcode = X86::FLD32m; - FI = MFI->CreateFixedObject(4, ArgOffset); - } else { - Opcode = X86::FLD64m; - FI = MFI->CreateFixedObject(8, ArgOffset); - ArgOffset += 4; // doubles require 4 additional bytes + if (ArgLive) { + unsigned Opcode; + if (I->getType() == Type::FloatTy) { + Opcode = X86::FLD32m; + FI = MFI->CreateFixedObject(4, ArgOffset); + } else { + Opcode = X86::FLD64m; + FI = MFI->CreateFixedObject(8, ArgOffset); + } + addFrameReference(BuildMI(BB, Opcode, 4, Reg), FI); } - addFrameReference(BuildMI(BB, Opcode, 4, Reg), FI); + if (I->getType() == Type::DoubleTy) + ArgOffset += 4; // doubles require 4 additional bytes break; default: assert(0 && "Unhandled argument type!"); @@ -2525,6 +2542,11 @@ void ISel::visitStoreInst(StoreInst &I) { /// void ISel::visitCastInst(CastInst &CI) { Value *Op = CI.getOperand(0); + + // Noop casts are not even emitted. + if (getClassB(CI.getType()) == getClassB(Op->getType())) + return; + // If this is a cast from a 32-bit integer to a Long type, and the only uses // of the case are GEP instructions, then the cast does not need to be // generated explicitly, it will be folded into the GEP. -- 2.34.1