<commit_before>//===- PowerPCRegisterInfo.cpp - PowerPC Register Information ---*- C++ -*-===//
//
//                     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 file contains the PowerPC implementation of the MRegisterInfo class.
//
//===----------------------------------------------------------------------===//

#include "PowerPC.h"
#include "PowerPCRegisterInfo.h"
#include "PowerPCInstrBuilder.h"
#include "llvm/Constants.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetMachineImpls.h"
#include "Support/CommandLine.h"
#include "Support/STLExtras.h"
using namespace llvm;

PowerPCRegisterInfo::PowerPCRegisterInfo()
  : PowerPCGenRegisterInfo(PPC32::ADJCALLSTACKDOWN,
                           PPC32::ADJCALLSTACKUP) {}

static unsigned getIdx(const TargetRegisterClass *RC) {
	if (RC == PowerPC::GPRCRegisterClass) {
		switch (RC->getSize()) {
			default: assert(0 && "Invalid data size!");
			case 1:  return 0;
			case 2:  return 1;
			case 4:  return 2;
		}
	}
	else if (RC == PowerPC::FPRCRegisterClass) {
		switch (RC->getSize()) {
			default: assert(0 && "Invalid data size!");
			case 4:  return 3;
			case 8:  return 4;
		}
	}
	abort();
}

int PowerPCRegisterInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
                                         MachineBasicBlock::iterator MI,
                                         unsigned SrcReg, int FrameIdx,
                                         const TargetRegisterClass *RC) const {
	static const unsigned Opcode[] =
	{ PPC32::STB, PPC32::STH, PPC32::STW, PPC32::STFS, PPC32::STFD };

	unsigned OC = Opcode[getIdx(RC)];
	MBB.insert(MI, addFrameReference(BuildMI(OC, 3).addReg(SrcReg),FrameIdx));
	return 1;
}

int PowerPCRegisterInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
                                          MachineBasicBlock::iterator MI,
                                          unsigned DestReg, int FrameIdx,
                                          const TargetRegisterClass *RC) const{
	static const unsigned Opcode[] =

	{ PPC32::LBZ, PPC32::LHZ, PPC32::LWZ, PPC32::LFS, PPC32::LFD };
	unsigned OC = Opcode[getIdx(RC)];
	MBB.insert(MI, addFrameReference(BuildMI(OC, 2, DestReg), FrameIdx));
	return 1;
}

int PowerPCRegisterInfo::copyRegToReg(MachineBasicBlock &MBB,
                                  MachineBasicBlock::iterator MI,
                                  unsigned DestReg, unsigned SrcReg,
                                  const TargetRegisterClass *RC) const {
	MachineInstr *I;

	if(RC == PowerPC::GPRCRegisterClass) {
		I = BuildMI(PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
	} else if (RC == PowerPC::FPRCRegisterClass) {
		I = BuildMI(PPC32::FMR, 1, DestReg).addReg(SrcReg);
	} else {
		std::cerr << "Attempt to copy register that is not GPR or FPR";
		abort();
	}
	MBB.insert(MI, I);
	return 1;
}

//===----------------------------------------------------------------------===//
// Stack Frame Processing methods
//===----------------------------------------------------------------------===//

// hasFP - Return true if the specified function should have a dedicated frame
// pointer register.  This is true if the function has variable sized allocas or
// if frame pointer elimination is disabled.
//
static bool hasFP(MachineFunction &MF) {
	return NoFramePointerElim || MF.getFrameInfo()->hasVarSizedObjects();
}

void PowerPCRegisterInfo::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                              MachineBasicBlock::iterator I) const {
	if (hasFP(MF)) {
		// If we have a frame pointer, turn the adjcallstackdown instruction into a
		// 'sub r1, r1, <amt>' and the adjcallstackup instruction into 'add r1, r1, <amt>'
		MachineInstr *Old = I;
		int Amount = Old->getOperand(0).getImmedValue();
		if (Amount != 0) {
			// We need to keep the stack aligned properly.  To do this, we round the
			// amount of space needed for the outgoing arguments up to the next
			// alignment boundary.
			unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
			Amount = (Amount+Align-1)/Align*Align;

			MachineInstr *New;
			if (Old->getOpcode() == PPC32::ADJCALLSTACKDOWN) {
				New=BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1).addSImm(-Amount);
			} else {
				assert(Old->getOpcode() == PPC32::ADJCALLSTACKUP);
				New=BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1).addSImm(Amount);
			}

			// Replace the pseudo instruction with a new instruction...
			MBB.insert(I, New);
		}
	}

	MBB.erase(I);
}

void
PowerPCRegisterInfo::eliminateFrameIndex(MachineFunction &MF,
                                         MachineBasicBlock::iterator II) const {
  unsigned i = 0;
  MachineInstr &MI = *II;
  while (!MI.getOperand(i).isFrameIndex()) {
    ++i;
    assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
  }

  int FrameIndex = MI.getOperand(i).getFrameIndex();

  // This must be part of a four operand memory reference.  Replace the
  // FrameIndex with base register with GPR1.
  MI.SetMachineOperandReg(i, PPC32::R1);

  // Take into account whether its an add or mem instruction
  if (i == 2) i--;

  // Now add the frame object offset to the offset from r1.
  int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
               MI.getOperand(i).getImmedValue()+4;

  if (!hasFP(MF))
    Offset += MF.getFrameInfo()->getStackSize();

  MI.SetMachineOperandConst(i-1, MachineOperand::MO_SignExtendedImmed, Offset);
  std::cout << "offset = " << Offset << std::endl;
}

void PowerPCRegisterInfo::processFunctionBeforeFrameFinalized(
    MachineFunction &MF) const {
	// Do Nothing
}

void PowerPCRegisterInfo::emitPrologue(MachineFunction &MF) const {
	MachineBasicBlock &MBB = MF.front();   // Prolog goes in entry BB
	MachineBasicBlock::iterator MBBI = MBB.begin();
	MachineFrameInfo *MFI = MF.getFrameInfo();
	MachineInstr *MI;

	// Get the number of bytes to allocate from the FrameInfo
	unsigned NumBytes = MFI->getStackSize();

    if (MFI->hasCalls()) {
		// When we have no frame pointer, we reserve argument space for call sites
		// in the function immediately on entry to the current function.  This
		// eliminates the need for add/sub brackets around call sites.
		//
		NumBytes += MFI->getMaxCallFrameSize();

		// Round the size to a multiple of the alignment (don't forget the 4 byte
		// offset though).
		unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
		NumBytes = ((NumBytes+4)+Align-1)/Align*Align - 4;

		// Store the incoming LR so it is preserved across calls
		MI= BuildMI(PPC32::MovePCtoLR, 0, PPC32::LR).addReg(PPC32::LR);
		MBB.insert(MBBI, MI);
		MI= BuildMI(PPC32::MFSPR, 1, PPC32::R0).addImm(8);
		MBB.insert(MBBI, MI);
		MI= BuildMI(PPC32::STW, 3).addReg(PPC32::R0).addSImm(8).addReg(PPC32::R1);
		MBB.insert(MBBI, MI);
    }

    // Update frame info to pretend that this is part of the stack...
    MFI->setStackSize(NumBytes);

	// adjust stack pointer: r1 -= numbytes
	if (NumBytes) {
		MI= BuildMI(PPC32::STWU, 2, PPC32::R1).addImm(-NumBytes).addReg(PPC32::R1);
		MBB.insert(MBBI, MI);
    }
}

void PowerPCRegisterInfo::emitEpilogue(MachineFunction &MF,
                                       MachineBasicBlock &MBB) const {
	const MachineFrameInfo *MFI = MF.getFrameInfo();
	MachineBasicBlock::iterator MBBI = prior(MBB.end());
	MachineInstr *MI;
	assert(MBBI->getOpcode() == PPC32::BLR &&
		   "Can only insert epilog into returning blocks");

	// Get the number of bytes allocated from the FrameInfo...
    unsigned NumBytes = MFI->getStackSize();

    // adjust stack pointer back: r1 += numbytes
    if (NumBytes) {
		MI =BuildMI(PPC32::ADDI, 2, PPC32::R1)
		.addReg(PPC32::R1)
		.addSImm(NumBytes);
		MBB.insert(MBBI, MI);
    }

	// If we have calls, restore the LR value before we branch to it
    if (MFI->hasCalls()) {
		MI = BuildMI(PPC32::LWZ, 2, PPC32::R0).addSImm(8).addReg(PPC32::R1);
		MBB.insert(MBBI, MI);
		MI = BuildMI(PPC32::MTLR, 1).addReg(PPC32::R0);
		MBB.insert(MBBI, MI);
	}
}

#include "PowerPCGenRegisterInfo.inc"

const TargetRegisterClass*
PowerPCRegisterInfo::getRegClassForType(const Type* Ty) const {
	switch (Ty->getTypeID()) {
		case Type::LongTyID:
		case Type::ULongTyID: assert(0 && "Long values can't fit in registers!");
		default:              assert(0 && "Invalid type to getClass!");
		case Type::BoolTyID:
		case Type::SByteTyID:
		case Type::UByteTyID:
		case Type::ShortTyID:
		case Type::UShortTyID:
		case Type::IntTyID:
		case Type::UIntTyID:
		case Type::PointerTyID: return &GPRCInstance;

		case Type::FloatTyID:
		case Type::DoubleTyID: return &FPRCInstance;
	}
}

<commit_msg>* Tabs to spaces * Send an error message to std::cerr before abort()ing<commit_after>//===- PowerPCRegisterInfo.cpp - PowerPC Register Information ---*- C++ -*-===//
//
//                     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 file contains the PowerPC implementation of the MRegisterInfo class.
//
//===----------------------------------------------------------------------===//

#include "PowerPC.h"
#include "PowerPCRegisterInfo.h"
#include "PowerPCInstrBuilder.h"
#include "llvm/Constants.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetMachineImpls.h"
#include "Support/CommandLine.h"
#include "Support/STLExtras.h"
using namespace llvm;

PowerPCRegisterInfo::PowerPCRegisterInfo()
  : PowerPCGenRegisterInfo(PPC32::ADJCALLSTACKDOWN,
                           PPC32::ADJCALLSTACKUP) {}

