From lattner at cs.uiuc.edu Mon Jan 6 12:24:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:24:01 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/MachineCodeEmitter.h Message-ID: <200301061823.MAA26279@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: MachineCodeEmitter.h updated: 1.5 -> 1.6 --- Log message: Add new methods for constant pool support --- Diffs of the changes: Index: llvm/include/llvm/CodeGen/MachineCodeEmitter.h diff -u llvm/include/llvm/CodeGen/MachineCodeEmitter.h:1.5 llvm/include/llvm/CodeGen/MachineCodeEmitter.h:1.6 --- llvm/include/llvm/CodeGen/MachineCodeEmitter.h:1.5 Wed Dec 4 00:44:27 2002 +++ llvm/include/llvm/CodeGen/MachineCodeEmitter.h Mon Jan 6 12:23:45 2003 @@ -12,6 +12,7 @@ class MachineFunction; class MachineBasicBlock; +class MachineConstantPool; class Value; class GlobalValue; @@ -28,6 +29,10 @@ /// virtual void finishFunction(MachineFunction &F) {} + /// emitConstantPool - This callback is invoked to output the constant pool + /// for the function. + virtual void emitConstantPool(MachineConstantPool *MCP) {} + /// startBasicBlock - This callback is invoked when a new basic block is about /// to be emitted. /// @@ -50,6 +55,13 @@ /// virtual void emitGlobalAddress(GlobalValue *V) {} + /// emitFunctionConstantValueAddress - This callback is invoked when the + /// address of a constant, which was spilled to memory, needs to be addressed. + /// This is used for constants which cannot be directly specified as operands + /// to instructions, such as large integer values on the sparc, or floating + /// point constants on the X86. + /// + virtual void emitFunctionConstantValueAddress(unsigned ConstantNum) {} /// createDebugMachineCodeEmitter - Return a dynamically allocated machine /// code emitter, which just prints the opcodes and fields out the cout. This From lattner at cs.uiuc.edu Mon Jan 6 12:25:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:25:01 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/MachineFrameInfo.h Message-ID: <200301061824.MAA26290@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: MachineFrameInfo.h updated: 1.2 -> 1.3 --- Log message: Add helper functions for easier access --- Diffs of the changes: Index: llvm/include/llvm/CodeGen/MachineFrameInfo.h diff -u llvm/include/llvm/CodeGen/MachineFrameInfo.h:1.2 llvm/include/llvm/CodeGen/MachineFrameInfo.h:1.3 --- llvm/include/llvm/CodeGen/MachineFrameInfo.h:1.2 Sat Dec 28 15:08:25 2002 +++ llvm/include/llvm/CodeGen/MachineFrameInfo.h Mon Jan 6 12:24:15 2003 @@ -28,8 +28,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CODEGEN_FUNCTIONFRAMEINFO_H -#define LLVM_CODEGEN_FUNCTIONFRAMEINFO_H +#ifndef LLVM_CODEGEN_MACHINEFRAMEINFO_H +#define LLVM_CODEGEN_MACHINEFRAMEINFO_H + +class TargetData; +class TargetRegisterClass; +#include class MachineFrameInfo { @@ -180,6 +184,12 @@ Objects.push_back(StackObject(Size, Alignment, -1)); return Objects.size()-NumFixedObjects-1; } + + /// CreateStackObject - Create a stack object for a value of the specified + /// LLVM type or register class. + /// + int CreateStackObject(const Type *Ty, const TargetData &TD); + int CreateStackObject(const TargetRegisterClass *RC); /// CreateVariableSizedObject - Notify the MachineFrameInfo object that a /// variable sized object has been created. This must be created whenever a From lattner at cs.uiuc.edu Mon Jan 6 12:27:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:27:00 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/MachineInstr.h Message-ID: <200301061826.MAA26312@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: MachineInstr.h updated: 1.94 -> 1.95 --- Log message: * Add support for ConstantPool indices. * Fix a bug where unassigned virtual registers were considered to be physical registers because they had regno -1 --- Diffs of the changes: Index: llvm/include/llvm/CodeGen/MachineInstr.h diff -u llvm/include/llvm/CodeGen/MachineInstr.h:1.94 llvm/include/llvm/CodeGen/MachineInstr.h:1.95 --- llvm/include/llvm/CodeGen/MachineInstr.h:1.94 Sat Dec 28 14:05:44 2002 +++ llvm/include/llvm/CodeGen/MachineInstr.h Mon Jan 6 12:25:53 2003 @@ -81,6 +81,7 @@ MO_PCRelativeDisp, MO_MachineBasicBlock, // MachineBasicBlock reference MO_FrameIndex, // Abstract Stack Frame Index + MO_ConstantPoolIndex, // Address of indexed Constant in Constant Pool }; private: @@ -174,7 +175,7 @@ } bool isPhysicalRegister() const { return (opType == MO_VirtualRegister || opType == MO_MachineRegister) - && regNum < MRegisterInfo::FirstVirtualRegister; + && (unsigned)regNum < MRegisterInfo::FirstVirtualRegister; } bool isRegister() const { return isVirtualRegister() || isPhysicalRegister();} bool isMachineRegister() const { return !isVirtualRegister(); } @@ -184,6 +185,7 @@ return opType == MO_SignExtendedImmed || opType == MO_UnextendedImmed; } bool isFrameIndex() const { return opType == MO_FrameIndex; } + bool isConstantPoolIndex() const { return opType == MO_ConstantPoolIndex; } Value* getVRegValue() const { assert(opType == MO_VirtualRegister || opType == MO_CCRegister || @@ -204,6 +206,10 @@ return MBB; } int getFrameIndex() const { assert(isFrameIndex()); return immedVal; } + unsigned getConstantPoolIndex() const { + assert(isConstantPoolIndex()); + return immedVal; + } bool opIsUse () const { return (flags & USEDEFMASK) == 0; } bool opIsDef () const { return flags & DEFFLAG; } @@ -500,6 +506,15 @@ operands.push_back(MachineOperand(Idx, MachineOperand::MO_FrameIndex)); } + /// addConstantPoolndexOperand - Add a constant pool object index to the + /// instruction. + /// + void addConstantPoolIndexOperand(unsigned I) { + assert(!OperandsComplete() && + "Trying to add an operand to a machine instr that is already done!"); + operands.push_back(MachineOperand(I, MachineOperand::MO_ConstantPoolIndex)); + } + //===--------------------------------------------------------------------===// // Accessors used to modify instructions in place. @@ -511,6 +526,17 @@ /// below. /// void replace(MachineOpCode Opcode, unsigned numOperands); + + /// setOpcode - Replace the opcode of the current instruction with a new one. + /// + void setOpcode(unsigned Op) { opCode = Op; } + + /// RemoveOperand - Erase an operand from an instruction, leaving it with one + /// fewer operand than it started with. + /// + void RemoveOperand(unsigned i) { + operands.erase(operands.begin()+i); + } // Access to set the operands when building the machine instruction // From lattner at cs.uiuc.edu Mon Jan 6 12:27:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:27:01 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/MachineInstrBuilder.h Message-ID: <200301061826.MAA26320@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: MachineInstrBuilder.h updated: 1.10 -> 1.11 --- Log message: * Add support for ConstantPool indices. --- Diffs of the changes: Index: llvm/include/llvm/CodeGen/MachineInstrBuilder.h diff -u llvm/include/llvm/CodeGen/MachineInstrBuilder.h:1.10 llvm/include/llvm/CodeGen/MachineInstrBuilder.h:1.11 --- llvm/include/llvm/CodeGen/MachineInstrBuilder.h:1.10 Tue Dec 24 23:01:18 2002 +++ llvm/include/llvm/CodeGen/MachineInstrBuilder.h Mon Jan 6 12:26:03 2003 @@ -91,6 +91,11 @@ MI->addFrameIndexOperand(Idx); return *this; } + + const MachineInstrBuilder &addConstantPoolIndex(unsigned Idx) const { + MI->addConstantPoolIndexOperand(Idx); + return *this; + } }; /// BuildMI - Builder interface. Specify how to create the initial instruction From lattner at cs.uiuc.edu Mon Jan 6 12:27:02 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:27:02 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/MachineFunction.h Message-ID: <200301061826.MAA26326@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: MachineFunction.h updated: 1.24 -> 1.25 --- Log message: Add support for a per-function constant pool --- Diffs of the changes: Index: llvm/include/llvm/CodeGen/MachineFunction.h diff -u llvm/include/llvm/CodeGen/MachineFunction.h:1.24 llvm/include/llvm/CodeGen/MachineFunction.h:1.25 --- llvm/include/llvm/CodeGen/MachineFunction.h:1.24 Sat Dec 28 15:08:25 2002 +++ llvm/include/llvm/CodeGen/MachineFunction.h Mon Jan 6 12:24:42 2003 @@ -21,8 +21,9 @@ class SSARegMap; class MachineFunctionInfo; class MachineFrameInfo; +class MachineConstantPool; -Pass *createMachineCodeConstructionPass(TargetMachine &Target); +Pass *createMachineCodeConstructionPass(TargetMachine &TM); Pass *createMachineCodeDestructionPass(); Pass *createMachineFunctionPrinterPass(); @@ -42,8 +43,11 @@ // Keep track of objects allocated on the stack. MachineFrameInfo *FrameInfo; + // Keep track of constants which are spilled to memory + MachineConstantPool *ConstantPool; + public: - MachineFunction(const Function *Fn, const TargetMachine& target); + MachineFunction(const Function *Fn, const TargetMachine &TM); ~MachineFunction(); /// getFunction - Return the LLVM function that this machine code represents @@ -66,6 +70,10 @@ /// MachineFrameInfo *getFrameInfo() const { return FrameInfo; } + /// getConstantPool - Return the constant pool object for the current + /// function. + MachineConstantPool *getConstantPool() const { return ConstantPool; } + /// MachineFunctionInfo - Keep track of various per-function pieces of /// information for the sparc backend. /// @@ -90,8 +98,7 @@ // for a given Method. // destruct() -- Destroy the MachineFunction object // - static MachineFunction& construct(const Function *Fn, - const TargetMachine &target); + static MachineFunction& construct(const Function *F, const TargetMachine &TM); static void destruct(const Function *F); static MachineFunction& get(const Function *F); From lattner at cs.uiuc.edu Mon Jan 6 12:28:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:28:01 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/MachineConstantPool.h Message-ID: <200301061827.MAA26337@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: MachineConstantPool.h added (r1.1) --- Log message: Represent a per-function constant pool --- Diffs of the changes: From lattner at cs.uiuc.edu Mon Jan 6 12:28:02 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:28:02 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/Passes.h Message-ID: <200301061827.MAA26347@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: Passes.h added (r1.1) --- Log message: Combine code generation passes into a single .h file --- Diffs of the changes: From lattner at cs.uiuc.edu Mon Jan 6 12:29:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:29:01 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/LiveVariables.h Message-ID: <200301061828.MAA26363@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: LiveVariables.h added (r1.1) --- Log message: Implement live variable analysis for machine code --- Diffs of the changes: From lattner at cs.uiuc.edu Mon Jan 6 12:29:02 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:29:02 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/SSARegMap.h Message-ID: <200301061828.MAA26372@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: SSARegMap.h updated: 1.2 -> 1.3 --- Log message: Simplify interface --- Diffs of the changes: Index: llvm/include/llvm/CodeGen/SSARegMap.h diff -u llvm/include/llvm/CodeGen/SSARegMap.h:1.2 llvm/include/llvm/CodeGen/SSARegMap.h:1.3 --- llvm/include/llvm/CodeGen/SSARegMap.h:1.2 Tue Dec 24 23:01:05 2002 +++ llvm/include/llvm/CodeGen/SSARegMap.h Mon Jan 6 12:27:41 2003 @@ -28,10 +28,12 @@ return RegClassMap[actualReg]; } - void addRegMap(unsigned Reg, const TargetRegisterClass* RegClass) { - assert(rescale(Reg) == RegClassMap.size() && - "Register mapping not added in sequential order!"); + /// createVirtualRegister - Create and return a new virtual register in the + /// function with the specified register class. + /// + unsigned createVirtualRegister(const TargetRegisterClass *RegClass) { RegClassMap.push_back(RegClass); + return RegClassMap.size()+MRegisterInfo::FirstVirtualRegister-1; } }; From lattner at cs.uiuc.edu Mon Jan 6 12:29:02 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:29:02 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/Target/MRegisterInfo.h Message-ID: <200301061828.MAA26379@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/Target: MRegisterInfo.h updated: 1.15 -> 1.16 --- Log message: Add a new getName accessor --- Diffs of the changes: Index: llvm/include/llvm/Target/MRegisterInfo.h diff -u llvm/include/llvm/Target/MRegisterInfo.h:1.15 llvm/include/llvm/Target/MRegisterInfo.h:1.16 --- llvm/include/llvm/Target/MRegisterInfo.h:1.15 Sat Dec 28 14:10:23 2002 +++ llvm/include/llvm/Target/MRegisterInfo.h Mon Jan 6 12:28:20 2003 @@ -33,6 +33,7 @@ /// namespace MRF { // MRF = Machine Register Flags enum { + Other = 0 << 0, // This is a non-standard register INT8 = 1 << 0, // This is an 8 bit integer register INT16 = 1 << 1, // This is a 16 bit integer register INT32 = 1 << 2, // This is a 32 bit integer register @@ -171,6 +172,12 @@ /// const unsigned *getAliasSet(unsigned RegNo) const { return get(RegNo).AliasSet; + } + + /// getName - Return the symbolic target specific name for the specified + /// physical register. + const char *getName(unsigned RegNo) const { + return get(RegNo).Name; } virtual const unsigned* getCalleeSaveRegs() const = 0; From lattner at cs.uiuc.edu Mon Jan 6 12:31:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:31:01 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/Target/TargetMachine.h Message-ID: <200301061830.MAA26401@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/Target: TargetMachine.h updated: 1.28 -> 1.29 --- Log message: Rename MachineInstrInfo to TargetInstrInfo --- Diffs of the changes: Index: llvm/include/llvm/Target/TargetMachine.h diff -u llvm/include/llvm/Target/TargetMachine.h:1.28 llvm/include/llvm/Target/TargetMachine.h:1.29 --- llvm/include/llvm/Target/TargetMachine.h:1.28 Sat Dec 28 21:12:54 2002 +++ llvm/include/llvm/Target/TargetMachine.h Mon Jan 6 12:30:12 2003 @@ -10,8 +10,8 @@ #include "llvm/Target/TargetData.h" #include "Support/NonCopyable.h" -class MachineInstrInfo; -class MachineInstrDescriptor; +class TargetInstrInfo; +class TargetInstrDescriptor; class TargetSchedInfo; class TargetRegInfo; class TargetFrameInfo; @@ -56,7 +56,7 @@ // -- Cache hierarchy information // -- Machine-level optimization information (peephole only) // - virtual const MachineInstrInfo& getInstrInfo() const = 0; + virtual const TargetInstrInfo& getInstrInfo() const = 0; virtual const TargetSchedInfo& getSchedInfo() const = 0; virtual const TargetRegInfo& getRegInfo() const = 0; virtual const TargetFrameInfo& getFrameInfo() const = 0; From lattner at cs.uiuc.edu Mon Jan 6 12:31:02 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:31:02 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/Target/MachineInstrInfo.h Message-ID: <200301061830.MAA26408@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/Target: MachineInstrInfo.h updated: 1.40 -> 1.41 --- Log message: * Rename MachineInstrInfo to TargetInstrInfo. Add backwards compatibility typedefs until we convert over all the way * Add new M_TERMINATOR_FLAG flag --- Diffs of the changes: Index: llvm/include/llvm/Target/MachineInstrInfo.h diff -u llvm/include/llvm/Target/MachineInstrInfo.h:1.40 llvm/include/llvm/Target/MachineInstrInfo.h:1.41 --- llvm/include/llvm/Target/MachineInstrInfo.h:1.40 Sat Dec 28 14:12:54 2002 +++ llvm/include/llvm/Target/MachineInstrInfo.h Mon Jan 6 12:29:50 2003 @@ -1,4 +1,4 @@ -//===-- llvm/Target/MachineInstrInstrInfo.h - Instruction Infor ---*-C++-*-===// +//===-- llvm/Target/TargetInstrInfo.h - Instruction Info --------*- C++ -*-===// // // This file describes the target machine instructions to the code generator. // @@ -10,7 +10,6 @@ #include "Support/DataTypes.h" #include -class MachineInstrDescriptor; class MachineInstr; class TargetMachine; class Value; @@ -39,25 +38,31 @@ // //--------------------------------------------------------------------------- -const unsigned M_NOP_FLAG = 1 << 0; -const unsigned M_BRANCH_FLAG = 1 << 1; -const unsigned M_CALL_FLAG = 1 << 2; -const unsigned M_RET_FLAG = 1 << 3; -const unsigned M_ARITH_FLAG = 1 << 4; -const unsigned M_CC_FLAG = 1 << 6; -const unsigned M_LOGICAL_FLAG = 1 << 6; -const unsigned M_INT_FLAG = 1 << 7; -const unsigned M_FLOAT_FLAG = 1 << 8; -const unsigned M_CONDL_FLAG = 1 << 9; -const unsigned M_LOAD_FLAG = 1 << 10; -const unsigned M_PREFETCH_FLAG = 1 << 11; -const unsigned M_STORE_FLAG = 1 << 12; -const unsigned M_DUMMY_PHI_FLAG = 1 << 13; -const unsigned M_PSEUDO_FLAG = 1 << 14; // Pseudo instruction +const unsigned M_NOP_FLAG = 1 << 0; +const unsigned M_BRANCH_FLAG = 1 << 1; +const unsigned M_CALL_FLAG = 1 << 2; +const unsigned M_RET_FLAG = 1 << 3; +const unsigned M_ARITH_FLAG = 1 << 4; +const unsigned M_CC_FLAG = 1 << 6; +const unsigned M_LOGICAL_FLAG = 1 << 6; +const unsigned M_INT_FLAG = 1 << 7; +const unsigned M_FLOAT_FLAG = 1 << 8; +const unsigned M_CONDL_FLAG = 1 << 9; +const unsigned M_LOAD_FLAG = 1 << 10; +const unsigned M_PREFETCH_FLAG = 1 << 11; +const unsigned M_STORE_FLAG = 1 << 12; +const unsigned M_DUMMY_PHI_FLAG = 1 << 13; +const unsigned M_PSEUDO_FLAG = 1 << 14; // Pseudo instruction // 3-addr instructions which really work like 2-addr ones, eg. X86 add/sub -const unsigned M_2_ADDR_FLAG = 1 << 15; +const unsigned M_2_ADDR_FLAG = 1 << 15; -struct MachineInstrDescriptor { +// M_TERMINATOR_FLAG - Is this instruction part of the terminator for a basic +// block? Typically this is things like return and branch instructions. +// Various passes use this to insert code into the bottom of a basic block, but +// before control flow occurs. +const unsigned M_TERMINATOR_FLAG = 1 << 16; + +struct TargetInstrDescriptor { const char * Name; // Assembly language mnemonic for the opcode. int numOperands; // Number of args; -1 if variable #args int resultPos; // Position of the result; -1 if no result @@ -73,18 +78,19 @@ const unsigned *ImplicitDefs; // Registers implicitly defined by this instr }; +typedef TargetInstrDescriptor MachineInstrDescriptor; -class MachineInstrInfo { - const MachineInstrDescriptor* desc; // raw array to allow static init'n - unsigned descSize; // number of entries in the desc array - unsigned numRealOpCodes; // number of non-dummy op codes +class TargetInstrInfo { + const TargetInstrDescriptor* desc; // raw array to allow static init'n + unsigned descSize; // number of entries in the desc array + unsigned numRealOpCodes; // number of non-dummy op codes - MachineInstrInfo(const MachineInstrInfo &); // DO NOT IMPLEMENT - void operator=(const MachineInstrInfo &); // DO NOT IMPLEMENT + TargetInstrInfo(const TargetInstrInfo &); // DO NOT IMPLEMENT + void operator=(const TargetInstrInfo &); // DO NOT IMPLEMENT public: - MachineInstrInfo(const MachineInstrDescriptor *desc, unsigned descSize, - unsigned numRealOpCodes); - virtual ~MachineInstrInfo(); + TargetInstrInfo(const TargetInstrDescriptor *desc, unsigned descSize, + unsigned numRealOpCodes); + virtual ~TargetInstrInfo(); // Invariant: All instruction sets use opcode #0 as the PHI instruction and // opcode #1 as the noop instruction. @@ -98,7 +104,7 @@ /// get - Return the machine instruction descriptor that corresponds to the /// specified instruction opcode. /// - const MachineInstrDescriptor& get(MachineOpCode opCode) const { + const TargetInstrDescriptor& get(MachineOpCode opCode) const { assert(opCode >= 0 && opCode < (int)descSize); return desc[opCode]; } @@ -187,15 +193,18 @@ || get(opCode).Flags & M_PREFETCH_FLAG || get(opCode).Flags & M_STORE_FLAG; } - bool isDummyPhiInstr(const MachineOpCode opCode) const { + bool isDummyPhiInstr(MachineOpCode opCode) const { return get(opCode).Flags & M_DUMMY_PHI_FLAG; } - bool isPseudoInstr(const MachineOpCode opCode) const { + bool isPseudoInstr(MachineOpCode opCode) const { return get(opCode).Flags & M_PSEUDO_FLAG; } - bool isTwoAddrInstr(const MachineOpCode opCode) const { + bool isTwoAddrInstr(MachineOpCode opCode) const { return get(opCode).Flags & M_2_ADDR_FLAG; } + bool isTerminatorInstr(unsigned Opcode) const { + return get(Opcode).Flags & M_TERMINATOR_FLAG; + } // Check if an instruction can be issued before its operands are ready, // or if a subsequent instruction that uses its result can be issued @@ -371,5 +380,7 @@ abort(); } }; + +typedef TargetInstrInfo MachineInstrInfo; #endif From lattner at cs.uiuc.edu Mon Jan 6 12:33:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:33:01 2003 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/MachineFunction.cpp Message-ID: <200301061832.MAA26435@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: MachineFunction.cpp updated: 1.36 -> 1.37 --- Log message: Add support for constant pool --- Diffs of the changes: Index: llvm/lib/CodeGen/MachineFunction.cpp diff -u llvm/lib/CodeGen/MachineFunction.cpp:1.36 llvm/lib/CodeGen/MachineFunction.cpp:1.37 --- llvm/lib/CodeGen/MachineFunction.cpp:1.36 Sat Dec 28 20:50:27 2002 +++ llvm/lib/CodeGen/MachineFunction.cpp Mon Jan 6 12:32:01 2003 @@ -12,6 +12,7 @@ #include "llvm/CodeGen/SSARegMap.h" #include "llvm/CodeGen/MachineFunctionInfo.h" #include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetFrameInfo.h" #include "llvm/Target/TargetCacheInfo.h" @@ -102,12 +103,14 @@ SSARegMapping = new SSARegMap(); MFInfo = new MachineFunctionInfo(*this); FrameInfo = new MachineFrameInfo(); + ConstantPool = new MachineConstantPool(); } MachineFunction::~MachineFunction() { delete SSARegMapping; delete MFInfo; delete FrameInfo; + delete ConstantPool; } void MachineFunction::dump() const { print(std::cerr); } @@ -118,6 +121,9 @@ // Print Frame Information getFrameInfo()->print(OS); + + // Print Constant Pool + getConstantPool()->print(OS); for (const_iterator BB = begin(); BB != end(); ++BB) { BasicBlock *LBB = BB->getBasicBlock(); @@ -171,10 +177,21 @@ // MachineFrameInfo implementation //===----------------------------------------------------------------------===// +/// CreateStackObject - Create a stack object for a value of the specified type. +/// +int MachineFrameInfo::CreateStackObject(const Type *Ty, const TargetData &TD) { + return CreateStackObject(TD.getTypeSize(Ty), TD.getTypeAlignment(Ty)); +} + +int MachineFrameInfo::CreateStackObject(const TargetRegisterClass *RC) { + return CreateStackObject(RC->getSize(), RC->getAlignment()); +} + + void MachineFrameInfo::print(std::ostream &OS) const { for (unsigned i = 0, e = Objects.size(); i != e; ++i) { const StackObject &SO = Objects[i]; - OS << " is "; + OS << " is "; if (SO.Size == 0) OS << "variable sized"; else @@ -199,6 +216,17 @@ void MachineFrameInfo::dump() const { print(std::cerr); } + +//===----------------------------------------------------------------------===// +// MachineConstantPool implementation +//===----------------------------------------------------------------------===// + +void MachineConstantPool::print(std::ostream &OS) const { + for (unsigned i = 0, e = Constants.size(); i != e; ++i) + OS << " is" << *(Value*)Constants[i] << "\n"; +} + +void MachineConstantPool::dump() const { print(std::cerr); } //===----------------------------------------------------------------------===// // MachineFunctionInfo implementation From lattner at cs.uiuc.edu Mon Jan 6 12:33:02 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:33:02 2003 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/MachineCodeEmitter.cpp Message-ID: <200301061832.MAA26440@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: MachineCodeEmitter.cpp updated: 1.2 -> 1.3 --- Log message: Add support for new methods to debug impl --- Diffs of the changes: Index: llvm/lib/CodeGen/MachineCodeEmitter.cpp diff -u llvm/lib/CodeGen/MachineCodeEmitter.cpp:1.2 llvm/lib/CodeGen/MachineCodeEmitter.cpp:1.3 --- llvm/lib/CodeGen/MachineCodeEmitter.cpp:1.2 Wed Dec 4 00:44:41 2002 +++ llvm/lib/CodeGen/MachineCodeEmitter.cpp Mon Jan 6 12:31:44 2003 @@ -31,6 +31,9 @@ void emitGlobalAddress(GlobalValue *V) { std::cout << "getName() << ": 0xXX 0xXX 0xXX 0xXX> "; } + void emitFunctionConstantValueAddress(unsigned ConstantNum) { + std::cout << " "; + } }; } From lattner at cs.uiuc.edu Mon Jan 6 12:34:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:34:01 2003 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/PrologEpilogInserter.cpp Message-ID: <200301061833.MAA26462@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: PrologEpilogInserter.cpp updated: 1.3 -> 1.4 --- Log message: Convert to a MachineFunction pass --- Diffs of the changes: Index: llvm/lib/CodeGen/PrologEpilogInserter.cpp diff -u llvm/lib/CodeGen/PrologEpilogInserter.cpp:1.3 llvm/lib/CodeGen/PrologEpilogInserter.cpp:1.4 --- llvm/lib/CodeGen/PrologEpilogInserter.cpp:1.3 Sat Dec 28 15:08:26 2002 +++ llvm/lib/CodeGen/PrologEpilogInserter.cpp Mon Jan 6 12:33:14 2003 @@ -9,8 +9,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Pass.h" -#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/Target/TargetMachine.h" @@ -19,9 +19,9 @@ #include "llvm/Target/MachineInstrInfo.h" namespace { - struct PEI : public FunctionPass { - bool runOnFunction(Function &Fn) { - return runOnMachineFunction(MachineFunction::get(&Fn)); + struct PEI : public MachineFunctionPass { + const char *getPassName() const { + return "Prolog/Epilog Insertion & Frame Finalization"; } /// runOnMachineFunction - Insert prolog/epilog code and replace abstract @@ -141,8 +141,7 @@ // stack slots for them. std::vector StackSlots; for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) { - const TargetRegisterClass *RC = RegInfo->getRegClass(RegsToSave[i]); - int FrameIdx = FFI->CreateStackObject(RC->getSize(), RC->getAlignment()); + int FrameIdx = FFI->CreateStackObject(RegInfo->getRegClass(RegsToSave[i])); StackSlots.push_back(FrameIdx); } From lattner at cs.uiuc.edu Mon Jan 6 12:34:02 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:34:02 2003 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/MachineInstr.cpp Message-ID: <200301061833.MAA26451@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: MachineInstr.cpp updated: 1.67 -> 1.68 --- Log message: Add support for constant pool --- Diffs of the changes: Index: llvm/lib/CodeGen/MachineInstr.cpp diff -u llvm/lib/CodeGen/MachineInstr.cpp:1.67 llvm/lib/CodeGen/MachineInstr.cpp:1.68 --- llvm/lib/CodeGen/MachineInstr.cpp:1.67 Sat Dec 28 14:37:37 2002 +++ llvm/lib/CodeGen/MachineInstr.cpp Mon Jan 6 12:32:50 2003 @@ -268,6 +268,9 @@ case MachineOperand::MO_FrameIndex: OS << ""; break; + case MachineOperand::MO_ConstantPoolIndex: + OS << ""; + break; default: assert(0 && "Unrecognized operand type"); } @@ -316,26 +319,26 @@ } -std::ostream &operator<<(std::ostream& os, const MachineInstr& minstr) +std::ostream &operator<<(std::ostream& os, const MachineInstr& MI) { - os << TargetInstrDescriptors[minstr.opCode].Name; + os << TargetInstrDescriptors[MI.opCode].Name; - for (unsigned i=0, N=minstr.getNumOperands(); i < N; i++) { - os << "\t" << minstr.getOperand(i); - if( minstr.operandIsDefined(i) ) - os << "*"; - if( minstr.operandIsDefinedAndUsed(i) ) - os << "*"; + for (unsigned i=0, N=MI.getNumOperands(); i < N; i++) { + os << "\t" << MI.getOperand(i); + if (MI.operandIsDefined(i)) + os << ""; + if (MI.operandIsDefinedAndUsed(i)) + os << ""; } // code for printing implict references - unsigned NumOfImpRefs = minstr.getNumImplicitRefs(); - if( NumOfImpRefs > 0 ) { + unsigned NumOfImpRefs = MI.getNumImplicitRefs(); + if (NumOfImpRefs > 0) { os << "\tImplicit: "; - for(unsigned z=0; z < NumOfImpRefs; z++) { - OutputValue(os, minstr.getImplicitRef(z)); - if( minstr.implicitRefIsDefined(z)) os << "*"; - if( minstr.implicitRefIsDefinedAndUsed(z)) os << "*"; + for (unsigned z=0; z < NumOfImpRefs; z++) { + OutputValue(os, MI.getImplicitRef(z)); + if (MI.implicitRefIsDefined(z)) os << ""; + if (MI.implicitRefIsDefinedAndUsed(z)) os << ""; os << "\t"; } } @@ -357,11 +360,13 @@ switch (MO.getType()) { case MachineOperand::MO_VirtualRegister: - OS << "%reg"; - OutputValue(OS, MO.getVRegValue()); - if (MO.hasAllocatedReg()) { - OS << "=="; + if (MO.hasAllocatedReg()) OutputReg(OS, MO.getAllocatedRegNum()); + + if (MO.getVRegValue()) { + if (MO.hasAllocatedReg()) OS << "=="; + OS << "%vreg"; + OutputValue(OS, MO.getVRegValue()); } break; case MachineOperand::MO_CCRegister: @@ -400,6 +405,9 @@ break; case MachineOperand::MO_FrameIndex: OS << ""; + break; + case MachineOperand::MO_ConstantPoolIndex: + OS << ""; break; default: assert(0 && "Unrecognized operand type"); From lattner at cs.uiuc.edu Mon Jan 6 12:43:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:43:00 2003 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/RegAllocSimple.cpp Message-ID: <200301061842.MAA26492@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: RegAllocSimple.cpp updated: 1.36 -> 1.37 --- Log message: * Use the Phi Elimination pass --- Diffs of the changes: Index: llvm/lib/CodeGen/RegAllocSimple.cpp diff -u llvm/lib/CodeGen/RegAllocSimple.cpp:1.36 llvm/lib/CodeGen/RegAllocSimple.cpp:1.37 --- llvm/lib/CodeGen/RegAllocSimple.cpp:1.36 Sat Dec 28 15:08:26 2002 +++ llvm/lib/CodeGen/RegAllocSimple.cpp Mon Jan 6 12:42:06 2003 @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/SSARegMap.h" @@ -46,14 +47,14 @@ /// runOnMachineFunction - Register allocate the whole function bool runOnMachineFunction(MachineFunction &Fn); + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequiredID(PHIEliminationID); // Eliminate PHI nodes + MachineFunctionPass::getAnalysisUsage(AU); + } private: /// AllocateBasicBlock - Register allocate the specified basic block. void AllocateBasicBlock(MachineBasicBlock &MBB); - /// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions - /// in predecessor basic blocks. - void EliminatePHINodes(MachineBasicBlock &MBB); - /// getStackSpaceFor - This returns the offset of the specified virtual /// register on the stack, allocating space if neccesary. int getStackSpaceFor(unsigned VirtReg, const TargetRegisterClass *RC); @@ -88,8 +89,7 @@ return I->second; // Already has space allocated? // Allocate a new stack object for this spill location... - int FrameIdx = - MF->getFrameInfo()->CreateStackObject(RC->getSize(), RC->getAlignment()); + int FrameIdx = MF->getFrameInfo()->CreateStackObject(RC); // Assign the slot... StackSlotForVirtReg.insert(I, std::make_pair(VirtReg, FrameIdx)); @@ -137,74 +137,6 @@ } -/// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions in -/// predecessor basic blocks. -/// -void RegAllocSimple::EliminatePHINodes(MachineBasicBlock &MBB) { - const MachineInstrInfo &MII = TM->getInstrInfo(); - - while (MBB.front()->getOpcode() == MachineInstrInfo::PHI) { - MachineInstr *MI = MBB.front(); - // Unlink the PHI node from the basic block... but don't delete the PHI yet - MBB.erase(MBB.begin()); - - DEBUG(std::cerr << "num ops: " << MI->getNumOperands() << "\n"); - assert(MI->getOperand(0).isVirtualRegister() && - "PHI node doesn't write virt reg?"); - - unsigned virtualReg = MI->getOperand(0).getAllocatedRegNum(); - - for (int i = MI->getNumOperands() - 1; i >= 2; i-=2) { - MachineOperand &opVal = MI->getOperand(i-1); - - // Get the MachineBasicBlock equivalent of the BasicBlock that is the - // source path the phi - MachineBasicBlock &opBlock = *MI->getOperand(i).getMachineBasicBlock(); - - // Check to make sure we haven't already emitted the copy for this block. - // This can happen because PHI nodes may have multiple entries for the - // same basic block. It doesn't matter which entry we use though, because - // all incoming values are guaranteed to be the same for a particular bb. - // - // Note that this is N^2 in the number of phi node entries, but since the - // # of entries is tiny, this is not a problem. - // - bool HaveNotEmitted = true; - for (int op = MI->getNumOperands() - 1; op != i; op -= 2) - if (&opBlock == MI->getOperand(op).getMachineBasicBlock()) { - HaveNotEmitted = false; - break; - } - - if (HaveNotEmitted) { - MachineBasicBlock::iterator opI = opBlock.end(); - MachineInstr *opMI = *--opI; - - // must backtrack over ALL the branches in the previous block - while (MII.isBranch(opMI->getOpcode()) && opI != opBlock.begin()) - opMI = *--opI; - - // move back to the first branch instruction so new instructions - // are inserted right in front of it and not in front of a non-branch - // - if (!MII.isBranch(opMI->getOpcode())) - ++opI; - - const TargetRegisterClass *RC = - MF->getSSARegMap()->getRegClass(virtualReg); - - assert(opVal.isVirtualRegister() && - "Machine PHI Operands must all be virtual registers!"); - RegInfo->copyRegToReg(opBlock, opI, virtualReg, opVal.getReg(), RC); - } - } - - // really delete the PHI instruction now! - delete MI; - } -} - - void RegAllocSimple::AllocateBasicBlock(MachineBasicBlock &MBB) { // loop over each instruction for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) { @@ -280,12 +212,6 @@ MF = &Fn; TM = &MF->getTarget(); RegInfo = TM->getRegisterInfo(); - - // First pass: eliminate PHI instructions by inserting copies into predecessor - // blocks. - for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); - MBB != MBBe; ++MBB) - EliminatePHINodes(*MBB); // Loop over all of the basic blocks, eliminating virtual register references for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); From lattner at cs.uiuc.edu Mon Jan 6 12:43:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:43:01 2003 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/RegAllocLocal.cpp Message-ID: <200301061842.MAA26497@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: RegAllocLocal.cpp updated: 1.10 -> 1.11 --- Log message: * Convert to use LiveVariable analysis * Convert to use PHIElimination pass * Don't spill values which have just been reloaded (big win reducing spills) * Add experimental support for eliminating spills before TwoAddress instructions. It currently is broken so it is #ifdef'd out. * Use new "is terminator" flag on instructions instead of looking for branches and returns explicitly. --- Diffs of the changes: Index: llvm/lib/CodeGen/RegAllocLocal.cpp diff -u llvm/lib/CodeGen/RegAllocLocal.cpp:1.10 llvm/lib/CodeGen/RegAllocLocal.cpp:1.11 --- llvm/lib/CodeGen/RegAllocLocal.cpp:1.10 Sat Dec 28 15:08:26 2002 +++ llvm/lib/CodeGen/RegAllocLocal.cpp Mon Jan 6 12:41:37 2003 @@ -5,16 +5,17 @@ // //===----------------------------------------------------------------------===// +#include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/SSARegMap.h" #include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/LiveVariables.h" #include "llvm/Target/MachineInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include "Support/Statistic.h" #include "Support/CommandLine.h" #include -#include namespace { Statistic<> NumSpilled ("ra-local", "Number of registers spilled"); @@ -26,6 +27,7 @@ const TargetMachine *TM; MachineFunction *MF; const MRegisterInfo *RegInfo; + LiveVariables *LV; // StackSlotForVirtReg - Maps SSA Regs => frame index where these values are // spilled @@ -54,12 +56,26 @@ // std::vector PhysRegsUseOrder; - // LastUserOf map - This multimap contains the set of registers that each - // key instruction is the last user of. If an instruction has an entry in - // this map, that means that the specified operands are killed after the - // instruction is executed, thus they don't need to be spilled into memory + // VirtRegModified - This bitset contains information about which virtual + // registers need to be spilled back to memory when their registers are + // scavenged. If a virtual register has simply been rematerialized, there + // is no reason to spill it to memory when we need the register back. // - std::multimap LastUserOf; + std::vector VirtRegModified; + + void markVirtRegModified(unsigned Reg, bool Val = true) { + assert(Reg >= MRegisterInfo::FirstVirtualRegister && "Illegal VirtReg!"); + Reg -= MRegisterInfo::FirstVirtualRegister; + if (VirtRegModified.size() <= Reg) VirtRegModified.resize(Reg+1); + VirtRegModified[Reg] = Val; + } + + bool isVirtRegModified(unsigned Reg) const { + assert(Reg >= MRegisterInfo::FirstVirtualRegister && "Illegal VirtReg!"); + assert(Reg - MRegisterInfo::FirstVirtualRegister < VirtRegModified.size() + && "Illegal virtual register!"); + return VirtRegModified[Reg - MRegisterInfo::FirstVirtualRegister]; + } void MarkPhysRegRecentlyUsed(unsigned Reg) { assert(!PhysRegsUseOrder.empty() && "No registers used!"); @@ -81,6 +97,13 @@ return "Local Register Allocator"; } + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + if (!DisableKill) + AU.addRequired(); + AU.addRequiredID(PHIEliminationID); + MachineFunctionPass::getAnalysisUsage(AU); + } + private: /// runOnMachineFunction - Register allocate the whole function bool runOnMachineFunction(MachineFunction &Fn); @@ -88,19 +111,6 @@ /// AllocateBasicBlock - Register allocate the specified basic block. void AllocateBasicBlock(MachineBasicBlock &MBB); - /// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions - /// in predecessor basic blocks. - void EliminatePHINodes(MachineBasicBlock &MBB); - - /// CalculateLastUseOfVReg - Calculate an approximation of the killing - /// uses for the virtual registers in the function. Here we try to capture - /// registers that are defined and only used within the same basic block. - /// Because we don't have use-def chains yet, we have to do this the hard - /// way. - /// - void CalculateLastUseOfVReg(MachineBasicBlock &MBB, - std::map &LastUseOfVReg) const; - /// areRegsEqual - This method returns true if the specified registers are /// related to each other. To do this, it checks to see if they are equal @@ -129,39 +139,41 @@ /// spillPhysReg - This method spills the specified physical register into /// the virtual register slot associated with it. - // + /// void spillPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, - unsigned PhysReg) { - std::map::iterator PI = PhysRegsUsed.find(PhysReg); - if (PI != PhysRegsUsed.end()) { // Only spill it if it's used! - spillVirtReg(MBB, I, PI->second, PhysReg); - } else if (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg)) { - // If the selected register aliases any other registers, we must make - // sure that one of the aliases isn't alive... - for (unsigned i = 0; AliasSet[i]; ++i) { - PI = PhysRegsUsed.find(AliasSet[i]); - if (PI != PhysRegsUsed.end()) // Spill aliased register... - spillVirtReg(MBB, I, PI->second, AliasSet[i]); - } - } - } + unsigned PhysReg); + + /// assignVirtToPhysReg - This method updates local state so that we know + /// that PhysReg is the proper container for VirtReg now. The physical + /// register must not be used for anything else when this is called. + /// + void assignVirtToPhysReg(unsigned VirtReg, unsigned PhysReg); - void AssignVirtToPhysReg(unsigned VirtReg, unsigned PhysReg); + /// liberatePhysReg - Make sure the specified physical register is available + /// for use. If there is currently a value in it, it is either moved out of + /// the way or spilled to memory. + /// + void liberatePhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, + unsigned PhysReg); /// isPhysRegAvailable - Return true if the specified physical register is /// free and available for use. This also includes checking to see if /// aliased registers are all free... /// bool isPhysRegAvailable(unsigned PhysReg) const; + + /// getFreeReg - Look to see if there is a free register available in the + /// specified register class. If not, return 0. + /// + unsigned getFreeReg(const TargetRegisterClass *RC); - /// getFreeReg - Find a physical register to hold the specified virtual + /// getReg - Find a physical register to hold the specified virtual /// register. If all compatible physical registers are used, this method /// spills the last used virtual register to the stack, and uses that /// register. /// - unsigned getFreeReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &I, - unsigned virtualReg); + unsigned getReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, + unsigned VirtReg); /// reloadVirtReg - This method loads the specified virtual register into a /// physical register, returning the physical register chosen. This updates @@ -186,8 +198,7 @@ return I->second; // Already has space allocated? // Allocate a new stack object for this spill location... - int FrameIdx = - MF->getFrameInfo()->CreateStackObject(RC->getSize(), RC->getAlignment()); + int FrameIdx = MF->getFrameInfo()->CreateStackObject(RC); // Assign the slot... StackSlotForVirtReg.insert(I, std::make_pair(VirtReg, FrameIdx)); @@ -208,6 +219,7 @@ PhysRegsUseOrder.erase(It); } + /// spillVirtReg - This method spills the value specified by PhysReg into the /// virtual register slot specified by VirtReg. It then updates the RA data /// structures to indicate the fact that PhysReg is now available. @@ -220,9 +232,12 @@ MF->getSSARegMap()->getRegClass(VirtReg); int FrameIndex = getStackSpaceFor(VirtReg, RegClass); - // Add move instruction(s) - RegInfo->storeRegToStackSlot(MBB, I, PhysReg, FrameIndex, RegClass); - ++NumSpilled; // Update statistics + // If we need to spill this value, do so now... + if (isVirtRegModified(VirtReg)) { + // Add move instruction(s) + RegInfo->storeRegToStackSlot(MBB, I, PhysReg, FrameIndex, RegClass); + ++NumSpilled; // Update statistics + } Virt2PhysRegMap.erase(VirtReg); // VirtReg no longer available } @@ -230,6 +245,41 @@ } +/// spillPhysReg - This method spills the specified physical register into the +/// virtual register slot associated with it. +/// +void RA::spillPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, + unsigned PhysReg) { + std::map::iterator PI = PhysRegsUsed.find(PhysReg); + if (PI != PhysRegsUsed.end()) { // Only spill it if it's used! + spillVirtReg(MBB, I, PI->second, PhysReg); + } else if (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg)) { + // If the selected register aliases any other registers, we must make + // sure that one of the aliases isn't alive... + for (unsigned i = 0; AliasSet[i]; ++i) { + PI = PhysRegsUsed.find(AliasSet[i]); + if (PI != PhysRegsUsed.end()) // Spill aliased register... + spillVirtReg(MBB, I, PI->second, AliasSet[i]); + } + } +} + + +/// assignVirtToPhysReg - This method updates local state so that we know +/// that PhysReg is the proper container for VirtReg now. The physical +/// register must not be used for anything else when this is called. +/// +void RA::assignVirtToPhysReg(unsigned VirtReg, unsigned PhysReg) { + assert(PhysRegsUsed.find(PhysReg) == PhysRegsUsed.end() && + "Phys reg already assigned!"); + // Update information to note the fact that this register was just used, and + // it holds VirtReg. + PhysRegsUsed[PhysReg] = VirtReg; + Virt2PhysRegMap[VirtReg] = PhysReg; + PhysRegsUseOrder.push_back(PhysReg); // New use of PhysReg +} + + /// isPhysRegAvailable - Return true if the specified physical register is free /// and available for use. This also includes checking to see if aliased /// registers are all free... @@ -247,31 +297,77 @@ } - -/// getFreeReg - Find a physical register to hold the specified virtual -/// register. If all compatible physical registers are used, this method spills -/// the last used virtual register to the stack, and uses that register. +/// getFreeReg - Look to see if there is a free register available in the +/// specified register class. If not, return 0. /// -unsigned RA::getFreeReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, - unsigned VirtReg) { - const TargetRegisterClass *RC = MF->getSSARegMap()->getRegClass(VirtReg); - +unsigned RA::getFreeReg(const TargetRegisterClass *RC) { // Get iterators defining the range of registers that are valid to allocate in // this class, which also specifies the preferred allocation order. TargetRegisterClass::iterator RI = RC->allocation_order_begin(*MF); TargetRegisterClass::iterator RE = RC->allocation_order_end(*MF); - // First check to see if we have a free register of the requested type... - unsigned PhysReg = 0; - for (; RI != RE; ++RI) { - unsigned R = *RI; - if (isPhysRegAvailable(R)) { // Is reg unused? - // Found an unused register! - PhysReg = R; - assert(PhysReg != 0 && "Cannot use register!"); - break; + for (; RI != RE; ++RI) + if (isPhysRegAvailable(*RI)) { // Is reg unused? + assert(*RI != 0 && "Cannot use register!"); + return *RI; // Found an unused register! + } + return 0; +} + + +/// liberatePhysReg - Make sure the specified physical register is available for +/// use. If there is currently a value in it, it is either moved out of the way +/// or spilled to memory. +/// +void RA::liberatePhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, + unsigned PhysReg) { + // FIXME: This code checks to see if a register is available, but it really + // wants to know if a reg is available BEFORE the instruction executes. If + // called after killed operands are freed, it runs the risk of reallocating a + // used operand... +#if 0 + if (isPhysRegAvailable(PhysReg)) return; // Already available... + + // Check to see if the register is directly used, not indirectly used through + // aliases. If aliased registers are the ones actually used, we cannot be + // sure that we will be able to save the whole thing if we do a reg-reg copy. + std::map::iterator PRUI = PhysRegsUsed.find(PhysReg); + if (PRUI != PhysRegsUsed.end()) { + unsigned VirtReg = PRUI->second; // The virtual register held... + + // Check to see if there is a compatible register available. If so, we can + // move the value into the new register... + // + const TargetRegisterClass *RC = RegInfo->getRegClass(PhysReg); + if (unsigned NewReg = getFreeReg(RC)) { + // Emit the code to copy the value... + RegInfo->copyRegToReg(MBB, I, NewReg, PhysReg, RC); + + // Update our internal state to indicate that PhysReg is available and Reg + // isn't. + Virt2PhysRegMap.erase(VirtReg); + removePhysReg(PhysReg); // Free the physreg + + // Move reference over to new register... + assignVirtToPhysReg(VirtReg, NewReg); + return; } } +#endif + spillPhysReg(MBB, I, PhysReg); +} + + +/// getReg - Find a physical register to hold the specified virtual +/// register. If all compatible physical registers are used, this method spills +/// the last used virtual register to the stack, and uses that register. +/// +unsigned RA::getReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, + unsigned VirtReg) { + const TargetRegisterClass *RC = MF->getSSARegMap()->getRegClass(VirtReg); + + // First check to see if we have a free register of the requested type... + unsigned PhysReg = getFreeReg(RC); // If we didn't find an unused register, scavenge one now! if (PhysReg == 0) { @@ -309,22 +405,11 @@ } // Now that we know which register we need to assign this to, do it now! - AssignVirtToPhysReg(VirtReg, PhysReg); + assignVirtToPhysReg(VirtReg, PhysReg); return PhysReg; } -void RA::AssignVirtToPhysReg(unsigned VirtReg, unsigned PhysReg) { - assert(PhysRegsUsed.find(PhysReg) == PhysRegsUsed.end() && - "Phys reg already assigned!"); - // Update information to note the fact that this register was just used, and - // it holds VirtReg. - PhysRegsUsed[PhysReg] = VirtReg; - Virt2PhysRegMap[VirtReg] = PhysReg; - PhysRegsUseOrder.push_back(PhysReg); // New use of PhysReg -} - - /// reloadVirtReg - This method loads the specified virtual register into a /// physical register, returning the physical register chosen. This updates the /// regalloc data structures to reflect the fact that the virtual reg is now @@ -339,148 +424,87 @@ return It->second; // Already have this value available! } - unsigned PhysReg = getFreeReg(MBB, I, VirtReg); + unsigned PhysReg = getReg(MBB, I, VirtReg); const TargetRegisterClass *RC = MF->getSSARegMap()->getRegClass(VirtReg); int FrameIndex = getStackSpaceFor(VirtReg, RC); + markVirtRegModified(VirtReg, false); // Note that this reg was just reloaded + // Add move instruction(s) RegInfo->loadRegFromStackSlot(MBB, I, PhysReg, FrameIndex, RC); ++NumReloaded; // Update statistics return PhysReg; } -/// CalculateLastUseOfVReg - Calculate an approximation of the killing uses for -/// the virtual registers in the function. Here we try to capture registers -/// that are defined and only used within the same basic block. Because we -/// don't have use-def chains yet, we have to do this the hard way. -/// -void RA::CalculateLastUseOfVReg(MachineBasicBlock &MBB, - std::map &LastUseOfVReg) const { - // Calculate the last machine instruction in this basic block that uses the - // specified virtual register defined in this basic block. - std::map LastLocalUses; - - for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;++I){ +void RA::AllocateBasicBlock(MachineBasicBlock &MBB) { + // loop over each instruction + MachineBasicBlock::iterator I = MBB.begin(); + for (; I != MBB.end(); ++I) { MachineInstr *MI = *I; - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { - MachineOperand &Op = MI->getOperand(i); - if (Op.isVirtualRegister()) { - if (Op.opIsDef()) { // Definition of a new virtual reg? - LastLocalUses[Op.getAllocatedRegNum()] = 0; // Record it - } else { // Use of a virtual reg. - std::map::iterator It = - LastLocalUses.find(Op.getAllocatedRegNum()); - if (It != LastLocalUses.end()) // Local use? - It->second = MI; // Update last use - else - LastUseOfVReg[Op.getAllocatedRegNum()] = 0; - } - } - } - } - - // Move local uses over... if there are any uses of a local already in the - // lastuse map, the newly inserted entry is ignored. - LastUseOfVReg.insert(LastLocalUses.begin(), LastLocalUses.end()); -} - - -/// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions in -/// predecessor basic blocks. -/// -void RA::EliminatePHINodes(MachineBasicBlock &MBB) { - const MachineInstrInfo &MII = TM->getInstrInfo(); + const MachineInstrDescriptor &MID = TM->getInstrInfo().get(MI->getOpcode()); - while (MBB.front()->getOpcode() == MachineInstrInfo::PHI) { - MachineInstr *MI = MBB.front(); - // Unlink the PHI node from the basic block... but don't delete the PHI yet - MBB.erase(MBB.begin()); - - assert(MI->getOperand(0).isVirtualRegister() && - "PHI node doesn't write virt reg?"); + // Loop over the implicit uses, making sure that they are at the head of the + // use order list, so they don't get reallocated. + if (const unsigned *ImplicitUses = MID.ImplicitUses) + for (unsigned i = 0; ImplicitUses[i]; ++i) + MarkPhysRegRecentlyUsed(ImplicitUses[i]); - unsigned virtualReg = MI->getOperand(0).getAllocatedRegNum(); + // Get the used operands into registers. This has the potiential to spill + // incoming values if we are out of registers. + // + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) + if (MI->getOperand(i).opIsUse() && + MI->getOperand(i).isVirtualRegister()) { + unsigned VirtSrcReg = MI->getOperand(i).getAllocatedRegNum(); + unsigned PhysSrcReg = reloadVirtReg(MBB, I, VirtSrcReg); + MI->SetMachineOperandReg(i, PhysSrcReg); // Assign the input register + } - for (int i = MI->getNumOperands() - 1; i >= 2; i-=2) { - MachineOperand &opVal = MI->getOperand(i-1); - - // Get the MachineBasicBlock equivalent of the BasicBlock that is the - // source path the phi - MachineBasicBlock &opBlock = *MI->getOperand(i).getMachineBasicBlock(); - - // Check to make sure we haven't already emitted the copy for this block. - // This can happen because PHI nodes may have multiple entries for the - // same basic block. It doesn't matter which entry we use though, because - // all incoming values are guaranteed to be the same for a particular bb. - // - // Note that this is N^2 in the number of phi node entries, but since the - // # of entries is tiny, this is not a problem. + if (!DisableKill) { + // If this instruction is the last user of anything in registers, kill the + // value, freeing the register being used, so it doesn't need to be + // spilled to memory. // - bool HaveNotEmitted = true; - for (int op = MI->getNumOperands() - 1; op != i; op -= 2) - if (&opBlock == MI->getOperand(op).getMachineBasicBlock()) { - HaveNotEmitted = false; - break; - } + for (LiveVariables::killed_iterator KI = LV->killed_begin(MI), + KE = LV->killed_end(MI); KI != KE; ++KI) { + unsigned VirtReg = KI->second; + unsigned PhysReg = VirtReg; + if (VirtReg >= MRegisterInfo::FirstVirtualRegister) { + std::map::iterator I = + Virt2PhysRegMap.find(VirtReg); + assert(I != Virt2PhysRegMap.end()); + PhysReg = I->second; + Virt2PhysRegMap.erase(I); + } - if (HaveNotEmitted) { - MachineBasicBlock::iterator opI = opBlock.end(); - MachineInstr *opMI = *--opI; - - // must backtrack over ALL the branches in the previous block - while (MII.isBranch(opMI->getOpcode()) && opI != opBlock.begin()) - opMI = *--opI; - - // move back to the first branch instruction so new instructions - // are inserted right in front of it and not in front of a non-branch - if (!MII.isBranch(opMI->getOpcode())) - ++opI; - - const TargetRegisterClass *RC = - MF->getSSARegMap()->getRegClass(virtualReg); - - assert(opVal.isVirtualRegister() && - "Machine PHI Operands must all be virtual registers!"); - RegInfo->copyRegToReg(opBlock, opI, virtualReg, opVal.getReg(), RC); + if (PhysReg) { + DEBUG(std::cout << "V: " << VirtReg << " P: " << PhysReg + << " Killed by: " << *MI); + removePhysReg(PhysReg); + } } } - - // really delete the PHI instruction now! - delete MI; - } -} - - -void RA::AllocateBasicBlock(MachineBasicBlock &MBB) { - // loop over each instruction - MachineBasicBlock::iterator I = MBB.begin(); - for (; I != MBB.end(); ++I) { - MachineInstr *MI = *I; - const MachineInstrDescriptor &MID = TM->getInstrInfo().get(MI->getOpcode()); // Loop over all of the operands of the instruction, spilling registers that // are defined, and marking explicit destinations in the PhysRegsUsed map. - - // FIXME: We don't need to spill a register if this is the last use of the - // value! for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) - if (MI->getOperand(i).opIsDef() && + if ((MI->getOperand(i).opIsDef() || MI->getOperand(i).opIsDefAndUse()) && MI->getOperand(i).isPhysicalRegister()) { unsigned Reg = MI->getOperand(i).getAllocatedRegNum(); - spillPhysReg(MBB, I, Reg); + spillPhysReg(MBB, I, Reg); // Spill any existing value in the reg PhysRegsUsed[Reg] = 0; // It is free and reserved now PhysRegsUseOrder.push_back(Reg); } - // Loop over the implicit defs, spilling them, as above. + // Loop over the implicit defs, spilling them as well. if (const unsigned *ImplicitDefs = MID.ImplicitDefs) for (unsigned i = 0; ImplicitDefs[i]; ++i) { unsigned Reg = ImplicitDefs[i]; // We don't want to spill implicit definitions if they were explicitly // chosen. For this reason, check to see now if the register we are - // to spill has a vreg of 0. + // to spill has a vreg of 0. FIXME: is this needed? if (PhysRegsUsed.count(Reg) && PhysRegsUsed[Reg] != 0) spillPhysReg(MBB, I, Reg); else if (PhysRegsUsed.count(Reg)) { @@ -491,35 +515,27 @@ PhysRegsUsed[Reg] = 0; // It is free and reserved now } - // Loop over the implicit uses, making sure that they are at the head of the - // use order list, so they don't get reallocated. - if (const unsigned *ImplicitUses = MID.ImplicitUses) - for (unsigned i = 0; ImplicitUses[i]; ++i) - MarkPhysRegRecentlyUsed(ImplicitUses[i]); - - // Loop over all of the operands again, getting the used operands into - // registers. This has the potiential to spill incoming values if we are - // out of registers. - // - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) - if (MI->getOperand(i).opIsUse() && - MI->getOperand(i).isVirtualRegister()) { - unsigned VirtSrcReg = MI->getOperand(i).getAllocatedRegNum(); - unsigned PhysSrcReg = reloadVirtReg(MBB, I, VirtSrcReg); - MI->SetMachineOperandReg(i, PhysSrcReg); // Assign the input register - } - // Okay, we have allocated all of the source operands and spilled any values // that would be destroyed by defs of this instruction. Loop over the - // implicit defs and assign them to a register, spilling the incoming value - // if we need to scavange a register. + // implicit defs and assign them to a register, spilling incoming values if + // we need to scavenge a register. // for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) if (MI->getOperand(i).opIsDef() && - !MI->getOperand(i).isPhysicalRegister()) { + MI->getOperand(i).isVirtualRegister()) { unsigned DestVirtReg = MI->getOperand(i).getAllocatedRegNum(); unsigned DestPhysReg; + // If DestVirtReg already has a value, forget about it. Why doesn't + // getReg do this right? + std::map::iterator DestI = + Virt2PhysRegMap.find(DestVirtReg); + if (DestI != Virt2PhysRegMap.end()) { + unsigned PhysReg = DestI->second; + Virt2PhysRegMap.erase(DestI); + removePhysReg(PhysReg); + } + if (TM->getInstrInfo().isTwoAddrInstr(MI->getOpcode()) && i == 0) { // must be same register number as the first operand // This maps a = b + c into b += c, and saves b into a's spot @@ -529,51 +545,56 @@ "Two address instruction invalid!"); DestPhysReg = MI->getOperand(1).getAllocatedRegNum(); - // Spill the incoming value, because we are about to change the - // register contents. - spillPhysReg(MBB, I, DestPhysReg); - AssignVirtToPhysReg(DestVirtReg, DestPhysReg); + liberatePhysReg(MBB, I, DestPhysReg); + assignVirtToPhysReg(DestVirtReg, DestPhysReg); } else { - DestPhysReg = getFreeReg(MBB, I, DestVirtReg); + DestPhysReg = getReg(MBB, I, DestVirtReg); } + markVirtRegModified(DestVirtReg); MI->SetMachineOperandReg(i, DestPhysReg); // Assign the output register } if (!DisableKill) { - // If this instruction is the last user of anything in registers, kill the - // value, freeing the register being used, so it doesn't need to be - // spilled to memory at the end of the block. - std::multimap::iterator LUOI = - LastUserOf.lower_bound(MI); - for (; LUOI != LastUserOf.end() && LUOI->first == MI; ++MI) { - unsigned VirtReg = LUOI->second; // entry found? - unsigned PhysReg = Virt2PhysRegMap[VirtReg]; - if (PhysReg) { - DEBUG(std::cout << "V: " << VirtReg << " P: " << PhysReg - << " Last use of: " << *MI); - removePhysReg(PhysReg); - } - Virt2PhysRegMap.erase(VirtReg); + // If this instruction defines any registers that are immediately dead, + // kill them now. + // + for (LiveVariables::killed_iterator KI = LV->dead_begin(MI), + KE = LV->dead_end(MI); KI != KE; ++KI) { + unsigned VirtReg = KI->second; + unsigned PhysReg = VirtReg; + if (VirtReg >= MRegisterInfo::FirstVirtualRegister) { + std::map::iterator I = + Virt2PhysRegMap.find(VirtReg); + assert(I != Virt2PhysRegMap.end()); + PhysReg = I->second; + Virt2PhysRegMap.erase(I); + } + + if (PhysReg) { + DEBUG(std::cout << "V: " << VirtReg << " P: " << PhysReg + << " dead after: " << *MI); + removePhysReg(PhysReg); + } } } } // Rewind the iterator to point to the first flow control instruction... const MachineInstrInfo &MII = TM->getInstrInfo(); - I = MBB.end(); - do { + I = MBB.end()-1; + while (I != MBB.begin() && MII.isTerminatorInstr((*(I-1))->getOpcode())) --I; - } while ((MII.isReturn((*I)->getOpcode()) || - MII.isBranch((*I)->getOpcode())) && I != MBB.begin()); - - if (!MII.isReturn((*I)->getOpcode()) && !MII.isBranch((*I)->getOpcode())) - ++I; // Spill all physical registers holding virtual registers now. while (!PhysRegsUsed.empty()) spillVirtReg(MBB, I, PhysRegsUsed.begin()->second, PhysRegsUsed.begin()->first); + for (std::map::iterator I = Virt2PhysRegMap.begin(), + E = Virt2PhysRegMap.end(); I != E; ++I) + std::cerr << "Register still mapped: " << I->first << " -> " + << I->second << "\n"; + assert(Virt2PhysRegMap.empty() && "Virtual registers still in phys regs?"); assert(PhysRegsUseOrder.empty() && "Physical regs still allocated?"); } @@ -587,38 +608,16 @@ TM = &Fn.getTarget(); RegInfo = TM->getRegisterInfo(); - // First pass: eliminate PHI instructions by inserting copies into predecessor - // blocks, and calculate a simple approximation of killing uses for virtual - // registers. - // - std::map LastUseOfVReg; - for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); - MBB != MBBe; ++MBB) { - if (!DisableKill) - CalculateLastUseOfVReg(*MBB, LastUseOfVReg); - EliminatePHINodes(*MBB); - } - - // At this point LastUseOfVReg has been filled in to contain the last - // MachineInstr user of the specified virtual register, if that user is - // within the same basic block as the definition (otherwise it contains - // null). Invert this mapping now: if (!DisableKill) - for (std::map::iterator I = LastUseOfVReg.begin(), - E = LastUseOfVReg.end(); I != E; ++I) - if (I->second) - LastUserOf.insert(std::make_pair(I->second, I->first)); - - // We're done with the temporary list now. - LastUseOfVReg.clear(); + LV = &getAnalysis(); // Loop over all of the basic blocks, eliminating virtual register references for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); MBB != MBBe; ++MBB) AllocateBasicBlock(*MBB); - LastUserOf.clear(); StackSlotForVirtReg.clear(); + VirtRegModified.clear(); return true; } From lattner at cs.uiuc.edu Mon Jan 6 12:43:03 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:43:03 2003 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/LiveVariables.cpp PHIElimination.cpp Message-ID: <200301061842.MAA26509@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: LiveVariables.cpp added (r1.1) PHIElimination.cpp added (r1.1) --- Log message: Initial checkin of LiveVariable analysis and PHI elimination passes --- Diffs of the changes: From lattner at cs.uiuc.edu Mon Jan 6 12:44:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:44:01 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/MachineInstrInfo.cpp Message-ID: <200301061843.MAA26522@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target: MachineInstrInfo.cpp updated: 1.5 -> 1.6 --- Log message: Start renaming MachineInstrInfo to TargetInstrInfo --- Diffs of the changes: Index: llvm/lib/Target/MachineInstrInfo.cpp diff -u llvm/lib/Target/MachineInstrInfo.cpp:1.5 llvm/lib/Target/MachineInstrInfo.cpp:1.6 --- llvm/lib/Target/MachineInstrInfo.cpp:1.5 Sun Nov 17 17:22:03 2002 +++ llvm/lib/Target/MachineInstrInfo.cpp Mon Jan 6 12:43:13 2003 @@ -1,4 +1,4 @@ -//===-- MachineInstrInfo.cpp - Target Instruction Information -------------===// +//===-- TargetInstrInfo.cpp - Target Instruction Information --------------===// // // //===----------------------------------------------------------------------===// @@ -12,34 +12,29 @@ // Initialized only when the TargetMachine class is created // and reset when that class is destroyed. // -const MachineInstrDescriptor* TargetInstrDescriptors = 0; +const TargetInstrDescriptor* TargetInstrDescriptors = 0; -//--------------------------------------------------------------------------- -// class MachineInstructionInfo -// Interface to description of machine instructions -//--------------------------------------------------------------------------- - -MachineInstrInfo::MachineInstrInfo(const MachineInstrDescriptor* Desc, - unsigned DescSize, - unsigned NumRealOpCodes) +TargetInstrInfo::TargetInstrInfo(const TargetInstrDescriptor* Desc, + unsigned DescSize, + unsigned NumRealOpCodes) : desc(Desc), descSize(DescSize), numRealOpCodes(NumRealOpCodes) { // FIXME: TargetInstrDescriptors should not be global assert(TargetInstrDescriptors == NULL && desc != NULL); TargetInstrDescriptors = desc; // initialize global variable } -MachineInstrInfo::~MachineInstrInfo() { +TargetInstrInfo::~TargetInstrInfo() { TargetInstrDescriptors = NULL; // reset global variable } -void MachineInstrInfo::print(const MachineInstr *MI, std::ostream &O, - const TargetMachine &TM) const { +void TargetInstrInfo::print(const MachineInstr *MI, std::ostream &O, + const TargetMachine &TM) const { MI->print(O, TM); } -bool MachineInstrInfo::constantFitsInImmedField(MachineOpCode opCode, - int64_t intValue) const { +bool TargetInstrInfo::constantFitsInImmedField(MachineOpCode opCode, + int64_t intValue) const { // First, check if opCode has an immed field. bool isSignExtended; uint64_t maxImmedValue = maxImmedConstant(opCode, isSignExtended); @@ -58,7 +53,7 @@ return false; } -bool MachineInstrInfo::ConstantTypeMustBeLoaded(const Constant* CV) const { +bool TargetInstrInfo::ConstantTypeMustBeLoaded(const Constant* CV) const { assert(CV->getType()->isPrimitiveType() || isa(CV->getType())); return !(CV->getType()->isIntegral() || isa(CV->getType())); } From lattner at cs.uiuc.edu Mon Jan 6 12:49:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:49:01 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200301061848.MAA26533@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.80 -> 1.81 --- Log message: * Adjust to use new interfaces, eliminating CurReg stuff * Support arbitrary FP constants * Fix bugs in frame layout for function calls and incoming arguments * Insert copies for constant arguments to PHI nodes into the BOTTOM of predecessor blocks, not the top. * Implement _floating point_ support: setcc, return, load, store, cast * Fix several bugs in the cast instruction --- Diffs of the changes: Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.80 llvm/lib/Target/X86/InstSelectSimple.cpp:1.81 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.80 Sat Dec 28 15:08:27 2002 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Mon Jan 6 12:47:54 2003 @@ -21,6 +21,7 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/SSARegMap.h" #include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Support/InstVisitor.h" #include "llvm/Target/MRegisterInfo.h" @@ -59,14 +60,12 @@ MachineFunction *F; // The function we are compiling into MachineBasicBlock *BB; // The current MBB we are compiling - unsigned CurReg; std::map RegMap; // Mapping between Val's and SSA Regs // MBBMap - Mapping between LLVM BB -> Machine BB std::map MBBMap; - ISel(TargetMachine &tm) - : TM(tm), F(0), BB(0), CurReg(MRegisterInfo::FirstVirtualRegister) {} + ISel(TargetMachine &tm) : TM(tm), F(0), BB(0) {} /// runOnFunction - Top level implementation of instruction selection for /// the entire function. @@ -89,7 +88,6 @@ RegMap.clear(); MBBMap.clear(); - CurReg = MRegisterInfo::FirstVirtualRegister; F = 0; return false; // We never modify the LLVM itself. } @@ -155,7 +153,9 @@ void visitSetGE(SetCondInst &I) { visitSetCCInst(I, 5); } // Memory Instructions + MachineInstr *doFPLoad(const Type *Ty, unsigned DestReg); void visitLoadInst(LoadInst &I); + void doFPStore(const Type *Ty, unsigned DestAddrReg, unsigned SrcReg); void visitStoreInst(StoreInst &I); void visitGetElementPtrInst(GetElementPtrInst &I); void visitAllocaInst(AllocaInst &I); @@ -198,8 +198,7 @@ // Add the mapping of regnumber => reg class to MachineFunction const TargetRegisterClass *RC = TM.getRegisterInfo()->getRegClassForType(Ty); - F->getSSARegMap()->addRegMap(CurReg, RC); - return CurReg++; + return F->getSSARegMap()->createVirtualRegister(RC); } /// getReg - This method turns an LLVM value into a register number. This @@ -316,8 +315,10 @@ else if (Value == +1.0) BMI(MBB, IP, X86::FLD1, 0, R); else { - std::cerr << "Cannot load constant '" << Value << "'!\n"; - assert(0); + // Otherwise we need to spill the constant to memory... + MachineConstantPool *CP = F->getConstantPool(); + unsigned CPI = CP->getConstantPoolIndex(CFP); + addConstantPoolReference(doFPLoad(CFP->getType(), R), CPI); } } else if (isa(C)) { @@ -344,15 +345,13 @@ // [ESP + 8] -- second argument, if four bytes in size // ... // - unsigned ArgOffset = 0; + unsigned ArgOffset = 4; MachineFrameInfo *MFI = F->getFrameInfo(); for (Function::aiterator I = Fn.abegin(), E = Fn.aend(); I != E; ++I) { unsigned Reg = getReg(*I); - ArgOffset += 4; // Each argument takes at least 4 bytes on the stack... int FI; // Frame object index - switch (getClassB(I->getType())) { case cByte: FI = MFI->CreateFixedObject(1, ArgOffset); @@ -373,14 +372,15 @@ FI = MFI->CreateFixedObject(4, ArgOffset); } else { Opcode = X86::FLDr64; - ArgOffset += 4; // doubles require 4 additional bytes FI = MFI->CreateFixedObject(8, ArgOffset); + ArgOffset += 4; // doubles require 4 additional bytes } addFrameReference(BuildMI(BB, Opcode, 4, Reg), FI); break; default: assert(0 && "Unhandled argument type!"); } + ArgOffset += 4; // Each argument takes at least 4 bytes on the stack... } } @@ -390,6 +390,7 @@ /// the current one. /// void ISel::SelectPHINodes() { + const MachineInstrInfo &MII = TM.getInstrInfo(); const Function &LF = *F->getFunction(); // The LLVM function... for (Function::const_iterator I = LF.begin(), E = LF.end(); I != E; ++I) { const BasicBlock *BB = I; @@ -410,11 +411,10 @@ // available in a virtual register, insert the computation code into // PredMBB // - // FIXME: This should insert the code into the BOTTOM of the block, not - // the top of the block. This just makes for huge live ranges... - MachineBasicBlock::iterator PI = PredMBB->begin(); - while ((*PI)->getOpcode() == X86::PHI) ++PI; - + MachineBasicBlock::iterator PI = PredMBB->end(); + while (PI != PredMBB->begin() && + MII.isTerminatorInstr((*(PI-1))->getOpcode())) + --PI; MI->addRegOperand(getReg(PN->getIncomingValue(i), PredMBB, PI)); MI->addMachineBasicBlockOperand(PredMBB); } @@ -433,6 +433,7 @@ void ISel::visitSetCCInst(SetCondInst &I, unsigned OpNum) { // The arguments are already supposed to be of the same type. const Type *CompTy = I.getOperand(0)->getType(); + bool isSigned = CompTy->isSigned(); unsigned reg1 = getReg(I.getOperand(0)); unsigned reg2 = getReg(I.getOperand(1)); @@ -442,44 +443,26 @@ // compare 8-bit with 8-bit, 16-bit with 16-bit, 32-bit with // 32-bit. case cByte: - BuildMI (BB, X86::CMPrr8, 2).addReg (reg1).addReg (reg2); + BuildMI(BB, X86::CMPrr8, 2).addReg(reg1).addReg(reg2); break; case cShort: - BuildMI (BB, X86::CMPrr16, 2).addReg (reg1).addReg (reg2); + BuildMI(BB, X86::CMPrr16, 2).addReg(reg1).addReg(reg2); break; case cInt: - BuildMI (BB, X86::CMPrr32, 2).addReg (reg1).addReg (reg2); + BuildMI(BB, X86::CMPrr32, 2).addReg(reg1).addReg(reg2); break; - -#if 0 - // Push the variables on the stack with fldl opcodes. - // FIXME: assuming var1, var2 are in memory, if not, spill to - // stack first - case cFP: // Floats - BuildMI (BB, X86::FLDr32, 1).addReg (reg1); - BuildMI (BB, X86::FLDr32, 1).addReg (reg2); + case cFP: + BuildMI(BB, X86::FpUCOM, 2).addReg(reg1).addReg(reg2); + BuildMI(BB, X86::FNSTSWr8, 0); + BuildMI(BB, X86::SAHF, 1); + isSigned = false; // Compare with unsigned operators break; - case cFP (doubles): // Doubles - BuildMI (BB, X86::FLDr64, 1).addReg (reg1); - BuildMI (BB, X86::FLDr64, 1).addReg (reg2); - break; -#endif + case cLong: default: visitInstruction(I); } -#if 0 - if (CompTy->isFloatingPoint()) { - // (Non-trapping) compare and pop twice. - BuildMI (BB, X86::FUCOMPP, 0); - // Move fp status word (concodes) to ax. - BuildMI (BB, X86::FNSTSWr8, 1, X86::AX); - // Load real concodes from ax. - BuildMI (BB, X86::SAHF, 1).addReg(X86::AH); - } -#endif - // Emit setOp instruction (extract concode; clobbers ax), // using the following mapping: // LLVM -> X86 signed X86 unsigned @@ -496,12 +479,12 @@ {X86::SETEr, X86::SETNEr, X86::SETLr, X86::SETGr, X86::SETLEr, X86::SETGEr}, }; - BuildMI(BB, OpcodeTab[CompTy->isSigned()][OpNum], 0, getReg(I)); + BuildMI(BB, OpcodeTab[isSigned][OpNum], 0, getReg(I)); } /// promote32 - Emit instructions to turn a narrow operand into a 32-bit-wide /// operand, in the specified target register. -void ISel::promote32 (unsigned targetReg, Value *v) { +void ISel::promote32(unsigned targetReg, Value *v) { unsigned vReg = getReg(v); bool isUnsigned = v->getType()->isUnsigned(); switch (getClass(v->getType())) { @@ -539,7 +522,7 @@ /// ret long, ulong : Move value into EAX/EDX and return /// ret float/double : Top of FP stack /// -void ISel::visitReturnInst (ReturnInst &I) { +void ISel::visitReturnInst(ReturnInst &I) { if (I.getNumOperands() == 0) { BuildMI(BB, X86::RET, 0); // Just emit a 'ret' instruction return; @@ -553,13 +536,13 @@ promote32(X86::EAX, RetVal); break; case cFP: // Floats & Doubles: Return in ST(0) - BuildMI(BB, X86::FpMOV, 1, X86::ST0).addReg(getReg(RetVal)); + BuildMI(BB, X86::FpSETRESULT, 1).addReg(getReg(RetVal)); break; case cLong: // ret long: use EAX(least significant 32 bits)/EDX (most // significant 32)... default: - visitInstruction (I); + visitInstruction(I); } // Emit a 'ret' instruction BuildMI(BB, X86::RET, 0); @@ -595,11 +578,9 @@ for (unsigned i = 1, e = CI.getNumOperands(); i != e; ++i) switch (getClass(CI.getOperand(i)->getType())) { case cByte: case cShort: case cInt: - NumBytes += 4; - break; + NumBytes += 4; break; case cLong: - NumBytes += 8; - break; + NumBytes += 8; break; case cFP: NumBytes += CI.getOperand(i)->getType() == Type::FloatTy ? 4 : 8; break; @@ -623,29 +604,32 @@ X86::ESP, ArgOffset).addReg(R); break; } - case cInt: + case cInt: { + unsigned ArgReg = getReg(Arg); addRegOffset(BuildMI(BB, X86::MOVrm32, 5), - X86::ESP, ArgOffset).addReg(getReg(Arg)); + X86::ESP, ArgOffset).addReg(ArgReg); break; + } - case cFP: + case cFP: { + unsigned ArgReg = getReg(Arg); if (Arg->getType() == Type::FloatTy) { addRegOffset(BuildMI(BB, X86::FSTr32, 5), - X86::ESP, ArgOffset).addReg(getReg(Arg)); + X86::ESP, ArgOffset).addReg(ArgReg); } else { assert(Arg->getType() == Type::DoubleTy && "Unknown FP type!"); - ArgOffset += 4; - addRegOffset(BuildMI(BB, X86::FSTr32, 5), - X86::ESP, ArgOffset).addReg(getReg(Arg)); + addRegOffset(BuildMI(BB, X86::FSTr64, 5), + X86::ESP, ArgOffset).addReg(ArgReg); + ArgOffset += 4; // 8 byte entry, not 4. } break; - + } default: - // FIXME: long/ulong/float/double args not handled. + // FIXME: long/ulong args not handled. visitInstruction(CI); break; } - ArgOffset += 4; + ArgOffset += 4; // All arguments are at least 4 bytes } } @@ -657,7 +641,8 @@ BuildMI(BB, X86::CALLr32, 1).addReg(Reg); } - BuildMI(BB, X86::ADJCALLSTACKUP, 1).addZImm(NumBytes); + if (NumBytes) + BuildMI(BB, X86::ADJCALLSTACKUP, 1).addZImm(NumBytes); // If there is a return value, scavenge the result from the location the call // leaves it in... @@ -679,7 +664,7 @@ break; } case cFP: // Floating-point return values live in %ST(0) - BuildMI(BB, X86::FpMOV, 1, getReg(CI)).addReg(X86::ST0); + BuildMI(BB, X86::FpGETRESULT, 1, getReg(CI)); break; default: std::cerr << "Cannot get return value for call of type '" @@ -783,7 +768,7 @@ if (I.getOpcode() == Instruction::Div) BuildMI(BB, X86::FpDIV, 2, ResultReg).addReg(Op0Reg).addReg(Op1Reg); else - BuildMI(BB, X86::FpREM, 2, ResultReg).addReg(Op0Reg).addReg(Op1Reg); + visitInstruction(I); return; default: case cLong: @@ -846,50 +831,94 @@ if (OperandClass > cInt) visitInstruction(I); // Can't handle longs yet! - if (ConstantUInt *CUI = dyn_cast (I.getOperand (1))) - { - // The shift amount is constant, guaranteed to be a ubyte. Get its value. - assert(CUI->getType() == Type::UByteTy && "Shift amount not a ubyte?"); - unsigned char shAmt = CUI->getValue(); - - static const unsigned ConstantOperand[][4] = { - { X86::SHRir8, X86::SHRir16, X86::SHRir32, 0 }, // SHR - { X86::SARir8, X86::SARir16, X86::SARir32, 0 }, // SAR - { X86::SHLir8, X86::SHLir16, X86::SHLir32, 0 }, // SHL - { X86::SHLir8, X86::SHLir16, X86::SHLir32, 0 }, // SAL = SHL - }; + if (ConstantUInt *CUI = dyn_cast(I.getOperand(1))) { + // The shift amount is constant, guaranteed to be a ubyte. Get its value. + assert(CUI->getType() == Type::UByteTy && "Shift amount not a ubyte?"); + unsigned char shAmt = CUI->getValue(); + + static const unsigned ConstantOperand[][4] = { + { X86::SHRir8, X86::SHRir16, X86::SHRir32, 0 }, // SHR + { X86::SARir8, X86::SARir16, X86::SARir32, 0 }, // SAR + { X86::SHLir8, X86::SHLir16, X86::SHLir32, 0 }, // SHL + { X86::SHLir8, X86::SHLir16, X86::SHLir32, 0 }, // SAL = SHL + }; - const unsigned *OpTab = // Figure out the operand table to use - ConstantOperand[isLeftShift*2+isOperandSigned]; + const unsigned *OpTab = // Figure out the operand table to use + ConstantOperand[isLeftShift*2+isOperandSigned]; - // Emit: reg, shamt (shift-by-immediate opcode "ir" form.) - BuildMI(BB, OpTab[OperandClass], 2, DestReg).addReg(Op0r).addZImm(shAmt); - } - else - { - // The shift amount is non-constant. - // - // In fact, you can only shift with a variable shift amount if - // that amount is already in the CL register, so we have to put it - // there first. - // + // Emit: reg, shamt (shift-by-immediate opcode "ir" form.) + BuildMI(BB, OpTab[OperandClass], 2, DestReg).addReg(Op0r).addZImm(shAmt); + } else { + // The shift amount is non-constant. + // + // In fact, you can only shift with a variable shift amount if + // that amount is already in the CL register, so we have to put it + // there first. + // - // Emit: move cl, shiftAmount (put the shift amount in CL.) - BuildMI(BB, X86::MOVrr8, 1, X86::CL).addReg(getReg(I.getOperand(1))); + // Emit: move cl, shiftAmount (put the shift amount in CL.) + BuildMI(BB, X86::MOVrr8, 1, X86::CL).addReg(getReg(I.getOperand(1))); - // This is a shift right (SHR). - static const unsigned NonConstantOperand[][4] = { - { X86::SHRrr8, X86::SHRrr16, X86::SHRrr32, 0 }, // SHR - { X86::SARrr8, X86::SARrr16, X86::SARrr32, 0 }, // SAR - { X86::SHLrr8, X86::SHLrr16, X86::SHLrr32, 0 }, // SHL - { X86::SHLrr8, X86::SHLrr16, X86::SHLrr32, 0 }, // SAL = SHL - }; + // This is a shift right (SHR). + static const unsigned NonConstantOperand[][4] = { + { X86::SHRrr8, X86::SHRrr16, X86::SHRrr32, 0 }, // SHR + { X86::SARrr8, X86::SARrr16, X86::SARrr32, 0 }, // SAR + { X86::SHLrr8, X86::SHLrr16, X86::SHLrr32, 0 }, // SHL + { X86::SHLrr8, X86::SHLrr16, X86::SHLrr32, 0 }, // SAL = SHL + }; - const unsigned *OpTab = // Figure out the operand table to use - NonConstantOperand[isLeftShift*2+isOperandSigned]; + const unsigned *OpTab = // Figure out the operand table to use + NonConstantOperand[isLeftShift*2+isOperandSigned]; - BuildMI(BB, OpTab[OperandClass], 1, DestReg).addReg(Op0r); - } + BuildMI(BB, OpTab[OperandClass], 1, DestReg).addReg(Op0r); + } +} + + +/// doFPLoad - This method is used to load an FP value from memory using the +/// current endianness. NOTE: This method returns a partially constructed load +/// instruction which needs to have the memory source filled in still. +/// +MachineInstr *ISel::doFPLoad(const Type *Ty, unsigned DestReg) { + assert(Ty == Type::FloatTy || Ty == Type::DoubleTy && "Unknown FP type!"); + unsigned LoadOpcode = Ty == Type::FloatTy ? X86::FLDr32 : X86::FLDr64; + + if (TM.getTargetData().isLittleEndian()) // fast path... + return BuildMI(BB, LoadOpcode, 4, DestReg); + + // If we are big-endian, start by creating an LEA instruction to represent the + // address of the memory location to load from... + // + unsigned SrcAddrReg = makeAnotherReg(Type::UIntTy); + MachineInstr *Result = BuildMI(BB, X86::LEAr32, 5, SrcAddrReg); + + // Allocate a temporary stack slot to transform the value into... + int FrameIdx = F->getFrameInfo()->CreateStackObject(Ty, TM.getTargetData()); + unsigned DestAddrReg = makeAnotherReg(Type::UIntTy); + addFrameReference(BuildMI(BB, X86::LEAr32, 5, DestAddrReg), FrameIdx); + + // Perform the bswaps 32 bits at a time... + unsigned TmpReg1 = makeAnotherReg(Type::UIntTy); + unsigned TmpReg2 = makeAnotherReg(Type::UIntTy); + addDirectMem(BuildMI(BB, X86::MOVmr32, 4, TmpReg1), SrcAddrReg); + BuildMI(BB, X86::BSWAPr32, 1, TmpReg2).addReg(TmpReg1); + unsigned Offset = (Ty == Type::DoubleTy) << 2; + addRegOffset(BuildMI(BB, X86::MOVrm32, 5), + DestAddrReg, Offset).addReg(TmpReg2); + + if (Ty == Type::DoubleTy) { // Swap the other 32 bits of a double value... + TmpReg1 = makeAnotherReg(Type::UIntTy); + TmpReg2 = makeAnotherReg(Type::UIntTy); + + addRegOffset(BuildMI(BB, X86::MOVmr32, 4, TmpReg1), SrcAddrReg, 4); + BuildMI(BB, X86::BSWAPr32, 1, TmpReg2).addReg(TmpReg1); + unsigned Offset = (Ty == Type::DoubleTy) << 2; + addDirectMem(BuildMI(BB, X86::MOVrm32, 5), DestAddrReg).addReg(TmpReg2); + } + + // Now we can reload the final byteswapped result into the final destination. + addFrameReference(BuildMI(BB, LoadOpcode, 4, DestReg), FrameIdx); + return Result; } @@ -907,9 +936,7 @@ switch (Class) { default: visitInstruction(I); // FIXME: Handle longs... case cFP: { - // FIXME: Handle endian swapping for FP values. - unsigned Opcode = I.getType() == Type::FloatTy ? X86::FLDr32 : X86::FLDr64; - addDirectMem(BuildMI(BB, Opcode, 4, DestReg), SrcAddrReg); + addDirectMem(doFPLoad(I.getType(), DestReg), SrcAddrReg); return; } case cInt: // Integers of various sizes handled below @@ -922,17 +949,17 @@ // in is in the upper part of the eight byte memory image of the pointer. It // also happens to be byte-swapped, but this will be handled later. // - if (!isLittleEndian && hasLongPointers && isa(I.getType())) { + if (!isLittleEndian && hasLongPointers && + (isa(I.getType()) || + I.getType() == Type::LongTy || I.getType() == Type::ULongTy)) { unsigned R = makeAnotherReg(Type::UIntTy); BuildMI(BB, X86::ADDri32, 2, R).addReg(SrcAddrReg).addZImm(4); SrcAddrReg = R; } unsigned IReg = DestReg; - if (!isLittleEndian) { // If big endian we need an intermediate stage - IReg = makeAnotherReg(I.getType()); - std::swap(IReg, DestReg); - } + if (!isLittleEndian) // If big endian we need an intermediate stage + DestReg = makeAnotherReg(I.getType()); static const unsigned Opcode[] = { X86::MOVmr8, X86::MOVmr16, X86::MOVmr32 }; addDirectMem(BuildMI(BB, Opcode[Class], 4, DestReg), SrcAddrReg); @@ -957,7 +984,7 @@ BuildMI(BB, X86::MOVrr16, 1, X86::AX).addReg(DestReg); BuildMI(BB, X86::XCHGrr8, 2).addReg(X86::AL, MOTy::UseAndDef) .addReg(X86::AH, MOTy::UseAndDef); - BuildMI(BB, X86::MOVrr16, 1, DestReg).addReg(X86::AX); + BuildMI(BB, X86::MOVrr16, 1, IReg).addReg(X86::AX); break; default: assert(0 && "Class not handled yet!"); } @@ -965,32 +992,70 @@ } +/// doFPStore - This method is used to store an FP value to memory using the +/// current endianness. +/// +void ISel::doFPStore(const Type *Ty, unsigned DestAddrReg, unsigned SrcReg) { + assert(Ty == Type::FloatTy || Ty == Type::DoubleTy && "Unknown FP type!"); + unsigned StoreOpcode = Ty == Type::FloatTy ? X86::FSTr32 : X86::FSTr64; + + if (TM.getTargetData().isLittleEndian()) { // fast path... + addDirectMem(BuildMI(BB, StoreOpcode,5), DestAddrReg).addReg(SrcReg); + return; + } + + // Allocate a temporary stack slot to transform the value into... + int FrameIdx = F->getFrameInfo()->CreateStackObject(Ty, TM.getTargetData()); + unsigned SrcAddrReg = makeAnotherReg(Type::UIntTy); + addFrameReference(BuildMI(BB, X86::LEAr32, 5, SrcAddrReg), FrameIdx); + + // Store the value into a temporary stack slot... + addDirectMem(BuildMI(BB, StoreOpcode, 5), SrcAddrReg).addReg(SrcReg); + + // Perform the bswaps 32 bits at a time... + unsigned TmpReg1 = makeAnotherReg(Type::UIntTy); + unsigned TmpReg2 = makeAnotherReg(Type::UIntTy); + addDirectMem(BuildMI(BB, X86::MOVmr32, 4, TmpReg1), SrcAddrReg); + BuildMI(BB, X86::BSWAPr32, 1, TmpReg2).addReg(TmpReg1); + unsigned Offset = (Ty == Type::DoubleTy) << 2; + addRegOffset(BuildMI(BB, X86::MOVrm32, 5), + DestAddrReg, Offset).addReg(TmpReg2); + + if (Ty == Type::DoubleTy) { // Swap the other 32 bits of a double value... + TmpReg1 = makeAnotherReg(Type::UIntTy); + TmpReg2 = makeAnotherReg(Type::UIntTy); + + addRegOffset(BuildMI(BB, X86::MOVmr32, 4, TmpReg1), SrcAddrReg, 4); + BuildMI(BB, X86::BSWAPr32, 1, TmpReg2).addReg(TmpReg1); + unsigned Offset = (Ty == Type::DoubleTy) << 2; + addDirectMem(BuildMI(BB, X86::MOVrm32, 5), DestAddrReg).addReg(TmpReg2); + } +} + + /// visitStoreInst - Implement LLVM store instructions in terms of the x86 'mov' /// instruction. /// void ISel::visitStoreInst(StoreInst &I) { bool isLittleEndian = TM.getTargetData().isLittleEndian(); bool hasLongPointers = TM.getTargetData().getPointerSize() == 8; - unsigned ValReg = getReg(I.getOperand(0)); - unsigned AddressReg = getReg(I.getOperand(1)); + unsigned ValReg = getReg(I.getOperand(0)); + unsigned AddressReg = getReg(I.getOperand(1)); unsigned Class = getClass(I.getOperand(0)->getType()); switch (Class) { default: visitInstruction(I); // FIXME: Handle longs... - case cFP: { - // FIXME: Handle endian swapping for FP values. - unsigned Opcode = I.getOperand(0)->getType() == Type::FloatTy ? - X86::FSTr32 : X86::FSTr64; - addDirectMem(BuildMI(BB, Opcode, 1+4), AddressReg).addReg(ValReg); + case cFP: + doFPStore(I.getOperand(0)->getType(), AddressReg, ValReg); return; - } case cInt: // Integers of various sizes handled below case cShort: case cByte: break; } if (!isLittleEndian && hasLongPointers && - isa(I.getOperand(0)->getType())) { + (isa(I.getOperand(0)->getType()) || + I.getType() == Type::LongTy || I.getType() == Type::ULongTy)) { unsigned R = makeAnotherReg(Type::UIntTy); BuildMI(BB, X86::ADDri32, 2, R).addReg(AddressReg).addZImm(4); AddressReg = R; @@ -1026,85 +1091,143 @@ /// visitCastInst - Here we have various kinds of copying with or without /// sign extension going on. -void -ISel::visitCastInst (CastInst &CI) -{ - const Type *targetType = CI.getType (); - Value *operand = CI.getOperand (0); - unsigned operandReg = getReg (operand); - const Type *sourceType = operand->getType (); - unsigned destReg = getReg (CI); - // - // Currently we handle: - // - // 1) cast * to bool - // - // 2) cast {sbyte, ubyte} to {sbyte, ubyte} - // cast {short, ushort} to {ushort, short} - // cast {int, uint, ptr} to {int, uint, ptr} - // - // 3) cast {sbyte, ubyte} to {ushort, short} - // cast {sbyte, ubyte} to {int, uint, ptr} - // cast {short, ushort} to {int, uint, ptr} - // - // 4) cast {int, uint, ptr} to {short, ushort} - // cast {int, uint, ptr} to {sbyte, ubyte} - // cast {short, ushort} to {sbyte, ubyte} +void ISel::visitCastInst(CastInst &CI) { + const Type *DestTy = CI.getType(); + Value *Src = CI.getOperand(0); + unsigned SrcReg = getReg(Src); + const Type *SrcTy = Src->getType(); + unsigned SrcClass = getClassB(SrcTy); + unsigned DestReg = getReg(CI); + unsigned DestClass = getClassB(DestTy); // 1) Implement casts to bool by using compare on the operand followed // by set if not zero on the result. - if (targetType == Type::BoolTy) - { - BuildMI (BB, X86::CMPri8, 2).addReg (operandReg).addZImm (0); - BuildMI (BB, X86::SETNEr, 1, destReg); - return; - } + if (DestTy == Type::BoolTy) { + if (SrcClass == cFP || SrcClass == cLong) + visitInstruction(CI); + + BuildMI(BB, X86::CMPri8, 2).addReg(SrcReg).addZImm(0); + BuildMI(BB, X86::SETNEr, 1, DestReg); + return; + } - // 2) Implement casts between values of the same type class (as determined - // by getClass) by using a register-to-register move. - unsigned srcClass = getClassB(sourceType); - unsigned targClass = getClass(targetType); - static const unsigned regRegMove[] = { - X86::MOVrr8, X86::MOVrr16, X86::MOVrr32 + static const unsigned RegRegMove[] = { + X86::MOVrr8, X86::MOVrr16, X86::MOVrr32, X86::FpMOV }; - if (srcClass <= cInt && targClass <= cInt && srcClass == targClass) { - BuildMI(BB, regRegMove[srcClass], 1, destReg).addReg(operandReg); + // Implement casts between values of the same type class (as determined by + // getClass) by using a register-to-register move. + if (SrcClass == DestClass) { + if (SrcClass <= cInt || (SrcClass == cFP && SrcTy == DestTy)) { + BuildMI(BB, RegRegMove[SrcClass], 1, DestReg).addReg(SrcReg); + } else if (SrcClass == cFP) { + if (SrcTy == Type::FloatTy) { // double -> float + assert(DestTy == Type::DoubleTy && "Unknown cFP member!"); + BuildMI(BB, X86::FpMOV, 1, DestReg).addReg(SrcReg); + } else { // float -> double + assert(SrcTy == Type::DoubleTy && DestTy == Type::FloatTy && + "Unknown cFP member!"); + // Truncate from double to float by storing to memory as short, then + // reading it back. + unsigned FltAlign = TM.getTargetData().getFloatAlignment(); + int FrameIdx = F->getFrameInfo()->CreateStackObject(4, FltAlign); + addFrameReference(BuildMI(BB, X86::FSTr32, 5), FrameIdx).addReg(SrcReg); + addFrameReference(BuildMI(BB, X86::FLDr32, 5, DestReg), FrameIdx); + } + } else { + visitInstruction(CI); + } return; } - // 3) Handle cast of SMALLER int to LARGER int using a move with sign - // extension or zero extension, depending on whether the source type - // was signed. - if ((srcClass <= cInt) && (targClass <= cInt) && (srcClass < targClass)) - { - static const unsigned ops[] = { - X86::MOVSXr16r8, X86::MOVSXr32r8, X86::MOVSXr32r16, - X86::MOVZXr16r8, X86::MOVZXr32r8, X86::MOVZXr32r16 - }; - unsigned srcSigned = sourceType->isSigned (); - BuildMI (BB, ops[3 * srcSigned + srcClass + targClass - 1], 1, - destReg).addReg (operandReg); - return; - } - // 4) Handle cast of LARGER int to SMALLER int using a move to EAX - // followed by a move out of AX or AL. - if ((srcClass <= cInt) && (targClass <= cInt) && (srcClass > targClass)) - { - static const unsigned AReg[] = { X86::AL, X86::AX, X86::EAX }; - BuildMI (BB, regRegMove[srcClass], 1, - AReg[srcClass]).addReg (operandReg); - BuildMI (BB, regRegMove[targClass], 1, destReg).addReg (AReg[srcClass]); - return; - } + + // Handle cast of SMALLER int to LARGER int using a move with sign extension + // or zero extension, depending on whether the source type was signed. + if (SrcClass <= cInt && DestClass <= cInt && SrcClass < DestClass) { + static const unsigned Opc[][3] = { + { X86::MOVSXr16r8, X86::MOVSXr32r8, X86::MOVSXr32r16 }, // signed + { X86::MOVZXr16r8, X86::MOVZXr32r8, X86::MOVZXr32r16 } // unsigned + }; + + BuildMI(BB, Opc[SrcTy->isUnsigned()][SrcClass + DestClass - 1], 1, + DestReg).addReg(SrcReg); + return; + } + + // Handle cast of LARGER int to SMALLER int using a move to EAX followed by a + // move out of AX or AL. + if (SrcClass <= cInt && DestClass <= cInt && SrcClass > DestClass) { + static const unsigned AReg[] = { X86::AL, X86::AX, X86::EAX }; + BuildMI(BB, RegRegMove[SrcClass], 1, AReg[SrcClass]).addReg(SrcReg); + BuildMI(BB, RegRegMove[DestClass], 1, DestReg).addReg(AReg[DestClass]); + return; + } + + // Handle casts from integer to floating point now... + if (DestClass == cFP) { + // unsigned int -> load as 64 bit int. + // unsigned long long -> more complex + if (SrcTy->isUnsigned() && SrcTy != Type::UByteTy) + visitInstruction(CI); // don't handle unsigned src yet! + + // We don't have the facilities for directly loading byte sized data from + // memory. Promote it to 16 bits. + if (SrcClass == cByte) { + unsigned TmpReg = makeAnotherReg(Type::ShortTy); + BuildMI(BB, SrcTy->isSigned() ? X86::MOVSXr16r8 : X86::MOVZXr16r8, + 1, TmpReg).addReg(SrcReg); + SrcTy = Type::ShortTy; // Pretend the short is our input now! + SrcClass = cShort; + SrcReg = TmpReg; + } + + // Spill the integer to memory and reload it from there... + int FrameIdx = + F->getFrameInfo()->CreateStackObject(SrcTy, TM.getTargetData()); + + if (SrcClass > cInt) visitInstruction(CI); + static const unsigned Op1[] = { X86::MOVrm8, X86::MOVrm16, X86::MOVrm32 }; + addFrameReference(BuildMI(BB, Op1[SrcClass], 5), FrameIdx).addReg(SrcReg); + + static const unsigned Op2[] = + { 0, X86::FILDr16, X86::FILDr32, 0, X86::FILDr64 }; + addFrameReference(BuildMI(BB, Op2[SrcClass], 5, DestReg), FrameIdx); + return; + } + + // Handle casts from floating point to integer now... + if (SrcClass == cFP) { + // unsigned long long -> more complex + if (SrcClass == cLong) + visitInstruction(CI); // don't handle unsigned src yet! + + // We don't have the facilities for directly storing byte sized data to + // memory. Promote it to 16 bits. We also must promote unsigned values to + // larger classes because we only have signed FP stores. + unsigned StoreClass = DestClass; + const Type *StoreTy = DestTy; + if (StoreClass == cByte || DestTy->isUnsigned()) + switch (StoreClass) { + case cByte: StoreTy = Type::ShortTy; StoreClass = cShort; break; + case cShort: StoreTy = Type::IntTy; StoreClass = cInt; break; + case cInt: StoreTy = Type::LongTy; StoreClass = cLong; break; + default: assert(0 && "Unknown store class!"); + } + + // Spill the integer to memory and reload it from there... + int FrameIdx = + F->getFrameInfo()->CreateStackObject(StoreTy, TM.getTargetData()); + + static const unsigned Op1[] = + { 0, X86::FISTr16, X86::FISTr32, 0, X86::FISTPr64 }; + addFrameReference(BuildMI(BB, Op1[StoreClass], 5), FrameIdx).addReg(SrcReg); + + if (DestClass > cInt) visitInstruction(CI); + static const unsigned Op2[] = { X86::MOVmr8, X86::MOVmr16, X86::MOVmr32 }; + addFrameReference(BuildMI(BB, Op2[DestClass], 5, DestReg), FrameIdx); + return; + } + // Anything we haven't handled already, we can't (yet) handle at all. - // - // FP to integral casts can be handled with FISTP to store onto the - // stack while converting to integer, followed by a MOV to load from - // the stack into the result register. Integral to FP casts can be - // handled with MOV to store onto the stack, followed by a FILD to - // load from the stack while converting to FP. For the moment, I - // can't quite get straight in my head how to borrow myself some - // stack space and write on it. Otherwise, this would be trivial. visitInstruction (CI); } @@ -1164,9 +1287,13 @@ unsigned idxValue = CUI->getValue(); unsigned memberOffset = TD.getStructLayout(StTy)->MemberOffsets[idxValue]; - // Emit an ADD to add memberOffset to the basePtr. - BMI(MBB, IP, X86::ADDri32, 2, - nextBasePtrReg).addReg(basePtrReg).addZImm(memberOffset); + if (memberOffset) { + // Emit an ADD to add memberOffset to the basePtr. + BMI(MBB, IP, X86::ADDri32, 2, + nextBasePtrReg).addReg(basePtrReg).addZImm(memberOffset); + } else { + BMI(MBB, IP, X86::MOVrr32, 1, nextBasePtrReg).addReg(basePtrReg); + } // The next type is the member of the structure selected by the // index. Ty = StTy->getElementTypes()[idxValue]; @@ -1276,7 +1403,7 @@ BuildMI(BB, X86::ANDri32, 2, AlignedSize).addReg(AddedSizeReg).addZImm(~15); // Subtract size from stack pointer, thereby allocating some space. - BuildMI(BB, X86::SUBri32, 2, X86::ESP).addReg(X86::ESP).addZImm(AlignedSize); + BuildMI(BB, X86::SUBrr32, 2, X86::ESP).addReg(X86::ESP).addReg(AlignedSize); // Put a pointer to the space into the result register, by copying // the stack pointer. From lattner at cs.uiuc.edu Mon Jan 6 12:52:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:52:00 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/Printer.cpp Message-ID: <200301061851.MAA26563@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: Printer.cpp updated: 1.32 -> 1.33 --- Log message: * Implement rudimentary output of the constant pool * Implement support for MRMS?m instructions --- Diffs of the changes: Index: llvm/lib/Target/X86/Printer.cpp diff -u llvm/lib/Target/X86/Printer.cpp:1.32 llvm/lib/Target/X86/Printer.cpp:1.33 --- llvm/lib/Target/X86/Printer.cpp:1.32 Sat Dec 28 14:25:38 2002 +++ llvm/lib/Target/X86/Printer.cpp Mon Jan 6 12:50:21 2003 @@ -8,21 +8,24 @@ #include "X86.h" #include "X86InstrInfo.h" #include "llvm/Function.h" +#include "llvm/Constant.h" #include "llvm/Target/TargetMachine.h" #include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineInstr.h" #include "Support/Statistic.h" namespace { struct Printer : public MachineFunctionPass { std::ostream &O; - - Printer(std::ostream &o) : O(o) {} + unsigned ConstIdx; + Printer(std::ostream &o) : O(o), ConstIdx(0) {} virtual const char *getPassName() const { return "X86 Assembly Printer"; } + void printConstantPool(MachineConstantPool *MCP, const TargetData &TD); bool runOnMachineFunction(MachineFunction &F); }; } @@ -36,6 +39,21 @@ } +// printConstantPool - Print out any constants which have been spilled to +// memory... +void Printer::printConstantPool(MachineConstantPool *MCP, const TargetData &TD){ + const std::vector &CP = MCP->getConstants(); + if (CP.empty()) return; + + for (unsigned i = 0, e = CP.size(); i != e; ++i) { + O << "\t.section .rodata\n"; + O << "\t.align " << (unsigned)TD.getTypeAlignment(CP[i]->getType()) << "\n"; + O << ".CPI" << i+ConstIdx << ":\t\t\t\t\t;" << *CP[i] << "\n"; + O << "\t*Constant output not implemented yet!*\n\n"; + } + ConstIdx += CP.size(); // Don't recycle constant pool index numbers +} + /// runOnFunction - This uses the X86InstructionInfo::print method /// to print assembly for each instruction. bool Printer::runOnMachineFunction(MachineFunction &MF) { @@ -43,7 +61,12 @@ const TargetMachine &TM = MF.getTarget(); const MachineInstrInfo &MII = TM.getInstrInfo(); + // Print out constants referenced by the function + printConstantPool(MF.getConstantPool(), TM.getTargetData()); + // Print out labels for the function. + O << "\t.text\n"; + O << "\t.align 16\n"; O << "\t.globl\t" << MF.getFunction()->getName() << "\n"; O << "\t.type\t" << MF.getFunction()->getName() << ", @function\n"; O << MF.getFunction()->getName() << ":\n"; @@ -72,6 +95,8 @@ } static bool isMem(const MachineInstr *MI, unsigned Op) { + if (MI->getOperand(Op+3).isFrameIndex()) return true; + if (MI->getOperand(Op+3).isConstantPoolIndex()) return true; return Op+4 <= MI->getNumOperands() && MI->getOperand(Op ).isRegister() &&isScale(MI->getOperand(Op+1)) && MI->getOperand(Op+2).isRegister() &&MI->getOperand(Op+3).isImmediate(); @@ -85,6 +110,7 @@ O << "<" << V->getName() << ">"; return; } + // FALLTHROUGH case MachineOperand::MO_MachineRegister: if (MO.getReg() < MRegisterInfo::FirstVirtualRegister) O << RI.get(MO.getReg()).Name; @@ -110,6 +136,7 @@ case X86II::Arg8: return "BYTE PTR"; case X86II::Arg16: return "WORD PTR"; case X86II::Arg32: return "DWORD PTR"; + case X86II::Arg64: return "QWORD PTR"; case X86II::ArgF32: return "DWORD PTR"; case X86II::ArgF64: return "QWORD PTR"; case X86II::ArgF80: return "XWORD PTR"; @@ -119,6 +146,15 @@ static void printMemReference(std::ostream &O, const MachineInstr *MI, unsigned Op, const MRegisterInfo &RI) { assert(isMem(MI, Op) && "Invalid memory reference!"); + + if (MI->getOperand(Op+3).isFrameIndex()) { + O << "[frame slot #" << MI->getOperand(Op+3).getFrameIndex() << "]"; + return; + } else if (MI->getOperand(Op+3).isConstantPoolIndex()) { + O << "[.CPI" << MI->getOperand(Op+3).getConstantPoolIndex() << "]"; + return; + } + const MachineOperand &BaseReg = MI->getOperand(Op); int ScaleVal = MI->getOperand(Op+1).getImmedValue(); const MachineOperand &IndexReg = MI->getOperand(Op+2); @@ -227,7 +263,9 @@ O << getName(MI->getOpCode()) << " "; printOp(O, MI->getOperand(0), RI); - if (MI->getNumOperands() == 2 && !MI->getOperand(1).isRegister()) { + if (MI->getNumOperands() == 2 && + (!MI->getOperand(1).isRegister() || + MI->getOperand(1).getVRegValueOrNull())) { O << ", "; printOp(O, MI->getOperand(1), RI); } @@ -269,7 +307,7 @@ assert(isMem(MI, 0) && MI->getNumOperands() == 4+1 && MI->getOperand(4).isRegister() && "Bad format for MRMDestMem!"); - O << getName(MI->getOpCode()) << " " << sizePtr (Desc) << " "; + O << getName(MI->getOpCode()) << " " << sizePtr(Desc) << " "; printMemReference(O, MI, 0, RI); O << ", "; printOp(O, MI->getOperand(4), RI); @@ -319,7 +357,7 @@ O << getName(MI->getOpCode()) << " "; printOp(O, MI->getOperand(0), RI); - O << ", " << sizePtr (Desc) << " "; + O << ", " << sizePtr(Desc) << " "; printMemReference(O, MI, MI->getNumOperands()-4, RI); O << "\n"; return; @@ -359,7 +397,33 @@ return; } + case X86II::MRMS0m: case X86II::MRMS1m: + case X86II::MRMS2m: case X86II::MRMS3m: + case X86II::MRMS4m: case X86II::MRMS5m: + case X86II::MRMS6m: case X86II::MRMS7m: { + // In this form, the following are valid formats: + // 1. sete [m] + // 2. cmp [m], immediate + // 2. shl [m], rinput + // 3. sbb [m], immediate + // + assert(MI->getNumOperands() >= 4 && MI->getNumOperands() <= 5 && + isMem(MI, 0) && "Bad MRMSxM format!"); + assert((MI->getNumOperands() != 5 || MI->getOperand(4).isImmediate()) && + "Bad MRMSxM format!"); + + O << getName(MI->getOpCode()) << " "; + O << sizePtr(Desc) << " "; + printMemReference(O, MI, 0, RI); + if (MI->getNumOperands() == 5) { + O << ", "; + printOp(O, MI->getOperand(4), RI); + } + O << "\n"; + return; + } + default: - O << "\t\t\t-"; MI->print(O, TM); break; + O << "\tUNKNOWN FORM:\t\t-"; MI->print(O, TM); break; } } From lattner at cs.uiuc.edu Mon Jan 6 12:52:02 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:52:02 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/MachineCodeEmitter.cpp Message-ID: <200301061851.MAA26568@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: MachineCodeEmitter.cpp updated: 1.17 -> 1.18 --- Log message: * Add support for FP registers ST* * Add support for the constant pool & constant pool indices * Add support for MRMS?m instructions --- Diffs of the changes: Index: llvm/lib/Target/X86/MachineCodeEmitter.cpp diff -u llvm/lib/Target/X86/MachineCodeEmitter.cpp:1.17 llvm/lib/Target/X86/MachineCodeEmitter.cpp:1.18 --- llvm/lib/Target/X86/MachineCodeEmitter.cpp:1.17 Sat Dec 28 14:24:48 2002 +++ llvm/lib/Target/X86/MachineCodeEmitter.cpp Mon Jan 6 12:49:24 2003 @@ -58,6 +58,7 @@ II = &((X86TargetMachine&)MF.getTarget()).getInstrInfo(); MCE.startFunction(MF); + MCE.emitConstantPool(MF.getConstantPool()); for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) emitBasicBlock(*I); MCE.finishFunction(MF); @@ -91,6 +92,10 @@ case X86::EBP: case X86::BP: case X86::CH: return N86::EBP; case X86::ESI: case X86::SI: case X86::DH: return N86::ESI; case X86::EDI: case X86::DI: case X86::BH: return N86::EDI; + + case X86::ST0: case X86::ST1: case X86::ST2: case X86::ST3: + case X86::ST4: case X86::ST5: case X86::ST6: case X86::ST7: + return RegNo-X86::ST0; default: assert(RegNo >= MRegisterInfo::FirstVirtualRegister && "Unknown physical register!"); @@ -128,6 +133,15 @@ void Emitter::emitMemModRMByte(const MachineInstr &MI, unsigned Op, unsigned RegOpcodeField) { + if (MI.getOperand(Op+3).isConstantPoolIndex()) { + // Emit a direct address reference [disp32] where the displacement is + // controlled by the MCE. + MCE.emitByte(ModRMByte(0, RegOpcodeField, 5)); + unsigned Index = MI.getOperand(Op+3).getConstantPoolIndex(); + MCE.emitFunctionConstantValueAddress(Index); + return; + } + const MachineOperand &BaseReg = MI.getOperand(Op); const MachineOperand &Scale = MI.getOperand(Op+1); const MachineOperand &IndexReg = MI.getOperand(Op+2); @@ -233,17 +247,19 @@ break; case X86II::D8: case X86II::D9: case X86II::DA: case X86II::DB: case X86II::DC: case X86II::DD: case X86II::DE: case X86II::DF: - MCE.emitByte(0xD8 + (Desc.TSFlags & X86II::Op0Mask)-X86II::D8); + MCE.emitByte(0xD8+ + (((Desc.TSFlags & X86II::Op0Mask)-X86II::D8) + >> X86II::Op0Shift)); break; // Two-byte opcode prefix - - default: break; // No prefix! + default: assert(0 && "Invalid prefix!"); + case 0: break; // No prefix! } unsigned char BaseOpcode = II->getBaseOpcodeFor(Opcode); switch (Desc.TSFlags & X86II::FormMask) { - default: assert(0 && "Unknown FormMask value!"); + default: assert(0 && "Unknown FormMask value in X86 MachineCodeEmitter!"); case X86II::Pseudo: - std::cerr << "X86 Machine Code Emitter: Not emitting: " << MI; + std::cerr << "X86 Machine Code Emitter: No 'form', not emitting: " << MI; break; case X86II::RawFrm: MCE.emitByte(BaseOpcode); @@ -297,6 +313,19 @@ if (MI.getOperand(MI.getNumOperands()-1).isImmediate()) { unsigned Size = sizeOfPtr(Desc); emitConstant(MI.getOperand(MI.getNumOperands()-1).getImmedValue(), Size); + } + break; + + case X86II::MRMS0m: case X86II::MRMS1m: + case X86II::MRMS2m: case X86II::MRMS3m: + case X86II::MRMS4m: case X86II::MRMS5m: + case X86II::MRMS6m: case X86II::MRMS7m: + MCE.emitByte(BaseOpcode); + emitMemModRMByte(MI, 0, (Desc.TSFlags & X86II::FormMask)-X86II::MRMS0m); + + if (MI.getNumOperands() == 5) { + unsigned Size = sizeOfPtr(Desc); + emitConstant(MI.getOperand(4).getImmedValue(), Size); } break; } From lattner at cs.uiuc.edu Mon Jan 6 12:52:04 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:52:04 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86.h Message-ID: <200301061851.MAA26575@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86.h updated: 1.11 -> 1.12 --- Log message: Move general codegen passes out to Codegen/Passes.h --- Diffs of the changes: Index: llvm/lib/Target/X86/X86.h diff -u llvm/lib/Target/X86/X86.h:1.11 llvm/lib/Target/X86/X86.h:1.12 --- llvm/lib/Target/X86/X86.h:1.11 Sat Dec 28 14:26:16 2002 +++ llvm/lib/Target/X86/X86.h Mon Jan 6 12:50:55 2003 @@ -3,8 +3,6 @@ // This file contains the entry points for global functions defined in the x86 // target library, as used by the LLVM JIT. // -// FIXME: This file will be dramatically changed in the future -// //===----------------------------------------------------------------------===// #ifndef TARGET_X86_H @@ -20,17 +18,16 @@ /// Pass *createSimpleX86InstructionSelector(TargetMachine &TM); -/// createSimpleRegisterAllocation - This function returns a pass that converts -/// the specified machine code function from SSA form to use explicit registers -/// by spilling every register. Wow, great policy huh? +/// createX86PeepholeOptimizer - Create a pass to perform X86 specific peephole +/// optimizations. /// -Pass *createSimpleRegisterAllocator(); -Pass *createLocalRegisterAllocator(); +Pass *createX86PeepholeOptimizerPass(); -/// createPrologEpilogCodeInserter - This function returns a pass that inserts -/// prolog and epilog code, and eliminates abstract frame references. +/// createX86FloatingPointStackifierPass - This function returns a pass which +/// converts floating point register references and pseudo instructions into +/// floating point stack references and physical instructions. /// -Pass *createPrologEpilogCodeInserter(); +Pass *createX86FloatingPointStackifierPass(); /// createX86CodePrinterPass - Print out the specified machine code function to /// the specified stream. This function should work regardless of whether or From lattner at cs.uiuc.edu Mon Jan 6 12:52:05 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:52:05 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrBuilder.h Message-ID: <200301061851.MAA26586@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrBuilder.h updated: 1.4 -> 1.5 --- Log message: Add support for Constant Pool indices --- Diffs of the changes: Index: llvm/lib/Target/X86/X86InstrBuilder.h diff -u llvm/lib/Target/X86/X86InstrBuilder.h:1.4 llvm/lib/Target/X86/X86InstrBuilder.h:1.5 --- llvm/lib/Target/X86/X86InstrBuilder.h:1.4 Sat Dec 28 14:26:58 2002 +++ llvm/lib/Target/X86/X86InstrBuilder.h Mon Jan 6 12:51:17 2003 @@ -50,4 +50,14 @@ return MIB.addReg(0).addZImm(1).addMReg(0).addFrameIndex(FI); } +/// addConstantPoolReference - This function is used to add a reference to the +/// base of a constant value spilled to the per-function constant pool. The +/// reference has base register and a ConstantPoolIndex offset which is +/// retained until either machine code emission or assembly output. +/// +inline const MachineInstrBuilder & +addConstantPoolReference(const MachineInstrBuilder &MIB, unsigned CPI) { + return MIB.addReg(0).addZImm(1).addMReg(0).addConstantPoolIndex(CPI); +} + #endif From lattner at cs.uiuc.edu Mon Jan 6 12:55:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:55:01 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/README.txt Message-ID: <200301061854.MAA26609@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: README.txt updated: 1.5 -> 1.6 --- Log message: Add silly suggestion --- Diffs of the changes: Index: llvm/lib/Target/X86/README.txt diff -u llvm/lib/Target/X86/README.txt:1.5 llvm/lib/Target/X86/README.txt:1.6 --- llvm/lib/Target/X86/README.txt:1.5 Wed Dec 4 10:12:54 2002 +++ llvm/lib/Target/X86/README.txt Mon Jan 6 12:50:36 2003 @@ -205,7 +205,7 @@ ------------------- 1. Implement lots of nifty runtime optimizations 2. Implement a static compiler backend for x86 (might come almost for free...) -3. Implement new targets: IA64? X86-64? M68k? Who knows... +3. Implement new targets: IA64? X86-64? M68k? MMIX? Who knows... Infrastructure Improvements: ---------------------------- From lattner at cs.uiuc.edu Mon Jan 6 12:55:02 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:55:02 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.h Message-ID: <200301061854.MAA26616@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.h updated: 1.19 -> 1.20 --- Log message: * Some instructions take 64 bit integers, add an Arg type for it * Add flags for different types of FP pseudo instrs --- Diffs of the changes: Index: llvm/lib/Target/X86/X86InstrInfo.h diff -u llvm/lib/Target/X86/X86InstrInfo.h:1.19 llvm/lib/Target/X86/X86InstrInfo.h:1.20 --- llvm/lib/Target/X86/X86InstrInfo.h:1.19 Sat Dec 28 14:29:41 2002 +++ llvm/lib/Target/X86/X86InstrInfo.h Mon Jan 6 12:54:11 2003 @@ -85,6 +85,7 @@ // is no prefix byte for obtaining a multibyte opcode. // Op0Mask = 0xF << 7, + Op0Shift = 7, // TB - TwoByte - Set if this instruction has a two byte opcode, which // starts with a 0x0F byte before the real opcode. @@ -95,17 +96,44 @@ D8 = 2 << 7, D9 = 3 << 7, DA = 4 << 7, DB = 5 << 7, DC = 6 << 7, DD = 7 << 7, DE = 8 << 7, DF = 9 << 7, + //===------------------------------------------------------------------===// // This three-bit field describes the size of a memory operand. Zero is // unused so that we can tell if we forgot to set a value. Arg8 = 1 << 11, Arg16 = 2 << 11, Arg32 = 3 << 11, - ArgF32 = 4 << 11, - ArgF64 = 5 << 11, - ArgF80 = 6 << 11, + Arg64 = 4 << 11, // 64 bit int argument for FILD64 + ArgF32 = 5 << 11, + ArgF64 = 6 << 11, + ArgF80 = 7 << 11, ArgMask = 7 << 11, - // Bits 14 -> 31 are unused + //===------------------------------------------------------------------===// + // FP Instruction Classification... Zero is non-fp instruction. + + // ZeroArgFP - 0 arg FP instruction which implicitly pushes ST(0), f.e. fld0 + ZeroArgFP = 1 << 14, + + // OneArgFP - 1 arg FP instructions which implicitly read ST(0), such as fst + OneArgFP = 2 << 14, + + // OneArgFPRW - 1 arg FP instruction which implicitly read ST(0) and write a + // result back to ST(0). For example, fcos, fsqrt, etc. + // + OneArgFPRW = 3 << 14, + + // TwoArgFP - 2 arg FP instructions which implicitly read ST(0), and an + // explicit argument, storing the result to either ST(0) or the implicit + // argument. For example: fadd, fsub, fmul, etc... + TwoArgFP = 4 << 14, + + // SpecialFP - Special instruction forms. Dispatch by opcode explicitly. + SpecialFP = 5 << 14, + + // FPTypeMask - Mask for all of the FP types... + FPTypeMask = 7 << 14, + + // Bits 17 -> 31 are unused }; } From lattner at cs.uiuc.edu Mon Jan 6 12:55:04 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:55:04 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.def Message-ID: <200301061854.MAA26625@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.def updated: 1.47 -> 1.48 --- Log message: * Function calls clobber fp registers * Use new M_TERMINATOR_FLAG flag * Add ::Void flag on several instructions so def-use info is correct! * Implement MANY FP instructions * Finalize pseudo FP instructions * Add set of Pseudo FP instruction description flags * --- Diffs of the changes: Index: llvm/lib/Target/X86/X86InstrInfo.def diff -u llvm/lib/Target/X86/X86InstrInfo.def:1.47 llvm/lib/Target/X86/X86InstrInfo.def:1.48 --- llvm/lib/Target/X86/X86InstrInfo.def:1.47 Sat Dec 28 14:29:14 2002 +++ llvm/lib/Target/X86/X86InstrInfo.def Mon Jan 6 12:53:30 2003 @@ -35,7 +35,14 @@ IMPREGSLIST(O_EBP, X86::EBP, 0) IMPREGSLIST(T_AXDX , X86::AX , X86::DX , 0) IMPREGSLIST(T_EAXEDX, X86::EAX, X86::EDX, 0) -IMPREGSLIST(C_CLOBBER, X86::EAX, X86::ECX, X86::EDX, 0) // Callee clobber regs +IMPREGSLIST(C_CLOBBER, X86::EAX, X86::ECX, X86::EDX, + X86::FP0, X86::FP1, X86::FP2, X86::FP3, + X86::FP4, X86::FP5, X86::FP6, 0) // Callee clobber regs + +// Floating point registers... +IMPREGSLIST(O_ST0, X86::ST0, 0) +//IMPREGSLIST(O_TOP, X86::TOP, 0) + #undef IMPREGSLIST @@ -73,10 +80,10 @@ I(ADJCALLSTACKUP , "adjcallstackup" , 0, 0, X86II::Pseudo, NoIR, NoIR) // Flow control instructions -I(RET , "ret", 0xC3, M_RET_FLAG, X86II::RawFrm | X86II::Void, NoIR, NoIR) // ret -I(JMP , "jmp", 0xE9, M_BRANCH_FLAG, X86II::RawFrm | X86II::Void, NoIR, NoIR) // jmp foo -I(JNE , "jne", 0x85, M_BRANCH_FLAG, X86II::RawFrm | X86II::TB | X86II::Void, NoIR, NoIR) // jne foo -I(JE , "je", 0x84, M_BRANCH_FLAG, X86II::RawFrm | X86II::TB | X86II::Void, NoIR, NoIR) // je foo +I(RET , "ret", 0xC3, M_RET_FLAG | M_TERMINATOR_FLAG, X86II::RawFrm | X86II::Void, NoIR, NoIR) // ret +I(JMP , "jmp", 0xE9, M_BRANCH_FLAG | M_TERMINATOR_FLAG, X86II::RawFrm | X86II::Void, NoIR, NoIR) // jmp foo +I(JNE , "jne", 0x85, M_BRANCH_FLAG | M_TERMINATOR_FLAG, X86II::RawFrm | X86II::TB | X86II::Void, NoIR, NoIR) // jne foo +I(JE , "je", 0x84, M_BRANCH_FLAG | M_TERMINATOR_FLAG, X86II::RawFrm | X86II::TB | X86II::Void, NoIR, NoIR) // je foo I(CALLpcrel32 , "call", 0xE8, M_CALL_FLAG, X86II::Void | X86II::RawFrm, NoIR, C_CLOBBER) // call pc+42 I(CALLr32 , "call", 0xFF, M_CALL_FLAG, X86II::Void | X86II::MRMS2r | X86II::Arg32, NoIR, C_CLOBBER) // call [r32] @@ -175,28 +182,28 @@ I(SARir32 , "sarl", 0xC1, M_2_ADDR_FLAG, X86II::MRMS7r | X86II::Arg8, NoIR, NoIR) // R32 >>= imm8 // Condition code ops, incl. set if equal/not equal/... -I(SAHF , "sahf", 0x9E, 0, X86II::RawFrm, O_AH, NoIR) // flags = AH -I(SETBr , "setb", 0x92, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = < unsign -I(SETAEr , "setae", 0x93, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = >=unsign +I(SAHF , "sahf", 0x9E, 0, X86II::RawFrm, O_AH, NoIR) // flags = AH +I(SETBr , "setb", 0x92, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = < unsign +I(SETAEr , "setae", 0x93, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = >= unsign I(SETEr , "sete", 0x94, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = == I(SETNEr , "setne", 0x95, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = != -I(SETBEr , "setbe", 0x96, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = <=unsign -I(SETAr , "seta", 0x97, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = > unsign -I(SETLr , "setl", 0x9C, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = < signed -I(SETGEr , "setge", 0x9D, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = >=signed -I(SETLEr , "setle", 0x9E, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = <=signed -I(SETGr , "setg", 0x9F, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = > signed +I(SETBEr , "setbe", 0x96, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = <= unsign +I(SETAr , "seta", 0x97, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = > unsign +I(SETLr , "setl", 0x9C, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = < signed +I(SETGEr , "setge", 0x9D, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = >= signed +I(SETLEr , "setle", 0x9E, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = <= signed +I(SETGr , "setg", 0x9F, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = > signed // Integer comparisons -I(CMPrr8 , "cmpb", 0x38, 0, X86II::MRMDestReg, NoIR, NoIR) // compare R8,R8 -I(CMPrr16 , "cmpw", 0x39, 0, X86II::MRMDestReg | X86II::OpSize, NoIR, NoIR) // compare R16,R16 -I(CMPrr32 , "cmpl", 0x39, 0, X86II::MRMDestReg, NoIR, NoIR) // compare R32,R32 -I(CMPri8 , "cmp", 0x80, 0, X86II::MRMS7r | X86II::Arg8, NoIR, NoIR) // compare R8, imm8 +I(CMPrr8 , "cmpb", 0x38, 0, X86II::Void | X86II::MRMDestReg , NoIR, NoIR) // compare R8,R8 +I(CMPrr16 , "cmpw", 0x39, 0, X86II::Void | X86II::MRMDestReg | X86II::OpSize, NoIR, NoIR) // compare R16,R16 +I(CMPrr32 , "cmpl", 0x39, 0, X86II::Void | X86II::MRMDestReg , NoIR, NoIR) // compare R32,R32 +I(CMPri8 , "cmp", 0x80, 0, X86II::Void | X86II::MRMS7r | X86II::Arg8 , NoIR, NoIR) // compare R8, imm8 // Sign extenders (first 3 are good for DIV/IDIV; the others are more general) -I(CBW , "cbw", 0x98, 0, X86II::RawFrm | X86II::OpSize, O_AL, O_AH) // AX = signext(AL) -I(CWD , "cwd", 0x99, 0, X86II::RawFrm, O_AX, O_DX) // DX:AX = signext(AX) -I(CDQ , "cdq", 0x99, 0, X86II::RawFrm, O_EAX, O_EDX) // EDX:EAX = signext(EAX) +I(CBW , "cbw", 0x98, 0, X86II::Void | X86II::RawFrm | X86II::OpSize, O_AL, O_AH) // AX = signext(AL) +I(CWD , "cwd", 0x99, 0, X86II::Void | X86II::RawFrm, O_AX, O_DX) // DX:AX = signext(AX) +I(CDQ , "cdq", 0x99, 0, X86II::Void | X86II::RawFrm, O_EAX, O_EDX) // EDX:EAX = signext(EAX) I(MOVSXr16r8 , "movsx", 0xBE, 0, X86II::MRMSrcReg | X86II::TB | // R16 = signext(R8) X86II::OpSize, NoIR, NoIR) I(MOVSXr32r8 , "movsx", 0xBE, 0, X86II::MRMSrcReg | X86II::TB, NoIR, NoIR) // R32 = signext(R8) @@ -212,35 +219,81 @@ //===----------------------------------------------------------------------===// // FIXME: These need to indicate mod/ref sets for FP regs... & FP 'TOP' -// FIXME: Remove Pseudo encodings from some insts -// Floating point loads & stores... PREFIX ARGTYPE ENCODING REF MOD -I(FLDr32 , "flds" , 0xD9, 0, X86II::ArgF32 | X86II::Pseudo, NoIR, NoIR) // load float MRMS0m -I(FLDr64 , "fldl" , 0xDD, 0, X86II::ArgF64 | X86II::Pseudo, NoIR, NoIR) // load double MRMS0m -I(FLDr80 , "fldx" , 0xDB, 0, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // store extended MRMS5m -I(FSTr32 , "fsts" , 0xD9, 0, X86II::ArgF32 | X86II::Pseudo, NoIR, NoIR) // store float MRMS2m -I(FSTr64 , "fstl" , 0xDD, 0, X86II::ArgF64 | X86II::Pseudo, NoIR, NoIR) // store double MRMS2m -I(FSTPr80 , "fstpx", 0xDB, 0, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // store extended MRMS7m +// Floating point pseudo instructions... +I(FpMOV , "FMOV" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo | X86II::SpecialFP, NoIR, NoIR) // f1 = fmov f2 +I(FpADD , "FADD" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo | X86II::TwoArgFP , NoIR, NoIR) // f1 = fadd f2, f3 +I(FpSUB , "FSUB" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo | X86II::TwoArgFP , NoIR, NoIR) // f1 = fsub f2, f3 +I(FpMUL , "FMUL" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo | X86II::TwoArgFP , NoIR, NoIR) // f1 = fmul f2, f3 +I(FpDIV , "FDIV" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo | X86II::TwoArgFP , NoIR, NoIR) // f1 = fdiv f2, f3 +I(FpUCOM , "FUCOM", 0, M_PSEUDO_FLAG, X86II::Void | X86II::ArgF80 | X86II::Pseudo | X86II::TwoArgFP , NoIR, NoIR) // FPSW = fucom f1, f2 + +I(FpGETRESULT , "FGETRESULT",0, M_PSEUDO_FLAG, X86II::Pseudo | X86II::SpecialFP, NoIR, NoIR) // FPR = ST(0) +I(FpSETRESULT , "FSETRESULT",0, M_PSEUDO_FLAG | M_TERMINATOR_FLAG, X86II::Void | X86II::Pseudo | X86II::SpecialFP, NoIR, NoIR) // ST(0) = FPR + +// Floating point loads & stores... PREFIX ARGTYPE ENCODING FP INST TYPE REF MOD +I(FLDr32 , "fld32", 0xD9, 0, X86II::ArgF32 | X86II::MRMS0m | X86II::ZeroArgFP, NoIR, NoIR) // load float +I(FLDr64 , "fld64", 0xDD, 0, X86II::ArgF64 | X86II::MRMS0m | X86II::ZeroArgFP, NoIR, NoIR) // load double +I(FLDr80 , "fld80", 0xDB, 0, X86II::ArgF80 | X86II::MRMS5m | X86II::ZeroArgFP, NoIR, NoIR) // load extended +I(FLDrr , "fld" , 0xC0, 0, X86II::D9 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // push(ST(i)) +I(FILDr16 , "fild16", 0xDF, 0, X86II::Arg16 | X86II::MRMS0m | X86II::ZeroArgFP, NoIR, NoIR) // load signed short +I(FILDr32 , "fild32", 0xDB, 0, X86II::Arg32 | X86II::MRMS0m | X86II::ZeroArgFP, NoIR, NoIR) // load signed int +I(FILDr64 , "fild64", 0xDF, 0, X86II::Arg64 | X86II::MRMS5m | X86II::ZeroArgFP, NoIR, NoIR) // load signed long + + +I(FSTr32 , "fst32", 0xD9, 0, X86II::Void | X86II::ArgF32 | X86II::MRMS2m | X86II::OneArgFP , NoIR, NoIR) // store float +I(FSTr64 , "fst64", 0xDD, 0, X86II::Void | X86II::ArgF64 | X86II::MRMS2m | X86II::OneArgFP , NoIR, NoIR) // store double +I(FSTPr32 , "fst32p", 0xD9, 0, X86II::Void | X86II::ArgF32 | X86II::MRMS3m , NoIR, NoIR) // store float, pop +I(FSTPr64 , "fst64p", 0xDD, 0, X86II::Void | X86II::ArgF64 | X86II::MRMS3m , NoIR, NoIR) // store double, pop +I(FSTPr80 , "fst80p", 0xDB, 0, X86II::Void | X86II::ArgF80 | X86II::MRMS7m | X86II::OneArgFP , NoIR, NoIR) // store extended, pop +I(FSTrr , "fst" , 0xD0, 0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(0) +I(FSTPrr , "fstp" , 0xD8, 0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(0), pop + +I(FISTr16 , "fist16", 0xDF, 0, X86II::Void | X86II::Arg16 | X86II::MRMS2m | X86II::OneArgFP , NoIR, NoIR) // store signed short +I(FISTr32 , "fist32", 0xDB, 0, X86II::Void | X86II::Arg32 | X86II::MRMS2m | X86II::OneArgFP , NoIR, NoIR) // store signed int +I(FISTPr16 , "fist16p", 0xDF, 0, X86II::Void | X86II::Arg16 | X86II::MRMS3m , NoIR, NoIR) // store short, pop +I(FISTPr32 , "fist32p", 0xDB, 0, X86II::Void | X86II::Arg32 | X86II::MRMS3m , NoIR, NoIR) // store int, pop +I(FISTPr64 , "fist64p", 0xDF, 0, X86II::Void | X86II::Arg64 | X86II::MRMS7m | X86II::OneArgFP , NoIR, NoIR) // store long, pop -// Floating point constant loads... -I(FLD0 , "fld0" , 0xEE, 0, X86II::D9 | X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // load +0.0 RawFrm -I(FLD1 , "fld1" , 0xE8, 0, X86II::D9 | X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // load +1.0 RawFrm +I(FXCH , "fxch" , 0xC8, 0, X86II::D9 | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm , O_ST0, O_ST0) // fxch ST(i), ST(0) -// Floating point pseudo instructions... -I(FpMOV , "FMOV" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // f1 = fmov f2 -I(FpADD , "FADD" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // f1 = fadd f2, f3 -I(FpSUB , "FSUB" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // f1 = fsub f2, f3 -I(FpMUL , "FMUL" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // f1 = fmul f2, f3 -I(FpDIV , "FDIV" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // f1 = fdiv f2, f3 -I(FpREM , "FREM" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // f1 = frem f2, f3 +// Floating point constant loads... +I(FLD0 , "fld0" , 0xEE, 0, X86II::D9 | X86II::ArgF80 | X86II::RawFrm | X86II::ZeroArgFP, NoIR, NoIR) // load +0.0 +I(FLD1 , "fld1" , 0xE8, 0, X86II::D9 | X86II::ArgF80 | X86II::RawFrm | X86II::ZeroArgFP, NoIR, NoIR) // load +1.0 +// Binary arithmetic operations... +I(FADDST0r , "fadd_0", 0xC0, 0, X86II::D8 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(0) = ST(0) + ST(i) +I(FADDrST0 , "fadd_i", 0xC0, 0, X86II::DC | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) + ST(0) +I(FADDPrST0 , "faddp_i", 0xC0, 0, X86II::DE | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) + ST(0), pop + +I(FSUBRST0r , "fsubr_0" , 0xE8, 0, X86II::D8 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(0) = ST(i) - ST(0) +I(FSUBrST0 , "fsub_i" , 0xE8, 0, X86II::DC | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) - ST(0) +I(FSUBPrST0 , "fsubp_i" , 0xE8, 0, X86II::DE | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) - ST(0), pop + +I(FSUBST0r , "fsub_0" , 0xE0, 0, X86II::D8 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(0) = ST(0) - ST(i) +I(FSUBRrST0 , "fsubr_i" , 0xE0, 0, X86II::DC | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(0) - ST(i) +I(FSUBRPrST0 , "fsubrp_i", 0xE0, 0, X86II::DE | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(0) - ST(i), pop + +I(FMULST0r , "fmul_0", 0xC8, 0, X86II::D8 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(0) = ST(0) * ST(i) +I(FMULrST0 , "fmul_i", 0xC8, 0, X86II::DC | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) * ST(0) +I(FMULPrST0 , "fmulp_i", 0xC8, 0, X86II::DE | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) * ST(0), pop + +I(FDIVRST0r , "fdivr_0" , 0xF8, 0, X86II::D8 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(0) = ST(i) / ST(0) +I(FDIVrST0 , "fdiv_i" , 0xF8, 0, X86II::DC | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) / ST(0) +I(FDIVPrST0 , "fdivp_i" , 0xF8, 0, X86II::DE | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) / ST(0), pop + +I(FDIVST0r , "fdiv_0" , 0xF0, 0, X86II::D8 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(0) = ST(0) / ST(i) +I(FDIVRrST0 , "fdivr_i" , 0xF0, 0, X86II::DC | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(0) / ST(i) +I(FDIVRPrST0 , "fdivrp_i", 0xF0, 0, X86II::DE | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(0) / ST(i), pop // Floating point compares -//I(FUCOMPP , "fucompp", 0xDA, 0, X86II::Void, NoIR, NoIR) // compare+pop2x +I(FUCOMr , "fucom" , 0xE0, 0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // FPSW = compare ST(0) with ST(i) +I(FUCOMPr , "fucomp" , 0xE8, 0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // compare, pop +I(FUCOMPPr , "fucompp" , 0xE9, 0, X86II::DA | X86II::Void | X86II::RawFrm , NoIR, NoIR) // compare ST(0) with ST(1), pop, pop // Floating point flag ops -//I(FNSTSWr8 , "fnstsw", 0xDF, 0, X86II::Void, NoIR, O_AX) // AX = fp flags +I(FNSTSWr8 , "fnstsw" , 0xE0, 0, X86II::DF | X86II::Void | X86II::RawFrm , NoIR, O_AX) // AX = fp flags From lattner at cs.uiuc.edu Mon Jan 6 12:56:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:56:00 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86RegisterInfo.def Message-ID: <200301061855.MAA26637@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86RegisterInfo.def updated: 1.11 -> 1.12 --- Log message: Capitalize FP register names for consistency --- Diffs of the changes: Index: llvm/lib/Target/X86/X86RegisterInfo.def diff -u llvm/lib/Target/X86/X86RegisterInfo.def:1.11 llvm/lib/Target/X86/X86RegisterInfo.def:1.12 --- llvm/lib/Target/X86/X86RegisterInfo.def:1.11 Tue Dec 24 23:08:03 2002 +++ llvm/lib/Target/X86/X86RegisterInfo.def Mon Jan 6 12:54:32 2003 @@ -91,13 +91,13 @@ R8 ( BH, "BH" , MRF::INT8 , 0, A_BH) // Pseudo Floating Point Registers -PFP(FP0, "fp0", MRF::FP80 , 0, 0 /*noalias*/) -PFP(FP1, "fp1", MRF::FP80 , 0, 0 /*noalias*/) -PFP(FP2, "fp2", MRF::FP80 , 0, 0 /*noalias*/) -PFP(FP3, "fp3", MRF::FP80 , 0, 0 /*noalias*/) -PFP(FP4, "fp4", MRF::FP80 , 0, 0 /*noalias*/) -PFP(FP5, "fp5", MRF::FP80 , 0, 0 /*noalias*/) -PFP(FP6, "fp6", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP0, "FP0", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP1, "FP1", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP2, "FP2", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP3, "FP3", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP4, "FP4", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP5, "FP5", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP6, "FP6", MRF::FP80 , 0, 0 /*noalias*/) // Floating point stack registers FPS(ST0, "ST(0)", MRF::FP80, 0, 0) From lattner at cs.uiuc.edu Mon Jan 6 12:56:02 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:56:02 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86TargetMachine.cpp Message-ID: <200301061855.MAA26644@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86TargetMachine.cpp updated: 1.11 -> 1.12 --- Log message: Add FP stackifier pass Add peephole optimizer pass --- Diffs of the changes: Index: llvm/lib/Target/X86/X86TargetMachine.cpp diff -u llvm/lib/Target/X86/X86TargetMachine.cpp:1.11 llvm/lib/Target/X86/X86TargetMachine.cpp:1.12 --- llvm/lib/Target/X86/X86TargetMachine.cpp:1.11 Sat Dec 28 14:33:32 2002 +++ llvm/lib/Target/X86/X86TargetMachine.cpp Mon Jan 6 12:55:04 2003 @@ -9,6 +9,7 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Target/TargetMachineImpls.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/Passes.h" #include "llvm/PassManager.h" #include "Support/CommandLine.h" #include "Support/Statistic.h" @@ -40,7 +41,6 @@ FrameInfo(TargetFrameInfo::StackGrowsDown, 1/*16*/, 0) { } - /// addPassesToJITCompile - Add passes to the specified pass manager to /// implement a fast dynamic compiler for this target. Return true if this is /// not supported for this target. @@ -55,6 +55,8 @@ // TODO: optional optimizations go here + // FIXME: Add SSA based peephole optimizer here. + // Print the instruction selected machine code... if (PrintCode) PM.add(createMachineFunctionPrinterPass()); @@ -68,13 +70,18 @@ if (PrintCode) PM.add(createMachineFunctionPrinterPass()); + PM.add(createX86FloatingPointStackifierPass()); + + if (PrintCode) + PM.add(createMachineFunctionPrinterPass()); + // Insert prolog/epilog code. Eliminate abstract frame index references... PM.add(createPrologEpilogCodeInserter()); + PM.add(createX86PeepholeOptimizerPass()); + if (PrintCode) // Print the register-allocated code PM.add(createX86CodePrinterPass(std::cerr)); - - PM.add(createMachineCodeDestructionPass()); return false; // success! } From lattner at cs.uiuc.edu Mon Jan 6 12:56:04 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:56:04 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/FloatingPoint.cpp PeepholeOptimizer.cpp Message-ID: <200301061855.MAA26654@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: FloatingPoint.cpp added (r1.1) PeepholeOptimizer.cpp added (r1.1) --- Log message: Initial checkin of peephole optimizer and floating point support passes --- Diffs of the changes: From lattner at cs.uiuc.edu Mon Jan 6 12:57:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:57:01 2003 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Olden-voronoi/Makefile Message-ID: <200301061856.MAA26666@apoc.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Olden-voronoi: Makefile updated: 1.2 -> 1.3 --- Log message: This shouldn't require the lex library --- Diffs of the changes: Index: llvm/test/Programs/MultiSource/Olden-voronoi/Makefile diff -u llvm/test/Programs/MultiSource/Olden-voronoi/Makefile:1.2 llvm/test/Programs/MultiSource/Olden-voronoi/Makefile:1.3 --- llvm/test/Programs/MultiSource/Olden-voronoi/Makefile:1.2 Sun May 19 10:52:16 2002 +++ llvm/test/Programs/MultiSource/Olden-voronoi/Makefile Mon Jan 6 12:56:18 2003 @@ -3,6 +3,6 @@ PROG = voronoi INCLUDES = defines.h CPPFLAGS = -DTORONTO -LDFLAGS = -ll -lm +LDFLAGS = -lm include ../Makefile.multisrc From lattner at cs.uiuc.edu Mon Jan 6 12:58:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:58:01 2003 Subject: [llvm-commits] CVS: llvm/test/Regression/Jello/test-cast.ll test-fp.ll Message-ID: <200301061857.MAA26682@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Jello: test-cast.ll updated: 1.1 -> 1.2 test-fp.ll updated: 1.2 -> 1.3 --- Log message: Test much more thoroughly --- Diffs of the changes: Index: llvm/test/Regression/Jello/test-cast.ll diff -u llvm/test/Regression/Jello/test-cast.ll:1.1 llvm/test/Regression/Jello/test-cast.ll:1.2 --- llvm/test/Regression/Jello/test-cast.ll:1.1 Sun Dec 15 01:55:43 2002 +++ llvm/test/Regression/Jello/test-cast.ll Mon Jan 6 12:56:56 2003 @@ -1,7 +1,42 @@ int %main() { + ; Identity casts... + cast long 0 to long + + ; cast bool to ... + cast bool true to bool cast bool true to int + + ; cast sbyte to ... + cast sbyte 0 to sbyte + cast sbyte 4 to short + cast sbyte 4 to double + + ; cast short to ... + cast short 0 to short + cast short 0 to double + + ; cast int to ... cast int 6 to bool + cast int 6 to short + cast int 0 to int + cast int 0 to double + + ; cast float to ... + cast float 0.0 to float + cast float 0.0 to double + + ; cast double to ... + cast double 0.0 to sbyte + cast double 0.0 to ubyte + cast double 0.0 to short + cast double 0.0 to ushort + cast double 0.0 to int + cast double 0.0 to uint + cast double 0.0 to long + cast double 0.0 to ulong + cast double 0.0 to float + cast double 0.0 to double ret int 0 } Index: llvm/test/Regression/Jello/test-fp.ll diff -u llvm/test/Regression/Jello/test-fp.ll:1.2 llvm/test/Regression/Jello/test-fp.ll:1.3 --- llvm/test/Regression/Jello/test-fp.ll:1.2 Sat Dec 28 14:00:47 2002 +++ llvm/test/Regression/Jello/test-fp.ll Mon Jan 6 12:56:56 2003 @@ -5,14 +5,16 @@ %W = sub double %V, %V %X = mul double %W, %W %Y = div double %X, %X - %Z = rem double %Y, %Y + ;%Z = rem double %Y, %Y + %Z = div double %Y, %W %Q = add double %Z, %Arg - store double %Q, double* %DP + %R = cast double %Q to double + store double %R, double* %DP ret double %Z } int %main() { %X = alloca double - call double %test(double* %X, double 1.0) + call double %test(double* %X, double 2.0) ret int 0 } From lattner at cs.uiuc.edu Mon Jan 6 12:58:03 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:58:03 2003 Subject: [llvm-commits] CVS: llvm/test/Regression/Jello/2003-01-04-ArgumentBug.ll 2003-01-04-LoopTest.ll 2003-01-04-PhiTest.llx Message-ID: <200301061857.MAA26692@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Jello: 2003-01-04-ArgumentBug.ll added (r1.1) 2003-01-04-LoopTest.ll added (r1.1) 2003-01-04-PhiTest.llx added (r1.1) --- Log message: New testcases for bug fixes --- Diffs of the changes: From lattner at cs.uiuc.edu Mon Jan 6 12:58:05 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 12:58:05 2003 Subject: [llvm-commits] CVS: llvm/tools/lli/ExecutionEngine.cpp Message-ID: <200301061857.MAA26727@apoc.cs.uiuc.edu> Changes in directory llvm/tools/lli: ExecutionEngine.cpp updated: 1.3 -> 1.4 --- Log message: Add fixme --- Diffs of the changes: Index: llvm/tools/lli/ExecutionEngine.cpp diff -u llvm/tools/lli/ExecutionEngine.cpp:1.3 llvm/tools/lli/ExecutionEngine.cpp:1.4 --- llvm/tools/lli/ExecutionEngine.cpp:1.3 Sat Dec 28 14:00:15 2002 +++ llvm/tools/lli/ExecutionEngine.cpp Mon Jan 6 12:57:42 2003 @@ -170,7 +170,8 @@ void *ExecutionEngine::CreateArgv(const std::vector &InputArgv) { // Pointers are 64 bits... - PointerTy *Result = new PointerTy[InputArgv.size()+1]; // 64 bit assumption + // FIXME: Assumes 64 bit target + PointerTy *Result = new PointerTy[InputArgv.size()+1]; DEBUG(std::cerr << "ARGV = " << (void*)Result << "\n"); for (unsigned i = 0; i < InputArgv.size(); ++i) { From lattner at cs.uiuc.edu Mon Jan 6 13:00:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 13:00:00 2003 Subject: [llvm-commits] CVS: llvm/tools/lli/JIT/Emitter.cpp Message-ID: <200301061859.MAA26748@apoc.cs.uiuc.edu> Changes in directory llvm/tools/lli/JIT: Emitter.cpp updated: 1.1 -> 1.2 --- Log message: * Add support for the constant pool * Allocate larger blocks of memory to support big functions --- Diffs of the changes: Index: llvm/tools/lli/JIT/Emitter.cpp diff -u llvm/tools/lli/JIT/Emitter.cpp:1.1 llvm/tools/lli/JIT/Emitter.cpp:1.2 --- llvm/tools/lli/JIT/Emitter.cpp:1.1 Mon Dec 23 18:01:04 2002 +++ llvm/tools/lli/JIT/Emitter.cpp Mon Jan 6 12:59:22 2003 @@ -8,6 +8,8 @@ #include "VM.h" #include "llvm/CodeGen/MachineCodeEmitter.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/Target/TargetData.h" #include "llvm/Function.h" #include "Support/Statistic.h" @@ -22,15 +24,18 @@ std::vector > BBRefs; std::map BBLocations; + std::vector ConstantPoolAddresses; public: Emitter(VM &vm) : TheVM(vm) {} virtual void startFunction(MachineFunction &F); virtual void finishFunction(MachineFunction &F); + virtual void emitConstantPool(MachineConstantPool *MCP); virtual void startBasicBlock(MachineBasicBlock &BB); virtual void emitByte(unsigned char B); virtual void emitPCRelativeDisp(Value *V); virtual void emitGlobalAddress(GlobalValue *V); + virtual void emitFunctionConstantValueAddress(unsigned ConstantNum); }; } @@ -44,7 +49,7 @@ #include static void *getMemory() { - return mmap(0, 4096*2, PROT_READ|PROT_WRITE|PROT_EXEC, + return mmap(0, 4096*8, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); } @@ -56,6 +61,7 @@ } void Emitter::finishFunction(MachineFunction &F) { + ConstantPoolAddresses.clear(); for (unsigned i = 0, e = BBRefs.size(); i != e; ++i) { unsigned Location = BBLocations[BBRefs[i].first]; unsigned *Ref = BBRefs[i].second; @@ -66,11 +72,24 @@ NumBytes += CurByte-CurBlock; - DEBUG(std::cerr << "Finished CodeGen of [" << std::hex << (unsigned)CurBlock + DEBUG(std::cerr << "Finished CodeGen of [0x" << std::hex << (unsigned)CurBlock << std::dec << "] Function: " << F.getFunction()->getName() << ": " << CurByte-CurBlock << " bytes of text\n"); } +void Emitter::emitConstantPool(MachineConstantPool *MCP) { + const std::vector &Constants = MCP->getConstants(); + for (unsigned i = 0, e = Constants.size(); i != e; ++i) { + // For now we just allocate some memory on the heap, this can be + // dramatically improved. + const Type *Ty = ((Value*)Constants[i])->getType(); + void *Addr = malloc(TheVM.getTargetData().getTypeSize(Ty)); + TheVM.InitializeMemory(Constants[i], Addr); + ConstantPoolAddresses.push_back(Addr); + } +} + + void Emitter::startBasicBlock(MachineBasicBlock &BB) { BBLocations[BB.getBasicBlock()] = (unsigned)CurByte; } @@ -103,5 +122,12 @@ void Emitter::emitGlobalAddress(GlobalValue *V) { *(void**)CurByte = TheVM.getPointerToGlobal(V); + CurByte += 4; +} + +void Emitter::emitFunctionConstantValueAddress(unsigned ConstantNum) { + assert(ConstantNum < ConstantPoolAddresses.size() && + "Invalid ConstantPoolIndex!"); + *(void**)CurByte = ConstantPoolAddresses[ConstantNum]; CurByte += 4; } From lattner at cs.uiuc.edu Mon Jan 6 13:00:03 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon Jan 6 13:00:03 2003 Subject: [llvm-commits] CVS: llvm/tools/lli/JIT/Callback.cpp Message-ID: <200301061859.MAA26755@apoc.cs.uiuc.edu> Changes in directory llvm/tools/lli/JIT: Callback.cpp updated: 1.1 -> 1.2 --- Log message: Print more info about bad segv's --- Diffs of the changes: Index: llvm/tools/lli/JIT/Callback.cpp diff -u llvm/tools/lli/JIT/Callback.cpp:1.1 llvm/tools/lli/JIT/Callback.cpp:1.2 --- llvm/tools/lli/JIT/Callback.cpp:1.1 Mon Dec 23 18:01:04 2002 +++ llvm/tools/lli/JIT/Callback.cpp Mon Jan 6 12:58:06 2003 @@ -19,7 +19,9 @@ #ifdef REG_EIP /* this code does not compile on Sparc! */ if (SI->si_code != SEGV_MAPERR || SI->si_addr != 0 || ucp->uc_mcontext.gregs[REG_EIP] != 0) { - std::cerr << "Bad SEGV encountered!\n"; + std::cerr << "Bad SEGV encountered EIP = 0x" << std::hex + << ucp->uc_mcontext.gregs[REG_EIP] << " addr = " + << SI->si_addr << "!\n"; abort(); } From lattner at cs.uiuc.edu Sun Jan 12 18:14:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:14:01 2003 Subject: [llvm-commits] CVS: llvm/Makefile.Linux Message-ID: <200301130013.SAA21802@apoc.cs.uiuc.edu> Changes in directory llvm: Makefile.Linux updated: 1.6 -> 1.7 --- Log message: Add an option (which will go away in the future) signfifying that there is a JIT under Linux --- Diffs of the changes: Index: llvm/Makefile.Linux diff -u llvm/Makefile.Linux:1.6 llvm/Makefile.Linux:1.7 --- llvm/Makefile.Linux:1.6 Thu Dec 5 21:45:20 2002 +++ llvm/Makefile.Linux Sun Jan 12 18:13:19 2003 @@ -29,3 +29,9 @@ # LLC itself can be run so disable the diffs, not LLC itself. # DISABLE_LLC_DIFFS := 1 + +# This platform has a JIT compiler! FIXME: This should be changed to be an +# option printed by LLI itself at some point. +# +TARGET_HAS_JIT := 1 + From lattner at cs.uiuc.edu Sun Jan 12 18:17:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:17:01 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/MachineFunction.h Message-ID: <200301130016.SAA21962@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: MachineFunction.h updated: 1.24 -> 1.25 --- Log message: * Add a constant pool to hold per-function constants which must be spilled to memory --- Diffs of the changes: Index: llvm/include/llvm/CodeGen/MachineFunction.h diff -u llvm/include/llvm/CodeGen/MachineFunction.h:1.24 llvm/include/llvm/CodeGen/MachineFunction.h:1.25 --- llvm/include/llvm/CodeGen/MachineFunction.h:1.24 Sat Dec 28 15:08:25 2002 +++ llvm/include/llvm/CodeGen/MachineFunction.h Sun Jan 12 18:16:10 2003 @@ -21,8 +21,9 @@ class SSARegMap; class MachineFunctionInfo; class MachineFrameInfo; +class MachineConstantPool; -Pass *createMachineCodeConstructionPass(TargetMachine &Target); +Pass *createMachineCodeConstructionPass(TargetMachine &TM); Pass *createMachineCodeDestructionPass(); Pass *createMachineFunctionPrinterPass(); @@ -42,8 +43,11 @@ // Keep track of objects allocated on the stack. MachineFrameInfo *FrameInfo; + // Keep track of constants which are spilled to memory + MachineConstantPool *ConstantPool; + public: - MachineFunction(const Function *Fn, const TargetMachine& target); + MachineFunction(const Function *Fn, const TargetMachine &TM); ~MachineFunction(); /// getFunction - Return the LLVM function that this machine code represents @@ -66,6 +70,10 @@ /// MachineFrameInfo *getFrameInfo() const { return FrameInfo; } + /// getConstantPool - Return the constant pool object for the current + /// function. + MachineConstantPool *getConstantPool() const { return ConstantPool; } + /// MachineFunctionInfo - Keep track of various per-function pieces of /// information for the sparc backend. /// @@ -90,8 +98,7 @@ // for a given Method. // destruct() -- Destroy the MachineFunction object // - static MachineFunction& construct(const Function *Fn, - const TargetMachine &target); + static MachineFunction& construct(const Function *F, const TargetMachine &TM); static void destruct(const Function *F); static MachineFunction& get(const Function *F); From lattner at cs.uiuc.edu Sun Jan 12 18:19:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:19:00 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/MachineInstrBuilder.h Message-ID: <200301130018.SAA22212@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: MachineInstrBuilder.h updated: 1.10 -> 1.11 --- Log message: * Add support for new types of operands --- Diffs of the changes: Index: llvm/include/llvm/CodeGen/MachineInstrBuilder.h diff -u llvm/include/llvm/CodeGen/MachineInstrBuilder.h:1.10 llvm/include/llvm/CodeGen/MachineInstrBuilder.h:1.11 --- llvm/include/llvm/CodeGen/MachineInstrBuilder.h:1.10 Tue Dec 24 23:01:18 2002 +++ llvm/include/llvm/CodeGen/MachineInstrBuilder.h Sun Jan 12 18:18:44 2003 @@ -18,9 +18,9 @@ #include "llvm/CodeGen/MachineInstr.h" -struct MachineInstrBuilder { +class MachineInstrBuilder { MachineInstr *MI; - +public: MachineInstrBuilder(MachineInstr *mi) : MI(mi) {} /// Allow automatic conversion to the machine instruction we are working on. @@ -89,6 +89,23 @@ const MachineInstrBuilder &addFrameIndex(unsigned Idx) const { MI->addFrameIndexOperand(Idx); + return *this; + } + + const MachineInstrBuilder &addConstantPoolIndex(unsigned Idx) const { + MI->addConstantPoolIndexOperand(Idx); + return *this; + } + + const MachineInstrBuilder &addGlobalAddress(GlobalValue *GV, + bool isPCRelative = false) const { + MI->addGlobalAddressOperand(GV, isPCRelative); + return *this; + } + + const MachineInstrBuilder &addExternalSymbol(const std::string &Name, + bool isPCRelative = false) const{ + MI->addExternalSymbolOperand(Name, isPCRelative); return *this; } }; From lattner at cs.uiuc.edu Sun Jan 12 18:19:02 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:19:02 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/MachineInstr.h Message-ID: <200301130018.SAA22217@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: MachineInstr.h updated: 1.94 -> 1.95 --- Log message: * Add 3 new types of MachineOperand: ConstantPoolIndex ExternalSymbol and GlobalAddress's * Add new isPCRelative modifier flag which should be used in place of MO_PCRelativeDisp type. * Fix a bug in isPhysicalRegister * Add new setOpcode and RemoveOperand methods --- Diffs of the changes: Index: llvm/include/llvm/CodeGen/MachineInstr.h diff -u llvm/include/llvm/CodeGen/MachineInstr.h:1.94 llvm/include/llvm/CodeGen/MachineInstr.h:1.95 --- llvm/include/llvm/CodeGen/MachineInstr.h:1.94 Sat Dec 28 14:05:44 2002 +++ llvm/include/llvm/CodeGen/MachineInstr.h Sun Jan 12 18:18:17 2003 @@ -18,6 +18,7 @@ class Function; class MachineBasicBlock; class TargetMachine; +class GlobalValue; typedef int MachineOpCode; @@ -70,8 +71,7 @@ // //--------------------------------------------------------------------------- -class MachineOperand { -public: +struct MachineOperand { enum MachineOperandType { MO_VirtualRegister, // virtual register for *value MO_MachineRegister, // pre-assigned machine register `regNum' @@ -81,29 +81,38 @@ MO_PCRelativeDisp, MO_MachineBasicBlock, // MachineBasicBlock reference MO_FrameIndex, // Abstract Stack Frame Index + MO_ConstantPoolIndex, // Address of indexed Constant in Constant Pool + MO_ExternalSymbol, // Name of external global symbol + MO_GlobalAddress, // Address of a global value }; private: // Bit fields of the flags variable used for different operand properties - static const char DEFFLAG = 0x01; // this is a def of the operand - static const char DEFUSEFLAG = 0x02; // this is both a def and a use - static const char HIFLAG32 = 0x04; // operand is %hi32(value_or_immedVal) - static const char LOFLAG32 = 0x08; // operand is %lo32(value_or_immedVal) - static const char HIFLAG64 = 0x10; // operand is %hi64(value_or_immedVal) - static const char LOFLAG64 = 0x20; // operand is %lo64(value_or_immedVal) - - static const char USEDEFMASK = 0x03; + enum { + DEFFLAG = 0x01, // this is a def of the operand + DEFUSEFLAG = 0x02, // this is both a def and a use + HIFLAG32 = 0x04, // operand is %hi32(value_or_immedVal) + LOFLAG32 = 0x08, // operand is %lo32(value_or_immedVal) + HIFLAG64 = 0x10, // operand is %hi64(value_or_immedVal) + LOFLAG64 = 0x20, // operand is %lo64(value_or_immedVal) + PCRELATIVE = 0x40, // Operand is relative to PC, not a global address + USEDEFMASK = 0x03, + }; + private: union { Value* value; // BasicBlockVal for a label operand. // ConstantVal for a non-address immediate. // Virtual register for an SSA operand, - // including hidden operands required for - // the generated machine code. - int64_t immedVal; // constant value for an explicit constant + // including hidden operands required for + // the generated machine code. + // LLVM global for MO_GlobalAddress. + + int64_t immedVal; // Constant value for an explicit constant MachineBasicBlock *MBB; // For MO_MachineBasicBlock type + std::string *SymbolName; // For MO_ExternalSymbol type }; char flags; // see bit field definitions above @@ -135,7 +144,8 @@ } } - MachineOperand(Value *V, MachineOperandType OpTy, MOTy::UseType UseTy) + MachineOperand(Value *V, MachineOperandType OpTy, MOTy::UseType UseTy, + bool isPCRelative = false) : value(V), opType(OpTy), regNum(-1) { switch (UseTy) { case MOTy::Use: flags = 0; break; @@ -143,25 +153,52 @@ case MOTy::UseAndDef: flags = DEFUSEFLAG; break; default: assert(0 && "Invalid value for UseTy!"); } + if (isPCRelative) flags |= PCRELATIVE; } MachineOperand(MachineBasicBlock *mbb) : MBB(mbb), flags(0), opType(MO_MachineBasicBlock), regNum(-1) {} + MachineOperand(const std::string &SymName, bool isPCRelative) + : SymbolName(new std::string(SymName)), flags(isPCRelative ? PCRELATIVE :0), + opType(MO_ExternalSymbol), regNum(-1) {} + public: - MachineOperand(const MachineOperand &M) - : immedVal(M.immedVal), - flags(M.flags), - opType(M.opType), - regNum(M.regNum) {} + MachineOperand(const MachineOperand &M) : immedVal(M.immedVal), + flags(M.flags), + opType(M.opType), + regNum(M.regNum) { + if (isExternalSymbol()) + SymbolName = new std::string(M.getSymbolName()); + } - ~MachineOperand() {} + ~MachineOperand() { + if (isExternalSymbol()) + delete SymbolName; + } + const MachineOperand &operator=(const MachineOperand &MO) { + immedVal = MO.immedVal; + flags = MO.flags; + opType = MO.opType; + regNum = MO.regNum; + if (isExternalSymbol()) + SymbolName = new std::string(MO.getSymbolName()); + return *this; + } + // Accessor methods. Caller is responsible for checking the // operand type before invoking the corresponding accessor. // MachineOperandType getType() const { return opType; } + /// isPCRelative - This returns the value of the PCRELATIVE flag, which + /// indicates whether this operand should be emitted as a PC relative value + /// instead of a global address. This is used for operands of the forms: + /// MachineBasicBlock, GlobalAddress, ExternalSymbol + /// + bool isPCRelative() const { return (flags & PCRELATIVE) != 0; } + // This is to finally stop caring whether we have a virtual or machine // register -- an easier interface is to simply call both virtual and machine @@ -174,7 +211,7 @@ } bool isPhysicalRegister() const { return (opType == MO_VirtualRegister || opType == MO_MachineRegister) - && regNum < MRegisterInfo::FirstVirtualRegister; + && (unsigned)regNum < MRegisterInfo::FirstVirtualRegister; } bool isRegister() const { return isVirtualRegister() || isPhysicalRegister();} bool isMachineRegister() const { return !isVirtualRegister(); } @@ -184,6 +221,9 @@ return opType == MO_SignExtendedImmed || opType == MO_UnextendedImmed; } bool isFrameIndex() const { return opType == MO_FrameIndex; } + bool isConstantPoolIndex() const { return opType == MO_ConstantPoolIndex; } + bool isGlobalAddress() const { return opType == MO_GlobalAddress; } + bool isExternalSymbol() const { return opType == MO_ExternalSymbol; } Value* getVRegValue() const { assert(opType == MO_VirtualRegister || opType == MO_CCRegister || @@ -204,6 +244,20 @@ return MBB; } int getFrameIndex() const { assert(isFrameIndex()); return immedVal; } + unsigned getConstantPoolIndex() const { + assert(isConstantPoolIndex()); + return immedVal; + } + + GlobalValue *getGlobal() const { + assert(isGlobalAddress()); + return (GlobalValue*)value; + } + + const std::string &getSymbolName() const { + assert(isExternalSymbol()); + return *SymbolName; + } bool opIsUse () const { return (flags & USEDEFMASK) == 0; } bool opIsDef () const { return flags & DEFFLAG; } @@ -412,11 +466,12 @@ !isDef ? MOTy::Use : (isDefAndUse ? MOTy::UseAndDef : MOTy::Def))); } - void addRegOperand(Value *V, MOTy::UseType UTy = MOTy::Use) { + void addRegOperand(Value *V, MOTy::UseType UTy = MOTy::Use, + bool isPCRelative = false) { assert(!OperandsComplete() && "Trying to add an operand to a machine instr that is already done!"); operands.push_back(MachineOperand(V, MachineOperand::MO_VirtualRegister, - UTy)); + UTy, isPCRelative)); } /// addRegOperand - Add a symbolic virtual register reference... @@ -500,6 +555,28 @@ operands.push_back(MachineOperand(Idx, MachineOperand::MO_FrameIndex)); } + /// addConstantPoolndexOperand - Add a constant pool object index to the + /// instruction. + /// + void addConstantPoolIndexOperand(unsigned I) { + assert(!OperandsComplete() && + "Trying to add an operand to a machine instr that is already done!"); + operands.push_back(MachineOperand(I, MachineOperand::MO_ConstantPoolIndex)); + } + + void addGlobalAddressOperand(GlobalValue *GV, bool isPCRelative) { + assert(!OperandsComplete() && + "Trying to add an operand to a machine instr that is already done!"); + operands.push_back(MachineOperand((Value*)GV, + MachineOperand::MO_GlobalAddress, + MOTy::Use, isPCRelative)); + } + + /// addExternalSymbolOperand - Add an external symbol operand to this instr + /// + void addExternalSymbolOperand(const std::string &SymName, bool isPCRelative) { + operands.push_back(MachineOperand(SymName, isPCRelative)); + } //===--------------------------------------------------------------------===// // Accessors used to modify instructions in place. @@ -511,6 +588,17 @@ /// below. /// void replace(MachineOpCode Opcode, unsigned numOperands); + + /// setOpcode - Replace the opcode of the current instruction with a new one. + /// + void setOpcode(unsigned Op) { opCode = Op; } + + /// RemoveOperand - Erase an operand from an instruction, leaving it with one + /// fewer operand than it started with. + /// + void RemoveOperand(unsigned i) { + operands.erase(operands.begin()+i); + } // Access to set the operands when building the machine instruction // From lattner at cs.uiuc.edu Sun Jan 12 18:20:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:20:00 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/MachineFrameInfo.h Message-ID: <200301130019.SAA22222@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: MachineFrameInfo.h updated: 1.2 -> 1.3 --- Log message: * Add utility methods which make common cases easier --- Diffs of the changes: Index: llvm/include/llvm/CodeGen/MachineFrameInfo.h diff -u llvm/include/llvm/CodeGen/MachineFrameInfo.h:1.2 llvm/include/llvm/CodeGen/MachineFrameInfo.h:1.3 --- llvm/include/llvm/CodeGen/MachineFrameInfo.h:1.2 Sat Dec 28 15:08:25 2002 +++ llvm/include/llvm/CodeGen/MachineFrameInfo.h Sun Jan 12 18:15:24 2003 @@ -28,8 +28,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CODEGEN_FUNCTIONFRAMEINFO_H -#define LLVM_CODEGEN_FUNCTIONFRAMEINFO_H +#ifndef LLVM_CODEGEN_MACHINEFRAMEINFO_H +#define LLVM_CODEGEN_MACHINEFRAMEINFO_H + +class TargetData; +class TargetRegisterClass; +#include class MachineFrameInfo { @@ -180,6 +184,12 @@ Objects.push_back(StackObject(Size, Alignment, -1)); return Objects.size()-NumFixedObjects-1; } + + /// CreateStackObject - Create a stack object for a value of the specified + /// LLVM type or register class. + /// + int CreateStackObject(const Type *Ty, const TargetData &TD); + int CreateStackObject(const TargetRegisterClass *RC); /// CreateVariableSizedObject - Notify the MachineFrameInfo object that a /// variable sized object has been created. This must be created whenever a From lattner at cs.uiuc.edu Sun Jan 12 18:20:03 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:20:03 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/MachineCodeEmitter.h Message-ID: <200301130019.SAA22227@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: MachineCodeEmitter.h updated: 1.5 -> 1.6 --- Log message: * Add support for values in the constant pool * Add support for functions referenced by name --- Diffs of the changes: Index: llvm/include/llvm/CodeGen/MachineCodeEmitter.h diff -u llvm/include/llvm/CodeGen/MachineCodeEmitter.h:1.5 llvm/include/llvm/CodeGen/MachineCodeEmitter.h:1.6 --- llvm/include/llvm/CodeGen/MachineCodeEmitter.h:1.5 Wed Dec 4 00:44:27 2002 +++ llvm/include/llvm/CodeGen/MachineCodeEmitter.h Sun Jan 12 18:14:55 2003 @@ -10,8 +10,10 @@ #ifndef LLVM_CODEGEN_MACHINE_CODE_EMITTER_H #define LLVM_CODEGEN_MACHINE_CODE_EMITTER_H +#include class MachineFunction; class MachineBasicBlock; +class MachineConstantPool; class Value; class GlobalValue; @@ -28,6 +30,10 @@ /// virtual void finishFunction(MachineFunction &F) {} + /// emitConstantPool - This callback is invoked to output the constant pool + /// for the function. + virtual void emitConstantPool(MachineConstantPool *MCP) {} + /// startBasicBlock - This callback is invoked when a new basic block is about /// to be emitted. /// @@ -48,8 +54,17 @@ /// address of a global value to machine code. This is important for indirect /// calls as well as accessing global variables. /// - virtual void emitGlobalAddress(GlobalValue *V) {} + virtual void emitGlobalAddress(GlobalValue *V, bool isPCRelative) {} + virtual void emitGlobalAddress(const std::string &Name, bool isPCRelative) {} + /// emitFunctionConstantValueAddress - This callback is invoked when the + /// address of a constant, which was spilled to memory, needs to be addressed. + /// This is used for constants which cannot be directly specified as operands + /// to instructions, such as large integer values on the sparc, or floating + /// point constants on the X86. + /// + virtual void emitFunctionConstantValueAddress(unsigned ConstantNum, + int Offset) {} /// createDebugMachineCodeEmitter - Return a dynamically allocated machine /// code emitter, which just prints the opcodes and fields out the cout. This From lattner at cs.uiuc.edu Sun Jan 12 18:20:05 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:20:05 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/SSARegMap.h Message-ID: <200301130019.SAA22238@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: SSARegMap.h updated: 1.2 -> 1.3 --- Log message: Simplify interface to creating a register --- Diffs of the changes: Index: llvm/include/llvm/CodeGen/SSARegMap.h diff -u llvm/include/llvm/CodeGen/SSARegMap.h:1.2 llvm/include/llvm/CodeGen/SSARegMap.h:1.3 --- llvm/include/llvm/CodeGen/SSARegMap.h:1.2 Tue Dec 24 23:01:05 2002 +++ llvm/include/llvm/CodeGen/SSARegMap.h Sun Jan 12 18:19:18 2003 @@ -28,10 +28,12 @@ return RegClassMap[actualReg]; } - void addRegMap(unsigned Reg, const TargetRegisterClass* RegClass) { - assert(rescale(Reg) == RegClassMap.size() && - "Register mapping not added in sequential order!"); + /// createVirtualRegister - Create and return a new virtual register in the + /// function with the specified register class. + /// + unsigned createVirtualRegister(const TargetRegisterClass *RegClass) { RegClassMap.push_back(RegClass); + return RegClassMap.size()+MRegisterInfo::FirstVirtualRegister-1; } }; From lattner at cs.uiuc.edu Sun Jan 12 18:22:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:22:01 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/Target/TargetMachine.h Message-ID: <200301130021.SAA22264@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/Target: TargetMachine.h updated: 1.28 -> 1.29 --- Log message: Rename MachineInstrInfo -> TargetInstrInfo --- Diffs of the changes: Index: llvm/include/llvm/Target/TargetMachine.h diff -u llvm/include/llvm/Target/TargetMachine.h:1.28 llvm/include/llvm/Target/TargetMachine.h:1.29 --- llvm/include/llvm/Target/TargetMachine.h:1.28 Sat Dec 28 21:12:54 2002 +++ llvm/include/llvm/Target/TargetMachine.h Sun Jan 12 18:21:32 2003 @@ -10,8 +10,8 @@ #include "llvm/Target/TargetData.h" #include "Support/NonCopyable.h" -class MachineInstrInfo; -class MachineInstrDescriptor; +class TargetInstrInfo; +class TargetInstrDescriptor; class TargetSchedInfo; class TargetRegInfo; class TargetFrameInfo; @@ -56,7 +56,7 @@ // -- Cache hierarchy information // -- Machine-level optimization information (peephole only) // - virtual const MachineInstrInfo& getInstrInfo() const = 0; + virtual const TargetInstrInfo& getInstrInfo() const = 0; virtual const TargetSchedInfo& getSchedInfo() const = 0; virtual const TargetRegInfo& getRegInfo() const = 0; virtual const TargetFrameInfo& getFrameInfo() const = 0; From lattner at cs.uiuc.edu Sun Jan 12 18:22:03 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:22:03 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/Target/MRegisterInfo.h Message-ID: <200301130021.SAA22336@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/Target: MRegisterInfo.h updated: 1.15 -> 1.16 --- Log message: Add new getName method --- Diffs of the changes: Index: llvm/include/llvm/Target/MRegisterInfo.h diff -u llvm/include/llvm/Target/MRegisterInfo.h:1.15 llvm/include/llvm/Target/MRegisterInfo.h:1.16 --- llvm/include/llvm/Target/MRegisterInfo.h:1.15 Sat Dec 28 14:10:23 2002 +++ llvm/include/llvm/Target/MRegisterInfo.h Sun Jan 12 18:19:44 2003 @@ -33,6 +33,7 @@ /// namespace MRF { // MRF = Machine Register Flags enum { + Other = 0 << 0, // This is a non-standard register INT8 = 1 << 0, // This is an 8 bit integer register INT16 = 1 << 1, // This is a 16 bit integer register INT32 = 1 << 2, // This is a 32 bit integer register @@ -171,6 +172,12 @@ /// const unsigned *getAliasSet(unsigned RegNo) const { return get(RegNo).AliasSet; + } + + /// getName - Return the symbolic target specific name for the specified + /// physical register. + const char *getName(unsigned RegNo) const { + return get(RegNo).Name; } virtual const unsigned* getCalleeSaveRegs() const = 0; From lattner at cs.uiuc.edu Sun Jan 12 18:22:05 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:22:05 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/Target/MachineInstrInfo.h Message-ID: <200301130021.SAA22342@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/Target: MachineInstrInfo.h updated: 1.40 -> 1.41 --- Log message: * Start renaming MachineInstrInfo -> TargetInstrInfo * Add new M_TERMINATOR_FLAG --- Diffs of the changes: Index: llvm/include/llvm/Target/MachineInstrInfo.h diff -u llvm/include/llvm/Target/MachineInstrInfo.h:1.40 llvm/include/llvm/Target/MachineInstrInfo.h:1.41 --- llvm/include/llvm/Target/MachineInstrInfo.h:1.40 Sat Dec 28 14:12:54 2002 +++ llvm/include/llvm/Target/MachineInstrInfo.h Sun Jan 12 18:21:19 2003 @@ -1,4 +1,4 @@ -//===-- llvm/Target/MachineInstrInstrInfo.h - Instruction Infor ---*-C++-*-===// +//===-- llvm/Target/TargetInstrInfo.h - Instruction Info --------*- C++ -*-===// // // This file describes the target machine instructions to the code generator. // @@ -10,7 +10,6 @@ #include "Support/DataTypes.h" #include -class MachineInstrDescriptor; class MachineInstr; class TargetMachine; class Value; @@ -39,25 +38,31 @@ // //--------------------------------------------------------------------------- -const unsigned M_NOP_FLAG = 1 << 0; -const unsigned M_BRANCH_FLAG = 1 << 1; -const unsigned M_CALL_FLAG = 1 << 2; -const unsigned M_RET_FLAG = 1 << 3; -const unsigned M_ARITH_FLAG = 1 << 4; -const unsigned M_CC_FLAG = 1 << 6; -const unsigned M_LOGICAL_FLAG = 1 << 6; -const unsigned M_INT_FLAG = 1 << 7; -const unsigned M_FLOAT_FLAG = 1 << 8; -const unsigned M_CONDL_FLAG = 1 << 9; -const unsigned M_LOAD_FLAG = 1 << 10; -const unsigned M_PREFETCH_FLAG = 1 << 11; -const unsigned M_STORE_FLAG = 1 << 12; -const unsigned M_DUMMY_PHI_FLAG = 1 << 13; -const unsigned M_PSEUDO_FLAG = 1 << 14; // Pseudo instruction +const unsigned M_NOP_FLAG = 1 << 0; +const unsigned M_BRANCH_FLAG = 1 << 1; +const unsigned M_CALL_FLAG = 1 << 2; +const unsigned M_RET_FLAG = 1 << 3; +const unsigned M_ARITH_FLAG = 1 << 4; +const unsigned M_CC_FLAG = 1 << 6; +const unsigned M_LOGICAL_FLAG = 1 << 6; +const unsigned M_INT_FLAG = 1 << 7; +const unsigned M_FLOAT_FLAG = 1 << 8; +const unsigned M_CONDL_FLAG = 1 << 9; +const unsigned M_LOAD_FLAG = 1 << 10; +const unsigned M_PREFETCH_FLAG = 1 << 11; +const unsigned M_STORE_FLAG = 1 << 12; +const unsigned M_DUMMY_PHI_FLAG = 1 << 13; +const unsigned M_PSEUDO_FLAG = 1 << 14; // Pseudo instruction // 3-addr instructions which really work like 2-addr ones, eg. X86 add/sub -const unsigned M_2_ADDR_FLAG = 1 << 15; +const unsigned M_2_ADDR_FLAG = 1 << 15; -struct MachineInstrDescriptor { +// M_TERMINATOR_FLAG - Is this instruction part of the terminator for a basic +// block? Typically this is things like return and branch instructions. +// Various passes use this to insert code into the bottom of a basic block, but +// before control flow occurs. +const unsigned M_TERMINATOR_FLAG = 1 << 16; + +struct TargetInstrDescriptor { const char * Name; // Assembly language mnemonic for the opcode. int numOperands; // Number of args; -1 if variable #args int resultPos; // Position of the result; -1 if no result @@ -73,18 +78,19 @@ const unsigned *ImplicitDefs; // Registers implicitly defined by this instr }; +typedef TargetInstrDescriptor MachineInstrDescriptor; -class MachineInstrInfo { - const MachineInstrDescriptor* desc; // raw array to allow static init'n - unsigned descSize; // number of entries in the desc array - unsigned numRealOpCodes; // number of non-dummy op codes +class TargetInstrInfo { + const TargetInstrDescriptor* desc; // raw array to allow static init'n + unsigned descSize; // number of entries in the desc array + unsigned numRealOpCodes; // number of non-dummy op codes - MachineInstrInfo(const MachineInstrInfo &); // DO NOT IMPLEMENT - void operator=(const MachineInstrInfo &); // DO NOT IMPLEMENT + TargetInstrInfo(const TargetInstrInfo &); // DO NOT IMPLEMENT + void operator=(const TargetInstrInfo &); // DO NOT IMPLEMENT public: - MachineInstrInfo(const MachineInstrDescriptor *desc, unsigned descSize, - unsigned numRealOpCodes); - virtual ~MachineInstrInfo(); + TargetInstrInfo(const TargetInstrDescriptor *desc, unsigned descSize, + unsigned numRealOpCodes); + virtual ~TargetInstrInfo(); // Invariant: All instruction sets use opcode #0 as the PHI instruction and // opcode #1 as the noop instruction. @@ -98,7 +104,7 @@ /// get - Return the machine instruction descriptor that corresponds to the /// specified instruction opcode. /// - const MachineInstrDescriptor& get(MachineOpCode opCode) const { + const TargetInstrDescriptor& get(MachineOpCode opCode) const { assert(opCode >= 0 && opCode < (int)descSize); return desc[opCode]; } @@ -187,15 +193,18 @@ || get(opCode).Flags & M_PREFETCH_FLAG || get(opCode).Flags & M_STORE_FLAG; } - bool isDummyPhiInstr(const MachineOpCode opCode) const { + bool isDummyPhiInstr(MachineOpCode opCode) const { return get(opCode).Flags & M_DUMMY_PHI_FLAG; } - bool isPseudoInstr(const MachineOpCode opCode) const { + bool isPseudoInstr(MachineOpCode opCode) const { return get(opCode).Flags & M_PSEUDO_FLAG; } - bool isTwoAddrInstr(const MachineOpCode opCode) const { + bool isTwoAddrInstr(MachineOpCode opCode) const { return get(opCode).Flags & M_2_ADDR_FLAG; } + bool isTerminatorInstr(unsigned Opcode) const { + return get(Opcode).Flags & M_TERMINATOR_FLAG; + } // Check if an instruction can be issued before its operands are ready, // or if a subsequent instruction that uses its result can be issued @@ -371,5 +380,7 @@ abort(); } }; + +typedef TargetInstrInfo MachineInstrInfo; #endif From lattner at cs.uiuc.edu Sun Jan 12 18:24:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:24:00 2003 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/MachineFunction.cpp Message-ID: <200301130023.SAA22378@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: MachineFunction.cpp updated: 1.36 -> 1.37 --- Log message: Add support for constant pool Add helper methods for MachineFrameInfo --- Diffs of the changes: Index: llvm/lib/CodeGen/MachineFunction.cpp diff -u llvm/lib/CodeGen/MachineFunction.cpp:1.36 llvm/lib/CodeGen/MachineFunction.cpp:1.37 --- llvm/lib/CodeGen/MachineFunction.cpp:1.36 Sat Dec 28 20:50:27 2002 +++ llvm/lib/CodeGen/MachineFunction.cpp Sun Jan 12 18:23:03 2003 @@ -12,6 +12,7 @@ #include "llvm/CodeGen/SSARegMap.h" #include "llvm/CodeGen/MachineFunctionInfo.h" #include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetFrameInfo.h" #include "llvm/Target/TargetCacheInfo.h" @@ -102,12 +103,14 @@ SSARegMapping = new SSARegMap(); MFInfo = new MachineFunctionInfo(*this); FrameInfo = new MachineFrameInfo(); + ConstantPool = new MachineConstantPool(); } MachineFunction::~MachineFunction() { delete SSARegMapping; delete MFInfo; delete FrameInfo; + delete ConstantPool; } void MachineFunction::dump() const { print(std::cerr); } @@ -118,6 +121,9 @@ // Print Frame Information getFrameInfo()->print(OS); + + // Print Constant Pool + getConstantPool()->print(OS); for (const_iterator BB = begin(); BB != end(); ++BB) { BasicBlock *LBB = BB->getBasicBlock(); @@ -171,10 +177,21 @@ // MachineFrameInfo implementation //===----------------------------------------------------------------------===// +/// CreateStackObject - Create a stack object for a value of the specified type. +/// +int MachineFrameInfo::CreateStackObject(const Type *Ty, const TargetData &TD) { + return CreateStackObject(TD.getTypeSize(Ty), TD.getTypeAlignment(Ty)); +} + +int MachineFrameInfo::CreateStackObject(const TargetRegisterClass *RC) { + return CreateStackObject(RC->getSize(), RC->getAlignment()); +} + + void MachineFrameInfo::print(std::ostream &OS) const { for (unsigned i = 0, e = Objects.size(); i != e; ++i) { const StackObject &SO = Objects[i]; - OS << " is "; + OS << " is "; if (SO.Size == 0) OS << "variable sized"; else @@ -199,6 +216,17 @@ void MachineFrameInfo::dump() const { print(std::cerr); } + +//===----------------------------------------------------------------------===// +// MachineConstantPool implementation +//===----------------------------------------------------------------------===// + +void MachineConstantPool::print(std::ostream &OS) const { + for (unsigned i = 0, e = Constants.size(); i != e; ++i) + OS << " is" << *(Value*)Constants[i] << "\n"; +} + +void MachineConstantPool::dump() const { print(std::cerr); } //===----------------------------------------------------------------------===// // MachineFunctionInfo implementation From lattner at cs.uiuc.edu Sun Jan 12 18:24:03 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:24:03 2003 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/MachineCodeEmitter.cpp Message-ID: <200301130023.SAA22385@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: MachineCodeEmitter.cpp updated: 1.2 -> 1.3 --- Log message: Add support for global address by string and constant pool values --- Diffs of the changes: Index: llvm/lib/CodeGen/MachineCodeEmitter.cpp diff -u llvm/lib/CodeGen/MachineCodeEmitter.cpp:1.2 llvm/lib/CodeGen/MachineCodeEmitter.cpp:1.3 --- llvm/lib/CodeGen/MachineCodeEmitter.cpp:1.2 Wed Dec 4 00:44:41 2002 +++ llvm/lib/CodeGen/MachineCodeEmitter.cpp Sun Jan 12 18:22:37 2003 @@ -28,8 +28,17 @@ void emitPCRelativeDisp(Value *V) { std::cout << "getName() << ": 0xXX 0xXX 0xXX 0xXX> "; } - void emitGlobalAddress(GlobalValue *V) { + void emitGlobalAddress(GlobalValue *V, bool isPCRelative) { std::cout << "getName() << ": 0xXX 0xXX 0xXX 0xXX> "; + } + void emitGlobalAddress(const std::string &Name, bool isPCRelative) { + std::cout << " "; + } + + void emitFunctionConstantValueAddress(unsigned ConstantNum, int Offset) { + std::cout << " "; } }; } From lattner at cs.uiuc.edu Sun Jan 12 18:24:05 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:24:05 2003 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/PrologEpilogInserter.cpp Message-ID: <200301130023.SAA22392@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: PrologEpilogInserter.cpp updated: 1.3 -> 1.4 --- Log message: Convert to MachineFunctionPass --- Diffs of the changes: Index: llvm/lib/CodeGen/PrologEpilogInserter.cpp diff -u llvm/lib/CodeGen/PrologEpilogInserter.cpp:1.3 llvm/lib/CodeGen/PrologEpilogInserter.cpp:1.4 --- llvm/lib/CodeGen/PrologEpilogInserter.cpp:1.3 Sat Dec 28 15:08:26 2002 +++ llvm/lib/CodeGen/PrologEpilogInserter.cpp Sun Jan 12 18:23:41 2003 @@ -9,8 +9,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Pass.h" -#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/Target/TargetMachine.h" @@ -19,9 +19,9 @@ #include "llvm/Target/MachineInstrInfo.h" namespace { - struct PEI : public FunctionPass { - bool runOnFunction(Function &Fn) { - return runOnMachineFunction(MachineFunction::get(&Fn)); + struct PEI : public MachineFunctionPass { + const char *getPassName() const { + return "Prolog/Epilog Insertion & Frame Finalization"; } /// runOnMachineFunction - Insert prolog/epilog code and replace abstract @@ -141,8 +141,7 @@ // stack slots for them. std::vector StackSlots; for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) { - const TargetRegisterClass *RC = RegInfo->getRegClass(RegsToSave[i]); - int FrameIdx = FFI->CreateStackObject(RC->getSize(), RC->getAlignment()); + int FrameIdx = FFI->CreateStackObject(RegInfo->getRegClass(RegsToSave[i])); StackSlots.push_back(FrameIdx); } From lattner at cs.uiuc.edu Sun Jan 12 18:25:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:25:01 2003 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/MachineInstr.cpp Message-ID: <200301130024.SAA22397@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: MachineInstr.cpp updated: 1.67 -> 1.68 --- Log message: Add support for 3 new forms of MachineOperand --- Diffs of the changes: Index: llvm/lib/CodeGen/MachineInstr.cpp diff -u llvm/lib/CodeGen/MachineInstr.cpp:1.67 llvm/lib/CodeGen/MachineInstr.cpp:1.68 --- llvm/lib/CodeGen/MachineInstr.cpp:1.67 Sat Dec 28 14:37:37 2002 +++ llvm/lib/CodeGen/MachineInstr.cpp Sun Jan 12 18:23:24 2003 @@ -10,6 +10,7 @@ #include "llvm/Target/MRegisterInfo.h" using std::cerr; + // Global variable holding an array of descriptors for machine instructions. // The actual object needs to be created separately for each target machine. // This variable is initialized and reset by class MachineInstrInfo. @@ -268,6 +269,15 @@ case MachineOperand::MO_FrameIndex: OS << ""; break; + case MachineOperand::MO_ConstantPoolIndex: + OS << ""; + break; + case MachineOperand::MO_GlobalAddress: + OS << "getName() << ">"; + break; + case MachineOperand::MO_ExternalSymbol: + OS << ""; + break; default: assert(0 && "Unrecognized operand type"); } @@ -316,26 +326,26 @@ } -std::ostream &operator<<(std::ostream& os, const MachineInstr& minstr) +std::ostream &operator<<(std::ostream& os, const MachineInstr& MI) { - os << TargetInstrDescriptors[minstr.opCode].Name; + os << TargetInstrDescriptors[MI.opCode].Name; - for (unsigned i=0, N=minstr.getNumOperands(); i < N; i++) { - os << "\t" << minstr.getOperand(i); - if( minstr.operandIsDefined(i) ) - os << "*"; - if( minstr.operandIsDefinedAndUsed(i) ) - os << "*"; + for (unsigned i=0, N=MI.getNumOperands(); i < N; i++) { + os << "\t" << MI.getOperand(i); + if (MI.operandIsDefined(i)) + os << ""; + if (MI.operandIsDefinedAndUsed(i)) + os << ""; } // code for printing implict references - unsigned NumOfImpRefs = minstr.getNumImplicitRefs(); - if( NumOfImpRefs > 0 ) { + unsigned NumOfImpRefs = MI.getNumImplicitRefs(); + if (NumOfImpRefs > 0) { os << "\tImplicit: "; - for(unsigned z=0; z < NumOfImpRefs; z++) { - OutputValue(os, minstr.getImplicitRef(z)); - if( minstr.implicitRefIsDefined(z)) os << "*"; - if( minstr.implicitRefIsDefinedAndUsed(z)) os << "*"; + for (unsigned z=0; z < NumOfImpRefs; z++) { + OutputValue(os, MI.getImplicitRef(z)); + if (MI.implicitRefIsDefined(z)) os << ""; + if (MI.implicitRefIsDefinedAndUsed(z)) os << ""; os << "\t"; } } @@ -357,11 +367,13 @@ switch (MO.getType()) { case MachineOperand::MO_VirtualRegister: - OS << "%reg"; - OutputValue(OS, MO.getVRegValue()); - if (MO.hasAllocatedReg()) { - OS << "=="; + if (MO.hasAllocatedReg()) OutputReg(OS, MO.getAllocatedRegNum()); + + if (MO.getVRegValue()) { + if (MO.hasAllocatedReg()) OS << "=="; + OS << "%vreg"; + OutputValue(OS, MO.getVRegValue()); } break; case MachineOperand::MO_CCRegister: @@ -400,6 +412,15 @@ break; case MachineOperand::MO_FrameIndex: OS << ""; + break; + case MachineOperand::MO_ConstantPoolIndex: + OS << ""; + break; + case MachineOperand::MO_GlobalAddress: + OS << "getName() << ">"; + break; + case MachineOperand::MO_ExternalSymbol: + OS << ""; break; default: assert(0 && "Unrecognized operand type"); From lattner at cs.uiuc.edu Sun Jan 12 18:27:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:27:01 2003 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/RegAllocSimple.cpp Message-ID: <200301130026.SAA22415@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: RegAllocSimple.cpp updated: 1.36 -> 1.37 --- Log message: * Use the PHI Elimination pass --- Diffs of the changes: Index: llvm/lib/CodeGen/RegAllocSimple.cpp diff -u llvm/lib/CodeGen/RegAllocSimple.cpp:1.36 llvm/lib/CodeGen/RegAllocSimple.cpp:1.37 --- llvm/lib/CodeGen/RegAllocSimple.cpp:1.36 Sat Dec 28 15:08:26 2002 +++ llvm/lib/CodeGen/RegAllocSimple.cpp Sun Jan 12 18:26:08 2003 @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/SSARegMap.h" @@ -46,14 +47,14 @@ /// runOnMachineFunction - Register allocate the whole function bool runOnMachineFunction(MachineFunction &Fn); + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequiredID(PHIEliminationID); // Eliminate PHI nodes + MachineFunctionPass::getAnalysisUsage(AU); + } private: /// AllocateBasicBlock - Register allocate the specified basic block. void AllocateBasicBlock(MachineBasicBlock &MBB); - /// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions - /// in predecessor basic blocks. - void EliminatePHINodes(MachineBasicBlock &MBB); - /// getStackSpaceFor - This returns the offset of the specified virtual /// register on the stack, allocating space if neccesary. int getStackSpaceFor(unsigned VirtReg, const TargetRegisterClass *RC); @@ -88,8 +89,7 @@ return I->second; // Already has space allocated? // Allocate a new stack object for this spill location... - int FrameIdx = - MF->getFrameInfo()->CreateStackObject(RC->getSize(), RC->getAlignment()); + int FrameIdx = MF->getFrameInfo()->CreateStackObject(RC); // Assign the slot... StackSlotForVirtReg.insert(I, std::make_pair(VirtReg, FrameIdx)); @@ -137,74 +137,6 @@ } -/// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions in -/// predecessor basic blocks. -/// -void RegAllocSimple::EliminatePHINodes(MachineBasicBlock &MBB) { - const MachineInstrInfo &MII = TM->getInstrInfo(); - - while (MBB.front()->getOpcode() == MachineInstrInfo::PHI) { - MachineInstr *MI = MBB.front(); - // Unlink the PHI node from the basic block... but don't delete the PHI yet - MBB.erase(MBB.begin()); - - DEBUG(std::cerr << "num ops: " << MI->getNumOperands() << "\n"); - assert(MI->getOperand(0).isVirtualRegister() && - "PHI node doesn't write virt reg?"); - - unsigned virtualReg = MI->getOperand(0).getAllocatedRegNum(); - - for (int i = MI->getNumOperands() - 1; i >= 2; i-=2) { - MachineOperand &opVal = MI->getOperand(i-1); - - // Get the MachineBasicBlock equivalent of the BasicBlock that is the - // source path the phi - MachineBasicBlock &opBlock = *MI->getOperand(i).getMachineBasicBlock(); - - // Check to make sure we haven't already emitted the copy for this block. - // This can happen because PHI nodes may have multiple entries for the - // same basic block. It doesn't matter which entry we use though, because - // all incoming values are guaranteed to be the same for a particular bb. - // - // Note that this is N^2 in the number of phi node entries, but since the - // # of entries is tiny, this is not a problem. - // - bool HaveNotEmitted = true; - for (int op = MI->getNumOperands() - 1; op != i; op -= 2) - if (&opBlock == MI->getOperand(op).getMachineBasicBlock()) { - HaveNotEmitted = false; - break; - } - - if (HaveNotEmitted) { - MachineBasicBlock::iterator opI = opBlock.end(); - MachineInstr *opMI = *--opI; - - // must backtrack over ALL the branches in the previous block - while (MII.isBranch(opMI->getOpcode()) && opI != opBlock.begin()) - opMI = *--opI; - - // move back to the first branch instruction so new instructions - // are inserted right in front of it and not in front of a non-branch - // - if (!MII.isBranch(opMI->getOpcode())) - ++opI; - - const TargetRegisterClass *RC = - MF->getSSARegMap()->getRegClass(virtualReg); - - assert(opVal.isVirtualRegister() && - "Machine PHI Operands must all be virtual registers!"); - RegInfo->copyRegToReg(opBlock, opI, virtualReg, opVal.getReg(), RC); - } - } - - // really delete the PHI instruction now! - delete MI; - } -} - - void RegAllocSimple::AllocateBasicBlock(MachineBasicBlock &MBB) { // loop over each instruction for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) { @@ -280,12 +212,6 @@ MF = &Fn; TM = &MF->getTarget(); RegInfo = TM->getRegisterInfo(); - - // First pass: eliminate PHI instructions by inserting copies into predecessor - // blocks. - for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); - MBB != MBBe; ++MBB) - EliminatePHINodes(*MBB); // Loop over all of the basic blocks, eliminating virtual register references for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); From lattner at cs.uiuc.edu Sun Jan 12 18:27:03 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:27:03 2003 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/RegAllocLocal.cpp Message-ID: <200301130026.SAA22420@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: RegAllocLocal.cpp updated: 1.10 -> 1.11 --- Log message: * Convert to use LiveVariable analysis * Convert to use PHIElimination pass * Don't spill values which have just been reloaded (big win reducing spills) * Add experimental support for eliminating spills before TwoAddress instructions. It currently is broken so it is #ifdef'd out. * Use new "is terminator" flag on instructions instead of looking for branches and returns explicitly. --- Diffs of the changes: Index: llvm/lib/CodeGen/RegAllocLocal.cpp diff -u llvm/lib/CodeGen/RegAllocLocal.cpp:1.10 llvm/lib/CodeGen/RegAllocLocal.cpp:1.11 --- llvm/lib/CodeGen/RegAllocLocal.cpp:1.10 Sat Dec 28 15:08:26 2002 +++ llvm/lib/CodeGen/RegAllocLocal.cpp Sun Jan 12 18:25:40 2003 @@ -5,16 +5,17 @@ // //===----------------------------------------------------------------------===// +#include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/SSARegMap.h" #include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/LiveVariables.h" #include "llvm/Target/MachineInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include "Support/Statistic.h" #include "Support/CommandLine.h" #include -#include namespace { Statistic<> NumSpilled ("ra-local", "Number of registers spilled"); @@ -26,6 +27,7 @@ const TargetMachine *TM; MachineFunction *MF; const MRegisterInfo *RegInfo; + LiveVariables *LV; // StackSlotForVirtReg - Maps SSA Regs => frame index where these values are // spilled @@ -54,12 +56,26 @@ // std::vector PhysRegsUseOrder; - // LastUserOf map - This multimap contains the set of registers that each - // key instruction is the last user of. If an instruction has an entry in - // this map, that means that the specified operands are killed after the - // instruction is executed, thus they don't need to be spilled into memory + // VirtRegModified - This bitset contains information about which virtual + // registers need to be spilled back to memory when their registers are + // scavenged. If a virtual register has simply been rematerialized, there + // is no reason to spill it to memory when we need the register back. // - std::multimap LastUserOf; + std::vector VirtRegModified; + + void markVirtRegModified(unsigned Reg, bool Val = true) { + assert(Reg >= MRegisterInfo::FirstVirtualRegister && "Illegal VirtReg!"); + Reg -= MRegisterInfo::FirstVirtualRegister; + if (VirtRegModified.size() <= Reg) VirtRegModified.resize(Reg+1); + VirtRegModified[Reg] = Val; + } + + bool isVirtRegModified(unsigned Reg) const { + assert(Reg >= MRegisterInfo::FirstVirtualRegister && "Illegal VirtReg!"); + assert(Reg - MRegisterInfo::FirstVirtualRegister < VirtRegModified.size() + && "Illegal virtual register!"); + return VirtRegModified[Reg - MRegisterInfo::FirstVirtualRegister]; + } void MarkPhysRegRecentlyUsed(unsigned Reg) { assert(!PhysRegsUseOrder.empty() && "No registers used!"); @@ -81,6 +97,13 @@ return "Local Register Allocator"; } + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + if (!DisableKill) + AU.addRequired(); + AU.addRequiredID(PHIEliminationID); + MachineFunctionPass::getAnalysisUsage(AU); + } + private: /// runOnMachineFunction - Register allocate the whole function bool runOnMachineFunction(MachineFunction &Fn); @@ -88,19 +111,6 @@ /// AllocateBasicBlock - Register allocate the specified basic block. void AllocateBasicBlock(MachineBasicBlock &MBB); - /// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions - /// in predecessor basic blocks. - void EliminatePHINodes(MachineBasicBlock &MBB); - - /// CalculateLastUseOfVReg - Calculate an approximation of the killing - /// uses for the virtual registers in the function. Here we try to capture - /// registers that are defined and only used within the same basic block. - /// Because we don't have use-def chains yet, we have to do this the hard - /// way. - /// - void CalculateLastUseOfVReg(MachineBasicBlock &MBB, - std::map &LastUseOfVReg) const; - /// areRegsEqual - This method returns true if the specified registers are /// related to each other. To do this, it checks to see if they are equal @@ -129,39 +139,41 @@ /// spillPhysReg - This method spills the specified physical register into /// the virtual register slot associated with it. - // + /// void spillPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, - unsigned PhysReg) { - std::map::iterator PI = PhysRegsUsed.find(PhysReg); - if (PI != PhysRegsUsed.end()) { // Only spill it if it's used! - spillVirtReg(MBB, I, PI->second, PhysReg); - } else if (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg)) { - // If the selected register aliases any other registers, we must make - // sure that one of the aliases isn't alive... - for (unsigned i = 0; AliasSet[i]; ++i) { - PI = PhysRegsUsed.find(AliasSet[i]); - if (PI != PhysRegsUsed.end()) // Spill aliased register... - spillVirtReg(MBB, I, PI->second, AliasSet[i]); - } - } - } + unsigned PhysReg); + + /// assignVirtToPhysReg - This method updates local state so that we know + /// that PhysReg is the proper container for VirtReg now. The physical + /// register must not be used for anything else when this is called. + /// + void assignVirtToPhysReg(unsigned VirtReg, unsigned PhysReg); - void AssignVirtToPhysReg(unsigned VirtReg, unsigned PhysReg); + /// liberatePhysReg - Make sure the specified physical register is available + /// for use. If there is currently a value in it, it is either moved out of + /// the way or spilled to memory. + /// + void liberatePhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, + unsigned PhysReg); /// isPhysRegAvailable - Return true if the specified physical register is /// free and available for use. This also includes checking to see if /// aliased registers are all free... /// bool isPhysRegAvailable(unsigned PhysReg) const; + + /// getFreeReg - Look to see if there is a free register available in the + /// specified register class. If not, return 0. + /// + unsigned getFreeReg(const TargetRegisterClass *RC); - /// getFreeReg - Find a physical register to hold the specified virtual + /// getReg - Find a physical register to hold the specified virtual /// register. If all compatible physical registers are used, this method /// spills the last used virtual register to the stack, and uses that /// register. /// - unsigned getFreeReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &I, - unsigned virtualReg); + unsigned getReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, + unsigned VirtReg); /// reloadVirtReg - This method loads the specified virtual register into a /// physical register, returning the physical register chosen. This updates @@ -186,8 +198,7 @@ return I->second; // Already has space allocated? // Allocate a new stack object for this spill location... - int FrameIdx = - MF->getFrameInfo()->CreateStackObject(RC->getSize(), RC->getAlignment()); + int FrameIdx = MF->getFrameInfo()->CreateStackObject(RC); // Assign the slot... StackSlotForVirtReg.insert(I, std::make_pair(VirtReg, FrameIdx)); @@ -208,6 +219,7 @@ PhysRegsUseOrder.erase(It); } + /// spillVirtReg - This method spills the value specified by PhysReg into the /// virtual register slot specified by VirtReg. It then updates the RA data /// structures to indicate the fact that PhysReg is now available. @@ -220,9 +232,12 @@ MF->getSSARegMap()->getRegClass(VirtReg); int FrameIndex = getStackSpaceFor(VirtReg, RegClass); - // Add move instruction(s) - RegInfo->storeRegToStackSlot(MBB, I, PhysReg, FrameIndex, RegClass); - ++NumSpilled; // Update statistics + // If we need to spill this value, do so now... + if (isVirtRegModified(VirtReg)) { + // Add move instruction(s) + RegInfo->storeRegToStackSlot(MBB, I, PhysReg, FrameIndex, RegClass); + ++NumSpilled; // Update statistics + } Virt2PhysRegMap.erase(VirtReg); // VirtReg no longer available } @@ -230,6 +245,41 @@ } +/// spillPhysReg - This method spills the specified physical register into the +/// virtual register slot associated with it. +/// +void RA::spillPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, + unsigned PhysReg) { + std::map::iterator PI = PhysRegsUsed.find(PhysReg); + if (PI != PhysRegsUsed.end()) { // Only spill it if it's used! + spillVirtReg(MBB, I, PI->second, PhysReg); + } else if (const unsigned *AliasSet = RegInfo->getAliasSet(PhysReg)) { + // If the selected register aliases any other registers, we must make + // sure that one of the aliases isn't alive... + for (unsigned i = 0; AliasSet[i]; ++i) { + PI = PhysRegsUsed.find(AliasSet[i]); + if (PI != PhysRegsUsed.end()) // Spill aliased register... + spillVirtReg(MBB, I, PI->second, AliasSet[i]); + } + } +} + + +/// assignVirtToPhysReg - This method updates local state so that we know +/// that PhysReg is the proper container for VirtReg now. The physical +/// register must not be used for anything else when this is called. +/// +void RA::assignVirtToPhysReg(unsigned VirtReg, unsigned PhysReg) { + assert(PhysRegsUsed.find(PhysReg) == PhysRegsUsed.end() && + "Phys reg already assigned!"); + // Update information to note the fact that this register was just used, and + // it holds VirtReg. + PhysRegsUsed[PhysReg] = VirtReg; + Virt2PhysRegMap[VirtReg] = PhysReg; + PhysRegsUseOrder.push_back(PhysReg); // New use of PhysReg +} + + /// isPhysRegAvailable - Return true if the specified physical register is free /// and available for use. This also includes checking to see if aliased /// registers are all free... @@ -247,31 +297,77 @@ } - -/// getFreeReg - Find a physical register to hold the specified virtual -/// register. If all compatible physical registers are used, this method spills -/// the last used virtual register to the stack, and uses that register. +/// getFreeReg - Look to see if there is a free register available in the +/// specified register class. If not, return 0. /// -unsigned RA::getFreeReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, - unsigned VirtReg) { - const TargetRegisterClass *RC = MF->getSSARegMap()->getRegClass(VirtReg); - +unsigned RA::getFreeReg(const TargetRegisterClass *RC) { // Get iterators defining the range of registers that are valid to allocate in // this class, which also specifies the preferred allocation order. TargetRegisterClass::iterator RI = RC->allocation_order_begin(*MF); TargetRegisterClass::iterator RE = RC->allocation_order_end(*MF); - // First check to see if we have a free register of the requested type... - unsigned PhysReg = 0; - for (; RI != RE; ++RI) { - unsigned R = *RI; - if (isPhysRegAvailable(R)) { // Is reg unused? - // Found an unused register! - PhysReg = R; - assert(PhysReg != 0 && "Cannot use register!"); - break; + for (; RI != RE; ++RI) + if (isPhysRegAvailable(*RI)) { // Is reg unused? + assert(*RI != 0 && "Cannot use register!"); + return *RI; // Found an unused register! + } + return 0; +} + + +/// liberatePhysReg - Make sure the specified physical register is available for +/// use. If there is currently a value in it, it is either moved out of the way +/// or spilled to memory. +/// +void RA::liberatePhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, + unsigned PhysReg) { + // FIXME: This code checks to see if a register is available, but it really + // wants to know if a reg is available BEFORE the instruction executes. If + // called after killed operands are freed, it runs the risk of reallocating a + // used operand... +#if 0 + if (isPhysRegAvailable(PhysReg)) return; // Already available... + + // Check to see if the register is directly used, not indirectly used through + // aliases. If aliased registers are the ones actually used, we cannot be + // sure that we will be able to save the whole thing if we do a reg-reg copy. + std::map::iterator PRUI = PhysRegsUsed.find(PhysReg); + if (PRUI != PhysRegsUsed.end()) { + unsigned VirtReg = PRUI->second; // The virtual register held... + + // Check to see if there is a compatible register available. If so, we can + // move the value into the new register... + // + const TargetRegisterClass *RC = RegInfo->getRegClass(PhysReg); + if (unsigned NewReg = getFreeReg(RC)) { + // Emit the code to copy the value... + RegInfo->copyRegToReg(MBB, I, NewReg, PhysReg, RC); + + // Update our internal state to indicate that PhysReg is available and Reg + // isn't. + Virt2PhysRegMap.erase(VirtReg); + removePhysReg(PhysReg); // Free the physreg + + // Move reference over to new register... + assignVirtToPhysReg(VirtReg, NewReg); + return; } } +#endif + spillPhysReg(MBB, I, PhysReg); +} + + +/// getReg - Find a physical register to hold the specified virtual +/// register. If all compatible physical registers are used, this method spills +/// the last used virtual register to the stack, and uses that register. +/// +unsigned RA::getReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I, + unsigned VirtReg) { + const TargetRegisterClass *RC = MF->getSSARegMap()->getRegClass(VirtReg); + + // First check to see if we have a free register of the requested type... + unsigned PhysReg = getFreeReg(RC); // If we didn't find an unused register, scavenge one now! if (PhysReg == 0) { @@ -309,22 +405,11 @@ } // Now that we know which register we need to assign this to, do it now! - AssignVirtToPhysReg(VirtReg, PhysReg); + assignVirtToPhysReg(VirtReg, PhysReg); return PhysReg; } -void RA::AssignVirtToPhysReg(unsigned VirtReg, unsigned PhysReg) { - assert(PhysRegsUsed.find(PhysReg) == PhysRegsUsed.end() && - "Phys reg already assigned!"); - // Update information to note the fact that this register was just used, and - // it holds VirtReg. - PhysRegsUsed[PhysReg] = VirtReg; - Virt2PhysRegMap[VirtReg] = PhysReg; - PhysRegsUseOrder.push_back(PhysReg); // New use of PhysReg -} - - /// reloadVirtReg - This method loads the specified virtual register into a /// physical register, returning the physical register chosen. This updates the /// regalloc data structures to reflect the fact that the virtual reg is now @@ -339,187 +424,109 @@ return It->second; // Already have this value available! } - unsigned PhysReg = getFreeReg(MBB, I, VirtReg); + unsigned PhysReg = getReg(MBB, I, VirtReg); const TargetRegisterClass *RC = MF->getSSARegMap()->getRegClass(VirtReg); int FrameIndex = getStackSpaceFor(VirtReg, RC); + markVirtRegModified(VirtReg, false); // Note that this reg was just reloaded + // Add move instruction(s) RegInfo->loadRegFromStackSlot(MBB, I, PhysReg, FrameIndex, RC); ++NumReloaded; // Update statistics return PhysReg; } -/// CalculateLastUseOfVReg - Calculate an approximation of the killing uses for -/// the virtual registers in the function. Here we try to capture registers -/// that are defined and only used within the same basic block. Because we -/// don't have use-def chains yet, we have to do this the hard way. -/// -void RA::CalculateLastUseOfVReg(MachineBasicBlock &MBB, - std::map &LastUseOfVReg) const { - // Calculate the last machine instruction in this basic block that uses the - // specified virtual register defined in this basic block. - std::map LastLocalUses; - - for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;++I){ +void RA::AllocateBasicBlock(MachineBasicBlock &MBB) { + // loop over each instruction + MachineBasicBlock::iterator I = MBB.begin(); + for (; I != MBB.end(); ++I) { MachineInstr *MI = *I; - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { - MachineOperand &Op = MI->getOperand(i); - if (Op.isVirtualRegister()) { - if (Op.opIsDef()) { // Definition of a new virtual reg? - LastLocalUses[Op.getAllocatedRegNum()] = 0; // Record it - } else { // Use of a virtual reg. - std::map::iterator It = - LastLocalUses.find(Op.getAllocatedRegNum()); - if (It != LastLocalUses.end()) // Local use? - It->second = MI; // Update last use - else - LastUseOfVReg[Op.getAllocatedRegNum()] = 0; - } - } - } - } - - // Move local uses over... if there are any uses of a local already in the - // lastuse map, the newly inserted entry is ignored. - LastUseOfVReg.insert(LastLocalUses.begin(), LastLocalUses.end()); -} - - -/// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions in -/// predecessor basic blocks. -/// -void RA::EliminatePHINodes(MachineBasicBlock &MBB) { - const MachineInstrInfo &MII = TM->getInstrInfo(); + const MachineInstrDescriptor &MID = TM->getInstrInfo().get(MI->getOpcode()); - while (MBB.front()->getOpcode() == MachineInstrInfo::PHI) { - MachineInstr *MI = MBB.front(); - // Unlink the PHI node from the basic block... but don't delete the PHI yet - MBB.erase(MBB.begin()); - - assert(MI->getOperand(0).isVirtualRegister() && - "PHI node doesn't write virt reg?"); + // Loop over the implicit uses, making sure that they are at the head of the + // use order list, so they don't get reallocated. + if (const unsigned *ImplicitUses = MID.ImplicitUses) + for (unsigned i = 0; ImplicitUses[i]; ++i) + MarkPhysRegRecentlyUsed(ImplicitUses[i]); - unsigned virtualReg = MI->getOperand(0).getAllocatedRegNum(); + // Get the used operands into registers. This has the potiential to spill + // incoming values if we are out of registers. + // + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) + if (MI->getOperand(i).opIsUse() && + MI->getOperand(i).isVirtualRegister()) { + unsigned VirtSrcReg = MI->getOperand(i).getAllocatedRegNum(); + unsigned PhysSrcReg = reloadVirtReg(MBB, I, VirtSrcReg); + MI->SetMachineOperandReg(i, PhysSrcReg); // Assign the input register + } - for (int i = MI->getNumOperands() - 1; i >= 2; i-=2) { - MachineOperand &opVal = MI->getOperand(i-1); - - // Get the MachineBasicBlock equivalent of the BasicBlock that is the - // source path the phi - MachineBasicBlock &opBlock = *MI->getOperand(i).getMachineBasicBlock(); - - // Check to make sure we haven't already emitted the copy for this block. - // This can happen because PHI nodes may have multiple entries for the - // same basic block. It doesn't matter which entry we use though, because - // all incoming values are guaranteed to be the same for a particular bb. - // - // Note that this is N^2 in the number of phi node entries, but since the - // # of entries is tiny, this is not a problem. + if (!DisableKill) { + // If this instruction is the last user of anything in registers, kill the + // value, freeing the register being used, so it doesn't need to be + // spilled to memory. // - bool HaveNotEmitted = true; - for (int op = MI->getNumOperands() - 1; op != i; op -= 2) - if (&opBlock == MI->getOperand(op).getMachineBasicBlock()) { - HaveNotEmitted = false; - break; - } + for (LiveVariables::killed_iterator KI = LV->killed_begin(MI), + KE = LV->killed_end(MI); KI != KE; ++KI) { + unsigned VirtReg = KI->second; + unsigned PhysReg = VirtReg; + if (VirtReg >= MRegisterInfo::FirstVirtualRegister) { + std::map::iterator I = + Virt2PhysRegMap.find(VirtReg); + assert(I != Virt2PhysRegMap.end()); + PhysReg = I->second; + Virt2PhysRegMap.erase(I); + } - if (HaveNotEmitted) { - MachineBasicBlock::iterator opI = opBlock.end(); - MachineInstr *opMI = *--opI; - - // must backtrack over ALL the branches in the previous block - while (MII.isBranch(opMI->getOpcode()) && opI != opBlock.begin()) - opMI = *--opI; - - // move back to the first branch instruction so new instructions - // are inserted right in front of it and not in front of a non-branch - if (!MII.isBranch(opMI->getOpcode())) - ++opI; - - const TargetRegisterClass *RC = - MF->getSSARegMap()->getRegClass(virtualReg); - - assert(opVal.isVirtualRegister() && - "Machine PHI Operands must all be virtual registers!"); - RegInfo->copyRegToReg(opBlock, opI, virtualReg, opVal.getReg(), RC); + if (PhysReg) { + DEBUG(std::cout << "V: " << VirtReg << " P: " << PhysReg + << " Killed by: " << *MI); + removePhysReg(PhysReg); + } } } - - // really delete the PHI instruction now! - delete MI; - } -} - - -void RA::AllocateBasicBlock(MachineBasicBlock &MBB) { - // loop over each instruction - MachineBasicBlock::iterator I = MBB.begin(); - for (; I != MBB.end(); ++I) { - MachineInstr *MI = *I; - const MachineInstrDescriptor &MID = TM->getInstrInfo().get(MI->getOpcode()); // Loop over all of the operands of the instruction, spilling registers that // are defined, and marking explicit destinations in the PhysRegsUsed map. - - // FIXME: We don't need to spill a register if this is the last use of the - // value! for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) - if (MI->getOperand(i).opIsDef() && + if ((MI->getOperand(i).opIsDef() || MI->getOperand(i).opIsDefAndUse()) && MI->getOperand(i).isPhysicalRegister()) { unsigned Reg = MI->getOperand(i).getAllocatedRegNum(); - spillPhysReg(MBB, I, Reg); + spillPhysReg(MBB, I, Reg); // Spill any existing value in the reg PhysRegsUsed[Reg] = 0; // It is free and reserved now PhysRegsUseOrder.push_back(Reg); } - // Loop over the implicit defs, spilling them, as above. + // Loop over the implicit defs, spilling them as well. if (const unsigned *ImplicitDefs = MID.ImplicitDefs) for (unsigned i = 0; ImplicitDefs[i]; ++i) { unsigned Reg = ImplicitDefs[i]; - - // We don't want to spill implicit definitions if they were explicitly - // chosen. For this reason, check to see now if the register we are - // to spill has a vreg of 0. - if (PhysRegsUsed.count(Reg) && PhysRegsUsed[Reg] != 0) - spillPhysReg(MBB, I, Reg); - else if (PhysRegsUsed.count(Reg)) { - // Remove the entry from PhysRegsUseOrder to avoid having two entries! - removePhysReg(Reg); - } + spillPhysReg(MBB, I, Reg); PhysRegsUseOrder.push_back(Reg); PhysRegsUsed[Reg] = 0; // It is free and reserved now } - // Loop over the implicit uses, making sure that they are at the head of the - // use order list, so they don't get reallocated. - if (const unsigned *ImplicitUses = MID.ImplicitUses) - for (unsigned i = 0; ImplicitUses[i]; ++i) - MarkPhysRegRecentlyUsed(ImplicitUses[i]); - - // Loop over all of the operands again, getting the used operands into - // registers. This has the potiential to spill incoming values if we are - // out of registers. - // - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) - if (MI->getOperand(i).opIsUse() && - MI->getOperand(i).isVirtualRegister()) { - unsigned VirtSrcReg = MI->getOperand(i).getAllocatedRegNum(); - unsigned PhysSrcReg = reloadVirtReg(MBB, I, VirtSrcReg); - MI->SetMachineOperandReg(i, PhysSrcReg); // Assign the input register - } - // Okay, we have allocated all of the source operands and spilled any values // that would be destroyed by defs of this instruction. Loop over the - // implicit defs and assign them to a register, spilling the incoming value - // if we need to scavange a register. + // implicit defs and assign them to a register, spilling incoming values if + // we need to scavenge a register. // for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) if (MI->getOperand(i).opIsDef() && - !MI->getOperand(i).isPhysicalRegister()) { + MI->getOperand(i).isVirtualRegister()) { unsigned DestVirtReg = MI->getOperand(i).getAllocatedRegNum(); unsigned DestPhysReg; + // If DestVirtReg already has a value, forget about it. Why doesn't + // getReg do this right? + std::map::iterator DestI = + Virt2PhysRegMap.find(DestVirtReg); + if (DestI != Virt2PhysRegMap.end()) { + unsigned PhysReg = DestI->second; + Virt2PhysRegMap.erase(DestI); + removePhysReg(PhysReg); + } + if (TM->getInstrInfo().isTwoAddrInstr(MI->getOpcode()) && i == 0) { // must be same register number as the first operand // This maps a = b + c into b += c, and saves b into a's spot @@ -529,51 +536,56 @@ "Two address instruction invalid!"); DestPhysReg = MI->getOperand(1).getAllocatedRegNum(); - // Spill the incoming value, because we are about to change the - // register contents. - spillPhysReg(MBB, I, DestPhysReg); - AssignVirtToPhysReg(DestVirtReg, DestPhysReg); + liberatePhysReg(MBB, I, DestPhysReg); + assignVirtToPhysReg(DestVirtReg, DestPhysReg); } else { - DestPhysReg = getFreeReg(MBB, I, DestVirtReg); + DestPhysReg = getReg(MBB, I, DestVirtReg); } + markVirtRegModified(DestVirtReg); MI->SetMachineOperandReg(i, DestPhysReg); // Assign the output register } if (!DisableKill) { - // If this instruction is the last user of anything in registers, kill the - // value, freeing the register being used, so it doesn't need to be - // spilled to memory at the end of the block. - std::multimap::iterator LUOI = - LastUserOf.lower_bound(MI); - for (; LUOI != LastUserOf.end() && LUOI->first == MI; ++MI) { - unsigned VirtReg = LUOI->second; // entry found? - unsigned PhysReg = Virt2PhysRegMap[VirtReg]; - if (PhysReg) { - DEBUG(std::cout << "V: " << VirtReg << " P: " << PhysReg - << " Last use of: " << *MI); - removePhysReg(PhysReg); - } - Virt2PhysRegMap.erase(VirtReg); + // If this instruction defines any registers that are immediately dead, + // kill them now. + // + for (LiveVariables::killed_iterator KI = LV->dead_begin(MI), + KE = LV->dead_end(MI); KI != KE; ++KI) { + unsigned VirtReg = KI->second; + unsigned PhysReg = VirtReg; + if (VirtReg >= MRegisterInfo::FirstVirtualRegister) { + std::map::iterator I = + Virt2PhysRegMap.find(VirtReg); + assert(I != Virt2PhysRegMap.end()); + PhysReg = I->second; + Virt2PhysRegMap.erase(I); + } + + if (PhysReg) { + DEBUG(std::cout << "V: " << VirtReg << " P: " << PhysReg + << " dead after: " << *MI); + removePhysReg(PhysReg); + } } } } // Rewind the iterator to point to the first flow control instruction... const MachineInstrInfo &MII = TM->getInstrInfo(); - I = MBB.end(); - do { + I = MBB.end()-1; + while (I != MBB.begin() && MII.isTerminatorInstr((*(I-1))->getOpcode())) --I; - } while ((MII.isReturn((*I)->getOpcode()) || - MII.isBranch((*I)->getOpcode())) && I != MBB.begin()); - - if (!MII.isReturn((*I)->getOpcode()) && !MII.isBranch((*I)->getOpcode())) - ++I; // Spill all physical registers holding virtual registers now. while (!PhysRegsUsed.empty()) spillVirtReg(MBB, I, PhysRegsUsed.begin()->second, PhysRegsUsed.begin()->first); + for (std::map::iterator I = Virt2PhysRegMap.begin(), + E = Virt2PhysRegMap.end(); I != E; ++I) + std::cerr << "Register still mapped: " << I->first << " -> " + << I->second << "\n"; + assert(Virt2PhysRegMap.empty() && "Virtual registers still in phys regs?"); assert(PhysRegsUseOrder.empty() && "Physical regs still allocated?"); } @@ -587,38 +599,16 @@ TM = &Fn.getTarget(); RegInfo = TM->getRegisterInfo(); - // First pass: eliminate PHI instructions by inserting copies into predecessor - // blocks, and calculate a simple approximation of killing uses for virtual - // registers. - // - std::map LastUseOfVReg; - for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); - MBB != MBBe; ++MBB) { - if (!DisableKill) - CalculateLastUseOfVReg(*MBB, LastUseOfVReg); - EliminatePHINodes(*MBB); - } - - // At this point LastUseOfVReg has been filled in to contain the last - // MachineInstr user of the specified virtual register, if that user is - // within the same basic block as the definition (otherwise it contains - // null). Invert this mapping now: if (!DisableKill) - for (std::map::iterator I = LastUseOfVReg.begin(), - E = LastUseOfVReg.end(); I != E; ++I) - if (I->second) - LastUserOf.insert(std::make_pair(I->second, I->first)); - - // We're done with the temporary list now. - LastUseOfVReg.clear(); + LV = &getAnalysis(); // Loop over all of the basic blocks, eliminating virtual register references for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); MBB != MBBe; ++MBB) AllocateBasicBlock(*MBB); - LastUserOf.clear(); StackSlotForVirtReg.clear(); + VirtRegModified.clear(); return true; } From lattner at cs.uiuc.edu Sun Jan 12 18:27:06 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:27:06 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/MachineInstrInfo.cpp Message-ID: <200301130026.SAA22432@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target: MachineInstrInfo.cpp updated: 1.5 -> 1.6 --- Log message: Start renaming MachineInstrInfo -> TargetInstrInfo --- Diffs of the changes: Index: llvm/lib/Target/MachineInstrInfo.cpp diff -u llvm/lib/Target/MachineInstrInfo.cpp:1.5 llvm/lib/Target/MachineInstrInfo.cpp:1.6 --- llvm/lib/Target/MachineInstrInfo.cpp:1.5 Sun Nov 17 17:22:03 2002 +++ llvm/lib/Target/MachineInstrInfo.cpp Sun Jan 12 18:26:36 2003 @@ -1,4 +1,4 @@ -//===-- MachineInstrInfo.cpp - Target Instruction Information -------------===// +//===-- TargetInstrInfo.cpp - Target Instruction Information --------------===// // // //===----------------------------------------------------------------------===// @@ -12,34 +12,29 @@ // Initialized only when the TargetMachine class is created // and reset when that class is destroyed. // -const MachineInstrDescriptor* TargetInstrDescriptors = 0; +const TargetInstrDescriptor* TargetInstrDescriptors = 0; -//--------------------------------------------------------------------------- -// class MachineInstructionInfo -// Interface to description of machine instructions -//--------------------------------------------------------------------------- - -MachineInstrInfo::MachineInstrInfo(const MachineInstrDescriptor* Desc, - unsigned DescSize, - unsigned NumRealOpCodes) +TargetInstrInfo::TargetInstrInfo(const TargetInstrDescriptor* Desc, + unsigned DescSize, + unsigned NumRealOpCodes) : desc(Desc), descSize(DescSize), numRealOpCodes(NumRealOpCodes) { // FIXME: TargetInstrDescriptors should not be global assert(TargetInstrDescriptors == NULL && desc != NULL); TargetInstrDescriptors = desc; // initialize global variable } -MachineInstrInfo::~MachineInstrInfo() { +TargetInstrInfo::~TargetInstrInfo() { TargetInstrDescriptors = NULL; // reset global variable } -void MachineInstrInfo::print(const MachineInstr *MI, std::ostream &O, - const TargetMachine &TM) const { +void TargetInstrInfo::print(const MachineInstr *MI, std::ostream &O, + const TargetMachine &TM) const { MI->print(O, TM); } -bool MachineInstrInfo::constantFitsInImmedField(MachineOpCode opCode, - int64_t intValue) const { +bool TargetInstrInfo::constantFitsInImmedField(MachineOpCode opCode, + int64_t intValue) const { // First, check if opCode has an immed field. bool isSignExtended; uint64_t maxImmedValue = maxImmedConstant(opCode, isSignExtended); @@ -58,7 +53,7 @@ return false; } -bool MachineInstrInfo::ConstantTypeMustBeLoaded(const Constant* CV) const { +bool TargetInstrInfo::ConstantTypeMustBeLoaded(const Constant* CV) const { assert(CV->getType()->isPrimitiveType() || isa(CV->getType())); return !(CV->getType()->isIntegral() || isa(CV->getType())); } From lattner at cs.uiuc.edu Sun Jan 12 18:28:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:28:00 2003 Subject: [llvm-commits] CVS: llvm/lib/Transforms/IPO/FunctionInlining.cpp Message-ID: <200301130027.SAA22443@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/IPO: FunctionInlining.cpp updated: 1.40 -> 1.41 --- Log message: Fix references to functions --- Diffs of the changes: Index: llvm/lib/Transforms/IPO/FunctionInlining.cpp diff -u llvm/lib/Transforms/IPO/FunctionInlining.cpp:1.40 llvm/lib/Transforms/IPO/FunctionInlining.cpp:1.41 --- llvm/lib/Transforms/IPO/FunctionInlining.cpp:1.40 Tue Nov 19 16:53:59 2002 +++ llvm/lib/Transforms/IPO/FunctionInlining.cpp Sun Jan 12 18:27:23 2003 @@ -8,13 +8,8 @@ // * Is able to inline ANY function call // . Has a smart heuristic for when to inline a function // -// Notice that: -// * This pass opens up a lot of opportunities for constant propogation. It -// is a good idea to to run a constant propogation pass, then a DCE pass -// sometime after running this pass. -// // FIXME: This pass should transform alloca instructions in the called function -// into malloc/free pairs! +// into malloc/free pairs! Or perhaps it should refuse to inline them! // //===----------------------------------------------------------------------===// @@ -104,6 +99,13 @@ // Make a vector to capture the return instructions in the cloned function... std::vector Returns; + + // Populate the value map with all of the globals in the program. + Module &M = *OrigBB->getParent()->getParent(); + for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) + ValueMap[I] = I; + for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I) + ValueMap[I] = I; // Do all of the hard part of cloning the callee into the caller... CloneFunctionInto(OrigBB->getParent(), CalledFunc, ValueMap, Returns, ".i"); From lattner at cs.uiuc.edu Sun Jan 12 18:36:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:36:01 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/MachineCodeEmitter.cpp Message-ID: <200301130035.SAA22481@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: MachineCodeEmitter.cpp updated: 1.17 -> 1.18 --- Log message: * Add support for FP registers ST* * Add support for the constant pool & constant pool indices * Add support for MRMS?m instructions * Fix FP Prefix emission * Add support for global addresses and external symbols --- Diffs of the changes: Index: llvm/lib/Target/X86/MachineCodeEmitter.cpp diff -u llvm/lib/Target/X86/MachineCodeEmitter.cpp:1.17 llvm/lib/Target/X86/MachineCodeEmitter.cpp:1.18 --- llvm/lib/Target/X86/MachineCodeEmitter.cpp:1.17 Sat Dec 28 14:24:48 2002 +++ llvm/lib/Target/X86/MachineCodeEmitter.cpp Sun Jan 12 18:33:59 2003 @@ -58,6 +58,7 @@ II = &((X86TargetMachine&)MF.getTarget()).getInstrInfo(); MCE.startFunction(MF); + MCE.emitConstantPool(MF.getConstantPool()); for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) emitBasicBlock(*I); MCE.finishFunction(MF); @@ -91,6 +92,10 @@ case X86::EBP: case X86::BP: case X86::CH: return N86::EBP; case X86::ESI: case X86::SI: case X86::DH: return N86::ESI; case X86::EDI: case X86::DI: case X86::BH: return N86::EDI; + + case X86::ST0: case X86::ST1: case X86::ST2: case X86::ST3: + case X86::ST4: case X86::ST5: case X86::ST6: case X86::ST7: + return RegNo-X86::ST0; default: assert(RegNo >= MRegisterInfo::FirstVirtualRegister && "Unknown physical register!"); @@ -128,10 +133,19 @@ void Emitter::emitMemModRMByte(const MachineInstr &MI, unsigned Op, unsigned RegOpcodeField) { + const MachineOperand &Disp = MI.getOperand(Op+3); + if (MI.getOperand(Op).isConstantPoolIndex()) { + // Emit a direct address reference [disp32] where the displacement is + // controlled by the MCE. + MCE.emitByte(ModRMByte(0, RegOpcodeField, 5)); + unsigned Index = MI.getOperand(Op).getConstantPoolIndex(); + MCE.emitFunctionConstantValueAddress(Index, Disp.getImmedValue()); + return; + } + const MachineOperand &BaseReg = MI.getOperand(Op); const MachineOperand &Scale = MI.getOperand(Op+1); const MachineOperand &IndexReg = MI.getOperand(Op+2); - const MachineOperand &Disp = MI.getOperand(Op+3); // Is a SIB byte needed? if (IndexReg.getReg() == 0 && BaseReg.getReg() != X86::ESP) { @@ -233,53 +247,79 @@ break; case X86II::D8: case X86II::D9: case X86II::DA: case X86II::DB: case X86II::DC: case X86II::DD: case X86II::DE: case X86II::DF: - MCE.emitByte(0xD8 + (Desc.TSFlags & X86II::Op0Mask)-X86II::D8); + MCE.emitByte(0xD8+ + (((Desc.TSFlags & X86II::Op0Mask)-X86II::D8) + >> X86II::Op0Shift)); break; // Two-byte opcode prefix - - default: break; // No prefix! + default: assert(0 && "Invalid prefix!"); + case 0: break; // No prefix! } unsigned char BaseOpcode = II->getBaseOpcodeFor(Opcode); switch (Desc.TSFlags & X86II::FormMask) { - default: assert(0 && "Unknown FormMask value!"); + default: assert(0 && "Unknown FormMask value in X86 MachineCodeEmitter!"); case X86II::Pseudo: - std::cerr << "X86 Machine Code Emitter: Not emitting: " << MI; + std::cerr << "X86 Machine Code Emitter: No 'form', not emitting: " << MI; break; + case X86II::RawFrm: MCE.emitByte(BaseOpcode); - if (MI.getNumOperands() == 1) { - assert(MI.getOperand(0).getType() == MachineOperand::MO_PCRelativeDisp); - MCE.emitPCRelativeDisp(MI.getOperand(0).getVRegValue()); + MachineOperand &MO = MI.getOperand(0); + if (MO.isPCRelativeDisp()) { + MCE.emitPCRelativeDisp(MO.getVRegValue()); + } else if (MO.isGlobalAddress()) { + MCE.emitGlobalAddress(MO.getGlobal(), MO.isPCRelative()); + } else if (MO.isExternalSymbol()) { + MCE.emitGlobalAddress(MO.getSymbolName(), MO.isPCRelative()); + } else { + assert(0 && "Unknown RawFrm operand!"); + } } break; + case X86II::AddRegFrm: MCE.emitByte(BaseOpcode + getX86RegNum(MI.getOperand(0).getReg())); - if (MI.getNumOperands() == 2 && (MI.getOperand(1).isImmediate() || - MI.getOperand(1).getVRegValueOrNull())) { - unsigned Size = sizeOfPtr(Desc); - if (Value *V = MI.getOperand(1).getVRegValueOrNull()) { - assert(Size == 4 && "Don't know how to emit non-pointer values!"); - MCE.emitGlobalAddress(cast(V)); - } else { - emitConstant(MI.getOperand(1).getImmedValue(), Size); + if (MI.getNumOperands() == 2) { + MachineOperand &MO1 = MI.getOperand(1); + if (MO1.isImmediate() || MO1.getVRegValueOrNull() || + MO1.isGlobalAddress() || MO1.isExternalSymbol()) { + unsigned Size = sizeOfPtr(Desc); + if (Value *V = MO1.getVRegValueOrNull()) { + assert(Size == 4 && "Don't know how to emit non-pointer values!"); + MCE.emitGlobalAddress(cast(V), false); + } else if (MO1.isGlobalAddress()) { + assert(Size == 4 && "Don't know how to emit non-pointer values!"); + MCE.emitGlobalAddress(MO1.getGlobal(), MO1.isPCRelative()); + } else if (MO1.isExternalSymbol()) { + assert(Size == 4 && "Don't know how to emit non-pointer values!"); + MCE.emitGlobalAddress(MO1.getSymbolName(), MO1.isPCRelative()); + } else { + emitConstant(MO1.getImmedValue(), Size); + } } } break; - case X86II::MRMDestReg: + + case X86II::MRMDestReg: { MCE.emitByte(BaseOpcode); - emitRegModRMByte(MI.getOperand(0).getReg(), - getX86RegNum(MI.getOperand(MI.getNumOperands()-1).getReg())); + MachineOperand &SrcOp = MI.getOperand(1+II->isTwoAddrInstr(Opcode)); + emitRegModRMByte(MI.getOperand(0).getReg(), getX86RegNum(SrcOp.getReg())); + if (MI.getNumOperands() == 4) + emitConstant(MI.getOperand(3).getImmedValue(), sizeOfPtr(Desc)); break; + } case X86II::MRMDestMem: MCE.emitByte(BaseOpcode); emitMemModRMByte(MI, 0, getX86RegNum(MI.getOperand(4).getReg())); break; + case X86II::MRMSrcReg: MCE.emitByte(BaseOpcode); emitRegModRMByte(MI.getOperand(MI.getNumOperands()-1).getReg(), getX86RegNum(MI.getOperand(0).getReg())); break; + case X86II::MRMSrcMem: MCE.emitByte(BaseOpcode); emitMemModRMByte(MI, MI.getNumOperands()-4, @@ -297,6 +337,19 @@ if (MI.getOperand(MI.getNumOperands()-1).isImmediate()) { unsigned Size = sizeOfPtr(Desc); emitConstant(MI.getOperand(MI.getNumOperands()-1).getImmedValue(), Size); + } + break; + + case X86II::MRMS0m: case X86II::MRMS1m: + case X86II::MRMS2m: case X86II::MRMS3m: + case X86II::MRMS4m: case X86II::MRMS5m: + case X86II::MRMS6m: case X86II::MRMS7m: + MCE.emitByte(BaseOpcode); + emitMemModRMByte(MI, 0, (Desc.TSFlags & X86II::FormMask)-X86II::MRMS0m); + + if (MI.getNumOperands() == 5) { + unsigned Size = sizeOfPtr(Desc); + emitConstant(MI.getOperand(4).getImmedValue(), Size); } break; } From lattner at cs.uiuc.edu Sun Jan 12 18:36:04 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:36:04 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/Printer.cpp Message-ID: <200301130035.SAA22488@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: Printer.cpp updated: 1.32 -> 1.33 --- Log message: * Implement rudimentary output of the constant pool * Implement support for MRMS?m instructions * Add Arg64 support * Add support for frame indexes and constant pool indexes * --- Diffs of the changes: Index: llvm/lib/Target/X86/Printer.cpp diff -u llvm/lib/Target/X86/Printer.cpp:1.32 llvm/lib/Target/X86/Printer.cpp:1.33 --- llvm/lib/Target/X86/Printer.cpp:1.32 Sat Dec 28 14:25:38 2002 +++ llvm/lib/Target/X86/Printer.cpp Sun Jan 12 18:35:03 2003 @@ -8,21 +8,24 @@ #include "X86.h" #include "X86InstrInfo.h" #include "llvm/Function.h" +#include "llvm/Constant.h" #include "llvm/Target/TargetMachine.h" #include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineInstr.h" #include "Support/Statistic.h" namespace { struct Printer : public MachineFunctionPass { std::ostream &O; - - Printer(std::ostream &o) : O(o) {} + unsigned ConstIdx; + Printer(std::ostream &o) : O(o), ConstIdx(0) {} virtual const char *getPassName() const { return "X86 Assembly Printer"; } + void printConstantPool(MachineConstantPool *MCP, const TargetData &TD); bool runOnMachineFunction(MachineFunction &F); }; } @@ -36,6 +39,21 @@ } +// printConstantPool - Print out any constants which have been spilled to +// memory... +void Printer::printConstantPool(MachineConstantPool *MCP, const TargetData &TD){ + const std::vector &CP = MCP->getConstants(); + if (CP.empty()) return; + + for (unsigned i = 0, e = CP.size(); i != e; ++i) { + O << "\t.section .rodata\n"; + O << "\t.align " << (unsigned)TD.getTypeAlignment(CP[i]->getType()) << "\n"; + O << ".CPI" << i+ConstIdx << ":\t\t\t\t\t;" << *CP[i] << "\n"; + O << "\t*Constant output not implemented yet!*\n\n"; + } + ConstIdx += CP.size(); // Don't recycle constant pool index numbers +} + /// runOnFunction - This uses the X86InstructionInfo::print method /// to print assembly for each instruction. bool Printer::runOnMachineFunction(MachineFunction &MF) { @@ -43,7 +61,12 @@ const TargetMachine &TM = MF.getTarget(); const MachineInstrInfo &MII = TM.getInstrInfo(); + // Print out constants referenced by the function + printConstantPool(MF.getConstantPool(), TM.getTargetData()); + // Print out labels for the function. + O << "\t.text\n"; + O << "\t.align 16\n"; O << "\t.globl\t" << MF.getFunction()->getName() << "\n"; O << "\t.type\t" << MF.getFunction()->getName() << ", @function\n"; O << MF.getFunction()->getName() << ":\n"; @@ -72,6 +95,8 @@ } static bool isMem(const MachineInstr *MI, unsigned Op) { + if (MI->getOperand(Op).isFrameIndex()) return true; + if (MI->getOperand(Op).isConstantPoolIndex()) return true; return Op+4 <= MI->getNumOperands() && MI->getOperand(Op ).isRegister() &&isScale(MI->getOperand(Op+1)) && MI->getOperand(Op+2).isRegister() &&MI->getOperand(Op+3).isImmediate(); @@ -85,6 +110,7 @@ O << "<" << V->getName() << ">"; return; } + // FALLTHROUGH case MachineOperand::MO_MachineRegister: if (MO.getReg() < MRegisterInfo::FirstVirtualRegister) O << RI.get(MO.getReg()).Name; @@ -99,6 +125,12 @@ case MachineOperand::MO_PCRelativeDisp: O << "<" << MO.getVRegValue()->getName() << ">"; return; + case MachineOperand::MO_GlobalAddress: + O << "<" << MO.getGlobal()->getName() << ">"; + return; + case MachineOperand::MO_ExternalSymbol: + O << "<" << MO.getSymbolName() << ">"; + return; default: O << ""; return; } @@ -110,6 +142,7 @@ case X86II::Arg8: return "BYTE PTR"; case X86II::Arg16: return "WORD PTR"; case X86II::Arg32: return "DWORD PTR"; + case X86II::Arg64: return "QWORD PTR"; case X86II::ArgF32: return "DWORD PTR"; case X86II::ArgF64: return "QWORD PTR"; case X86II::ArgF80: return "XWORD PTR"; @@ -119,6 +152,21 @@ static void printMemReference(std::ostream &O, const MachineInstr *MI, unsigned Op, const MRegisterInfo &RI) { assert(isMem(MI, Op) && "Invalid memory reference!"); + + if (MI->getOperand(Op).isFrameIndex()) { + O << "[frame slot #" << MI->getOperand(Op).getFrameIndex(); + if (MI->getOperand(Op+3).getImmedValue()) + O << " + " << MI->getOperand(Op+3).getImmedValue(); + O << "]"; + return; + } else if (MI->getOperand(Op).isConstantPoolIndex()) { + O << "[.CPI" << MI->getOperand(Op).getConstantPoolIndex(); + if (MI->getOperand(Op+3).getImmedValue()) + O << " + " << MI->getOperand(Op+3).getImmedValue(); + O << "]"; + return; + } + const MachineOperand &BaseReg = MI->getOperand(Op); int ScaleVal = MI->getOperand(Op+1).getImmedValue(); const MachineOperand &IndexReg = MI->getOperand(Op+2); @@ -194,9 +242,13 @@ // The accepted forms of Raw instructions are: // 1. nop - No operand required // 2. jmp foo - PC relative displacement operand + // 3. call bar - GlobalAddress Operand or External Symbol Operand // assert(MI->getNumOperands() == 0 || - (MI->getNumOperands() == 1 && MI->getOperand(0).isPCRelativeDisp())&& + (MI->getNumOperands() == 1 && + (MI->getOperand(0).isPCRelativeDisp() || + MI->getOperand(0).isGlobalAddress() || + MI->getOperand(0).isExternalSymbol())) && "Illegal raw instruction!"); O << getName(MI->getOpcode()) << " "; @@ -220,14 +272,20 @@ (MI->getNumOperands() == 2 && (MI->getOperand(1).getVRegValueOrNull() || MI->getOperand(1).isImmediate() || - MI->getOperand(1).isRegister()))) && + MI->getOperand(1).isRegister() || + MI->getOperand(1).isGlobalAddress() || + MI->getOperand(1).isExternalSymbol()))) && "Illegal form for AddRegFrm instruction!"); unsigned Reg = MI->getOperand(0).getReg(); O << getName(MI->getOpCode()) << " "; printOp(O, MI->getOperand(0), RI); - if (MI->getNumOperands() == 2 && !MI->getOperand(1).isRegister()) { + if (MI->getNumOperands() == 2 && + (!MI->getOperand(1).isRegister() || + MI->getOperand(1).getVRegValueOrNull() || + MI->getOperand(1).isGlobalAddress() || + MI->getOperand(1).isExternalSymbol())) { O << ", "; printOp(O, MI->getOperand(1), RI); } @@ -235,29 +293,36 @@ return; } case X86II::MRMDestReg: { - // There are two acceptable forms of MRMDestReg instructions, those with 3 - // and 2 operands: + // There are two acceptable forms of MRMDestReg instructions, those with 2, + // 3 and 4 operands: + // + // 2 Operands: this is for things like mov that do not read a second input // // 3 Operands: in this form, the first two registers (the destination, and // the first operand) should be the same, post register allocation. The 3rd // operand is an additional input. This should be for things like add // instructions. // - // 2 Operands: this is for things like mov that do not read a second input + // 4 Operands: This form is for instructions which are 3 operands forms, but + // have a constant argument as well. // + bool isTwoAddr = isTwoAddrInstr(Opcode); assert(MI->getOperand(0).isRegister() && - (MI->getNumOperands() == 2 || - (MI->getNumOperands() == 3 && MI->getOperand(1).isRegister())) && - MI->getOperand(MI->getNumOperands()-1).isRegister() + (MI->getNumOperands() == 2 || + (isTwoAddr && MI->getOperand(1).isRegister() && + MI->getOperand(0).getReg() == MI->getOperand(1).getReg() && + (MI->getNumOperands() == 3 || + (MI->getNumOperands() == 4 && MI->getOperand(3).isImmediate())))) && "Bad format for MRMDestReg!"); - if (MI->getNumOperands() == 3 && - MI->getOperand(0).getReg() != MI->getOperand(1).getReg()) - O << "**"; O << getName(MI->getOpCode()) << " "; printOp(O, MI->getOperand(0), RI); O << ", "; - printOp(O, MI->getOperand(MI->getNumOperands()-1), RI); + printOp(O, MI->getOperand(1+isTwoAddr), RI); + if (MI->getNumOperands() == 4) { + O << ", "; + printOp(O, MI->getOperand(3), RI); + } O << "\n"; return; } @@ -269,7 +334,7 @@ assert(isMem(MI, 0) && MI->getNumOperands() == 4+1 && MI->getOperand(4).isRegister() && "Bad format for MRMDestMem!"); - O << getName(MI->getOpCode()) << " " << sizePtr (Desc) << " "; + O << getName(MI->getOpCode()) << " " << sizePtr(Desc) << " "; printMemReference(O, MI, 0, RI); O << ", "; printOp(O, MI->getOperand(4), RI); @@ -291,7 +356,7 @@ MI->getOperand(1).isRegister() && (MI->getNumOperands() == 2 || (MI->getNumOperands() == 3 && MI->getOperand(2).isRegister())) - && "Bad format for MRMDestReg!"); + && "Bad format for MRMSrcReg!"); if (MI->getNumOperands() == 3 && MI->getOperand(0).getReg() != MI->getOperand(1).getReg()) O << "**"; @@ -319,7 +384,7 @@ O << getName(MI->getOpCode()) << " "; printOp(O, MI->getOperand(0), RI); - O << ", " << sizePtr (Desc) << " "; + O << ", " << sizePtr(Desc) << " "; printMemReference(O, MI, MI->getNumOperands()-4, RI); O << "\n"; return; @@ -359,7 +424,33 @@ return; } + case X86II::MRMS0m: case X86II::MRMS1m: + case X86II::MRMS2m: case X86II::MRMS3m: + case X86II::MRMS4m: case X86II::MRMS5m: + case X86II::MRMS6m: case X86II::MRMS7m: { + // In this form, the following are valid formats: + // 1. sete [m] + // 2. cmp [m], immediate + // 2. shl [m], rinput + // 3. sbb [m], immediate + // + assert(MI->getNumOperands() >= 4 && MI->getNumOperands() <= 5 && + isMem(MI, 0) && "Bad MRMSxM format!"); + assert((MI->getNumOperands() != 5 || MI->getOperand(4).isImmediate()) && + "Bad MRMSxM format!"); + + O << getName(MI->getOpCode()) << " "; + O << sizePtr(Desc) << " "; + printMemReference(O, MI, 0, RI); + if (MI->getNumOperands() == 5) { + O << ", "; + printOp(O, MI->getOperand(4), RI); + } + O << "\n"; + return; + } + default: - O << "\t\t\t-"; MI->print(O, TM); break; + O << "\tUNKNOWN FORM:\t\t-"; MI->print(O, TM); break; } } From lattner at cs.uiuc.edu Sun Jan 12 18:36:06 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:36:06 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/README.txt Message-ID: <200301130035.SAA22495@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: README.txt updated: 1.5 -> 1.6 --- Log message: Add speculation --- Diffs of the changes: Index: llvm/lib/Target/X86/README.txt diff -u llvm/lib/Target/X86/README.txt:1.5 llvm/lib/Target/X86/README.txt:1.6 --- llvm/lib/Target/X86/README.txt:1.5 Wed Dec 4 10:12:54 2002 +++ llvm/lib/Target/X86/README.txt Sun Jan 12 18:35:08 2003 @@ -205,7 +205,7 @@ ------------------- 1. Implement lots of nifty runtime optimizations 2. Implement a static compiler backend for x86 (might come almost for free...) -3. Implement new targets: IA64? X86-64? M68k? Who knows... +3. Implement new targets: IA64? X86-64? M68k? MMIX? Who knows... Infrastructure Improvements: ---------------------------- From lattner at cs.uiuc.edu Sun Jan 12 18:36:09 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:36:09 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/InstSelectSimple.cpp Message-ID: <200301130035.SAA22500@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: InstSelectSimple.cpp updated: 1.80 -> 1.81 --- Log message: * Adjust to use new interfaces, eliminating CurReg stuff * Support arbitrary FP constants * Fix bugs in frame layout for function calls and incoming arguments * Insert copies for constant arguments to PHI nodes into the BOTTOM of predecessor blocks, not the top. * Implement _floating point_ support: setcc, return, load, store, cast * Fix several bugs in the cast instruction * Abstract out call emission and load/store for FP * Implement malloc/free without previous lowering pass. * Make use of new forms of MachineOperand * Implement _long_ support! * Fix many bugs in FP support * Change branch from je/jne to je/jmp * Simplify code generated for GEP instructions --- Diffs of the changes: Index: llvm/lib/Target/X86/InstSelectSimple.cpp diff -u llvm/lib/Target/X86/InstSelectSimple.cpp:1.80 llvm/lib/Target/X86/InstSelectSimple.cpp:1.81 --- llvm/lib/Target/X86/InstSelectSimple.cpp:1.80 Sat Dec 28 15:08:27 2002 +++ llvm/lib/Target/X86/InstSelectSimple.cpp Sun Jan 12 18:32:26 2003 @@ -1,6 +1,6 @@ //===-- InstSelectSimple.cpp - A simple instruction selector for x86 ------===// // -// This file defines a simple peephole instruction selector for the x86 platform +// This file defines a simple peephole instruction selector for the x86 target // //===----------------------------------------------------------------------===// @@ -21,6 +21,7 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/SSARegMap.h" #include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Support/InstVisitor.h" #include "llvm/Target/MRegisterInfo.h" @@ -59,14 +60,12 @@ MachineFunction *F; // The function we are compiling into MachineBasicBlock *BB; // The current MBB we are compiling - unsigned CurReg; std::map RegMap; // Mapping between Val's and SSA Regs // MBBMap - Mapping between LLVM BB -> Machine BB std::map MBBMap; - ISel(TargetMachine &tm) - : TM(tm), F(0), BB(0), CurReg(MRegisterInfo::FirstVirtualRegister) {} + ISel(TargetMachine &tm) : TM(tm), F(0), BB(0) {} /// runOnFunction - Top level implementation of instruction selection for /// the entire function. @@ -89,7 +88,6 @@ RegMap.clear(); MBBMap.clear(); - CurReg = MRegisterInfo::FirstVirtualRegister; F = 0; return false; // We never modify the LLVM itself. } @@ -125,6 +123,14 @@ // Control flow operators void visitReturnInst(ReturnInst &RI); void visitBranchInst(BranchInst &BI); + + struct ValueRecord { + unsigned Reg; + const Type *Ty; + ValueRecord(unsigned R, const Type *T) : Reg(R), Ty(T) {} + }; + void doCall(const ValueRecord &Ret, MachineInstr *CallMI, + const std::vector &Args); void visitCallInst(CallInst &I); // Arithmetic operators @@ -132,8 +138,8 @@ void visitAdd(BinaryOperator &B) { visitSimpleBinary(B, 0); } void visitSub(BinaryOperator &B) { visitSimpleBinary(B, 1); } void doMultiply(MachineBasicBlock *MBB, MachineBasicBlock::iterator &MBBI, - unsigned destReg, const Type *resultType, - unsigned op0Reg, unsigned op1Reg); + unsigned DestReg, const Type *DestTy, + unsigned Op0Reg, unsigned Op1Reg); void visitMul(BinaryOperator &B); void visitDiv(BinaryOperator &B) { visitDivRem(B); } @@ -155,15 +161,16 @@ void visitSetGE(SetCondInst &I) { visitSetCCInst(I, 5); } // Memory Instructions + MachineInstr *doFPLoad(MachineBasicBlock *MBB, + MachineBasicBlock::iterator &MBBI, + const Type *Ty, unsigned DestReg); void visitLoadInst(LoadInst &I); + void doFPStore(const Type *Ty, unsigned DestAddrReg, unsigned SrcReg); void visitStoreInst(StoreInst &I); void visitGetElementPtrInst(GetElementPtrInst &I); void visitAllocaInst(AllocaInst &I); - - // We assume that by this point, malloc instructions have been - // lowered to calls, and dlsym will magically find malloc for us. - void visitMallocInst(MallocInst &I) { visitInstruction (I); } - void visitFreeInst(FreeInst &I) { visitInstruction(I); } + void visitMallocInst(MallocInst &I); + void visitFreeInst(FreeInst &I); // Other operators void visitShiftInst(ShiftInst &I); @@ -176,11 +183,16 @@ } /// promote32 - Make a value 32-bits wide, and put it somewhere. - void promote32 (const unsigned targetReg, Value *v); + /// + void promote32(unsigned targetReg, const ValueRecord &VR); + + /// EmitByteSwap - Byteswap SrcReg into DestReg. + /// + void EmitByteSwap(unsigned DestReg, unsigned SrcReg, unsigned Class); - // emitGEPOperation - Common code shared between visitGetElementPtrInst and - // constant expression GEP support. - // + /// emitGEPOperation - Common code shared between visitGetElementPtrInst and + /// constant expression GEP support. + /// void emitGEPOperation(MachineBasicBlock *BB, MachineBasicBlock::iterator&IP, Value *Src, User::op_iterator IdxBegin, User::op_iterator IdxEnd, unsigned TargetReg); @@ -192,14 +204,28 @@ MachineBasicBlock::iterator &MBBI, Constant *C, unsigned Reg); - /// makeAnotherReg - This method returns the next register number - /// we haven't yet used. + /// makeAnotherReg - This method returns the next register number we haven't + /// yet used. + /// + /// Long values are handled somewhat specially. They are always allocated + /// as pairs of 32 bit integer values. The register number returned is the + /// lower 32 bits of the long value, and the regNum+1 is the upper 32 bits + /// of the long value. + /// unsigned makeAnotherReg(const Type *Ty) { + if (Ty == Type::LongTy || Ty == Type::ULongTy) { + const TargetRegisterClass *RC = + TM.getRegisterInfo()->getRegClassForType(Type::IntTy); + // Create the lower part + F->getSSARegMap()->createVirtualRegister(RC); + // Create the upper part. + return F->getSSARegMap()->createVirtualRegister(RC)-1; + } + // Add the mapping of regnumber => reg class to MachineFunction const TargetRegisterClass *RC = TM.getRegisterInfo()->getRegClassForType(Ty); - F->getSSARegMap()->addRegMap(CurReg, RC); - return CurReg++; + return F->getSSARegMap()->createVirtualRegister(RC); } /// getReg - This method turns an LLVM value into a register number. This @@ -228,7 +254,7 @@ RegMap.erase(V); // Assign a new name to this constant if ref'd again } else if (GlobalValue *GV = dyn_cast(V)) { // Move the address of the global into the register - BMI(MBB, IPt, X86::MOVir32, 1, Reg).addReg(GV); + BMI(MBB, IPt, X86::MOVir32, 1, Reg).addGlobalAddress(GV); RegMap.erase(V); // Assign a new name to this address if ref'd again } @@ -259,9 +285,9 @@ case Type::FloatTyID: case Type::DoubleTyID: return cFP; // Floating Point is #3 + case Type::LongTyID: - case Type::ULongTyID: //return cLong; // Longs are class #3 - return cInt; // FIXME: LONGS ARE TREATED AS INTS! + case Type::ULongTyID: return cLong; // Longs are class #4 default: assert(0 && "Invalid type to getClass!"); return cByte; // not reached @@ -294,6 +320,20 @@ if (C->getType()->isIntegral()) { unsigned Class = getClassB(C->getType()); + + if (Class == cLong) { + // Copy the value into the register pair. + uint64_t Val; + if (C->getType()->isSigned()) + Val = cast(C)->getValue(); + else + Val = cast(C)->getValue(); + + BMI(MBB, IP, X86::MOVir32, 1, R).addZImm(Val & 0xFFFFFFFF); + BMI(MBB, IP, X86::MOVir32, 1, R+1).addZImm(Val >> 32); + return; + } + assert(Class <= cInt && "Type not handled yet!"); static const unsigned IntegralOpcodeTab[] = { @@ -304,7 +344,7 @@ BMI(MBB, IP, X86::MOVir8, 1, R).addZImm(C == ConstantBool::True); } else if (C->getType()->isSigned()) { ConstantSInt *CSI = cast(C); - BMI(MBB, IP, IntegralOpcodeTab[Class], 1, R).addSImm(CSI->getValue()); + BMI(MBB, IP, IntegralOpcodeTab[Class], 1, R).addZImm(CSI->getValue()); } else { ConstantUInt *CUI = cast(C); BMI(MBB, IP, IntegralOpcodeTab[Class], 1, R).addZImm(CUI->getValue()); @@ -316,8 +356,10 @@ else if (Value == +1.0) BMI(MBB, IP, X86::FLD1, 0, R); else { - std::cerr << "Cannot load constant '" << Value << "'!\n"; - assert(0); + // Otherwise we need to spill the constant to memory... + MachineConstantPool *CP = F->getConstantPool(); + unsigned CPI = CP->getConstantPoolIndex(CFP); + addConstantPoolReference(doFPLoad(MBB, IP, CFP->getType(), R), CPI); } } else if (isa(C)) { @@ -340,19 +382,17 @@ // X86, the stack frame looks like this: // // [ESP] -- return address - // [ESP + 4] -- first argument (leftmost lexically) if four bytes in size - // [ESP + 8] -- second argument, if four bytes in size + // [ESP + 4] -- first argument (leftmost lexically) + // [ESP + 8] -- second argument, if first argument is four bytes in size // ... // - unsigned ArgOffset = 0; + unsigned ArgOffset = 4; MachineFrameInfo *MFI = F->getFrameInfo(); for (Function::aiterator I = Fn.abegin(), E = Fn.aend(); I != E; ++I) { unsigned Reg = getReg(*I); - ArgOffset += 4; // Each argument takes at least 4 bytes on the stack... int FI; // Frame object index - switch (getClassB(I->getType())) { case cByte: FI = MFI->CreateFixedObject(1, ArgOffset); @@ -366,6 +406,12 @@ FI = MFI->CreateFixedObject(4, ArgOffset); addFrameReference(BuildMI(BB, X86::MOVmr32, 4, Reg), FI); break; + case cLong: + FI = MFI->CreateFixedObject(8, ArgOffset); + addFrameReference(BuildMI(BB, X86::MOVmr32, 4, Reg), FI); + addFrameReference(BuildMI(BB, X86::MOVmr32, 4, Reg+1), FI, 4); + ArgOffset += 4; // longs require 4 additional bytes + break; case cFP: unsigned Opcode; if (I->getType() == Type::FloatTy) { @@ -373,14 +419,15 @@ FI = MFI->CreateFixedObject(4, ArgOffset); } else { Opcode = X86::FLDr64; - ArgOffset += 4; // doubles require 4 additional bytes FI = MFI->CreateFixedObject(8, ArgOffset); + ArgOffset += 4; // doubles require 4 additional bytes } addFrameReference(BuildMI(BB, Opcode, 4, Reg), FI); break; default: assert(0 && "Unhandled argument type!"); } + ArgOffset += 4; // Each argument takes at least 4 bytes on the stack... } } @@ -390,6 +437,7 @@ /// the current one. /// void ISel::SelectPHINodes() { + const MachineInstrInfo &MII = TM.getInstrInfo(); const Function &LF = *F->getFunction(); // The LLVM function... for (Function::const_iterator I = LF.begin(), E = LF.end(); I != E; ++I) { const BasicBlock *BB = I; @@ -399,9 +447,17 @@ unsigned NumPHIs = 0; for (BasicBlock::const_iterator I = BB->begin(); PHINode *PN = (PHINode*)dyn_cast(&*I); ++I) { + // Create a new machine instr PHI node, and insert it. - MachineInstr *MI = BuildMI(X86::PHI, PN->getNumOperands(), getReg(*PN)); - MBB->insert(MBB->begin()+NumPHIs++, MI); // Insert it at the top of the BB + unsigned PHIReg = getReg(*PN); + MachineInstr *PhiMI = BuildMI(X86::PHI, PN->getNumOperands(), PHIReg); + MBB->insert(MBB->begin()+NumPHIs++, PhiMI); + + MachineInstr *LongPhiMI = 0; + if (PN->getType() == Type::LongTy || PN->getType() == Type::ULongTy) { + LongPhiMI = BuildMI(X86::PHI, PN->getNumOperands(), PHIReg+1); + MBB->insert(MBB->begin()+NumPHIs++, LongPhiMI); + } for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { MachineBasicBlock *PredMBB = MBBMap[PN->getIncomingBlock(i)]; @@ -410,13 +466,17 @@ // available in a virtual register, insert the computation code into // PredMBB // - // FIXME: This should insert the code into the BOTTOM of the block, not - // the top of the block. This just makes for huge live ranges... - MachineBasicBlock::iterator PI = PredMBB->begin(); - while ((*PI)->getOpcode() == X86::PHI) ++PI; - - MI->addRegOperand(getReg(PN->getIncomingValue(i), PredMBB, PI)); - MI->addMachineBasicBlockOperand(PredMBB); + MachineBasicBlock::iterator PI = PredMBB->end(); + while (PI != PredMBB->begin() && + MII.isTerminatorInstr((*(PI-1))->getOpcode())) + --PI; + unsigned ValReg = getReg(PN->getIncomingValue(i), PredMBB, PI); + PhiMI->addRegOperand(ValReg); + PhiMI->addMachineBasicBlockOperand(PredMBB); + if (LongPhiMI) { + LongPhiMI->addRegOperand(ValReg+1); + LongPhiMI->addMachineBasicBlockOperand(PredMBB); + } } } } @@ -426,102 +486,108 @@ /// SetCC instructions - Here we just emit boilerplate code to set a byte-sized /// register, then move it to wherever the result should be. -/// We handle FP setcc instructions by pushing them, doing a -/// compare-and-pop-twice, and then copying the concodes to the main -/// processor's concodes (I didn't make this up, it's in the Intel manual) /// void ISel::visitSetCCInst(SetCondInst &I, unsigned OpNum) { // The arguments are already supposed to be of the same type. const Type *CompTy = I.getOperand(0)->getType(); + bool isSigned = CompTy->isSigned(); unsigned reg1 = getReg(I.getOperand(0)); unsigned reg2 = getReg(I.getOperand(1)); + unsigned DestReg = getReg(I); - unsigned Class = getClass(CompTy); + // LLVM -> X86 signed X86 unsigned + // ----- ---------- ------------ + // seteq -> sete sete + // setne -> setne setne + // setlt -> setl setb + // setgt -> setg seta + // setle -> setle setbe + // setge -> setge setae + static const unsigned OpcodeTab[2][6] = { + {X86::SETEr, X86::SETNEr, X86::SETBr, X86::SETAr, X86::SETBEr, X86::SETAEr}, + {X86::SETEr, X86::SETNEr, X86::SETLr, X86::SETGr, X86::SETLEr, X86::SETGEr}, + }; + + unsigned Class = getClassB(CompTy); switch (Class) { + default: assert(0 && "Unknown type class!"); // Emit: cmp , (do the comparison). We can // compare 8-bit with 8-bit, 16-bit with 16-bit, 32-bit with // 32-bit. case cByte: - BuildMI (BB, X86::CMPrr8, 2).addReg (reg1).addReg (reg2); + BuildMI(BB, X86::CMPrr8, 2).addReg(reg1).addReg(reg2); break; case cShort: - BuildMI (BB, X86::CMPrr16, 2).addReg (reg1).addReg (reg2); + BuildMI(BB, X86::CMPrr16, 2).addReg(reg1).addReg(reg2); break; case cInt: - BuildMI (BB, X86::CMPrr32, 2).addReg (reg1).addReg (reg2); - break; - -#if 0 - // Push the variables on the stack with fldl opcodes. - // FIXME: assuming var1, var2 are in memory, if not, spill to - // stack first - case cFP: // Floats - BuildMI (BB, X86::FLDr32, 1).addReg (reg1); - BuildMI (BB, X86::FLDr32, 1).addReg (reg2); + BuildMI(BB, X86::CMPrr32, 2).addReg(reg1).addReg(reg2); break; - case cFP (doubles): // Doubles - BuildMI (BB, X86::FLDr64, 1).addReg (reg1); - BuildMI (BB, X86::FLDr64, 1).addReg (reg2); + case cFP: + BuildMI(BB, X86::FpUCOM, 2).addReg(reg1).addReg(reg2); + BuildMI(BB, X86::FNSTSWr8, 0); + BuildMI(BB, X86::SAHF, 1); + isSigned = false; // Compare with unsigned operators break; -#endif + case cLong: - default: - visitInstruction(I); - } + if (OpNum < 2) { // seteq, setne + unsigned LoTmp = makeAnotherReg(Type::IntTy); + unsigned HiTmp = makeAnotherReg(Type::IntTy); + unsigned FinalTmp = makeAnotherReg(Type::IntTy); + BuildMI(BB, X86::XORrr32, 2, LoTmp).addReg(reg1).addReg(reg2); + BuildMI(BB, X86::XORrr32, 2, HiTmp).addReg(reg1+1).addReg(reg2+1); + BuildMI(BB, X86::ORrr32, 2, FinalTmp).addReg(LoTmp).addReg(HiTmp); + break; // Allow the sete or setne to be generated from flags set by OR + } else { + // Emit a sequence of code which compares the high and low parts once + // each, then uses a conditional move to handle the overflow case. For + // example, a setlt for long would generate code like this: + // + // AL = lo(op1) < lo(op2) // Signedness depends on operands + // BL = hi(op1) < hi(op2) // Always unsigned comparison + // dest = hi(op1) == hi(op2) ? AL : BL; + // -#if 0 - if (CompTy->isFloatingPoint()) { - // (Non-trapping) compare and pop twice. - BuildMI (BB, X86::FUCOMPP, 0); - // Move fp status word (concodes) to ax. - BuildMI (BB, X86::FNSTSWr8, 1, X86::AX); - // Load real concodes from ax. - BuildMI (BB, X86::SAHF, 1).addReg(X86::AH); + // FIXME: This would be much better if we had heirarchical register + // classes! Until then, hardcode registers so that we can deal with their + // aliases (because we don't have conditional byte moves). + // + BuildMI(BB, X86::CMPrr32, 2).addReg(reg1).addReg(reg2); + BuildMI(BB, OpcodeTab[0][OpNum], 0, X86::AL); + BuildMI(BB, X86::CMPrr32, 2).addReg(reg1+1).addReg(reg2+1); + BuildMI(BB, OpcodeTab[isSigned][OpNum], 0, X86::BL); + BuildMI(BB, X86::CMOVErr16, 2, X86::BX).addReg(X86::BX).addReg(X86::AX); + BuildMI(BB, X86::MOVrr8, 1, DestReg).addReg(X86::BL); + return; + } } -#endif - // Emit setOp instruction (extract concode; clobbers ax), - // using the following mapping: - // LLVM -> X86 signed X86 unsigned - // ----- ----- ----- - // seteq -> sete sete - // setne -> setne setne - // setlt -> setl setb - // setgt -> setg seta - // setle -> setle setbe - // setge -> setge setae - - static const unsigned OpcodeTab[2][6] = { - {X86::SETEr, X86::SETNEr, X86::SETBr, X86::SETAr, X86::SETBEr, X86::SETAEr}, - {X86::SETEr, X86::SETNEr, X86::SETLr, X86::SETGr, X86::SETLEr, X86::SETGEr}, - }; - - BuildMI(BB, OpcodeTab[CompTy->isSigned()][OpNum], 0, getReg(I)); + BuildMI(BB, OpcodeTab[isSigned][OpNum], 0, DestReg); } /// promote32 - Emit instructions to turn a narrow operand into a 32-bit-wide /// operand, in the specified target register. -void ISel::promote32 (unsigned targetReg, Value *v) { - unsigned vReg = getReg(v); - bool isUnsigned = v->getType()->isUnsigned(); - switch (getClass(v->getType())) { +void ISel::promote32(unsigned targetReg, const ValueRecord &VR) { + bool isUnsigned = VR.Ty->isUnsigned(); + switch (getClassB(VR.Ty)) { case cByte: // Extend value into target register (8->32) if (isUnsigned) - BuildMI(BB, X86::MOVZXr32r8, 1, targetReg).addReg(vReg); + BuildMI(BB, X86::MOVZXr32r8, 1, targetReg).addReg(VR.Reg); else - BuildMI(BB, X86::MOVSXr32r8, 1, targetReg).addReg(vReg); + BuildMI(BB, X86::MOVSXr32r8, 1, targetReg).addReg(VR.Reg); break; case cShort: // Extend value into target register (16->32) if (isUnsigned) - BuildMI(BB, X86::MOVZXr32r16, 1, targetReg).addReg(vReg); + BuildMI(BB, X86::MOVZXr32r16, 1, targetReg).addReg(VR.Reg); else - BuildMI(BB, X86::MOVSXr32r16, 1, targetReg).addReg(vReg); + BuildMI(BB, X86::MOVSXr32r16, 1, targetReg).addReg(VR.Reg); break; case cInt: // Move value into target register (32->32) - BuildMI(BB, X86::MOVrr32, 1, targetReg).addReg(vReg); + BuildMI(BB, X86::MOVrr32, 1, targetReg).addReg(VR.Reg); break; default: assert(0 && "Unpromotable operand class in promote32"); @@ -539,27 +605,29 @@ /// ret long, ulong : Move value into EAX/EDX and return /// ret float/double : Top of FP stack /// -void ISel::visitReturnInst (ReturnInst &I) { +void ISel::visitReturnInst(ReturnInst &I) { if (I.getNumOperands() == 0) { BuildMI(BB, X86::RET, 0); // Just emit a 'ret' instruction return; } Value *RetVal = I.getOperand(0); - switch (getClass(RetVal->getType())) { + unsigned RetReg = getReg(RetVal); + switch (getClassB(RetVal->getType())) { case cByte: // integral return values: extend or move into EAX and return case cShort: case cInt: - promote32(X86::EAX, RetVal); + promote32(X86::EAX, ValueRecord(RetReg, RetVal->getType())); break; case cFP: // Floats & Doubles: Return in ST(0) - BuildMI(BB, X86::FpMOV, 1, X86::ST0).addReg(getReg(RetVal)); + BuildMI(BB, X86::FpSETRESULT, 1).addReg(RetReg); break; case cLong: - // ret long: use EAX(least significant 32 bits)/EDX (most - // significant 32)... + BuildMI(BB, X86::MOVrr32, 1, X86::EAX).addReg(RetReg); + BuildMI(BB, X86::MOVrr32, 1, X86::EDX).addReg(RetReg+1); + break; default: - visitInstruction (I); + visitInstruction(I); } // Emit a 'ret' instruction BuildMI(BB, X86::RET, 0); @@ -572,36 +640,33 @@ /// void ISel::visitBranchInst(BranchInst &BI) { if (BI.isConditional()) { - BasicBlock *ifTrue = BI.getSuccessor(0); - BasicBlock *ifFalse = BI.getSuccessor(1); - - // Compare condition with zero, followed by jump-if-equal to ifFalse, and - // jump-if-nonequal to ifTrue unsigned condReg = getReg(BI.getCondition()); BuildMI(BB, X86::CMPri8, 2).addReg(condReg).addZImm(0); - BuildMI(BB, X86::JNE, 1).addPCDisp(BI.getSuccessor(0)); BuildMI(BB, X86::JE, 1).addPCDisp(BI.getSuccessor(1)); - } else { // unconditional branch - BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(0)); } + BuildMI(BB, X86::JMP, 1).addPCDisp(BI.getSuccessor(0)); } -/// visitCallInst - Push args on stack and do a procedure call instruction. -void ISel::visitCallInst(CallInst &CI) { + +/// doCall - This emits an abstract call instruction, setting up the arguments +/// and the return value as appropriate. For the actual function call itself, +/// it inserts the specified CallMI instruction into the stream. +/// +void ISel::doCall(const ValueRecord &Ret, MachineInstr *CallMI, + const std::vector &Args) { + // Count how many bytes are to be pushed on the stack... unsigned NumBytes = 0; - if (CI.getNumOperands() > 1) { - for (unsigned i = 1, e = CI.getNumOperands(); i != e; ++i) - switch (getClass(CI.getOperand(i)->getType())) { + if (!Args.empty()) { + for (unsigned i = 0, e = Args.size(); i != e; ++i) + switch (getClassB(Args[i].Ty)) { case cByte: case cShort: case cInt: - NumBytes += 4; - break; + NumBytes += 4; break; case cLong: - NumBytes += 8; - break; + NumBytes += 8; break; case cFP: - NumBytes += CI.getOperand(i)->getType() == Type::FloatTy ? 4 : 8; + NumBytes += Args[i].Ty == Type::FloatTy ? 4 : 8; break; default: assert(0 && "Unknown class!"); } @@ -611,60 +676,60 @@ // Arguments go on the stack in reverse order, as specified by the ABI. unsigned ArgOffset = 0; - for (unsigned i = 1, e = CI.getNumOperands(); i != e; ++i) { - Value *Arg = CI.getOperand(i); - switch (getClass(Arg->getType())) { + for (unsigned i = 0, e = Args.size(); i != e; ++i) { + unsigned ArgReg = Args[i].Reg; + switch (getClassB(Args[i].Ty)) { case cByte: case cShort: { // Promote arg to 32 bits wide into a temporary register... unsigned R = makeAnotherReg(Type::UIntTy); - promote32(R, Arg); + promote32(R, Args[i]); addRegOffset(BuildMI(BB, X86::MOVrm32, 5), X86::ESP, ArgOffset).addReg(R); break; } case cInt: addRegOffset(BuildMI(BB, X86::MOVrm32, 5), - X86::ESP, ArgOffset).addReg(getReg(Arg)); + X86::ESP, ArgOffset).addReg(ArgReg); break; - + case cLong: + addRegOffset(BuildMI(BB, X86::MOVrm32, 5), + X86::ESP, ArgOffset).addReg(ArgReg); + addRegOffset(BuildMI(BB, X86::MOVrm32, 5), + X86::ESP, ArgOffset+4).addReg(ArgReg+1); + ArgOffset += 4; // 8 byte entry, not 4. + break; + case cFP: - if (Arg->getType() == Type::FloatTy) { + if (Args[i].Ty == Type::FloatTy) { addRegOffset(BuildMI(BB, X86::FSTr32, 5), - X86::ESP, ArgOffset).addReg(getReg(Arg)); + X86::ESP, ArgOffset).addReg(ArgReg); } else { - assert(Arg->getType() == Type::DoubleTy && "Unknown FP type!"); - ArgOffset += 4; - addRegOffset(BuildMI(BB, X86::FSTr32, 5), - X86::ESP, ArgOffset).addReg(getReg(Arg)); + assert(Args[i].Ty == Type::DoubleTy && "Unknown FP type!"); + addRegOffset(BuildMI(BB, X86::FSTr64, 5), + X86::ESP, ArgOffset).addReg(ArgReg); + ArgOffset += 4; // 8 byte entry, not 4. } break; - default: - // FIXME: long/ulong/float/double args not handled. - visitInstruction(CI); - break; + default: assert(0 && "Unknown class!"); } ArgOffset += 4; } - } - - if (Function *F = CI.getCalledFunction()) { - // Emit a CALL instruction with PC-relative displacement. - BuildMI(BB, X86::CALLpcrel32, 1).addPCDisp(F); } else { - unsigned Reg = getReg(CI.getCalledValue()); - BuildMI(BB, X86::CALLr32, 1).addReg(Reg); + BuildMI(BB, X86::ADJCALLSTACKDOWN, 1).addZImm(0); } + BB->push_back(CallMI); + BuildMI(BB, X86::ADJCALLSTACKUP, 1).addZImm(NumBytes); // If there is a return value, scavenge the result from the location the call // leaves it in... // - if (CI.getType() != Type::VoidTy) { - unsigned resultTypeClass = getClass(CI.getType()); - switch (resultTypeClass) { + if (Ret.Ty != Type::VoidTy) { + unsigned DestClass = getClassB(Ret.Ty); + switch (DestClass) { case cByte: case cShort: case cInt: { @@ -674,32 +739,49 @@ X86::MOVrr8, X86::MOVrr16, X86::MOVrr32 }; static const unsigned AReg[] = { X86::AL, X86::AX, X86::EAX }; - BuildMI(BB, regRegMove[resultTypeClass], 1, getReg(CI)) - .addReg(AReg[resultTypeClass]); + BuildMI(BB, regRegMove[DestClass], 1, Ret.Reg).addReg(AReg[DestClass]); break; } case cFP: // Floating-point return values live in %ST(0) - BuildMI(BB, X86::FpMOV, 1, getReg(CI)).addReg(X86::ST0); + BuildMI(BB, X86::FpGETRESULT, 1, Ret.Reg); break; - default: - std::cerr << "Cannot get return value for call of type '" - << *CI.getType() << "'\n"; - visitInstruction(CI); + case cLong: // Long values are left in EDX:EAX + BuildMI(BB, X86::MOVrr32, 1, Ret.Reg).addReg(X86::EAX); + BuildMI(BB, X86::MOVrr32, 1, Ret.Reg+1).addReg(X86::EDX); + break; + default: assert(0 && "Unknown class!"); } } } + +/// visitCallInst - Push args on stack and do a procedure call instruction. +void ISel::visitCallInst(CallInst &CI) { + MachineInstr *TheCall; + if (Function *F = CI.getCalledFunction()) { + // Emit a CALL instruction with PC-relative displacement. + TheCall = BuildMI(X86::CALLpcrel32, 1).addGlobalAddress(F, true); + } else { // Emit an indirect call... + unsigned Reg = getReg(CI.getCalledValue()); + TheCall = BuildMI(X86::CALLr32, 1).addReg(Reg); + } + + std::vector Args; + for (unsigned i = 1, e = CI.getNumOperands(); i != e; ++i) + Args.push_back(ValueRecord(getReg(CI.getOperand(i)), + CI.getOperand(i)->getType())); + + unsigned DestReg = CI.getType() != Type::VoidTy ? getReg(CI) : 0; + doCall(ValueRecord(DestReg, CI.getType()), TheCall, Args); +} + + /// visitSimpleBinary - Implement simple binary operators for integral types... /// OperatorClass is one of: 0 for Add, 1 for Sub, 2 for And, 3 for Or, /// 4 for Xor. /// void ISel::visitSimpleBinary(BinaryOperator &B, unsigned OperatorClass) { - if (B.getType() == Type::BoolTy) // FIXME: Handle bools for logicals - visitInstruction(B); - - unsigned Class = getClass(B.getType()); - if (Class > cFP) // FIXME: Handle longs - visitInstruction(B); + unsigned Class = getClassB(B.getType()); static const unsigned OpcodeTab[][4] = { // Arithmetic operators @@ -711,28 +793,45 @@ { X86:: ORrr8, X86:: ORrr16, X86:: ORrr32, 0 }, // OR { X86::XORrr8, X86::XORrr16, X86::XORrr32, 0 }, // XOR }; + + bool isLong = false; + if (Class == cLong) { + isLong = true; + Class = cInt; // Bottom 32 bits are handled just like ints + } unsigned Opcode = OpcodeTab[OperatorClass][Class]; assert(Opcode && "Floating point arguments to logical inst?"); unsigned Op0r = getReg(B.getOperand(0)); unsigned Op1r = getReg(B.getOperand(1)); - BuildMI(BB, Opcode, 2, getReg(B)).addReg(Op0r).addReg(Op1r); + unsigned DestReg = getReg(B); + BuildMI(BB, Opcode, 2, DestReg).addReg(Op0r).addReg(Op1r); + + if (isLong) { // Handle the upper 32 bits of long values... + static const unsigned TopTab[] = { + X86::ADCrr32, X86::SBBrr32, X86::ANDrr32, X86::ORrr32, X86::XORrr32 + }; + BuildMI(BB, TopTab[OperatorClass], 2, + DestReg+1).addReg(Op0r+1).addReg(Op1r+1); + } } -/// doMultiply - Emit appropriate instructions to multiply together -/// the registers op0Reg and op1Reg, and put the result in destReg. -/// The type of the result should be given as resultType. +/// doMultiply - Emit appropriate instructions to multiply together the +/// registers op0Reg and op1Reg, and put the result in DestReg. The type of the +/// result should be given as DestTy. +/// +/// FIXME: doMultiply should use one of the two address IMUL instructions! +/// void ISel::doMultiply(MachineBasicBlock *MBB, MachineBasicBlock::iterator &MBBI, - unsigned destReg, const Type *resultType, + unsigned DestReg, const Type *DestTy, unsigned op0Reg, unsigned op1Reg) { - unsigned Class = getClass(resultType); + unsigned Class = getClass(DestTy); switch (Class) { case cFP: // Floating point multiply - BuildMI(BB, X86::FpMUL, 2, destReg).addReg(op0Reg).addReg(op1Reg); + BMI(BB, MBBI, X86::FpMUL, 2, DestReg).addReg(op0Reg).addReg(op1Reg); return; default: - case cLong: - assert(0 && "doMultiply not implemented for this class yet!"); + case cLong: assert(0 && "doMultiply cannot operate on LONG values!"); case cByte: case cShort: case cInt: // Small integerals, handled below... @@ -740,30 +839,58 @@ } static const unsigned Regs[] ={ X86::AL , X86::AX , X86::EAX }; - static const unsigned MulOpcode[]={ X86::MULrr8, X86::MULrr16, X86::MULrr32 }; + static const unsigned MulOpcode[]={ X86::MULr8 , X86::MULr16 , X86::MULr32 }; static const unsigned MovOpcode[]={ X86::MOVrr8, X86::MOVrr16, X86::MOVrr32 }; unsigned Reg = Regs[Class]; // Emit a MOV to put the first operand into the appropriately-sized // subreg of EAX. - BMI(MBB, MBBI, MovOpcode[Class], 1, Reg).addReg (op0Reg); + BMI(MBB, MBBI, MovOpcode[Class], 1, Reg).addReg(op0Reg); // Emit the appropriate multiply instruction. - BMI(MBB, MBBI, MulOpcode[Class], 1).addReg (op1Reg); + BMI(MBB, MBBI, MulOpcode[Class], 1).addReg(op1Reg); // Emit another MOV to put the result into the destination register. - BMI(MBB, MBBI, MovOpcode[Class], 1, destReg).addReg (Reg); + BMI(MBB, MBBI, MovOpcode[Class], 1, DestReg).addReg(Reg); } /// visitMul - Multiplies are not simple binary operators because they must deal /// with the EAX register explicitly. /// void ISel::visitMul(BinaryOperator &I) { - unsigned DestReg = getReg(I); unsigned Op0Reg = getReg(I.getOperand(0)); unsigned Op1Reg = getReg(I.getOperand(1)); - MachineBasicBlock::iterator MBBI = BB->end(); - doMultiply(BB, MBBI, DestReg, I.getType(), Op0Reg, Op1Reg); + unsigned DestReg = getReg(I); + + // Simple scalar multiply? + if (I.getType() != Type::LongTy && I.getType() != Type::ULongTy) { + MachineBasicBlock::iterator MBBI = BB->end(); + doMultiply(BB, MBBI, DestReg, I.getType(), Op0Reg, Op1Reg); + } else { + // Long value. We have to do things the hard way... + // Multiply the two low parts... capturing carry into EDX + BuildMI(BB, X86::MOVrr32, 1, X86::EAX).addReg(Op0Reg); + BuildMI(BB, X86::MULr32, 1).addReg(Op1Reg); // AL*BL + + unsigned OverflowReg = makeAnotherReg(Type::UIntTy); + BuildMI(BB, X86::MOVrr32, 1, DestReg).addReg(X86::EAX); // AL*BL + BuildMI(BB, X86::MOVrr32, 1, OverflowReg).addReg(X86::EDX); // AL*BL >> 32 + + MachineBasicBlock::iterator MBBI = BB->end(); + unsigned AHBLReg = makeAnotherReg(Type::UIntTy); + doMultiply(BB, MBBI, AHBLReg, Type::UIntTy, Op0Reg+1, Op1Reg); // AH*BL + + unsigned AHBLplusOverflowReg = makeAnotherReg(Type::UIntTy); + BuildMI(BB, X86::ADDrr32, 2, // AH*BL+(AL*BL >> 32) + AHBLplusOverflowReg).addReg(AHBLReg).addReg(OverflowReg); + + MBBI = BB->end(); + unsigned ALBHReg = makeAnotherReg(Type::UIntTy); + doMultiply(BB, MBBI, ALBHReg, Type::UIntTy, Op0Reg, Op1Reg+1); // AL*BH + + BuildMI(BB, X86::ADDrr32, 2, // AL*BH + AH*BL + (AL*BL >> 32) + DestReg+1).addReg(AHBLplusOverflowReg).addReg(ALBHReg); + } } @@ -779,19 +906,36 @@ unsigned ResultReg = getReg(I); switch (Class) { - case cFP: // Floating point multiply + case cFP: // Floating point divide if (I.getOpcode() == Instruction::Div) BuildMI(BB, X86::FpDIV, 2, ResultReg).addReg(Op0Reg).addReg(Op1Reg); - else - BuildMI(BB, X86::FpREM, 2, ResultReg).addReg(Op0Reg).addReg(Op1Reg); + else { // Floating point remainder... + MachineInstr *TheCall = + BuildMI(X86::CALLpcrel32, 1).addExternalSymbol("fmod", true); + std::vector Args; + Args.push_back(ValueRecord(Op0Reg, Type::DoubleTy)); + Args.push_back(ValueRecord(Op1Reg, Type::DoubleTy)); + doCall(ValueRecord(ResultReg, Type::DoubleTy), TheCall, Args); + } return; - default: - case cLong: - assert(0 && "div/rem not implemented for this class yet!"); - case cByte: - case cShort: - case cInt: // Small integerals, handled below... - break; + case cLong: { + static const char *FnName[] = + { "__moddi3", "__divdi3", "__umoddi3", "__udivdi3" }; + + unsigned NameIdx = I.getType()->isUnsigned()*2; + NameIdx += I.getOpcode() == Instruction::Div; + MachineInstr *TheCall = + BuildMI(X86::CALLpcrel32, 1).addExternalSymbol(FnName[NameIdx], true); + + std::vector Args; + Args.push_back(ValueRecord(Op0Reg, Type::LongTy)); + Args.push_back(ValueRecord(Op1Reg, Type::LongTy)); + doCall(ValueRecord(ResultReg, Type::LongTy), TheCall, Args); + return; + } + case cByte: case cShort: case cInt: + break; // Small integerals, handled below... + default: assert(0 && "Unknown class!"); } static const unsigned Regs[] ={ X86::AL , X86::AX , X86::EAX }; @@ -801,8 +945,8 @@ static const unsigned ExtRegs[] ={ X86::AH , X86::DX , X86::EDX }; static const unsigned DivOpcode[][4] = { - { X86::DIVrr8 , X86::DIVrr16 , X86::DIVrr32 , 0 }, // Unsigned division - { X86::IDIVrr8, X86::IDIVrr16, X86::IDIVrr32, 0 }, // Signed division + { X86::DIVr8 , X86::DIVr16 , X86::DIVr32 , 0 }, // Unsigned division + { X86::IDIVr8, X86::IDIVr16, X86::IDIVr32, 0 }, // Signed division }; bool isSigned = I.getType()->isSigned(); @@ -836,60 +980,149 @@ /// shift values equal to 1. Even the general case is sort of special, /// because the shift amount has to be in CL, not just any old register. /// -void ISel::visitShiftInst (ShiftInst &I) { - unsigned Op0r = getReg (I.getOperand(0)); +void ISel::visitShiftInst(ShiftInst &I) { + unsigned SrcReg = getReg(I.getOperand(0)); unsigned DestReg = getReg(I); bool isLeftShift = I.getOpcode() == Instruction::Shl; - bool isOperandSigned = I.getType()->isUnsigned(); - unsigned OperandClass = getClass(I.getType()); + bool isSigned = I.getType()->isSigned(); + unsigned Class = getClass(I.getType()); + + static const unsigned ConstantOperand[][4] = { + { X86::SHRir8, X86::SHRir16, X86::SHRir32, X86::SHRDir32 }, // SHR + { X86::SARir8, X86::SARir16, X86::SARir32, X86::SHRDir32 }, // SAR + { X86::SHLir8, X86::SHLir16, X86::SHLir32, X86::SHLDir32 }, // SHL + { X86::SHLir8, X86::SHLir16, X86::SHLir32, X86::SHLDir32 }, // SAL = SHL + }; - if (OperandClass > cInt) - visitInstruction(I); // Can't handle longs yet! + static const unsigned NonConstantOperand[][4] = { + { X86::SHRrr8, X86::SHRrr16, X86::SHRrr32 }, // SHR + { X86::SARrr8, X86::SARrr16, X86::SARrr32 }, // SAR + { X86::SHLrr8, X86::SHLrr16, X86::SHLrr32 }, // SHL + { X86::SHLrr8, X86::SHLrr16, X86::SHLrr32 }, // SAL = SHL + }; - if (ConstantUInt *CUI = dyn_cast (I.getOperand (1))) - { - // The shift amount is constant, guaranteed to be a ubyte. Get its value. - assert(CUI->getType() == Type::UByteTy && "Shift amount not a ubyte?"); - unsigned char shAmt = CUI->getValue(); - - static const unsigned ConstantOperand[][4] = { - { X86::SHRir8, X86::SHRir16, X86::SHRir32, 0 }, // SHR - { X86::SARir8, X86::SARir16, X86::SARir32, 0 }, // SAR - { X86::SHLir8, X86::SHLir16, X86::SHLir32, 0 }, // SHL - { X86::SHLir8, X86::SHLir16, X86::SHLir32, 0 }, // SAL = SHL - }; + // Longs, as usual, are handled specially... + if (Class == cLong) { + // If we have a constant shift, we can generate much more efficient code + // than otherwise... + // + if (ConstantUInt *CUI = dyn_cast(I.getOperand(1))) { + unsigned Amount = CUI->getValue(); + if (Amount < 32) { + const unsigned *Opc = ConstantOperand[isLeftShift*2+isSigned]; + if (isLeftShift) { + BuildMI(BB, Opc[3], 3, + DestReg+1).addReg(SrcReg+1).addReg(SrcReg).addZImm(Amount); + BuildMI(BB, Opc[2], 2, DestReg).addReg(SrcReg).addZImm(Amount); + } else { + BuildMI(BB, Opc[3], 3, + DestReg).addReg(SrcReg ).addReg(SrcReg+1).addZImm(Amount); + BuildMI(BB, Opc[2], 2, DestReg+1).addReg(SrcReg+1).addZImm(Amount); + } + } else { // Shifting more than 32 bits + Amount -= 32; + if (isLeftShift) { + BuildMI(BB, X86::SHLir32, 2,DestReg+1).addReg(SrcReg).addZImm(Amount); + BuildMI(BB, X86::MOVir32, 1,DestReg ).addZImm(0); + } else { + unsigned Opcode = isSigned ? X86::SARir32 : X86::SHRir32; + BuildMI(BB, Opcode, 2, DestReg).addReg(SrcReg+1).addZImm(Amount); + BuildMI(BB, X86::MOVir32, 1, DestReg+1).addZImm(0); + } + } + } else { + visitInstruction(I); // FIXME: Implement long shift by non-constant + } + return; + } - const unsigned *OpTab = // Figure out the operand table to use - ConstantOperand[isLeftShift*2+isOperandSigned]; + if (ConstantUInt *CUI = dyn_cast(I.getOperand(1))) { + // The shift amount is constant, guaranteed to be a ubyte. Get its value. + assert(CUI->getType() == Type::UByteTy && "Shift amount not a ubyte?"); - // Emit: reg, shamt (shift-by-immediate opcode "ir" form.) - BuildMI(BB, OpTab[OperandClass], 2, DestReg).addReg(Op0r).addZImm(shAmt); - } - else - { - // The shift amount is non-constant. - // - // In fact, you can only shift with a variable shift amount if - // that amount is already in the CL register, so we have to put it - // there first. - // + const unsigned *Opc = ConstantOperand[isLeftShift*2+isSigned]; + BuildMI(BB, Opc[Class], 2, DestReg).addReg(SrcReg).addZImm(CUI->getValue()); + } else { // The shift amount is non-constant. + BuildMI(BB, X86::MOVrr8, 1, X86::CL).addReg(getReg(I.getOperand(1))); - // Emit: move cl, shiftAmount (put the shift amount in CL.) - BuildMI(BB, X86::MOVrr8, 1, X86::CL).addReg(getReg(I.getOperand(1))); + const unsigned *Opc = NonConstantOperand[isLeftShift*2+isSigned]; + BuildMI(BB, Opc[Class], 1, DestReg).addReg(SrcReg); + } +} - // This is a shift right (SHR). - static const unsigned NonConstantOperand[][4] = { - { X86::SHRrr8, X86::SHRrr16, X86::SHRrr32, 0 }, // SHR - { X86::SARrr8, X86::SARrr16, X86::SARrr32, 0 }, // SAR - { X86::SHLrr8, X86::SHLrr16, X86::SHLrr32, 0 }, // SHL - { X86::SHLrr8, X86::SHLrr16, X86::SHLrr32, 0 }, // SAL = SHL - }; - const unsigned *OpTab = // Figure out the operand table to use - NonConstantOperand[isLeftShift*2+isOperandSigned]; +/// doFPLoad - This method is used to load an FP value from memory using the +/// current endianness. NOTE: This method returns a partially constructed load +/// instruction which needs to have the memory source filled in still. +/// +MachineInstr *ISel::doFPLoad(MachineBasicBlock *MBB, + MachineBasicBlock::iterator &MBBI, + const Type *Ty, unsigned DestReg) { + assert(Ty == Type::FloatTy || Ty == Type::DoubleTy && "Unknown FP type!"); + unsigned LoadOpcode = Ty == Type::FloatTy ? X86::FLDr32 : X86::FLDr64; - BuildMI(BB, OpTab[OperandClass], 1, DestReg).addReg(Op0r); - } + if (TM.getTargetData().isLittleEndian()) // fast path... + return BMI(MBB, MBBI, LoadOpcode, 4, DestReg); + + // If we are big-endian, start by creating an LEA instruction to represent the + // address of the memory location to load from... + // + unsigned SrcAddrReg = makeAnotherReg(Type::UIntTy); + MachineInstr *Result = BMI(MBB, MBBI, X86::LEAr32, 5, SrcAddrReg); + + // Allocate a temporary stack slot to transform the value into... + int FrameIdx = F->getFrameInfo()->CreateStackObject(Ty, TM.getTargetData()); + + // Perform the bswaps 32 bits at a time... + unsigned TmpReg1 = makeAnotherReg(Type::UIntTy); + unsigned TmpReg2 = makeAnotherReg(Type::UIntTy); + addDirectMem(BMI(MBB, MBBI, X86::MOVmr32, 4, TmpReg1), SrcAddrReg); + BMI(MBB, MBBI, X86::BSWAPr32, 1, TmpReg2).addReg(TmpReg1); + unsigned Offset = (Ty == Type::DoubleTy) << 2; + addFrameReference(BMI(MBB, MBBI, X86::MOVrm32, 5), + FrameIdx, Offset).addReg(TmpReg2); + + if (Ty == Type::DoubleTy) { // Swap the other 32 bits of a double value... + TmpReg1 = makeAnotherReg(Type::UIntTy); + TmpReg2 = makeAnotherReg(Type::UIntTy); + + addRegOffset(BMI(MBB, MBBI, X86::MOVmr32, 4, TmpReg1), SrcAddrReg, 4); + BMI(MBB, MBBI, X86::BSWAPr32, 1, TmpReg2).addReg(TmpReg1); + unsigned Offset = (Ty == Type::DoubleTy) << 2; + addFrameReference(BMI(MBB, MBBI, X86::MOVrm32,5), FrameIdx).addReg(TmpReg2); + } + + // Now we can reload the final byteswapped result into the final destination. + addFrameReference(BMI(MBB, MBBI, LoadOpcode, 4, DestReg), FrameIdx); + return Result; +} + +/// EmitByteSwap - Byteswap SrcReg into DestReg. +/// +void ISel::EmitByteSwap(unsigned DestReg, unsigned SrcReg, unsigned Class) { + // Emit the byte swap instruction... + switch (Class) { + case cByte: + // No byteswap neccesary for 8 bit value... + BuildMI(BB, X86::MOVrr8, 1, DestReg).addReg(SrcReg); + break; + case cInt: + // Use the 32 bit bswap instruction to do a 32 bit swap... + BuildMI(BB, X86::BSWAPr32, 1, DestReg).addReg(SrcReg); + break; + + case cShort: + // For 16 bit we have to use an xchg instruction, because there is no + // 16-bit bswap. XCHG is neccesarily not in SSA form, so we force things + // into AX to do the xchg. + // + BuildMI(BB, X86::MOVrr16, 1, X86::AX).addReg(SrcReg); + BuildMI(BB, X86::XCHGrr8, 2).addReg(X86::AL, MOTy::UseAndDef) + .addReg(X86::AH, MOTy::UseAndDef); + BuildMI(BB, X86::MOVrr16, 1, DestReg).addReg(X86::AX); + break; + default: assert(0 && "Cannot byteswap this class!"); + } } @@ -905,16 +1138,14 @@ unsigned Class = getClass(I.getType()); switch (Class) { - default: visitInstruction(I); // FIXME: Handle longs... case cFP: { - // FIXME: Handle endian swapping for FP values. - unsigned Opcode = I.getType() == Type::FloatTy ? X86::FLDr32 : X86::FLDr64; - addDirectMem(BuildMI(BB, Opcode, 4, DestReg), SrcAddrReg); + MachineBasicBlock::iterator MBBI = BB->end(); + addDirectMem(doFPLoad(BB, MBBI, I.getType(), DestReg), SrcAddrReg); return; } - case cInt: // Integers of various sizes handled below - case cShort: - case cByte: break; + case cLong: case cInt: case cShort: case cByte: + break; // Integers of various sizes handled below + default: assert(0 && "Unknown memory class!"); } // We need to adjust the input pointer if we are emulating a big-endian @@ -929,38 +1160,69 @@ } unsigned IReg = DestReg; - if (!isLittleEndian) { // If big endian we need an intermediate stage - IReg = makeAnotherReg(I.getType()); - std::swap(IReg, DestReg); - } + if (!isLittleEndian) // If big endian we need an intermediate stage + DestReg = makeAnotherReg(Class != cLong ? I.getType() : Type::UIntTy); - static const unsigned Opcode[] = { X86::MOVmr8, X86::MOVmr16, X86::MOVmr32 }; + static const unsigned Opcode[] = { + X86::MOVmr8, X86::MOVmr16, X86::MOVmr32, 0, X86::MOVmr32 + }; addDirectMem(BuildMI(BB, Opcode[Class], 4, DestReg), SrcAddrReg); - if (!isLittleEndian) { - // Emit the byte swap instruction... - switch (Class) { - case cByte: - // No byteswap neccesary for 8 bit value... - BuildMI(BB, X86::MOVrr8, 1, IReg).addReg(DestReg); - break; - case cInt: - // Use the 32 bit bswap instruction to do a 32 bit swap... - BuildMI(BB, X86::BSWAPr32, 1, IReg).addReg(DestReg); - break; - - case cShort: - // For 16 bit we have to use an xchg instruction, because there is no - // 16-bit bswap. XCHG is neccesarily not in SSA form, so we force things - // into AX to do the xchg. - // - BuildMI(BB, X86::MOVrr16, 1, X86::AX).addReg(DestReg); - BuildMI(BB, X86::XCHGrr8, 2).addReg(X86::AL, MOTy::UseAndDef) - .addReg(X86::AH, MOTy::UseAndDef); - BuildMI(BB, X86::MOVrr16, 1, DestReg).addReg(X86::AX); - break; - default: assert(0 && "Class not handled yet!"); + // Handle long values now... + if (Class == cLong) { + if (isLittleEndian) { + addRegOffset(BuildMI(BB, X86::MOVmr32, 4, DestReg+1), SrcAddrReg, 4); + } else { + EmitByteSwap(IReg+1, DestReg, cInt); + unsigned TempReg = makeAnotherReg(Type::IntTy); + addRegOffset(BuildMI(BB, X86::MOVmr32, 4, TempReg), SrcAddrReg, 4); + EmitByteSwap(IReg, TempReg, cInt); } + return; + } + + if (!isLittleEndian) + EmitByteSwap(IReg, DestReg, Class); +} + + +/// doFPStore - This method is used to store an FP value to memory using the +/// current endianness. +/// +void ISel::doFPStore(const Type *Ty, unsigned DestAddrReg, unsigned SrcReg) { + assert(Ty == Type::FloatTy || Ty == Type::DoubleTy && "Unknown FP type!"); + unsigned StoreOpcode = Ty == Type::FloatTy ? X86::FSTr32 : X86::FSTr64; + + if (TM.getTargetData().isLittleEndian()) { // fast path... + addDirectMem(BuildMI(BB, StoreOpcode,5), DestAddrReg).addReg(SrcReg); + return; + } + + // Allocate a temporary stack slot to transform the value into... + int FrameIdx = F->getFrameInfo()->CreateStackObject(Ty, TM.getTargetData()); + unsigned SrcAddrReg = makeAnotherReg(Type::UIntTy); + addFrameReference(BuildMI(BB, X86::LEAr32, 5, SrcAddrReg), FrameIdx); + + // Store the value into a temporary stack slot... + addDirectMem(BuildMI(BB, StoreOpcode, 5), SrcAddrReg).addReg(SrcReg); + + // Perform the bswaps 32 bits at a time... + unsigned TmpReg1 = makeAnotherReg(Type::UIntTy); + unsigned TmpReg2 = makeAnotherReg(Type::UIntTy); + addDirectMem(BuildMI(BB, X86::MOVmr32, 4, TmpReg1), SrcAddrReg); + BuildMI(BB, X86::BSWAPr32, 1, TmpReg2).addReg(TmpReg1); + unsigned Offset = (Ty == Type::DoubleTy) << 2; + addRegOffset(BuildMI(BB, X86::MOVrm32, 5), + DestAddrReg, Offset).addReg(TmpReg2); + + if (Ty == Type::DoubleTy) { // Swap the other 32 bits of a double value... + TmpReg1 = makeAnotherReg(Type::UIntTy); + TmpReg2 = makeAnotherReg(Type::UIntTy); + + addRegOffset(BuildMI(BB, X86::MOVmr32, 4, TmpReg1), SrcAddrReg, 4); + BuildMI(BB, X86::BSWAPr32, 1, TmpReg2).addReg(TmpReg1); + unsigned Offset = (Ty == Type::DoubleTy) << 2; + addDirectMem(BuildMI(BB, X86::MOVrm32, 5), DestAddrReg).addReg(TmpReg2); } } @@ -971,22 +1233,31 @@ void ISel::visitStoreInst(StoreInst &I) { bool isLittleEndian = TM.getTargetData().isLittleEndian(); bool hasLongPointers = TM.getTargetData().getPointerSize() == 8; - unsigned ValReg = getReg(I.getOperand(0)); - unsigned AddressReg = getReg(I.getOperand(1)); + unsigned ValReg = getReg(I.getOperand(0)); + unsigned AddressReg = getReg(I.getOperand(1)); unsigned Class = getClass(I.getOperand(0)->getType()); switch (Class) { - default: visitInstruction(I); // FIXME: Handle longs... - case cFP: { - // FIXME: Handle endian swapping for FP values. - unsigned Opcode = I.getOperand(0)->getType() == Type::FloatTy ? - X86::FSTr32 : X86::FSTr64; - addDirectMem(BuildMI(BB, Opcode, 1+4), AddressReg).addReg(ValReg); + case cLong: + if (isLittleEndian) { + addDirectMem(BuildMI(BB, X86::MOVrm32, 1+4), AddressReg).addReg(ValReg); + addRegOffset(BuildMI(BB, X86::MOVrm32, 1+4), + AddressReg, 4).addReg(ValReg+1); + } else { + unsigned T1 = makeAnotherReg(Type::IntTy); + unsigned T2 = makeAnotherReg(Type::IntTy); + EmitByteSwap(T1, ValReg , cInt); + EmitByteSwap(T2, ValReg+1, cInt); + addDirectMem(BuildMI(BB, X86::MOVrm32, 1+4), AddressReg).addReg(T2); + addRegOffset(BuildMI(BB, X86::MOVrm32, 1+4), AddressReg, 4).addReg(T1); + } return; - } - case cInt: // Integers of various sizes handled below - case cShort: - case cByte: break; + case cFP: + doFPStore(I.getOperand(0)->getType(), AddressReg, ValReg); + return; + case cInt: case cShort: case cByte: + break; // Integers of various sizes handled below + default: assert(0 && "Unknown memory class!"); } if (!isLittleEndian && hasLongPointers && @@ -997,26 +1268,9 @@ } if (!isLittleEndian && Class != cByte) { - // Emit a byte swap instruction... - switch (Class) { - case cInt: { - unsigned R = makeAnotherReg(I.getOperand(0)->getType()); - BuildMI(BB, X86::BSWAPr32, 1, R).addReg(ValReg); - ValReg = R; - break; - } - case cShort: - // For 16 bit we have to use an xchg instruction, because there is no - // 16-bit bswap. XCHG is neccesarily not in SSA form, so we force things - // into AX to do the xchg. - // - BuildMI(BB, X86::MOVrr16, 1, X86::AX).addReg(ValReg); - BuildMI(BB, X86::XCHGrr8, 2).addReg(X86::AL, MOTy::UseAndDef) - .addReg(X86::AH, MOTy::UseAndDef); - ValReg = X86::AX; - break; - default: assert(0 && "Unknown class!"); - } + unsigned R = makeAnotherReg(I.getOperand(0)->getType()); + EmitByteSwap(R, ValReg, Class); + ValReg = R; } static const unsigned Opcode[] = { X86::MOVrm8, X86::MOVrm16, X86::MOVrm32 }; @@ -1026,85 +1280,195 @@ /// visitCastInst - Here we have various kinds of copying with or without /// sign extension going on. -void -ISel::visitCastInst (CastInst &CI) -{ - const Type *targetType = CI.getType (); - Value *operand = CI.getOperand (0); - unsigned operandReg = getReg (operand); - const Type *sourceType = operand->getType (); - unsigned destReg = getReg (CI); - // - // Currently we handle: - // - // 1) cast * to bool - // - // 2) cast {sbyte, ubyte} to {sbyte, ubyte} - // cast {short, ushort} to {ushort, short} - // cast {int, uint, ptr} to {int, uint, ptr} - // - // 3) cast {sbyte, ubyte} to {ushort, short} - // cast {sbyte, ubyte} to {int, uint, ptr} - // cast {short, ushort} to {int, uint, ptr} - // - // 4) cast {int, uint, ptr} to {short, ushort} - // cast {int, uint, ptr} to {sbyte, ubyte} - // cast {short, ushort} to {sbyte, ubyte} - - // 1) Implement casts to bool by using compare on the operand followed - // by set if not zero on the result. - if (targetType == Type::BoolTy) - { - BuildMI (BB, X86::CMPri8, 2).addReg (operandReg).addZImm (0); - BuildMI (BB, X86::SETNEr, 1, destReg); - return; - } +void ISel::visitCastInst(CastInst &CI) { + const Type *DestTy = CI.getType(); + Value *Src = CI.getOperand(0); + unsigned SrcReg = getReg(Src); + const Type *SrcTy = Src->getType(); + unsigned SrcClass = getClassB(SrcTy); + unsigned DestReg = getReg(CI); + unsigned DestClass = getClassB(DestTy); + + // Implement casts to bool by using compare on the operand followed by set if + // not zero on the result. + if (DestTy == Type::BoolTy) { + if (SrcClass == cFP || SrcClass == cLong) + visitInstruction(CI); + + BuildMI(BB, X86::CMPri8, 2).addReg(SrcReg).addZImm(0); + BuildMI(BB, X86::SETNEr, 1, DestReg); + return; + } - // 2) Implement casts between values of the same type class (as determined - // by getClass) by using a register-to-register move. - unsigned srcClass = getClassB(sourceType); - unsigned targClass = getClass(targetType); - static const unsigned regRegMove[] = { - X86::MOVrr8, X86::MOVrr16, X86::MOVrr32 + static const unsigned RegRegMove[] = { + X86::MOVrr8, X86::MOVrr16, X86::MOVrr32, X86::FpMOV, X86::MOVrr32 }; - if (srcClass <= cInt && targClass <= cInt && srcClass == targClass) { - BuildMI(BB, regRegMove[srcClass], 1, destReg).addReg(operandReg); + // Implement casts between values of the same type class (as determined by + // getClass) by using a register-to-register move. + if (SrcClass == DestClass) { + if (SrcClass <= cInt || (SrcClass == cFP && SrcTy == DestTy)) { + BuildMI(BB, RegRegMove[SrcClass], 1, DestReg).addReg(SrcReg); + } else if (SrcClass == cFP) { + if (SrcTy == Type::FloatTy) { // double -> float + assert(DestTy == Type::DoubleTy && "Unknown cFP member!"); + BuildMI(BB, X86::FpMOV, 1, DestReg).addReg(SrcReg); + } else { // float -> double + assert(SrcTy == Type::DoubleTy && DestTy == Type::FloatTy && + "Unknown cFP member!"); + // Truncate from double to float by storing to memory as short, then + // reading it back. + unsigned FltAlign = TM.getTargetData().getFloatAlignment(); + int FrameIdx = F->getFrameInfo()->CreateStackObject(4, FltAlign); + addFrameReference(BuildMI(BB, X86::FSTr32, 5), FrameIdx).addReg(SrcReg); + addFrameReference(BuildMI(BB, X86::FLDr32, 5, DestReg), FrameIdx); + } + } else if (SrcClass == cLong) { + BuildMI(BB, X86::MOVrr32, 1, DestReg).addReg(SrcReg); + BuildMI(BB, X86::MOVrr32, 1, DestReg+1).addReg(SrcReg+1); + } else { + visitInstruction(CI); + } return; } - // 3) Handle cast of SMALLER int to LARGER int using a move with sign - // extension or zero extension, depending on whether the source type - // was signed. - if ((srcClass <= cInt) && (targClass <= cInt) && (srcClass < targClass)) - { - static const unsigned ops[] = { - X86::MOVSXr16r8, X86::MOVSXr32r8, X86::MOVSXr32r16, - X86::MOVZXr16r8, X86::MOVZXr32r8, X86::MOVZXr32r16 - }; - unsigned srcSigned = sourceType->isSigned (); - BuildMI (BB, ops[3 * srcSigned + srcClass + targClass - 1], 1, - destReg).addReg (operandReg); - return; + + // Handle cast of SMALLER int to LARGER int using a move with sign extension + // or zero extension, depending on whether the source type was signed. + if (SrcClass <= cInt && (DestClass <= cInt || DestClass == cLong) && + SrcClass < DestClass) { + bool isLong = DestClass == cLong; + if (isLong) DestClass = cInt; + + static const unsigned Opc[][4] = { + { X86::MOVSXr16r8, X86::MOVSXr32r8, X86::MOVSXr32r16, X86::MOVrr32 }, // s + { X86::MOVZXr16r8, X86::MOVZXr32r8, X86::MOVZXr32r16, X86::MOVrr32 } // u + }; + + bool isUnsigned = SrcTy->isUnsigned(); + BuildMI(BB, Opc[isUnsigned][SrcClass + DestClass - 1], 1, + DestReg).addReg(SrcReg); + + if (isLong) { // Handle upper 32 bits as appropriate... + if (isUnsigned) // Zero out top bits... + BuildMI(BB, X86::MOVir32, 1, DestReg+1).addZImm(0); + else // Sign extend bottom half... + BuildMI(BB, X86::SARir32, 2, DestReg+1).addReg(DestReg).addZImm(31); } - // 4) Handle cast of LARGER int to SMALLER int using a move to EAX - // followed by a move out of AX or AL. - if ((srcClass <= cInt) && (targClass <= cInt) && (srcClass > targClass)) - { - static const unsigned AReg[] = { X86::AL, X86::AX, X86::EAX }; - BuildMI (BB, regRegMove[srcClass], 1, - AReg[srcClass]).addReg (operandReg); - BuildMI (BB, regRegMove[targClass], 1, destReg).addReg (AReg[srcClass]); - return; + return; + } + + // Special case long -> int ... + if (SrcClass == cLong && DestClass == cInt) { + BuildMI(BB, X86::MOVrr32, 1, DestReg).addReg(SrcReg); + return; + } + + // Handle cast of LARGER int to SMALLER int using a move to EAX followed by a + // move out of AX or AL. + if ((SrcClass <= cInt || SrcClass == cLong) && DestClass <= cInt + && SrcClass > DestClass) { + static const unsigned AReg[] = { X86::AL, X86::AX, X86::EAX, 0, X86::EAX }; + BuildMI(BB, RegRegMove[SrcClass], 1, AReg[SrcClass]).addReg(SrcReg); + BuildMI(BB, RegRegMove[DestClass], 1, DestReg).addReg(AReg[DestClass]); + return; + } + + // Handle casts from integer to floating point now... + if (DestClass == cFP) { + // unsigned int -> load as 64 bit int. + // unsigned long long -> more complex + if (SrcTy->isUnsigned() && SrcTy != Type::UByteTy) + visitInstruction(CI); // don't handle unsigned src yet! + + // We don't have the facilities for directly loading byte sized data from + // memory. Promote it to 16 bits. + if (SrcClass == cByte) { + unsigned TmpReg = makeAnotherReg(Type::ShortTy); + BuildMI(BB, SrcTy->isSigned() ? X86::MOVSXr16r8 : X86::MOVZXr16r8, + 1, TmpReg).addReg(SrcReg); + SrcTy = Type::ShortTy; // Pretend the short is our input now! + SrcClass = cShort; + SrcReg = TmpReg; + } + + // Spill the integer to memory and reload it from there... + int FrameIdx = + F->getFrameInfo()->CreateStackObject(SrcTy, TM.getTargetData()); + + if (SrcClass == cLong) { + if (SrcTy == Type::ULongTy) visitInstruction(CI); + addFrameReference(BuildMI(BB, X86::MOVrm32, 5), FrameIdx).addReg(SrcReg); + addFrameReference(BuildMI(BB, X86::MOVrm32, 5), + FrameIdx, 4).addReg(SrcReg+1); + } else { + static const unsigned Op1[] = { X86::MOVrm8, X86::MOVrm16, X86::MOVrm32 }; + addFrameReference(BuildMI(BB, Op1[SrcClass], 5), FrameIdx).addReg(SrcReg); + } + + static const unsigned Op2[] = + { 0, X86::FILDr16, X86::FILDr32, 0, X86::FILDr64 }; + addFrameReference(BuildMI(BB, Op2[SrcClass], 5, DestReg), FrameIdx); + return; + } + + // Handle casts from floating point to integer now... + if (SrcClass == cFP) { + // Change the floating point control register to use "round towards zero" + // mode when truncating to an integer value. + // + int CWFrameIdx = F->getFrameInfo()->CreateStackObject(2, 2); + addFrameReference(BuildMI(BB, X86::FNSTCWm16, 4), CWFrameIdx); + + // Load the old value of the high byte of the control word... + unsigned HighPartOfCW = makeAnotherReg(Type::UByteTy); + addFrameReference(BuildMI(BB, X86::MOVmr8, 4, HighPartOfCW), CWFrameIdx, 1); + + // Set the high part to be round to zero... + addFrameReference(BuildMI(BB, X86::MOVim8, 5), CWFrameIdx, 1).addZImm(12); + + // Reload the modified control word now... + addFrameReference(BuildMI(BB, X86::FLDCWm16, 4), CWFrameIdx); + + // Restore the memory image of control word to original value + addFrameReference(BuildMI(BB, X86::MOVrm8, 5), + CWFrameIdx, 1).addReg(HighPartOfCW); + + // We don't have the facilities for directly storing byte sized data to + // memory. Promote it to 16 bits. We also must promote unsigned values to + // larger classes because we only have signed FP stores. + unsigned StoreClass = DestClass; + const Type *StoreTy = DestTy; + if (StoreClass == cByte || DestTy->isUnsigned()) + switch (StoreClass) { + case cByte: StoreTy = Type::ShortTy; StoreClass = cShort; break; + case cShort: StoreTy = Type::IntTy; StoreClass = cInt; break; + case cInt: StoreTy = Type::LongTy; StoreClass = cLong; break; + case cLong: visitInstruction(CI); // unsigned long long -> more complex + default: assert(0 && "Unknown store class!"); + } + + // Spill the integer to memory and reload it from there... + int FrameIdx = + F->getFrameInfo()->CreateStackObject(StoreTy, TM.getTargetData()); + + static const unsigned Op1[] = + { 0, X86::FISTr16, X86::FISTr32, 0, X86::FISTPr64 }; + addFrameReference(BuildMI(BB, Op1[StoreClass], 5), FrameIdx).addReg(SrcReg); + + if (DestClass == cLong) { + addFrameReference(BuildMI(BB, X86::MOVmr32, 4, DestReg), FrameIdx); + addFrameReference(BuildMI(BB, X86::MOVmr32, 4, DestReg+1), FrameIdx, 4); + } else { + static const unsigned Op2[] = { X86::MOVmr8, X86::MOVmr16, X86::MOVmr32 }; + addFrameReference(BuildMI(BB, Op2[DestClass], 4, DestReg), FrameIdx); } + + // Reload the original control word now... + addFrameReference(BuildMI(BB, X86::FLDCWm16, 4), CWFrameIdx); + return; + } + // Anything we haven't handled already, we can't (yet) handle at all. - // - // FP to integral casts can be handled with FISTP to store onto the - // stack while converting to integer, followed by a MOV to load from - // the stack into the result register. Integral to FP casts can be - // handled with MOV to store onto the stack, followed by a FILD to - // load from the stack while converting to FP. For the moment, I - // can't quite get straight in my head how to borrow myself some - // stack space and write on it. Otherwise, this would be trivial. visitInstruction (CI); } @@ -1121,16 +1485,8 @@ return Count+1; } -/// visitGetElementPtrInst - I don't know, most programs don't have -/// getelementptr instructions, right? That means we can put off -/// implementing this, right? Right. This method emits machine -/// instructions to perform type-safe pointer arithmetic. I am -/// guessing this could be cleaned up somewhat to use fewer temporary -/// registers. -void -ISel::visitGetElementPtrInst (GetElementPtrInst &I) -{ - unsigned outputReg = getReg (I); +void ISel::visitGetElementPtrInst(GetElementPtrInst &I) { + unsigned outputReg = getReg(I); MachineBasicBlock::iterator MI = BB->end(); emitGEPOperation(BB, MI, I.getOperand(0), I.op_begin()+1, I.op_end(), outputReg); @@ -1142,14 +1498,14 @@ User::op_iterator IdxEnd, unsigned TargetReg) { const TargetData &TD = TM.getTargetData(); const Type *Ty = Src->getType(); - unsigned basePtrReg = getReg(Src, MBB, IP); + unsigned BaseReg = getReg(Src, MBB, IP); // GEPs have zero or more indices; we must perform a struct access // or array access for each one. for (GetElementPtrInst::op_iterator oi = IdxBegin, oe = IdxEnd; oi != oe; ++oi) { Value *idx = *oi; - unsigned nextBasePtrReg = makeAnotherReg(Type::UIntTy); + unsigned NextReg = BaseReg; if (const StructType *StTy = dyn_cast(Ty)) { // It's a struct access. idx is the index into the structure, // which names the field. This index must have ubyte type. @@ -1162,11 +1518,12 @@ // right byte offset from the StructLayout class's list of // structure member offsets. unsigned idxValue = CUI->getValue(); - unsigned memberOffset = - TD.getStructLayout(StTy)->MemberOffsets[idxValue]; - // Emit an ADD to add memberOffset to the basePtr. - BMI(MBB, IP, X86::ADDri32, 2, - nextBasePtrReg).addReg(basePtrReg).addZImm(memberOffset); + unsigned FieldOff = TD.getStructLayout(StTy)->MemberOffsets[idxValue]; + if (FieldOff) { + NextReg = makeAnotherReg(Type::UIntTy); + // Emit an ADD to add FieldOff to the basePtr. + BMI(MBB, IP, X86::ADDri32, 2,NextReg).addReg(BaseReg).addZImm(FieldOff); + } // The next type is the member of the structure selected by the // index. Ty = StTy->getElementTypes()[idxValue]; @@ -1178,7 +1535,7 @@ // time. assert(idx->getType() == Type::LongTy && "Bad GEP array index!"); - // We want to add basePtrReg to(idxReg * sizeof ElementType). First, we + // We want to add BaseReg to(idxReg * sizeof ElementType). First, we // must find the size of the pointed-to type (Not coincidentally, the next // type is the type of the elements in the array). Ty = SqTy->getElementType(); @@ -1186,25 +1543,21 @@ // If idxReg is a constant, we don't need to perform the multiply! if (ConstantSInt *CSI = dyn_cast(idx)) { - if (CSI->isNullValue()) { - BMI(MBB, IP, X86::MOVrr32, 1, nextBasePtrReg).addReg(basePtrReg); - } else { + if (!CSI->isNullValue()) { unsigned Offset = elementSize*CSI->getValue(); - - BMI(MBB, IP, X86::ADDri32, 2, - nextBasePtrReg).addReg(basePtrReg).addZImm(Offset); + NextReg = makeAnotherReg(Type::UIntTy); + BMI(MBB, IP, X86::ADDri32, 2,NextReg).addReg(BaseReg).addZImm(Offset); } } else if (elementSize == 1) { // If the element size is 1, we don't have to multiply, just add unsigned idxReg = getReg(idx, MBB, IP); - BMI(MBB, IP, X86::ADDrr32, 2, - nextBasePtrReg).addReg(basePtrReg).addReg(idxReg); + NextReg = makeAnotherReg(Type::UIntTy); + BMI(MBB, IP, X86::ADDrr32, 2, NextReg).addReg(BaseReg).addReg(idxReg); } else { unsigned idxReg = getReg(idx, MBB, IP); unsigned OffsetReg = makeAnotherReg(Type::UIntTy); if (unsigned Shift = ExactLog2(elementSize)) { // If the element size is exactly a power of 2, use a shift to get it. - BMI(MBB, IP, X86::SHLir32, 2, OffsetReg).addReg(idxReg).addZImm(Shift-1); } else { @@ -1214,22 +1567,22 @@ // Emit a MUL to multiply the register holding the index by // elementSize, putting the result in OffsetReg. - doMultiply(MBB, IP, OffsetReg, Type::LongTy, idxReg, elementSizeReg); + doMultiply(MBB, IP, OffsetReg, Type::IntTy, idxReg, elementSizeReg); } // Emit an ADD to add OffsetReg to the basePtr. - BMI(MBB, IP, X86::ADDrr32, 2, - nextBasePtrReg).addReg(basePtrReg).addReg(OffsetReg); + NextReg = makeAnotherReg(Type::UIntTy); + BMI(MBB, IP, X86::ADDrr32, 2,NextReg).addReg(BaseReg).addReg(OffsetReg); } } // Now that we are here, further indices refer to subtypes of this - // one, so we don't need to worry about basePtrReg itself, anymore. - basePtrReg = nextBasePtrReg; + // one, so we don't need to worry about BaseReg itself, anymore. + BaseReg = NextReg; } // After we have processed all the indices, the result is left in - // basePtrReg. Move it to the register where we were expected to + // BaseReg. Move it to the register where we were expected to // put the answer. A 32-bit move should do it, because we are in // ILP32 land. - BMI(MBB, IP, X86::MOVrr32, 1, TargetReg).addReg(basePtrReg); + BMI(MBB, IP, X86::MOVrr32, 1, TargetReg).addReg(BaseReg); } @@ -1276,7 +1629,7 @@ BuildMI(BB, X86::ANDri32, 2, AlignedSize).addReg(AddedSizeReg).addZImm(~15); // Subtract size from stack pointer, thereby allocating some space. - BuildMI(BB, X86::SUBri32, 2, X86::ESP).addReg(X86::ESP).addZImm(AlignedSize); + BuildMI(BB, X86::SUBrr32, 2, X86::ESP).addReg(X86::ESP).addReg(AlignedSize); // Put a pointer to the space into the result register, by copying // the stack pointer. @@ -1286,7 +1639,46 @@ // object. F->getFrameInfo()->CreateVariableSizedObject(); } - + +/// visitMallocInst - Malloc instructions are code generated into direct calls +/// to the library malloc. +/// +void ISel::visitMallocInst(MallocInst &I) { + unsigned AllocSize = TM.getTargetData().getTypeSize(I.getAllocatedType()); + unsigned Arg; + + if (ConstantUInt *C = dyn_cast(I.getOperand(0))) { + Arg = getReg(ConstantUInt::get(Type::UIntTy, C->getValue() * AllocSize)); + } else { + Arg = makeAnotherReg(Type::UIntTy); + unsigned Op0Reg = getReg(ConstantUInt::get(Type::UIntTy, AllocSize)); + unsigned Op1Reg = getReg(I.getOperand(0)); + MachineBasicBlock::iterator MBBI = BB->end(); + doMultiply(BB, MBBI, Arg, Type::UIntTy, Op0Reg, Op1Reg); + + + } + + std::vector Args; + Args.push_back(ValueRecord(Arg, Type::UIntTy)); + MachineInstr *TheCall = BuildMI(X86::CALLpcrel32, + 1).addExternalSymbol("malloc", true); + doCall(ValueRecord(getReg(I), I.getType()), TheCall, Args); +} + + +/// visitFreeInst - Free instructions are code gen'd to call the free libc +/// function. +/// +void ISel::visitFreeInst(FreeInst &I) { + std::vector Args; + Args.push_back(ValueRecord(getReg(I.getOperand(0)), + I.getOperand(0)->getType())); + MachineInstr *TheCall = BuildMI(X86::CALLpcrel32, + 1).addExternalSymbol("free", true); + doCall(ValueRecord(0, Type::VoidTy), TheCall, Args); +} + /// createSimpleX86InstructionSelector - This pass converts an LLVM function /// into a machine code representation is a very simple peep-hole fashion. The From lattner at cs.uiuc.edu Sun Jan 12 18:46:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:46:00 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86.h Message-ID: <200301130045.SAA22524@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86.h updated: 1.11 -> 1.12 --- Log message: Move passes out to Passes.h --- Diffs of the changes: Index: llvm/lib/Target/X86/X86.h diff -u llvm/lib/Target/X86/X86.h:1.11 llvm/lib/Target/X86/X86.h:1.12 --- llvm/lib/Target/X86/X86.h:1.11 Sat Dec 28 14:26:16 2002 +++ llvm/lib/Target/X86/X86.h Sun Jan 12 18:45:29 2003 @@ -3,8 +3,6 @@ // This file contains the entry points for global functions defined in the x86 // target library, as used by the LLVM JIT. // -// FIXME: This file will be dramatically changed in the future -// //===----------------------------------------------------------------------===// #ifndef TARGET_X86_H @@ -20,17 +18,16 @@ /// Pass *createSimpleX86InstructionSelector(TargetMachine &TM); -/// createSimpleRegisterAllocation - This function returns a pass that converts -/// the specified machine code function from SSA form to use explicit registers -/// by spilling every register. Wow, great policy huh? +/// createX86PeepholeOptimizer - Create a pass to perform X86 specific peephole +/// optimizations. /// -Pass *createSimpleRegisterAllocator(); -Pass *createLocalRegisterAllocator(); +Pass *createX86PeepholeOptimizerPass(); -/// createPrologEpilogCodeInserter - This function returns a pass that inserts -/// prolog and epilog code, and eliminates abstract frame references. +/// createX86FloatingPointStackifierPass - This function returns a pass which +/// converts floating point register references and pseudo instructions into +/// floating point stack references and physical instructions. /// -Pass *createPrologEpilogCodeInserter(); +Pass *createX86FloatingPointStackifierPass(); /// createX86CodePrinterPass - Print out the specified machine code function to /// the specified stream. This function should work regardless of whether or From lattner at cs.uiuc.edu Sun Jan 12 18:49:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:49:01 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.def Message-ID: <200301130048.SAA22541@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.def updated: 1.47 -> 1.48 --- Log message: * Function calls clobber fp registers * Use new M_TERMINATOR_FLAG flag * Add ::Void flag on several instructions so def-use info is correct! * Implement MANY FP instructions * Finalize pseudo FP instructions * Add set of Pseudo FP instruction description flags * Add support for MOVim instrs * Add support for 64 bit support instrs, like adc sbb, etc * Add conditional move --- Diffs of the changes: Index: llvm/lib/Target/X86/X86InstrInfo.def diff -u llvm/lib/Target/X86/X86InstrInfo.def:1.47 llvm/lib/Target/X86/X86InstrInfo.def:1.48 --- llvm/lib/Target/X86/X86InstrInfo.def:1.47 Sat Dec 28 14:29:14 2002 +++ llvm/lib/Target/X86/X86InstrInfo.def Sun Jan 12 18:48:46 2003 @@ -35,7 +35,14 @@ IMPREGSLIST(O_EBP, X86::EBP, 0) IMPREGSLIST(T_AXDX , X86::AX , X86::DX , 0) IMPREGSLIST(T_EAXEDX, X86::EAX, X86::EDX, 0) -IMPREGSLIST(C_CLOBBER, X86::EAX, X86::ECX, X86::EDX, 0) // Callee clobber regs +IMPREGSLIST(C_CLOBBER, X86::EAX, X86::ECX, X86::EDX, + X86::FP0, X86::FP1, X86::FP2, X86::FP3, + X86::FP4, X86::FP5, X86::FP6, 0) // Callee clobber regs + +// Floating point registers... +IMPREGSLIST(O_ST0, X86::ST0, 0) +//IMPREGSLIST(O_TOP, X86::TOP, 0) + #undef IMPREGSLIST @@ -73,10 +80,10 @@ I(ADJCALLSTACKUP , "adjcallstackup" , 0, 0, X86II::Pseudo, NoIR, NoIR) // Flow control instructions -I(RET , "ret", 0xC3, M_RET_FLAG, X86II::RawFrm | X86II::Void, NoIR, NoIR) // ret -I(JMP , "jmp", 0xE9, M_BRANCH_FLAG, X86II::RawFrm | X86II::Void, NoIR, NoIR) // jmp foo -I(JNE , "jne", 0x85, M_BRANCH_FLAG, X86II::RawFrm | X86II::TB | X86II::Void, NoIR, NoIR) // jne foo -I(JE , "je", 0x84, M_BRANCH_FLAG, X86II::RawFrm | X86II::TB | X86II::Void, NoIR, NoIR) // je foo +I(RET , "ret", 0xC3, M_RET_FLAG | M_TERMINATOR_FLAG, X86II::RawFrm | X86II::Void, NoIR, NoIR) // ret +I(JMP , "jmp", 0xE9, M_BRANCH_FLAG | M_TERMINATOR_FLAG, X86II::RawFrm | X86II::Void, NoIR, NoIR) // jmp foo +I(JNE , "jne", 0x85, M_BRANCH_FLAG | M_TERMINATOR_FLAG, X86II::RawFrm | X86II::TB | X86II::Void, NoIR, NoIR) // jne foo +I(JE , "je", 0x84, M_BRANCH_FLAG | M_TERMINATOR_FLAG, X86II::RawFrm | X86II::TB | X86II::Void, NoIR, NoIR) // je foo I(CALLpcrel32 , "call", 0xE8, M_CALL_FLAG, X86II::Void | X86II::RawFrm, NoIR, C_CLOBBER) // call pc+42 I(CALLr32 , "call", 0xFF, M_CALL_FLAG, X86II::Void | X86II::MRMS2r | X86II::Arg32, NoIR, C_CLOBBER) // call [r32] @@ -100,6 +107,10 @@ I(MOVir8 , "mov", 0xB0, 0, X86II::AddRegFrm | X86II::Arg8, NoIR, NoIR) // R8 = imm8 I(MOVir16 , "mov", 0xB8, 0, X86II::AddRegFrm | X86II::Arg16 | X86II::OpSize, NoIR, NoIR) // R16 = imm16 I(MOVir32 , "mov", 0xB8, 0, X86II::AddRegFrm | X86II::Arg32, NoIR, NoIR) // R32 = imm32 +I(MOVim8 , "mov", 0xC6, 0, X86II::MRMS0m | X86II::Arg8, NoIR, NoIR) // [mem] = imm8 +I(MOVim16 , "mov", 0xC7, 0, X86II::MRMS0m | X86II::Arg16 | X86II::OpSize, NoIR, NoIR) // [mem] = imm16 +I(MOVim32 , "mov", 0xC7, 0, X86II::MRMS0m | X86II::Arg32, NoIR, NoIR) // [mem] = imm32 + I(MOVmr8 , "mov", 0x8A, 0, X86II::MRMSrcMem | X86II::Arg8, NoIR, NoIR) // R8 = [mem] I(MOVmr16 , "mov", 0x8B, 0, X86II::MRMSrcMem | X86II::OpSize | X86II::Arg16, NoIR, NoIR) // R16 = [mem] @@ -111,35 +122,35 @@ I(MOVrm32 , "mov", 0x89, 0, X86II::MRMDestMem | X86II::Void | X86II::Arg32, NoIR, NoIR) // [mem] = R32 - //I(PUSHr32 , "pushl", 0x50, 0, X86II::AddRegFrm | X86II::Void, NoIR, NoIR) - //I(POPr32 , "popl", 0x58, 0, X86II::AddRegFrm, NoIR, NoIR) - // Arithmetic instructions I(ADDrr8 , "add", 0x00, M_2_ADDR_FLAG, X86II::MRMDestReg, NoIR, NoIR) // R8 += R8 I(ADDrr16 , "add", 0x01, M_2_ADDR_FLAG, X86II::MRMDestReg | X86II::OpSize, NoIR, NoIR) // R16 += R16 I(ADDrr32 , "add", 0x01, M_2_ADDR_FLAG, X86II::MRMDestReg, NoIR, NoIR) // R32 += R32 I(ADDri32 , "add", 0x81, M_2_ADDR_FLAG, X86II::MRMS0r | X86II::Arg32, NoIR, NoIR) // R32 += imm32 +I(ADCrr32 , "adc", 0x11, M_2_ADDR_FLAG, X86II::MRMDestReg | X86II::Arg32, NoIR, NoIR) // R32 += R32 + Carry + I(SUBrr8 , "sub", 0x28, M_2_ADDR_FLAG, X86II::MRMDestReg, NoIR, NoIR) // R8 -= R8 I(SUBrr16 , "sub", 0x29, M_2_ADDR_FLAG, X86II::MRMDestReg | X86II::OpSize, NoIR, NoIR) // R16 -= R16 I(SUBrr32 , "sub", 0x29, M_2_ADDR_FLAG, X86II::MRMDestReg, NoIR, NoIR) // R32 -= R32 I(SUBri32 , "sub", 0x81, M_2_ADDR_FLAG, X86II::MRMS5r | X86II::Arg32, NoIR, NoIR) // R32 -= imm32 -I(MULrr8 , "mul", 0xF6, 0, X86II::MRMS4r | X86II::Void, O_AL, O_AX) // AX = AL*R8 -I(MULrr16 , "mul", 0xF7, 0, X86II::MRMS4r | X86II::Void | // DX:AX= AX*R16 +I(SBBrr32 , "sbb", 0x19, M_2_ADDR_FLAG, X86II::MRMDestReg | X86II::Arg32, NoIR, NoIR) // R32 -= R32 + Carry +I(MULr8 , "mul", 0xF6, 0, X86II::MRMS4r | X86II::Void, O_AL, O_AX) // AX = AL*R8 +I(MULr16 , "mul", 0xF7, 0, X86II::MRMS4r | X86II::Void | // DX:AX= AX*R16 X86II::OpSize, O_AX, T_AXDX) -I(MULrr32 , "mul", 0xF7, 0, X86II::MRMS4r | X86II::Void, O_EAX, T_EAXEDX) // ED:EA= EA*R32 +I(MULr32 , "mul", 0xF7, 0, X86II::MRMS4r | X86II::Void, O_EAX, T_EAXEDX) // ED:EA= EA*R32 // unsigned division/remainder -I(DIVrr8 , "div", 0xF6, 0, X86II::MRMS6r | X86II::Void, O_AX, O_AX) // AX/r8= AL&AH -I(DIVrr16 , "div", 0xF7, 0, X86II::MRMS6r | X86II::Void | // ED:EA/r16=AX&DX +I(DIVr8 , "div", 0xF6, 0, X86II::MRMS6r | X86II::Void, O_AX, O_AX) // AX/r8= AL&AH +I(DIVr16 , "div", 0xF7, 0, X86II::MRMS6r | X86II::Void | // ED:EA/r16=AX&DX X86II::OpSize, T_AXDX, T_AXDX) -I(DIVrr32 , "div", 0xF7, 0, X86II::MRMS6r | X86II::Void, T_EAXEDX, +I(DIVr32 , "div", 0xF7, 0, X86II::MRMS6r | X86II::Void, T_EAXEDX, T_EAXEDX) // ED:EA/r32=EA&ED // signed division/remainder -I(IDIVrr8 , "idiv", 0xF6, 0, X86II::MRMS7r | X86II::Void, O_AX, O_AX) // AX/r8= AL&AH -I(IDIVrr16 , "idiv", 0xF7, 0, X86II::MRMS7r | X86II::Void | // DA/r16=AX&DX +I(IDIVr8 , "idiv", 0xF6, 0, X86II::MRMS7r | X86II::Void, O_AX, O_AX) // AX/r8= AL&AH +I(IDIVr16 , "idiv", 0xF7, 0, X86II::MRMS7r | X86II::Void | // DA/r16=AX&DX X86II::OpSize, T_AXDX, T_AXDX) -I(IDIVrr32 , "idiv", 0xF7, 0, X86II::MRMS7r | X86II::Void, T_EAXEDX, +I(IDIVr32 , "idiv", 0xF7, 0, X86II::MRMS7r | X86II::Void, T_EAXEDX, T_EAXEDX) // DA/r32=EAX&DX // Logical operators @@ -155,48 +166,59 @@ I(XORrr32 , "xor", 0x31, M_2_ADDR_FLAG, X86II::MRMDestReg, NoIR, NoIR) // R32 ^= R32 // Shift instructions -I(SHLrr8 , "shlb", 0xD2, M_2_ADDR_FLAG, X86II::MRMS4r, O_CL, NoIR) // R8 <<= cl -I(SHLrr16 , "shlw", 0xD3, M_2_ADDR_FLAG, X86II::MRMS4r | X86II::OpSize, O_CL, NoIR) // R16 <<= cl -I(SHLrr32 , "shll", 0xD3, M_2_ADDR_FLAG, X86II::MRMS4r, O_CL, NoIR) // R32 <<= cl -I(SHLir8 , "shlb", 0xC0, M_2_ADDR_FLAG, X86II::MRMS4r | X86II::Arg8, NoIR, NoIR) // R8 <<= imm8 -I(SHLir16 , "shlw", 0xC1, M_2_ADDR_FLAG, X86II::MRMS4r | X86II::Arg8 | X86II::OpSize, NoIR, NoIR) // R16 <<= imm8 -I(SHLir32 , "shll", 0xC1, M_2_ADDR_FLAG, X86II::MRMS4r | X86II::Arg8, NoIR, NoIR) // R32 <<= imm8 -I(SHRrr8 , "shrb", 0xD2, M_2_ADDR_FLAG, X86II::MRMS5r, O_CL, NoIR) // R8 >>>= cl -I(SHRrr16 , "shrw", 0xD3, M_2_ADDR_FLAG, X86II::MRMS5r | X86II::OpSize, O_CL, NoIR) // R16 >>>= cl -I(SHRrr32 , "shrl", 0xD3, M_2_ADDR_FLAG, X86II::MRMS5r, O_CL, NoIR) // R32 >>>= cl -I(SHRir8 , "shrb", 0xC0, M_2_ADDR_FLAG, X86II::MRMS5r | X86II::Arg8, NoIR, NoIR) // R8 >>>= imm8 -I(SHRir16 , "shrw", 0xC1, M_2_ADDR_FLAG, X86II::MRMS5r | X86II::Arg8 | X86II::OpSize, NoIR, NoIR) // R16 >>>= imm8 -I(SHRir32 , "shrl", 0xC1, M_2_ADDR_FLAG, X86II::MRMS5r | X86II::Arg8, NoIR, NoIR) // R32 >>>= imm8 -I(SARrr8 , "sarb", 0xD2, M_2_ADDR_FLAG, X86II::MRMS7r, O_CL, NoIR) // R8 >>= cl -I(SARrr16 , "sarw", 0xD3, M_2_ADDR_FLAG, X86II::MRMS7r | X86II::OpSize, O_CL, NoIR) // R16 >>= cl -I(SARrr32 , "sarl", 0xD3, M_2_ADDR_FLAG, X86II::MRMS7r, O_CL, NoIR) // R32 >>= cl -I(SARir8 , "sarb", 0xC0, M_2_ADDR_FLAG, X86II::MRMS7r | X86II::Arg8, NoIR, NoIR) // R8 >>= imm8 -I(SARir16 , "sarw", 0xC1, M_2_ADDR_FLAG, X86II::MRMS7r | X86II::Arg8 | X86II::OpSize, NoIR, NoIR) // R16 >>= imm8 -I(SARir32 , "sarl", 0xC1, M_2_ADDR_FLAG, X86II::MRMS7r | X86II::Arg8, NoIR, NoIR) // R32 >>= imm8 +I(SHLrr8 , "shl", 0xD2, M_2_ADDR_FLAG, X86II::MRMS4r, O_CL, NoIR) // R8 <<= cl +I(SHLrr16 , "shl", 0xD3, M_2_ADDR_FLAG, X86II::MRMS4r | X86II::OpSize, O_CL, NoIR) // R16 <<= cl +I(SHLrr32 , "shl", 0xD3, M_2_ADDR_FLAG, X86II::MRMS4r, O_CL, NoIR) // R32 <<= cl +I(SHLir8 , "shl", 0xC0, M_2_ADDR_FLAG, X86II::MRMS4r | X86II::Arg8, NoIR, NoIR) // R8 <<= imm8 +I(SHLir16 , "shl", 0xC1, M_2_ADDR_FLAG, X86II::MRMS4r | X86II::Arg8 | X86II::OpSize, NoIR, NoIR) // R16 <<= imm8 +I(SHLir32 , "shl", 0xC1, M_2_ADDR_FLAG, X86II::MRMS4r | X86II::Arg8, NoIR, NoIR) // R32 <<= imm8 +I(SHRrr8 , "shr", 0xD2, M_2_ADDR_FLAG, X86II::MRMS5r, O_CL, NoIR) // R8 >>>= cl +I(SHRrr16 , "shr", 0xD3, M_2_ADDR_FLAG, X86II::MRMS5r | X86II::OpSize, O_CL, NoIR) // R16 >>>= cl +I(SHRrr32 , "shr", 0xD3, M_2_ADDR_FLAG, X86II::MRMS5r, O_CL, NoIR) // R32 >>>= cl +I(SHRir8 , "shr", 0xC0, M_2_ADDR_FLAG, X86II::MRMS5r | X86II::Arg8, NoIR, NoIR) // R8 >>>= imm8 +I(SHRir16 , "shr", 0xC1, M_2_ADDR_FLAG, X86II::MRMS5r | X86II::Arg8 | X86II::OpSize, NoIR, NoIR) // R16 >>>= imm8 +I(SHRir32 , "shr", 0xC1, M_2_ADDR_FLAG, X86II::MRMS5r | X86II::Arg8, NoIR, NoIR) // R32 >>>= imm8 +I(SARrr8 , "sar", 0xD2, M_2_ADDR_FLAG, X86II::MRMS7r, O_CL, NoIR) // R8 >>= cl +I(SARrr16 , "sar", 0xD3, M_2_ADDR_FLAG, X86II::MRMS7r | X86II::OpSize, O_CL, NoIR) // R16 >>= cl +I(SARrr32 , "sar", 0xD3, M_2_ADDR_FLAG, X86II::MRMS7r, O_CL, NoIR) // R32 >>= cl +I(SARir8 , "sar", 0xC0, M_2_ADDR_FLAG, X86II::MRMS7r | X86II::Arg8, NoIR, NoIR) // R8 >>= imm8 +I(SARir16 , "sar", 0xC1, M_2_ADDR_FLAG, X86II::MRMS7r | X86II::Arg8 | X86II::OpSize, NoIR, NoIR) // R16 >>= imm8 +I(SARir32 , "sar", 0xC1, M_2_ADDR_FLAG, X86II::MRMS7r | X86II::Arg8, NoIR, NoIR) // R32 >>= imm8 + +I(SHLDir32 , "shld", 0xA4, M_2_ADDR_FLAG, X86II::MRMDestReg | X86II::TB | X86II::Arg8, NoIR, NoIR) // R32 >>= R32,R32 imm8 +I(SHLDrr32 , "shld", 0xA5, M_2_ADDR_FLAG, X86II::MRMDestReg | X86II::TB, O_CL, NoIR) // R32 >>= R32,R32 cl +I(SHRDir32 , "shrd", 0xAC, M_2_ADDR_FLAG, X86II::MRMDestReg | X86II::TB | X86II::Arg8, NoIR, NoIR) // R32 >>= R32,R32 imm8 +I(SHRDrr32 , "shrd", 0xAD, M_2_ADDR_FLAG, X86II::MRMDestReg | X86II::TB, O_CL, NoIR) // R32 >>= R32,R32 cl + // Condition code ops, incl. set if equal/not equal/... -I(SAHF , "sahf", 0x9E, 0, X86II::RawFrm, O_AH, NoIR) // flags = AH -I(SETBr , "setb", 0x92, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = < unsign -I(SETAEr , "setae", 0x93, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = >=unsign +I(SAHF , "sahf", 0x9E, 0, X86II::RawFrm, O_AH, NoIR) // flags = AH +I(SETBr , "setb", 0x92, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = < unsign +I(SETAEr , "setae", 0x93, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = >= unsign I(SETEr , "sete", 0x94, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = == I(SETNEr , "setne", 0x95, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = != -I(SETBEr , "setbe", 0x96, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = <=unsign -I(SETAr , "seta", 0x97, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = > unsign -I(SETLr , "setl", 0x9C, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = < signed -I(SETGEr , "setge", 0x9D, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = >=signed -I(SETLEr , "setle", 0x9E, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = <=signed -I(SETGr , "setg", 0x9F, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = > signed +I(SETBEr , "setbe", 0x96, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = <= unsign +I(SETAr , "seta", 0x97, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = > unsign +I(SETLr , "setl", 0x9C, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = < signed +I(SETGEr , "setge", 0x9D, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = >= signed +I(SETLEr , "setle", 0x9E, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = <= signed +I(SETGr , "setg", 0x9F, 0, X86II::TB | X86II::MRMS0r, NoIR, NoIR) // R8 = > signed + +// Conditional moves. These are modelled as X = cmovXX Y, Z. Eventually +// register allocated to cmovXX XY, Z +I(CMOVErr16 , "cmove", 0x44, M_2_ADDR_FLAG, X86II::TB | X86II::OpSize | X86II::MRMSrcReg, NoIR, NoIR) // if ==, R16 = R16 + // Integer comparisons -I(CMPrr8 , "cmpb", 0x38, 0, X86II::MRMDestReg, NoIR, NoIR) // compare R8,R8 -I(CMPrr16 , "cmpw", 0x39, 0, X86II::MRMDestReg | X86II::OpSize, NoIR, NoIR) // compare R16,R16 -I(CMPrr32 , "cmpl", 0x39, 0, X86II::MRMDestReg, NoIR, NoIR) // compare R32,R32 -I(CMPri8 , "cmp", 0x80, 0, X86II::MRMS7r | X86II::Arg8, NoIR, NoIR) // compare R8, imm8 +I(CMPrr8 , "cmpb", 0x38, 0, X86II::Void | X86II::MRMDestReg , NoIR, NoIR) // compare R8,R8 +I(CMPrr16 , "cmpw", 0x39, 0, X86II::Void | X86II::MRMDestReg | X86II::OpSize, NoIR, NoIR) // compare R16,R16 +I(CMPrr32 , "cmpl", 0x39, 0, X86II::Void | X86II::MRMDestReg , NoIR, NoIR) // compare R32,R32 +I(CMPri8 , "cmp", 0x80, 0, X86II::Void | X86II::MRMS7r | X86II::Arg8 , NoIR, NoIR) // compare R8, imm8 // Sign extenders (first 3 are good for DIV/IDIV; the others are more general) -I(CBW , "cbw", 0x98, 0, X86II::RawFrm | X86II::OpSize, O_AL, O_AH) // AX = signext(AL) -I(CWD , "cwd", 0x99, 0, X86II::RawFrm, O_AX, O_DX) // DX:AX = signext(AX) -I(CDQ , "cdq", 0x99, 0, X86II::RawFrm, O_EAX, O_EDX) // EDX:EAX = signext(EAX) +I(CBW , "cbw", 0x98, 0, X86II::Void | X86II::RawFrm | X86II::OpSize, O_AL, O_AH) // AX = signext(AL) +I(CWD , "cwd", 0x99, 0, X86II::Void | X86II::RawFrm, O_AX, O_DX) // DX:AX = signext(AX) +I(CDQ , "cdq", 0x99, 0, X86II::Void | X86II::RawFrm, O_EAX, O_EDX) // EDX:EAX = signext(EAX) I(MOVSXr16r8 , "movsx", 0xBE, 0, X86II::MRMSrcReg | X86II::TB | // R16 = signext(R8) X86II::OpSize, NoIR, NoIR) I(MOVSXr32r8 , "movsx", 0xBE, 0, X86II::MRMSrcReg | X86II::TB, NoIR, NoIR) // R32 = signext(R8) @@ -212,36 +234,83 @@ //===----------------------------------------------------------------------===// // FIXME: These need to indicate mod/ref sets for FP regs... & FP 'TOP' -// FIXME: Remove Pseudo encodings from some insts -// Floating point loads & stores... PREFIX ARGTYPE ENCODING REF MOD -I(FLDr32 , "flds" , 0xD9, 0, X86II::ArgF32 | X86II::Pseudo, NoIR, NoIR) // load float MRMS0m -I(FLDr64 , "fldl" , 0xDD, 0, X86II::ArgF64 | X86II::Pseudo, NoIR, NoIR) // load double MRMS0m -I(FLDr80 , "fldx" , 0xDB, 0, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // store extended MRMS5m -I(FSTr32 , "fsts" , 0xD9, 0, X86II::ArgF32 | X86II::Pseudo, NoIR, NoIR) // store float MRMS2m -I(FSTr64 , "fstl" , 0xDD, 0, X86II::ArgF64 | X86II::Pseudo, NoIR, NoIR) // store double MRMS2m -I(FSTPr80 , "fstpx", 0xDB, 0, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // store extended MRMS7m +// Floating point pseudo instructions... +I(FpMOV , "FMOV" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo | X86II::SpecialFP, NoIR, NoIR) // f1 = fmov f2 +I(FpADD , "FADD" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo | X86II::TwoArgFP , NoIR, NoIR) // f1 = fadd f2, f3 +I(FpSUB , "FSUB" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo | X86II::TwoArgFP , NoIR, NoIR) // f1 = fsub f2, f3 +I(FpMUL , "FMUL" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo | X86II::TwoArgFP , NoIR, NoIR) // f1 = fmul f2, f3 +I(FpDIV , "FDIV" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo | X86II::TwoArgFP , NoIR, NoIR) // f1 = fdiv f2, f3 +I(FpUCOM , "FUCOM", 0, M_PSEUDO_FLAG, X86II::Void | X86II::ArgF80 | X86II::Pseudo | X86II::TwoArgFP , NoIR, NoIR) // FPSW = fucom f1, f2 + +I(FpGETRESULT , "FGETRESULT",0, M_PSEUDO_FLAG, X86II::Pseudo | X86II::SpecialFP, NoIR, NoIR) // FPR = ST(0) +I(FpSETRESULT , "FSETRESULT",0, M_PSEUDO_FLAG | M_TERMINATOR_FLAG, X86II::Void | X86II::Pseudo | X86II::SpecialFP, NoIR, NoIR) // ST(0) = FPR + +// Floating point loads & stores... PREFIX ARGTYPE ENCODING FP INST TYPE REF MOD +I(FLDr32 , "fld32", 0xD9, 0, X86II::ArgF32 | X86II::MRMS0m | X86II::ZeroArgFP, NoIR, NoIR) // load float +I(FLDr64 , "fld64", 0xDD, 0, X86II::ArgF64 | X86II::MRMS0m | X86II::ZeroArgFP, NoIR, NoIR) // load double +I(FLDr80 , "fld80", 0xDB, 0, X86II::ArgF80 | X86II::MRMS5m | X86II::ZeroArgFP, NoIR, NoIR) // load extended +I(FLDrr , "fld" , 0xC0, 0, X86II::D9 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // push(ST(i)) +I(FILDr16 , "fild16", 0xDF, 0, X86II::Arg16 | X86II::MRMS0m | X86II::ZeroArgFP, NoIR, NoIR) // load signed short +I(FILDr32 , "fild32", 0xDB, 0, X86II::Arg32 | X86II::MRMS0m | X86II::ZeroArgFP, NoIR, NoIR) // load signed int +I(FILDr64 , "fild64", 0xDF, 0, X86II::Arg64 | X86II::MRMS5m | X86II::ZeroArgFP, NoIR, NoIR) // load signed long + + +I(FSTr32 , "fst32", 0xD9, 0, X86II::Void | X86II::ArgF32 | X86II::MRMS2m | X86II::OneArgFP , NoIR, NoIR) // store float +I(FSTr64 , "fst64", 0xDD, 0, X86II::Void | X86II::ArgF64 | X86II::MRMS2m | X86II::OneArgFP , NoIR, NoIR) // store double +I(FSTPr32 , "fst32p", 0xD9, 0, X86II::Void | X86II::ArgF32 | X86II::MRMS3m , NoIR, NoIR) // store float, pop +I(FSTPr64 , "fst64p", 0xDD, 0, X86II::Void | X86II::ArgF64 | X86II::MRMS3m , NoIR, NoIR) // store double, pop +I(FSTPr80 , "fst80p", 0xDB, 0, X86II::Void | X86II::ArgF80 | X86II::MRMS7m | X86II::OneArgFP , NoIR, NoIR) // store extended, pop +I(FSTrr , "fst" , 0xD0, 0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(0) +I(FSTPrr , "fstp" , 0xD8, 0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(0), pop + +I(FISTr16 , "fist16", 0xDF, 0, X86II::Void | X86II::Arg16 | X86II::MRMS2m | X86II::OneArgFP , NoIR, NoIR) // store signed short +I(FISTr32 , "fist32", 0xDB, 0, X86II::Void | X86II::Arg32 | X86II::MRMS2m | X86II::OneArgFP , NoIR, NoIR) // store signed int +I(FISTPr16 , "fist16p", 0xDF, 0, X86II::Void | X86II::Arg16 | X86II::MRMS3m , NoIR, NoIR) // store short, pop +I(FISTPr32 , "fist32p", 0xDB, 0, X86II::Void | X86II::Arg32 | X86II::MRMS3m , NoIR, NoIR) // store int, pop +I(FISTPr64 , "fist64p", 0xDF, 0, X86II::Void | X86II::Arg64 | X86II::MRMS7m | X86II::OneArgFP , NoIR, NoIR) // store long, pop -// Floating point constant loads... -I(FLD0 , "fld0" , 0xEE, 0, X86II::D9 | X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // load +0.0 RawFrm -I(FLD1 , "fld1" , 0xE8, 0, X86II::D9 | X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // load +1.0 RawFrm +I(FXCH , "fxch" , 0xC8, 0, X86II::D9 | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm , O_ST0, O_ST0) // fxch ST(i), ST(0) -// Floating point pseudo instructions... -I(FpMOV , "FMOV" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // f1 = fmov f2 -I(FpADD , "FADD" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // f1 = fadd f2, f3 -I(FpSUB , "FSUB" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // f1 = fsub f2, f3 -I(FpMUL , "FMUL" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // f1 = fmul f2, f3 -I(FpDIV , "FDIV" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // f1 = fdiv f2, f3 -I(FpREM , "FREM" , 0, M_PSEUDO_FLAG, X86II::ArgF80 | X86II::Pseudo, NoIR, NoIR) // f1 = frem f2, f3 +// Floating point constant loads... +I(FLD0 , "fld0" , 0xEE, 0, X86II::D9 | X86II::ArgF80 | X86II::RawFrm | X86II::ZeroArgFP, NoIR, NoIR) // load +0.0 +I(FLD1 , "fld1" , 0xE8, 0, X86II::D9 | X86II::ArgF80 | X86II::RawFrm | X86II::ZeroArgFP, NoIR, NoIR) // load +1.0 +// Binary arithmetic operations... +I(FADDST0r , "fadd_0", 0xC0, 0, X86II::D8 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(0) = ST(0) + ST(i) +I(FADDrST0 , "fadd_i", 0xC0, 0, X86II::DC | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) + ST(0) +I(FADDPrST0 , "faddp_i", 0xC0, 0, X86II::DE | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) + ST(0), pop + +I(FSUBRST0r , "fsubr_0" , 0xE8, 0, X86II::D8 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(0) = ST(i) - ST(0) +I(FSUBrST0 , "fsub_i" , 0xE8, 0, X86II::DC | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) - ST(0) +I(FSUBPrST0 , "fsubp_i" , 0xE8, 0, X86II::DE | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) - ST(0), pop + +I(FSUBST0r , "fsub_0" , 0xE0, 0, X86II::D8 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(0) = ST(0) - ST(i) +I(FSUBRrST0 , "fsubr_i" , 0xE0, 0, X86II::DC | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(0) - ST(i) +I(FSUBRPrST0 , "fsubrp_i", 0xE0, 0, X86II::DE | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(0) - ST(i), pop + +I(FMULST0r , "fmul_0", 0xC8, 0, X86II::D8 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(0) = ST(0) * ST(i) +I(FMULrST0 , "fmul_i", 0xC8, 0, X86II::DC | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) * ST(0) +I(FMULPrST0 , "fmulp_i", 0xC8, 0, X86II::DE | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) * ST(0), pop + +I(FDIVRST0r , "fdivr_0" , 0xF8, 0, X86II::D8 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(0) = ST(i) / ST(0) +I(FDIVrST0 , "fdiv_i" , 0xF8, 0, X86II::DC | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) / ST(0) +I(FDIVPrST0 , "fdivp_i" , 0xF8, 0, X86II::DE | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(i) / ST(0), pop + +I(FDIVST0r , "fdiv_0" , 0xF0, 0, X86II::D8 | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(0) = ST(0) / ST(i) +I(FDIVRrST0 , "fdivr_i" , 0xF0, 0, X86II::DC | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(0) / ST(i) +I(FDIVRPrST0 , "fdivrp_i", 0xF0, 0, X86II::DE | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // ST(i) = ST(0) / ST(i), pop // Floating point compares -//I(FUCOMPP , "fucompp", 0xDA, 0, X86II::Void, NoIR, NoIR) // compare+pop2x +I(FUCOMr , "fucom" , 0xE0, 0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // FPSW = compare ST(0) with ST(i) +I(FUCOMPr , "fucomp" , 0xE8, 0, X86II::DD | X86II::Void | X86II::ArgF80 | X86II::AddRegFrm , NoIR, NoIR) // compare, pop +I(FUCOMPPr , "fucompp" , 0xE9, 0, X86II::DA | X86II::Void | X86II::RawFrm , NoIR, NoIR) // compare ST(0) with ST(1), pop, pop // Floating point flag ops -//I(FNSTSWr8 , "fnstsw", 0xDF, 0, X86II::Void, NoIR, O_AX) // AX = fp flags - +I(FNSTSWr8 , "fnstsw" , 0xE0, 0, X86II::DF | X86II::Void | X86II::RawFrm , NoIR, O_AX) // AX = fp flags +I(FNSTCWm16 , "fnstcw" , 0xD9, 0, X86II::Void | X86II::Arg16 | X86II::MRMS7m , NoIR, NoIR) // [mem16] = X87 Control Word +I(FLDCWm16 , "fldcw" , 0xD9, 0, X86II::Void | X86II::Arg16 | X86II::MRMS5m , NoIR, NoIR) // X87 Control Word = [mem16] // At this point, I is dead, so undefine the macro From lattner at cs.uiuc.edu Sun Jan 12 18:50:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:50:01 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrBuilder.h Message-ID: <200301130049.SAA22550@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrBuilder.h updated: 1.4 -> 1.5 --- Log message: Add support for frame and constant pool references --- Diffs of the changes: Index: llvm/lib/Target/X86/X86InstrBuilder.h diff -u llvm/lib/Target/X86/X86InstrBuilder.h:1.4 llvm/lib/Target/X86/X86InstrBuilder.h:1.5 --- llvm/lib/Target/X86/X86InstrBuilder.h:1.4 Sat Dec 28 14:26:58 2002 +++ llvm/lib/Target/X86/X86InstrBuilder.h Sun Jan 12 18:45:53 2003 @@ -42,12 +42,24 @@ /// addFrameReference - This function is used to add a reference to the base of /// an abstract object on the stack frame of the current function. This -/// reference has base register and a FrameIndex offset until it is -/// resolved. +/// reference has base register as the FrameIndex offset until it is resolved. +/// This allows a constant offset to be specified as well... /// inline const MachineInstrBuilder & -addFrameReference(const MachineInstrBuilder &MIB, int FI) { - return MIB.addReg(0).addZImm(1).addMReg(0).addFrameIndex(FI); +addFrameReference(const MachineInstrBuilder &MIB, int FI, int Offset = 0) { + return MIB.addFrameIndex(FI).addZImm(1).addMReg(0).addSImm(Offset); +} + +/// addConstantPoolReference - This function is used to add a reference to the +/// base of a constant value spilled to the per-function constant pool. The +/// reference has base register ConstantPoolIndex offset which is retained until +/// either machine code emission or assembly output. This allows an optional +/// offset to be added as well. +/// +inline const MachineInstrBuilder & +addConstantPoolReference(const MachineInstrBuilder &MIB, unsigned CPI, + int Offset = 0) { + return MIB.addConstantPoolIndex(CPI).addZImm(1).addMReg(0).addSImm(Offset); } #endif From lattner at cs.uiuc.edu Sun Jan 12 18:50:05 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:50:05 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.h Message-ID: <200301130049.SAA22557@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.h updated: 1.19 -> 1.20 --- Log message: * Some instructions take 64 bit integers, add an Arg type for it * Add flags for different types of FP pseudo instrs --- Diffs of the changes: Index: llvm/lib/Target/X86/X86InstrInfo.h diff -u llvm/lib/Target/X86/X86InstrInfo.h:1.19 llvm/lib/Target/X86/X86InstrInfo.h:1.20 --- llvm/lib/Target/X86/X86InstrInfo.h:1.19 Sat Dec 28 14:29:41 2002 +++ llvm/lib/Target/X86/X86InstrInfo.h Sun Jan 12 18:49:24 2003 @@ -85,6 +85,7 @@ // is no prefix byte for obtaining a multibyte opcode. // Op0Mask = 0xF << 7, + Op0Shift = 7, // TB - TwoByte - Set if this instruction has a two byte opcode, which // starts with a 0x0F byte before the real opcode. @@ -95,17 +96,44 @@ D8 = 2 << 7, D9 = 3 << 7, DA = 4 << 7, DB = 5 << 7, DC = 6 << 7, DD = 7 << 7, DE = 8 << 7, DF = 9 << 7, + //===------------------------------------------------------------------===// // This three-bit field describes the size of a memory operand. Zero is // unused so that we can tell if we forgot to set a value. Arg8 = 1 << 11, Arg16 = 2 << 11, Arg32 = 3 << 11, - ArgF32 = 4 << 11, - ArgF64 = 5 << 11, - ArgF80 = 6 << 11, + Arg64 = 4 << 11, // 64 bit int argument for FILD64 + ArgF32 = 5 << 11, + ArgF64 = 6 << 11, + ArgF80 = 7 << 11, ArgMask = 7 << 11, - // Bits 14 -> 31 are unused + //===------------------------------------------------------------------===// + // FP Instruction Classification... Zero is non-fp instruction. + + // ZeroArgFP - 0 arg FP instruction which implicitly pushes ST(0), f.e. fld0 + ZeroArgFP = 1 << 14, + + // OneArgFP - 1 arg FP instructions which implicitly read ST(0), such as fst + OneArgFP = 2 << 14, + + // OneArgFPRW - 1 arg FP instruction which implicitly read ST(0) and write a + // result back to ST(0). For example, fcos, fsqrt, etc. + // + OneArgFPRW = 3 << 14, + + // TwoArgFP - 2 arg FP instructions which implicitly read ST(0), and an + // explicit argument, storing the result to either ST(0) or the implicit + // argument. For example: fadd, fsub, fmul, etc... + TwoArgFP = 4 << 14, + + // SpecialFP - Special instruction forms. Dispatch by opcode explicitly. + SpecialFP = 5 << 14, + + // FPTypeMask - Mask for all of the FP types... + FPTypeMask = 7 << 14, + + // Bits 17 -> 31 are unused }; } From lattner at cs.uiuc.edu Sun Jan 12 18:52:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:52:00 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86RegisterInfo.def Message-ID: <200301130051.SAA22581@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86RegisterInfo.def updated: 1.11 -> 1.12 --- Log message: rename FP -> fp* --- Diffs of the changes: Index: llvm/lib/Target/X86/X86RegisterInfo.def diff -u llvm/lib/Target/X86/X86RegisterInfo.def:1.11 llvm/lib/Target/X86/X86RegisterInfo.def:1.12 --- llvm/lib/Target/X86/X86RegisterInfo.def:1.11 Tue Dec 24 23:08:03 2002 +++ llvm/lib/Target/X86/X86RegisterInfo.def Sun Jan 12 18:50:46 2003 @@ -91,13 +91,13 @@ R8 ( BH, "BH" , MRF::INT8 , 0, A_BH) // Pseudo Floating Point Registers -PFP(FP0, "fp0", MRF::FP80 , 0, 0 /*noalias*/) -PFP(FP1, "fp1", MRF::FP80 , 0, 0 /*noalias*/) -PFP(FP2, "fp2", MRF::FP80 , 0, 0 /*noalias*/) -PFP(FP3, "fp3", MRF::FP80 , 0, 0 /*noalias*/) -PFP(FP4, "fp4", MRF::FP80 , 0, 0 /*noalias*/) -PFP(FP5, "fp5", MRF::FP80 , 0, 0 /*noalias*/) -PFP(FP6, "fp6", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP0, "FP0", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP1, "FP1", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP2, "FP2", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP3, "FP3", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP4, "FP4", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP5, "FP5", MRF::FP80 , 0, 0 /*noalias*/) +PFP(FP6, "FP6", MRF::FP80 , 0, 0 /*noalias*/) // Floating point stack registers FPS(ST0, "ST(0)", MRF::FP80, 0, 0) From lattner at cs.uiuc.edu Sun Jan 12 18:52:04 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:52:04 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86TargetMachine.cpp Message-ID: <200301130051.SAA22589@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86TargetMachine.cpp updated: 1.11 -> 1.12 --- Log message: * No longer need lowerallocation pass * Add X86 Stackifier pass * Add peephole optimizer pass --- Diffs of the changes: Index: llvm/lib/Target/X86/X86TargetMachine.cpp diff -u llvm/lib/Target/X86/X86TargetMachine.cpp:1.11 llvm/lib/Target/X86/X86TargetMachine.cpp:1.12 --- llvm/lib/Target/X86/X86TargetMachine.cpp:1.11 Sat Dec 28 14:33:32 2002 +++ llvm/lib/Target/X86/X86TargetMachine.cpp Sun Jan 12 18:51:23 2003 @@ -6,9 +6,9 @@ #include "X86TargetMachine.h" #include "X86.h" -#include "llvm/Transforms/Scalar.h" #include "llvm/Target/TargetMachineImpls.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/Passes.h" #include "llvm/PassManager.h" #include "Support/CommandLine.h" #include "Support/Statistic.h" @@ -40,21 +40,17 @@ FrameInfo(TargetFrameInfo::StackGrowsDown, 1/*16*/, 0) { } - /// addPassesToJITCompile - Add passes to the specified pass manager to /// implement a fast dynamic compiler for this target. Return true if this is /// not supported for this target. /// bool X86TargetMachine::addPassesToJITCompile(PassManager &PM) { - // For the moment we have decided that malloc and free will be - // taken care of by converting them to calls, using the existing - // LLVM scalar transforms pass to do this. - PM.add(createLowerAllocationsPass()); - PM.add(createSimpleX86InstructionSelector(*this)); // TODO: optional optimizations go here + // FIXME: Add SSA based peephole optimizer here. + // Print the instruction selected machine code... if (PrintCode) PM.add(createMachineFunctionPrinterPass()); @@ -68,13 +64,18 @@ if (PrintCode) PM.add(createMachineFunctionPrinterPass()); + PM.add(createX86FloatingPointStackifierPass()); + + if (PrintCode) + PM.add(createMachineFunctionPrinterPass()); + // Insert prolog/epilog code. Eliminate abstract frame index references... PM.add(createPrologEpilogCodeInserter()); + PM.add(createX86PeepholeOptimizerPass()); + if (PrintCode) // Print the register-allocated code PM.add(createX86CodePrinterPass(std::cerr)); - - PM.add(createMachineCodeDestructionPass()); return false; // success! } From lattner at cs.uiuc.edu Sun Jan 12 18:52:07 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:52:07 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86RegisterInfo.cpp Message-ID: <200301130051.SAA22596@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86RegisterInfo.cpp updated: 1.27 -> 1.28 --- Log message: * Move frame and constant pool indexes to first argument of memory reference so we can put an offset in there as well... * Fix long/ulong stuff --- Diffs of the changes: Index: llvm/lib/Target/X86/X86RegisterInfo.cpp diff -u llvm/lib/Target/X86/X86RegisterInfo.cpp:1.27 llvm/lib/Target/X86/X86RegisterInfo.cpp:1.28 --- llvm/lib/Target/X86/X86RegisterInfo.cpp:1.27 Sat Dec 28 15:08:28 2002 +++ llvm/lib/Target/X86/X86RegisterInfo.cpp Sun Jan 12 18:50:33 2003 @@ -123,27 +123,29 @@ void X86RegisterInfo::eliminateFrameIndex(MachineFunction &MF, MachineBasicBlock::iterator &II) const { - unsigned i = 3; + unsigned i = 0; MachineInstr &MI = **II; while (!MI.getOperand(i).isFrameIndex()) { ++i; assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); } + int FrameIndex = MI.getOperand(i).getFrameIndex(); + // This must be part of a four operand memory reference. Replace the - // FrameIndex with the offset and the base register with EBP. - MI.SetMachineOperandReg(i-3, hasFP(MF) ? X86::EBP : X86::ESP); + // FrameIndex with base register with EBP. Add add an offset to the offset. + MI.SetMachineOperandReg(i, hasFP(MF) ? X86::EBP : X86::ESP); - // Now replace the frame index itself with the offset from EBP. - int FrameIndex = MI.getOperand(i).getFrameIndex(); - int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex); + // Now add the frame object offset to the offset from EBP. + int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) + + MI.getOperand(i+3).getImmedValue(); if (!hasFP(MF) && hasSPAdjust(MF)) { const MachineFrameInfo *MFI = MF.getFrameInfo(); Offset += MFI->getStackSize() + MFI->getMaxCallFrameSize(); } - MI.SetMachineOperandConst(i, MachineOperand::MO_SignExtendedImmed, Offset); + MI.SetMachineOperandConst(i+3, MachineOperand::MO_SignExtendedImmed, Offset); } void X86RegisterInfo::processFunctionBeforeFrameFinalized(MachineFunction &MF) @@ -332,15 +334,14 @@ const TargetRegisterClass* X86RegisterInfo::getRegClassForType(const Type* Ty) const { switch (Ty->getPrimitiveID()) { - default: assert(0 && "Invalid type to getClass!"); + case Type::LongTyID: + case Type::ULongTyID: assert(0 && "Long values can't fit in registers!"); + default: assert(0 && "Invalid type to getClass!"); case Type::BoolTyID: case Type::SByteTyID: case Type::UByteTyID: return &X86ByteRegisterClassInstance; case Type::ShortTyID: case Type::UShortTyID: return &X86ShortRegisterClassInstance; - case Type::LongTyID: // FIXME: Longs are not handled yet! - case Type::ULongTyID: // FIXME: Treat these like ints, this is bogus! - case Type::IntTyID: case Type::UIntTyID: case Type::PointerTyID: return &X86IntRegisterClassInstance; From lattner at cs.uiuc.edu Sun Jan 12 18:53:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:53:00 2003 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Instrumentation/TraceValues.cpp Message-ID: <200301130052.SAA22615@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Instrumentation: TraceValues.cpp updated: 1.51 -> 1.52 --- Log message: Make sure to handle %'s in strings correctly so that the names of BB's and functions are actually printed! --- Diffs of the changes: Index: llvm/lib/Transforms/Instrumentation/TraceValues.cpp diff -u llvm/lib/Transforms/Instrumentation/TraceValues.cpp:1.51 llvm/lib/Transforms/Instrumentation/TraceValues.cpp:1.52 --- llvm/lib/Transforms/Instrumentation/TraceValues.cpp:1.51 Mon Oct 21 15:00:23 2002 +++ llvm/lib/Transforms/Instrumentation/TraceValues.cpp Sun Jan 12 18:52:14 2003 @@ -26,8 +26,8 @@ cl::desc("Disable pointer hashing")); static cl::list -TraceFuncName("tracefunc", cl::desc("trace only specific functions"), - cl::value_desc("function"), cl::Hidden); +TraceFuncNames("tracefunc", cl::desc("trace only specific functions"), + cl::value_desc("function"), cl::Hidden); static void TraceValuesAtBBExit(BasicBlock *BB, Function *Printf, Function* HashPtrToSeqNum, @@ -37,13 +37,12 @@ // or if the function is in the specified list. // inline static bool -TraceThisFunction(Function &func) +TraceThisFunction(Function &F) { - if (TraceFuncName.size() == 0) - return true; + if (TraceFuncNames.empty()) return true; - return std::find(TraceFuncName.begin(), TraceFuncName.end(), func.getName()) - != TraceFuncName.end(); + return std::find(TraceFuncNames.begin(), TraceFuncNames.end(), F.getName()) + != TraceFuncNames.end(); } @@ -222,7 +221,7 @@ Tmp.erase(Tmp.begin(), I); I = std::find(Tmp.begin(), Tmp.end(), '%'); } - + Message += Tmp; Module *Mod = BB->getParent()->getParent(); // Turn the marker string into a global variable... @@ -232,7 +231,7 @@ Instruction *GEP = new GetElementPtrInst(fmtVal, vector(2,ConstantSInt::get(Type::LongTy, 0)), - "trstr", InsertBefore); + "trstrp", InsertBefore); // Insert a call to the hash function if this is a pointer value if (V && isa(V->getType()) && !DisablePtrHashing) { @@ -350,7 +349,7 @@ Instruction *InsertPos = BB.begin(); std::ostringstream OutStr; - WriteAsOperand(OutStr, &F, true); + WriteAsOperand(OutStr, &F); InsertPrintInst(0, &BB, InsertPos, "ENTERING FUNCTION: " + OutStr.str(), Printf, HashPtrToSeqNum); From lattner at cs.uiuc.edu Sun Jan 12 18:53:04 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:53:04 2003 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/ValueMapper.cpp Message-ID: <200301130052.SAA22627@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: ValueMapper.cpp updated: 1.2 -> 1.3 --- Log message: Add debugging helper --- Diffs of the changes: Index: llvm/lib/Transforms/Utils/ValueMapper.cpp diff -u llvm/lib/Transforms/Utils/ValueMapper.cpp:1.2 llvm/lib/Transforms/Utils/ValueMapper.cpp:1.3 --- llvm/lib/Transforms/Utils/ValueMapper.cpp:1.2 Sat Dec 7 15:27:16 2002 +++ llvm/lib/Transforms/Utils/ValueMapper.cpp Sun Jan 12 18:52:25 2003 @@ -81,7 +81,8 @@ assert(0 && "Unknown type of constant!"); } } - + + V->dump(); assert(0 && "Unknown value type: why didn't it get resolved?!"); return 0; } From lattner at cs.uiuc.edu Sun Jan 12 18:53:08 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:53:08 2003 Subject: [llvm-commits] CVS: llvm/lib/VMCore/Annotation.cpp Message-ID: <200301130052.SAA22636@apoc.cs.uiuc.edu> Changes in directory llvm/lib/VMCore: Annotation.cpp updated: 1.6 -> 1.7 --- Log message: Fix static initializer ordering dependency --- Diffs of the changes: Index: llvm/lib/VMCore/Annotation.cpp diff -u llvm/lib/VMCore/Annotation.cpp:1.6 llvm/lib/VMCore/Annotation.cpp:1.7 --- llvm/lib/VMCore/Annotation.cpp:1.6 Wed Jul 24 15:17:22 2002 +++ llvm/lib/VMCore/Annotation.cpp Sun Jan 12 18:52:43 2003 @@ -20,7 +20,22 @@ // On demand annotation creation support... typedef Annotation *(*AnnFactory)(AnnotationID, const Annotable *, void *); typedef map > FactMapType; -static FactMapType &getFactMap() { static FactMapType FactMap; return FactMap; } + +static FactMapType *TheFactMap = 0; +static FactMapType &getFactMap() { + if (TheFactMap == 0) + TheFactMap = new FactMapType(); + return *TheFactMap; +} + +static void eraseFromFactMap(unsigned ID) { + assert(TheFactMap && "No entries found!"); + TheFactMap->erase(ID); + if (TheFactMap->empty()) { // Delete when empty + delete TheFactMap; + TheFactMap = 0; + } +} AnnotationID AnnotationManager::getID(const string &Name) { // Name -> ID @@ -64,7 +79,7 @@ if (F) getFactMap()[ID.ID] = make_pair(F, ExtraData); else - getFactMap().erase(ID.ID); + eraseFromFactMap(ID.ID); } // createAnnotation - Create an annotation of the specified ID for the From lattner at cs.uiuc.edu Sun Jan 12 18:54:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:54:01 2003 Subject: [llvm-commits] CVS: llvm/test/Programs/Makefile.programs Message-ID: <200301130053.SAA22647@apoc.cs.uiuc.edu> Changes in directory llvm/test/Programs: Makefile.programs updated: 1.20 -> 1.21 --- Log message: Add support for testing the JIT compiler --- Diffs of the changes: Index: llvm/test/Programs/Makefile.programs diff -u llvm/test/Programs/Makefile.programs:1.20 llvm/test/Programs/Makefile.programs:1.21 --- llvm/test/Programs/Makefile.programs:1.20 Wed Oct 23 12:33:24 2002 +++ llvm/test/Programs/Makefile.programs Sun Jan 12 18:53:13 2003 @@ -5,10 +5,11 @@ # building stuff in the Programs directory. The main job of this is to take # executables for the following targets: # -# 1. The native Sun Sparc compiler +# 1. The native platform compiler # 2. LLVM Bytecode Compiler + LLI interpreter (if ENABLE_LLI is enabled) # 3. LLVM Bytecode Compiler + LLC Sparc machine code backend # 4. LLVM Bytecode Compiler + C Backend + Native Sun Compiler +# 5. LLVM Bytecode Compiler + LLI Just-In-Time Compiler # # Running them, and then diffing the output. If there are any failures, they # are flagged. @@ -49,24 +50,28 @@ # Generated code for llc (which does not require the target platform) LLCCODEGEN := $(addsuffix .llc.s, $(PREFIXED_PROGRAMS_TO_TEST)) CBECODEGEN := $(addsuffix .cbe.c, $(PREFIXED_PROGRAMS_TO_TEST)) - + # Output produced by programs run GCCOUTPUT := $(addsuffix .ll, $(addprefix Output/,$(Source:.c=))) NATOUTPUT := $(addsuffix .out-nat, $(PREFIXED_PROGRAMS_TO_TEST)) LLIOUTPUT := $(addsuffix .out-lli, $(PREFIXED_PROGRAMS_TO_TEST)) +JITOUTPUT := $(addsuffix .out-jit, $(PREFIXED_PROGRAMS_TO_TEST)) LLCOUTPUT := $(addsuffix .out-llc, $(PREFIXED_PROGRAMS_TO_TEST)) CBEOUTPUT := $(addsuffix .out-cbe, $(PREFIXED_PROGRAMS_TO_TEST)) # Diffs of program runs vs the native program LLIDIFFS := $(addsuffix .diff-lli, $(PREFIXED_PROGRAMS_TO_TEST)) +JITDIFFS := $(addsuffix .diff-jit, $(PREFIXED_PROGRAMS_TO_TEST)) LLCDIFFS := $(addsuffix .diff-llc, $(PREFIXED_PROGRAMS_TO_TEST)) CBEDIFFS := $(addsuffix .diff-cbe, $(PREFIXED_PROGRAMS_TO_TEST)) # Build Program outputs: -.PRECIOUS: Output/%.out-lli Output/%.out-llc Output/%.out-nat Output/%.out-cbe +.PRECIOUS: Output/%.out-lli Output/%.out-jit Output/%.out-llc +.PRECIOUS: Output/%.out-nat Output/%.out-cbe -# Build diffs for LLI and LLC output... -.PRECIOUS: Output/%.diff-lli Output/%.diff-llc Output/%.diff-cbe +# Build diffs from the output... +.PRECIOUS: Output/%.diff-lli Output/%.diff-jit +.PRECIOUS: Output/%.diff-llc Output/%.diff-cbe # Regardless of what other options are specified, build the program's bytecode # representation. @@ -75,6 +80,7 @@ ifdef RUN_GCC_ONLY DISABLE_LLC = 1 DISABLE_CBE = 1 +DISABLE_JIT = 1 ENABLE_LLI = all:: $(GCCOUTPUT) endif @@ -99,6 +105,12 @@ all:: $(CBEDIFFS) endif +ifdef TARGET_HAS_JIT +ifndef DISABLE_JIT +all:: $(JITDIFFS) +endif +endif + ifdef ENABLE_LLI all:: $(LLIDIFFS) endif @@ -116,8 +128,10 @@ # Rules to build the test output... Output/%.out-nat: Output/%.native -$< > $@ 2>&1 $(RUN_OPTIONS) -Output/%.out-lli: Output/%.llvm $(LLI) - -$< > $@ 2>&1 $(RUN_OPTIONS) +Output/%.out-lli: Output/%.llvm.bc $(LLI) + -$(LLI) -q -abort-on-exception -force-interpreter=true $< > $@ 2>&1 $(RUN_OPTIONS) +Output/%.out-jit: Output/%.llvm.bc $(LLI) + -$(LLI) -force-interpreter=false $< > $@ 2>&1 $(RUN_OPTIONS) Output/%.out-llc: Output/%.llc -$< > $@ 2>&1 $(RUN_OPTIONS) Output/%.out-cbe: Output/%.cbe @@ -126,6 +140,9 @@ # Rules to diff test output... Output/%.diff-lli: Output/%.out-nat Output/%.out-lli $(DIFFPROG) lli $(subst Output/,,$(@:.diff-lli=)) + +Output/%.diff-jit: Output/%.out-nat Output/%.out-jit + $(DIFFPROG) jit $(subst Output/,,$(@:.diff-jit=)) Output/%.diff-llc: Output/%.out-nat Output/%.out-llc $(DIFFPROG) llc $(subst Output/,,$(@:.diff-llc=)) From lattner at cs.uiuc.edu Sun Jan 12 18:55:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:55:00 2003 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Olden-health/args.c Message-ID: <200301130054.SAA22673@apoc.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Olden-health: args.c updated: 1.5 -> 1.6 --- Log message: Minor fix to make it work better on X86 jit --- Diffs of the changes: Index: llvm/test/Programs/MultiSource/Olden-health/args.c diff -u llvm/test/Programs/MultiSource/Olden-health/args.c:1.5 llvm/test/Programs/MultiSource/Olden-health/args.c:1.6 --- llvm/test/Programs/MultiSource/Olden-health/args.c:1.5 Tue Jan 22 14:40:26 2002 +++ llvm/test/Programs/MultiSource/Olden-health/args.c Sun Jan 12 18:54:06 2003 @@ -20,7 +20,7 @@ seed = atol(argv[3]); } - printf("max_level=%d max_time=%ld seed=%ld \n", max_level, max_time, seed); + printf("max_level=%d max_time=%d seed=%d \n", max_level, (int)max_time, (int)seed); } From lattner at cs.uiuc.edu Sun Jan 12 18:55:04 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:55:04 2003 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Olden-em3d/util.c Message-ID: <200301130054.SAA22660@apoc.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Olden-em3d: util.c updated: 1.1 -> 1.2 --- Log message: Fix to work on x86 --- Diffs of the changes: Index: llvm/test/Programs/MultiSource/Olden-em3d/util.c diff -u llvm/test/Programs/MultiSource/Olden-em3d/util.c:1.1 llvm/test/Programs/MultiSource/Olden-em3d/util.c:1.2 --- llvm/test/Programs/MultiSource/Olden-em3d/util.c:1.1 Mon Nov 12 23:44:57 2001 +++ llvm/test/Programs/MultiSource/Olden-em3d/util.c Sun Jan 12 18:53:50 2003 @@ -20,7 +20,7 @@ /* return a random number from 0 to range-1 */ int gen_number(int range) { - return lrand48() % range; + return (int)lrand48() % range; } /* return a random number in [-range,range] but not zero */ From lattner at cs.uiuc.edu Sun Jan 12 18:56:00 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:56:00 2003 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Olden-voronoi/defines.h newvor.c Message-ID: <200301130055.SAA22692@apoc.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Olden-voronoi: defines.h updated: 1.2 -> 1.3 newvor.c updated: 1.1 -> 1.2 --- Log message: Changes to enable it to work on both 32 and 64 bit targets --- Diffs of the changes: Index: llvm/test/Programs/MultiSource/Olden-voronoi/defines.h diff -u llvm/test/Programs/MultiSource/Olden-voronoi/defines.h:1.2 llvm/test/Programs/MultiSource/Olden-voronoi/defines.h:1.3 --- llvm/test/Programs/MultiSource/Olden-voronoi/defines.h:1.2 Thu May 9 19:12:55 2002 +++ llvm/test/Programs/MultiSource/Olden-voronoi/defines.h Sun Jan 12 18:54:55 2003 @@ -4,12 +4,13 @@ typedef int BOOLEAN; typedef unsigned long long uint64_t; +typedef unsigned long uptrint; struct edge_rec { struct VERTEX *v; struct edge_rec *next; - int wasseen; - int more_data[3]; /* 32 byte align this thing */ + long wasseen; + void *Buffer; }; @@ -68,13 +69,13 @@ #define destv(a) dest(a)->v -#define SIZE ((uint64_t) sizeof(struct edge_rec)) -#define ANDF ((uint64_t) 4*sizeof(struct edge_rec) - 1) +#define SIZE ((uptrint) sizeof(struct edge_rec)) +#define ANDF ((uptrint) 4*sizeof(struct edge_rec) - 1) -#define sym(a) ((QUAD_EDGE) (((uint64_t) (a)) ^ 2*SIZE)) -#define rot(a) ((QUAD_EDGE) ( (((uint64_t) (a) + 1*SIZE) & ANDF) | ((uint64_t) (a) & ~ANDF) )) -#define rotinv(a) ((QUAD_EDGE) ( (((uint64_t) (a) + 3*SIZE) & ANDF) | ((uint64_t) (a) & ~ANDF) )) -#define base(a) ((QUAD_EDGE) ((uint64_t a) & ~ANDF)) +#define sym(a) ((QUAD_EDGE) (((uptrint) (a)) ^ 2*SIZE)) +#define rot(a) ((QUAD_EDGE) ( (((uptrint) (a) + 1*SIZE) & ANDF) | ((uptrint) (a) & ~ANDF) )) +#define rotinv(a) ((QUAD_EDGE) ( (((uptrint) (a) + 3*SIZE) & ANDF) | ((uptrint) (a) & ~ANDF) )) +#define base(a) ((QUAD_EDGE) ((uptrint a) & ~ANDF)) QUAD_EDGE alloc_edge(); void free_edge(QUAD_EDGE e); Index: llvm/test/Programs/MultiSource/Olden-voronoi/newvor.c diff -u llvm/test/Programs/MultiSource/Olden-voronoi/newvor.c:1.1 llvm/test/Programs/MultiSource/Olden-voronoi/newvor.c:1.2 --- llvm/test/Programs/MultiSource/Olden-voronoi/newvor.c:1.1 Mon Feb 18 12:48:49 2002 +++ llvm/test/Programs/MultiSource/Olden-voronoi/newvor.c Sun Jan 12 18:54:55 2003 @@ -164,11 +164,12 @@ void* myalign(int align_size, int alloc_size) { char* base = (char*)malloc(alloc_size + align_size); + void *Result; if (base == NULL){ printf("myalign() failed\n"); exit(-1); } - return (void*)(base + align_size - ((uint64_t)base % align_size)); + return (void*)(base + align_size - ((uptrint)base % align_size)); } QUAD_EDGE alloc_edge() { @@ -177,7 +178,7 @@ if (avail_edge == NYL) { ans = (QUAD_EDGE)myalign(4*(sizeof(struct edge_rec)), 4*(sizeof(struct edge_rec))); - if ((uint64_t) ans & ANDF) { + if ((uptrint)ans & ANDF) { printf("Aborting in alloc_edge, ans = 0x%p\n", ans); exit(-1); } @@ -187,7 +188,7 @@ } void free_edge(QUAD_EDGE e) { - e = (QUAD_EDGE) ((uint64_t) e ^ ((uint64_t) e & ANDF)); + e = (QUAD_EDGE) ((uptrint) e ^ ((uptrint) e & ANDF)); onext(e) = avail_edge; avail_edge = e; } @@ -228,7 +229,6 @@ double dret ; double xa,ya,xb,yb,xc,yc; VERTEX_PTR loc_a,loc_b,loc_c; - loc_a = a; xa=X(loc_a); ya=Y(loc_a); loc_b = b; @@ -254,13 +254,13 @@ onext(temp) = ans; orig(temp) = origin; - temp = (QUAD_EDGE) ((uint64_t) temp+SIZE); - onext(temp) = (QUAD_EDGE) ((uint64_t) ans + 3*SIZE); - temp = (QUAD_EDGE) ((uint64_t) temp+SIZE); - onext(temp) = (QUAD_EDGE) ((uint64_t) ans + 2*SIZE); + temp = (QUAD_EDGE) ((uptrint) temp+SIZE); + onext(temp) = (QUAD_EDGE) ((uptrint) ans + 3*SIZE); + temp = (QUAD_EDGE) ((uptrint) temp+SIZE); + onext(temp) = (QUAD_EDGE) ((uptrint) ans + 2*SIZE); orig(temp) = destination; - temp = (QUAD_EDGE) ((uint64_t) temp+SIZE); - onext(temp) = (QUAD_EDGE) ((uint64_t) ans + 1*SIZE); + temp = (QUAD_EDGE) ((uptrint) temp+SIZE); + onext(temp) = (QUAD_EDGE) ((uptrint) ans + 1*SIZE); /*printf("Edge made @ 0x%x\n",ans);*/ /*dump_quad(ans);*/ @@ -343,7 +343,7 @@ QUAD_EDGE j; VERTEX_PTR v; - ptr = (QUAD_EDGE) ((uint64_t) ptr & ~ANDF); + ptr = (QUAD_EDGE) ((uptrint) ptr & ~ANDF); printf("Entered DUMP_QUAD: ptr=0x%p\n",ptr); for (i=0; i<4; i++) { @@ -363,7 +363,7 @@ int rvalid, lvalid; register QUAD_EDGE basel,lcand,rcand,t; VERTEX_PTR t1,t2; - + /*printf("merge\n");*/ while (1) { VERTEX_PTR t3=orig(rdi); @@ -616,6 +616,8 @@ struct get_point point; int j; + //printf("seed = %d %f %d %d %d %d\n", n, curmax, i, seed, processor, numnodes); + if (n<1) { point.v = NULL; point.curmax=curmax; @@ -632,6 +634,7 @@ node = (VERTEX_PTR) malloc(sizeof(struct VERTEX)); /*printf("Get points past alloc,n=%d\n",n);*/ + //printf("%f\n", (double)point.seed); X(node) = point.curmax * exp(log(drand(point.seed))/i); Y(node) = drand(point.seed); NORM(node) = X(node)*X(node) + Y(node)*Y(node); From lattner at cs.uiuc.edu Sun Jan 12 18:56:04 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:56:04 2003 Subject: [llvm-commits] CVS: llvm/test/Programs/MultiSource/Olden-voronoi/Makefile Message-ID: <200301130055.SAA22697@apoc.cs.uiuc.edu> Changes in directory llvm/test/Programs/MultiSource/Olden-voronoi: Makefile updated: 1.2 -> 1.3 --- Log message: No apparent reason to link to libl --- Diffs of the changes: Index: llvm/test/Programs/MultiSource/Olden-voronoi/Makefile diff -u llvm/test/Programs/MultiSource/Olden-voronoi/Makefile:1.2 llvm/test/Programs/MultiSource/Olden-voronoi/Makefile:1.3 --- llvm/test/Programs/MultiSource/Olden-voronoi/Makefile:1.2 Sun May 19 10:52:16 2002 +++ llvm/test/Programs/MultiSource/Olden-voronoi/Makefile Sun Jan 12 18:54:27 2003 @@ -3,6 +3,6 @@ PROG = voronoi INCLUDES = defines.h CPPFLAGS = -DTORONTO -LDFLAGS = -ll -lm +LDFLAGS = -lm include ../Makefile.multisrc From lattner at cs.uiuc.edu Sun Jan 12 18:56:08 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:56:08 2003 Subject: [llvm-commits] CVS: llvm/test/Programs/SingleSource/pi.c Message-ID: <200301130055.SAA22710@apoc.cs.uiuc.edu> Changes in directory llvm/test/Programs/SingleSource: pi.c updated: 1.2 -> 1.3 --- Log message: Fixes to make it work better in X86 64 bit emulation --- Diffs of the changes: Index: llvm/test/Programs/SingleSource/pi.c diff -u llvm/test/Programs/SingleSource/pi.c:1.2 llvm/test/Programs/SingleSource/pi.c:1.3 --- llvm/test/Programs/SingleSource/pi.c:1.2 Thu Jan 31 22:29:41 2002 +++ llvm/test/Programs/SingleSource/pi.c Sun Jan 12 18:55:38 2003 @@ -32,7 +32,6 @@ itot = 1200; for(j=1; j<=itot; j++) { - /* c X and Y are two uniform random numbers between 0 and 1. c They are computed using two linear congruential generators. @@ -54,9 +53,8 @@ low = low + 1; } } - printf(" x = %9.6f y = %12.2f low = %8ld j = %7ld\n",x,y,low,j); + printf(" x = %9.6f y = %12.2f low = %8d j = %7d\n",x,y,(int)low,(int)j); pi = 4.0 * (float)low/(float)itot; - printf("Pi = %9.6f ztot = %12.2f itot = %8ld\n",pi,ztot,itot); - + printf("Pi = %9.6f ztot = %12.2f itot = %8d\n",pi,ztot,(int)itot); return 0; } From lattner at cs.uiuc.edu Sun Jan 12 18:58:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:58:01 2003 Subject: [llvm-commits] CVS: llvm/test/Regression/Jello/test-fp.ll Message-ID: <200301130057.SAA22829@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Jello: test-fp.ll updated: 1.2 -> 1.3 --- Log message: add div test as well --- Diffs of the changes: Index: llvm/test/Regression/Jello/test-fp.ll diff -u llvm/test/Regression/Jello/test-fp.ll:1.2 llvm/test/Regression/Jello/test-fp.ll:1.3 --- llvm/test/Regression/Jello/test-fp.ll:1.2 Sat Dec 28 14:00:47 2002 +++ llvm/test/Regression/Jello/test-fp.ll Sun Jan 12 18:56:54 2003 @@ -6,13 +6,15 @@ %X = mul double %W, %W %Y = div double %X, %X %Z = rem double %Y, %Y + %Z = div double %Z, %W %Q = add double %Z, %Arg - store double %Q, double* %DP + %R = cast double %Q to double + store double %R, double* %DP ret double %Z } int %main() { %X = alloca double - call double %test(double* %X, double 1.0) + call double %test(double* %X, double 2.0) ret int 0 } From lattner at cs.uiuc.edu Sun Jan 12 18:58:04 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:58:04 2003 Subject: [llvm-commits] CVS: llvm/test/Regression/Jello/test-arith.ll Message-ID: <200301130057.SAA22834@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Jello: test-arith.ll updated: 1.6 -> 1.7 --- Log message: Test long support --- Diffs of the changes: Index: llvm/test/Regression/Jello/test-arith.ll diff -u llvm/test/Regression/Jello/test-arith.ll:1.6 llvm/test/Regression/Jello/test-arith.ll:1.7 --- llvm/test/Regression/Jello/test-arith.ll:1.6 Thu Dec 12 23:51:32 2002 +++ llvm/test/Regression/Jello/test-arith.ll Sun Jan 12 18:56:27 2003 @@ -1,4 +1,3 @@ - int %main() { %A = add sbyte 0, 12 %B = sub sbyte %A, 1 @@ -23,6 +22,14 @@ %E = rem int %D, %D %F = div uint 5, 6 %G = rem uint 6, 5 + + %A = add long 0, 12 + %B = sub long %A, 1 + %C = mul long %B, %B + %D = div long %C, %C + %E = rem long %D, %D + %F = div ulong 5, 6 + %G = rem ulong 6, 5 ret int 0 } From lattner at cs.uiuc.edu Sun Jan 12 18:58:08 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:58:08 2003 Subject: [llvm-commits] CVS: llvm/test/Regression/Jello/test-loadstore.ll Message-ID: <200301130057.SAA22845@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Jello: test-loadstore.ll updated: 1.4 -> 1.5 --- Log message: Add test for longs --- Diffs of the changes: Index: llvm/test/Regression/Jello/test-loadstore.ll diff -u llvm/test/Regression/Jello/test-loadstore.ll:1.4 llvm/test/Regression/Jello/test-loadstore.ll:1.5 --- llvm/test/Regression/Jello/test-loadstore.ll:1.4 Sat Dec 28 14:00:33 2002 +++ llvm/test/Regression/Jello/test-loadstore.ll Sun Jan 12 18:57:04 2003 @@ -1,5 +1,5 @@ -void %test(sbyte* %P, short* %P, int* %P) { +void %test(sbyte* %P, short* %P, int* %P, long* %P) { %V = load sbyte* %P store sbyte %V, sbyte* %P @@ -8,6 +8,10 @@ %V = load int* %P store int %V, int* %P + + %V = load long* %P + store long %V, long* %P + ret void } @@ -22,7 +26,8 @@ %A = alloca sbyte %B = alloca short %C = alloca int - call void %test(sbyte* %A, short* %B, int* %C) + %D = alloca long + call void %test(sbyte* %A, short* %B, int* %C, long* %D) call uint %varalloca(uint 7) ret int 0 From lattner at cs.uiuc.edu Sun Jan 12 18:58:12 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:58:12 2003 Subject: [llvm-commits] CVS: llvm/test/Regression/Jello/test-logical.ll Message-ID: <200301130057.SAA22856@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Jello: test-logical.ll updated: 1.3 -> 1.4 --- Log message: TEst longs --- Diffs of the changes: Index: llvm/test/Regression/Jello/test-logical.ll diff -u llvm/test/Regression/Jello/test-logical.ll:1.3 llvm/test/Regression/Jello/test-logical.ll:1.4 --- llvm/test/Regression/Jello/test-logical.ll:1.3 Mon Dec 16 20:02:01 2002 +++ llvm/test/Regression/Jello/test-logical.ll Sun Jan 12 18:57:11 2003 @@ -12,5 +12,9 @@ %B = or int %A, 7 %C = xor int %B, %A + %A = and long 4, 8 + %B = or long %A, 7 + %C = xor long %B, %A + ret int 0 } From lattner at cs.uiuc.edu Sun Jan 12 18:58:16 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:58:16 2003 Subject: [llvm-commits] CVS: llvm/test/Regression/Jello/test-ret.ll Message-ID: <200301130057.SAA22873@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Jello: test-ret.ll updated: 1.3 -> 1.4 --- Log message: Test longs and fp --- Diffs of the changes: Index: llvm/test/Regression/Jello/test-ret.ll diff -u llvm/test/Regression/Jello/test-ret.ll:1.3 llvm/test/Regression/Jello/test-ret.ll:1.4 --- llvm/test/Regression/Jello/test-ret.ll:1.3 Thu Dec 12 23:42:57 2002 +++ llvm/test/Regression/Jello/test-ret.ll Sun Jan 12 18:57:19 2003 @@ -7,7 +7,7 @@ ushort %test() { ret ushort 65535 } int %main() { ret int 0 } uint %test() { ret uint 4 } -;long %test() { ret void } -;ulong %test() { ret void } -;float %test() { ret float 1.0 } -;double %test() { ret double 2.0 } +long %test() { ret long 0 } +ulong %test() { ret ulong 0 } +float %test() { ret float 1.0 } +double %test() { ret double 2.0 } From lattner at cs.uiuc.edu Sun Jan 12 18:58:19 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:58:19 2003 Subject: [llvm-commits] CVS: llvm/test/Regression/Jello/test-shift.ll Message-ID: <200301130057.SAA22880@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Jello: test-shift.ll updated: 1.2 -> 1.3 --- Log message: test the shift cases for long that are implemented --- Diffs of the changes: Index: llvm/test/Regression/Jello/test-shift.ll diff -u llvm/test/Regression/Jello/test-shift.ll:1.2 llvm/test/Regression/Jello/test-shift.ll:1.3 --- llvm/test/Regression/Jello/test-shift.ll:1.2 Thu Dec 12 23:44:21 2002 +++ llvm/test/Regression/Jello/test-shift.ll Sun Jan 12 18:57:49 2003 @@ -1,27 +1,31 @@ ; test shifts int %main() { - %i = add int 10, 0 - %u = add uint 20, 0 - %shamt = add ubyte 0, 0 - %shamt2 = add ubyte 1, 0 - %shamt3 = add ubyte 2, 0 - %shamt4 = add ubyte 3, 0 - ; constantShiftAmount isRightShift isOperandUnsigned - ; 0 0 0 - %temp01 = shl int %i, ubyte %shamt - ; 0 0 1 - %temp02 = shl uint %u, ubyte %shamt2 - ; 0 1 0 - %temp03 = shr int %i, ubyte %shamt3 - ; 0 1 1 - %temp04 = shr uint %u, ubyte %shamt4 - ; 1 0 0 - %temp05 = shl int %i, ubyte 4 - ; 1 0 1 - %temp06 = shl uint %u, ubyte 5 - ; 1 1 0 - %temp07 = shr int %i, ubyte 6 - ; 1 1 1 - %temp08 = shr uint %u, ubyte 7 + %shamt = add ubyte 0, 1 + + ; Left shifts... + %t1 = shl int 1, ubyte %shamt + %t2 = shl int 1, ubyte 4 + + %t1 = shl uint 1, ubyte %shamt + %t2 = shl uint 1, ubyte 5 + + ;%t1 = shl long 1, ubyte %shamt + %t2 = shl long 1, ubyte 4 + + ;%t1 = shl ulong 1, ubyte %shamt + %t2 = shl ulong 1, ubyte 5 + + ; Right shifts... + %t1 = shr int 1, ubyte %shamt + %t2 = shr int 1, ubyte 4 + + %t1 = shr uint 1, ubyte %shamt + %t2 = shr uint 1, ubyte 5 + + ;%t1 = shr long 1, ubyte %shamt + %t2 = shr long 1, ubyte 4 + + ;%t1 = shr ulong 1, ubyte %shamt + %t2 = shr ulong 1, ubyte 5 ret int 0 } From lattner at cs.uiuc.edu Sun Jan 12 18:59:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:59:01 2003 Subject: [llvm-commits] CVS: llvm/test/Regression/Jello/test-setcond-int.ll Message-ID: <200301130058.SAA22893@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Jello: test-setcond-int.ll updated: 1.3 -> 1.4 --- Log message: test longs --- Diffs of the changes: Index: llvm/test/Regression/Jello/test-setcond-int.ll diff -u llvm/test/Regression/Jello/test-setcond-int.ll:1.3 llvm/test/Regression/Jello/test-setcond-int.ll:1.4 --- llvm/test/Regression/Jello/test-setcond-int.ll:1.3 Thu Dec 12 23:43:36 2002 +++ llvm/test/Regression/Jello/test-setcond-int.ll Sun Jan 12 18:57:37 2003 @@ -2,8 +2,8 @@ int %main() { %int1 = add int 0, 0 %int2 = add int 0, 0 - ;%long1 = add long 0, 0 - ;%long2 = add long 0, 0 + %long1 = add long 0, 0 + %long2 = add long 0, 0 %sbyte1 = add sbyte 0, 0 %sbyte2 = add sbyte 0, 0 %short1 = add short 0, 0 @@ -12,8 +12,8 @@ %ubyte2 = add ubyte 0, 0 %uint1 = add uint 0, 0 %uint2 = add uint 0, 0 - ;%ulong1 = add ulong 0, 0 - ;%ulong2 = add ulong 0, 0 + %ulong1 = add ulong 0, 0 + %ulong2 = add ulong 0, 0 %ushort1 = add ushort 0, 0 %ushort2 = add ushort 0, 0 %test1 = seteq ubyte %ubyte1, %ubyte2 @@ -34,12 +34,12 @@ %test16 = setle uint %uint1, %uint2 %test17 = setlt uint %uint1, %uint2 %test18 = setne uint %uint1, %uint2 - ;%test19 = seteq ulong %ulong1, %ulong2 - ;%test20 = setge ulong %ulong1, %ulong2 - ;%test21 = setgt ulong %ulong1, %ulong2 - ;%test22 = setle ulong %ulong1, %ulong2 - ;%test23 = setlt ulong %ulong1, %ulong2 - ;%test24 = setne ulong %ulong1, %ulong2 + %test19 = seteq ulong %ulong1, %ulong2 + %test20 = setge ulong %ulong1, %ulong2 + %test21 = setgt ulong %ulong1, %ulong2 + %test22 = setle ulong %ulong1, %ulong2 + %test23 = setlt ulong %ulong1, %ulong2 + %test24 = setne ulong %ulong1, %ulong2 %test25 = seteq sbyte %sbyte1, %sbyte2 %test26 = setge sbyte %sbyte1, %sbyte2 %test27 = setgt sbyte %sbyte1, %sbyte2 @@ -58,11 +58,11 @@ %test40 = setle int %int1, %int2 %test41 = setlt int %int1, %int2 %test42 = setne int %int1, %int2 - ;%test43 = seteq long %long1, %long2 - ;%test44 = setge long %long1, %long2 - ;%test45 = setgt long %long1, %long2 - ;%test46 = setle long %long1, %long2 - ;%test47 = setlt long %long1, %long2 - ;%test48 = setne long %long1, %long2 + %test43 = seteq long %long1, %long2 + %test44 = setge long %long1, %long2 + %test45 = setgt long %long1, %long2 + %test46 = setle long %long1, %long2 + %test47 = setlt long %long1, %long2 + %test48 = setne long %long1, %long2 ret int 0 } From lattner at cs.uiuc.edu Sun Jan 12 18:59:05 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:59:05 2003 Subject: [llvm-commits] CVS: llvm/test/Regression/Jello/test-cast.ll Message-ID: <200301130058.SAA22898@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Jello: test-cast.ll updated: 1.1 -> 1.2 --- Log message: test a bunch of stuff --- Diffs of the changes: Index: llvm/test/Regression/Jello/test-cast.ll diff -u llvm/test/Regression/Jello/test-cast.ll:1.1 llvm/test/Regression/Jello/test-cast.ll:1.2 --- llvm/test/Regression/Jello/test-cast.ll:1.1 Sun Dec 15 01:55:43 2002 +++ llvm/test/Regression/Jello/test-cast.ll Sun Jan 12 18:56:37 2003 @@ -1,7 +1,65 @@ +int %foo() { + ret int 0 +} + int %main() { + ; cast bool to ... + cast bool true to bool cast bool true to int + + ; cast sbyte to ... + cast sbyte 0 to sbyte + cast sbyte 4 to short + cast sbyte 4 to long + cast sbyte 4 to ulong + cast sbyte 4 to double + + ; cast short to ... + cast short 0 to short + cast short 0 to long + cast short 0 to ulong + cast short 0 to double + + ; cast int to ... cast int 6 to bool + cast int 6 to short + cast int 0 to int + cast int 0 to long + cast int 0 to ulong + cast int 0 to double + + ; cast uint to ... + cast uint 0 to long + cast uint 0 to ulong + + ; cast long to ... + cast long 0 to sbyte + cast long 0 to ubyte + cast long 0 to short + cast long 0 to ushort + cast long 0 to int + cast long 0 to uint + cast long 0 to long + cast long 0 to ulong + cast long 0 to float + cast long 0 to double + + ; cast float to ... + cast float 0.0 to float + cast float 0.0 to double + + ; cast double to ... + cast double 0.0 to sbyte + cast double 0.0 to ubyte + cast double 0.0 to short + cast double 0.0 to ushort + cast double 0.0 to int + cast double 0.0 to uint + cast double 0.0 to long + ;cast double 0.0 to ulong + cast double 0.0 to float + cast double 0.0 to double ret int 0 } From lattner at cs.uiuc.edu Sun Jan 12 18:59:09 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:59:09 2003 Subject: [llvm-commits] CVS: llvm/tools/lli/Makefile Message-ID: <200301130058.SAA22907@apoc.cs.uiuc.edu> Changes in directory llvm/tools/lli: Makefile updated: 1.19 -> 1.20 --- Log message: No longer need scalaropts lib --- Diffs of the changes: Index: llvm/tools/lli/Makefile diff -u llvm/tools/lli/Makefile:1.19 llvm/tools/lli/Makefile:1.20 --- llvm/tools/lli/Makefile:1.19 Mon Dec 23 17:59:32 2002 +++ llvm/tools/lli/Makefile Sun Jan 12 18:58:18 2003 @@ -2,7 +2,7 @@ TOOLNAME = lli PARALLEL_DIRS = Interpreter JIT -JITLIBS = lli-jit codegen x86 scalaropts.a +JITLIBS = lli-jit codegen x86 USEDLIBS = lli-interpreter $(JITLIBS) bcreader vmcore analysis.a support.a target.a #transforms.a From lattner at cs.uiuc.edu Sun Jan 12 18:59:13 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 18:59:13 2003 Subject: [llvm-commits] CVS: llvm/tools/lli/ExecutionEngine.cpp Message-ID: <200301130058.SAA22915@apoc.cs.uiuc.edu> Changes in directory llvm/tools/lli: ExecutionEngine.cpp updated: 1.3 -> 1.4 --- Log message: Add fixme --- Diffs of the changes: Index: llvm/tools/lli/ExecutionEngine.cpp diff -u llvm/tools/lli/ExecutionEngine.cpp:1.3 llvm/tools/lli/ExecutionEngine.cpp:1.4 --- llvm/tools/lli/ExecutionEngine.cpp:1.3 Sat Dec 28 14:00:15 2002 +++ llvm/tools/lli/ExecutionEngine.cpp Sun Jan 12 18:58:06 2003 @@ -170,7 +170,8 @@ void *ExecutionEngine::CreateArgv(const std::vector &InputArgv) { // Pointers are 64 bits... - PointerTy *Result = new PointerTy[InputArgv.size()+1]; // 64 bit assumption + // FIXME: Assumes 64 bit target + PointerTy *Result = new PointerTy[InputArgv.size()+1]; DEBUG(std::cerr << "ARGV = " << (void*)Result << "\n"); for (unsigned i = 0; i < InputArgv.size(); ++i) { From lattner at cs.uiuc.edu Sun Jan 12 19:00:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 19:00:01 2003 Subject: [llvm-commits] CVS: llvm/tools/lli/Interpreter/ExternalFunctions.cpp Message-ID: <200301130059.SAA22937@apoc.cs.uiuc.edu> Changes in directory llvm/tools/lli/Interpreter: ExternalFunctions.cpp updated: 1.41 -> 1.42 --- Log message: * Wrap at 80 columns * Fix a ton of warnings * Implement puts --- Diffs of the changes: Index: llvm/tools/lli/Interpreter/ExternalFunctions.cpp diff -u llvm/tools/lli/Interpreter/ExternalFunctions.cpp:1.41 llvm/tools/lli/Interpreter/ExternalFunctions.cpp:1.42 --- llvm/tools/lli/Interpreter/ExternalFunctions.cpp:1.41 Mon Dec 23 17:59:41 2002 +++ llvm/tools/lli/Interpreter/ExternalFunctions.cpp Sun Jan 12 18:59:47 2003 @@ -118,9 +118,10 @@ extern "C" { // Don't add C++ manglings to llvm mangling :) // Implement void printstr([ubyte {x N}] *) -GenericValue lle_VP_printstr(FunctionType *M, const vector &ArgVal){ +GenericValue lle_VP_printstr(FunctionType *M, + const vector &ArgVal){ assert(ArgVal.size() == 1 && "printstr only takes one argument!"); - cout << (char*)ArgVal[0].PointerVal; + cout << (char*)GVTOP(ArgVal[0]); return GenericValue(); } @@ -133,7 +134,8 @@ } // Implement 'void printVal(X)' for every type... -GenericValue lle_X_printVal(FunctionType *M, const vector &ArgVal) { +GenericValue lle_X_printVal(FunctionType *M, + const vector &ArgVal) { assert(ArgVal.size() == 1 && "generic print only takes one argument!"); // Specialize print([ubyte {x N} ] *) and print(sbyte *) @@ -150,7 +152,8 @@ // Implement 'void printString(X)' // Argument must be [ubyte {x N} ] * or sbyte * -GenericValue lle_X_printString(FunctionType *M, const vector &ArgVal) { +GenericValue lle_X_printString(FunctionType *M, + const vector &ArgVal) { assert(ArgVal.size() == 1 && "generic print only takes one argument!"); return lle_VP_printstr(M, ArgVal); } @@ -219,15 +222,13 @@ // void *malloc(uint) GenericValue lle_X_malloc(FunctionType *M, const vector &Args) { assert(Args.size() == 1 && "Malloc expects one argument!"); - GenericValue GV; - GV.PointerVal = (PointerTy)malloc(Args[0].UIntVal); - return GV; + return PTOGV(malloc(Args[0].UIntVal)); } // void free(void *) GenericValue lle_X_free(FunctionType *M, const vector &Args) { assert(Args.size() == 1); - free((void*)Args[0].PointerVal); + free(GVTOP(Args[0])); return GenericValue(); } @@ -235,7 +236,7 @@ GenericValue lle_X_atoi(FunctionType *M, const vector &Args) { assert(Args.size() == 1); GenericValue GV; - GV.IntVal = atoi((char*)Args[0].PointerVal); + GV.IntVal = atoi((char*)GVTOP(Args[0])); return GV; } @@ -317,11 +318,19 @@ return GenericValue(); } +// int puts(const char*) +GenericValue lle_X_puts(FunctionType *M, const vector &Args) { + assert(Args.size() == 1); + GenericValue GV; + GV.IntVal = puts((char*)GVTOP(Args[0])); + return GV; +} + // int sprintf(sbyte *, sbyte *, ...) - a very rough implementation to make // output useful. GenericValue lle_X_sprintf(FunctionType *M, const vector &Args) { - char *OutputBuffer = (char *)Args[0].PointerVal; - const char *FmtStr = (const char *)Args[1].PointerVal; + char *OutputBuffer = (char *)GVTOP(Args[0]); + const char *FmtStr = (const char *)GVTOP(Args[1]); unsigned ArgNo = 2; // printf should return # chars printed. This is completely incorrect, but @@ -376,9 +385,9 @@ case 'e': case 'E': case 'g': case 'G': case 'f': sprintf(Buffer, FmtBuf, Args[ArgNo++].DoubleVal); break; case 'p': - sprintf(Buffer, FmtBuf, (void*)Args[ArgNo++].PointerVal); break; + sprintf(Buffer, FmtBuf, (void*)GVTOP(Args[ArgNo++])); break; case 's': - sprintf(Buffer, FmtBuf, (char*)Args[ArgNo++].PointerVal); break; + sprintf(Buffer, FmtBuf, (char*)GVTOP(Args[ArgNo++])); break; default: cout << ""; ArgNo++; break; } @@ -394,10 +403,9 @@ GenericValue lle_X_printf(FunctionType *M, const vector &Args) { char Buffer[10000]; vector NewArgs; - GenericValue GV; GV.PointerVal = (PointerTy)Buffer; - NewArgs.push_back(GV); + NewArgs.push_back(PTOGV(Buffer)); NewArgs.insert(NewArgs.end(), Args.begin(), Args.end()); - GV = lle_X_sprintf(M, NewArgs); + GenericValue GV = lle_X_sprintf(M, NewArgs); cout << Buffer; return GV; } @@ -408,7 +416,7 @@ const char *Args[10]; for (unsigned i = 0; i < args.size(); ++i) - Args[i] = (const char*)args[i].PointerVal; + Args[i] = (const char*)GVTOP(args[i]); GenericValue GV; GV.IntVal = sscanf(Args[0], Args[1], Args[2], Args[3], Args[4], @@ -434,7 +442,7 @@ // have pointers that are relative to the __iob array. If this is the case, // change the FILE into the REAL stdio stream. // -static FILE *getFILE(PointerTy Ptr) { +static FILE *getFILE(void *Ptr) { static Module *LastMod = 0; static PointerTy IOBBase = 0; static unsigned FILESize; @@ -477,7 +485,7 @@ // Check to see if this is a reference to __iob... if (IOBBase) { - unsigned FDNum = (Ptr-IOBBase)/FILESize; + unsigned FDNum = ((unsigned long)Ptr-IOBBase)/FILESize; if (FDNum == 0) return stdin; else if (FDNum == 1) @@ -493,19 +501,15 @@ // FILE *fopen(const char *filename, const char *mode); GenericValue lle_X_fopen(FunctionType *M, const vector &Args) { assert(Args.size() == 2); - GenericValue GV; - - GV.PointerVal = (PointerTy)fopen((const char *)Args[0].PointerVal, - (const char *)Args[1].PointerVal); - return GV; + return PTOGV(fopen((const char *)GVTOP(Args[0]), + (const char *)GVTOP(Args[1]))); } // int fclose(FILE *F); GenericValue lle_X_fclose(FunctionType *M, const vector &Args) { assert(Args.size() == 1); GenericValue GV; - - GV.IntVal = fclose(getFILE(Args[0].PointerVal)); + GV.IntVal = fclose(getFILE(GVTOP(Args[0]))); return GV; } @@ -514,7 +518,7 @@ assert(Args.size() == 1); GenericValue GV; - GV.IntVal = feof(getFILE(Args[0].PointerVal)); + GV.IntVal = feof(getFILE(GVTOP(Args[0]))); return GV; } @@ -523,8 +527,8 @@ assert(Args.size() == 4); GenericValue GV; - GV.UIntVal = fread((void*)Args[0].PointerVal, Args[1].UIntVal, - Args[2].UIntVal, getFILE(Args[3].PointerVal)); + GV.UIntVal = fread((void*)GVTOP(Args[0]), Args[1].UIntVal, + Args[2].UIntVal, getFILE(GVTOP(Args[3]))); return GV; } @@ -533,36 +537,30 @@ assert(Args.size() == 4); GenericValue GV; - GV.UIntVal = fwrite((void*)Args[0].PointerVal, Args[1].UIntVal, - Args[2].UIntVal, getFILE(Args[3].PointerVal)); + GV.UIntVal = fwrite((void*)GVTOP(Args[0]), Args[1].UIntVal, + Args[2].UIntVal, getFILE(GVTOP(Args[3]))); return GV; } // char *fgets(char *s, int n, FILE *stream); GenericValue lle_X_fgets(FunctionType *M, const vector &Args) { assert(Args.size() == 3); - GenericValue GV; - - GV.PointerVal = (PointerTy)fgets((char*)Args[0].PointerVal, Args[1].IntVal, - getFILE(Args[2].PointerVal)); - return GV; + return GVTOP(fgets((char*)GVTOP(Args[0]), Args[1].IntVal, + getFILE(GVTOP(Args[2])))); } // FILE *freopen(const char *path, const char *mode, FILE *stream); GenericValue lle_X_freopen(FunctionType *M, const vector &Args) { assert(Args.size() == 3); - GenericValue GV; - GV.PointerVal = (PointerTy)freopen((char*)Args[0].PointerVal, - (char*)Args[1].PointerVal, - getFILE(Args[2].PointerVal)); - return GV; + return PTOGV(freopen((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1]), + getFILE(GVTOP(Args[2])))); } // int fflush(FILE *stream); GenericValue lle_X_fflush(FunctionType *M, const vector &Args) { assert(Args.size() == 1); GenericValue GV; - GV.IntVal = fflush(getFILE(Args[0].PointerVal)); + GV.IntVal = fflush(getFILE(GVTOP(Args[0]))); return GV; } @@ -570,7 +568,7 @@ GenericValue lle_X_getc(FunctionType *M, const vector &Args) { assert(Args.size() == 1); GenericValue GV; - GV.IntVal = getc(getFILE(Args[0].PointerVal)); + GV.IntVal = getc(getFILE(GVTOP(Args[0]))); return GV; } @@ -578,7 +576,7 @@ GenericValue lle_X_fputc(FunctionType *M, const vector &Args) { assert(Args.size() == 2); GenericValue GV; - GV.IntVal = fputc(Args[0].IntVal, getFILE(Args[1].PointerVal)); + GV.IntVal = fputc(Args[0].IntVal, getFILE(GVTOP(Args[1]))); return GV; } @@ -586,7 +584,7 @@ GenericValue lle_X_ungetc(FunctionType *M, const vector &Args) { assert(Args.size() == 2); GenericValue GV; - GV.IntVal = ungetc(Args[0].IntVal, getFILE(Args[1].PointerVal)); + GV.IntVal = ungetc(Args[0].IntVal, getFILE(GVTOP(Args[1]))); return GV; } @@ -596,12 +594,11 @@ assert(Args.size() > 2); char Buffer[10000]; vector NewArgs; - GenericValue GV; GV.PointerVal = (PointerTy)Buffer; - NewArgs.push_back(GV); + NewArgs.push_back(PTOGV(Buffer)); NewArgs.insert(NewArgs.end(), Args.begin()+1, Args.end()); - GV = lle_X_sprintf(M, NewArgs); + GenericValue GV = lle_X_sprintf(M, NewArgs); - fputs(Buffer, getFILE(Args[0].PointerVal)); + fputs(Buffer, getFILE(GVTOP(Args[0]))); return GV; } @@ -643,6 +640,7 @@ FuncNames["lle_X_srand48"] = lle_X_srand48; FuncNames["lle_X_lrand48"] = lle_X_lrand48; FuncNames["lle_X_sqrt"] = lle_X_sqrt; + FuncNames["lle_X_puts"] = lle_X_puts; FuncNames["lle_X_printf"] = lle_X_printf; FuncNames["lle_X_sprintf"] = lle_X_sprintf; FuncNames["lle_X_sscanf"] = lle_X_sscanf; From lattner at cs.uiuc.edu Sun Jan 12 19:00:06 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 19:00:06 2003 Subject: [llvm-commits] CVS: llvm/tools/lli/Interpreter/Execution.cpp Message-ID: <200301130059.SAA22924@apoc.cs.uiuc.edu> Changes in directory llvm/tools/lli/Interpreter: Execution.cpp updated: 1.74 -> 1.75 --- Log message: Handle value promotion properly to work with tracing better --- Diffs of the changes: Index: llvm/tools/lli/Interpreter/Execution.cpp diff -u llvm/tools/lli/Interpreter/Execution.cpp:1.74 llvm/tools/lli/Interpreter/Execution.cpp:1.75 --- llvm/tools/lli/Interpreter/Execution.cpp:1.74 Mon Dec 23 17:59:41 2002 +++ llvm/tools/lli/Interpreter/Execution.cpp Sun Jan 12 18:58:52 2003 @@ -815,8 +815,28 @@ ECStack.back().Caller = &I; vector ArgVals; ArgVals.reserve(I.getNumOperands()-1); - for (unsigned i = 1; i < I.getNumOperands(); ++i) + for (unsigned i = 1; i < I.getNumOperands(); ++i) { ArgVals.push_back(getOperandValue(I.getOperand(i), SF)); + // Promote all integral types whose size is < sizeof(int) into ints. We do + // this by zero or sign extending the value as appropriate according to the + // source type. + if (I.getOperand(i)->getType()->isIntegral() && + I.getOperand(i)->getType()->getPrimitiveSize() < 4) { + const Type *Ty = I.getOperand(i)->getType(); + if (Ty == Type::ShortTy) + ArgVals.back().IntVal = ArgVals.back().ShortVal; + else if (Ty == Type::UShortTy) + ArgVals.back().UIntVal = ArgVals.back().UShortVal; + else if (Ty == Type::SByteTy) + ArgVals.back().IntVal = ArgVals.back().SByteVal; + else if (Ty == Type::UByteTy) + ArgVals.back().UIntVal = ArgVals.back().UByteVal; + else if (Ty == Type::BoolTy) + ArgVals.back().UIntVal = ArgVals.back().BoolVal; + else + assert(0 && "Unknown type!"); + } + } // To handle indirect calls, we must get the pointer value from the argument // and treat it as a function pointer. From lattner at cs.uiuc.edu Sun Jan 12 19:01:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 19:01:01 2003 Subject: [llvm-commits] CVS: llvm/tools/lli/JIT/Emitter.cpp Message-ID: <200301130100.TAA22959@apoc.cs.uiuc.edu> Changes in directory llvm/tools/lli/JIT: Emitter.cpp updated: 1.1 -> 1.2 --- Log message: Add support for new types of values --- Diffs of the changes: Index: llvm/tools/lli/JIT/Emitter.cpp diff -u llvm/tools/lli/JIT/Emitter.cpp:1.1 llvm/tools/lli/JIT/Emitter.cpp:1.2 --- llvm/tools/lli/JIT/Emitter.cpp:1.1 Mon Dec 23 18:01:04 2002 +++ llvm/tools/lli/JIT/Emitter.cpp Sun Jan 12 19:00:12 2003 @@ -8,6 +8,8 @@ #include "VM.h" #include "llvm/CodeGen/MachineCodeEmitter.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/Target/TargetData.h" #include "llvm/Function.h" #include "Support/Statistic.h" @@ -22,15 +24,22 @@ std::vector > BBRefs; std::map BBLocations; + std::vector ConstantPoolAddresses; public: Emitter(VM &vm) : TheVM(vm) {} virtual void startFunction(MachineFunction &F); virtual void finishFunction(MachineFunction &F); + virtual void emitConstantPool(MachineConstantPool *MCP); virtual void startBasicBlock(MachineBasicBlock &BB); virtual void emitByte(unsigned char B); virtual void emitPCRelativeDisp(Value *V); - virtual void emitGlobalAddress(GlobalValue *V); + virtual void emitGlobalAddress(GlobalValue *V, bool isPCRelative); + virtual void emitGlobalAddress(const std::string &Name, bool isPCRelative); + virtual void emitFunctionConstantValueAddress(unsigned ConstantNum, + int Offset); + private: + void emitAddress(void *Addr, bool isPCRelative); }; } @@ -44,7 +53,7 @@ #include static void *getMemory() { - return mmap(0, 4096*2, PROT_READ|PROT_WRITE|PROT_EXEC, + return mmap(0, 4096*8, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); } @@ -56,6 +65,7 @@ } void Emitter::finishFunction(MachineFunction &F) { + ConstantPoolAddresses.clear(); for (unsigned i = 0, e = BBRefs.size(); i != e; ++i) { unsigned Location = BBLocations[BBRefs[i].first]; unsigned *Ref = BBRefs[i].second; @@ -66,11 +76,24 @@ NumBytes += CurByte-CurBlock; - DEBUG(std::cerr << "Finished CodeGen of [" << std::hex << (unsigned)CurBlock + DEBUG(std::cerr << "Finished CodeGen of [0x" << std::hex << (unsigned)CurBlock << std::dec << "] Function: " << F.getFunction()->getName() << ": " << CurByte-CurBlock << " bytes of text\n"); } +void Emitter::emitConstantPool(MachineConstantPool *MCP) { + const std::vector &Constants = MCP->getConstants(); + for (unsigned i = 0, e = Constants.size(); i != e; ++i) { + // For now we just allocate some memory on the heap, this can be + // dramatically improved. + const Type *Ty = ((Value*)Constants[i])->getType(); + void *Addr = malloc(TheVM.getTargetData().getTypeSize(Ty)); + TheVM.InitializeMemory(Constants[i], Addr); + ConstantPoolAddresses.push_back(Addr); + } +} + + void Emitter::startBasicBlock(MachineBasicBlock &BB) { BBLocations[BB.getBasicBlock()] = (unsigned)CurByte; } @@ -89,19 +112,39 @@ // may be patched up when the basic block is defined. // void Emitter::emitPCRelativeDisp(Value *V) { - if (Function *F = dyn_cast(V)) { - TheVM.addFunctionRef(CurByte, F); - unsigned ZeroAddr = -(unsigned)CurByte-4; // Calculate displacement to null - *(unsigned*)CurByte = ZeroAddr; // 4 byte offset - CurByte += 4; + BasicBlock *BB = cast(V); // Keep track of reference... + BBRefs.push_back(std::make_pair(BB, (unsigned*)CurByte)); + CurByte += 4; +} + +// emitAddress - Emit an address in either direct or PCRelative form... +// +void Emitter::emitAddress(void *Addr, bool isPCRelative) { + if (isPCRelative) { + *(unsigned*)CurByte = (unsigned)Addr - (unsigned)CurByte-4; } else { - BasicBlock *BB = cast(V); // Keep track of reference... - BBRefs.push_back(std::make_pair(BB, (unsigned*)CurByte)); - CurByte += 4; + *(void**)CurByte = Addr; } + CurByte += 4; +} + +void Emitter::emitGlobalAddress(GlobalValue *V, bool isPCRelative) { + if (isPCRelative) { // must be a call, this is a major hack! + TheVM.addFunctionRef(CurByte, cast(V)); + emitAddress(0, isPCRelative); // Delayed resolution... + } else { + emitAddress(TheVM.getPointerToGlobal(V), isPCRelative); + } +} + +void Emitter::emitGlobalAddress(const std::string &Name, bool isPCRelative) { + emitAddress(TheVM.getPointerToNamedFunction(Name), isPCRelative); } -void Emitter::emitGlobalAddress(GlobalValue *V) { - *(void**)CurByte = TheVM.getPointerToGlobal(V); +void Emitter::emitFunctionConstantValueAddress(unsigned ConstantNum, + int Offset) { + assert(ConstantNum < ConstantPoolAddresses.size() && + "Invalid ConstantPoolIndex!"); + *(void**)CurByte = (char*)ConstantPoolAddresses[ConstantNum]+Offset; CurByte += 4; } From lattner at cs.uiuc.edu Sun Jan 12 19:01:05 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 19:01:05 2003 Subject: [llvm-commits] CVS: llvm/tools/lli/JIT/GlobalVars.cpp Message-ID: <200301130100.TAA22970@apoc.cs.uiuc.edu> Changes in directory llvm/tools/lli/JIT: GlobalVars.cpp (r1.1) removed --- Log message: Dead file --- Diffs of the changes: From lattner at cs.uiuc.edu Sun Jan 12 19:01:09 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 19:01:09 2003 Subject: [llvm-commits] CVS: llvm/tools/lli/JIT/Callback.cpp Message-ID: <200301130100.TAA22977@apoc.cs.uiuc.edu> Changes in directory llvm/tools/lli/JIT: Callback.cpp updated: 1.1 -> 1.2 --- Log message: Bad segvs actually cause a segv now --- Diffs of the changes: Index: llvm/tools/lli/JIT/Callback.cpp diff -u llvm/tools/lli/JIT/Callback.cpp:1.1 llvm/tools/lli/JIT/Callback.cpp:1.2 --- llvm/tools/lli/JIT/Callback.cpp:1.1 Mon Dec 23 18:01:04 2002 +++ llvm/tools/lli/JIT/Callback.cpp Sun Jan 12 19:00:02 2003 @@ -19,8 +19,15 @@ #ifdef REG_EIP /* this code does not compile on Sparc! */ if (SI->si_code != SEGV_MAPERR || SI->si_addr != 0 || ucp->uc_mcontext.gregs[REG_EIP] != 0) { - std::cerr << "Bad SEGV encountered!\n"; - abort(); + std::cerr << "Bad SEGV encountered EIP = 0x" << std::hex + << ucp->uc_mcontext.gregs[REG_EIP] << " addr = " + << SI->si_addr << "!\n"; + + struct sigaction SA; // Restore old SEGV handler... + SA.sa_handler = SIG_DFL; + SA.sa_flags = SA_NOMASK; + sigaction(SIGSEGV, &SA, 0); + return; // Should core dump now... } // The call instruction should have pushed the return value onto the stack... From lattner at cs.uiuc.edu Sun Jan 12 19:01:13 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 19:01:13 2003 Subject: [llvm-commits] CVS: llvm/tools/lli/JIT/VM.cpp Message-ID: <200301130100.TAA22988@apoc.cs.uiuc.edu> Changes in directory llvm/tools/lli/JIT: VM.cpp updated: 1.1 -> 1.2 --- Log message: Add support for named functions --- Diffs of the changes: Index: llvm/tools/lli/JIT/VM.cpp diff -u llvm/tools/lli/JIT/VM.cpp:1.1 llvm/tools/lli/JIT/VM.cpp:1.2 --- llvm/tools/lli/JIT/VM.cpp:1.1 Mon Dec 23 18:01:05 2002 +++ llvm/tools/lli/JIT/VM.cpp Sun Jan 12 19:00:38 2003 @@ -55,6 +55,22 @@ static void NoopFn() {} +/// getPointerToNamedFunction - This method returns the address of the specified +/// function by using the dlsym function call. As such it is only useful for +/// resolving library symbols, not code generated symbols. +/// +void *VM::getPointerToNamedFunction(const std::string &Name) { + // If it's an external function, look it up in the process image... + void *Ptr = dlsym(0, Name.c_str()); + if (Ptr == 0) { + std::cerr << "WARNING: Cannot resolve fn '" << Name + << "' using a dummy noop function instead!\n"; + Ptr = (void*)NoopFn; + } + + return Ptr; +} + /// getPointerToFunction - This method is used to get the address of the /// specified function, compiling it if neccesary. /// @@ -62,17 +78,8 @@ void *&Addr = GlobalAddress[F]; // Function already code gen'd if (Addr) return Addr; - if (F->isExternal()) { - // If it's an external function, look it up in the process image... - void *Ptr = dlsym(0, F->getName().c_str()); - if (Ptr == 0) { - std::cerr << "WARNING: Cannot resolve fn '" << F->getName() - << "' using a dummy noop function instead!\n"; - Ptr = (void*)NoopFn; - } - - return Addr = Ptr; - } + if (F->isExternal()) + return Addr = getPointerToNamedFunction(F->getName()); // JIT all of the functions in the module. Eventually this will JIT functions // on demand. This has the effect of populating all of the non-external From lattner at cs.uiuc.edu Sun Jan 12 19:01:18 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 19:01:18 2003 Subject: [llvm-commits] CVS: llvm/tools/lli/JIT/VM.h Message-ID: <200301130100.TAA22997@apoc.cs.uiuc.edu> Changes in directory llvm/tools/lli/JIT: VM.h updated: 1.1 -> 1.2 --- Log message: Add support for named functions --- Diffs of the changes: Index: llvm/tools/lli/JIT/VM.h diff -u llvm/tools/lli/JIT/VM.h:1.1 llvm/tools/lli/JIT/VM.h:1.2 --- llvm/tools/lli/JIT/VM.h:1.1 Mon Dec 23 18:01:22 2002 +++ llvm/tools/lli/JIT/VM.h Sun Jan 12 19:00:48 2003 @@ -44,6 +44,12 @@ void *resolveFunctionReference(void *RefAddr); + /// getPointerToNamedFunction - This method returns the address of the + /// specified function by using the dlsym function call. As such it is only + /// useful for resolving library symbols, not code generated symbols. + /// + void *getPointerToNamedFunction(const std::string &Name); + private: static MachineCodeEmitter *createEmitter(VM &V); void setupPassManager(); From lattner at cs.uiuc.edu Sun Jan 12 19:02:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 19:02:01 2003 Subject: [llvm-commits] CVS: llvm/include/llvm/CodeGen/LiveVariables.h MachineConstantPool.h Passes.h Message-ID: <200301130101.TAA23011@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/CodeGen: LiveVariables.h added (r1.1) MachineConstantPool.h added (r1.1) Passes.h added (r1.1) --- Log message: Add new files --- Diffs of the changes: From lattner at cs.uiuc.edu Sun Jan 12 19:03:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 19:03:01 2003 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/FloatingPoint.cpp PeepholeOptimizer.cpp Message-ID: <200301130102.TAA23029@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: FloatingPoint.cpp added (r1.1) PeepholeOptimizer.cpp added (r1.1) --- Log message: New files --- Diffs of the changes: From lattner at cs.uiuc.edu Sun Jan 12 19:04:01 2003 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Sun Jan 12 19:04:01 2003 Subject: [llvm-commits] CVS: llvm/test/Regression/Jello/2003-01-04-ArgumentBug.ll 2003-01-04-LoopTest.ll 2003-01-09-SARTest.ll 2003-01-10-FUCOM.ll test-malloc.ll Message-ID: <200301130103.TAA23050@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Jello: 2003-01-04-ArgumentBug.ll added (r1.1) 2003-01-04-LoopTest.ll added (r1.1) 2003-01-09-SARTest.ll added (r1.1) 2003-01-10-FUCOM.ll added (r1.1) test-malloc.ll added (r1.1) --- Log message: New testcases --- Diffs of the changes: