blob: 9be6b7fe582dac27663e4653032da94536a4df07 [file] [log] [blame]
Chris Lattner035dfbe2002-08-09 20:08:06 +00001//===-- SparcInternals.h ----------------------------------------*- C++ -*-===//
Vikram S. Adve7f37fe52001-11-08 04:55:13 +00002//
Chris Lattner035dfbe2002-08-09 20:08:06 +00003// This file defines stuff that is to be private to the Sparc backend, but is
4// shared among different portions of the backend.
5//
6//===----------------------------------------------------------------------===//
Chris Lattnerc6495ee2001-09-14 03:56:45 +00007
8#ifndef SPARC_INTERNALS_H
9#define SPARC_INTERNALS_H
10
Ruchira Sasanka89fb46b2001-09-18 22:52:44 +000011#include "llvm/Target/TargetMachine.h"
Vikram S. Adve339084b2001-09-18 13:04:24 +000012#include "llvm/Target/MachineSchedInfo.h"
Vikram S. Adve5afff3b2001-11-09 02:15:52 +000013#include "llvm/Target/MachineFrameInfo.h"
14#include "llvm/Target/MachineCacheInfo.h"
Chris Lattner699683c2002-02-04 05:59:25 +000015#include "llvm/Target/MachineRegInfo.h"
Vikram S. Adved55697c2002-09-20 00:52:09 +000016#include "llvm/Target/MachineOptInfo.h"
Chris Lattnerc6495ee2001-09-14 03:56:45 +000017#include "llvm/Type.h"
Chris Lattner46cbff62001-09-14 16:56:32 +000018#include <sys/types.h>
Chris Lattnerc6495ee2001-09-14 03:56:45 +000019
Chris Lattner4387e312002-02-03 23:42:19 +000020class LiveRange;
Chris Lattnerf6e0e282001-09-14 04:32:55 +000021class UltraSparc;
Chris Lattner4387e312002-02-03 23:42:19 +000022class PhyRegAlloc;
Chris Lattner9aa697b2002-04-09 05:16:36 +000023class Pass;
Chris Lattner4387e312002-02-03 23:42:19 +000024
Chris Lattnerc6495ee2001-09-14 03:56:45 +000025enum SparcInstrSchedClass {
26 SPARC_NONE, /* Instructions with no scheduling restrictions */
27 SPARC_IEUN, /* Integer class that can use IEU0 or IEU1 */
28 SPARC_IEU0, /* Integer class IEU0 */
29 SPARC_IEU1, /* Integer class IEU1 */
30 SPARC_FPM, /* FP Multiply or Divide instructions */
31 SPARC_FPA, /* All other FP instructions */
32 SPARC_CTI, /* Control-transfer instructions */
33 SPARC_LD, /* Load instructions */
34 SPARC_ST, /* Store instructions */
35 SPARC_SINGLE, /* Instructions that must issue by themselves */
36
37 SPARC_INV, /* This should stay at the end for the next value */
38 SPARC_NUM_SCHED_CLASSES = SPARC_INV
39};
40
Chris Lattnerc6495ee2001-09-14 03:56:45 +000041
42//---------------------------------------------------------------------------
43// enum SparcMachineOpCode.
44// const MachineInstrDescriptor SparcMachineInstrDesc[]
45//
46// Purpose:
47// Description of UltraSparc machine instructions.
48//
49//---------------------------------------------------------------------------
50
Chris Lattnerc6495ee2001-09-14 03:56:45 +000051enum SparcMachineOpCode {
Chris Lattner9a3d63b2001-09-19 15:56:23 +000052#define I(ENUM, OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \
53 NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS) \
54 ENUM,
55#include "SparcInstr.def"
Chris Lattnerc6495ee2001-09-14 03:56:45 +000056
Chris Lattnerc6495ee2001-09-14 03:56:45 +000057 // End-of-array marker
58 INVALID_OPCODE,
Vikram S. Advec1521632001-10-22 13:31:53 +000059 NUM_REAL_OPCODES = PHI, // number of valid opcodes
Chris Lattnerc6495ee2001-09-14 03:56:45 +000060 NUM_TOTAL_OPCODES = INVALID_OPCODE
61};
62
Chris Lattnerc6495ee2001-09-14 03:56:45 +000063
Chris Lattner9a3d63b2001-09-19 15:56:23 +000064// Array of machine instruction descriptions...
65extern const MachineInstrDescriptor SparcMachineInstrDesc[];
Chris Lattnerc6495ee2001-09-14 03:56:45 +000066
67
68//---------------------------------------------------------------------------
69// class UltraSparcInstrInfo
70//
71// Purpose:
72// Information about individual instructions.
73// Most information is stored in the SparcMachineInstrDesc array above.
74// Other information is computed on demand, and most such functions
75// default to member functions in base class MachineInstrInfo.
76//---------------------------------------------------------------------------
77
Chris Lattner035dfbe2002-08-09 20:08:06 +000078struct UltraSparcInstrInfo : public MachineInstrInfo {
Chris Lattner047bbaf2002-10-29 15:45:20 +000079 UltraSparcInstrInfo();
Vikram S. Adve4c5fe2d2001-11-14 18:48:36 +000080
81 //
Vikram S. Advedd558992002-03-18 03:02:42 +000082 // All immediate constants are in position 1 except the
Vikram S. Advee1f72802002-09-16 15:39:26 +000083 // store instructions and SETxx.
Vikram S. Adve4c5fe2d2001-11-14 18:48:36 +000084 //
Vikram S. Advedd558992002-03-18 03:02:42 +000085 virtual int getImmedConstantPos(MachineOpCode opCode) const {
Vikram S. Adve4c5fe2d2001-11-14 18:48:36 +000086 bool ignore;
87 if (this->maxImmedConstant(opCode, ignore) != 0)
88 {
Vikram S. Advefe09fb22002-07-08 23:34:10 +000089 assert(! this->isStore((MachineOpCode) STB - 1)); // 1st store opcode
90 assert(! this->isStore((MachineOpCode) STXFSR+1));// last store opcode
Vikram S. Advee1f72802002-09-16 15:39:26 +000091 if (opCode==SETSW || opCode==SETUW || opCode==SETX || opCode==SETHI)
92 return 0;
93 if (opCode >= STB && opCode <= STXFSR)
94 return 2;
95 return 1;
Vikram S. Adve4c5fe2d2001-11-14 18:48:36 +000096 }
97 else
98 return -1;
99 }
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000100
Vikram S. Adve5684c4e2001-10-18 00:02:06 +0000101 virtual bool hasResultInterlock (MachineOpCode opCode) const
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000102 {
103 // All UltraSPARC instructions have interlocks (note that delay slots
104 // are not considered here).
105 // However, instructions that use the result of an FCMP produce a
106 // 9-cycle stall if they are issued less than 3 cycles after the FCMP.
107 // Force the compiler to insert a software interlock (i.e., gap of
108 // 2 other groups, including NOPs if necessary).
109 return (opCode == FCMPS || opCode == FCMPD || opCode == FCMPQ);
110 }
111
Vikram S. Adve5684c4e2001-10-18 00:02:06 +0000112 //-------------------------------------------------------------------------
Vikram S. Advee1f72802002-09-16 15:39:26 +0000113 // Queries about representation of LLVM quantities (e.g., constants)
114 //-------------------------------------------------------------------------
115
116 virtual bool ConstantMayNotFitInImmedField(const Constant* CV,
117 const Instruction* I) const;
118
119 //-------------------------------------------------------------------------
Vikram S. Adve5684c4e2001-10-18 00:02:06 +0000120 // Code generation support for creating individual machine instructions
121 //-------------------------------------------------------------------------
Vikram S. Adved55697c2002-09-20 00:52:09 +0000122
123 // Get certain common op codes for the current target. This and all the
124 // Create* methods below should be moved to a machine code generation class
125 //
126 virtual MachineOpCode getNOPOpCode() const { return NOP; }
127
Vikram S. Adve5684c4e2001-10-18 00:02:06 +0000128 // Create an instruction sequence to put the constant `val' into
Vikram S. Adve242a8082002-05-19 15:25:51 +0000129 // the virtual register `dest'. `val' may be a Constant or a
130 // GlobalValue, viz., the constant address of a global variable or function.
131 // The generated instructions are returned in `mvec'.
132 // Any temp. registers (TmpInstruction) created are recorded in mcfi.
133 // Any stack space required is allocated via mcff.
Vikram S. Adve5684c4e2001-10-18 00:02:06 +0000134 //
Vikram S. Adve242a8082002-05-19 15:25:51 +0000135 virtual void CreateCodeToLoadConst(const TargetMachine& target,
136 Function* F,
Vikram S. Advedd558992002-03-18 03:02:42 +0000137 Value* val,
Vikram S. Adve5684c4e2001-10-18 00:02:06 +0000138 Instruction* dest,
Vikram S. Adve242a8082002-05-19 15:25:51 +0000139 std::vector<MachineInstr*>& mvec,
140 MachineCodeForInstruction& mcfi) const;
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000141
Vikram S. Adve5afff3b2001-11-09 02:15:52 +0000142 // Create an instruction sequence to copy an integer value `val'
143 // to a floating point value `dest' by copying to memory and back.
144 // val must be an integral type. dest must be a Float or Double.
Vikram S. Adve242a8082002-05-19 15:25:51 +0000145 // The generated instructions are returned in `mvec'.
146 // Any temp. registers (TmpInstruction) created are recorded in mcfi.
147 // Any stack space required is allocated via mcff.
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000148 //
Vikram S. Adve242a8082002-05-19 15:25:51 +0000149 virtual void CreateCodeToCopyIntToFloat(const TargetMachine& target,
150 Function* F,
151 Value* val,
152 Instruction* dest,
153 std::vector<MachineInstr*>& mvec,
154 MachineCodeForInstruction& mcfi) const;
Vikram S. Adve5afff3b2001-11-09 02:15:52 +0000155
156 // Similarly, create an instruction sequence to copy an FP value
157 // `val' to an integer value `dest' by copying to memory and back.
Vikram S. Adve242a8082002-05-19 15:25:51 +0000158 // The generated instructions are returned in `mvec'.
159 // Any temp. registers (TmpInstruction) created are recorded in mcfi.
160 // Any stack space required is allocated via mcff.
Vikram S. Adve5afff3b2001-11-09 02:15:52 +0000161 //
Vikram S. Adve242a8082002-05-19 15:25:51 +0000162 virtual void CreateCodeToCopyFloatToInt(const TargetMachine& target,
163 Function* F,
164 Value* val,
165 Instruction* dest,
166 std::vector<MachineInstr*>& mvec,
167 MachineCodeForInstruction& mcfi) const;
168
169 // Create instruction(s) to copy src to dest, for arbitrary types
170 // The generated instructions are returned in `mvec'.
171 // Any temp. registers (TmpInstruction) created are recorded in mcfi.
172 // Any stack space required is allocated via mcff.
173 //
Vikram S. Advedd558992002-03-18 03:02:42 +0000174 virtual void CreateCopyInstructionsByType(const TargetMachine& target,
Vikram S. Adve242a8082002-05-19 15:25:51 +0000175 Function* F,
176 Value* src,
177 Instruction* dest,
178 std::vector<MachineInstr*>& mvec,
179 MachineCodeForInstruction& mcfi) const;
180
181 // Create instruction sequence to produce a sign-extended register value
182 // from an arbitrary sized value (sized in bits, not bytes).
Vikram S. Advef36f06b2002-09-05 18:34:31 +0000183 // The generated instructions are appended to `mvec'.
184 // Any temp. registers (TmpInstruction) created are recorded in mcfi.
Vikram S. Adve242a8082002-05-19 15:25:51 +0000185 // Any stack space required is allocated via mcff.
186 //
187 virtual void CreateSignExtensionInstructions(const TargetMachine& target,
188 Function* F,
Vikram S. Advef36f06b2002-09-05 18:34:31 +0000189 Value* srcVal,
Vikram S. Adve5cedede2002-09-27 14:29:45 +0000190 Value* destVal,
191 unsigned int numLowBits,
Vikram S. Advef36f06b2002-09-05 18:34:31 +0000192 std::vector<MachineInstr*>& mvec,
193 MachineCodeForInstruction& mcfi) const;
194
195 // Create instruction sequence to produce a zero-extended register value
196 // from an arbitrary sized value (sized in bits, not bytes).
197 // The generated instructions are appended to `mvec'.
198 // Any temp. registers (TmpInstruction) created are recorded in mcfi.
199 // Any stack space required is allocated via mcff.
200 //
201 virtual void CreateZeroExtensionInstructions(const TargetMachine& target,
202 Function* F,
203 Value* srcVal,
Vikram S. Adve5cedede2002-09-27 14:29:45 +0000204 Value* destVal,
205 unsigned int numLowBits,
Vikram S. Adve242a8082002-05-19 15:25:51 +0000206 std::vector<MachineInstr*>& mvec,
207 MachineCodeForInstruction& mcfi) const;
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000208};
209
Ruchira Sasankae38bd5332001-09-15 00:30:44 +0000210
Ruchira Sasanka20c82b12001-10-28 18:15:12 +0000211//----------------------------------------------------------------------------
212// class UltraSparcRegInfo
213//
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000214// This class implements the virtual class MachineRegInfo for Sparc.
215//
Ruchira Sasanka20c82b12001-10-28 18:15:12 +0000216//----------------------------------------------------------------------------
217
Chris Lattner699683c2002-02-04 05:59:25 +0000218class UltraSparcRegInfo : public MachineRegInfo {
Ruchira Sasankaab304c42001-09-30 23:19:57 +0000219 // The actual register classes in the Sparc
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000220 //
Ruchira Sasankae38bd5332001-09-15 00:30:44 +0000221 enum RegClassIDs {
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000222 IntRegClassID, // Integer
223 FloatRegClassID, // Float (both single/double)
224 IntCCRegClassID, // Int Condition Code
225 FloatCCRegClassID // Float Condition code
Ruchira Sasankae38bd5332001-09-15 00:30:44 +0000226 };
227
Ruchira Sasankaab304c42001-09-30 23:19:57 +0000228
229 // Type of registers available in Sparc. There can be several reg types
230 // in the same class. For instace, the float reg class has Single/Double
231 // types
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000232 //
Ruchira Sasankaab304c42001-09-30 23:19:57 +0000233 enum RegTypes {
234 IntRegType,
235 FPSingleRegType,
236 FPDoubleRegType,
237 IntCCRegType,
238 FloatCCRegType
239 };
240
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000241 // **** WARNING: If the above enum order is changed, also modify
Ruchira Sasankae38bd5332001-09-15 00:30:44 +0000242 // getRegisterClassOfValue method below since it assumes this particular
243 // order for efficiency.
244
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000245
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000246 // Number of registers used for passing int args (usually 6: %o0 - %o5)
247 //
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000248 unsigned const NumOfIntArgRegs;
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000249
250 // Number of registers used for passing float args (usually 32: %f0 - %f31)
251 //
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000252 unsigned const NumOfFloatArgRegs;
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000253
254 // An out of bound register number that can be used to initialize register
255 // numbers. Useful for error detection.
256 //
Ruchira Sasankac4d4b762001-10-16 01:23:19 +0000257 int const InvalidRegNum;
Ruchira Sasanka20c82b12001-10-28 18:15:12 +0000258
259
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000260 // ======================== Private Methods =============================
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000261
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000262 // The following methods are used to color special live ranges (e.g.
Chris Lattnerf57b8452002-04-27 06:56:12 +0000263 // function args and return values etc.) with specific hardware registers
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000264 // as required. See SparcRegInfo.cpp for the implementation.
265 //
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000266 void suggestReg4RetAddr(MachineInstr *RetMI,
Chris Lattner699683c2002-02-04 05:59:25 +0000267 LiveRangeInfo &LRI) const;
Ruchira Sasankacc3ccac2001-10-15 16:25:28 +0000268
Vikram S. Adve106604e2002-09-28 16:56:59 +0000269 void suggestReg4CallAddr(MachineInstr *CallMI, LiveRangeInfo &LRI) const;
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000270
271 void InitializeOutgoingArg(MachineInstr* CallMI, AddedInstrns *CallAI,
Vikram S. Adve242a8082002-05-19 15:25:51 +0000272 PhyRegAlloc &PRA, LiveRange* LR,
273 unsigned regType, unsigned RegClassID,
274 int UniArgReg, unsigned int argNo,
275 std::vector<MachineInstr *>& AddedInstrnsBefore)
276 const;
277
278 // The following 4 methods are used to find the RegType (see enum above)
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000279 // for a reg class and a given primitive type, a LiveRange, a Value,
280 // or a particular machine register.
281 // The fifth function gives the reg class of the given RegType.
282 //
Vikram S. Adve242a8082002-05-19 15:25:51 +0000283 int getRegType(unsigned regClassID, const Type* type) const;
Chris Lattner699683c2002-02-04 05:59:25 +0000284 int getRegType(const LiveRange *LR) const;
285 int getRegType(const Value *Val) const;
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000286 int getRegType(int unifiedRegNum) const;
Ruchira Sasanka3839e6e2001-11-03 19:59:59 +0000287
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000288 // Used to generate a copy instruction based on the register class of
289 // value.
290 //
Chris Lattner699683c2002-02-04 05:59:25 +0000291 MachineInstr *cpValue2RegMI(Value *Val, unsigned DestReg,
292 int RegType) const;
Ruchira Sasankaae4bcd72001-11-10 21:20:43 +0000293
294
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000295 // The following 2 methods are used to order the instructions addeed by
Chris Lattnerf57b8452002-04-27 06:56:12 +0000296 // the register allocator in association with function calling. See
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000297 // SparcRegInfo.cpp for more details
298 //
Chris Lattner697954c2002-01-20 22:54:45 +0000299 void moveInst2OrdVec(std::vector<MachineInstr *> &OrdVec,
300 MachineInstr *UnordInst,
301 PhyRegAlloc &PRA) const;
Ruchira Sasankaae4bcd72001-11-10 21:20:43 +0000302
Chris Lattner697954c2002-01-20 22:54:45 +0000303 void OrderAddedInstrns(std::vector<MachineInstr *> &UnordVec,
304 std::vector<MachineInstr *> &OrdVec,
305 PhyRegAlloc &PRA) const;
Ruchira Sasankaae4bcd72001-11-10 21:20:43 +0000306
307
Vikram S. Adve6d783112002-04-25 04:40:24 +0000308 // Compute which register can be used for an argument, if any
309 //
310 int regNumForIntArg(bool inCallee, bool isVarArgsCall,
311 unsigned argNo, unsigned intArgNo, unsigned fpArgNo,
312 unsigned& regClassId) const;
Ruchira Sasankaae4bcd72001-11-10 21:20:43 +0000313
Vikram S. Adve6d783112002-04-25 04:40:24 +0000314 int regNumForFPArg(unsigned RegType, bool inCallee, bool isVarArgsCall,
315 unsigned argNo, unsigned intArgNo, unsigned fpArgNo,
316 unsigned& regClassId) const;
317
Chris Lattner699683c2002-02-04 05:59:25 +0000318public:
319 UltraSparcRegInfo(const UltraSparc &tgt);
Ruchira Sasankae38bd5332001-09-15 00:30:44 +0000320
Vikram S. Advedd558992002-03-18 03:02:42 +0000321 // To find the register class used for a specified Type
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000322 //
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000323 unsigned getRegClassIDOfType(const Type *type,
324 bool isCCReg = false) const;
Ruchira Sasankae38bd5332001-09-15 00:30:44 +0000325
Vikram S. Advedd558992002-03-18 03:02:42 +0000326 // To find the register class of a Value
327 //
328 inline unsigned getRegClassIDOfValue(const Value *Val,
329 bool isCCReg = false) const {
330 return getRegClassIDOfType(Val->getType(), isCCReg);
331 }
332
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000333 // To find the register class to which a specified register belongs
334 //
335 unsigned getRegClassIDOfReg(int unifiedRegNum) const;
336 unsigned getRegClassIDOfRegType(int regType) const;
Vikram S. Advedd558992002-03-18 03:02:42 +0000337
Chris Lattner699683c2002-02-04 05:59:25 +0000338 // getZeroRegNum - returns the register that contains always zero this is the
339 // unified register number
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000340 //
Chris Lattner699683c2002-02-04 05:59:25 +0000341 virtual int getZeroRegNum() const;
Ruchira Sasanka89fb46b2001-09-18 22:52:44 +0000342
Chris Lattner699683c2002-02-04 05:59:25 +0000343 // getCallAddressReg - returns the reg used for pushing the address when a
Chris Lattnerf57b8452002-04-27 06:56:12 +0000344 // function is called. This can be used for other purposes between calls
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000345 //
Chris Lattner699683c2002-02-04 05:59:25 +0000346 unsigned getCallAddressReg() const;
Ruchira Sasanka89fb46b2001-09-18 22:52:44 +0000347
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000348 // Returns the register containing the return address.
349 // It should be made sure that this register contains the return
350 // value when a return instruction is reached.
351 //
Chris Lattner699683c2002-02-04 05:59:25 +0000352 unsigned getReturnAddressReg() const;
Ruchira Sasanka89fb46b2001-09-18 22:52:44 +0000353
Vikram S. Adve242a8082002-05-19 15:25:51 +0000354 // Number of registers used for passing int args (usually 6: %o0 - %o5)
355 // and float args (usually 32: %f0 - %f31)
356 //
357 unsigned const GetNumOfIntArgRegs() const { return NumOfIntArgRegs; }
358 unsigned const GetNumOfFloatArgRegs() const { return NumOfFloatArgRegs; }
359
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000360 // The following methods are used to color special live ranges (e.g.
Chris Lattnerf57b8452002-04-27 06:56:12 +0000361 // function args and return values etc.) with specific hardware registers
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000362 // as required. See SparcRegInfo.cpp for the implementation for Sparc.
363 //
Chris Lattnerb7653df2002-04-08 22:03:57 +0000364 void suggestRegs4MethodArgs(const Function *Meth,
Ruchira Sasankaab304c42001-09-30 23:19:57 +0000365 LiveRangeInfo& LRI) const;
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000366
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000367 void suggestRegs4CallArgs(MachineInstr *CallMI,
Vikram S. Adve106604e2002-09-28 16:56:59 +0000368 LiveRangeInfo& LRI) const;
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000369
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000370 void suggestReg4RetValue(MachineInstr *RetMI,
Chris Lattner697954c2002-01-20 22:54:45 +0000371 LiveRangeInfo& LRI) const;
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000372
Chris Lattnerb7653df2002-04-08 22:03:57 +0000373 void colorMethodArgs(const Function *Meth, LiveRangeInfo &LRI,
Chris Lattner699683c2002-02-04 05:59:25 +0000374 AddedInstrns *FirstAI) const;
Ruchira Sasankaab304c42001-09-30 23:19:57 +0000375
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000376 void colorCallArgs(MachineInstr *CallMI, LiveRangeInfo &LRI,
Chris Lattner699683c2002-02-04 05:59:25 +0000377 AddedInstrns *CallAI, PhyRegAlloc &PRA,
Ruchira Sasankad00982a2002-01-07 19:20:28 +0000378 const BasicBlock *BB) const;
Ruchira Sasankaab304c42001-09-30 23:19:57 +0000379
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000380 void colorRetValue(MachineInstr *RetI, LiveRangeInfo& LRI,
Chris Lattner699683c2002-02-04 05:59:25 +0000381 AddedInstrns *RetAI) const;
Ruchira Sasankaab304c42001-09-30 23:19:57 +0000382
383
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000384 // method used for printing a register for debugging purposes
385 //
Chris Lattner699683c2002-02-04 05:59:25 +0000386 static void printReg(const LiveRange *LR);
Ruchira Sasanka89fb46b2001-09-18 22:52:44 +0000387
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000388 // Each register class has a seperate space for register IDs. To convert
389 // a regId in a register class to a common Id, or vice versa,
390 // we use the folloing methods.
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000391 //
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000392 // This method provides a unique number for each register
393 inline int getUnifiedRegNum(unsigned regClassID, int reg) const {
394
395 if (regClassID == IntRegClassID) {
396 assert(reg < 32 && "Invalid reg. number");
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000397 return reg;
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000398 }
399 else if (regClassID == FloatRegClassID) {
400 assert(reg < 64 && "Invalid reg. number");
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000401 return reg + 32; // we have 32 int regs
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000402 }
403 else if (regClassID == FloatCCRegClassID) {
404 assert(reg < 4 && "Invalid reg. number");
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000405 return reg + 32 + 64; // 32 int, 64 float
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000406 }
407 else if (regClassID == IntCCRegClassID ) {
408 assert(reg == 0 && "Invalid reg. number");
409 return reg + 4+ 32 + 64; // only one int CC reg
410 }
411 else if (reg==InvalidRegNum) {
Ruchira Sasankac4d4b762001-10-16 01:23:19 +0000412 return InvalidRegNum;
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000413 }
Ruchira Sasankae38bd5332001-09-15 00:30:44 +0000414 else
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000415 assert(0 && "Invalid register class");
Chris Lattner6dad5062001-11-07 13:49:12 +0000416 return 0;
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000417 }
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000418
419 // This method converts the unified number to the number in its class,
420 // and returns the class ID in regClassID.
421 inline int getClassRegNum(int ureg, unsigned& regClassID) const {
422 if (ureg < 32) { regClassID = IntRegClassID; return ureg; }
423 else if (ureg < 32+64) { regClassID = FloatRegClassID; return ureg-32; }
424 else if (ureg < 4 +96) { regClassID = FloatCCRegClassID; return ureg-96; }
425 else if (ureg < 1 +100) { regClassID = IntCCRegClassID; return ureg-100;}
426 else if (ureg == InvalidRegNum) { return InvalidRegNum; }
427 else { assert(0 && "Invalid unified register number"); }
Chris Lattnerb82d97e2002-07-25 06:08:32 +0000428 return 0;
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000429 }
430
431 // Returns the assembly-language name of the specified machine register.
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000432 //
Chris Lattner95685682002-08-12 21:25:05 +0000433 virtual const char * const getUnifiedRegName(int reg) const;
Ruchira Sasankad00982a2002-01-07 19:20:28 +0000434
435
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000436 // returns the # of bytes of stack space allocated for each register
437 // type. For Sparc, currently we allocate 8 bytes on stack for all
438 // register types. We can optimize this later if necessary to save stack
439 // space (However, should make sure that stack alignment is correct)
440 //
Chris Lattner699683c2002-02-04 05:59:25 +0000441 inline int getSpilledRegSize(int RegType) const {
Ruchira Sasankad00982a2002-01-07 19:20:28 +0000442 return 8;
Ruchira Sasankad00982a2002-01-07 19:20:28 +0000443 }
444
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000445
Vikram S. Advea44c6c02002-03-31 19:04:50 +0000446 // To obtain the return value and the indirect call address (if any)
447 // contained in a CALL machine instruction
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000448 //
Ruchira Sasankab3b6f532001-10-21 16:43:41 +0000449 const Value * getCallInstRetVal(const MachineInstr *CallMI) const;
Vikram S. Advea44c6c02002-03-31 19:04:50 +0000450 const Value * getCallInstIndirectAddrVal(const MachineInstr *CallMI) const;
Ruchira Sasankab3b6f532001-10-21 16:43:41 +0000451
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000452 // The following methods are used to generate "copy" machine instructions
453 // for an architecture.
454 //
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000455 // The function regTypeNeedsScratchReg() can be used to check whether a
456 // scratch register is needed to copy a register of type `regType' to
457 // or from memory. If so, such a scratch register can be provided by
458 // the caller (e.g., if it knows which regsiters are free); otherwise
459 // an arbitrary one will be chosen and spilled by the copy instructions.
460 //
461 bool regTypeNeedsScratchReg(int RegType,
462 int& scratchRegClassId) const;
Ruchira Sasankac4d4b762001-10-16 01:23:19 +0000463
Vikram S. Advefe09fb22002-07-08 23:34:10 +0000464 void cpReg2RegMI(std::vector<MachineInstr*>& mvec,
465 unsigned SrcReg, unsigned DestReg,
466 int RegType) const;
467
468 void cpReg2MemMI(std::vector<MachineInstr*>& mvec,
469 unsigned SrcReg, unsigned DestPtrReg,
470 int Offset, int RegType, int scratchReg = -1) const;
471
472 void cpMem2RegMI(std::vector<MachineInstr*>& mvec,
473 unsigned SrcPtrReg, int Offset, unsigned DestReg,
474 int RegType, int scratchReg = -1) const;
Ruchira Sasankac4d4b762001-10-16 01:23:19 +0000475
Vikram S. Adve242a8082002-05-19 15:25:51 +0000476 void cpValue2Value(Value *Src, Value *Dest,
Anand Shuklacfb22d32002-06-25 20:55:50 +0000477 std::vector<MachineInstr*>& mvec) const;
Ruchira Sasankaef1b0cb2001-11-03 17:13:27 +0000478
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000479 // To see whether a register is a volatile (i.e., whehter it must be
480 // preserved acorss calls)
481 //
Chris Lattner699683c2002-02-04 05:59:25 +0000482 inline bool isRegVolatile(int RegClassID, int Reg) const {
483 return MachineRegClassArr[RegClassID]->isRegVolatile(Reg);
Ruchira Sasankac4d4b762001-10-16 01:23:19 +0000484 }
485
486
Chris Lattner699683c2002-02-04 05:59:25 +0000487 virtual unsigned getFramePointer() const;
488 virtual unsigned getStackPointer() const;
Ruchira Sasankac4d4b762001-10-16 01:23:19 +0000489
Chris Lattner699683c2002-02-04 05:59:25 +0000490 virtual int getInvalidRegNum() const {
Ruchira Sasankac4d4b762001-10-16 01:23:19 +0000491 return InvalidRegNum;
492 }
493
Ruchira Sasanka2563a982002-01-07 20:28:49 +0000494 // This method inserts the caller saving code for call instructions
495 //
Anand Shukla24787fa2002-07-11 00:16:28 +0000496 void insertCallerSavingCode(std::vector<MachineInstr*>& instrnsBefore,
497 std::vector<MachineInstr*>& instrnsAfter,
Vikram S. Adve6a49a1e2002-07-10 21:42:42 +0000498 MachineInstr *MInst,
Ruchira Sasanka20c82b12001-10-28 18:15:12 +0000499 const BasicBlock *BB, PhyRegAlloc &PRA ) const;
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000500};
501
502
503
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000504
505//---------------------------------------------------------------------------
506// class UltraSparcSchedInfo
507//
508// Purpose:
509// Interface to instruction scheduling information for UltraSPARC.
510// The parameter values above are based on UltraSPARC IIi.
511//---------------------------------------------------------------------------
512
513
514class UltraSparcSchedInfo: public MachineSchedInfo {
515public:
Chris Lattner699683c2002-02-04 05:59:25 +0000516 UltraSparcSchedInfo(const TargetMachine &tgt);
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000517protected:
Chris Lattner699683c2002-02-04 05:59:25 +0000518 virtual void initializeResources();
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000519};
520
Chris Lattnerf6e0e282001-09-14 04:32:55 +0000521
522//---------------------------------------------------------------------------
Vikram S. Advec1521632001-10-22 13:31:53 +0000523// class UltraSparcFrameInfo
524//
525// Purpose:
526// Interface to stack frame layout info for the UltraSPARC.
Vikram S. Adve00521d72001-11-12 23:26:35 +0000527// Starting offsets for each area of the stack frame are aligned at
528// a multiple of getStackFrameSizeAlignment().
Vikram S. Advec1521632001-10-22 13:31:53 +0000529//---------------------------------------------------------------------------
530
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000531class UltraSparcFrameInfo: public MachineFrameInfo {
Vikram S. Advec1521632001-10-22 13:31:53 +0000532public:
Chris Lattner699683c2002-02-04 05:59:25 +0000533 UltraSparcFrameInfo(const TargetMachine &tgt) : MachineFrameInfo(tgt) {}
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000534
535public:
Vikram S. Advee1f72802002-09-16 15:39:26 +0000536 // These methods provide constant parameters of the frame layout.
537 //
Chris Lattnerf57b8452002-04-27 06:56:12 +0000538 int getStackFrameSizeAlignment() const { return StackFrameSizeAlignment;}
539 int getMinStackFrameSize() const { return MinStackFrameSize; }
540 int getNumFixedOutgoingArgs() const { return NumFixedOutgoingArgs; }
541 int getSizeOfEachArgOnStack() const { return SizeOfEachArgOnStack; }
542 bool argsOnStackHaveFixedSize() const { return true; }
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000543
Vikram S. Advee1f72802002-09-16 15:39:26 +0000544 // This method adjusts a stack offset to meet alignment rules of target.
545 // The fixed OFFSET (0x7ff) must be subtracted and the result aligned.
546 virtual int adjustAlignment (int unalignedOffset,
547 bool growUp,
548 unsigned int align) const {
549 return unalignedOffset + (growUp? +1:-1)*((unalignedOffset-OFFSET) % align);
550 }
551
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000552 // These methods compute offsets using the frame contents for a
Chris Lattnerf57b8452002-04-27 06:56:12 +0000553 // particular function. The frame contents are obtained from the
554 // MachineCodeInfoForMethod object for the given function.
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000555 //
Misha Brukmanfce11432002-10-28 00:28:31 +0000556 int getFirstIncomingArgOffset (MachineFunction& mcInfo,
Vikram S. Adve6d783112002-04-25 04:40:24 +0000557 bool& growUp) const
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000558 {
Vikram S. Adve6d783112002-04-25 04:40:24 +0000559 growUp = true; // arguments area grows upwards
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000560 return FirstIncomingArgOffsetFromFP;
561 }
Misha Brukmanfce11432002-10-28 00:28:31 +0000562 int getFirstOutgoingArgOffset (MachineFunction& mcInfo,
Vikram S. Adve6d783112002-04-25 04:40:24 +0000563 bool& growUp) const
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000564 {
Vikram S. Adve6d783112002-04-25 04:40:24 +0000565 growUp = true; // arguments area grows upwards
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000566 return FirstOutgoingArgOffsetFromSP;
567 }
Misha Brukmanfce11432002-10-28 00:28:31 +0000568 int getFirstOptionalOutgoingArgOffset(MachineFunction& mcInfo,
Vikram S. Adve6d783112002-04-25 04:40:24 +0000569 bool& growUp)const
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000570 {
Vikram S. Adve6d783112002-04-25 04:40:24 +0000571 growUp = true; // arguments area grows upwards
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000572 return FirstOptionalOutgoingArgOffsetFromSP;
573 }
574
Misha Brukmanfce11432002-10-28 00:28:31 +0000575 int getFirstAutomaticVarOffset (MachineFunction& mcInfo,
Vikram S. Adve6d783112002-04-25 04:40:24 +0000576 bool& growUp) const;
Misha Brukmanfce11432002-10-28 00:28:31 +0000577 int getRegSpillAreaOffset (MachineFunction& mcInfo,
Vikram S. Adve6d783112002-04-25 04:40:24 +0000578 bool& growUp) const;
Misha Brukmanfce11432002-10-28 00:28:31 +0000579 int getTmpAreaOffset (MachineFunction& mcInfo,
Vikram S. Adve6d783112002-04-25 04:40:24 +0000580 bool& growUp) const;
Misha Brukmanfce11432002-10-28 00:28:31 +0000581 int getDynamicAreaOffset (MachineFunction& mcInfo,
Vikram S. Adve6d783112002-04-25 04:40:24 +0000582 bool& growUp) const;
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000583
584 //
585 // These methods specify the base register used for each stack area
586 // (generally FP or SP)
587 //
588 virtual int getIncomingArgBaseRegNum() const {
589 return (int) target.getRegInfo().getFramePointer();
590 }
591 virtual int getOutgoingArgBaseRegNum() const {
592 return (int) target.getRegInfo().getStackPointer();
593 }
594 virtual int getOptionalOutgoingArgBaseRegNum() const {
595 return (int) target.getRegInfo().getStackPointer();
596 }
597 virtual int getAutomaticVarBaseRegNum() const {
598 return (int) target.getRegInfo().getFramePointer();
599 }
600 virtual int getRegSpillAreaBaseRegNum() const {
601 return (int) target.getRegInfo().getFramePointer();
602 }
603 virtual int getDynamicAreaBaseRegNum() const {
604 return (int) target.getRegInfo().getStackPointer();
605 }
606
607private:
Vikram S. Advee1f72802002-09-16 15:39:26 +0000608 /*----------------------------------------------------------------------
609 This diagram shows the stack frame layout used by llc on Sparc V9.
610 Note that only the location of automatic variables, spill area,
611 temporary storage, and dynamically allocated stack area are chosen
612 by us. The rest conform to the Sparc V9 ABI.
613 All stack addresses are offset by OFFSET = 0x7ff (2047).
614
615 Alignment assumpteions and other invariants:
616 (1) %sp+OFFSET and %fp+OFFSET are always aligned on 16-byte boundary
617 (2) Variables in automatic, spill, temporary, or dynamic regions
618 are aligned according to their size as in all memory accesses.
619 (3) Everything below the dynamically allocated stack area is only used
620 during a call to another function, so it is never needed when
621 the current function is active. This is why space can be allocated
622 dynamically by incrementing %sp any time within the function.
623
624 STACK FRAME LAYOUT:
625
626 ...
627 %fp+OFFSET+176 Optional extra incoming arguments# 1..N
628 %fp+OFFSET+168 Incoming argument #6
629 ... ...
630 %fp+OFFSET+128 Incoming argument #1
631 ... ...
632 ---%fp+OFFSET-0--------Bottom of caller's stack frame--------------------
633 %fp+OFFSET-8 Automatic variables <-- ****TOP OF STACK FRAME****
634 Spill area
635 Temporary storage
636 ...
637
638 %sp+OFFSET+176+8N Bottom of dynamically allocated stack area
639 %sp+OFFSET+168+8N Optional extra outgoing argument# N
640 ... ...
641 %sp+OFFSET+176 Optional extra outgoing argument# 1
642 %sp+OFFSET+168 Outgoing argument #6
643 ... ...
644 %sp+OFFSET+128 Outgoing argument #1
645 %sp+OFFSET+120 Save area for %i7
646 ... ...
647 %sp+OFFSET+0 Save area for %l0 <-- ****BOTTOM OF STACK FRAME****
648
649 *----------------------------------------------------------------------*/
650
Vikram S. Adve5afff3b2001-11-09 02:15:52 +0000651 // All stack addresses must be offset by 0x7ff (2047) on Sparc V9.
652 static const int OFFSET = (int) 0x7ff;
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000653 static const int StackFrameSizeAlignment = 16;
Vikram S. Advec1521632001-10-22 13:31:53 +0000654 static const int MinStackFrameSize = 176;
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000655 static const int NumFixedOutgoingArgs = 6;
656 static const int SizeOfEachArgOnStack = 8;
Vikram S. Adve5afff3b2001-11-09 02:15:52 +0000657 static const int FirstIncomingArgOffsetFromFP = 128 + OFFSET;
658 static const int FirstOptionalIncomingArgOffsetFromFP = 176 + OFFSET;
Vikram S. Advee1f72802002-09-16 15:39:26 +0000659 static const int StaticAreaOffsetFromFP = 0 + OFFSET;
Vikram S. Adve5afff3b2001-11-09 02:15:52 +0000660 static const int FirstOutgoingArgOffsetFromSP = 128 + OFFSET;
661 static const int FirstOptionalOutgoingArgOffsetFromSP = 176 + OFFSET;
Vikram S. Advec1521632001-10-22 13:31:53 +0000662};
663
664
Vikram S. Adve5afff3b2001-11-09 02:15:52 +0000665//---------------------------------------------------------------------------
666// class UltraSparcCacheInfo
667//
668// Purpose:
669// Interface to cache parameters for the UltraSPARC.
670// Just use defaults for now.
671//---------------------------------------------------------------------------
672
673class UltraSparcCacheInfo: public MachineCacheInfo {
674public:
Chris Lattner7327d7e2002-02-04 00:04:35 +0000675 UltraSparcCacheInfo(const TargetMachine &T) : MachineCacheInfo(T) {}
Vikram S. Adve5afff3b2001-11-09 02:15:52 +0000676};
677
Vikram S. Advec1521632001-10-22 13:31:53 +0000678
679//---------------------------------------------------------------------------
Vikram S. Adved55697c2002-09-20 00:52:09 +0000680// class UltraSparcOptInfo
681//
682// Purpose:
683// Interface to machine-level optimization routines for the UltraSPARC.
684//---------------------------------------------------------------------------
685
686class UltraSparcOptInfo: public MachineOptInfo {
687public:
688 UltraSparcOptInfo(const TargetMachine &T) : MachineOptInfo(T) {}
689
690 virtual bool IsUselessCopy (const MachineInstr* MI) const;
691};
692
693
694//---------------------------------------------------------------------------
Chris Lattnerf6e0e282001-09-14 04:32:55 +0000695// class UltraSparcMachine
696//
697// Purpose:
698// Primary interface to machine description for the UltraSPARC.
699// Primarily just initializes machine-dependent parameters in
700// class TargetMachine, and creates machine-dependent subclasses
Vikram S. Adve339084b2001-09-18 13:04:24 +0000701// for classes such as InstrInfo, SchedInfo and RegInfo.
Chris Lattnerf6e0e282001-09-14 04:32:55 +0000702//---------------------------------------------------------------------------
703
704class UltraSparc : public TargetMachine {
Vikram S. Adve339084b2001-09-18 13:04:24 +0000705 UltraSparcInstrInfo instrInfo;
706 UltraSparcSchedInfo schedInfo;
707 UltraSparcRegInfo regInfo;
Vikram S. Advec1521632001-10-22 13:31:53 +0000708 UltraSparcFrameInfo frameInfo;
Vikram S. Adve5afff3b2001-11-09 02:15:52 +0000709 UltraSparcCacheInfo cacheInfo;
Vikram S. Adved55697c2002-09-20 00:52:09 +0000710 UltraSparcOptInfo optInfo;
Chris Lattnerf6e0e282001-09-14 04:32:55 +0000711public:
712 UltraSparc();
Vikram S. Adved55697c2002-09-20 00:52:09 +0000713
Chris Lattner32f600a2001-09-19 13:47:12 +0000714 virtual const MachineInstrInfo &getInstrInfo() const { return instrInfo; }
715 virtual const MachineSchedInfo &getSchedInfo() const { return schedInfo; }
716 virtual const MachineRegInfo &getRegInfo() const { return regInfo; }
Vikram S. Adve7f37fe52001-11-08 04:55:13 +0000717 virtual const MachineFrameInfo &getFrameInfo() const { return frameInfo; }
Vikram S. Adve5afff3b2001-11-09 02:15:52 +0000718 virtual const MachineCacheInfo &getCacheInfo() const { return cacheInfo; }
Vikram S. Adved55697c2002-09-20 00:52:09 +0000719 virtual const MachineOptInfo &getOptInfo() const { return optInfo; }
Chris Lattner32f600a2001-09-19 13:47:12 +0000720
Chris Lattner4f946372002-10-28 01:03:43 +0000721 virtual void addPassesToEmitAssembly(PassManager &PM, std::ostream &Out);
722
Vikram S. Advee1f72802002-09-16 15:39:26 +0000723 // getPrologEpilogCodeInserter - Inserts prolog/epilog code.
724 virtual Pass* getPrologEpilogInsertionPass();
Chris Lattnerf6e0e282001-09-14 04:32:55 +0000725
Vikram S. Advee1f72802002-09-16 15:39:26 +0000726 // getFunctionAsmPrinterPass - Writes out machine code for a single function
727 virtual Pass* getFunctionAsmPrinterPass(std::ostream &Out);
728
729 // getModuleAsmPrinterPass - Writes generated machine code to assembly file.
730 virtual Pass* getModuleAsmPrinterPass(std::ostream &Out);
731
732 // getEmitBytecodeToAsmPass - Emits final LLVM bytecode to assembly file.
733 virtual Pass* getEmitBytecodeToAsmPass(std::ostream &Out);
Chris Lattner6edfcc52002-02-03 07:51:17 +0000734};
Chris Lattnerf6e0e282001-09-14 04:32:55 +0000735
Chris Lattnerc6495ee2001-09-14 03:56:45 +0000736#endif