static unsigned getIdx(const TargetRegisterClass *RC) {
  if (RC == PowerPC::GPRCRegisterClass) {
    switch (RC->getSize()) {
      default: assert(0 && "Invalid data size!");
      case 1:  return 0;
      case 2:  return 1;
      case 4:  return 2;
    }
  } else if (RC == PowerPC::FPRCRegisterClass) {
    switch (RC->getSize()) {
      default: assert(0 && "Invalid data size!");
      case 4:  return 3;
      case 8:  return 4;
    }
  }
  std::cerr << "Invalid register class to getIdx()!\n";
  abort();
}

int
PowerPCRegisterInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
                                         MachineBasicBlock::iterator MI,
                                         unsigned SrcReg, int FrameIdx,
                                         const TargetRegisterClass *RC) const {
  static const unsigned Opcode[] = {
    PPC32::STB, PPC32::STH, PPC32::STW, PPC32::STFS, PPC32::STFD
  };
  unsigned OC = Opcode[getIdx(RC)];
  MBB.insert(MI, addFrameReference(BuildMI(OC, 3).addReg(SrcReg),FrameIdx));
  return 1;
}

int PowerPCRegisterInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
                                          MachineBasicBlock::iterator MI,
                                          unsigned DestReg, int FrameIdx,
                                          const TargetRegisterClass *RC) const{
  static const unsigned Opcode[] = {
    PPC32::LBZ, PPC32::LHZ, PPC32::LWZ, PPC32::LFS, PPC32::LFD
  };
  unsigned OC = Opcode[getIdx(RC)];
  MBB.insert(MI, addFrameReference(BuildMI(OC, 2, DestReg), FrameIdx));
  return 1;
}

int PowerPCRegisterInfo::copyRegToReg(MachineBasicBlock &MBB,
                                      MachineBasicBlock::iterator MI,
                                      unsigned DestReg, unsigned SrcReg,
                                      const TargetRegisterClass *RC) const {
  MachineInstr *I;

  if (RC == PowerPC::GPRCRegisterClass) {
    I = BuildMI(PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
  } else if (RC == PowerPC::FPRCRegisterClass) {
    I = BuildMI(PPC32::FMR, 1, DestReg).addReg(SrcReg);
  } else {
    std::cerr << "Attempt to copy register that is not GPR or FPR";
    abort();
  }
  MBB.insert(MI, I);
  return 1;
}

//===----------------------------------------------------------------------===//
// Stack Frame Processing methods
//===----------------------------------------------------------------------===//

// hasFP - Return true if the specified function should have a dedicated frame
// pointer register.  This is true if the function has variable sized allocas or
// if frame pointer elimination is disabled.
//
static bool hasFP(MachineFunction &MF) {
  return NoFramePointerElim || MF.getFrameInfo()->hasVarSizedObjects();
}

void PowerPCRegisterInfo::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                              MachineBasicBlock::iterator I) const {
	if (hasFP(MF)) {
		// If we have a frame pointer, turn the adjcallstackdown instruction into a
		// 'sub r1, r1, <amt>' and the adjcallstackup instruction into 'add r1, r1, <amt>'
		MachineInstr *Old = I;
		int Amount = Old->getOperand(0).getImmedValue();
		if (Amount != 0) {
			// We need to keep the stack aligned properly.  To do this, we round the
			// amount of space needed for the outgoing arguments up to the next
			// alignment boundary.
			unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
			Amount = (Amount+Align-1)/Align*Align;

			MachineInstr *New;
			if (Old->getOpcode() == PPC32::ADJCALLSTACKDOWN) {
				New = BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1)
          .addSImm(-Amount);
			} else {
				assert(Old->getOpcode() == PPC32::ADJCALLSTACKUP);
				New = BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1)
          .addSImm(Amount);
			}

			// Replace the pseudo instruction with a new instruction...
			MBB.insert(I, New);
		}
	}

	MBB.erase(I);
}

void
PowerPCRegisterInfo::eliminateFrameIndex(MachineFunction &MF,
                                         MachineBasicBlock::iterator II) const {
  unsigned i = 0;
  MachineInstr &MI = *II;
  while (!MI.getOperand(i).isFrameIndex()) {
    ++i;
    assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
  }

  int FrameIndex = MI.getOperand(i).getFrameIndex();

  // This must be part of a four operand memory reference.  Replace the
  // FrameIndex with base register with GPR1.
  MI.SetMachineOperandReg(i, PPC32::R1);

  // Take into account whether its an add or mem instruction
  if (i == 2) i--;

  // Now add the frame object offset to the offset from r1.
  int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
               MI.getOperand(i).getImmedValue()+4;

  if (!hasFP(MF))
    Offset += MF.getFrameInfo()->getStackSize();

  MI.SetMachineOperandConst(i-1, MachineOperand::MO_SignExtendedImmed, Offset);
  std::cout << "offset = " << Offset << std::endl;
}

void
PowerPCRegisterInfo::processFunctionBeforeFrameFinalized(MachineFunction &MF)
  const {
  // Do Nothing
}

void PowerPCRegisterInfo::emitPrologue(MachineFunction &MF) const {
  MachineBasicBlock &MBB = MF.front();   // Prolog goes in entry BB
  MachineBasicBlock::iterator MBBI = MBB.begin();
  MachineFrameInfo *MFI = MF.getFrameInfo();
  MachineInstr *MI;

  // Get the number of bytes to allocate from the FrameInfo
  unsigned NumBytes = MFI->getStackSize();

  if (MFI->hasCalls()) {
    // When we have no frame pointer, we reserve argument space for call sites
    // in the function immediately on entry to the current function.  This
    // eliminates the need for add/sub brackets around call sites.
    //
    NumBytes += MFI->getMaxCallFrameSize();

    // Round the size to a multiple of the alignment (don't forget the 4 byte
    // offset though).
    unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
    NumBytes = ((NumBytes+4)+Align-1)/Align*Align - 4;

    // Store the incoming LR so it is preserved across calls
    MI = BuildMI(PPC32::MovePCtoLR, 0, PPC32::LR).addReg(PPC32::LR);
    MBB.insert(MBBI, MI);
    MI = BuildMI(PPC32::MFSPR, 1, PPC32::R0).addImm(8);
    MBB.insert(MBBI, MI);
    MI = BuildMI(PPC32::STW, 3).addReg(PPC32::R0).addSImm(8).addReg(PPC32::R1);
    MBB.insert(MBBI, MI);
  }

  // Update frame info to pretend that this is part of the stack...
  MFI->setStackSize(NumBytes);

  // adjust stack pointer: r1 -= numbytes
  if (NumBytes) {
    MI = BuildMI(PPC32::STWU, 2, PPC32::R1).addImm(-NumBytes).addReg(PPC32::R1);
    MBB.insert(MBBI, MI);
  }
}

void PowerPCRegisterInfo::emitEpilogue(MachineFunction &MF,
                                       MachineBasicBlock &MBB) const {
  const MachineFrameInfo *MFI = MF.getFrameInfo();
  MachineBasicBlock::iterator MBBI = prior(MBB.end());
  MachineInstr *MI;
  assert(MBBI->getOpcode() == PPC32::BLR &&
       "Can only insert epilog into returning blocks");

  // Get the number of bytes allocated from the FrameInfo...
  unsigned NumBytes = MFI->getStackSize();

  // adjust stack pointer back: r1 += numbytes
  if (NumBytes) {
    MI =BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1).addSImm(NumBytes);
    MBB.insert(MBBI, MI);
  }

  // If we have calls, restore the LR value before we branch to it
  if (MFI->hasCalls()) {
    MI = BuildMI(PPC32::LWZ, 2, PPC32::R0).addSImm(8).addReg(PPC32::R1);
    MBB.insert(MBBI, MI);
    MI = BuildMI(PPC32::MTLR, 1).addReg(PPC32::R0);
    MBB.insert(MBBI, MI);
  }
}

#include "PowerPCGenRegisterInfo.inc"

const TargetRegisterClass*
PowerPCRegisterInfo::getRegClassForType(const Type* Ty) const {
  switch (Ty->getTypeID()) {
    case Type::LongTyID:
    case Type::ULongTyID: assert(0 && "Long values can't fit in registers!");
    default:              assert(0 && "Invalid type to getClass!");
    case Type::BoolTyID:
    case Type::SByteTyID:
    case Type::UByteTyID:
    case Type::ShortTyID:
    case Type::UShortTyID:
    case Type::IntTyID:
    case Type::UIntTyID:
    case Type::PointerTyID: return &GPRCInstance;

    case Type::FloatTyID:
    case Type::DoubleTyID: return &FPRCInstance;
  }
}

<|endoftext|>


<commit_before>//===- PreSelection.cpp - Specialize LLVM code for target machine ---------===//
//
// This file defines the PreSelection pass which specializes LLVM code for a
// target machine, while remaining in legal portable LLVM form and
// preserving type information and type safety.  This is meant to enable
// dataflow optimizations on target-specific operations such as accesses to
// constants, globals, and array indexing.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/PreSelection.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Support/InstVisitor.h"
#include "llvm/Module.h"
#include "llvm/Constants.h"
#include "llvm/iMemory.h"
#include "llvm/iPHINode.h"
#include "llvm/iOther.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Pass.h"
#include "Support/CommandLine.h"
#include <algorithm>

namespace {
  //===--------------------------------------------------------------------===//
  // SelectDebugLevel - Allow command line control over debugging.
  //
  enum PreSelectDebugLevel_t {
    PreSelect_NoDebugInfo,
    PreSelect_PrintOutput,
  };

  // Enable Debug Options to be specified on the command line
  cl::opt<PreSelectDebugLevel_t>
  PreSelectDebugLevel("dpreselect", cl::Hidden,
     cl::desc("debug information for target-dependent pre-selection"),
     cl::values(
       clEnumValN(PreSelect_NoDebugInfo, "n", "disable debug output (default)"),
       clEnumValN(PreSelect_PrintOutput, "y", "print generated machine code"),
       /* default level = */ PreSelect_NoDebugInfo));

  //===--------------------------------------------------------------------===//
  // class ConstantPoolForModule:
  //
  // The pool of constants that must be emitted for a module.
  // This is a single pool for the entire module and is shared by
  // all invocations of the PreSelection pass for this module by putting
  // this as an annotation on the Module object.
  // A single GlobalVariable is created for each constant in the pool
  // representing the memory for that constant.
  //
  AnnotationID CPFM_AID(
                 AnnotationManager::getID("CodeGen::ConstantPoolForModule"));

