<commit_before>//===-- JIT.cpp - LLVM Just in Time Compiler ------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tool implements a just-in-time compiler for LLVM, allowing direct
// execution of LLVM bytecode in an efficient manner.
//
//===----------------------------------------------------------------------===//

#include "JIT.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Instructions.h"
#include "llvm/ModuleProvider.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/Support/MutexGuard.h"
#include "llvm/System/DynamicLibrary.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetJITInfo.h"
#include <iostream>
using namespace llvm;

#ifdef __APPLE__
// __dso_handle is resolved by Mac OS X dynamic linker.
extern void *__dso_handle __attribute__ ((__visibility__ ("hidden")));
#endif

static struct RegisterJIT {
  RegisterJIT() { JIT::Register(); }
} JITRegistrator;

namespace llvm {
  void LinkInJIT() {
  }
}

JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji)
  : ExecutionEngine(MP), TM(tm), TJI(tji), state(MP) {
  setTargetData(TM.getTargetData());

  // Initialize MCE
  MCE = createEmitter(*this);

  // Add target data
  MutexGuard locked(lock);
  FunctionPassManager& PM = state.getPM(locked);
  PM.add(new TargetData(*TM.getTargetData()));

  // Compile LLVM Code down to machine code in the intermediate representation
  TJI.addPassesToJITCompile(PM);

  // Turn the machine code intermediate representation into bytes in memory that
  // may be executed.
  if (TM.addPassesToEmitMachineCode(PM, *MCE)) {
    std::cerr << "Target '" << TM.getName()
              << "' doesn't support machine code emission!\n";
    abort();
  }
}

JIT::~JIT() {
  delete MCE;
  delete &TM;
}

/// run - Start execution with the specified function and arguments.
///
GenericValue JIT::runFunction(Function *F,
                              const std::vector<GenericValue> &ArgValues) {
  assert(F && "Function *F was null at entry to run()");

  void *FPtr = getPointerToFunction(F);
  assert(FPtr && "Pointer to fn's code was null after getPointerToFunction");
  const FunctionType *FTy = F->getFunctionType();
  const Type *RetTy = FTy->getReturnType();

  assert((FTy->getNumParams() <= ArgValues.size() || FTy->isVarArg()) &&
         "Too many arguments passed into function!");
  assert(FTy->getNumParams() == ArgValues.size() &&
         "This doesn't support passing arguments through varargs (yet)!");

  // Handle some common cases first.  These cases correspond to common `main'
  // prototypes.
  if (RetTy == Type::IntTy || RetTy == Type::UIntTy || RetTy == Type::VoidTy) {
    switch (ArgValues.size()) {
    case 3:
      if ((FTy->getParamType(0) == Type::IntTy ||
           FTy->getParamType(0) == Type::UIntTy) &&
          isa<PointerType>(FTy->getParamType(1)) &&
          isa<PointerType>(FTy->getParamType(2))) {
        int (*PF)(int, char **, const char **) =
          (int(*)(int, char **, const char **))(intptr_t)FPtr;

        // Call the function.
        GenericValue rv;
        rv.IntVal = PF(ArgValues[0].IntVal, (char **)GVTOP(ArgValues[1]),
                       (const char **)GVTOP(ArgValues[2]));
        return rv;
      }
      break;
    case 2:
      if ((FTy->getParamType(0) == Type::IntTy ||
           FTy->getParamType(0) == Type::UIntTy) &&
          isa<PointerType>(FTy->getParamType(1))) {
        int (*PF)(int, char **) = (int(*)(int, char **))(intptr_t)FPtr;

        // Call the function.
        GenericValue rv;
        rv.IntVal = PF(ArgValues[0].IntVal, (char **)GVTOP(ArgValues[1]));
        return rv;
      }
      break;
    case 1:
      if (FTy->getNumParams() == 1 &&
          (FTy->getParamType(0) == Type::IntTy ||
           FTy->getParamType(0) == Type::UIntTy)) {
        GenericValue rv;
        int (*PF)(int) = (int(*)(int))(intptr_t)FPtr;
        rv.IntVal = PF(ArgValues[0].IntVal);
        return rv;
      }
      break;
    }
  }

  // Handle cases where no arguments are passed first.
  if (ArgValues.empty()) {
    GenericValue rv;
    switch (RetTy->getTypeID()) {
    default: assert(0 && "Unknown return type for function call!");
    case Type::BoolTyID:
      rv.BoolVal = ((bool(*)())(intptr_t)FPtr)();
      return rv;
    case Type::SByteTyID:
    case Type::UByteTyID:
      rv.SByteVal = ((char(*)())(intptr_t)FPtr)();
      return rv;
    case Type::ShortTyID:
    case Type::UShortTyID:
      rv.ShortVal = ((short(*)())(intptr_t)FPtr)();
      return rv;
    case Type::VoidTyID:
    case Type::IntTyID:
    case Type::UIntTyID:
      rv.IntVal = ((int(*)())(intptr_t)FPtr)();
      return rv;
    case Type::LongTyID:
    case Type::ULongTyID:
      rv.LongVal = ((int64_t(*)())(intptr_t)FPtr)();
      return rv;
    case Type::FloatTyID:
      rv.FloatVal = ((float(*)())(intptr_t)FPtr)();
      return rv;
    case Type::DoubleTyID:
      rv.DoubleVal = ((double(*)())(intptr_t)FPtr)();
      return rv;
    case Type::PointerTyID:
      return PTOGV(((void*(*)())(intptr_t)FPtr)());
    }
  }

  // Okay, this is not one of our quick and easy cases.  Because we don't have a
  // full FFI, we have to codegen a nullary stub function that just calls the
  // function we are interested in, passing in constants for all of the
  // arguments.  Make this function and return.

  // First, create the function.
  FunctionType *STy=FunctionType::get(RetTy, std::vector<const Type*>(), false);
  Function *Stub = new Function(STy, Function::InternalLinkage, "",
                                F->getParent());

  // Insert a basic block.
  BasicBlock *StubBB = new BasicBlock("", Stub);

  // Convert all of the GenericValue arguments over to constants.  Note that we
  // currently don't support varargs.
  std::vector<Value*> Args;
  for (unsigned i = 0, e = ArgValues.size(); i != e; ++i) {
    Constant *C = 0;
    const Type *ArgTy = FTy->getParamType(i);
    const GenericValue &AV = ArgValues[i];
    switch (ArgTy->getTypeID()) {
    default: assert(0 && "Unknown argument type for function call!");
    case Type::BoolTyID:   C = ConstantBool::get(AV.BoolVal); break;
    case Type::SByteTyID:  C = ConstantSInt::get(ArgTy, AV.SByteVal);  break;
    case Type::UByteTyID:  C = ConstantUInt::get(ArgTy, AV.UByteVal);  break;
    case Type::ShortTyID:  C = ConstantSInt::get(ArgTy, AV.ShortVal);  break;
    case Type::UShortTyID: C = ConstantUInt::get(ArgTy, AV.UShortVal); break;
    case Type::IntTyID:    C = ConstantSInt::get(ArgTy, AV.IntVal);    break;
    case Type::UIntTyID:   C = ConstantUInt::get(ArgTy, AV.UIntVal);   break;
    case Type::LongTyID:   C = ConstantSInt::get(ArgTy, AV.LongVal);   break;
    case Type::ULongTyID:  C = ConstantUInt::get(ArgTy, AV.ULongVal);  break;
    case Type::FloatTyID:  C = ConstantFP  ::get(ArgTy, AV.FloatVal);  break;
    case Type::DoubleTyID: C = ConstantFP  ::get(ArgTy, AV.DoubleVal); break;
    case Type::PointerTyID:
      void *ArgPtr = GVTOP(AV);
      if (sizeof(void*) == 4) {
        C = ConstantSInt::get(Type::IntTy, (int)(intptr_t)ArgPtr);
      } else {
        C = ConstantSInt::get(Type::LongTy, (intptr_t)ArgPtr);
      }
      C = ConstantExpr::getCast(C, ArgTy);  // Cast the integer to pointer
      break;
    }
    Args.push_back(C);
  }

  CallInst *TheCall = new CallInst(F, Args, "", StubBB);
  TheCall->setTailCall();
  if (TheCall->getType() != Type::VoidTy)
    new ReturnInst(TheCall, StubBB);             // Return result of the call.
  else
    new ReturnInst(StubBB);                      // Just return void.

  // Finally, return the value returned by our nullary stub function.
  return runFunction(Stub, std::vector<GenericValue>());
}

/// runJITOnFunction - Run the FunctionPassManager full of
/// just-in-time compilation passes on F, hopefully filling in
/// GlobalAddress[F] with the address of F's machine code.
///
void JIT::runJITOnFunction(Function *F) {
  static bool isAlreadyCodeGenerating = false;
  assert(!isAlreadyCodeGenerating && "Error: Recursive compilation detected!");

  MutexGuard locked(lock);

  // JIT the function
  isAlreadyCodeGenerating = true;
  state.getPM(locked).run(*F);
  isAlreadyCodeGenerating = false;

  // If the function referred to a global variable that had not yet been
  // emitted, it allocates memory for the global, but doesn't emit it yet.  Emit
  // all of these globals now.
  while (!state.getPendingGlobals(locked).empty()) {
    const GlobalVariable *GV = state.getPendingGlobals(locked).back();
    state.getPendingGlobals(locked).pop_back();
    EmitGlobalVariable(GV);
  }
}

/// getPointerToFunction - This method is used to get the address of the
/// specified function, compiling it if neccesary.
///
void *JIT::getPointerToFunction(Function *F) {
  MutexGuard locked(lock);

  if (void *Addr = getPointerToGlobalIfAvailable(F))
    return Addr;   // Check if function already code gen'd

  // Make sure we read in the function if it exists in this Module
  if (F->hasNotBeenReadFromBytecode()) {
    std::string ErrorMsg;
    if (MP->materializeFunction(F, &ErrorMsg)) {
      std::cerr << "Error reading function '" << F->getName()
                << "' from bytecode file: " << ErrorMsg << "\n";
      abort();
    }
  }

  if (F->isExternal()) {
    void *Addr = getPointerToNamedFunction(F->getName());
    addGlobalMapping(F, Addr);
    return Addr;
  }

  runJITOnFunction(F);

  void *Addr = getPointerToGlobalIfAvailable(F);
  assert(Addr && "Code generation didn't add function to GlobalAddress table!");
  return Addr;
}

/// getOrEmitGlobalVariable - Return the address of the specified global
/// variable, possibly emitting it to memory if needed.  This is used by the
/// Emitter.
void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
  MutexGuard locked(lock);

  void *Ptr = getPointerToGlobalIfAvailable(GV);
  if (Ptr) return Ptr;

  // If the global is external, just remember the address.
  if (GV->isExternal()) {
    // __dso_handle is resolved by the Mac OS X dynamic linker.
    if (GV->getName() == "__dso_handle")
      return (void*)&__dso_handle;
    Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(GV->getName().c_str());
    if (Ptr == 0) {
      std::cerr << "Could not resolve external global address: "
                << GV->getName() << "\n";
      abort();
    }
  } else {
    // If the global hasn't been emitted to memory yet, allocate space.  We will
    // actually initialize the global after current function has finished
    // compilation.
    const Type *GlobalType = GV->getType()->getElementType();
    size_t S = getTargetData()->getTypeSize(GlobalType);
    size_t A = getTargetData()->getTypeAlignment(GlobalType);
    if (A <= 8) {
      Ptr = malloc(S);
    } else {
      // Allocate S+A bytes of memory, then use an aligned pointer within that
      // space.
      Ptr = malloc(S+A);
      unsigned MisAligned = ((intptr_t)Ptr & (A-1));
      Ptr = (char*)Ptr + (MisAligned ? (A-MisAligned) : 0);
    }
    state.getPendingGlobals(locked).push_back(GV);
  }
  addGlobalMapping(GV, Ptr);
  return Ptr;
}

