LLVM API Documentation

X86CodeEmitter.cpp

Go to the documentation of this file.
00001 //===-- X86/X86CodeEmitter.cpp - Convert X86 code to machine code ---------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file was developed by the LLVM research group and is distributed under
00006 // the University of Illinois Open Source License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file contains the pass that transforms the X86 machine instructions into
00011 // relocatable machine code.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "X86TargetMachine.h"
00016 #include "X86Relocations.h"
00017 #include "X86.h"
00018 #include "llvm/PassManager.h"
00019 #include "llvm/CodeGen/MachineCodeEmitter.h"
00020 #include "llvm/CodeGen/MachineFunctionPass.h"
00021 #include "llvm/CodeGen/MachineInstr.h"
00022 #include "llvm/CodeGen/Passes.h"
00023 #include "llvm/Function.h"
00024 #include "llvm/ADT/Statistic.h"
00025 #include "llvm/Support/Visibility.h"
00026 #include "llvm/Target/TargetOptions.h"
00027 #include <iostream>
00028 using namespace llvm;
00029 
00030 namespace {
00031   Statistic<>
00032   NumEmitted("x86-emitter", "Number of machine instructions emitted");
00033 }
00034 
00035 namespace {
00036   class VISIBILITY_HIDDEN Emitter : public MachineFunctionPass {
00037     const X86InstrInfo  *II;
00038     TargetMachine &TM;
00039     MachineCodeEmitter  &MCE;
00040   public:
00041     explicit Emitter(TargetMachine &tm, MachineCodeEmitter &mce)
00042       : II(0), TM(tm), MCE(mce) {}
00043     Emitter(TargetMachine &tm, MachineCodeEmitter &mce,
00044             const X86InstrInfo& ii)
00045       : II(&ii), TM(tm), MCE(mce) {}
00046 
00047     bool runOnMachineFunction(MachineFunction &MF);
00048 
00049     virtual const char *getPassName() const {
00050       return "X86 Machine Code Emitter";
00051     }
00052 
00053     void emitInstruction(const MachineInstr &MI);
00054 
00055   private:
00056     void emitPCRelativeBlockAddress(MachineBasicBlock *MBB);
00057     void emitPCRelativeValue(unsigned Address);
00058     void emitGlobalAddressForCall(GlobalValue *GV, bool isTailCall);
00059     void emitGlobalAddressForPtr(GlobalValue *GV, int Disp = 0);
00060     void emitExternalSymbolAddress(const char *ES, bool isPCRelative);
00061 
00062     void emitDisplacementField(const MachineOperand *RelocOp, int DispVal);
00063 
00064     void emitRegModRMByte(unsigned ModRMReg, unsigned RegOpcodeField);
00065     void emitSIBByte(unsigned SS, unsigned Index, unsigned Base);
00066     void emitConstant(unsigned Val, unsigned Size);
00067 
00068     void emitMemModRMByte(const MachineInstr &MI,
00069                           unsigned Op, unsigned RegOpcodeField);
00070 
00071   };
00072 }
00073 
00074 /// createX86CodeEmitterPass - Return a pass that emits the collected X86 code
00075 /// to the specified MCE object.
00076 FunctionPass *llvm::createX86CodeEmitterPass(X86TargetMachine &TM,
00077                                              MachineCodeEmitter &MCE) {
00078   return new Emitter(TM, MCE);
00079 }
00080 
00081 bool Emitter::runOnMachineFunction(MachineFunction &MF) {
00082   assert((MF.getTarget().getRelocationModel() != Reloc::Default ||
00083           MF.getTarget().getRelocationModel() != Reloc::Static) &&
00084          "JIT relocation model must be set to static or default!");
00085   II = ((X86TargetMachine&)MF.getTarget()).getInstrInfo();
00086 
00087   do {
00088     MCE.startFunction(MF);
00089     for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); 
00090          MBB != E; ++MBB) {
00091       MCE.StartMachineBasicBlock(MBB);
00092       for (MachineBasicBlock::const_iterator I = MBB->begin(), E = MBB->end();
00093            I != E; ++I)
00094         emitInstruction(*I);
00095     }
00096   } while (MCE.finishFunction(MF));
00097 
00098   return false;
00099 }
00100 
00101 /// emitPCRelativeValue - Emit a 32-bit PC relative address.
00102 ///
00103 void Emitter::emitPCRelativeValue(unsigned Address) {
00104   MCE.emitWordLE(Address-MCE.getCurrentPCValue()-4);
00105 }
00106 
00107 /// emitPCRelativeBlockAddress - This method keeps track of the information
00108 /// necessary to resolve the address of this block later and emits a dummy
00109 /// value.
00110 ///
00111 void Emitter::emitPCRelativeBlockAddress(MachineBasicBlock *MBB) {
00112   // Remember where this reference was and where it is to so we can
00113   // deal with it later.
00114   TM.getJITInfo()->addBBRef(MBB, MCE.getCurrentPCValue());
00115   MCE.emitWordLE(0);
00116 }
00117 
00118 /// emitGlobalAddressForCall - Emit the specified address to the code stream
00119 /// assuming this is part of a function call, which is PC relative.
00120 ///
00121 void Emitter::emitGlobalAddressForCall(GlobalValue *GV, bool isTailCall) {
00122   MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(),
00123                                       X86::reloc_pcrel_word, GV, 0,
00124                                       !isTailCall /*Doesn'tNeedStub*/));
00125   MCE.emitWordLE(0);
00126 }
00127 
00128 /// emitGlobalAddress - Emit the specified address to the code stream assuming
00129 /// this is part of a "take the address of a global" instruction, which is not
00130 /// PC relative.
00131 ///
00132 void Emitter::emitGlobalAddressForPtr(GlobalValue *GV, int Disp /* = 0 */) {
00133   MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(),
00134                                       X86::reloc_absolute_word, GV));
00135   MCE.emitWordLE(Disp); // The relocated value will be added to the displacement
00136 }
00137 
00138 /// emitExternalSymbolAddress - Arrange for the address of an external symbol to
00139 /// be emitted to the current location in the function, and allow it to be PC
00140 /// relative.
00141 void Emitter::emitExternalSymbolAddress(const char *ES, bool isPCRelative) {
00142   MCE.addRelocation(MachineRelocation::getExtSym(MCE.getCurrentPCOffset(),
00143           isPCRelative ? X86::reloc_pcrel_word : X86::reloc_absolute_word, ES));
00144   MCE.emitWordLE(0);
00145 }
00146 
00147 /// N86 namespace - Native X86 Register numbers... used by X86 backend.
00148 ///
00149 namespace N86 {
00150   enum {
00151     EAX = 0, ECX = 1, EDX = 2, EBX = 3, ESP = 4, EBP = 5, ESI = 6, EDI = 7
00152   };
00153 }
00154 
00155 
00156 // getX86RegNum - This function maps LLVM register identifiers to their X86
00157 // specific numbering, which is used in various places encoding instructions.
00158 //
00159 static unsigned getX86RegNum(unsigned RegNo) {
00160   switch(RegNo) {
00161   case X86::EAX: case X86::AX: case X86::AL: return N86::EAX;
00162   case X86::ECX: case X86::CX: case X86::CL: return N86::ECX;
00163   case X86::EDX: case X86::DX: case X86::DL: return N86::EDX;
00164   case X86::EBX: case X86::BX: case X86::BL: return N86::EBX;
00165   case X86::ESP: case X86::SP: case X86::AH: return N86::ESP;
00166   case X86::EBP: case X86::BP: case X86::CH: return N86::EBP;
00167   case X86::ESI: case X86::SI: case X86::DH: return N86::ESI;
00168   case X86::EDI: case X86::DI: case X86::BH: return N86::EDI;
00169 
00170   case X86::ST0: case X86::ST1: case X86::ST2: case X86::ST3:
00171   case X86::ST4: case X86::ST5: case X86::ST6: case X86::ST7:
00172     return RegNo-X86::ST0;
00173 
00174   case X86::XMM0: case X86::XMM1: case X86::XMM2: case X86::XMM3:
00175   case X86::XMM4: case X86::XMM5: case X86::XMM6: case X86::XMM7:
00176     return RegNo-X86::XMM0;
00177 
00178   default:
00179     assert(MRegisterInfo::isVirtualRegister(RegNo) &&
00180            "Unknown physical register!");
00181     assert(0 && "Register allocator hasn't allocated reg correctly yet!");
00182     return 0;
00183   }
00184 }
00185 
00186 inline static unsigned char ModRMByte(unsigned Mod, unsigned RegOpcode,
00187                                       unsigned RM) {
00188   assert(Mod < 4 && RegOpcode < 8 && RM < 8 && "ModRM Fields out of range!");
00189   return RM | (RegOpcode << 3) | (Mod << 6);
00190 }
00191 
00192 void Emitter::emitRegModRMByte(unsigned ModRMReg, unsigned RegOpcodeFld){
00193   MCE.emitByte(ModRMByte(3, RegOpcodeFld, getX86RegNum(ModRMReg)));
00194 }
00195 
00196 void Emitter::emitSIBByte(unsigned SS, unsigned Index, unsigned Base) {
00197   // SIB byte is in the same format as the ModRMByte...
00198   MCE.emitByte(ModRMByte(SS, Index, Base));
00199 }
00200 
00201 void Emitter::emitConstant(unsigned Val, unsigned Size) {
00202   // Output the constant in little endian byte order...
00203   for (unsigned i = 0; i != Size; ++i) {
00204     MCE.emitByte(Val & 255);
00205     Val >>= 8;
00206   }
00207 }
00208 
00209 /// isDisp8 - Return true if this signed displacement fits in a 8-bit 
00210 /// sign-extended field. 
00211 static bool isDisp8(int Value) {
00212   return Value == (signed char)Value;
00213 }
00214 
00215 void Emitter::emitDisplacementField(const MachineOperand *RelocOp,
00216                                     int DispVal) {
00217   // If this is a simple integer displacement that doesn't require a relocation,
00218   // emit it now.
00219   if (!RelocOp) {
00220     emitConstant(DispVal, 4);
00221     return;
00222   }
00223   
00224   // Otherwise, this is something that requires a relocation.  Emit it as such
00225   // now.
00226   if (RelocOp->isGlobalAddress()) {
00227     emitGlobalAddressForPtr(RelocOp->getGlobal(), RelocOp->getOffset());
00228   } else {
00229     assert(0 && "Unknown value to relocate!");
00230   }
00231 }
00232 
00233 void Emitter::emitMemModRMByte(const MachineInstr &MI,
00234                                unsigned Op, unsigned RegOpcodeField) {
00235   const MachineOperand &Op3 = MI.getOperand(Op+3);
00236   int DispVal = 0;
00237   const MachineOperand *DispForReloc = 0;
00238   
00239   // Figure out what sort of displacement we have to handle here.
00240   if (Op3.isGlobalAddress()) {
00241     DispForReloc = &Op3;
00242   } else if (Op3.isConstantPoolIndex()) {
00243     DispVal += MCE.getConstantPoolEntryAddress(Op3.getConstantPoolIndex());
00244     DispVal += Op3.getOffset();
00245   } else if (Op3.isJumpTableIndex()) {
00246     DispVal += MCE.getJumpTableEntryAddress(Op3.getJumpTableIndex());
00247   } else {
00248     DispVal = Op3.getImmedValue();
00249   }
00250 
00251   const MachineOperand &Base     = MI.getOperand(Op);
00252   const MachineOperand &Scale    = MI.getOperand(Op+1);
00253   const MachineOperand &IndexReg = MI.getOperand(Op+2);
00254 
00255   unsigned BaseReg = Base.getReg();
00256 
00257   // Is a SIB byte needed?
00258   if (IndexReg.getReg() == 0 && BaseReg != X86::ESP) {
00259     if (BaseReg == 0) {  // Just a displacement?
00260       // Emit special case [disp32] encoding
00261       MCE.emitByte(ModRMByte(0, RegOpcodeField, 5));
00262       
00263       emitDisplacementField(DispForReloc, DispVal);
00264     } else {
00265       unsigned BaseRegNo = getX86RegNum(BaseReg);
00266       if (!DispForReloc && DispVal == 0 && BaseRegNo != N86::EBP) {
00267         // Emit simple indirect register encoding... [EAX] f.e.
00268         MCE.emitByte(ModRMByte(0, RegOpcodeField, BaseRegNo));
00269       } else if (!DispForReloc && isDisp8(DispVal)) {
00270         // Emit the disp8 encoding... [REG+disp8]
00271         MCE.emitByte(ModRMByte(1, RegOpcodeField, BaseRegNo));
00272         emitConstant(DispVal, 1);
00273       } else {
00274         // Emit the most general non-SIB encoding: [REG+disp32]
00275         MCE.emitByte(ModRMByte(2, RegOpcodeField, BaseRegNo));
00276         emitDisplacementField(DispForReloc, DispVal);
00277       }
00278     }
00279 
00280   } else {  // We need a SIB byte, so start by outputting the ModR/M byte first
00281     assert(IndexReg.getReg() != X86::ESP && "Cannot use ESP as index reg!");
00282 
00283     bool ForceDisp32 = false;
00284     bool ForceDisp8  = false;
00285     if (BaseReg == 0) {
00286       // If there is no base register, we emit the special case SIB byte with
00287       // MOD=0, BASE=5, to JUST get the index, scale, and displacement.
00288       MCE.emitByte(ModRMByte(0, RegOpcodeField, 4));
00289       ForceDisp32 = true;
00290     } else if (DispForReloc) {
00291       // Emit the normal disp32 encoding.
00292       MCE.emitByte(ModRMByte(2, RegOpcodeField, 4));
00293       ForceDisp32 = true;
00294     } else if (DispVal == 0 && BaseReg != X86::EBP) {
00295       // Emit no displacement ModR/M byte
00296       MCE.emitByte(ModRMByte(0, RegOpcodeField, 4));
00297     } else if (isDisp8(DispVal)) {
00298       // Emit the disp8 encoding...
00299       MCE.emitByte(ModRMByte(1, RegOpcodeField, 4));
00300       ForceDisp8 = true;           // Make sure to force 8 bit disp if Base=EBP
00301     } else {
00302       // Emit the normal disp32 encoding...
00303       MCE.emitByte(ModRMByte(2, RegOpcodeField, 4));
00304     }
00305 
00306     // Calculate what the SS field value should be...
00307     static const unsigned SSTable[] = { ~0, 0, 1, ~0, 2, ~0, ~0, ~0, 3 };
00308     unsigned SS = SSTable[Scale.getImmedValue()];
00309 
00310     if (BaseReg == 0) {
00311       // Handle the SIB byte for the case where there is no base.  The
00312       // displacement has already been output.
00313       assert(IndexReg.getReg() && "Index register must be specified!");
00314       emitSIBByte(SS, getX86RegNum(IndexReg.getReg()), 5);
00315     } else {
00316       unsigned BaseRegNo = getX86RegNum(BaseReg);
00317       unsigned IndexRegNo;
00318       if (IndexReg.getReg())
00319         IndexRegNo = getX86RegNum(IndexReg.getReg());
00320       else
00321         IndexRegNo = 4;   // For example [ESP+1*<noreg>+4]
00322       emitSIBByte(SS, IndexRegNo, BaseRegNo);
00323     }
00324 
00325     // Do we need to output a displacement?
00326     if (ForceDisp8) {
00327       emitConstant(DispVal, 1);
00328     } else if (DispVal != 0 || ForceDisp32) {
00329       emitDisplacementField(DispForReloc, DispVal);
00330     }
00331   }
00332 }
00333 
00334 static unsigned sizeOfImm(const TargetInstrDescriptor &Desc) {
00335   switch (Desc.TSFlags & X86II::ImmMask) {
00336   case X86II::Imm8:   return 1;
00337   case X86II::Imm16:  return 2;
00338   case X86II::Imm32:  return 4;
00339   default: assert(0 && "Immediate size not set!");
00340     return 0;
00341   }
00342 }
00343 
00344 void Emitter::emitInstruction(const MachineInstr &MI) {
00345   NumEmitted++;  // Keep track of the # of mi's emitted
00346 
00347   unsigned Opcode = MI.getOpcode();
00348   const TargetInstrDescriptor &Desc = II->get(Opcode);
00349 
00350   // Emit the repeat opcode prefix as needed.
00351   if ((Desc.TSFlags & X86II::Op0Mask) == X86II::REP) MCE.emitByte(0xF3);
00352 
00353   // Emit the operand size opcode prefix as needed.
00354   if (Desc.TSFlags & X86II::OpSize) MCE.emitByte(0x66);
00355 
00356   switch (Desc.TSFlags & X86II::Op0Mask) {
00357   case X86II::TB:
00358     MCE.emitByte(0x0F);   // Two-byte opcode prefix
00359     break;
00360   case X86II::REP: break; // already handled.
00361   case X86II::XS:   // F3 0F
00362     MCE.emitByte(0xF3);
00363     MCE.emitByte(0x0F);
00364     break;
00365   case X86II::XD:   // F2 0F
00366     MCE.emitByte(0xF2);
00367     MCE.emitByte(0x0F);
00368     break;
00369   case X86II::D8: case X86II::D9: case X86II::DA: case X86II::DB:
00370   case X86II::DC: case X86II::DD: case X86II::DE: case X86II::DF:
00371     MCE.emitByte(0xD8+
00372                  (((Desc.TSFlags & X86II::Op0Mask)-X86II::D8)
00373                                    >> X86II::Op0Shift));
00374     break; // Two-byte opcode prefix
00375   default: assert(0 && "Invalid prefix!");
00376   case 0: break;  // No prefix!
00377   }
00378 
00379   unsigned char BaseOpcode = II->getBaseOpcodeFor(Opcode);
00380   switch (Desc.TSFlags & X86II::FormMask) {
00381   default: assert(0 && "Unknown FormMask value in X86 MachineCodeEmitter!");
00382   case X86II::Pseudo:
00383 #ifndef NDEBUG
00384     switch (Opcode) {
00385     default: 
00386       assert(0 && "psuedo instructions should be removed before code emission");
00387     case X86::IMPLICIT_USE:
00388     case X86::IMPLICIT_DEF:
00389     case X86::IMPLICIT_DEF_GR8:
00390     case X86::IMPLICIT_DEF_GR16:
00391     case X86::IMPLICIT_DEF_GR32:
00392     case X86::IMPLICIT_DEF_FR32:
00393     case X86::IMPLICIT_DEF_FR64:
00394     case X86::IMPLICIT_DEF_VR64:
00395     case X86::IMPLICIT_DEF_VR128:
00396     case X86::FP_REG_KILL:
00397       break;
00398     }
00399 #endif
00400     break;
00401 
00402   case X86II::RawFrm:
00403     MCE.emitByte(BaseOpcode);
00404     if (Desc.numOperands == 1) {
00405       const MachineOperand &MO = MI.getOperand(0);
00406       if (MO.isMachineBasicBlock()) {
00407         emitPCRelativeBlockAddress(MO.getMachineBasicBlock());
00408       } else if (MO.isGlobalAddress()) {
00409         bool isTailCall = Opcode == X86::TAILJMPd ||
00410                           Opcode == X86::TAILJMPr || Opcode == X86::TAILJMPm;
00411         emitGlobalAddressForCall(MO.getGlobal(), isTailCall);
00412       } else if (MO.isExternalSymbol()) {
00413         emitExternalSymbolAddress(MO.getSymbolName(), true);
00414       } else if (MO.isImmediate()) {
00415         emitConstant(MO.getImmedValue(), sizeOfImm(Desc));
00416       } else {
00417         assert(0 && "Unknown RawFrm operand!");
00418       }
00419     }
00420     break;
00421 
00422   case X86II::AddRegFrm:
00423     MCE.emitByte(BaseOpcode + getX86RegNum(MI.getOperand(0).getReg()));
00424     if (MI.getNumOperands() == 2) {
00425       const MachineOperand &MO1 = MI.getOperand(1);
00426       if (MO1.isGlobalAddress()) {
00427         assert(sizeOfImm(Desc) == 4 &&
00428                "Don't know how to emit non-pointer values!");
00429         emitGlobalAddressForPtr(MO1.getGlobal(), MO1.getOffset());
00430       } else if (MO1.isExternalSymbol()) {
00431         assert(sizeOfImm(Desc) == 4 &&
00432                "Don't know how to emit non-pointer values!");
00433         emitExternalSymbolAddress(MO1.getSymbolName(), false);
00434       } else if (MO1.isJumpTableIndex()) {
00435         assert(sizeOfImm(Desc) == 4 &&
00436                "Don't know how to emit non-pointer values!");
00437         emitConstant(MCE.getJumpTableEntryAddress(MO1.getJumpTableIndex()), 4);
00438       } else {
00439         emitConstant(MO1.getImmedValue(), sizeOfImm(Desc));
00440       }
00441     }
00442     break;
00443 
00444   case X86II::MRMDestReg: {
00445     MCE.emitByte(BaseOpcode);
00446     emitRegModRMByte(MI.getOperand(0).getReg(),
00447                      getX86RegNum(MI.getOperand(1).getReg()));
00448     if (MI.getNumOperands() == 3)
00449       emitConstant(MI.getOperand(2).getImmedValue(), sizeOfImm(Desc));
00450     break;
00451   }
00452   case X86II::MRMDestMem:
00453     MCE.emitByte(BaseOpcode);
00454     emitMemModRMByte(MI, 0, getX86RegNum(MI.getOperand(4).getReg()));
00455     if (MI.getNumOperands() == 6)
00456       emitConstant(MI.getOperand(5).getImmedValue(), sizeOfImm(Desc));
00457     break;
00458 
00459   case X86II::MRMSrcReg:
00460     MCE.emitByte(BaseOpcode);
00461     emitRegModRMByte(MI.getOperand(1).getReg(),
00462                      getX86RegNum(MI.getOperand(0).getReg()));
00463     if (MI.getNumOperands() == 3)
00464       emitConstant(MI.getOperand(2).getImmedValue(), sizeOfImm(Desc));
00465     break;
00466 
00467   case X86II::MRMSrcMem:
00468     MCE.emitByte(BaseOpcode);
00469     emitMemModRMByte(MI, 1, getX86RegNum(MI.getOperand(0).getReg()));
00470     if (MI.getNumOperands() == 2+4)
00471       emitConstant(MI.getOperand(5).getImmedValue(), sizeOfImm(Desc));
00472     break;
00473 
00474   case X86II::MRM0r: case X86II::MRM1r:
00475   case X86II::MRM2r: case X86II::MRM3r:
00476   case X86II::MRM4r: case X86II::MRM5r:
00477   case X86II::MRM6r: case X86II::MRM7r:
00478     MCE.emitByte(BaseOpcode);
00479     emitRegModRMByte(MI.getOperand(0).getReg(),
00480                      (Desc.TSFlags & X86II::FormMask)-X86II::MRM0r);
00481 
00482     if (MI.getOperand(MI.getNumOperands()-1).isImmediate()) {
00483       emitConstant(MI.getOperand(MI.getNumOperands()-1).getImmedValue(),
00484                    sizeOfImm(Desc));
00485     }
00486     break;
00487 
00488   case X86II::MRM0m: case X86II::MRM1m:
00489   case X86II::MRM2m: case X86II::MRM3m:
00490   case X86II::MRM4m: case X86II::MRM5m:
00491   case X86II::MRM6m: case X86II::MRM7m:
00492     MCE.emitByte(BaseOpcode);
00493     emitMemModRMByte(MI, 0, (Desc.TSFlags & X86II::FormMask)-X86II::MRM0m);
00494 
00495     if (MI.getNumOperands() == 5) {
00496       if (MI.getOperand(4).isImmediate())
00497         emitConstant(MI.getOperand(4).getImmedValue(), sizeOfImm(Desc));
00498       else if (MI.getOperand(4).isGlobalAddress())
00499         emitGlobalAddressForPtr(MI.getOperand(4).getGlobal(),
00500                                 MI.getOperand(4).getOffset());
00501       else if (MI.getOperand(4).isJumpTableIndex())
00502         emitConstant(MCE.getJumpTableEntryAddress(MI.getOperand(4)
00503                                                     .getJumpTableIndex()), 4);
00504       else
00505         assert(0 && "Unknown operand!");
00506     }
00507     break;
00508 
00509   case X86II::MRMInitReg:
00510     MCE.emitByte(BaseOpcode);
00511     emitRegModRMByte(MI.getOperand(0).getReg(),
00512                      getX86RegNum(MI.getOperand(0).getReg()));
00513     break;
00514   }
00515 }