  class ConstantPoolForModule : private Annotation {
    Module* myModule;
    std::map<const Constant*, GlobalVariable*> gvars;
    std::map<const Constant*, GlobalVariable*> origGVars;
    ConstantPoolForModule(Module* M);   // called only by annotation builder
    ConstantPoolForModule();                      // DO NOT IMPLEMENT
    void operator=(const ConstantPoolForModule&); // DO NOT IMPLEMENT
  public:
    static ConstantPoolForModule& get(Module* M) {
      ConstantPoolForModule* cpool =
        (ConstantPoolForModule*) M->getAnnotation(CPFM_AID);
      if (cpool == NULL) // create a new annotation and add it to the Module
        M->addAnnotation(cpool = new ConstantPoolForModule(M));
      return *cpool;
    }

    GlobalVariable* getGlobalForConstant(Constant* CV) {
      std::map<const Constant*, GlobalVariable*>::iterator I = gvars.find(CV);
      if (I != gvars.end())
        return I->second;               // global exists so return it
      return addToConstantPool(CV);     // create a new global and return it
    }

    GlobalVariable*  addToConstantPool(Constant* CV) {
      GlobalVariable*& GV = gvars[CV];  // handle to global var entry in map
      if (GV == NULL)
        { // check if a global constant already existed; otherwise create one
          std::map<const Constant*, GlobalVariable*>::iterator PI =
            origGVars.find(CV);
          if (PI != origGVars.end())
            GV = PI->second;            // put in map
          else
            {
              GV = new GlobalVariable(CV->getType(), true, //put in map
                                      GlobalValue::InternalLinkage, CV);
              myModule->getGlobalList().push_back(GV); // GV owned by module now
            }
        }
      return GV;
    }
  };

  /* ctor */
  ConstantPoolForModule::ConstantPoolForModule(Module* M)
    : Annotation(CPFM_AID), myModule(M)
  {
    // Build reverse map for pre-existing global constants so we can find them
    for (Module::giterator GI = M->gbegin(), GE = M->gend(); GI != GE; ++GI)
      if (GI->hasInitializer() && GI->isConstant())
        origGVars[GI->getInitializer()] = GI;
  }

  //===--------------------------------------------------------------------===//
  // PreSelection Pass - Specialize LLVM code for the current target machine.
  // This was and will be a basicblock pass, but make it a FunctionPass until
  // BasicBlockPass ::doFinalization(Function&) is available.
  //
  class PreSelection : public BasicBlockPass, public InstVisitor<PreSelection>
  {
    const TargetMachine ⌖
    const TargetInstrInfo &instrInfo;
    Function* function;

    GlobalVariable* getGlobalForConstant(Constant* CV) {
      Module* M = function->getParent();
      return ConstantPoolForModule::get(M).getGlobalForConstant(CV);
    }

  public:
    PreSelection (const TargetMachine &T):
      target(T), instrInfo(T.getInstrInfo()), function(NULL) {}

    // runOnBasicBlock - apply this pass to each BB
    bool runOnBasicBlock(BasicBlock &BB) {
      function = BB.getParent();
      this->visit(BB);
      return true;
    }

    bool doFinalization(Function &F) {
      if (PreSelectDebugLevel >= PreSelect_PrintOutput)
        std::cerr << "\n\n*** LLVM code after pre-selection for function "
                  << F.getName() << ":\n\n" << F;
      return false;
    }

    // These methods do the actual work of specializing code
    void visitInstruction(Instruction &I);   // common work for every instr.
    void visitGetElementPtrInst(GetElementPtrInst &I);
    void visitCastInst(CastInst &I);
    void visitCallInst(CallInst &I);

    // Helper functions for visiting operands of every instruction
    //
    // visitOperands() works on every operand in [firstOp, lastOp-1].
    // If lastOp==0, lastOp defaults to #operands or #incoming Phi values.
    //
    // visitOneOperand() does all the work for one operand.
    //
    void visitOperands(Instruction &I, int firstOp=0, int lastOp=0);
    void visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
                         Instruction& insertBefore);
  };

  // Register the pass...
  RegisterOpt<PreSelection> X("preselect",
                              "Specialize LLVM code for a target machine",
                              createPreSelectionPass);
}  // end anonymous namespace

//------------------------------------------------------------------------------
// Helper functions used by methods of class PreSelection
//------------------------------------------------------------------------------

// getGlobalAddr(): Put address of a global into a v. register.
static GetElementPtrInst* getGlobalAddr(Value* ptr, Instruction& insertBefore)
{
  if (isa<ConstantPointerRef>(ptr))
    ptr = cast<ConstantPointerRef>(ptr)->getValue();

  return (isa<GlobalVariable>(ptr))
    ? new GetElementPtrInst(ptr,
                    std::vector<Value*>(1, ConstantSInt::get(Type::LongTy, 0U)),
                    "addrOfGlobal", &insertBefore)
    : NULL;
}

// Wrapper on Constant::classof to use in find_if :-(
inline static bool nonConstant(const Use& U)
{
  return ! isa<Constant>(U);
}

static Instruction* DecomposeConstantExpr(ConstantExpr* CE,
                                          Instruction& insertBefore)
{
  Value *getArg1, *getArg2;

  switch(CE->getOpcode())
    {
    case Instruction::Cast:
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      return new CastInst(getArg1, CE->getType(), "constantCast",&insertBefore);

    case Instruction::GetElementPtr:
      assert(find_if(CE->op_begin()+1, CE->op_end(),nonConstant) == CE->op_end()
             && "All indices in ConstantExpr getelementptr must be constant!");
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      else if (GetElementPtrInst* gep = getGlobalAddr(getArg1, insertBefore))
        getArg1 = gep;
      return new GetElementPtrInst(getArg1,
                          std::vector<Value*>(CE->op_begin()+1, CE->op_end()),
                          "constantGEP", &insertBefore);

    default:                            // must be a binary operator
      assert(CE->getOpcode() >= Instruction::BinaryOpsBegin &&
             CE->getOpcode() <  Instruction::BinaryOpsEnd &&
             "Unrecognized opcode in ConstantExpr");
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      getArg2 = CE->getOperand(1);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg2))
        getArg2 = DecomposeConstantExpr(CEarg, insertBefore);
      return BinaryOperator::create((Instruction::BinaryOps) CE->getOpcode(),
                                    getArg1, getArg2,
                                    "constantBinaryOp", &insertBefore);
    }
}

//------------------------------------------------------------------------------
// Instruction visitor methods to perform instruction-specific operations
//------------------------------------------------------------------------------
inline void
PreSelection::visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
                              Instruction& insertBefore)
{
  assert(&insertBefore != NULL && "Must have instruction to insert before.");

  if (GetElementPtrInst* gep = getGlobalAddr(Op, insertBefore)) {
    I.setOperand(opNum, gep);           // replace global operand
    return;                             // nothing more to do for this op.
  }

  Constant* CV  = dyn_cast<Constant>(Op);
  if (CV == NULL)
    return;

  if (ConstantExpr* CE = dyn_cast<ConstantExpr>(CV))
    { // load-time constant: factor it out so we optimize as best we can
      Instruction* computeConst = DecomposeConstantExpr(CE, insertBefore);
      I.setOperand(opNum, computeConst); // replace expr operand with result
    }
  else if (instrInfo.ConstantTypeMustBeLoaded(CV))
    { // load address of constant into a register, then load the constant
      GetElementPtrInst* gep = getGlobalAddr(getGlobalForConstant(CV),
                                             insertBefore);
      LoadInst* ldI = new LoadInst(gep, "loadConst", &insertBefore);
      I.setOperand(opNum, ldI);        // replace operand with copy in v.reg.
    }
  else if (instrInfo.ConstantMayNotFitInImmedField(CV, &I))
    { // put the constant into a virtual register using a cast
      CastInst* castI = new CastInst(CV, CV->getType(), "copyConst",
                                     &insertBefore);
      I.setOperand(opNum, castI);      // replace operand with copy in v.reg.
    }
}

// visitOperands() transforms individual operands of all instructions:
// -- Load "large" int constants into a virtual register.  What is large
//    depends on the type of instruction and on the target architecture.
// -- For any constants that cannot be put in an immediate field,
//    load address into virtual register first, and then load the constant.
//
// firstOp and lastOp can be used to skip leading and trailing operands.
// If lastOp is 0, it defaults to #operands or #incoming Phi values.
//
inline void
PreSelection::visitOperands(Instruction &I, int firstOp, int lastOp)
{
  // For any instruction other than PHI, copies go just before the instr.
  // For a PHI, operand copies must be before the terminator of the
  // appropriate predecessor basic block.  Remaining logic is simple
  // so just handle PHIs and other instructions separately.
  //
  if (PHINode* phi = dyn_cast<PHINode>(&I))
    {
      if (lastOp == 0)
        lastOp = phi->getNumIncomingValues();
      for (unsigned i=firstOp, N=lastOp; i < N; ++i)
        this->visitOneOperand(I, phi->getIncomingValue(i),
                              phi->getOperandNumForIncomingValue(i),
                              * phi->getIncomingBlock(i)->getTerminator());
    }
  else
    {
      if (lastOp == 0)
        lastOp = I.getNumOperands();
      for (unsigned i=firstOp, N=lastOp; i < N; ++i)
        this->visitOneOperand(I, I.getOperand(i), i, I);
    }
}

// Common work for *all* instructions.  This needs to be called explicitly
// by other visit<InstructionType> functions.
inline void
PreSelection::visitInstruction(Instruction &I)
{
  visitOperands(I);              // Perform operand transformations
}

// GetElementPtr instructions: check if pointer is a global
void
PreSelection::visitGetElementPtrInst(GetElementPtrInst &I)
{
  Instruction* curI = &I;

  // Decompose multidimensional array references
  if (I.getNumIndices() >= 2) {
    // DecomposeArrayRef() replaces I and deletes it, if successful,
    // so remember predecessor in order to find the replacement instruction.
    // Also remember the basic block in case there is no predecessor.
    Instruction* prevI = I.getPrev();
    BasicBlock* bb = I.getParent();
    if (DecomposeArrayRef(&I))
      // first instr. replacing I
      curI = cast<GetElementPtrInst>(prevI? prevI->getNext() : &bb->front());
  }

  // Perform other transformations common to all instructions
  visitInstruction(*curI);
}