/// recompileAndRelinkFunction - This method is used to force a function
/// which has already been compiled, to be compiled again, possibly
/// after it has been modified. Then the entry to the old copy is overwritten
/// with a branch to the new copy. If there was no old copy, this acts
/// just like JIT::getPointerToFunction().
///
void *JIT::recompileAndRelinkFunction(Function *F) {
  void *OldAddr = getPointerToGlobalIfAvailable(F);

  // If it's not already compiled there is no reason to patch it up.
  if (OldAddr == 0) { return getPointerToFunction(F); }

  // Delete the old function mapping.
  addGlobalMapping(F, 0);

  // Recodegen the function
  runJITOnFunction(F);

  // Update state, forward the old function to the new function.
  void *Addr = getPointerToGlobalIfAvailable(F);
  assert(Addr && "Code generation didn't add function to GlobalAddress table!");
  TJI.replaceMachineCodeForFunction(OldAddr, Addr);
  return Addr;
}

<commit_msg>Forgot to #ifdef __APPLE__<commit_after>//===-- JIT.cpp - LLVM Just in Time Compiler ------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tool implements a just-in-time compiler for LLVM, allowing direct
// execution of LLVM bytecode in an efficient manner.
//
//===----------------------------------------------------------------------===//

#include "JIT.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Instructions.h"
#include "llvm/ModuleProvider.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/Support/MutexGuard.h"
#include "llvm/System/DynamicLibrary.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetJITInfo.h"
#include <iostream>
using namespace llvm;

#ifdef __APPLE__
// __dso_handle is resolved by Mac OS X dynamic linker.
extern void *__dso_handle __attribute__ ((__visibility__ ("hidden")));
#endif

static struct RegisterJIT {
  RegisterJIT() { JIT::Register(); }
} JITRegistrator;

namespace llvm {
  void LinkInJIT() {
  }
}

JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji)
  : ExecutionEngine(MP), TM(tm), TJI(tji), state(MP) {
  setTargetData(TM.getTargetData());

  // Initialize MCE
  MCE = createEmitter(*this);

  // Add target data
  MutexGuard locked(lock);
  FunctionPassManager& PM = state.getPM(locked);
  PM.add(new TargetData(*TM.getTargetData()));

  // Compile LLVM Code down to machine code in the intermediate representation
  TJI.addPassesToJITCompile(PM);

  // Turn the machine code intermediate representation into bytes in memory that
  // may be executed.
  if (TM.addPassesToEmitMachineCode(PM, *MCE)) {
    std::cerr << "Target '" << TM.getName()
              << "' doesn't support machine code emission!\n";
    abort();
  }
}

JIT::~JIT() {
  delete MCE;
  delete &TM;
}

/// run - Start execution with the specified function and arguments.
///
GenericValue JIT::runFunction(Function *F,
                              const std::vector<GenericValue> &ArgValues) {
  assert(F && "Function *F was null at entry to run()");

  void *FPtr = getPointerToFunction(F);
  assert(FPtr && "Pointer to fn's code was null after getPointerToFunction");
  const FunctionType *FTy = F->getFunctionType();
  const Type *RetTy = FTy->getReturnType();

  assert((FTy->getNumParams() <= ArgValues.size() || FTy->isVarArg()) &&
         "Too many arguments passed into function!");
  assert(FTy->getNumParams() == ArgValues.size() &&
         "This doesn't support passing arguments through varargs (yet)!");

  // Handle some common cases first.  These cases correspond to common `main'
  // prototypes.
  if (RetTy == Type::IntTy || RetTy == Type::UIntTy || RetTy == Type::VoidTy) {
    switch (ArgValues.size()) {
    case 3:
      if ((FTy->getParamType(0) == Type::IntTy ||
           FTy->getParamType(0) == Type::UIntTy) &&
          isa<PointerType>(FTy->getParamType(1)) &&
          isa<PointerType>(FTy->getParamType(2))) {
        int (*PF)(int, char **, const char **) =
          (int(*)(int, char **, const char **))(intptr_t)FPtr;

        // Call the function.
        GenericValue rv;
        rv.IntVal = PF(ArgValues[0].IntVal, (char **)GVTOP(ArgValues[1]),
                       (const char **)GVTOP(ArgValues[2]));
        return rv;
      }
      break;
    case 2:
      if ((FTy->getParamType(0) == Type::IntTy ||
           FTy->getParamType(0) == Type::UIntTy) &&
          isa<PointerType>(FTy->getParamType(1))) {
        int (*PF)(int, char **) = (int(*)(int, char **))(intptr_t)FPtr;

        // Call the function.
        GenericValue rv;
        rv.IntVal = PF(ArgValues[0].IntVal, (char **)GVTOP(ArgValues[1]));
        return rv;
      }
      break;
    case 1:
      if (FTy->getNumParams() == 1 &&
          (FTy->getParamType(0) == Type::IntTy ||
           FTy->getParamType(0) == Type::UIntTy)) {
        GenericValue rv;
        int (*PF)(int) = (int(*)(int))(intptr_t)FPtr;
        rv.IntVal = PF(ArgValues[0].IntVal);
        return rv;
      }
      break;
    }
  }

  // Handle cases where no arguments are passed first.
  if (ArgValues.empty()) {
    GenericValue rv;
    switch (RetTy->getTypeID()) {
    default: assert(0 && "Unknown return type for function call!");
    case Type::BoolTyID:
      rv.BoolVal = ((bool(*)())(intptr_t)FPtr)();
      return rv;
    case Type::SByteTyID:
    case Type::UByteTyID:
      rv.SByteVal = ((char(*)())(intptr_t)FPtr)();
      return rv;
    case Type::ShortTyID:
    case Type::UShortTyID:
      rv.ShortVal = ((short(*)())(intptr_t)FPtr)();
      return rv;
    case Type::VoidTyID:
    case Type::IntTyID:
    case Type::UIntTyID:
      rv.IntVal = ((int(*)())(intptr_t)FPtr)();
      return rv;
    case Type::LongTyID:
    case Type::ULongTyID:
      rv.LongVal = ((int64_t(*)())(intptr_t)FPtr)();
      return rv;
    case Type::FloatTyID:
      rv.FloatVal = ((float(*)())(intptr_t)FPtr)();
      return rv;
    case Type::DoubleTyID:
      rv.DoubleVal = ((double(*)())(intptr_t)FPtr)();
      return rv;
    case Type::PointerTyID:
      return PTOGV(((void*(*)())(intptr_t)FPtr)());
    }
  }

  // Okay, this is not one of our quick and easy cases.  Because we don't have a
  // full FFI, we have to codegen a nullary stub function that just calls the
  // function we are interested in, passing in constants for all of the
  // arguments.  Make this function and return.

  // First, create the function.
  FunctionType *STy=FunctionType::get(RetTy, std::vector<const Type*>(), false);
  Function *Stub = new Function(STy, Function::InternalLinkage, "",
                                F->getParent());

  // Insert a basic block.
  BasicBlock *StubBB = new BasicBlock("", Stub);

  // Convert all of the GenericValue arguments over to constants.  Note that we
  // currently don't support varargs.
  std::vector<Value*> Args;
  for (unsigned i = 0, e = ArgValues.size(); i != e; ++i) {
    Constant *C = 0;
    const Type *ArgTy = FTy->getParamType(i);
    const GenericValue &AV = ArgValues[i];
    switch (ArgTy->getTypeID()) {
    default: assert(0 && "Unknown argument type for function call!");
    case Type::BoolTyID:   C = ConstantBool::get(AV.BoolVal); break;
    case Type::SByteTyID:  C = ConstantSInt::get(ArgTy, AV.SByteVal);  break;
    case Type::UByteTyID:  C = ConstantUInt::get(ArgTy, AV.UByteVal);  break;
    case Type::ShortTyID:  C = ConstantSInt::get(ArgTy, AV.ShortVal);  break;
    case Type::UShortTyID: C = ConstantUInt::get(ArgTy, AV.UShortVal); break;
    case Type::IntTyID:    C = ConstantSInt::get(ArgTy, AV.IntVal);    break;
    case Type::UIntTyID:   C = ConstantUInt::get(ArgTy, AV.UIntVal);   break;
    case Type::LongTyID:   C = ConstantSInt::get(ArgTy, AV.LongVal);   break;
    case Type::ULongTyID:  C = ConstantUInt::get(ArgTy, AV.ULongVal);  break;
    case Type::FloatTyID:  C = ConstantFP  ::get(ArgTy, AV.FloatVal);  break;
    case Type::DoubleTyID: C = ConstantFP  ::get(ArgTy, AV.DoubleVal); break;
    case Type::PointerTyID:
      void *ArgPtr = GVTOP(AV);
      if (sizeof(void*) == 4) {
        C = ConstantSInt::get(Type::IntTy, (int)(intptr_t)ArgPtr);
      } else {
        C = ConstantSInt::get(Type::LongTy, (intptr_t)ArgPtr);
      }
      C = ConstantExpr::getCast(C, ArgTy);  // Cast the integer to pointer
      break;
    }
    Args.push_back(C);
  }

  CallInst *TheCall = new CallInst(F, Args, "", StubBB);
  TheCall->setTailCall();
  if (TheCall->getType() != Type::VoidTy)
    new ReturnInst(TheCall, StubBB);             // Return result of the call.
  else
    new ReturnInst(StubBB);                      // Just return void.

  // Finally, return the value returned by our nullary stub function.
  return runFunction(Stub, std::vector<GenericValue>());
}

/// runJITOnFunction - Run the FunctionPassManager full of
/// just-in-time compilation passes on F, hopefully filling in
/// GlobalAddress[F] with the address of F's machine code.
///
void JIT::runJITOnFunction(Function *F) {
  static bool isAlreadyCodeGenerating = false;
  assert(!isAlreadyCodeGenerating && "Error: Recursive compilation detected!");

  MutexGuard locked(lock);

  // JIT the function
  isAlreadyCodeGenerating = true;
  state.getPM(locked).run(*F);
  isAlreadyCodeGenerating = false;

  // If the function referred to a global variable that had not yet been
  // emitted, it allocates memory for the global, but doesn't emit it yet.  Emit
  // all of these globals now.
  while (!state.getPendingGlobals(locked).empty()) {
    const GlobalVariable *GV = state.getPendingGlobals(locked).back();
    state.getPendingGlobals(locked).pop_back();
    EmitGlobalVariable(GV);
  }
}

/// getPointerToFunction - This method is used to get the address of the
/// specified function, compiling it if neccesary.
///
void *JIT::getPointerToFunction(Function *F) {
  MutexGuard locked(lock);

  if (void *Addr = getPointerToGlobalIfAvailable(F))
    return Addr;   // Check if function already code gen'd

  // Make sure we read in the function if it exists in this Module
  if (F->hasNotBeenReadFromBytecode()) {
    std::string ErrorMsg;
    if (MP->materializeFunction(F, &ErrorMsg)) {
      std::cerr << "Error reading function '" << F->getName()
                << "' from bytecode file: " << ErrorMsg << "\n";
      abort();
    }
  }

  if (F->isExternal()) {
    void *Addr = getPointerToNamedFunction(F->getName());
    addGlobalMapping(F, Addr);
    return Addr;
  }

  runJITOnFunction(F);

  void *Addr = getPointerToGlobalIfAvailable(F);
  assert(Addr && "Code generation didn't add function to GlobalAddress table!");
  return Addr;
}

/// getOrEmitGlobalVariable - Return the address of the specified global
/// variable, possibly emitting it to memory if needed.  This is used by the
/// Emitter.
void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
  MutexGuard locked(lock);

  void *Ptr = getPointerToGlobalIfAvailable(GV);
  if (Ptr) return Ptr;

  // If the global is external, just remember the address.
  if (GV->isExternal()) {
#ifdef __APPLE__
    // __dso_handle is resolved by the Mac OS X dynamic linker.
    if (GV->getName() == "__dso_handle")
      return (void*)&__dso_handle;
#endif
    Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(GV->getName().c_str());
    if (Ptr == 0) {
      std::cerr << "Could not resolve external global address: "
                << GV->getName() << "\n";
      abort();
    }
  } else {
    // If the global hasn't been emitted to memory yet, allocate space.  We will
    // actually initialize the global after current function has finished
    // compilation.
    const Type *GlobalType = GV->getType()->getElementType();
    size_t S = getTargetData()->getTypeSize(GlobalType);
    size_t A = getTargetData()->getTypeAlignment(GlobalType);
    if (A <= 8) {
      Ptr = malloc(S);
    } else {
      // Allocate S+A bytes of memory, then use an aligned pointer within that
      // space.
      Ptr = malloc(S+A);
      unsigned MisAligned = ((intptr_t)Ptr & (A-1));
      Ptr = (char*)Ptr + (MisAligned ? (A-MisAligned) : 0);
    }
    state.getPendingGlobals(locked).push_back(GV);
  }
  addGlobalMapping(GV, Ptr);
  return Ptr;
}

/// recompileAndRelinkFunction - This method is used to force a function
/// which has already been compiled, to be compiled again, possibly
/// after it has been modified. Then the entry to the old copy is overwritten
/// with a branch to the new copy. If there was no old copy, this acts
/// just like JIT::getPointerToFunction().
///
void *JIT::recompileAndRelinkFunction(Function *F) {
  void *OldAddr = getPointerToGlobalIfAvailable(F);

  // If it's not already compiled there is no reason to patch it up.
  if (OldAddr == 0) { return getPointerToFunction(F); }

  // Delete the old function mapping.
  addGlobalMapping(F, 0);

  // Recodegen the function
  runJITOnFunction(F);

  // Update state, forward the old function to the new function.
  void *Addr = getPointerToGlobalIfAvailable(F);
  assert(Addr && "Code generation didn't add function to GlobalAddress table!");
  TJI.replaceMachineCodeForFunction(OldAddr, Addr);
  return Addr;
}

<|endoftext|>


<commit_before>
#include <string.h>
#include <vector>
#include <stdio.h>
#include <cassert>
#include <stdexcept>
#include "univalue.h"

using namespace std;

enum tokentype {
    TOK_ERR        = -1,
    TOK_NONE       = 0,                           // eof
    TOK_OBJ_OPEN,
    TOK_OBJ_CLOSE,
    TOK_ARR_OPEN,
    TOK_ARR_CLOSE,
    TOK_COLON,
    TOK_COMMA,
    TOK_KW_NULL,
    TOK_KW_TRUE,
    TOK_KW_FALSE,
    TOK_NUMBER,
    TOK_STRING,
};

enum tokentype getJsonToken(string& tokenVal, unsigned int& consumed,
                            const char *raw)
{
    tokenVal.clear();
    consumed = 0;

    const char *rawStart = raw;

    while ((*raw) && (isspace(*raw)))             // skip whitespace
        raw++;

    switch (*raw) {

    case 0:
        return TOK_NONE;

    case '{':
        raw++;
        consumed = (raw - rawStart);
        return TOK_OBJ_OPEN;
    case '}':
        raw++;
        consumed = (raw - rawStart);
        return TOK_OBJ_CLOSE;
    case '[':
        raw++;
        consumed = (raw - rawStart);
        return TOK_ARR_OPEN;
    case ']':
        raw++;
        consumed = (raw - rawStart);
        return TOK_ARR_CLOSE;

    case ':':
        raw++;
        consumed = (raw - rawStart);
        return TOK_COLON;
    case ',':
        raw++;
        consumed = (raw - rawStart);
        return TOK_COMMA;

    case 'n':
    case 't':
    case 'f':
        if (!strncmp(raw, "null", 4)) {
            raw += 4;
            consumed = (raw - rawStart);
            return TOK_KW_NULL;
        } else if (!strncmp(raw, "true", 4)) {
            raw += 4;
            consumed = (raw - rawStart);
            return TOK_KW_TRUE;
        } else if (!strncmp(raw, "false", 5)) {
            raw += 5;
            consumed = (raw - rawStart);
            return TOK_KW_FALSE;
        } else
            return TOK_ERR;

    case '-':
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9': {
        // part 1: int
        string numStr;

        const char *first = raw;

        const char *firstDigit = first;
        if (!isdigit(*firstDigit))
            firstDigit++;
        if (*firstDigit == '0')
            return TOK_ERR;

        numStr += *raw;                       // copy first char
        raw++;

        if ((*first == '-') && (!isdigit(*raw)))
            return TOK_ERR;

        while ((*raw) && isdigit(*raw)) {     // copy digits
            numStr += *raw;
            raw++;
        }

        // part 2: frac
        if (*raw == '.') {
            numStr += *raw;                   // copy .
            raw++;

            if (!isdigit(*raw))
                return TOK_ERR;
            while ((*raw) && isdigit(*raw)) { // copy digits
                numStr += *raw;
                raw++;
            }
        }

        // part 3: exp
        if (*raw == 'e' || *raw == 'E') {
            numStr += *raw;                   // copy E
            raw++;

            if (*raw == '-' || *raw == '+') { // copy +/-
                numStr += *raw;
                raw++;
            }

            if (!isdigit(*raw))
                return TOK_ERR;
            while ((*raw) && isdigit(*raw)) { // copy digits
                numStr += *raw;
                raw++;
            }
        }

        tokenVal = numStr;
        consumed = (raw - rawStart);
        return TOK_NUMBER;
        }

    case '"': {
        raw++;                                // skip "

        string valStr;

        while (*raw) {
            if (*raw < 0x20)
                return TOK_ERR;

            else if (*raw == '\\') {
                raw++;                        // skip backslash

                switch (*raw) {
                case '"':  valStr += "\""; break;
                case '\\': valStr += "\\"; break;
                case '/':  valStr += "/"; break;
                case 'b':  valStr += "\b"; break;
                case 'f':  valStr += "\f"; break;
                case 'n':  valStr += "\n"; break;
                case 'r':  valStr += "\r"; break;
                case 't':  valStr += "\t"; break;
                case 'u':
                    // TODO: not supported yet
                    assert(0);
                    break;
                default:
                    return TOK_ERR;

                }

                raw++;                        // skip esc'd char
            }

            else if (*raw == '"') {
                raw++;                        // skip "
                break;                        // stop scanning
            }

            else {
                valStr += *raw;
                raw++;
            }
        }

        tokenVal = valStr;
        consumed = (raw - rawStart);
        return TOK_STRING;
        }

    default:
        return TOK_ERR;
    }
}

void UniValue::read(const char *raw)
{
    clear();

    bool expectName = false;
    bool expectColon = false;
    vector<UniValue*> stack;

    enum tokentype tok = TOK_NONE;
    enum tokentype last_tok = TOK_NONE;
    while (1) {
        last_tok = tok;

        string tokenVal;
        unsigned int consumed;
        tok = getJsonToken(tokenVal, consumed, raw);
        if (tok == TOK_NONE || tok == TOK_ERR)
            break;
        raw += consumed;

        switch (tok) {

        case TOK_OBJ_OPEN:
        case TOK_ARR_OPEN: {
            VType utyp = (tok == TOK_OBJ_OPEN ? VOBJ : VARR);
            if (!stack.size()) {
                if (utyp == VOBJ)
                    setObject();
                else
                    setArray();
                stack.push_back(this);
            } else {
                UniValue tmpVal(utyp);
                UniValue *top = stack.back();
                top->values.push_back(tmpVal);

                UniValue *newTop = &(top->values.back());
                stack.push_back(newTop);
            }

            if (utyp == VOBJ)
                expectName = true;
            break;
            }

        case TOK_OBJ_CLOSE:
        case TOK_ARR_CLOSE: {
            if (!stack.size() || expectColon || (last_tok == TOK_COMMA))
                throw runtime_error("json parse: unexpected }]");

            VType utyp = (tok == TOK_OBJ_CLOSE ? VOBJ : VARR);
            UniValue *top = stack.back();
            if (utyp != top->getType())
                throw runtime_error("json parse: mismatched }]");

            stack.pop_back();
            expectName = false;
            break;
            }

        case TOK_COLON: {
            if (!stack.size() || expectName || !expectColon)
                throw runtime_error("json parse: : stack empty or want name");

            UniValue *top = stack.back();
            if (top->getType() != VOBJ)
                throw runtime_error("json parse: : parent not object");

            expectColon = false;
            break;
            }

        case TOK_COMMA: {
            if (!stack.size() || expectName || expectColon ||
                (last_tok == TOK_COMMA) || (last_tok == TOK_ARR_OPEN))
                throw runtime_error("json parse: , stack empty or want name");

            UniValue *top = stack.back();
            if (top->getType() == VOBJ)
                expectName = true;
            break;
            }

        case TOK_KW_NULL:
        case TOK_KW_TRUE:
        case TOK_KW_FALSE: {
            if (!stack.size() || expectName || expectColon)
                throw runtime_error("json parse: ntf stack empty or want name");

            VType utyp;
            switch (tok) {
            case TOK_KW_NULL:  utyp = VNULL; break;
            case TOK_KW_TRUE:  utyp = VTRUE; break;
            case TOK_KW_FALSE: utyp = VFALSE; break;
            default: assert(0); break;
            }

            UniValue tmpVal(utyp);
            UniValue *top = stack.back();
            top->values.push_back(tmpVal);

            break;
            }

        case TOK_NUMBER: {
            if (!stack.size() || expectName || expectColon)
                throw runtime_error("json parse digits: stack empty or want name");

            UniValue tmpVal(VNUM, tokenVal);
            UniValue *top = stack.back();
            top->values.push_back(tmpVal);

            break;
            }

        case TOK_STRING: {
            if (!stack.size())
                throw runtime_error("json parse string: stack empty");

            UniValue *top = stack.back();

            if (expectName) {
                top->keys.push_back(tokenVal);
                expectName = false;
                expectColon = true;
            } else {
                UniValue tmpVal(VSTR, tokenVal);
                top->values.push_back(tmpVal);
            }

            break;
            }

        default:
            throw runtime_error("json parse string: illegal expression");
        }
    }

    if (stack.size() != 0) {
        char msg[64];
        sprintf(msg, "json parse: too many toplevel obj, %lu", stack.size());
        throw runtime_error(msg);
    }
}

<commit_msg>univalue_read: make check more strict, fix test<commit_after>
#include <string.h>
#include <vector>
#include <stdio.h>
#include <cassert>
#include <stdexcept>
#include "univalue.h"

using namespace std;

enum tokentype {
    TOK_ERR        = -1,
    TOK_NONE       = 0,                           // eof
    TOK_OBJ_OPEN,
    TOK_OBJ_CLOSE,
    TOK_ARR_OPEN,
    TOK_ARR_CLOSE,
    TOK_COLON,
    TOK_COMMA,
    TOK_KW_NULL,
    TOK_KW_TRUE,
    TOK_KW_FALSE,
    TOK_NUMBER,
    TOK_STRING,
};