// Cast instructions:
// -- make multi-step casts explicit:
//    -- float/double to uint32_t:
//         If target does not have a float-to-unsigned instruction, we
//         need to convert to uint64_t and then to uint32_t, or we may
//         overflow the signed int representation for legal uint32_t
//         values.  Expand this without checking target.
// -- other common transformations on operands
//
void
PreSelection::visitCastInst(CastInst &I)
{
  CastInst* castI = NULL;

  // Check for a global and put its address into a register before this instr
  if (I.getType() == Type::UIntTy &&
      I.getOperand(0)->getType()->isFloatingPoint()) {
    // insert a cast-fp-to-long before I, and then replace the operand of I
    castI = new CastInst(I.getOperand(0), Type::LongTy, "fp2Long2Uint", &I);
    I.setOperand(0, castI);           // replace fp operand with long
  }

  // Perform other transformations common to all instructions
  visitInstruction(I);
  if (castI)
    visitInstruction(*castI);
}

void
PreSelection::visitCallInst(CallInst &I)
{
  // Tell visitOperands to ignore the function name if this is a direct call.
  visitOperands(I, (/*firstOp=*/ I.getCalledFunction()? 1 : 0));
}

//===----------------------------------------------------------------------===//
// createPreSelectionPass - Public entrypoint for pre-selection pass
// and this file as a whole...
//
Pass*
createPreSelectionPass(TargetMachine &T)
{
  return new PreSelection(T);
}

<commit_msg>Remove conversion of fp-to-uint cast into a multi-step cast: this is not an optional transformation on SPARC and is now handled directly by instruction selection.<commit_after>//===- PreSelection.cpp - Specialize LLVM code for target machine ---------===//
//
// This file defines the PreSelection pass which specializes LLVM code for a
// target machine, while remaining in legal portable LLVM form and
// preserving type information and type safety.  This is meant to enable
// dataflow optimizations on target-specific operations such as accesses to
// constants, globals, and array indexing.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/PreSelection.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Support/InstVisitor.h"
#include "llvm/Module.h"
#include "llvm/Constants.h"
#include "llvm/iMemory.h"
#include "llvm/iPHINode.h"
#include "llvm/iOther.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Pass.h"
#include "Support/CommandLine.h"
#include <algorithm>

namespace {
  //===--------------------------------------------------------------------===//
  // SelectDebugLevel - Allow command line control over debugging.
  //
  enum PreSelectDebugLevel_t {
    PreSelect_NoDebugInfo,
    PreSelect_PrintOutput,
  };

  // Enable Debug Options to be specified on the command line
  cl::opt<PreSelectDebugLevel_t>
  PreSelectDebugLevel("dpreselect", cl::Hidden,
     cl::desc("debug information for target-dependent pre-selection"),
     cl::values(
       clEnumValN(PreSelect_NoDebugInfo, "n", "disable debug output (default)"),
       clEnumValN(PreSelect_PrintOutput, "y", "print generated machine code"),
       /* default level = */ PreSelect_NoDebugInfo));

  //===--------------------------------------------------------------------===//
  // class ConstantPoolForModule:
  //
  // The pool of constants that must be emitted for a module.
  // This is a single pool for the entire module and is shared by
  // all invocations of the PreSelection pass for this module by putting
  // this as an annotation on the Module object.
  // A single GlobalVariable is created for each constant in the pool
  // representing the memory for that constant.
  //
  AnnotationID CPFM_AID(
                 AnnotationManager::getID("CodeGen::ConstantPoolForModule"));

  class ConstantPoolForModule : private Annotation {
    Module* myModule;
    std::map<const Constant*, GlobalVariable*> gvars;
    std::map<const Constant*, GlobalVariable*> origGVars;
    ConstantPoolForModule(Module* M);   // called only by annotation builder
    ConstantPoolForModule();                      // DO NOT IMPLEMENT
    void operator=(const ConstantPoolForModule&); // DO NOT IMPLEMENT
  public:
    static ConstantPoolForModule& get(Module* M) {
      ConstantPoolForModule* cpool =
        (ConstantPoolForModule*) M->getAnnotation(CPFM_AID);
      if (cpool == NULL) // create a new annotation and add it to the Module
        M->addAnnotation(cpool = new ConstantPoolForModule(M));
      return *cpool;
    }

    GlobalVariable* getGlobalForConstant(Constant* CV) {
      std::map<const Constant*, GlobalVariable*>::iterator I = gvars.find(CV);
      if (I != gvars.end())
        return I->second;               // global exists so return it
      return addToConstantPool(CV);     // create a new global and return it
    }

    GlobalVariable*  addToConstantPool(Constant* CV) {
      GlobalVariable*& GV = gvars[CV];  // handle to global var entry in map
      if (GV == NULL)
        { // check if a global constant already existed; otherwise create one
          std::map<const Constant*, GlobalVariable*>::iterator PI =
            origGVars.find(CV);
          if (PI != origGVars.end())
            GV = PI->second;            // put in map
          else
            {
              GV = new GlobalVariable(CV->getType(), true, //put in map
                                      GlobalValue::InternalLinkage, CV);
              myModule->getGlobalList().push_back(GV); // GV owned by module now
            }
        }
      return GV;
    }
  };

  /* ctor */
  ConstantPoolForModule::ConstantPoolForModule(Module* M)
    : Annotation(CPFM_AID), myModule(M)
  {
    // Build reverse map for pre-existing global constants so we can find them
    for (Module::giterator GI = M->gbegin(), GE = M->gend(); GI != GE; ++GI)
      if (GI->hasInitializer() && GI->isConstant())
        origGVars[GI->getInitializer()] = GI;
  }

  //===--------------------------------------------------------------------===//
  // PreSelection Pass - Specialize LLVM code for the current target machine.
  // This was and will be a basicblock pass, but make it a FunctionPass until
  // BasicBlockPass ::doFinalization(Function&) is available.
  //
  class PreSelection : public BasicBlockPass, public InstVisitor<PreSelection>
  {
    const TargetMachine ⌖
    const TargetInstrInfo &instrInfo;
    Function* function;

    GlobalVariable* getGlobalForConstant(Constant* CV) {
      Module* M = function->getParent();
      return ConstantPoolForModule::get(M).getGlobalForConstant(CV);
    }

  public:
    PreSelection (const TargetMachine &T):
      target(T), instrInfo(T.getInstrInfo()), function(NULL) {}

    // runOnBasicBlock - apply this pass to each BB
    bool runOnBasicBlock(BasicBlock &BB) {
      function = BB.getParent();
      this->visit(BB);
      return true;
    }

    bool doFinalization(Function &F) {
      if (PreSelectDebugLevel >= PreSelect_PrintOutput)
        std::cerr << "\n\n*** LLVM code after pre-selection for function "
                  << F.getName() << ":\n\n" << F;
      return false;
    }

    // These methods do the actual work of specializing code
    void visitInstruction(Instruction &I);   // common work for every instr.
    void visitGetElementPtrInst(GetElementPtrInst &I);
    void visitCallInst(CallInst &I);

    // Helper functions for visiting operands of every instruction
    //
    // visitOperands() works on every operand in [firstOp, lastOp-1].
    // If lastOp==0, lastOp defaults to #operands or #incoming Phi values.
    //
    // visitOneOperand() does all the work for one operand.
    //
    void visitOperands(Instruction &I, int firstOp=0, int lastOp=0);
    void visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
                         Instruction& insertBefore);
  };

  // Register the pass...
  RegisterOpt<PreSelection> X("preselect",
                              "Specialize LLVM code for a target machine",
                              createPreSelectionPass);
}  // end anonymous namespace

//------------------------------------------------------------------------------
// Helper functions used by methods of class PreSelection
//------------------------------------------------------------------------------

// getGlobalAddr(): Put address of a global into a v. register.
static GetElementPtrInst* getGlobalAddr(Value* ptr, Instruction& insertBefore)
{
  if (isa<ConstantPointerRef>(ptr))
    ptr = cast<ConstantPointerRef>(ptr)->getValue();

  return (isa<GlobalVariable>(ptr))
    ? new GetElementPtrInst(ptr,
                    std::vector<Value*>(1, ConstantSInt::get(Type::LongTy, 0U)),
                    "addrOfGlobal", &insertBefore)
    : NULL;
}

// Wrapper on Constant::classof to use in find_if :-(
inline static bool nonConstant(const Use& U)
{
  return ! isa<Constant>(U);
}

static Instruction* DecomposeConstantExpr(ConstantExpr* CE,
                                          Instruction& insertBefore)
{
  Value *getArg1, *getArg2;

  switch(CE->getOpcode())
    {
    case Instruction::Cast:
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      return new CastInst(getArg1, CE->getType(), "constantCast",&insertBefore);

    case Instruction::GetElementPtr:
      assert(find_if(CE->op_begin()+1, CE->op_end(),nonConstant) == CE->op_end()
             && "All indices in ConstantExpr getelementptr must be constant!");
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      else if (GetElementPtrInst* gep = getGlobalAddr(getArg1, insertBefore))
        getArg1 = gep;
      return new GetElementPtrInst(getArg1,
                          std::vector<Value*>(CE->op_begin()+1, CE->op_end()),
                          "constantGEP", &insertBefore);

    default:                            // must be a binary operator
      assert(CE->getOpcode() >= Instruction::BinaryOpsBegin &&
             CE->getOpcode() <  Instruction::BinaryOpsEnd &&
             "Unrecognized opcode in ConstantExpr");
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      getArg2 = CE->getOperand(1);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg2))
        getArg2 = DecomposeConstantExpr(CEarg, insertBefore);
      return BinaryOperator::create((Instruction::BinaryOps) CE->getOpcode(),
                                    getArg1, getArg2,
                                    "constantBinaryOp", &insertBefore);
    }
}