enum tokentype getJsonToken(string& tokenVal, unsigned int& consumed,
                            const char *raw)
{
    tokenVal.clear();
    consumed = 0;

    const char *rawStart = raw;

    while ((*raw) && (isspace(*raw)))             // skip whitespace
        raw++;

    switch (*raw) {

    case 0:
        return TOK_NONE;

    case '{':
        raw++;
        consumed = (raw - rawStart);
        return TOK_OBJ_OPEN;
    case '}':
        raw++;
        consumed = (raw - rawStart);
        return TOK_OBJ_CLOSE;
    case '[':
        raw++;
        consumed = (raw - rawStart);
        return TOK_ARR_OPEN;
    case ']':
        raw++;
        consumed = (raw - rawStart);
        return TOK_ARR_CLOSE;

    case ':':
        raw++;
        consumed = (raw - rawStart);
        return TOK_COLON;
    case ',':
        raw++;
        consumed = (raw - rawStart);
        return TOK_COMMA;

    case 'n':
    case 't':
    case 'f':
        if (!strncmp(raw, "null", 4)) {
            raw += 4;
            consumed = (raw - rawStart);
            return TOK_KW_NULL;
        } else if (!strncmp(raw, "true", 4)) {
            raw += 4;
            consumed = (raw - rawStart);
            return TOK_KW_TRUE;
        } else if (!strncmp(raw, "false", 5)) {
            raw += 5;
            consumed = (raw - rawStart);
            return TOK_KW_FALSE;
        } else
            return TOK_ERR;

    case '-':
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9': {
        // part 1: int
        string numStr;

        const char *first = raw;

        const char *firstDigit = first;
        if (!isdigit(*firstDigit))
            firstDigit++;
        if ((*firstDigit == '0') && isdigit(firstDigit[1]))
            return TOK_ERR;

        numStr += *raw;                       // copy first char
        raw++;

        if ((*first == '-') && (!isdigit(*raw)))
            return TOK_ERR;

        while ((*raw) && isdigit(*raw)) {     // copy digits
            numStr += *raw;
            raw++;
        }

        // part 2: frac
        if (*raw == '.') {
            numStr += *raw;                   // copy .
            raw++;

            if (!isdigit(*raw))
                return TOK_ERR;
            while ((*raw) && isdigit(*raw)) { // copy digits
                numStr += *raw;
                raw++;
            }
        }

        // part 3: exp
        if (*raw == 'e' || *raw == 'E') {
            numStr += *raw;                   // copy E
            raw++;

            if (*raw == '-' || *raw == '+') { // copy +/-
                numStr += *raw;
                raw++;
            }

            if (!isdigit(*raw))
                return TOK_ERR;
            while ((*raw) && isdigit(*raw)) { // copy digits
                numStr += *raw;
                raw++;
            }
        }

        tokenVal = numStr;
        consumed = (raw - rawStart);
        return TOK_NUMBER;
        }

    case '"': {
        raw++;                                // skip "

        string valStr;

        while (*raw) {
            if (*raw < 0x20)
                return TOK_ERR;

            else if (*raw == '\\') {
                raw++;                        // skip backslash

                switch (*raw) {
                case '"':  valStr += "\""; break;
                case '\\': valStr += "\\"; break;
                case '/':  valStr += "/"; break;
                case 'b':  valStr += "\b"; break;
                case 'f':  valStr += "\f"; break;
                case 'n':  valStr += "\n"; break;
                case 'r':  valStr += "\r"; break;
                case 't':  valStr += "\t"; break;
                case 'u':
                    // TODO: not supported yet
                    assert(0);
                    break;
                default:
                    return TOK_ERR;

                }

                raw++;                        // skip esc'd char
            }

            else if (*raw == '"') {
                raw++;                        // skip "
                break;                        // stop scanning
            }

            else {
                valStr += *raw;
                raw++;
            }
        }

        tokenVal = valStr;
        consumed = (raw - rawStart);
        return TOK_STRING;
        }

    default:
        return TOK_ERR;
    }
}

void UniValue::read(const char *raw)
{
    clear();

    bool expectName = false;
    bool expectColon = false;
    vector<UniValue*> stack;

    enum tokentype tok = TOK_NONE;
    enum tokentype last_tok = TOK_NONE;
    while (1) {
        last_tok = tok;

        string tokenVal;
        unsigned int consumed;
        tok = getJsonToken(tokenVal, consumed, raw);
        if (tok == TOK_NONE || tok == TOK_ERR)
            break;
        raw += consumed;

        switch (tok) {

        case TOK_OBJ_OPEN:
        case TOK_ARR_OPEN: {
            VType utyp = (tok == TOK_OBJ_OPEN ? VOBJ : VARR);
            if (!stack.size()) {
                if (utyp == VOBJ)
                    setObject();
                else
                    setArray();
                stack.push_back(this);
            } else {
                UniValue tmpVal(utyp);
                UniValue *top = stack.back();
                top->values.push_back(tmpVal);

                UniValue *newTop = &(top->values.back());
                stack.push_back(newTop);
            }

            if (utyp == VOBJ)
                expectName = true;
            break;
            }

        case TOK_OBJ_CLOSE:
        case TOK_ARR_CLOSE: {
            if (!stack.size() || expectColon || (last_tok == TOK_COMMA))
                throw runtime_error("json parse: unexpected }]");

            VType utyp = (tok == TOK_OBJ_CLOSE ? VOBJ : VARR);
            UniValue *top = stack.back();
            if (utyp != top->getType())
                throw runtime_error("json parse: mismatched }]");

            stack.pop_back();
            expectName = false;
            break;
            }

        case TOK_COLON: {
            if (!stack.size() || expectName || !expectColon)
                throw runtime_error("json parse: : stack empty or want name");

            UniValue *top = stack.back();
            if (top->getType() != VOBJ)
                throw runtime_error("json parse: : parent not object");

            expectColon = false;
            break;
            }

        case TOK_COMMA: {
            if (!stack.size() || expectName || expectColon ||
                (last_tok == TOK_COMMA) || (last_tok == TOK_ARR_OPEN))
                throw runtime_error("json parse: , stack empty or want name");

            UniValue *top = stack.back();
            if (top->getType() == VOBJ)
                expectName = true;
            break;
            }

        case TOK_KW_NULL:
        case TOK_KW_TRUE:
        case TOK_KW_FALSE: {
            if (!stack.size() || expectName || expectColon)
                throw runtime_error("json parse: ntf stack empty or want name");

            VType utyp;
            switch (tok) {
            case TOK_KW_NULL:  utyp = VNULL; break;
            case TOK_KW_TRUE:  utyp = VTRUE; break;
            case TOK_KW_FALSE: utyp = VFALSE; break;
            default: assert(0); break;
            }

            UniValue tmpVal(utyp);
            UniValue *top = stack.back();
            top->values.push_back(tmpVal);

            break;
            }

        case TOK_NUMBER: {
            if (!stack.size() || expectName || expectColon)
                throw runtime_error("json parse digits: stack empty or want name");

            UniValue tmpVal(VNUM, tokenVal);
            UniValue *top = stack.back();
            top->values.push_back(tmpVal);

            break;
            }

        case TOK_STRING: {
            if (!stack.size())
                throw runtime_error("json parse string: stack empty");

            UniValue *top = stack.back();

            if (expectName) {
                top->keys.push_back(tokenVal);
                expectName = false;
                expectColon = true;
            } else {
                UniValue tmpVal(VSTR, tokenVal);
                top->values.push_back(tmpVal);
            }

            break;
            }

        default:
            throw runtime_error("json parse string: illegal expression");
        }
    }

    if (stack.size() != 0) {
        char msg[64];
        sprintf(msg, "json parse: too many toplevel obj, %lu", stack.size());
        throw runtime_error(msg);
    }
}

<|endoftext|>


<commit_before>//===- X86EvexToVex.cpp ---------------------------------------------------===//
// Compress EVEX instructions to VEX encoding when possible to reduce code size
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
/// This file defines the pass that goes over all AVX-512 instructions which
/// are encoded using the EVEX prefix and if possible replaces them by their
/// corresponding VEX encoding which is usually shorter by 2 bytes.
/// EVEX instructions may be encoded via the VEX prefix when the AVX-512
/// instruction has a corresponding AVX/AVX2 opcode and when it does not
/// use the xmm or the mask registers or xmm/ymm registers with indexes
/// higher than 15.
/// The pass applies code reduction on the generated code for AVX-512 instrs.
//
//===----------------------------------------------------------------------===//

#include "InstPrinter/X86InstComments.h"
#include "MCTargetDesc/X86BaseInfo.h"
#include "X86.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/Pass.h"
#include <cassert>
#include <cstdint>

using namespace llvm;

// Including the generated EVEX2VEX tables.
struct X86EvexToVexCompressTableEntry {
  uint16_t EvexOpcode;
  uint16_t VexOpcode;
};
#include "X86GenEVEX2VEXTables.inc"

#define EVEX2VEX_DESC "Compressing EVEX instrs to VEX encoding when possible"
#define EVEX2VEX_NAME "x86-evex-to-vex-compress"

#define DEBUG_TYPE EVEX2VEX_NAME

namespace {

class EvexToVexInstPass : public MachineFunctionPass {

  /// X86EvexToVexCompressTable - Evex to Vex encoding opcode map.
  using EvexToVexTableType = DenseMap<unsigned, uint16_t>;
  EvexToVexTableType EvexToVex128Table;
  EvexToVexTableType EvexToVex256Table;

  /// For EVEX instructions that can be encoded using VEX encoding, replace
  /// them by the VEX encoding in order to reduce size.
  bool CompressEvexToVexImpl(MachineInstr &MI) const;

  /// For initializing the hash map tables of all AVX-512 EVEX
  /// corresponding to AVX/AVX2 opcodes.
  void AddTableEntry(EvexToVexTableType &EvexToVexTable, uint16_t EvexOp,
                     uint16_t VexOp);

public:
  static char ID;

  EvexToVexInstPass() : MachineFunctionPass(ID) {
    initializeEvexToVexInstPassPass(*PassRegistry::getPassRegistry());

    // Initialize the EVEX to VEX 128 table map.
    for (X86EvexToVexCompressTableEntry Entry : X86EvexToVex128CompressTable) {
      AddTableEntry(EvexToVex128Table, Entry.EvexOpcode, Entry.VexOpcode);
    }

    // Initialize the EVEX to VEX 256 table map.
    for (X86EvexToVexCompressTableEntry Entry : X86EvexToVex256CompressTable) {
      AddTableEntry(EvexToVex256Table, Entry.EvexOpcode, Entry.VexOpcode);
    }
  }

  StringRef getPassName() const override { return EVEX2VEX_DESC; }

  /// Loop over all of the basic blocks, replacing EVEX instructions
  /// by equivalent VEX instructions when possible for reducing code size.
  bool runOnMachineFunction(MachineFunction &MF) override;

  // This pass runs after regalloc and doesn't support VReg operands.
  MachineFunctionProperties getRequiredProperties() const override {
    return MachineFunctionProperties().set(
        MachineFunctionProperties::Property::NoVRegs);
  }

private:
  /// Machine instruction info used throughout the class.
  const X86InstrInfo *TII;
};

} // end anonymous namespace

char EvexToVexInstPass::ID = 0;

bool EvexToVexInstPass::runOnMachineFunction(MachineFunction &MF) {
  TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();

  const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();
  if (!ST.hasAVX512())
    return false;

  bool Changed = false;

  /// Go over all basic blocks in function and replace
  /// EVEX encoded instrs by VEX encoding when possible.
  for (MachineBasicBlock &MBB : MF) {

    // Traverse the basic block.
    for (MachineInstr &MI : MBB)
      Changed |= CompressEvexToVexImpl(MI);
  }

  return Changed;
}

void EvexToVexInstPass::AddTableEntry(EvexToVexTableType &EvexToVexTable,
                                      uint16_t EvexOp, uint16_t VexOp) {
  EvexToVexTable[EvexOp] = VexOp;
}

static bool usesExtendedRegister(const MachineInstr &MI) {
  auto isHiRegIdx = [](unsigned Reg) {
    // Check for XMM register with indexes between 16 - 31.
    if (Reg >= X86::XMM16 && Reg <= X86::XMM31)
      return true;

    // Check for YMM register with indexes between 16 - 31.
    if (Reg >= X86::YMM16 && Reg <= X86::YMM31)
      return true;

    return false;
  };

  // Check that operands are not ZMM regs or
  // XMM/YMM regs with hi indexes between 16 - 31.
  for (const MachineOperand &MO : MI.explicit_operands()) {
    if (!MO.isReg())
      continue;

    unsigned Reg = MO.getReg();

    assert(!(Reg >= X86::ZMM0 && Reg <= X86::ZMM31) &&
           "ZMM instructions should not be in the EVEX->VEX tables");

    if (isHiRegIdx(Reg))
      return true;
  }

  return false;
}