//------------------------------------------------------------------------------
// Instruction visitor methods to perform instruction-specific operations
//------------------------------------------------------------------------------
inline void
PreSelection::visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
                              Instruction& insertBefore)
{
  assert(&insertBefore != NULL && "Must have instruction to insert before.");

  if (GetElementPtrInst* gep = getGlobalAddr(Op, insertBefore)) {
    I.setOperand(opNum, gep);           // replace global operand
    return;                             // nothing more to do for this op.
  }

  Constant* CV  = dyn_cast<Constant>(Op);
  if (CV == NULL)
    return;

  if (ConstantExpr* CE = dyn_cast<ConstantExpr>(CV))
    { // load-time constant: factor it out so we optimize as best we can
      Instruction* computeConst = DecomposeConstantExpr(CE, insertBefore);
      I.setOperand(opNum, computeConst); // replace expr operand with result
    }
  else if (instrInfo.ConstantTypeMustBeLoaded(CV))
    { // load address of constant into a register, then load the constant
      GetElementPtrInst* gep = getGlobalAddr(getGlobalForConstant(CV),
                                             insertBefore);
      LoadInst* ldI = new LoadInst(gep, "loadConst", &insertBefore);
      I.setOperand(opNum, ldI);        // replace operand with copy in v.reg.
    }
  else if (instrInfo.ConstantMayNotFitInImmedField(CV, &I))
    { // put the constant into a virtual register using a cast
      CastInst* castI = new CastInst(CV, CV->getType(), "copyConst",
                                     &insertBefore);
      I.setOperand(opNum, castI);      // replace operand with copy in v.reg.
    }
}

// visitOperands() transforms individual operands of all instructions:
// -- Load "large" int constants into a virtual register.  What is large
//    depends on the type of instruction and on the target architecture.
// -- For any constants that cannot be put in an immediate field,
//    load address into virtual register first, and then load the constant.
//
// firstOp and lastOp can be used to skip leading and trailing operands.
// If lastOp is 0, it defaults to #operands or #incoming Phi values.
//
inline void
PreSelection::visitOperands(Instruction &I, int firstOp, int lastOp)
{
  // For any instruction other than PHI, copies go just before the instr.
  // For a PHI, operand copies must be before the terminator of the
  // appropriate predecessor basic block.  Remaining logic is simple
  // so just handle PHIs and other instructions separately.
  //
  if (PHINode* phi = dyn_cast<PHINode>(&I))
    {
      if (lastOp == 0)
        lastOp = phi->getNumIncomingValues();
      for (unsigned i=firstOp, N=lastOp; i < N; ++i)
        this->visitOneOperand(I, phi->getIncomingValue(i),
                              phi->getOperandNumForIncomingValue(i),
                              * phi->getIncomingBlock(i)->getTerminator());
    }
  else
    {
      if (lastOp == 0)
        lastOp = I.getNumOperands();
      for (unsigned i=firstOp, N=lastOp; i < N; ++i)
        this->visitOneOperand(I, I.getOperand(i), i, I);
    }
}

// Common work for *all* instructions.  This needs to be called explicitly
// by other visit<InstructionType> functions.
inline void
PreSelection::visitInstruction(Instruction &I)
{
  visitOperands(I);              // Perform operand transformations
}

// GetElementPtr instructions: check if pointer is a global
void
PreSelection::visitGetElementPtrInst(GetElementPtrInst &I)
{
  Instruction* curI = &I;

  // Decompose multidimensional array references
  if (I.getNumIndices() >= 2) {
    // DecomposeArrayRef() replaces I and deletes it, if successful,
    // so remember predecessor in order to find the replacement instruction.
    // Also remember the basic block in case there is no predecessor.
    Instruction* prevI = I.getPrev();
    BasicBlock* bb = I.getParent();
    if (DecomposeArrayRef(&I))
      // first instr. replacing I
      curI = cast<GetElementPtrInst>(prevI? prevI->getNext() : &bb->front());
  }

  // Perform other transformations common to all instructions
  visitInstruction(*curI);
}

void
PreSelection::visitCallInst(CallInst &I)
{
  // Tell visitOperands to ignore the function name if this is a direct call.
  visitOperands(I, (/*firstOp=*/ I.getCalledFunction()? 1 : 0));
}

//===----------------------------------------------------------------------===//
// createPreSelectionPass - Public entrypoint for pre-selection pass
// and this file as a whole...
//
Pass*
createPreSelectionPass(TargetMachine &T)
{
  return new PreSelection(T);
}

<|endoftext|>


<commit_before>class RegisterClassDetails
{
public:

private:
    BitSet _members;
};

Array<RegisterClassDetails>

class RegisterClass
{
public:
private:
    int _index;
};

typedef int ConstantClass;
typedef int Register;

class InstructionPattern
{
public:
    Array<RegisterClass> _registerHoles;
    Array<ConstantClass> _constantHoles;

};

class MachineDescription
{
public:
    Array<InstructionPattern> _patterns;
    Array<RegisterClassDetails> _registerClassDetails;
    Array<ConstantClassDetails> _constantClassDetails;
};
<commit_msg>More machine descriptions<commit_after>class RegisterClassDetails
{
public:
private:
    BitSet _members;
};

class RegisterClass
{
public:
private:
    int _index;
};

class ConstantClassDetails
{
public:
private:
    int _minimum;
    int _maximum;
    int _step;
};

class ConstantClass
{
public:
private:
    int _index;
};

class Register
{
public:
private:
    int _index;
};

class InstructionPattern
{
public:
    Array<RegisterClass> _registerHoles;
    Array<ConstantClass> _constantHoles;

};

class MachineDescription
{
public:
    Array<InstructionPattern> _patterns;
    Array<RegisterClassDetails> _registerClassDetails;
    Array<ConstantClassDetails> _constantClassDetails;
};
<|endoftext|>


<commit_before>/***************************************************************************
* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht          *
* Copyright (c) QuantStack                                                 *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XTL_HASH_HPP
#define XTL_HASH_HPP

#include <cstddef>
#include <cstdint>
#include <cstring>

#include <type_traits>

namespace xtl
{

    std::size_t hash_bytes(const void* buffer, std::size_t lenght, std::size_t seed);

    /******************************
     *  hash_bytes implementation *
     ******************************/

    namespace detail
    {
        // Dummy hash implementation for unusual sizeof(std::size_t)
        template <std::size_t N>
        std::size_t murmur_hash(const void* buffer, std::size_t length, std::size_t seed)
        {
            std::size_t hash = seed;
            const char* data = static_cast<const char*>(buffer);
            for (; length != 0; --length)
            {
                hash = (hash * 131) + static_cast<std::size_t>(*data++);
            }
            return hash;
        }

        // Murmur hash is an algorithm written by Austin Appleby. See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp
        template <>
        inline std::size_t murmur_hash<4>(const void* buffer, std::size_t length, std::size_t seed)
        {
            constexpr std::size_t m = 0x5bd1e995;
            std::size_t hash = seed ^ length;
            const unsigned char* data = static_cast<const unsigned char*>(buffer);

            // Mix 4 bytes at a time into the hash.
            while (length >= 4)
            {
                std::size_t k;
                std::memcpy(&k, data, sizeof(k));
                k *= m;
                k ^= k >> 24;
                k *= m;
                hash *= m;
                hash ^= k;
                data += 4;
                length -= 4;
            }

            // Handle the last frwe bytes of the input array.
            switch (length)
            {
            case 3:
                hash ^= static_cast<std::size_t>(data[2] << 16);
            case 2:
                hash ^= static_cast<std::size_t>(data[1] << 8);
            case 1:
                hash ^= static_cast<std::size_t>(data[0]);
                hash *= m;
            }

            // Do a few final mix of the hash to ensure the last few
            // bytes are well-incorporated.

            hash ^= hash >> 13;
            hash *= m;
            hash ^= hash >> 15;
            return hash;
        }

        inline std::size_t load_bytes(const char* p, int n)
        {
            std::size_t result = 0;
            --n;
            do
            {
                result = (result << 8) + static_cast<unsigned char>(p[n]);
            } while (--n >= 0);
            return result;
        }

#if INTPTR_MAX == INT64_MAX
        // 64-bits hash for 64-bits platform
        template <>
        inline std::size_t murmur_hash<8>(const void* buffer, std::size_t length, std::size_t seed)
        {
            constexpr std::size_t m = (static_cast<std::size_t>(0xc6a4a793UL) << 32UL) +
                static_cast<std::size_t>(0x5bd1e995UL);
            constexpr int r = 47;
            const char* data = static_cast<const char*>(buffer);
            const char* end = data + (length & std::size_t(~0x7));
            std::size_t hash = seed ^ (length * m);
            while (data != end)
            {
                std::size_t k;
                std::memcpy(&k, data, sizeof(k));
                k *= m;
                k ^= k >> r;
                k *= m;
                hash ^= k;
                hash *= m;
                data += 8;
            }
            if ((length & 0x7) != 0)
            {
                std::size_t k = load_bytes(end, length & 0x7);
                hash ^= k;
                hash *= m;
            }
            hash ^= hash >> r;
            hash *= m;
            hash ^= hash >> r;

            return hash;
        }
#elif INTPTR_MAX == INT32_MAX
        //64-bits hash for 32-bits platform
        inline void mmix(uint32_t& h, uint32_t& k, uint32_t m, int r)
        {
            k *= m; k ^= k >> r; k *= m; h *= m; h ^= k;
        }

        template <>
        inline std::size_t murmur_hash<8>(const void* buffer, std::size_t length, std::size_t seed)
        {
            const uint32_t m = 0x5bd1e995;
            const int r = 24;
            uint32_t l = length;

            const auto* data = reinterpret_cast<const unsigned char*>(buffer);

            uint32_t h = seed;

            while (length >= 4)
            {
                uint32_t k = *(uint32_t*)data;

                mmix(h, k, m, r);

                data += 4;
                length -= 4;
            }

            uint32_t t = 0;

            switch (length)
            {
            case 3: t ^= data[2] << 16;
            case 2: t ^= data[1] << 8;
            case 1: t ^= data[0];
            };

            mmix(h, t, m, r);
            mmix(h, l, m, r);

            h ^= h >> 13;
            h *= m;
            h ^= h >> 15;

            return h;
        }
#else
#error Unknown pointer size or missing size macros!
#endif
    }

    inline std::size_t hash_bytes(const void* buffer, std::size_t length, std::size_t seed)
    {
        return detail::murmur_hash<sizeof(std::size_t)>(buffer, length, seed);
    }
}