// Do any custom cleanup needed to finalize the conversion.
static bool performCustomAdjustments(MachineInstr &MI, unsigned NewOpc) {
  (void)NewOpc;
  unsigned Opc = MI.getOpcode();
  switch (Opc) {
  case X86::VALIGNDZ128rri:
  case X86::VALIGNDZ128rmi:
  case X86::VALIGNQZ128rri:
  case X86::VALIGNQZ128rmi: {
    assert((NewOpc == X86::VPALIGNRrri || NewOpc == X86::VPALIGNRrmi) &&
           "Unexpected new opcode!");
    unsigned Scale = (Opc == X86::VALIGNQZ128rri ||
                      Opc == X86::VALIGNQZ128rmi) ? 8 : 4;
    MachineOperand &Imm = MI.getOperand(MI.getNumExplicitOperands()-1);
    Imm.setImm(Imm.getImm() * Scale);
    break;
  }
  case X86::VSHUFF32X4Z256rmi:
  case X86::VSHUFF32X4Z256rri:
  case X86::VSHUFF64X2Z256rmi:
  case X86::VSHUFF64X2Z256rri:
  case X86::VSHUFI32X4Z256rmi:
  case X86::VSHUFI32X4Z256rri:
  case X86::VSHUFI64X2Z256rmi:
  case X86::VSHUFI64X2Z256rri: {
    assert((NewOpc == X86::VPERM2F128rr || NewOpc == X86::VPERM2I128rr ||
            NewOpc == X86::VPERM2F128rm || NewOpc == X86::VPERM2I128rm) &&
           "Unexpected new opcode!");
    MachineOperand &Imm = MI.getOperand(MI.getNumExplicitOperands()-1);
    int64_t ImmVal = Imm.getImm();
    // Set bit 5, move bit 1 to bit 4, copy bit 0.
    Imm.setImm(0x20 | ((ImmVal & 2) << 3) | (ImmVal & 1));
    break;
  }
  case X86::VRNDSCALEPDZ128rri:
  case X86::VRNDSCALEPDZ128rmi:
  case X86::VRNDSCALEPSZ128rri:
  case X86::VRNDSCALEPSZ128rmi:
  case X86::VRNDSCALEPDZ256rri:
  case X86::VRNDSCALEPDZ256rmi:
  case X86::VRNDSCALEPSZ256rri:
  case X86::VRNDSCALEPSZ256rmi:
  case X86::VRNDSCALESDZr:
  case X86::VRNDSCALESDZm:
  case X86::VRNDSCALESSZr:
  case X86::VRNDSCALESSZm:
  case X86::VRNDSCALESDZr_Int:
  case X86::VRNDSCALESDZm_Int:
  case X86::VRNDSCALESSZr_Int:
  case X86::VRNDSCALESSZm_Int:
    const MachineOperand &Imm = MI.getOperand(MI.getNumExplicitOperands()-1);
    int64_t ImmVal = Imm.getImm();
    // Ensure that only bits 3:0 of the immediate are used.
    if ((ImmVal & 0xf) != ImmVal)
      return false;
    break;
  }

  return true;
}

// For EVEX instructions that can be encoded using VEX encoding
// replace them by the VEX encoding in order to reduce size.
bool EvexToVexInstPass::CompressEvexToVexImpl(MachineInstr &MI) const {
  // VEX format.
  // # of bytes: 0,2,3  1      1      0,1   0,1,2,4  0,1
  //  [Prefixes] [VEX]  OPCODE ModR/M [SIB] [DISP]  [IMM]
  //
  // EVEX format.
  //  # of bytes: 4    1      1      1      4       / 1         1
  //  [Prefixes]  EVEX Opcode ModR/M [SIB] [Disp32] / [Disp8*N] [Immediate]

  const MCInstrDesc &Desc = MI.getDesc();

  // Check for EVEX instructions only.
  if ((Desc.TSFlags & X86II::EncodingMask) != X86II::EVEX)
    return false;

  // Check for EVEX instructions with mask or broadcast as in these cases
  // the EVEX prefix is needed in order to carry this information
  // thus preventing the transformation to VEX encoding.
  if (Desc.TSFlags & (X86II::EVEX_K | X86II::EVEX_B))
    return false;

  // Check for non EVEX_V512 instrs only.
  // EVEX_V512 instr: bit EVEX_L2 = 1; bit VEX_L = 0.
  if ((Desc.TSFlags & X86II::EVEX_L2) && !(Desc.TSFlags & X86II::VEX_L))
    return false;

  // EVEX_V128 instr: bit EVEX_L2 = 0, bit VEX_L = 0.
  bool IsEVEX_V128 =
      (!(Desc.TSFlags & X86II::EVEX_L2) && !(Desc.TSFlags & X86II::VEX_L));

  // EVEX_V256 instr: bit EVEX_L2 = 0, bit VEX_L = 1.
  bool IsEVEX_V256 =
      (!(Desc.TSFlags & X86II::EVEX_L2) && (Desc.TSFlags & X86II::VEX_L));

  unsigned NewOpc = 0;

  // Check for EVEX_V256 instructions.
  if (IsEVEX_V256) {
    // Search for opcode in the EvexToVex256 table.
    auto It = EvexToVex256Table.find(MI.getOpcode());
    if (It != EvexToVex256Table.end())
      NewOpc = It->second;
  }
  // Check for EVEX_V128 or Scalar instructions.
  else if (IsEVEX_V128) {
    // Search for opcode in the EvexToVex128 table.
    auto It = EvexToVex128Table.find(MI.getOpcode());
    if (It != EvexToVex128Table.end())
      NewOpc = It->second;
  }

  if (!NewOpc)
    return false;

  if (usesExtendedRegister(MI))
    return false;

  if (!performCustomAdjustments(MI, NewOpc))
    return false;

  MI.setDesc(TII->get(NewOpc));
  MI.setAsmPrinterFlag(X86::AC_EVEX_2_VEX);
  return true;
}

INITIALIZE_PASS(EvexToVexInstPass, EVEX2VEX_NAME, EVEX2VEX_DESC, false, false)

FunctionPass *llvm::createX86EvexToVexInsts() {
  return new EvexToVexInstPass();
}
<commit_msg>[X86] Simplify the TSFlags checking code in EvexToVexInstPass. NFCI<commit_after>//===- X86EvexToVex.cpp ---------------------------------------------------===//
// Compress EVEX instructions to VEX encoding when possible to reduce code size
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
/// This file defines the pass that goes over all AVX-512 instructions which
/// are encoded using the EVEX prefix and if possible replaces them by their
/// corresponding VEX encoding which is usually shorter by 2 bytes.
/// EVEX instructions may be encoded via the VEX prefix when the AVX-512
/// instruction has a corresponding AVX/AVX2 opcode and when it does not
/// use the xmm or the mask registers or xmm/ymm registers with indexes
/// higher than 15.
/// The pass applies code reduction on the generated code for AVX-512 instrs.
//
//===----------------------------------------------------------------------===//

#include "InstPrinter/X86InstComments.h"
#include "MCTargetDesc/X86BaseInfo.h"
#include "X86.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/Pass.h"
#include <cassert>
#include <cstdint>

using namespace llvm;

// Including the generated EVEX2VEX tables.
struct X86EvexToVexCompressTableEntry {
  uint16_t EvexOpcode;
  uint16_t VexOpcode;
};
#include "X86GenEVEX2VEXTables.inc"

#define EVEX2VEX_DESC "Compressing EVEX instrs to VEX encoding when possible"
#define EVEX2VEX_NAME "x86-evex-to-vex-compress"

#define DEBUG_TYPE EVEX2VEX_NAME

namespace {

class EvexToVexInstPass : public MachineFunctionPass {

  /// X86EvexToVexCompressTable - Evex to Vex encoding opcode map.
  using EvexToVexTableType = DenseMap<unsigned, uint16_t>;
  EvexToVexTableType EvexToVex128Table;
  EvexToVexTableType EvexToVex256Table;

  /// For EVEX instructions that can be encoded using VEX encoding, replace
  /// them by the VEX encoding in order to reduce size.
  bool CompressEvexToVexImpl(MachineInstr &MI) const;

  /// For initializing the hash map tables of all AVX-512 EVEX
  /// corresponding to AVX/AVX2 opcodes.
  void AddTableEntry(EvexToVexTableType &EvexToVexTable, uint16_t EvexOp,
                     uint16_t VexOp);

public:
  static char ID;

  EvexToVexInstPass() : MachineFunctionPass(ID) {
    initializeEvexToVexInstPassPass(*PassRegistry::getPassRegistry());

    // Initialize the EVEX to VEX 128 table map.
    for (X86EvexToVexCompressTableEntry Entry : X86EvexToVex128CompressTable) {
      AddTableEntry(EvexToVex128Table, Entry.EvexOpcode, Entry.VexOpcode);
    }

    // Initialize the EVEX to VEX 256 table map.
    for (X86EvexToVexCompressTableEntry Entry : X86EvexToVex256CompressTable) {
      AddTableEntry(EvexToVex256Table, Entry.EvexOpcode, Entry.VexOpcode);
    }
  }

  StringRef getPassName() const override { return EVEX2VEX_DESC; }

  /// Loop over all of the basic blocks, replacing EVEX instructions
  /// by equivalent VEX instructions when possible for reducing code size.
  bool runOnMachineFunction(MachineFunction &MF) override;

  // This pass runs after regalloc and doesn't support VReg operands.
  MachineFunctionProperties getRequiredProperties() const override {
    return MachineFunctionProperties().set(
        MachineFunctionProperties::Property::NoVRegs);
  }

private:
  /// Machine instruction info used throughout the class.
  const X86InstrInfo *TII;
};

} // end anonymous namespace

char EvexToVexInstPass::ID = 0;

bool EvexToVexInstPass::runOnMachineFunction(MachineFunction &MF) {
  TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();

  const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();
  if (!ST.hasAVX512())
    return false;

  bool Changed = false;

  /// Go over all basic blocks in function and replace
  /// EVEX encoded instrs by VEX encoding when possible.
  for (MachineBasicBlock &MBB : MF) {

    // Traverse the basic block.
    for (MachineInstr &MI : MBB)
      Changed |= CompressEvexToVexImpl(MI);
  }

  return Changed;
}

void EvexToVexInstPass::AddTableEntry(EvexToVexTableType &EvexToVexTable,
                                      uint16_t EvexOp, uint16_t VexOp) {
  EvexToVexTable[EvexOp] = VexOp;
}

static bool usesExtendedRegister(const MachineInstr &MI) {
  auto isHiRegIdx = [](unsigned Reg) {
    // Check for XMM register with indexes between 16 - 31.
    if (Reg >= X86::XMM16 && Reg <= X86::XMM31)
      return true;

    // Check for YMM register with indexes between 16 - 31.
    if (Reg >= X86::YMM16 && Reg <= X86::YMM31)
      return true;

    return false;
  };

  // Check that operands are not ZMM regs or
  // XMM/YMM regs with hi indexes between 16 - 31.
  for (const MachineOperand &MO : MI.explicit_operands()) {
    if (!MO.isReg())
      continue;

    unsigned Reg = MO.getReg();

    assert(!(Reg >= X86::ZMM0 && Reg <= X86::ZMM31) &&
           "ZMM instructions should not be in the EVEX->VEX tables");

    if (isHiRegIdx(Reg))
      return true;
  }

  return false;
}

// Do any custom cleanup needed to finalize the conversion.
static bool performCustomAdjustments(MachineInstr &MI, unsigned NewOpc) {
  (void)NewOpc;
  unsigned Opc = MI.getOpcode();
  switch (Opc) {
  case X86::VALIGNDZ128rri:
  case X86::VALIGNDZ128rmi:
  case X86::VALIGNQZ128rri:
  case X86::VALIGNQZ128rmi: {
    assert((NewOpc == X86::VPALIGNRrri || NewOpc == X86::VPALIGNRrmi) &&
           "Unexpected new opcode!");
    unsigned Scale = (Opc == X86::VALIGNQZ128rri ||
                      Opc == X86::VALIGNQZ128rmi) ? 8 : 4;
    MachineOperand &Imm = MI.getOperand(MI.getNumExplicitOperands()-1);
    Imm.setImm(Imm.getImm() * Scale);
    break;
  }
  case X86::VSHUFF32X4Z256rmi:
  case X86::VSHUFF32X4Z256rri:
  case X86::VSHUFF64X2Z256rmi:
  case X86::VSHUFF64X2Z256rri:
  case X86::VSHUFI32X4Z256rmi:
  case X86::VSHUFI32X4Z256rri:
  case X86::VSHUFI64X2Z256rmi:
  case X86::VSHUFI64X2Z256rri: {
    assert((NewOpc == X86::VPERM2F128rr || NewOpc == X86::VPERM2I128rr ||
            NewOpc == X86::VPERM2F128rm || NewOpc == X86::VPERM2I128rm) &&
           "Unexpected new opcode!");
    MachineOperand &Imm = MI.getOperand(MI.getNumExplicitOperands()-1);
    int64_t ImmVal = Imm.getImm();
    // Set bit 5, move bit 1 to bit 4, copy bit 0.
    Imm.setImm(0x20 | ((ImmVal & 2) << 3) | (ImmVal & 1));
    break;
  }
  case X86::VRNDSCALEPDZ128rri:
  case X86::VRNDSCALEPDZ128rmi:
  case X86::VRNDSCALEPSZ128rri:
  case X86::VRNDSCALEPSZ128rmi:
  case X86::VRNDSCALEPDZ256rri:
  case X86::VRNDSCALEPDZ256rmi:
  case X86::VRNDSCALEPSZ256rri:
  case X86::VRNDSCALEPSZ256rmi:
  case X86::VRNDSCALESDZr:
  case X86::VRNDSCALESDZm:
  case X86::VRNDSCALESSZr:
  case X86::VRNDSCALESSZm:
  case X86::VRNDSCALESDZr_Int:
  case X86::VRNDSCALESDZm_Int:
  case X86::VRNDSCALESSZr_Int:
  case X86::VRNDSCALESSZm_Int:
    const MachineOperand &Imm = MI.getOperand(MI.getNumExplicitOperands()-1);
    int64_t ImmVal = Imm.getImm();
    // Ensure that only bits 3:0 of the immediate are used.
    if ((ImmVal & 0xf) != ImmVal)
      return false;
    break;
  }

  return true;
}

// For EVEX instructions that can be encoded using VEX encoding
// replace them by the VEX encoding in order to reduce size.
bool EvexToVexInstPass::CompressEvexToVexImpl(MachineInstr &MI) const {
  // VEX format.
  // # of bytes: 0,2,3  1      1      0,1   0,1,2,4  0,1
  //  [Prefixes] [VEX]  OPCODE ModR/M [SIB] [DISP]  [IMM]
  //
  // EVEX format.
  //  # of bytes: 4    1      1      1      4       / 1         1
  //  [Prefixes]  EVEX Opcode ModR/M [SIB] [Disp32] / [Disp8*N] [Immediate]

  const MCInstrDesc &Desc = MI.getDesc();

  // Check for EVEX instructions only.
  if ((Desc.TSFlags & X86II::EncodingMask) != X86II::EVEX)
    return false;

  // Check for EVEX instructions with mask or broadcast as in these cases
  // the EVEX prefix is needed in order to carry this information
  // thus preventing the transformation to VEX encoding.
  if (Desc.TSFlags & (X86II::EVEX_K | X86II::EVEX_B))
    return false;

  // Check for EVEX instructions with L2 set. These instructions are 512-bits
  // and can't be converted to VEX.
  if (Desc.TSFlags & X86II::EVEX_L2)
    return false;

  unsigned NewOpc = 0;

  // Use the VEX.L bit to select the 128 or 256-bit table.
  if (Desc.TSFlags & X86II::VEX_L) {
    // Search for opcode in the EvexToVex256 table.
    auto It = EvexToVex256Table.find(MI.getOpcode());
    if (It != EvexToVex256Table.end())
      NewOpc = It->second;
  } else {
    // Search for opcode in the EvexToVex128 table.
    auto It = EvexToVex128Table.find(MI.getOpcode());
    if (It != EvexToVex128Table.end())
      NewOpc = It->second;
  }

  if (!NewOpc)
    return false;

  if (usesExtendedRegister(MI))
    return false;

  if (!performCustomAdjustments(MI, NewOpc))
    return false;

  MI.setDesc(TII->get(NewOpc));
  MI.setAsmPrinterFlag(X86::AC_EVEX_2_VEX);
  return true;
}

INITIALIZE_PASS(EvexToVexInstPass, EVEX2VEX_NAME, EVEX2VEX_DESC, false, false)

FunctionPass *llvm::createX86EvexToVexInsts() {
  return new EvexToVexInstPass();
}
<|endoftext|>


<commit_before>//===- X86InstrInfo.cpp - X86 Instruction Information ---------------===//
//
// This file contains the X86 implementation of the MachineInstrInfo class.
//
//===----------------------------------------------------------------------===//

#include "X86InstrInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include <iostream>

// X86Insts - Turn the InstrInfo.def file into a bunch of instruction
// descriptors
//
static const MachineInstrDescriptor X86Insts[] = {
#define I(ENUM, NAME, BASEOPCODE, FLAGS, TSFLAGS)   \
             { NAME,                    \
               -1, /* Always vararg */  \
               ((TSFLAGS) & X86II::Void) ? -1 : 0,  /* Result is in 0 */ \
               0, false, 0, 0, TSFLAGS, FLAGS, TSFLAGS },
#include "X86InstrInfo.def"
};

X86InstrInfo::X86InstrInfo()
  : MachineInstrInfo(X86Insts, sizeof(X86Insts)/sizeof(X86Insts[0]), 0) {
}

static unsigned char BaseOpcodes[] = {
#define I(ENUM, NAME, BASEOPCODE, FLAGS, TSFLAGS) BASEOPCODE,
#include "X86InstrInfo.def"
};

// getBaseOpcodeFor - This function returns the "base" X86 opcode for the
// specified opcode number.
//
unsigned char X86InstrInfo::getBaseOpcodeFor(unsigned Opcode) const {
  assert(Opcode < sizeof(BaseOpcodes)/sizeof(BaseOpcodes[0]) &&
         "Opcode out of range!");
  return BaseOpcodes[Opcode];
}
<commit_msg>Added -*- C++ -*- mode to the comments.<commit_after>//===- X86InstrInfo.cpp - X86 Instruction Information -----------*- C++ -*-===//
//
// This file contains the X86 implementation of the MachineInstrInfo class.
//
//===----------------------------------------------------------------------===//

#include "X86InstrInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include <iostream>

// X86Insts - Turn the InstrInfo.def file into a bunch of instruction
// descriptors
//
static const MachineInstrDescriptor X86Insts[] = {
#define I(ENUM, NAME, BASEOPCODE, FLAGS, TSFLAGS)   \
             { NAME,                    \
               -1, /* Always vararg */  \
               ((TSFLAGS) & X86II::Void) ? -1 : 0,  /* Result is in 0 */ \
               0, false, 0, 0, TSFLAGS, FLAGS, TSFLAGS },
#include "X86InstrInfo.def"
};

X86InstrInfo::X86InstrInfo()
  : MachineInstrInfo(X86Insts, sizeof(X86Insts)/sizeof(X86Insts[0]), 0) {
}

static unsigned char BaseOpcodes[] = {
#define I(ENUM, NAME, BASEOPCODE, FLAGS, TSFLAGS) BASEOPCODE,
#include "X86InstrInfo.def"
};

// getBaseOpcodeFor - This function returns the "base" X86 opcode for the
// specified opcode number.
//
unsigned char X86InstrInfo::getBaseOpcodeFor(unsigned Opcode) const {
  assert(Opcode < sizeof(BaseOpcodes)/sizeof(BaseOpcodes[0]) &&
         "Opcode out of range!");
  return BaseOpcodes[Opcode];
}
<|endoftext|>


<commit_before>// RUN: %check_clang_tidy %s hicpp-exception-baseclass %t

namespace std {
class exception {};
} // namespace std

class derived_exception : public std::exception {};
class non_derived_exception {};

void problematic() {
  try {
    throw int(42); // Built in is not allowed
// CHECK-MESSAGES: [[@LINE-1]]:5: warning: throwing an exception whose type is not derived from 'std::exception'
  } catch (int e) {
  }
  throw int(42); // Bad
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type is not derived from 'std::exception'

  try {
    throw non_derived_exception(); // Some class is not allowed
// CHECK-MESSAGES: [[@LINE-1]]:5: warning: throwing an exception whose type is not derived from 'std::exception'
// CHECK-MESSAGES: 8:1: note: type defined here
  } catch (non_derived_exception &e) {
  }
  throw non_derived_exception(); // Bad
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type is not derived from 'std::exception'
// CHECK-MESSAGES: 8:1: note: type defined here
}

void allowed_throws() {
  try {
    throw std::exception(); // Ok
  } catch (std::exception &e) { // Ok
  }
  throw std::exception();

  try {
    throw derived_exception(); // Ok
  } catch (derived_exception &e) { // Ok
  }
  throw derived_exception(); // Ok
}
<commit_msg>Enable exceptions for this test case to speculatively fix the build bots.<commit_after>// RUN: %check_clang_tidy %s hicpp-exception-baseclass %t -- -- -fcxx-exceptions

namespace std {
class exception {};
} // namespace std

class derived_exception : public std::exception {};
class non_derived_exception {};

void problematic() {
  try {
    throw int(42); // Built in is not allowed
// CHECK-MESSAGES: [[@LINE-1]]:5: warning: throwing an exception whose type is not derived from 'std::exception'
  } catch (int e) {
  }
  throw int(42); // Bad
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type is not derived from 'std::exception'

  try {
    throw non_derived_exception(); // Some class is not allowed
// CHECK-MESSAGES: [[@LINE-1]]:5: warning: throwing an exception whose type is not derived from 'std::exception'
// CHECK-MESSAGES: 8:1: note: type defined here
  } catch (non_derived_exception &e) {
  }
  throw non_derived_exception(); // Bad
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type is not derived from 'std::exception'
// CHECK-MESSAGES: 8:1: note: type defined here
}