#endif
<commit_msg>Fixed murmur implementation for x86 platform<commit_after>/***************************************************************************
* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht          *
* Copyright (c) QuantStack                                                 *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XTL_HASH_HPP
#define XTL_HASH_HPP

#include <cstddef>
#include <cstdint>
#include <cstring>

#include <type_traits>

namespace xtl
{

    std::size_t hash_bytes(const void* buffer, std::size_t lenght, std::size_t seed);

    uint32_t murmur2_x86(const void* buffer, std::size_t length, uint32_t seed);
    uint64_t murmur2_x64(const void* buffer, std::size_t length, uint64_t seed);

    /******************************
     *  hash_bytes implementation *
     ******************************/

    namespace detail
    {
        // Dummy hash implementation for unusual sizeof(std::size_t)
        template <std::size_t N>
        std::size_t murmur_hash(const void* buffer, std::size_t length, std::size_t seed)
        {
            std::size_t hash = seed;
            const char* data = static_cast<const char*>(buffer);
            for (; length != 0; --length)
            {
                hash = (hash * 131) + static_cast<std::size_t>(*data++);
            }
            return hash;
        }

        // Murmur hash is an algorithm written by Austin Appleby. See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp
        inline uint32_t murmur2_x86_impl(const void* buffer, std::size_t length, uint32_t seed)
        {
            const uint32_t m = 0x5bd1e995;
            uint32_t len = static_cast<uint32_t>(length);

            // Initialize the hash to a 'random' value
            uint32_t h = seed ^ len;

            // Mix 4 bytes at a time into the hash
            const unsigned char * data = (const unsigned char *)buffer;

            while(len >= 4)
            {
                uint32_t k = *(uint32_t*)data;
                k *= m;
                k ^= k >> 24;
                k *= m;

                h *= m;
                h ^= k;

                data += 4;
                len -= 4;
            }

            // Handle the last few bytes of the input array
            switch(len)
            {
            case 3: h ^= static_cast<uint32_t>(data[2] << 16);
            case 2: h ^= static_cast<uint32_t>(data[1] << 8);
            case 1: h ^= static_cast<uint32_t>(data[0]);
                h *= m;
            };

            // Do a few final mixes of the hash to ensure the last few
            // // bytes are well-incorporated.
            h ^= h >> 13;
            h *= m;
            h ^= h >> 15;

            return h;
        }

        template <>
        inline std::size_t murmur_hash<4>(const void* buffer, std::size_t length, std::size_t seed)
        {
            return std::size_t(murmur2_x86_impl(buffer, length, static_cast<uint32_t>(seed)));
        }

        inline std::size_t load_bytes(const char* p, int n)
        {
            std::size_t result = 0;
            --n;
            do
            {
                result = (result << 8) + static_cast<unsigned char>(p[n]);
            } while (--n >= 0);
            return result;
        }

#if INTPTR_MAX == INT64_MAX
        // 64-bits hash for 64-bits platform
        template <>
        inline std::size_t murmur_hash<8>(const void* buffer, std::size_t length, std::size_t seed)
        {
            constexpr std::size_t m = (static_cast<std::size_t>(0xc6a4a793UL) << 32UL) +
                static_cast<std::size_t>(0x5bd1e995UL);
            constexpr int r = 47;
            const char* data = static_cast<const char*>(buffer);
            const char* end = data + (length & std::size_t(~0x7));
            std::size_t hash = seed ^ (length * m);
            while (data != end)
            {
                std::size_t k;
                std::memcpy(&k, data, sizeof(k));
                k *= m;
                k ^= k >> r;
                k *= m;
                hash ^= k;
                hash *= m;
                data += 8;
            }
            if ((length & 0x7) != 0)
            {
                std::size_t k = load_bytes(end, length & 0x7);
                hash ^= k;
                hash *= m;
            }
            hash ^= hash >> r;
            hash *= m;
            hash ^= hash >> r;

            return hash;
        }
#elif INTPTR_MAX == INT32_MAX
        //64-bits hash for 32-bits platform
        inline void mmix(uint32_t& h, uint32_t& k, uint32_t m, int r)
        {
            k *= m; k ^= k >> r; k *= m; h *= m; h ^= k;
        }

        template <>
        inline std::size_t murmur_hash<8>(const void* buffer, std::size_t length, std::size_t seed)
        {
            const uint32_t m = 0x5bd1e995;
            const int r = 24;
            uint32_t l = length;

            const auto* data = reinterpret_cast<const unsigned char*>(buffer);

            uint32_t h = seed;

            while (length >= 4)
            {
                uint32_t k = *(uint32_t*)data;

                mmix(h, k, m, r);

                data += 4;
                length -= 4;
            }

            uint32_t t = 0;

            switch (length)
            {
            case 3: t ^= data[2] << 16;
            case 2: t ^= data[1] << 8;
            case 1: t ^= data[0];
            };

            mmix(h, t, m, r);
            mmix(h, l, m, r);

            h ^= h >> 13;
            h *= m;
            h ^= h >> 15;

            return h;
        }
#else
#error Unknown pointer size or missing size macros!
#endif
    }

    inline std::size_t hash_bytes(const void* buffer, std::size_t length, std::size_t seed)
    {
        return detail::murmur_hash<sizeof(std::size_t)>(buffer, length, seed);
    }

    inline uint32_t murmur2_x86(const void* buffer, std::size_t length, uint32_t seed)
    {
        return detail::murmur2_x86_impl(buffer, length, seed);
    }

    inline uint64_t murmur2_x64(const void* buffer, std::size_t length, uint64_t seed)
    {
        return detail::murmur_hash<8>(buffer, length, seed);
    }
}

#endif
<|endoftext|>


<commit_before>#include <Python.h>
#include <vigra/timing.hxx>
#include <vigra/multi_array.hxx>
#include <vigra/numpy_array.hxx>
#include <boost/python.hpp>

void thrashCache() {
    char* d  = new char[1024*1024*50];
    char* d2 = new char[1024*1024*50];
    std::copy(d, d+1024*1024*50, d2);
    char* d3 = new char[1024*1024*50];
    std::copy(d2, d2+1024*1024*50, d3);

    delete[] d;
    delete[] d2;
    delete[] d3;
}

template<typename T>
void bench_new(size_t size, size_t testIter) {
    USETICTOC;
    double t = 0.0;
    for(int tI=0; tI<testIter; ++tI) {
        TIC;
        T* d = new T[size];
        t += TOCN;
        delete[] d;
    }
    std::cout << "  new:      " << t/testIter << " msec." << std::endl;
}

template<typename T>
void bench_allocator_fill(size_t size, size_t testIter) {
    //TODO:
    //
    //read http://stackoverflow.com/questions/6047840/does-an-allocator-construct-loop-equal-stduninitialized-copy
    //

    USETICTOC;
    std::allocator<T> alloc;
    double t = 0.0;
    for(int tI=0; tI<testIter; ++tI) {
        T* ptr = alloc.allocate(size);
        const T zero = 0;
        const T& zeroRef = zero;
        const vigra::MultiArrayIndex s = size;
        try {
            TIC;
            for (vigra::MultiArrayIndex i = 0; i < s; ++i) {
                alloc.construct (ptr + i, zeroRef /*init*/);
            }
            t += TOCN;
        }
        catch (...) {
            for(size_t j = 0; j < size; ++j) {
                alloc.destroy (ptr + j);
            }
            alloc.deallocate(ptr, size);
            throw;
        }
    }
    std::cout << "  alloc fill:  " << t/testIter << " msec." << std::endl;
}

template<typename T>
void bench_writeasc(size_t size, size_t testIter) {
    USETICTOC;
    double t = 0.0;
    for(int tI=0; tI<testIter; ++tI) {
        T* d = new T[size];
        TIC;
        for(size_t j=0; j<size; ++j) {
            d[j] = j;
        }
        t += TOCN;
        delete[] d;
    }
    std::cout << "  write asc:           " << t/testIter << " msec." << std::endl;
}

template<typename T>
void bench_fill(size_t size, size_t testIter) {
    USETICTOC;
    double t = 0.0;
    for(int tI=0; tI<testIter; ++tI) {
        T* d = new T[size];
        for(int i=0; i<size; ++i) { d[i] = i; }
        TIC;
        std::fill(d, d+size, 0);
        t += TOCN;
        delete[] d;
    }
    std::cout << "  fill:        " << t/testIter << " msec." << std::endl;
}

template<typename T>
void bench_memset(size_t size, size_t testIter) {
    USETICTOC;
    double t = 0.0;
    for(int tI=0; tI<testIter; ++tI) {
        T* d = new T[size];
        for(int i=0; i<size; ++i) { d[i] = i; }
        TIC;
        memset(d, 0, size*sizeof(T));
        t += TOCN;
        delete[] d;
    }
    std::cout << "  memset:      " << t/testIter << " msec." << std::endl;
}

template<typename T>
void bench_stdcopy(size_t size, size_t testIter) {
    USETICTOC;
    double t = 0.0;
    for(int tI=0; tI<testIter; ++tI) {
        T* d  = new T[size];
        T* d2 = new T[size];
        TIC;
        std::copy(d, d+size, d2);
        t += TOCN;
        delete[] d;
        delete[] d2;
    }
    std::cout << "  std::copy                 " << t/testIter << " msec. " << std::endl;
}

template<int N, class T>
void bench_MultiArray_new(
    typename vigra::MultiArrayShape<N>::type shape,
    size_t testIter
) {
    USETICTOC;
    double t;
    for(int tI=0; tI<testIter; ++tI) {
        TIC;
        vigra::MultiArray<N,T> a(shape);
        t += TOCN;
    }
    std::cout << "  MultiArray() " << t/testIter << " msec. " << std::endl;
}

template<int N, class T>
void bench_MultiArray_writeasc(
    typename vigra::MultiArrayShape<N>::type shape,
    size_t testIter
) {
    USETICTOC;
    double t;
    for(int tI=0; tI<testIter; ++tI) {
        vigra::MultiArray<N,T> a(shape);
        TIC;
        for(size_t j=0; j<a.size(); ++j) {
            a(j) = j; //ATTENTION: this is much faster than a[j], but still slow
        }
        t += TOCN;
    }
    std::cout << "  MultiArray write asc " << t/testIter << " msec. " << std::endl;
}

template<int N, class T>
void bench_MultiArray_copy_assignment(
    typename vigra::MultiArrayShape<N>::type shape,
    size_t testIter
) {
    USETICTOC;
    double t;
    for(int tI=0; tI<testIter; ++tI) {
        vigra::MultiArray<N,T> a(shape);
        //for(int i=0; i<a.size(); ++i) { a[i] = i; }
        vigra::MultiArray<N,T> b(a.shape());
        TIC;
        b = a;
        t += TOCN;
    }
    std::cout << "  MultiArray::operator=     " << t/testIter << " msec. " << std::endl;
}