void allowed_throws() {
  try {
    throw std::exception(); // Ok
  } catch (std::exception &e) { // Ok
  }
  throw std::exception();

  try {
    throw derived_exception(); // Ok
  } catch (derived_exception &e) { // Ok
  }
  throw derived_exception(); // Ok
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*! @file
	@brief  NSF Player クラス @n
			Copyright 2017 Kunihito Hiramatsu
	@author 平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "main.hpp"
#include "utils/file_io.hpp"
#include "utils/format.hpp"

#include "emu/cpu/nes6502.h"
#include "emu/nes/nes_rom.h"
#include "emu/nes/nes_mmc.h"

namespace emu {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	nesemu シーン・クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class nsfplay {

		struct info_t {
			char		sig_[5];		///< シグネチュア（"MESM", 0x1A）
			uint8_t		version_;		///< バージョン番号 (現在は 01h 固定)
			uint8_t		music_num_;		///< 全曲数 (1=1 全１曲, 2=2 全２曲, etc)
			uint8_t		start_no_;		///< 開始曲番号 (1=1番目の曲, 2=2番目の曲, etc)
			uint16_t	load_org_;		///< (low/high) ロード開始アドレス (8000 〜 FFFF)
			uint16_t	init_org_;		///< (low/high) 初期化開始アドレス (8000 〜 FFFF)
			uint16_t	play_org_;		///< (low/high) 曲再生開始アドレス (8000 〜 FFFF)
			char		m_name_[32];	///< 曲名（null終端文字列）
			char		m_artist_[32];	///< アーティスト名[分かっている場合のみ]（null終端文字列）
			char		m_cpr_[32];		///< 著作者情報（null終端文字列）
			uint16_t	speed_ntsc_;	///< (low/high) スピード, 1 / 1,000,000回/秒 NTSC用 (曲の再生の項目参照)
			uint8_t		init_bank_[8];	///< バンク切り替え用初期値 (後述の説明参照, FDSの項目)
			uint16_t	speed_pal_;		///< (low/high) スピード, 1 / 1,000,000回/秒 PAL用  (曲の再生の項目参照)
			uint8_t		pal_ntsc_;		///< PAL/NTSCの設定:
										///  bit 0    : 0の時、NTSCモード
										///  bit 0    : 1の時、PALモード
										///  bit 1    : 1の時、デュアルモード（PAL/NTSC）
										///  bit 2〜7 : 未使用（0で固定）
			uint8_t		ext_chip_;		///< 拡張サウンドチップサポート
										///  bit 0    : 1の時、VRCVI
										///  bit 1    : 1の時、VRCVII
										///  bit 2    : 1の時、FDS Sound
										///  bit 3    : 1の時、MMC5 audio
										///  bit 4    : 1の時、Namco 106
										///  bit 5    : 1の時、Sunsoft FME-07
										///  bit 6・7 : 将来の拡張用（0で固定）
			uint8_t		ext_[4];		///< 拡張用バイト列（0で固定）

			bool probe() const {
				if(sig_[0] == 'N' && sig_[1] == 'E' && sig_[2] == 'S' && sig_[3] == 'M' && sig_[4] == 0x1a) {
					return true;
				} else {
					return false;
				}
			}

			void list() const {
				utils::format("NSF file:\n");
				utils::format("Music Num: %d\n") % static_cast<uint32_t>(music_num_);
				utils::format("Load ORG: %04X\n") % static_cast<uint32_t>(load_org_);
				utils::format("Init ORG: %04X\n") % static_cast<uint32_t>(init_org_);
				utils::format("Play ORG: %04X\n") % static_cast<uint32_t>(play_org_);
			}
		};

		info_t		info_;

		nes6502_context* 	cpu_;
		nes6502_memread		read_handler_[MAX_MEM_HANDLERS];
		nes6502_memwrite	write_handler_[MAX_MEM_HANDLERS];

		rominfo_t			rominfo_;
		mmc_t*				mmc_;

		uint8_t		nes_ram_[0x800];

		std::vector<uint8_t>	code_;

		static uint8_t ram_read_(uint32_t address) {
///			return nes_ram_[address & (sizeof(nes_ram_) - 1)];
			return 0;
		}

		static void ram_write_(uint32_t address, uint8_t value) {
///			nes_ram_[address & (sizeof(nes_ram_) - 1)] = value;
		}

		static uint8_t read_protect_(uint32_t address) {
			return 0xFF;
		}

		static void write_protect_(uint32_t address, uint8_t value) {
		}

		void build_address_handlers_()
		{
			memset(read_handler_, 0, sizeof(read_handler_));
			memset(write_handler_, 0, sizeof(write_handler_));

			int num = 0;

			read_handler_[num].min_range = 0x0800;
			read_handler_[num].max_range = 0x1FFF;
			read_handler_[num].read_func = ram_read_;
			num++;
			read_handler_[num].min_range = 0x4000;
			read_handler_[num].max_range = 0x4015;
			read_handler_[num].read_func = apu_read;
			num++;

			const mapintf_t *intf = mmc_->intf;
#if 0
			if(intf->sound_ext) {
				if(NULL != intf->sound_ext->mem_read) {
					for(int i = 0; num < MAX_MEM_HANDLERS; i++, num++) {
						if(NULL == intf->sound_ext->mem_read[count].read_func) break;
						memcpy(&read_handler_[num], &intf->sound_ext->mem_read[count], sizeof(nes6502_memread));
					}
				}
			}
#endif
			if(NULL != intf->mem_read) {
				for(int i = 0; num < MAX_MEM_HANDLERS; i++, num++) {
					if(NULL == intf->mem_read[i].read_func) break;
					memcpy(&read_handler_[num], &intf->mem_read[i], sizeof(nes6502_memread));
				}
			}

			read_handler_[num].min_range = 0x4018;
			read_handler_[num].max_range = 0x5FFF;
			read_handler_[num].read_func = read_protect_;
			num++;
			read_handler_[num].min_range = -1;
			read_handler_[num].max_range = -1;
			read_handler_[num].read_func = NULL;

			num = 0;
			write_handler_[num].min_range = 0x0800;
			write_handler_[num].max_range = 0x1FFF;
			write_handler_[num].write_func = ram_write_;
			num++;
			write_handler_[num].min_range = 0x4000;
			write_handler_[num].max_range = 0x4013;
			write_handler_[num].write_func = apu_write;
			num++;
			write_handler_[num].min_range = 0x4015;
			write_handler_[num].max_range = 0x4015;
			write_handler_[num].write_func = apu_write;
			num++;
#if 0
			if(intf->sound_ext) {
				if(NULL != intf->sound_ext->mem_write) {
					for(count = 0; num_handlers < MAX_MEM_HANDLERS; count++, num_handlers++) {
						if(NULL == intf->sound_ext->mem_write[count].write_func) break;
						memcpy(&nes_.writehandler[num_handlers], &intf->sound_ext->mem_write[count],
							sizeof(nes6502_memwrite));
					}
				}
			}
#endif
			if(NULL != intf->mem_write) {
				for(int i = 0; num < MAX_MEM_HANDLERS; i++, num++) {
					if(NULL == intf->mem_write[i].write_func) break;
					memcpy(&write_handler_[num], &intf->mem_write[i], sizeof(nes6502_memwrite));
				}
			}

			write_handler_[num].min_range = 0x4018;
			write_handler_[num].max_range = 0x5FFF;
			write_handler_[num].write_func = write_protect_;
			num++;
			write_handler_[num].min_range = 0x8000;
			write_handler_[num].max_range = 0xFFFF;
			write_handler_[num].write_func = write_protect_;
			num++;
			write_handler_[num].min_range = -1;
			write_handler_[num].max_range = -1;
			write_handler_[num].write_func = NULL;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		nsfplay() : info_(), cpu_(nullptr) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  オープン
			@param[in]	filename	ファイル名
			@return エラーなら「false」
		*/
		//-----------------------------------------------------------------//
		bool open(const std::string& filename)
		{
			utils::file_io fi;
			if(!fi.open(filename, "rb")) {
				return false;
			}

			auto fsz = fi.get_file_size();

			if(fi.read(&info_, 128) != 128) {
				return false;
			}
			if(!info_.probe()) {
				return false;
			}

			uint32_t csz = fsz - 128;
			code_.resize(csz);
			if(fi.read(&code_[0], csz) != csz) {
				return false;
			}

			info_.list();

			rominfo_.rom = &code_[0];
			rominfo_.vrom = NULL;
			rominfo_.sram = nes_ram_;
			rominfo_.vram = NULL;

			rominfo_.rom_banks = csz / 0x4000;
			rominfo_.vrom_banks = 0;
			rominfo_.sram_banks = sizeof(nes_ram_) / 0x400;
			rominfo_.vram_banks = 0;

			rominfo_.mapper_number = 0;

			nes6502_init();
			cpu_ = nes6502_getcontext();

			mmc_create(&rominfo_);
			mmc_ = mmc_getcontext();

			cpu_->mem_page[0] = nes_ram_;
			cpu_->read_handler  = read_handler_;
			cpu_->write_handler = write_handler_;

			nes6502_setup_page();

			build_address_handlers_();

			nes6502_reset();

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  サービス
		*/
		//-----------------------------------------------------------------//
		void service()
		{

		}

	};
}
<commit_msg>update<commit_after>#pragma once
//=====================================================================//
/*! @file
	@brief  NSF Player クラス @n
			Copyright 2017 Kunihito Hiramatsu
	@author 平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "main.hpp"
#include "utils/file_io.hpp"
#include "utils/format.hpp"

#include "emu/cpu/nes6502.h"
#include "emu/nes/nes_rom.h"
#include "emu/nes/nes_mmc.h"

namespace emu {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	nesemu シーン・クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class nsfplay {

		struct info_t {
			char		sig_[5];		///< シグネチュア（"MESM", 0x1A）
			uint8_t		version_;		///< バージョン番号 (現在は 01h 固定)
			uint8_t		music_num_;		///< 全曲数 (1=1 全１曲, 2=2 全２曲, etc)
			uint8_t		start_no_;		///< 開始曲番号 (1=1番目の曲, 2=2番目の曲, etc)
			uint16_t	load_org_;		///< (low/high) ロード開始アドレス (8000 〜 FFFF)
			uint16_t	init_org_;		///< (low/high) 初期化開始アドレス (8000 〜 FFFF)
			uint16_t	play_org_;		///< (low/high) 曲再生開始アドレス (8000 〜 FFFF)
			char		m_name_[32];	///< 曲名（null終端文字列）
			char		m_artist_[32];	///< アーティスト名[分かっている場合のみ]（null終端文字列）
			char		m_cpr_[32];		///< 著作者情報（null終端文字列）
			uint16_t	speed_ntsc_;	///< (low/high) スピード, 1 / 1,000,000回/秒 NTSC用 (曲の再生の項目参照)
			uint8_t		init_bank_[8];	///< バンク切り替え用初期値 (後述の説明参照, FDSの項目)
			uint16_t	speed_pal_;		///< (low/high) スピード, 1 / 1,000,000回/秒 PAL用  (曲の再生の項目参照)
			uint8_t		pal_ntsc_;		///< PAL/NTSCの設定:
										///  bit 0    : 0の時、NTSCモード
										///  bit 0    : 1の時、PALモード
										///  bit 1    : 1の時、デュアルモード（PAL/NTSC）
										///  bit 2〜7 : 未使用（0で固定）
			uint8_t		ext_chip_;		///< 拡張サウンドチップサポート
										///  bit 0    : 1の時、VRCVI
										///  bit 1    : 1の時、VRCVII
										///  bit 2    : 1の時、FDS Sound
										///  bit 3    : 1の時、MMC5 audio
										///  bit 4    : 1の時、Namco 106
										///  bit 5    : 1の時、Sunsoft FME-07
										///  bit 6・7 : 将来の拡張用（0で固定）
			uint8_t		ext_[4];		///< 拡張用バイト列（0で固定）

			bool probe() const {
				if(sig_[0] == 'N' && sig_[1] == 'E' && sig_[2] == 'S' && sig_[3] == 'M' && sig_[4] == 0x1a) {
					return true;
				} else {
					return false;
				}
			}

			void list() const {
				utils::format("NSF file:\n");
				utils::format("Music Num: %d\n") % static_cast<uint32_t>(music_num_);
				utils::format("Load ORG: %04X\n") % static_cast<uint32_t>(load_org_);
				utils::format("Init ORG: %04X\n") % static_cast<uint32_t>(init_org_);
				utils::format("Play ORG: %04X\n") % static_cast<uint32_t>(play_org_);
			}
		};

		info_t		info_;

		nes6502_context* 	cpu_;
		nes6502_memread		read_handler_[MAX_MEM_HANDLERS];
		nes6502_memwrite	write_handler_[MAX_MEM_HANDLERS];

		rominfo_t			rominfo_;
		mmc_t*				mmc_;

		uint8_t				nes_ram_[0x800];

		std::vector<uint8_t>	code_;

		static uint8_t ram_read_(uint32_t address) {
///			return nes_ram_[address & (sizeof(nes_ram_) - 1)];
			return 0;
		}

		static void ram_write_(uint32_t address, uint8_t value) {
///			nes_ram_[address & (sizeof(nes_ram_) - 1)] = value;
		}

		static uint8_t read_protect_(uint32_t address) {
			return 0xFF;
		}

		static void write_protect_(uint32_t address, uint8_t value) {
		}

		void build_address_handlers_()
		{
			memset(read_handler_, 0, sizeof(read_handler_));
			memset(write_handler_, 0, sizeof(write_handler_));

			int num = 0;

			read_handler_[num].min_range = 0x0800;
			read_handler_[num].max_range = 0x1FFF;
			read_handler_[num].read_func = ram_read_;
			num++;
			read_handler_[num].min_range = 0x4000;
			read_handler_[num].max_range = 0x4015;
			read_handler_[num].read_func = apu_read;
			num++;

			const mapintf_t *intf = mmc_->intf;
#if 0
			if(intf->sound_ext) {
				if(NULL != intf->sound_ext->mem_read) {
					for(int i = 0; num < MAX_MEM_HANDLERS; i++, num++) {
						if(NULL == intf->sound_ext->mem_read[count].read_func) break;
						memcpy(&read_handler_[num], &intf->sound_ext->mem_read[count], sizeof(nes6502_memread));
					}
				}
			}
#endif
			if(NULL != intf->mem_read) {
				for(int i = 0; num < MAX_MEM_HANDLERS; i++, num++) {
					if(NULL == intf->mem_read[i].read_func) break;
					memcpy(&read_handler_[num], &intf->mem_read[i], sizeof(nes6502_memread));
				}
			}

			read_handler_[num].min_range = 0x4018;
			read_handler_[num].max_range = 0x5FFF;
			read_handler_[num].read_func = read_protect_;
			num++;
			read_handler_[num].min_range = -1;
			read_handler_[num].max_range = -1;
			read_handler_[num].read_func = NULL;

			num = 0;
			write_handler_[num].min_range = 0x0800;
			write_handler_[num].max_range = 0x1FFF;
			write_handler_[num].write_func = ram_write_;
			num++;
			write_handler_[num].min_range = 0x4000;
			write_handler_[num].max_range = 0x4013;
			write_handler_[num].write_func = apu_write;
			num++;
			write_handler_[num].min_range = 0x4015;
			write_handler_[num].max_range = 0x4015;
			write_handler_[num].write_func = apu_write;
			num++;
#if 0
			if(intf->sound_ext) {
				if(NULL != intf->sound_ext->mem_write) {
					for(count = 0; num_handlers < MAX_MEM_HANDLERS; count++, num_handlers++) {
						if(NULL == intf->sound_ext->mem_write[count].write_func) break;
						memcpy(&nes_.writehandler[num_handlers], &intf->sound_ext->mem_write[count],
							sizeof(nes6502_memwrite));
					}
				}
			}
#endif
			if(NULL != intf->mem_write) {
				for(int i = 0; num < MAX_MEM_HANDLERS; i++, num++) {
					if(NULL == intf->mem_write[i].write_func) break;
					memcpy(&write_handler_[num], &intf->mem_write[i], sizeof(nes6502_memwrite));
				}
			}

			write_handler_[num].min_range = 0x4018;
			write_handler_[num].max_range = 0x5FFF;
			write_handler_[num].write_func = write_protect_;
			num++;
			write_handler_[num].min_range = 0x8000;
			write_handler_[num].max_range = 0xFFFF;
			write_handler_[num].write_func = write_protect_;
			num++;
			write_handler_[num].min_range = -1;
			write_handler_[num].max_range = -1;
			write_handler_[num].write_func = NULL;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		nsfplay() : info_(), cpu_(nullptr) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  オープン
			@param[in]	filename	ファイル名
			@return エラーなら「false」
		*/
		//-----------------------------------------------------------------//
		bool open(const std::string& filename)
		{
			utils::file_io fi;
			if(!fi.open(filename, "rb")) {
				return false;
			}

			auto fsz = fi.get_file_size();

			if(fi.read(&info_, 128) != 128) {
				return false;
			}
			if(!info_.probe()) {
				return false;
			}

			uint32_t csz = fsz - 128;
			code_.resize(csz);
			if(fi.read(&code_[0], csz) != csz) {
				return false;
			}

			info_.list();

			rominfo_.rom = &code_[0];
			rominfo_.vrom = NULL;
			rominfo_.sram = nes_ram_;
			rominfo_.vram = NULL;

			rominfo_.rom_banks = csz / 0x4000;
			rominfo_.vrom_banks = 0;
			rominfo_.sram_banks = sizeof(nes_ram_) / 0x400;
			rominfo_.vram_banks = 0;

			rominfo_.mapper_number = 0;

			nes6502_init();
			cpu_ = nes6502_getcontext();

			mmc_create(&rominfo_);
			mmc_ = mmc_getcontext();

			cpu_->mem_page[0] = nes_ram_;
			cpu_->read_handler  = read_handler_;
			cpu_->write_handler = write_handler_;

			nes6502_setup_page();

			build_address_handlers_();

			nes6502_reset();

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  サービス
		*/
		//-----------------------------------------------------------------//
		void service()
		{

		}

	};
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

using namespace std;

vector<int> multply(vector<int> a, vector<int> b);
vector<int> pow_(vector<int> base, int expnt);

int main() {
  string s;
  int n;

  while (cin >> s >> n) {
    vector<int> number;
    int dot_idx = s.find(".");
    int rev_dot_pos = s.size() - 1 - dot_idx;
    string int_part = s.substr(0, dot_idx);
    string dec_part = s.substr(dot_idx + 1, s.size() - dot_idx - 1);
    if (int_part.compare("0") == 0)
      s = dec_part;
    else
      s = int_part + dec_part;

    cout << s << endl;

    for (int i = s.size() - 1; i >= 0; i--)
      number.push_back(s[i] - '0');

    number = pow_(number, n);

    int rev_dot_pos_new = rev_dot_pos * n;
    //int dot_pos_new     = number.size() - rev_dot_pos_new - 1;
    int dot_pos_new     = number.size() - rev_dot_pos_new;
    int cnt = 0;
    int i = number.size() - 1;
    string res;
    while (cnt < number.size() + 1) {
      if (cnt == dot_pos_new)
        res += ".";
      else
        res += number[i--];

      cnt++;
    }

    cout << res;
    /*
    for (int i = number.size() - 1; i >= 0; i--)
      cout << number[i];
    */

    cout << endl;
  }
}

vector<int> multiply(vector<int> a, vector<int> b) {
  vector<int> res(a.size() + b.size(), 0);

  for (int i = 0; i < a.size(); i++)
    for (int j = 0; j < b.size(); j++)
      res[i + j] += a[i] * b[j];

  for (int i = 0; i < res.size() - 1; i++) {
    res[i + 1] += res[i] / 10;
    res[i] %= 10;
  }

  while (!res.empty() && res.back() == 0)
    res.pop_back();

  if (res.empty())
    res.push_back(0);

  return res;
}

vector<int> pow_(vector<int> base, int expnt) {
  vector<int> res = vector<int>(1, 1);

  while (expnt) {
    if (expnt & 1) res = multiply(res, base);
    base = multiply(base, base);
    expnt >>= 1;
  }

  return res;
}
<commit_msg>need more debugging<commit_after>#include <iostream>
#include <vector>

using namespace std;

vector<int> multply(vector<int> a, vector<int> b);
vector<int> pow_(vector<int> base, int expnt);

int main() {
  string s;
  int n;

  while (cin >> s >> n) {
    vector<int> number;
    int dot_idx = s.find(".");

    if (dot_idx == -1) {

      for (int i = s.size() - 1; i >= 0; i--)
        number.push_back(s[i] - '0');

      number = pow_(number, n);

      for (int i = number.size() - 1; i >= 0; i--)
        cout << number[i];

      cout << endl;

    }
    else {
      int rev_dot_pos = s.size() - 1 - dot_idx;
      string int_part = s.substr(0, dot_idx);
      string dec_part = s.substr(dot_idx + 1, s.size() - dot_idx - 1);
      if (int_part.compare("0") == 0)
        s = dec_part;
      else
        s = int_part + dec_part;

      for (int i = s.size() - 1; i >= 0; i--)
        number.push_back(s[i] - '0');

      number = pow_(number, n);

      int rev_dot_pos_new = rev_dot_pos * n;
      //int dot_pos_new     = number.size() - rev_dot_pos_new - 1;
      if (number.size() < rev_dot_pos_new) {
        int i = 0;
        while (number.size() + i < rev_dot_pos_new)
          number.push_back(0);
      }
      int dot_pos_new     = number.size() - rev_dot_pos_new;

      int cnt = 0;

      int non_zero_pos = 0;
      while (number[non_zero_pos] == 0)
        non_zero_pos++;

      int i = number.size() - 1;
      while (i >= non_zero_pos) {
        if (cnt == dot_pos_new)
          cout << ".";
        else
          cout << number[i--];

        cnt++;
      }

      /*
      for (int i = number.size() - 1; i >= 0; i--)
        cout << number[i];
      */

      cout << endl;
    }
  }
}

vector<int> multiply(vector<int> a, vector<int> b) {
  vector<int> res(a.size() + b.size(), 0);

  for (int i = 0; i < a.size(); i++)
    for (int j = 0; j < b.size(); j++)
      res[i + j] += a[i] * b[j];

  for (int i = 0; i < res.size() - 1; i++) {
    res[i + 1] += res[i] / 10;
    res[i] %= 10;
  }

  if (res[res.size() - 1] == 0)
    res.pop_back();

  while (!res.empty() && res.back() == 0)
    res.pop_back();

  if (res.empty())
    res.push_back(0);

  return res;
}

vector<int> pow_(vector<int> base, int expnt) {
  vector<int> res = vector<int>(1, 1);

  while (expnt) {
    if (expnt & 1) res = multiply(res, base);
    base = multiply(base, base);
    expnt >>= 1;
  }

  return res;
}
<|endoftext|>


<commit_before>/********************************************************************
* Description: interpl.hh
*   Mechanism for building lists of arbitrary NML messages, used by
*   the canonical interface and interpreter to pass planned sequences
*   to the HME.
*
*   Derived from a work by Fred Proctor & Will Shackleford
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#ifndef INTERP_LIST_HH
#define INTERP_LIST_HH

#define MAX_NML_COMMAND_SIZE 1000

// these go on the interp list
struct NML_INTERP_LIST_NODE {
    int line_number;		// line number it was on
    union _dummy_union {
	int i;
	long l;
	double d;
	float f;
	long long ll;
	long double ld;
    } dummy;			// paranoid alignment variable.

    union _command_union {
	char commandbuf[MAX_NML_COMMAND_SIZE];	// the NML command;
	int i;
	long l;
	double d;
	float f;
	long long ll;
	long double ld;
    } command;
};

// here's the interp list itself
class NML_INTERP_LIST {
  public:
    NML_INTERP_LIST();
    ~NML_INTERP_LIST();

    int set_line_number(int line);
    int get_line_number();
    int append(NMLmsg &);
    int append(NMLmsg *);
    NMLmsg *get();
    NMLmsg *get_and_next();
    NMLmsg *get_and_last();
    NMLmsg *get_by_lineno(int lineno);
    bool is_eol();
    void clear();
    void print();
    int len();

  private:
    class LinkedList * linked_list_ptr;
    NML_INTERP_LIST_NODE temp_node;	// filled in and put on the list
    int next_line_number;	// line number used to fill temp_node
    int line_number;		// line number of node from get()
};

extern NML_INTERP_LIST interp_list;	/* NML Union, for interpreter */

#endif
<commit_msg>interpl.hh: add *get_next_lineno()<commit_after>/********************************************************************
* Description: interpl.hh
*   Mechanism for building lists of arbitrary NML messages, used by
*   the canonical interface and interpreter to pass planned sequences
*   to the HME.
*
*   Derived from a work by Fred Proctor & Will Shackleford
*
* Author:
* License: GPL Version 2
* System: Linux
*
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#ifndef INTERP_LIST_HH
#define INTERP_LIST_HH

#define MAX_NML_COMMAND_SIZE 1000

// these go on the interp list
struct NML_INTERP_LIST_NODE {
    int line_number;		// line number it was on
    union _dummy_union {
	int i;
	long l;
	double d;
	float f;
	long long ll;
	long double ld;
    } dummy;			// paranoid alignment variable.

    union _command_union {
	char commandbuf[MAX_NML_COMMAND_SIZE];	// the NML command;
	int i;
	long l;
	double d;
	float f;
	long long ll;
	long double ld;
    } command;
};

// here's the interp list itself
class NML_INTERP_LIST {
  public:
    NML_INTERP_LIST();
    ~NML_INTERP_LIST();

    int set_line_number(int line);
    int get_line_number();
    int append(NMLmsg &);
    int append(NMLmsg *);
    NMLmsg *get();
    NMLmsg *get_and_next();
    NMLmsg *get_and_last();
    NMLmsg *get_by_lineno(int lineno);
    NMLmsg *get_next_lineno(int lineno);
    bool is_eol();
    void clear();
    void print();
    int len();

  private:
    class LinkedList * linked_list_ptr;
    NML_INTERP_LIST_NODE temp_node;	// filled in and put on the list
    int next_line_number;	// line number used to fill temp_node
    int line_number;		// line number of node from get()
};

extern NML_INTERP_LIST interp_list;	/* NML Union, for interpreter */

#endif
<|endoftext|>