template<int N, class T>
void bench_MultiArray_copy_view(
    typename vigra::MultiArrayShape<N>::type shape,
    size_t testIter
) {
    USETICTOC;
    double t;
    for(int tI=0; tI<testIter; ++tI) {
        vigra::MultiArray<N,T> a(shape);
        vigra::MultiArray<N,T> b(shape);
        vigra::MultiArrayView<N,T> bView = b.view();
        TIC;
        b = a.subarray(typename vigra::MultiArrayShape<N>::type(),shape);
        t += TOCN;
    }
    std::cout << "  MultiArrayView::operator= " << t/testIter << " msec." << std::endl;
}

int main() {
    using namespace vigra;
    using std::cout; using std::endl;
    USETICTOC;

    const int N = 5;
    typedef unsigned char T;

    Shape5 sh(1,300,310,320,1);

    size_t size = 1; for(int i=0; i<N; ++i) { size *= sh[i]; };
    std::cout << "*** size " << size*sizeof(T)/(1024*1024) << "MB:" << std::endl;

    const int testIter = 20;

    std::cout << "* new" << std::endl;
    bench_new<T>(size, testIter);
    std::cout << std::endl;

    std::cout << "* initialize with 0" << std::endl;
    bench_fill<T>(size, testIter);
    bench_allocator_fill<T>(size, testIter);
    bench_memset<T>(size, testIter);
    bench_MultiArray_new<N,T>(sh, testIter);
    std::cout << std::endl;

    std::cout << "* full copy" << std::endl;
    bench_stdcopy<T>(size, testIter);
    bench_MultiArray_copy_assignment<N,T>(sh, testIter);
    bench_MultiArray_copy_view<N,T>(sh, testIter);
    std::cout << std::endl;

    std::cout << "* write ascending numbers" << std::endl;
    bench_writeasc<T>(size, testIter);
    bench_MultiArray_writeasc<N,T>(sh, testIter);

    MultiArray<N,T> dataCpp(sh);
    typedef MultiArray<N,T>::view_type view_type;

    /*
    std::cout << "data has strides: " << a.stride() << std::endl;
    std::cout << "out has strides:  " << out.stride() << std::endl;
    MultiArrayView<N, T> outViewP = out.view();
    outViewP = outViewP.permuteStridesAscending();
    std::cout << "outViewP has strides:  " << outViewP.stride() << ", " << outViewP.strideOrdering() << std::endl;
    outViewP = outViewP.permuteStridesDescending();
    std::cout << "outViewP has strides:  " << outViewP.stride() << ", " << outViewP.strideOrdering() << std::endl;
    TIC;
    outViewP = mydata.subarray(ShapeN(),sh);
    std::cout << "strides differ " << TOCS << std::endl;
    */

    using namespace boost::python;
    Py_Initialize();
    _import_array();
    object main_module((handle<>(borrowed(PyImport_AddModule("__main__")))));
    object main_namespace = main_module.attr("__dict__");

    std::stringstream pyCode;
    pyCode << "import numpy; ";
    pyCode << "a = numpy.zeros((";
    for(int i=0; i<N; ++i) { pyCode << dataCpp.shape(i); if(i<N-1) { pyCode << ","; } }
    pyCode << "), dtype=numpy.uint8);";
    std::cout << "running python code \"" << pyCode.str() << "\"" << std::endl;

    handle<> ignored((PyRun_String(pyCode.str().c_str(),
                      Py_file_input, main_namespace.ptr(), main_namespace.ptr() ) ));

    object objectA = main_namespace["a"];
    if(!PyArray_Check(objectA.ptr())) { throw std::runtime_error("failed to get array"); }
    PyArrayObject* pyA = (PyArrayObject*)objectA.ptr();
    std::cout << "numpy array dim     = " << PyArray_NDIM(pyA) << std::endl;
    std::cout << "            shape   = ";
    std::copy(PyArray_DIMS(pyA), PyArray_DIMS(pyA)+PyArray_NDIM(pyA), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
    std::cout << "            strides = ";
    std::copy(PyArray_STRIDES(pyA), PyArray_STRIDES(pyA)+PyArray_NDIM(pyA), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;

    vigra::NumpyArray<N,T> numpyA((PyObject*)pyA);
    std::cout << "vigra::NumpyArray strides = " << numpyA.stride() << std::endl;

    TIC;
    numpyA = dataCpp;
    std::cout << "copy from c++ into Numpy array (1): " << TOCS << std::endl;

    MultiArray<N,T> dataCppR(Shape5(1,320,310,300,1));
    std::cout << "dataCppR strides = " << dataCppR.stride() << std::endl;
    TIC;
    numpyA = dataCppR.permuteStridesDescending();
    std::cout << "copy from c++ into Numpy array (2):" << TOCS << std::endl;

    return 0;
}
    <commit_msg>bench_copy: fix memleak; benchmark memset<commit_after>#include <Python.h>
#include <vigra/timing.hxx>
#include <vigra/multi_array.hxx>
#include <vigra/numpy_array.hxx>
#include <boost/python.hpp>

void thrashCache() {
    char* d  = new char[1024*1024*50];
    char* d2 = new char[1024*1024*50];
    std::copy(d, d+1024*1024*50, d2);
    char* d3 = new char[1024*1024*50];
    std::copy(d2, d2+1024*1024*50, d3);

    delete[] d;
    delete[] d2;
    delete[] d3;
}

template<typename T>
void bench_new(size_t size, size_t testIter) {
    USETICTOC;
    double t = 0.0;
    for(int tI=0; tI<testIter; ++tI) {
        TIC;
        T* d = new T[size];
        t += TOCN;
        delete[] d;
    }
    std::cout << "  new:      " << t/testIter << " msec." << std::endl;
}

template<typename T>
void bench_allocator_fill(size_t size, size_t testIter) {
    //TODO:
    //
    //read http://stackoverflow.com/questions/6047840/does-an-allocator-construct-loop-equal-stduninitialized-copy
    //

    USETICTOC;
    std::allocator<T> alloc;
    double t = 0.0;
    for(int tI=0; tI<testIter; ++tI) {
        T* ptr = alloc.allocate(size);
        const T zero = 0;
        const T& zeroRef = zero;
        const vigra::MultiArrayIndex s = size;
        try {
            TIC;
            for (vigra::MultiArrayIndex i = 0; i < s; ++i) {
                alloc.construct (ptr + i, zeroRef /*init*/);
            }
            t += TOCN;
        }
        catch (...) {
            for(size_t j = 0; j < size; ++j) {
                alloc.destroy (ptr + j);
            }
            alloc.deallocate(ptr, size);
            throw;
        }
        alloc.deallocate(ptr, size);
    }
    std::cout << "  alloc fill:  " << t/testIter << " msec." << std::endl;
}

template<typename T>
void bench_writeasc(size_t size, size_t testIter) {
    USETICTOC;
    double t = 0.0;
    for(int tI=0; tI<testIter; ++tI) {
        T* d = new T[size];
        TIC;
        for(size_t j=0; j<size; ++j) {
            d[j] = j;
        }
        t += TOCN;
        delete[] d;
    }
    std::cout << "  write asc:           " << t/testIter << " msec." << std::endl;
}

template<typename T>
void bench_fill(size_t size, size_t testIter) {
    USETICTOC;
    double t = 0.0;
    for(int tI=0; tI<testIter; ++tI) {
        T* d = new T[size];
        for(int i=0; i<size; ++i) { d[i] = i; }
        TIC;
        std::fill(d, d+size, 0);
        t += TOCN;
        delete[] d;
    }
    std::cout << "  fill:        " << t/testIter << " msec." << std::endl;
}

template<typename T>
void bench_memset(size_t size, size_t testIter) {
    USETICTOC;
    double t = 0.0;
    for(int tI=0; tI<testIter; ++tI) {
        T* d = new T[size];
        for(int i=0; i<size; ++i) { d[i] = i; }
        TIC;
        memset(d, 0, size*sizeof(T));
        t += TOCN;
        delete[] d;
    }
    std::cout << "  memset:      " << t/testIter << " msec." << std::endl;
}

template<typename T>
void bench_stdcopy(size_t size, size_t testIter) {
    USETICTOC;
    double t = 0.0;
    for(int tI=0; tI<testIter; ++tI) {
        T* d  = new T[size];
        T* d2 = new T[size];
        TIC;
        std::copy(d, d+size, d2);
        t += TOCN;
        delete[] d;
        delete[] d2;
    }
    std::cout << "  std::copy                 " << t/testIter << " msec. " << std::endl;
}

template<typename T>
void bench_memcpy(size_t size, size_t testIter) {
    USETICTOC;
    double t = 0.0;
    for(int tI=0; tI<testIter; ++tI) {
        T* d  = new T[size];
        T* d2 = new T[size];
        TIC;
        memcpy(d2, d, size*sizeof(T));
        t += TOCN;
        delete[] d;
        delete[] d2;
    }
    std::cout << "  memcpy                    " << t/testIter << " msec. " << std::endl;
}

template<int N, class T>
void bench_MultiArray_new(
    typename vigra::MultiArrayShape<N>::type shape,
    size_t testIter
) {
    USETICTOC;
    double t;
    for(int tI=0; tI<testIter; ++tI) {
        TIC;
        vigra::MultiArray<N,T> a(shape);
        t += TOCN;
    }
    std::cout << "  MultiArray() " << t/testIter << " msec. " << std::endl;
}

template<int N, class T>
void bench_MultiArray_writeasc(
    typename vigra::MultiArrayShape<N>::type shape,
    size_t testIter
) {
    USETICTOC;
    double t;
    for(int tI=0; tI<testIter; ++tI) {
        vigra::MultiArray<N,T> a(shape);
        TIC;
        for(size_t j=0; j<a.size(); ++j) {
            a(j) = j; //ATTENTION: this is much faster than a[j], but still slow
        }
        t += TOCN;
    }
    std::cout << "  MultiArray write asc " << t/testIter << " msec. " << std::endl;
}

template<int N, class T>
void bench_MultiArray_copy_assignment(
    typename vigra::MultiArrayShape<N>::type shape,
    size_t testIter
) {
    USETICTOC;
    double t;
    for(int tI=0; tI<testIter; ++tI) {
        vigra::MultiArray<N,T> a(shape);
        //for(int i=0; i<a.size(); ++i) { a[i] = i; }
        vigra::MultiArray<N,T> b(a.shape());
        TIC;
        b = a;
        t += TOCN;
    }
    std::cout << "  MultiArray::operator=     " << t/testIter << " msec. " << std::endl;
}

template<int N, class T>
void bench_MultiArray_copy_view(
    typename vigra::MultiArrayShape<N>::type shape,
    size_t testIter
) {
    USETICTOC;
    double t;
    for(int tI=0; tI<testIter; ++tI) {
        vigra::MultiArray<N,T> a(shape);
        vigra::MultiArray<N,T> b(shape);
        vigra::MultiArrayView<N,T> bView = b.view();
        TIC;
        b = a.subarray(typename vigra::MultiArrayShape<N>::type(),shape);
        t += TOCN;
    }
    std::cout << "  MultiArrayView::operator= " << t/testIter << " msec." << std::endl;
}

int main() {
    using namespace vigra;
    using std::cout; using std::endl;
    USETICTOC;

    const int N = 5;
    typedef unsigned char T;

    Shape5 sh(1,300,310,320,1);

    size_t size = 1; for(int i=0; i<N; ++i) { size *= sh[i]; };
    std::cout << "*** size " << size*sizeof(T)/(1024*1024) << "MB:" << std::endl;

    const int testIter = 20;

    std::cout << "* new" << std::endl;
    bench_new<T>(size, testIter);
    std::cout << std::endl;

    std::cout << "* initialize with 0" << std::endl;
    bench_fill<T>(size, testIter);
    bench_allocator_fill<T>(size, testIter);
    bench_memset<T>(size, testIter);
    bench_MultiArray_new<N,T>(sh, testIter);
    std::cout << std::endl;

    std::cout << "* full copy" << std::endl;
    bench_stdcopy<T>(size, testIter);
    bench_memcpy<T>(size, testIter);
    bench_MultiArray_copy_assignment<N,T>(sh, testIter);
    bench_MultiArray_copy_view<N,T>(sh, testIter);
    std::cout << std::endl;

    std::cout << "* write ascending numbers" << std::endl;
    bench_writeasc<T>(size, testIter);
    bench_MultiArray_writeasc<N,T>(sh, testIter);
    std::cout << std::endl;

    MultiArray<N,T> dataCpp(sh);
    typedef MultiArray<N,T>::view_type view_type;

    /*
    std::cout << "data has strides: " << a.stride() << std::endl;
    std::cout << "out has strides:  " << out.stride() << std::endl;
    MultiArrayView<N, T> outViewP = out.view();
    outViewP = outViewP.permuteStridesAscending();
    std::cout << "outViewP has strides:  " << outViewP.stride() << ", " << outViewP.strideOrdering() << std::endl;
    outViewP = outViewP.permuteStridesDescending();
    std::cout << "outViewP has strides:  " << outViewP.stride() << ", " << outViewP.strideOrdering() << std::endl;
    TIC;
    outViewP = mydata.subarray(ShapeN(),sh);
    std::cout << "strides differ " << TOCS << std::endl;
    */

    using namespace boost::python;
    Py_Initialize();
    _import_array();
    object main_module((handle<>(borrowed(PyImport_AddModule("__main__")))));
    object main_namespace = main_module.attr("__dict__");

    std::stringstream pyCode;
    pyCode << "import numpy; ";
    pyCode << "a = numpy.zeros((";
    for(int i=0; i<N; ++i) { pyCode << dataCpp.shape(i); if(i<N-1) { pyCode << ","; } }
    pyCode << "), dtype=numpy.uint8);";
    std::cout << "running python code \"" << pyCode.str() << "\"" << std::endl;

    handle<> ignored((PyRun_String(pyCode.str().c_str(),
                      Py_file_input, main_namespace.ptr(), main_namespace.ptr() ) ));

    object objectA = main_namespace["a"];
    if(!PyArray_Check(objectA.ptr())) { throw std::runtime_error("failed to get array"); }
    PyArrayObject* pyA = (PyArrayObject*)objectA.ptr();
    std::cout << "numpy array dim     = " << PyArray_NDIM(pyA) << std::endl;
    std::cout << "            shape   = ";
    std::copy(PyArray_DIMS(pyA), PyArray_DIMS(pyA)+PyArray_NDIM(pyA), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
    std::cout << "            strides = ";
    std::copy(PyArray_STRIDES(pyA), PyArray_STRIDES(pyA)+PyArray_NDIM(pyA), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;

    vigra::NumpyArray<N,T> numpyA((PyObject*)pyA);
    std::cout << "vigra::NumpyArray strides = " << numpyA.stride() << std::endl;

    TIC;
    numpyA = dataCpp;
    std::cout << "copy from c++ into Numpy array (1): " << TOCS << std::endl;

    MultiArray<N,T> dataCppR(Shape5(1,320,310,300,1));
    std::cout << "dataCppR strides = " << dataCppR.stride() << std::endl;
    TIC;
    numpyA = dataCppR.permuteStridesDescending();
    std::cout << "copy from c++ into Numpy array (2):" << TOCS << std::endl;

    return 0;
}
    <|endoftext|>


<commit_before>/* Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 *
 * Copyright 2022 INRIA.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*! \file BodyShapeRecord.hpp
  \brief Definition of an abstract Body shape record
  The objective of this class is to keep associate ds and static body woth the
shape in a contactor.
*/

#ifndef BodyShapeRecord_h
#define BodyShapeRecord_h

// We need to maintain a record associating each body with a shape,
// contactor, and collision object for each shape type.  We also need
// to access generic shape stuff (group, margin) by a pointer from the
// collision callback, so we need a record base class.
class BodyShapeRecord {
public:
  BodyShapeRecord(SP::SiconosVector b, SP::SecondOrderDS d, SP::SiconosShape sh,
                  SP::SiconosContactor con, SP::StaticBody staticCSR)
      : base(b), ds(d), sshape(sh), contactor(con),
        shape_version(sh->version()), staticBody(staticCSR)
  {
  }
  virtual ~BodyShapeRecord() {}

  SP::SiconosVector base;
  SP::SecondOrderDS ds;
  SP::SiconosShape sshape;
  SP::SiconosContactor contactor;
  unsigned int shape_version;
  SP::StaticBody staticBody;

  VIRTUAL_ACCEPT_VISITORS();
};

#endif /* BodyShapeRecord_h */
<commit_msg>[mechanics] add display method<commit_after>/* Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 *
 * Copyright 2022 INRIA.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*! \file BodyShapeRecord.hpp
  \brief Definition of an abstract Body shape record
  The objective of this class is to keep associate ds and static body woth the
shape in a contactor.
*/

#ifndef BodyShapeRecord_h
#define BodyShapeRecord_h

// We need to maintain a record associating each body with a shape,
// contactor, and collision object for each shape type.  We also need
// to access generic shape stuff (group, margin) by a pointer from the
// collision callback, so we need a record base class.
class BodyShapeRecord {
public:
  BodyShapeRecord(SP::SiconosVector b, SP::SecondOrderDS d, SP::SiconosShape sh,
                  SP::SiconosContactor con, SP::StaticBody staticCSR)
      : base(b), ds(d), sshape(sh), contactor(con),
        shape_version(sh->version()), staticBody(staticCSR)
  {
  }
  virtual ~BodyShapeRecord() {}

  SP::SiconosVector base;
  SP::SecondOrderDS ds;
  SP::SiconosShape sshape;
  SP::SiconosContactor contactor;
  unsigned int shape_version;
  SP::StaticBody staticBody;

  void display() const
  {
    std::cout << "BodyShapeRecord display" << std::endl;

    if (ds)
    {
      std::cout << "ds number: " << ds->number() << std::endl;
    }
    if (staticBody)
    {
      std::cout << "static Body number :" << staticBody->number << std::endl;
    }

  };

  VIRTUAL_ACCEPT_VISITORS();
};

#endif /* BodyShapeRecord_h */
<|endoftext|>


<commit_before>
#include "register_types.h"

// Godot headers
#include "object_type_db.h"
#include "reference.h"
#include "ustring.h"

// Wrap for oda
#include "engine.h"

#include <vector>
#include <string>

using std::string;
using std::vector;

const static string paths[1] = {"patches"};

class ODAModule : public Reference {
  OBJ_TYPE(ODAModule, Reference);
  public:
    ODAModule ()
      : engine_(vector<string>(paths, paths + sizeof(paths)/sizeof(string))) {}
    bool ok () const { return engine_.ok(); }
    size_t eventInstance (const String &name) {
      return engine_.eventInstance(name.c_str());
    }
  protected:
    static void _bind_methods () {
      ObjectTypeDB::bind_method("ok", &ODAModule::ok);
      ObjectTypeDB::bind_method("eventInstance", &ODAModule::eventInstance);
    }
  private:
    oda::godot::Engine engine_;
};

void register_openda_types () {
  ObjectTypeDB::register_type<ODAModule>();
}

void unregister_openda_types () {
  // nothing at all?
}

<commit_msg>Event creation<commit_after>
#include "register_types.h"

// Godot headers
#include "object_type_db.h"
#include "reference.h"
#include "ustring.h"

// Wrap for oda
#include "engine.h"

#include <vector>
#include <string>

using std::string;
using std::vector;

const static string paths[1] = {"patches"};

class ODAModule : public Reference {
  OBJ_TYPE(ODAModule, Reference);
  public:
    ODAModule ()
      : engine_(vector<string>(paths, paths + sizeof(paths)/sizeof(string))) {}
    bool ok () const { return engine_.ok(); }
    size_t eventInstance (const String &name) {
      return engine_.eventInstance(name.ascii().get_data());
    }
  protected:
    static void _bind_methods () {
      ObjectTypeDB::bind_method("ok", &ODAModule::ok);
      ObjectTypeDB::bind_method("eventInstance", &ODAModule::eventInstance);
    }
  private:
    oda::godot::Engine engine_;
};

void register_openda_types () {
  ObjectTypeDB::register_type<ODAModule>();
}

void unregister_openda_types () {
  // nothing at all?
}

<|endoftext|>