<commit_before>
#include "Wren++.h"
#include "File.h"
#include "detail/ChunkAllocator.h"
#include <cstdlib>  // for malloc
#include <cstring>  // for strcmp, memcpy
#include <cstdio>
#include <cassert>

namespace wrenpp {
AllocStats stats{};
}

namespace {

std::unordered_map< std::size_t, WrenForeignMethodFn > boundForeignMethods{};
std::unordered_map< std::size_t, WrenForeignClassMethods > boundForeignClasses{};

WrenForeignMethodFn foreignMethodProvider(WrenVM* vm,
    const char* module,
    const char* className,
    bool isStatic,
    const char* signature) {
    auto it = boundForeignMethods.find(wrenpp::detail::hashMethodSignature(module, className, isStatic, signature));
    if (it == boundForeignMethods.end()) {
        return NULL;
    }

    return it->second;
}

WrenForeignClassMethods foreignClassProvider(WrenVM* vm, const char* m, const char* c) {
    auto it = boundForeignClasses.find(wrenpp::detail::hashClassSignature(m, c));
    if (it == boundForeignClasses.end()) {
        return WrenForeignClassMethods{ nullptr, nullptr };
    }

    return it->second;
}

char* loadModuleFnWrapper(WrenVM* vm, const char* mod) {
    return wrenpp::VM::loadModuleFn(mod);
}

void writeFnWrapper(WrenVM* vm, const char* text) {
    wrenpp::VM::writeFn(vm, text);
}

wrenpp::detail::ChunkAllocator* allocator{ nullptr };

void* reallocateFnWrapper(void* memory, std::size_t newSize) {
    if (newSize > wrenpp::stats.largestByte) {
        wrenpp::stats.largestByte = newSize;
    }
    else if (newSize < wrenpp::stats.smallestByte) {
        wrenpp::stats.smallestByte = newSize;
    }
    wrenpp::stats.count++;
    wrenpp::stats.accumulation += newSize;

    assert(allocator != nullptr);
    return allocator->realloc(memory, newSize);
}

}

namespace wrenpp {

namespace detail {
void registerFunction(const std::string& mod, const std::string& cName, bool isStatic, std::string sig, FunctionPtr function) {
    std::size_t hash = detail::hashMethodSignature(mod.c_str(), cName.c_str(), isStatic, sig.c_str());
    boundForeignMethods.insert(std::make_pair(hash, function));
}

void registerClass(const std::string& mod, std::string cName, WrenForeignClassMethods methods) {
    std::size_t hash = detail::hashClassSignature(mod.c_str(), cName.c_str());
    boundForeignClasses.insert(std::make_pair(hash, methods));
}
}

Value::Value(WrenVM* vm, WrenValue* val)
    : vm_{ vm },
    value_{ val },
    refCount_{ nullptr } {
    refCount_ = new unsigned;
    *refCount_ = 1u;
}

Value::Value(const Value& other)
    : vm_{ other.vm_ },
    value_{ other.value_ },
    refCount_{ other.refCount_ } {
    retain_();
}

Value::Value(Value&& other)
    : vm_{ other.vm_ },
    value_{ other.value_ },
    refCount_{ other.refCount_ } {
    other.vm_ = nullptr;
    other.value_ = nullptr;
    other.refCount_ = nullptr;
}

Value& Value::operator=(const Value& rhs) {
    release_();
    vm_ = rhs.vm_;
    value_ = rhs.value_;
    refCount_ = rhs.refCount_;
    retain_();
    return *this;
}

Value& Value::operator=(Value&& rhs) {
    release_();
    vm_ = rhs.vm_;
    value_ = rhs.value_;
    refCount_ = rhs.refCount_;
    rhs.vm_ = nullptr;
    rhs.value_ = nullptr;
    rhs.refCount_ = nullptr;
    return *this;

}

Value::~Value() {
    release_();
}

bool Value::isNull() const {
    return value_ == nullptr;
}

WrenValue* Value::pointer() {
    return value_;
}

void Value::retain_() {
    *refCount_ += 1u;
}

void Value::release_() {
    if (refCount_) {
        *refCount_ -= 1u;
        if (*refCount_ == 0u) {
            wrenReleaseValue(vm_, value_);
            delete refCount_;
            refCount_ = nullptr;
        }
    }
}

Method::Method(VM* vm, WrenValue* variable, WrenValue* method)
    : vm_(vm),
    method_(method),
    variable_(variable),
    refCount_(nullptr) {
    refCount_ = new unsigned;
    *refCount_ = 1u;
}

Method::Method(const Method& other)
    : vm_(other.vm_),
    method_(other.method_),
    variable_(other.variable_),
    refCount_(other.refCount_) {
    retain_();
}

Method::Method(Method&& other)
    : vm_(other.vm_),
    method_(other.method_),
    variable_(other.variable_),
    refCount_(other.refCount_) {
    other.vm_ = nullptr;
    other.method_ = nullptr;
    other.variable_ = nullptr;
    other.refCount_ = nullptr;
}

Method::~Method() {
    release_();
}

Method& Method::operator=(const Method& rhs) {
    release_();
    vm_ = rhs.vm_;
    method_ = rhs.method_;
    variable_ = rhs.variable_;
    refCount_ = rhs.refCount_;
    retain_();
    return *this;
}

Method& Method::operator=(Method&& rhs) {
    release_();
    vm_ = rhs.vm_;
    method_ = rhs.method_;
    variable_ = rhs.variable_;
    refCount_ = rhs.refCount_;
    rhs.vm_ = nullptr;
    rhs.method_ = nullptr;
    rhs.variable_ = nullptr;
    rhs.refCount_ = nullptr;
    return *this;
}

void Method::retain_() {
    *refCount_ += 1u;
}

void Method::release_() {
    if (refCount_) {
        *refCount_ -= 1u;
        if (*refCount_ == 0u) {
            wrenReleaseValue(vm_->vm(), method_);
            wrenReleaseValue(vm_->vm(), variable_);
            delete refCount_;
            refCount_ = nullptr;
        }
    }
}

ModuleContext::ModuleContext(std::string module)
    : name_(module)
{}

ClassContext ModuleContext::beginClass(std::string c) {
    return ClassContext(c, this);
}

void ModuleContext::endModule() {}

ModuleContext beginModule(std::string mod) {
    return ModuleContext{ mod };
}

ModuleContext& ClassContext::endClass() {
    return *module_;
}

ClassContext::ClassContext(std::string c, ModuleContext* mod)
    : module_(mod),
    class_(c)
{}

ClassContext& ClassContext::bindCFunction(bool isStatic, std::string signature, FunctionPtr function) {
    detail::registerFunction(module_->name_, class_, isStatic, signature, function);
    return *this;
}

/*
 * Returns the source as a heap-allocated string.
 * Uses malloc, because our reallocateFn is set to default:
 * it uses malloc, realloc and free.
 * */
LoadModuleFn VM::loadModuleFn = [](const char* mod) -> char* {
    std::string path(mod);
    path += ".wren";
    std::string source;
    try {
        source = wrenpp::fileToString(path);
    }
    catch (const std::exception&) {
        return NULL;
    }
    char* buffer = (char*)malloc(source.size());
    assert(buffer != nullptr);
    memcpy(buffer, source.c_str(), source.size());
    return buffer;
};

WriteFn VM::writeFn = [](WrenVM* vm, const char* text) -> void {
    printf("%s", text);
    fflush(stdout);
};

AllocateFn VM::allocateFn = std::malloc;

FreeFn VM::freeFn = std::free;

std::size_t VM::initialHeapSize = 0xA00000u;

std::size_t VM::minHeapSize = 0x100000u;

int VM::heapGrowthPercent = 50;

std::size_t VM::chunkSize = 0x500000u;

VM::VM()
    : vm_{ nullptr },
    allocator_{} {
    setState_();

    WrenConfiguration configuration{};
    wrenInitConfiguration( &configuration );
    configuration.reallocateFn = reallocateFnWrapper;
    configuration.initialHeapSize = initialHeapSize;
    configuration.minHeapSize = minHeapSize;
    configuration.heapGrowthPercent = heapGrowthPercent;
    configuration.bindForeignMethodFn = foreignMethodProvider;
    configuration.loadModuleFn = loadModuleFnWrapper;
    configuration.bindForeignClassFn = foreignClassProvider;
    configuration.writeFn = writeFnWrapper;
    vm_ = wrenNewVM( &configuration );
}

VM::VM(VM&& other )
:   vm_( other.vm_ ) {
    other.vm_ = nullptr;
}

VM& VM::operator=(VM&& rhs ) {
    vm_             = rhs.vm_;
    rhs.vm_         = nullptr;
    return *this;
}

VM::~VM() {
    if ( vm_ != nullptr ) {
        wrenFreeVM( vm_ );
    }
    allocator = nullptr;
}

WrenVM* VM::vm() {
    return vm_;
}

Result VM::executeModule( const std::string& mod ) {
    setState_();
    const std::string source( loadModuleFn( mod.c_str() ) );
    auto res = wrenInterpret( vm_, source.c_str() );

    if ( res == WrenInterpretResult::WREN_RESULT_COMPILE_ERROR ) {
        return Result::CompileError;
    }

    if ( res == WrenInterpretResult::WREN_RESULT_RUNTIME_ERROR ) {
        return Result::RuntimeError;
    }

    return Result::Success;
}

Result VM::executeString( const std::string& code ) {
    setState_();
    auto res = wrenInterpret( vm_, code.c_str() );

    if ( res == WrenInterpretResult::WREN_RESULT_COMPILE_ERROR ) {
        return Result::CompileError;
    }

    if ( res == WrenInterpretResult::WREN_RESULT_RUNTIME_ERROR ) {
        return Result::RuntimeError;
    }

    return Result::Success;
}

void VM::collectGarbage() {
    wrenCollectGarbage( vm_ );
}

Method VM::method(
    const std::string& mod,
    const std::string& var,
    const std::string& sig
) {
    setState_();
    wrenEnsureSlots( vm_, 1 );
    wrenGetVariable( vm_, mod.c_str(), var.c_str(), 0 );
    WrenValue* variable = wrenGetSlotValue( vm_, 0 );
    WrenValue* handle = wrenMakeCallHandle(vm_, sig.c_str());
    return Method( this, variable, handle );
}

void VM::setState_() {
    allocator = &allocator_;
}

}
<commit_msg>Fix VM move, and set state in method release as well<commit_after>
#include "Wren++.h"
#include "File.h"
#include "detail/ChunkAllocator.h"
#include <cstdlib>  // for malloc
#include <cstring>  // for strcmp, memcpy
#include <cstdio>
#include <cassert>

namespace wrenpp {
AllocStats stats{};
}

namespace {

std::unordered_map< std::size_t, WrenForeignMethodFn > boundForeignMethods{};
std::unordered_map< std::size_t, WrenForeignClassMethods > boundForeignClasses{};

WrenForeignMethodFn foreignMethodProvider(WrenVM* vm,
    const char* module,
    const char* className,
    bool isStatic,
    const char* signature) {
    auto it = boundForeignMethods.find(wrenpp::detail::hashMethodSignature(module, className, isStatic, signature));
    if (it == boundForeignMethods.end()) {
        return NULL;
    }

    return it->second;
}

WrenForeignClassMethods foreignClassProvider(WrenVM* vm, const char* m, const char* c) {
    auto it = boundForeignClasses.find(wrenpp::detail::hashClassSignature(m, c));
    if (it == boundForeignClasses.end()) {
        return WrenForeignClassMethods{ nullptr, nullptr };
    }

    return it->second;
}

char* loadModuleFnWrapper(WrenVM* vm, const char* mod) {
    return wrenpp::VM::loadModuleFn(mod);
}

void writeFnWrapper(WrenVM* vm, const char* text) {
    wrenpp::VM::writeFn(vm, text);
}

wrenpp::detail::ChunkAllocator* allocator{ nullptr };

void* reallocateFnWrapper(void* memory, std::size_t newSize) {
    if (newSize > wrenpp::stats.largestByte) {
        wrenpp::stats.largestByte = newSize;
    }
    else if (newSize < wrenpp::stats.smallestByte) {
        wrenpp::stats.smallestByte = newSize;
    }
    wrenpp::stats.count++;
    wrenpp::stats.accumulation += newSize;

    assert(allocator != nullptr);
    return allocator->realloc(memory, newSize);
}

}

namespace wrenpp {

namespace detail {
void registerFunction(const std::string& mod, const std::string& cName, bool isStatic, std::string sig, FunctionPtr function) {
    std::size_t hash = detail::hashMethodSignature(mod.c_str(), cName.c_str(), isStatic, sig.c_str());
    boundForeignMethods.insert(std::make_pair(hash, function));
}

void registerClass(const std::string& mod, std::string cName, WrenForeignClassMethods methods) {
    std::size_t hash = detail::hashClassSignature(mod.c_str(), cName.c_str());
    boundForeignClasses.insert(std::make_pair(hash, methods));
}
}

Value::Value(WrenVM* vm, WrenValue* val)
    : vm_{ vm },
    value_{ val },
    refCount_{ nullptr } {
    refCount_ = new unsigned;
    *refCount_ = 1u;
}

Value::Value(const Value& other)
    : vm_{ other.vm_ },
    value_{ other.value_ },
    refCount_{ other.refCount_ } {
    retain_();
}

Value::Value(Value&& other)
    : vm_{ other.vm_ },
    value_{ other.value_ },
    refCount_{ other.refCount_ } {
    other.vm_ = nullptr;
    other.value_ = nullptr;
    other.refCount_ = nullptr;
}

Value& Value::operator=(const Value& rhs) {
    release_();
    vm_ = rhs.vm_;
    value_ = rhs.value_;
    refCount_ = rhs.refCount_;
    retain_();
    return *this;
}

Value& Value::operator=(Value&& rhs) {
    release_();
    vm_ = rhs.vm_;
    value_ = rhs.value_;
    refCount_ = rhs.refCount_;
    rhs.vm_ = nullptr;
    rhs.value_ = nullptr;
    rhs.refCount_ = nullptr;
    return *this;

}

Value::~Value() {
    release_();
}

bool Value::isNull() const {
    return value_ == nullptr;
}

WrenValue* Value::pointer() {
    return value_;
}

void Value::retain_() {
    *refCount_ += 1u;
}

void Value::release_() {
    if (refCount_) {
        *refCount_ -= 1u;
        if (*refCount_ == 0u) {
            wrenReleaseValue(vm_, value_);
            delete refCount_;
            refCount_ = nullptr;
        }
    }
}

Method::Method(VM* vm, WrenValue* variable, WrenValue* method)
    : vm_(vm),
    method_(method),
    variable_(variable),
    refCount_(nullptr) {
    refCount_ = new unsigned;
    *refCount_ = 1u;
}

Method::Method(const Method& other)
    : vm_(other.vm_),
    method_(other.method_),
    variable_(other.variable_),
    refCount_(other.refCount_) {
    retain_();
}

Method::Method(Method&& other)
    : vm_(other.vm_),
    method_(other.method_),
    variable_(other.variable_),
    refCount_(other.refCount_) {
    other.vm_ = nullptr;
    other.method_ = nullptr;
    other.variable_ = nullptr;
    other.refCount_ = nullptr;
}

Method::~Method() {
    release_();
}

Method& Method::operator=(const Method& rhs) {
    release_();
    vm_ = rhs.vm_;
    method_ = rhs.method_;
    variable_ = rhs.variable_;
    refCount_ = rhs.refCount_;
    retain_();
    return *this;
}

Method& Method::operator=(Method&& rhs) {
    release_();
    vm_ = rhs.vm_;
    method_ = rhs.method_;
    variable_ = rhs.variable_;
    refCount_ = rhs.refCount_;
    rhs.vm_ = nullptr;
    rhs.method_ = nullptr;
    rhs.variable_ = nullptr;
    rhs.refCount_ = nullptr;
    return *this;
}

void Method::retain_() {
    *refCount_ += 1u;
}

void Method::release_() {
    if (refCount_) {
        *refCount_ -= 1u;
        if (*refCount_ == 0u) {
            vm_->setState_();   // wrenReelaseValue will cause wren to free memory
            wrenReleaseValue(vm_->vm(), method_);
            wrenReleaseValue(vm_->vm(), variable_);
            delete refCount_;
            refCount_ = nullptr;
        }
    }
}

ModuleContext::ModuleContext(std::string module)
    : name_(module)
{}

ClassContext ModuleContext::beginClass(std::string c) {
    return ClassContext(c, this);
}

void ModuleContext::endModule() {}

ModuleContext beginModule(std::string mod) {
    return ModuleContext{ mod };
}

ModuleContext& ClassContext::endClass() {
    return *module_;
}

ClassContext::ClassContext(std::string c, ModuleContext* mod)
    : module_(mod),
    class_(c)
{}

ClassContext& ClassContext::bindCFunction(bool isStatic, std::string signature, FunctionPtr function) {
    detail::registerFunction(module_->name_, class_, isStatic, signature, function);
    return *this;
}

/*
 * Returns the source as a heap-allocated string.
 * Uses malloc, because our reallocateFn is set to default:
 * it uses malloc, realloc and free.
 * */
LoadModuleFn VM::loadModuleFn = [](const char* mod) -> char* {
    std::string path(mod);
    path += ".wren";
    std::string source;
    try {
        source = wrenpp::fileToString(path);
    }
    catch (const std::exception&) {
        return NULL;
    }
    char* buffer = (char*)malloc(source.size());
    assert(buffer != nullptr);
    memcpy(buffer, source.c_str(), source.size());
    return buffer;
};

WriteFn VM::writeFn = [](WrenVM* vm, const char* text) -> void {
    printf("%s", text);
    fflush(stdout);
};

AllocateFn VM::allocateFn = std::malloc;

FreeFn VM::freeFn = std::free;

std::size_t VM::initialHeapSize = 0xA00000u;

std::size_t VM::minHeapSize = 0x100000u;

int VM::heapGrowthPercent = 50;

std::size_t VM::chunkSize = 0x500000u;

VM::VM()
    : vm_{ nullptr },
    allocator_{} {
    setState_();

    WrenConfiguration configuration{};
    wrenInitConfiguration( &configuration );
    configuration.reallocateFn = reallocateFnWrapper;
    configuration.initialHeapSize = initialHeapSize;
    configuration.minHeapSize = minHeapSize;
    configuration.heapGrowthPercent = heapGrowthPercent;
    configuration.bindForeignMethodFn = foreignMethodProvider;
    configuration.loadModuleFn = loadModuleFnWrapper;
    configuration.bindForeignClassFn = foreignClassProvider;
    configuration.writeFn = writeFnWrapper;
    vm_ = wrenNewVM( &configuration );
}

VM::VM(VM&& other )
    : vm_{ other.vm_ },
    allocator_{ std::move(other.allocator_) } {
    other.vm_ = nullptr;
}

VM& VM::operator=(VM&& rhs ) {
    vm_             = rhs.vm_;
    allocator_      = std::move(rhs.allocator_);
    rhs.vm_         = nullptr;
    return *this;
}

VM::~VM() {
    if ( vm_ != nullptr ) {
        wrenFreeVM( vm_ );
    }
    allocator = nullptr;
}

WrenVM* VM::vm() {
    return vm_;
}

Result VM::executeModule( const std::string& mod ) {
    setState_();
    const std::string source( loadModuleFn( mod.c_str() ) );
    auto res = wrenInterpret( vm_, source.c_str() );

    if ( res == WrenInterpretResult::WREN_RESULT_COMPILE_ERROR ) {
        return Result::CompileError;
    }

    if ( res == WrenInterpretResult::WREN_RESULT_RUNTIME_ERROR ) {
        return Result::RuntimeError;
    }

    return Result::Success;
}

Result VM::executeString( const std::string& code ) {
    setState_();
    auto res = wrenInterpret( vm_, code.c_str() );

    if ( res == WrenInterpretResult::WREN_RESULT_COMPILE_ERROR ) {
        return Result::CompileError;
    }

    if ( res == WrenInterpretResult::WREN_RESULT_RUNTIME_ERROR ) {
        return Result::RuntimeError;
    }

    return Result::Success;
}

void VM::collectGarbage() {
    wrenCollectGarbage( vm_ );
}

Method VM::method(
    const std::string& mod,
    const std::string& var,
    const std::string& sig
) {
    setState_();
    wrenEnsureSlots( vm_, 1 );
    wrenGetVariable( vm_, mod.c_str(), var.c_str(), 0 );
    WrenValue* variable = wrenGetSlotValue( vm_, 0 );
    WrenValue* handle = wrenMakeCallHandle(vm_, sig.c_str());
    return Method( this, variable, handle );
}

void VM::setState_() {
    allocator = &allocator_;
}

}
<|endoftext|>


<commit_before>//===-- MachineCSE.cpp - Machine Common Subexpression Elimination Pass ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass performs global common subexpression elimination on machine
// instructions using a scoped hash table based value numbering scheme. It
// must be run while the machine function is still in SSA form.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "machine-cse"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"

using namespace llvm;

STATISTIC(NumCoalesces, "Number of copies coalesced");
STATISTIC(NumCSEs,      "Number of common subexpression eliminated");

namespace {
  class MachineCSE : public MachineFunctionPass {
    const TargetInstrInfo *TII;
    MachineRegisterInfo  *MRI;
    MachineDominatorTree *DT;
  public:
    static char ID; // Pass identification
    MachineCSE() : MachineFunctionPass(&ID), CurrVN(0) {}

    virtual bool runOnMachineFunction(MachineFunction &MF);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      MachineFunctionPass::getAnalysisUsage(AU);
      AU.addRequired<MachineDominatorTree>();
      AU.addPreserved<MachineDominatorTree>();
    }

  private:
    unsigned CurrVN;
    ScopedHashTable<MachineInstr*, unsigned, MachineInstrExpressionTrait> VNT;
    SmallVector<MachineInstr*, 64> Exps;

    bool PerformTrivialCoalescing(MachineInstr *MI, MachineBasicBlock *MBB);
    bool ProcessBlock(MachineDomTreeNode *Node);
  };
} // end anonymous namespace

char MachineCSE::ID = 0;
static RegisterPass<MachineCSE>
X("machine-cse", "Machine Common Subexpression Elimination");

FunctionPass *llvm::createMachineCSEPass() { return new MachineCSE(); }

bool MachineCSE::PerformTrivialCoalescing(MachineInstr *MI,
                                          MachineBasicBlock *MBB) {
  bool Changed = false;
  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    MachineOperand &MO = MI->getOperand(i);
    if (!MO.isReg() || !MO.isUse())
      continue;
    unsigned Reg = MO.getReg();
    if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg))
      continue;
    if (!MRI->hasOneUse(Reg))
      // Only coalesce single use copies. This ensure the copy will be
      // deleted.
      continue;
    MachineInstr *DefMI = MRI->getVRegDef(Reg);
    if (DefMI->getParent() != MBB)
      continue;
    unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx;
    if (TII->isMoveInstr(*DefMI, SrcReg, DstReg, SrcSubIdx, DstSubIdx) &&
        TargetRegisterInfo::isVirtualRegister(SrcReg) &&
        !SrcSubIdx && !DstSubIdx) {
      MO.setReg(SrcReg);
      DefMI->eraseFromParent();
      ++NumCoalesces;
      Changed = true;
    }
  }

  return Changed;
}

static bool hasLivePhysRegDefUse(MachineInstr *MI) {
  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    MachineOperand &MO = MI->getOperand(i);
    if (!MO.isReg())
      continue;
    unsigned Reg = MO.getReg();
    if (!Reg)
      continue;
    // FIXME: This is obviously overly conservative. On x86 lots of instructions
    // will def EFLAGS and they are not marked dead at this point.
    if (TargetRegisterInfo::isPhysicalRegister(Reg) &&
        !(MO.isDef() && MO.isDead()))
      return true;
  }
  return false;
}

bool MachineCSE::ProcessBlock(MachineDomTreeNode *Node) {
  bool Changed = false;

  ScopedHashTableScope<MachineInstr*, unsigned,
    MachineInstrExpressionTrait> VNTS(VNT);
  MachineBasicBlock *MBB = Node->getBlock();
  for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; ) {
    MachineInstr *MI = &*I;
    ++I;
    bool SawStore = false;
    if (!MI->isSafeToMove(TII, 0, SawStore))
      continue;
    // Ignore copies or instructions that read / write physical registers
    // (except for dead defs of physical registers).
    unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx;
    if (TII->isMoveInstr(*MI, SrcReg, DstReg, SrcSubIdx, DstSubIdx) ||
        MI->isExtractSubreg() || MI->isInsertSubreg() || MI->isSubregToReg())
      continue;
    if (hasLivePhysRegDefUse(MI))
      continue;

    bool FoundCSE = VNT.count(MI);
    if (!FoundCSE) {
      // Look for trivial copy coalescing opportunities.
      if (PerformTrivialCoalescing(MI, MBB))
        FoundCSE = VNT.count(MI);
    }

    if (!FoundCSE) {
      VNT.insert(MI, CurrVN++);
      Exps.push_back(MI);
      continue;
    }

    // Found a common subexpression, eliminate it.
    unsigned CSVN = VNT.lookup(MI);
    MachineInstr *CSMI = Exps[CSVN];
    DEBUG(dbgs() << "Examining: " << *MI);
    DEBUG(dbgs() << "*** Found a common subexpression: " << *CSMI);
    unsigned NumDefs = MI->getDesc().getNumDefs();
    for (unsigned i = 0, e = MI->getNumOperands(); NumDefs && i != e; ++i) {
      MachineOperand &MO = MI->getOperand(i);
      if (!MO.isReg() || !MO.isDef())
        continue;
      unsigned OldReg = MO.getReg();
      unsigned NewReg = CSMI->getOperand(i).getReg();
      assert(OldReg != NewReg &&
             TargetRegisterInfo::isVirtualRegister(OldReg) &&
             TargetRegisterInfo::isVirtualRegister(NewReg) &&
             "Do not CSE physical register defs!");
      MRI->replaceRegWith(OldReg, NewReg);
      --NumDefs;
    }
    MI->eraseFromParent();
    ++NumCSEs;
  }

  // Recursively call ProcessBlock with childred.
  const std::vector<MachineDomTreeNode*> &Children = Node->getChildren();
  for (unsigned i = 0, e = Children.size(); i != e; ++i)
    Changed |= ProcessBlock(Children[i]);

  return Changed;
}

bool MachineCSE::runOnMachineFunction(MachineFunction &MF) {
  TII = MF.getTarget().getInstrInfo();
  MRI = &MF.getRegInfo();
  DT = &getAnalysis<MachineDominatorTree>();
  return ProcessBlock(DT->getRootNode());
}
<commit_msg>Fix a logic error. An instruction that has a live physical register def cannot be CSE'ed, but it *can* be used to replace a common subexpression.<commit_after>//===-- MachineCSE.cpp - Machine Common Subexpression Elimination Pass ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass performs global common subexpression elimination on machine
// instructions using a scoped hash table based value numbering scheme. It
// must be run while the machine function is still in SSA form.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "machine-cse"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"

using namespace llvm;

STATISTIC(NumCoalesces, "Number of copies coalesced");
STATISTIC(NumCSEs,      "Number of common subexpression eliminated");

namespace {
  class MachineCSE : public MachineFunctionPass {
    const TargetInstrInfo *TII;
    MachineRegisterInfo  *MRI;
    MachineDominatorTree *DT;
  public:
    static char ID; // Pass identification
    MachineCSE() : MachineFunctionPass(&ID), CurrVN(0) {}

    virtual bool runOnMachineFunction(MachineFunction &MF);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      MachineFunctionPass::getAnalysisUsage(AU);
      AU.addRequired<MachineDominatorTree>();
      AU.addPreserved<MachineDominatorTree>();
    }

  private:
    unsigned CurrVN;
    ScopedHashTable<MachineInstr*, unsigned, MachineInstrExpressionTrait> VNT;
    SmallVector<MachineInstr*, 64> Exps;

    bool PerformTrivialCoalescing(MachineInstr *MI, MachineBasicBlock *MBB);
    bool ProcessBlock(MachineDomTreeNode *Node);
  };
} // end anonymous namespace

char MachineCSE::ID = 0;
static RegisterPass<MachineCSE>
X("machine-cse", "Machine Common Subexpression Elimination");

FunctionPass *llvm::createMachineCSEPass() { return new MachineCSE(); }

bool MachineCSE::PerformTrivialCoalescing(MachineInstr *MI,
                                          MachineBasicBlock *MBB) {
  bool Changed = false;
  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    MachineOperand &MO = MI->getOperand(i);
    if (!MO.isReg() || !MO.isUse())
      continue;
    unsigned Reg = MO.getReg();
    if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg))
      continue;
    if (!MRI->hasOneUse(Reg))
      // Only coalesce single use copies. This ensure the copy will be
      // deleted.
      continue;
    MachineInstr *DefMI = MRI->getVRegDef(Reg);
    if (DefMI->getParent() != MBB)
      continue;
    unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx;
    if (TII->isMoveInstr(*DefMI, SrcReg, DstReg, SrcSubIdx, DstSubIdx) &&
        TargetRegisterInfo::isVirtualRegister(SrcReg) &&
        !SrcSubIdx && !DstSubIdx) {
      MO.setReg(SrcReg);
      DefMI->eraseFromParent();
      ++NumCoalesces;
      Changed = true;
    }
  }

  return Changed;
}

static bool hasLivePhysRegDefUse(MachineInstr *MI) {
  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    MachineOperand &MO = MI->getOperand(i);
    if (!MO.isReg())
      continue;
    unsigned Reg = MO.getReg();
    if (!Reg)
      continue;
    // FIXME: This is obviously overly conservative. On x86 lots of instructions
    // will def EFLAGS and they are not marked dead at this point.
    if (TargetRegisterInfo::isPhysicalRegister(Reg) &&
        !(MO.isDef() && MO.isDead()))
      return true;
  }
  return false;
}

bool MachineCSE::ProcessBlock(MachineDomTreeNode *Node) {
  bool Changed = false;

  ScopedHashTableScope<MachineInstr*, unsigned,
    MachineInstrExpressionTrait> VNTS(VNT);
  MachineBasicBlock *MBB = Node->getBlock();
  for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; ) {
    MachineInstr *MI = &*I;
    ++I;
    bool SawStore = false;
    if (!MI->isSafeToMove(TII, 0, SawStore))
      continue;
    // Ignore copies or instructions that read / write physical registers
    // (except for dead defs of physical registers).
    unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx;
    if (TII->isMoveInstr(*MI, SrcReg, DstReg, SrcSubIdx, DstSubIdx) ||
        MI->isExtractSubreg() || MI->isInsertSubreg() || MI->isSubregToReg())
      continue;

    bool FoundCSE = VNT.count(MI);
    if (!FoundCSE) {
      // Look for trivial copy coalescing opportunities.
      if (PerformTrivialCoalescing(MI, MBB))
        FoundCSE = VNT.count(MI);
    }

    // If the instruction defines a physical register and the value *may* be
    // used, then it's not safe to replace it with a common subexpression.
    if (FoundCSE && hasLivePhysRegDefUse(MI))
      FoundCSE = false;

    if (!FoundCSE) {
      VNT.insert(MI, CurrVN++);
      Exps.push_back(MI);
      continue;
    }

    // Found a common subexpression, eliminate it.
    unsigned CSVN = VNT.lookup(MI);
    MachineInstr *CSMI = Exps[CSVN];
    DEBUG(dbgs() << "Examining: " << *MI);
    DEBUG(dbgs() << "*** Found a common subexpression: " << *CSMI);
    unsigned NumDefs = MI->getDesc().getNumDefs();
    for (unsigned i = 0, e = MI->getNumOperands(); NumDefs && i != e; ++i) {
      MachineOperand &MO = MI->getOperand(i);
      if (!MO.isReg() || !MO.isDef())
        continue;
      unsigned OldReg = MO.getReg();
      unsigned NewReg = CSMI->getOperand(i).getReg();
      assert(OldReg != NewReg &&
             TargetRegisterInfo::isVirtualRegister(OldReg) &&
             TargetRegisterInfo::isVirtualRegister(NewReg) &&
             "Do not CSE physical register defs!");
      MRI->replaceRegWith(OldReg, NewReg);
      --NumDefs;
    }
    MI->eraseFromParent();
    ++NumCSEs;
  }

  // Recursively call ProcessBlock with childred.
  const std::vector<MachineDomTreeNode*> &Children = Node->getChildren();
  for (unsigned i = 0, e = Children.size(); i != e; ++i)
    Changed |= ProcessBlock(Children[i]);

  return Changed;
}

bool MachineCSE::runOnMachineFunction(MachineFunction &MF) {
  TII = MF.getTarget().getInstrInfo();
  MRI = &MF.getRegInfo();
  DT = &getAnalysis<MachineDominatorTree>();
  return ProcessBlock(DT->getRootNode());
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2011 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

/**
 * @file brw_vec4_copy_propagation.cpp
 *
 * Implements tracking of values copied between registers, and
 * optimizations based on that: copy propagation and constant
 * propagation.
 */

#include "brw_vec4.h"
extern "C" {
#include "main/macros.h"
}

namespace brw {

static bool
is_direct_copy(vec4_instruction *inst)
{
   return (inst->opcode == BRW_OPCODE_MOV &&
	   !inst->predicate &&
	   inst->dst.file == GRF &&
	   !inst->saturate &&
	   !inst->dst.reladdr &&
	   !inst->src[0].reladdr &&
	   inst->dst.type == inst->src[0].type);
}

static bool
is_dominated_by_previous_instruction(vec4_instruction *inst)
{
   return (inst->opcode != BRW_OPCODE_DO &&
	   inst->opcode != BRW_OPCODE_WHILE &&
	   inst->opcode != BRW_OPCODE_ELSE &&
	   inst->opcode != BRW_OPCODE_ENDIF);
}

static bool
try_constant_propagation(vec4_instruction *inst, int arg, src_reg *values[4])
{
   /* For constant propagation, we only handle the same constant
    * across all 4 channels.  Some day, we should handle the 8-bit
    * float vector format, which would let us constant propagate
    * vectors better.
    */
   src_reg value = *values[0];
   for (int i = 1; i < 4; i++) {
      if (!value.equals(values[i]))
	 return false;
   }

   if (value.file != IMM)
      return false;

   if (inst->src[arg].abs) {
      if (value.type == BRW_REGISTER_TYPE_F) {
	 value.imm.f = fabs(value.imm.f);
      } else if (value.type == BRW_REGISTER_TYPE_D) {
	 if (value.imm.i < 0)
	    value.imm.i = -value.imm.i;
      }
   }

   if (inst->src[arg].negate) {
      if (value.type == BRW_REGISTER_TYPE_F)
	 value.imm.f = -value.imm.f;
      else
	 value.imm.u = -value.imm.u;
   }

   switch (inst->opcode) {
   case BRW_OPCODE_MOV:
      inst->src[arg] = value;
      return true;

   case BRW_OPCODE_MUL:
   case BRW_OPCODE_ADD:
      if (arg == 1) {
	 inst->src[arg] = value;
	 return true;
      } else if (arg == 0 && inst->src[1].file != IMM) {
	 /* Fit this constant in by commuting the operands.  Exception: we
	  * can't do this for 32-bit integer MUL because it's asymmetric.
	  */
	 if (inst->opcode == BRW_OPCODE_MUL &&
	     (inst->src[1].type == BRW_REGISTER_TYPE_D ||
	      inst->src[1].type == BRW_REGISTER_TYPE_UD))
	    break;
	 inst->src[0] = inst->src[1];
	 inst->src[1] = value;
	 return true;
      }
      break;

   case BRW_OPCODE_CMP:
      if (arg == 1) {
	 inst->src[arg] = value;
	 return true;
      } else if (arg == 0 && inst->src[1].file != IMM) {
	 uint32_t new_cmod;

	 new_cmod = brw_swap_cmod(inst->conditional_mod);
	 if (new_cmod != ~0u) {
	    /* Fit this constant in by swapping the operands and
	     * flipping the test.
	     */
	    inst->src[0] = inst->src[1];
	    inst->src[1] = value;
	    inst->conditional_mod = new_cmod;
	    return true;
	 }
      }
      break;

   case BRW_OPCODE_SEL:
      if (arg == 1) {
	 inst->src[arg] = value;
	 return true;
      } else if (arg == 0 && inst->src[1].file != IMM) {
	 inst->src[0] = inst->src[1];
	 inst->src[1] = value;

	 /* If this was predicated, flipping operands means
	  * we also need to flip the predicate.
	  */
	 if (inst->conditional_mod == BRW_CONDITIONAL_NONE) {
	    inst->predicate_inverse = !inst->predicate_inverse;
	 }
	 return true;
      }
      break;

   default:
      break;
   }

   return false;
}

bool
vec4_visitor::try_copy_propagation(struct intel_context *intel,
                                   vec4_instruction *inst, int arg,
                                   src_reg *values[4])
{
   /* For constant propagation, we only handle the same constant
    * across all 4 channels.  Some day, we should handle the 8-bit
    * float vector format, which would let us constant propagate
    * vectors better.
    */
   src_reg value = *values[0];
   for (int i = 1; i < 4; i++) {
      /* This is equals() except we don't care about the swizzle. */
      if (value.file != values[i]->file ||
	  value.reg != values[i]->reg ||
	  value.reg_offset != values[i]->reg_offset ||
	  value.type != values[i]->type ||
	  value.negate != values[i]->negate ||
	  value.abs != values[i]->abs) {
	 return false;
      }
   }

   /* Compute the swizzle of the original register by swizzling the
    * component loaded from each value according to the swizzle of
    * operand we're going to change.
    */
   int s[4];
   for (int i = 0; i < 4; i++) {
      s[i] = BRW_GET_SWZ(values[i]->swizzle,
			 BRW_GET_SWZ(inst->src[arg].swizzle, i));
   }
   value.swizzle = BRW_SWIZZLE4(s[0], s[1], s[2], s[3]);

   if (value.file != UNIFORM &&
       value.file != GRF &&
       value.file != ATTR)
      return false;

   if (inst->src[arg].abs) {
      value.negate = false;
      value.abs = true;
   }
   if (inst->src[arg].negate)
      value.negate = !value.negate;

   bool has_source_modifiers = (value.negate || value.abs ||
                                value.swizzle != BRW_SWIZZLE_XYZW ||
                                value.file == UNIFORM);

   /* gen6 math and gen7+ SENDs from GRFs ignore source modifiers on
    * instructions.
    */
   if (has_source_modifiers && !can_do_source_mods(inst))
      return false;

   bool is_3src_inst = (inst->opcode == BRW_OPCODE_LRP ||
                        inst->opcode == BRW_OPCODE_MAD ||
                        inst->opcode == BRW_OPCODE_BFE ||
                        inst->opcode == BRW_OPCODE_BFI2);
   if (is_3src_inst && value.file == UNIFORM)
      return false;

   /* We can't copy-propagate a UD negation into a condmod
    * instruction, because the condmod ends up looking at the 33-bit
    * signed accumulator value instead of the 32-bit value we wanted
    */
   if (inst->conditional_mod &&
       value.negate &&
       value.type == BRW_REGISTER_TYPE_UD)
      return false;

   /* Don't report progress if this is a noop. */
   if (value.equals(&inst->src[arg]))
      return false;

   value.type = inst->src[arg].type;
   inst->src[arg] = value;
   return true;
}

bool
vec4_visitor::opt_copy_propagation()
{
   bool progress = false;
   src_reg *cur_value[virtual_grf_reg_count][4];

   memset(&cur_value, 0, sizeof(cur_value));

   foreach_list(node, &this->instructions) {
      vec4_instruction *inst = (vec4_instruction *)node;

      /* This pass only works on basic blocks.  If there's flow
       * control, throw out all our information and start from
       * scratch.
       *
       * This should really be fixed by using a structure like in
       * src/glsl/opt_copy_propagation.cpp to track available copies.
       */
      if (!is_dominated_by_previous_instruction(inst)) {
	 memset(cur_value, 0, sizeof(cur_value));
	 continue;
      }

      /* For each source arg, see if each component comes from a copy
       * from the same type file (IMM, GRF, UNIFORM), and try
       * optimizing out access to the copy result
       */
      for (int i = 2; i >= 0; i--) {
	 /* Copied values end up in GRFs, and we don't track reladdr
	  * accesses.
	  */
	 if (inst->src[i].file != GRF ||
	     inst->src[i].reladdr)
	    continue;

	 int reg = (virtual_grf_reg_map[inst->src[i].reg] +
		    inst->src[i].reg_offset);

	 /* Find the regs that each swizzle component came from.
	  */
	 src_reg *values[4];
	 int c;
	 for (c = 0; c < 4; c++) {
	    values[c] = cur_value[reg][BRW_GET_SWZ(inst->src[i].swizzle, c)];

	    /* If there's no available copy for this channel, bail.
	     * We could be more aggressive here -- some channels might
	     * not get used based on the destination writemask.
	     */
	    if (!values[c])
	       break;

	    /* We'll only be able to copy propagate if the sources are
	     * all from the same file -- there's no ability to swizzle
	     * 0 or 1 constants in with source registers like in i915.
	     */
	    if (c > 0 && values[c - 1]->file != values[c]->file)
	       break;
	 }

	 if (c != 4)
	    continue;

	 if (try_constant_propagation(inst, i, values) ||
	     try_copy_propagation(intel, inst, i, values))
	    progress = true;
      }

      /* Track available source registers. */
      if (inst->dst.file == GRF) {
	 const int reg =
	    virtual_grf_reg_map[inst->dst.reg] + inst->dst.reg_offset;

	 /* Update our destination's current channel values.  For a direct copy,
	  * the value is the newly propagated source.  Otherwise, we don't know
	  * the new value, so clear it.
	  */
	 bool direct_copy = is_direct_copy(inst);
	 for (int i = 0; i < 4; i++) {
	    if (inst->dst.writemask & (1 << i)) {
	       cur_value[reg][i] = direct_copy ? &inst->src[0] : NULL;
	    }
	 }

	 /* Clear the records for any registers whose current value came from
	  * our destination's updated channels, as the two are no longer equal.
	  */
	 if (inst->dst.reladdr)
	    memset(cur_value, 0, sizeof(cur_value));
	 else {
	    for (int i = 0; i < virtual_grf_reg_count; i++) {
	       for (int j = 0; j < 4; j++) {
		  if (inst->dst.writemask & (1 << j) &&
		      cur_value[i][j] &&
		      cur_value[i][j]->file == GRF &&
		      cur_value[i][j]->reg == inst->dst.reg &&
		      cur_value[i][j]->reg_offset == inst->dst.reg_offset) {
		     cur_value[i][j] = NULL;
		  }
	       }
	    }
	 }
      }
   }

   if (progress)
      live_intervals_valid = false;

   return progress;
}

} /* namespace brw */
<commit_msg>i965/vs: Allow copy propagation into MUL/MACH.<commit_after>/*
 * Copyright © 2011 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

/**
 * @file brw_vec4_copy_propagation.cpp
 *
 * Implements tracking of values copied between registers, and
 * optimizations based on that: copy propagation and constant
 * propagation.
 */

#include "brw_vec4.h"
extern "C" {
#include "main/macros.h"
}

namespace brw {

static bool
is_direct_copy(vec4_instruction *inst)
{
   return (inst->opcode == BRW_OPCODE_MOV &&
	   !inst->predicate &&
	   inst->dst.file == GRF &&
	   !inst->saturate &&
	   !inst->dst.reladdr &&
	   !inst->src[0].reladdr &&
	   inst->dst.type == inst->src[0].type);
}

static bool
is_dominated_by_previous_instruction(vec4_instruction *inst)
{
   return (inst->opcode != BRW_OPCODE_DO &&
	   inst->opcode != BRW_OPCODE_WHILE &&
	   inst->opcode != BRW_OPCODE_ELSE &&
	   inst->opcode != BRW_OPCODE_ENDIF);
}

static bool
try_constant_propagation(vec4_instruction *inst, int arg, src_reg *values[4])
{
   /* For constant propagation, we only handle the same constant
    * across all 4 channels.  Some day, we should handle the 8-bit
    * float vector format, which would let us constant propagate
    * vectors better.
    */
   src_reg value = *values[0];
   for (int i = 1; i < 4; i++) {
      if (!value.equals(values[i]))
	 return false;
   }

   if (value.file != IMM)
      return false;

   if (inst->src[arg].abs) {
      if (value.type == BRW_REGISTER_TYPE_F) {
	 value.imm.f = fabs(value.imm.f);
      } else if (value.type == BRW_REGISTER_TYPE_D) {
	 if (value.imm.i < 0)
	    value.imm.i = -value.imm.i;
      }
   }

   if (inst->src[arg].negate) {
      if (value.type == BRW_REGISTER_TYPE_F)
	 value.imm.f = -value.imm.f;
      else
	 value.imm.u = -value.imm.u;
   }

   switch (inst->opcode) {
   case BRW_OPCODE_MOV:
      inst->src[arg] = value;
      return true;

   case BRW_OPCODE_MACH:
   case BRW_OPCODE_MUL:
   case BRW_OPCODE_ADD:
      if (arg == 1) {
	 inst->src[arg] = value;
	 return true;
      } else if (arg == 0 && inst->src[1].file != IMM) {
	 /* Fit this constant in by commuting the operands.  Exception: we
	  * can't do this for 32-bit integer MUL/MACH because it's asymmetric.
	  */
	 if ((inst->opcode == BRW_OPCODE_MUL ||
              inst->opcode == BRW_OPCODE_MACH) &&
	     (inst->src[1].type == BRW_REGISTER_TYPE_D ||
	      inst->src[1].type == BRW_REGISTER_TYPE_UD))
	    break;
	 inst->src[0] = inst->src[1];
	 inst->src[1] = value;
	 return true;
      }
      break;

   case BRW_OPCODE_CMP:
      if (arg == 1) {
	 inst->src[arg] = value;
	 return true;
      } else if (arg == 0 && inst->src[1].file != IMM) {
	 uint32_t new_cmod;

	 new_cmod = brw_swap_cmod(inst->conditional_mod);
	 if (new_cmod != ~0u) {
	    /* Fit this constant in by swapping the operands and
	     * flipping the test.
	     */
	    inst->src[0] = inst->src[1];
	    inst->src[1] = value;
	    inst->conditional_mod = new_cmod;
	    return true;
	 }
      }
      break;

   case BRW_OPCODE_SEL:
      if (arg == 1) {
	 inst->src[arg] = value;
	 return true;
      } else if (arg == 0 && inst->src[1].file != IMM) {
	 inst->src[0] = inst->src[1];
	 inst->src[1] = value;

	 /* If this was predicated, flipping operands means
	  * we also need to flip the predicate.
	  */
	 if (inst->conditional_mod == BRW_CONDITIONAL_NONE) {
	    inst->predicate_inverse = !inst->predicate_inverse;
	 }
	 return true;
      }
      break;

   default:
      break;
   }

   return false;
}

bool
vec4_visitor::try_copy_propagation(struct intel_context *intel,
                                   vec4_instruction *inst, int arg,
                                   src_reg *values[4])
{
   /* For constant propagation, we only handle the same constant
    * across all 4 channels.  Some day, we should handle the 8-bit
    * float vector format, which would let us constant propagate
    * vectors better.
    */
   src_reg value = *values[0];
   for (int i = 1; i < 4; i++) {
      /* This is equals() except we don't care about the swizzle. */
      if (value.file != values[i]->file ||
	  value.reg != values[i]->reg ||
	  value.reg_offset != values[i]->reg_offset ||
	  value.type != values[i]->type ||
	  value.negate != values[i]->negate ||
	  value.abs != values[i]->abs) {
	 return false;
      }
   }

   /* Compute the swizzle of the original register by swizzling the
    * component loaded from each value according to the swizzle of
    * operand we're going to change.
    */
   int s[4];
   for (int i = 0; i < 4; i++) {
      s[i] = BRW_GET_SWZ(values[i]->swizzle,
			 BRW_GET_SWZ(inst->src[arg].swizzle, i));
   }
   value.swizzle = BRW_SWIZZLE4(s[0], s[1], s[2], s[3]);

   if (value.file != UNIFORM &&
       value.file != GRF &&
       value.file != ATTR)
      return false;

   if (inst->src[arg].abs) {
      value.negate = false;
      value.abs = true;
   }
   if (inst->src[arg].negate)
      value.negate = !value.negate;

   bool has_source_modifiers = (value.negate || value.abs ||
                                value.swizzle != BRW_SWIZZLE_XYZW ||
                                value.file == UNIFORM);

   /* gen6 math and gen7+ SENDs from GRFs ignore source modifiers on
    * instructions.
    */
   if (has_source_modifiers && !can_do_source_mods(inst))
      return false;

   bool is_3src_inst = (inst->opcode == BRW_OPCODE_LRP ||
                        inst->opcode == BRW_OPCODE_MAD ||
                        inst->opcode == BRW_OPCODE_BFE ||
                        inst->opcode == BRW_OPCODE_BFI2);
   if (is_3src_inst && value.file == UNIFORM)
      return false;

   /* We can't copy-propagate a UD negation into a condmod
    * instruction, because the condmod ends up looking at the 33-bit
    * signed accumulator value instead of the 32-bit value we wanted
    */
   if (inst->conditional_mod &&
       value.negate &&
       value.type == BRW_REGISTER_TYPE_UD)
      return false;

   /* Don't report progress if this is a noop. */
   if (value.equals(&inst->src[arg]))
      return false;

   value.type = inst->src[arg].type;
   inst->src[arg] = value;
   return true;
}

bool
vec4_visitor::opt_copy_propagation()
{
   bool progress = false;
   src_reg *cur_value[virtual_grf_reg_count][4];

   memset(&cur_value, 0, sizeof(cur_value));

   foreach_list(node, &this->instructions) {
      vec4_instruction *inst = (vec4_instruction *)node;

      /* This pass only works on basic blocks.  If there's flow
       * control, throw out all our information and start from
       * scratch.
       *
       * This should really be fixed by using a structure like in
       * src/glsl/opt_copy_propagation.cpp to track available copies.
       */
      if (!is_dominated_by_previous_instruction(inst)) {
	 memset(cur_value, 0, sizeof(cur_value));
	 continue;
      }

      /* For each source arg, see if each component comes from a copy
       * from the same type file (IMM, GRF, UNIFORM), and try
       * optimizing out access to the copy result
       */
      for (int i = 2; i >= 0; i--) {
	 /* Copied values end up in GRFs, and we don't track reladdr
	  * accesses.
	  */
	 if (inst->src[i].file != GRF ||
	     inst->src[i].reladdr)
	    continue;

	 int reg = (virtual_grf_reg_map[inst->src[i].reg] +
		    inst->src[i].reg_offset);

	 /* Find the regs that each swizzle component came from.
	  */
	 src_reg *values[4];
	 int c;
	 for (c = 0; c < 4; c++) {
	    values[c] = cur_value[reg][BRW_GET_SWZ(inst->src[i].swizzle, c)];

	    /* If there's no available copy for this channel, bail.
	     * We could be more aggressive here -- some channels might
	     * not get used based on the destination writemask.
	     */
	    if (!values[c])
	       break;

	    /* We'll only be able to copy propagate if the sources are
	     * all from the same file -- there's no ability to swizzle
	     * 0 or 1 constants in with source registers like in i915.
	     */
	    if (c > 0 && values[c - 1]->file != values[c]->file)
	       break;
	 }

	 if (c != 4)
	    continue;

	 if (try_constant_propagation(inst, i, values) ||
	     try_copy_propagation(intel, inst, i, values))
	    progress = true;
      }

      /* Track available source registers. */
      if (inst->dst.file == GRF) {
	 const int reg =
	    virtual_grf_reg_map[inst->dst.reg] + inst->dst.reg_offset;

	 /* Update our destination's current channel values.  For a direct copy,
	  * the value is the newly propagated source.  Otherwise, we don't know
	  * the new value, so clear it.
	  */
	 bool direct_copy = is_direct_copy(inst);
	 for (int i = 0; i < 4; i++) {
	    if (inst->dst.writemask & (1 << i)) {
	       cur_value[reg][i] = direct_copy ? &inst->src[0] : NULL;
	    }
	 }

	 /* Clear the records for any registers whose current value came from
	  * our destination's updated channels, as the two are no longer equal.
	  */
	 if (inst->dst.reladdr)
	    memset(cur_value, 0, sizeof(cur_value));
	 else {
	    for (int i = 0; i < virtual_grf_reg_count; i++) {
	       for (int j = 0; j < 4; j++) {
		  if (inst->dst.writemask & (1 << j) &&
		      cur_value[i][j] &&
		      cur_value[i][j]->file == GRF &&
		      cur_value[i][j]->reg == inst->dst.reg &&
		      cur_value[i][j]->reg_offset == inst->dst.reg_offset) {
		     cur_value[i][j] = NULL;
		  }
	       }
	    }
	 }
      }
   }

   if (progress)
      live_intervals_valid = false;

   return progress;
}

} /* namespace brw */
<|endoftext|>


<commit_before>/**
 * @file
 * @brief Implementation of Geant4 deposition module
 * @remarks Based on code from Mathieu Benoit
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "DepositionGeant4Module.hpp"

#include <limits>
#include <string>
#include <utility>

#include <G4EmParameters.hh>
#include <G4HadronicProcessStore.hh>
#include <G4LogicalVolume.hh>
#include <G4PhysListFactory.hh>
#include <G4RunManager.hh>
#include <G4StepLimiterPhysics.hh>
#include <G4UImanager.hh>
#include <G4UserLimits.hh>

#include "G4FieldManager.hh"
#include "G4TransportationManager.hh"
#include "G4UniformMagField.hh"

#include "core/config/exceptions.h"
#include "core/geometry/GeometryManager.hpp"
#include "core/module/exceptions.h"
#include "core/utils/log.h"
#include "objects/DepositedCharge.hpp"
#include "tools/ROOT.h"
#include "tools/geant4.h"

#include "GeneratorActionG4.hpp"
#include "SensitiveDetectorActionG4.hpp"
#include "SetTrackInfoUserHookG4.hpp"

#define G4_NUM_SEEDS 10

using namespace allpix;

/**
 * Includes the particle source point to the geometry using \ref GeometryManager::addPoint.
 */
DepositionGeant4Module::DepositionGeant4Module(Configuration& config, Messenger* messenger, GeometryManager* geo_manager)
    : Module(config), messenger_(messenger), geo_manager_(geo_manager), last_event_num_(1), run_manager_g4_(nullptr) {
    // Create user limits for maximum step length in the sensor
    user_limits_ = std::make_unique<G4UserLimits>(config_.get<double>("max_step_length", Units::get(1.0, "um")));

    // Set default physics list
    config_.setDefault("physics_list", "FTFP_BERT_LIV");

    config_.setDefault("source_type", "beam");
    config_.setDefault<bool>("output_plots", false);
    config_.setDefault<int>("output_plots_scale", Units::get(100, "ke"));

    // Set alias for support of old particle source definition
    config_.setAlias("source_position", "beam_position");
    config_.setAlias("source_energy", "beam_energy");
    config_.setAlias("source_energy_spread", "beam_energy_spread");

    // Add the particle source position to the geometry
    geo_manager_->addPoint(config_.get<ROOT::Math::XYZPoint>("source_position"));
}

/**
 * Module depends on \ref GeometryBuilderGeant4Module loaded first, because it owns the pointer to the Geant4 run manager.
 */
void DepositionGeant4Module::init() {
    // Load the G4 run manager (which is owned by the geometry builder)
    run_manager_g4_ = G4RunManager::GetRunManager();
    if(run_manager_g4_ == nullptr) {
        throw ModuleError("Cannot deposit charges using Geant4 without a Geant4 geometry builder");
    }

    // Suppress all output from G4
    SUPPRESS_STREAM(G4cout);

    // Get UI manager for sending commands
    G4UImanager* ui_g4 = G4UImanager::GetUIpointer();

    // Apply optional PAI model
    if(config_.get<bool>("enable_pai", false)) {
        LOG(TRACE) << "Enabling PAI model on all detectors";
        G4EmParameters::Instance();

        for(auto& detector : geo_manager_->getDetectors()) {
            // Get logical volume
            auto logical_volume = detector->getExternalObject<G4LogicalVolume>("sensor_log");
            if(logical_volume == nullptr) {
                throw ModuleError("Detector " + detector->getName() + " has no sensitive device (broken Geant4 geometry)");
            }
            // Create region
            G4Region* region = new G4Region(detector->getName() + "_sensor_region");
            region->AddRootLogicalVolume(logical_volume.get());

            auto pai_model = config_.get<std::string>("pai_model", "pai");
            auto lcase_model = pai_model;
            std::transform(lcase_model.begin(), lcase_model.end(), lcase_model.begin(), ::tolower);
            if(lcase_model == "pai") {
                pai_model = "PAI";
            } else if(lcase_model == "paiphoton") {
                pai_model = "PAIphoton";
            } else {
                throw InvalidValueError(config_, "pai_model", "model has to be either 'pai' or 'paiphoton'");
            }

            ui_g4->ApplyCommand("/process/em/AddPAIRegion all " + region->GetName() + " " + pai_model);
        }
    }

    // Find the physics list
    G4PhysListFactory physListFactory;
    G4VModularPhysicsList* physicsList = physListFactory.GetReferencePhysList(config_.get<std::string>("physics_list"));
    if(physicsList == nullptr) {
        std::string message = "specified physics list does not exists";
        std::vector<G4String> base_lists = physListFactory.AvailablePhysLists();
        message += " (available base lists are ";
        for(auto& base_list : base_lists) {
            message += base_list;
            message += ", ";
        }
        message = message.substr(0, message.size() - 2);
        message += " with optional suffixes for electromagnetic lists ";
        std::vector<G4String> em_lists = physListFactory.AvailablePhysListsEM();
        for(auto& em_list : em_lists) {
            if(em_list.empty()) {
                continue;
            }
            message += em_list;
            message += ", ";
        }
        message = message.substr(0, message.size() - 2);
        message += ")";

        throw InvalidValueError(config_, "physics_list", message);
    } else {
        LOG(INFO) << "Using G4 physics list \"" << config_.get<std::string>("physics_list") << "\"";
    }
    // Register a step limiter (uses the user limits defined earlier)
    physicsList->RegisterPhysics(new G4StepLimiterPhysics());

    // Set the range-cut off threshold for secondary production:
    double production_cut;
    if(config_.has("range_cut")) {
        production_cut = config_.get<double>("range_cut");
        LOG(INFO) << "Setting configured G4 production cut to " << Units::display(production_cut, {"mm", "um"});
    } else {
        // Define the production cut as one fifth of the minimum size (thickness, pitch) among the detectors
        double min_size = std::numeric_limits<double>::max();
        std::string min_detector;
        for(auto& detector : geo_manager_->getDetectors()) {
            auto model = detector->getModel();
            double prev_min_size = min_size;
            min_size =
                std::min({min_size, model->getPixelSize().x(), model->getPixelSize().y(), model->getSensorSize().z()});
            if(min_size != prev_min_size) {
                min_detector = detector->getName();
            }
        }
        production_cut = min_size / 5;
        LOG(INFO) << "Setting G4 production cut to " << Units::display(production_cut, {"mm", "um"})
                  << ", derived from properties of detector \"" << min_detector << "\"";
    }
    ui_g4->ApplyCommand("/run/setCut " + std::to_string(production_cut));

    // Initialize the physics list
    LOG(TRACE) << "Initializing physics processes";
    run_manager_g4_->SetUserInitialization(physicsList);
    run_manager_g4_->InitializePhysics();

    // Initialize the full run manager to ensure correct state flags
    run_manager_g4_->Initialize();

    // Build particle generator
    LOG(TRACE) << "Constructing particle source";
    auto generator = new GeneratorActionG4(config_);
    run_manager_g4_->SetUserAction(generator);

    track_info_manager_ = std::make_unique<TrackInfoManager>();

    // User hook to store additional information at track initialization and termination as well as custom track ids
    auto userTrackIDHook = new SetTrackInfoUserHookG4(track_info_manager_.get());
    run_manager_g4_->SetUserAction(userTrackIDHook);

    if(geo_manager_->hasMagneticField()) {
        MagneticFieldType magnetic_field_type_ = geo_manager_->getMagneticFieldType();

        if(magnetic_field_type_ == MagneticFieldType::CONSTANT) {
            ROOT::Math::XYZVector b_field = geo_manager_->getMagneticField(ROOT::Math::XYZPoint(0., 0., 0.));
            G4MagneticField* magField = new G4UniformMagField(G4ThreeVector(b_field.x(), b_field.y(), b_field.z()));
            G4FieldManager* globalFieldMgr = G4TransportationManager::GetTransportationManager()->GetFieldManager();
            globalFieldMgr->SetDetectorField(magField);
            globalFieldMgr->CreateChordFinder(magField);
        } else {
            throw ModuleError("Magnetic field enabled, but not constant. This can't be handled by this module yet.");
        }
    }

    // Get the creation energy for charge (default is silicon electron hole pair energy)
    auto charge_creation_energy = config_.get<double>("charge_creation_energy", Units::get(3.64, "eV"));

    // Loop through all detectors and set the sensitive detector action that handles the particle passage
    bool useful_deposition = false;
    for(auto& detector : geo_manager_->getDetectors()) {
        // Do not add sensitive detector for detectors that have no listeners for the deposited charges
        // FIXME Probably the MCParticle has to be checked as well
        if(!messenger_->hasReceiver(this,
                                    std::make_shared<DepositedChargeMessage>(std::vector<DepositedCharge>(), detector))) {
            LOG(INFO) << "Not depositing charges in " << detector->getName()
                      << " because there is no listener for its output";
            continue;
        }
        useful_deposition = true;

        // Get model of the sensitive device
        auto sensitive_detector_action =
            new SensitiveDetectorActionG4(this, detector, messenger_, track_info_manager_.get(), charge_creation_energy);
        auto logical_volume = detector->getExternalObject<G4LogicalVolume>("sensor_log");
        if(logical_volume == nullptr) {
            throw ModuleError("Detector " + detector->getName() + " has no sensitive device (broken Geant4 geometry)");
        }

        // Apply the user limits to this element
        logical_volume->SetUserLimits(user_limits_.get());

        // Add the sensitive detector action
        logical_volume->SetSensitiveDetector(sensitive_detector_action);
        sensors_.push_back(sensitive_detector_action);

        // If requested, prepare output plots
        if(config_.get<bool>("output_plots")) {
            LOG(TRACE) << "Creating output plots";

            // Plot axis are in kilo electrons - convert from framework units!
            int maximum = static_cast<int>(Units::convert(config_.get<int>("output_plots_scale"), "ke"));
            int nbins = 5 * maximum;

            // Create histograms if needed
            std::string plot_name = "deposited_charge_" + sensitive_detector_action->getName();
            charge_per_event_[sensitive_detector_action->getName()] =
                new TH1D(plot_name.c_str(), "deposited charge per event;deposited charge [ke];events", nbins, 0, maximum);
        }
    }

    if(!useful_deposition) {
        LOG(ERROR) << "Not a single listener for deposited charges, module is useless!";
    }

    // Disable verbose messages from processes
    ui_g4->ApplyCommand("/process/verbose 0");
    ui_g4->ApplyCommand("/process/em/verbose 0");
    ui_g4->ApplyCommand("/process/eLoss/verbose 0");
    G4HadronicProcessStore::Instance()->SetVerbose(0);

    // Set the random seed for Geant4 generation
    // NOTE Assumes this is the only Geant4 module using random numbers
    std::string seed_command = "/random/setSeeds ";
    for(int i = 0; i < G4_NUM_SEEDS; ++i) {
        seed_command += std::to_string(static_cast<uint32_t>(getRandomSeed() % INT_MAX));
        if(i != G4_NUM_SEEDS - 1) {
            seed_command += " ";
        }
    }
    ui_g4->ApplyCommand(seed_command);

    // Release the output stream
    RELEASE_STREAM(G4cout);
}

void DepositionGeant4Module::run(unsigned int event_num) {
    // Suppress output stream if not in debugging mode
    IFLOG(DEBUG);
    else {
        SUPPRESS_STREAM(G4cout);
    }

    // Start a single event from the beam
    LOG(TRACE) << "Enabling beam";
    run_manager_g4_->BeamOn(static_cast<int>(config_.get<unsigned int>("number_of_particles", 1)));
    last_event_num_ = event_num;

    // Release the stream (if it was suspended)
    RELEASE_STREAM(G4cout);

    track_info_manager_->createMCTracks();

    // Dispatch the necessary messages
    for(auto& sensor : sensors_) {
        sensor->dispatchMessages();

        // Fill output plots if requested:
        if(config_.get<bool>("output_plots")) {
            double charge = static_cast<double>(Units::convert(sensor->getDepositedCharge(), "ke"));
            charge_per_event_[sensor->getName()]->Fill(charge);
        }
    }

    track_info_manager_->dispatchMessage(this, messenger_);
    track_info_manager_->resetTrackInfoManager();
}

void DepositionGeant4Module::finalize() {
    size_t total_charges = 0;
    for(auto& sensor : sensors_) {
        total_charges += sensor->getTotalDepositedCharge();
    }

    if(config_.get<bool>("output_plots")) {
        // Write histograms
        LOG(TRACE) << "Writing output plots to file";
        for(auto& plot : charge_per_event_) {
            plot.second->Write();
        }
    }

    // Print summary or warns if module did not output any charges
    if(!sensors_.empty() && total_charges > 0 && last_event_num_ > 0) {
        size_t average_charge = total_charges / sensors_.size() / last_event_num_;
        LOG(INFO) << "Deposited total of " << total_charges << " charges in " << sensors_.size() << " sensor(s) (average of "
                  << average_charge << " per sensor for every event)";
    } else {
        LOG(WARNING) << "No charges deposited";
    }
}
<commit_msg>DepositionGeant4: always activate decay physics lists (FIXME: affects non-decaying particles or speed?)<commit_after>/**
 * @file
 * @brief Implementation of Geant4 deposition module
 * @remarks Based on code from Mathieu Benoit
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "DepositionGeant4Module.hpp"

#include <limits>
#include <string>
#include <utility>

#include <G4DecayPhysics.hh>
#include <G4EmParameters.hh>
#include <G4HadronicProcessStore.hh>
#include <G4LogicalVolume.hh>
#include <G4PhysListFactory.hh>
#include <G4RadioactiveDecayPhysics.hh>
#include <G4RunManager.hh>
#include <G4StepLimiterPhysics.hh>
#include <G4UImanager.hh>
#include <G4UserLimits.hh>

#include "G4FieldManager.hh"
#include "G4TransportationManager.hh"
#include "G4UniformMagField.hh"

#include "core/config/exceptions.h"
#include "core/geometry/GeometryManager.hpp"
#include "core/module/exceptions.h"
#include "core/utils/log.h"
#include "objects/DepositedCharge.hpp"
#include "tools/ROOT.h"
#include "tools/geant4.h"

#include "GeneratorActionG4.hpp"
#include "SensitiveDetectorActionG4.hpp"
#include "SetTrackInfoUserHookG4.hpp"

#define G4_NUM_SEEDS 10

using namespace allpix;

/**
 * Includes the particle source point to the geometry using \ref GeometryManager::addPoint.
 */
DepositionGeant4Module::DepositionGeant4Module(Configuration& config, Messenger* messenger, GeometryManager* geo_manager)
    : Module(config), messenger_(messenger), geo_manager_(geo_manager), last_event_num_(1), run_manager_g4_(nullptr) {
    // Create user limits for maximum step length in the sensor
    user_limits_ = std::make_unique<G4UserLimits>(config_.get<double>("max_step_length", Units::get(1.0, "um")));

    // Set default physics list
    config_.setDefault("physics_list", "FTFP_BERT_LIV");

    config_.setDefault("source_type", "beam");
    config_.setDefault<bool>("output_plots", false);
    config_.setDefault<int>("output_plots_scale", Units::get(100, "ke"));

    // Set alias for support of old particle source definition
    config_.setAlias("source_position", "beam_position");
    config_.setAlias("source_energy", "beam_energy");
    config_.setAlias("source_energy_spread", "beam_energy_spread");

    // Add the particle source position to the geometry
    geo_manager_->addPoint(config_.get<ROOT::Math::XYZPoint>("source_position"));
}

/**
 * Module depends on \ref GeometryBuilderGeant4Module loaded first, because it owns the pointer to the Geant4 run manager.
 */
void DepositionGeant4Module::init() {
    // Load the G4 run manager (which is owned by the geometry builder)
    run_manager_g4_ = G4RunManager::GetRunManager();
    if(run_manager_g4_ == nullptr) {
        throw ModuleError("Cannot deposit charges using Geant4 without a Geant4 geometry builder");
    }

    // Suppress all output from G4
    SUPPRESS_STREAM(G4cout);

    // Get UI manager for sending commands
    G4UImanager* ui_g4 = G4UImanager::GetUIpointer();

    // Apply optional PAI model
    if(config_.get<bool>("enable_pai", false)) {
        LOG(TRACE) << "Enabling PAI model on all detectors";
        G4EmParameters::Instance();

        for(auto& detector : geo_manager_->getDetectors()) {
            // Get logical volume
            auto logical_volume = detector->getExternalObject<G4LogicalVolume>("sensor_log");
            if(logical_volume == nullptr) {
                throw ModuleError("Detector " + detector->getName() + " has no sensitive device (broken Geant4 geometry)");
            }
            // Create region
            G4Region* region = new G4Region(detector->getName() + "_sensor_region");
            region->AddRootLogicalVolume(logical_volume.get());

            auto pai_model = config_.get<std::string>("pai_model", "pai");
            auto lcase_model = pai_model;
            std::transform(lcase_model.begin(), lcase_model.end(), lcase_model.begin(), ::tolower);
            if(lcase_model == "pai") {
                pai_model = "PAI";
            } else if(lcase_model == "paiphoton") {
                pai_model = "PAIphoton";
            } else {
                throw InvalidValueError(config_, "pai_model", "model has to be either 'pai' or 'paiphoton'");
            }

            ui_g4->ApplyCommand("/process/em/AddPAIRegion all " + region->GetName() + " " + pai_model);
        }
    }

    // Find the physics list
    G4PhysListFactory physListFactory;
    G4VModularPhysicsList* physicsList = physListFactory.GetReferencePhysList(config_.get<std::string>("physics_list"));
    if(physicsList == nullptr) {
        std::string message = "specified physics list does not exists";
        std::vector<G4String> base_lists = physListFactory.AvailablePhysLists();
        message += " (available base lists are ";
        for(auto& base_list : base_lists) {
            message += base_list;
            message += ", ";
        }
        message = message.substr(0, message.size() - 2);
        message += " with optional suffixes for electromagnetic lists ";
        std::vector<G4String> em_lists = physListFactory.AvailablePhysListsEM();
        for(auto& em_list : em_lists) {
            if(em_list.empty()) {
                continue;
            }
            message += em_list;
            message += ", ";
        }
        message = message.substr(0, message.size() - 2);
        message += ")";

        throw InvalidValueError(config_, "physics_list", message);
    } else {
        LOG(INFO) << "Using G4 physics list \"" << config_.get<std::string>("physics_list") << "\"";
    }
    // Register a step limiter (uses the user limits defined earlier)
    physicsList->RegisterPhysics(new G4StepLimiterPhysics());

    // Radioactive decay
    physicsList->RegisterPhysics(new G4DecayPhysics());
    physicsList->RegisterPhysics(new G4RadioactiveDecayPhysics());

    // Set the range-cut off threshold for secondary production:
    double production_cut;
    if(config_.has("range_cut")) {
        production_cut = config_.get<double>("range_cut");
        LOG(INFO) << "Setting configured G4 production cut to " << Units::display(production_cut, {"mm", "um"});
    } else {
        // Define the production cut as one fifth of the minimum size (thickness, pitch) among the detectors
        double min_size = std::numeric_limits<double>::max();
        std::string min_detector;
        for(auto& detector : geo_manager_->getDetectors()) {
            auto model = detector->getModel();
            double prev_min_size = min_size;
            min_size =
                std::min({min_size, model->getPixelSize().x(), model->getPixelSize().y(), model->getSensorSize().z()});
            if(min_size != prev_min_size) {
                min_detector = detector->getName();
            }
        }
        production_cut = min_size / 5;
        LOG(INFO) << "Setting G4 production cut to " << Units::display(production_cut, {"mm", "um"})
                  << ", derived from properties of detector \"" << min_detector << "\"";
    }
    ui_g4->ApplyCommand("/run/setCut " + std::to_string(production_cut));

    // Initialize the physics list
    LOG(TRACE) << "Initializing physics processes";
    run_manager_g4_->SetUserInitialization(physicsList);
    run_manager_g4_->InitializePhysics();

    // Initialize the full run manager to ensure correct state flags
    run_manager_g4_->Initialize();

    // Build particle generator
    LOG(TRACE) << "Constructing particle source";
    auto generator = new GeneratorActionG4(config_);
    run_manager_g4_->SetUserAction(generator);

    track_info_manager_ = std::make_unique<TrackInfoManager>();

    // User hook to store additional information at track initialization and termination as well as custom track ids
    auto userTrackIDHook = new SetTrackInfoUserHookG4(track_info_manager_.get());
    run_manager_g4_->SetUserAction(userTrackIDHook);

    if(geo_manager_->hasMagneticField()) {
        MagneticFieldType magnetic_field_type_ = geo_manager_->getMagneticFieldType();

        if(magnetic_field_type_ == MagneticFieldType::CONSTANT) {
            ROOT::Math::XYZVector b_field = geo_manager_->getMagneticField(ROOT::Math::XYZPoint(0., 0., 0.));
            G4MagneticField* magField = new G4UniformMagField(G4ThreeVector(b_field.x(), b_field.y(), b_field.z()));
            G4FieldManager* globalFieldMgr = G4TransportationManager::GetTransportationManager()->GetFieldManager();
            globalFieldMgr->SetDetectorField(magField);
            globalFieldMgr->CreateChordFinder(magField);
        } else {
            throw ModuleError("Magnetic field enabled, but not constant. This can't be handled by this module yet.");
        }
    }

    // Get the creation energy for charge (default is silicon electron hole pair energy)
    auto charge_creation_energy = config_.get<double>("charge_creation_energy", Units::get(3.64, "eV"));

    // Loop through all detectors and set the sensitive detector action that handles the particle passage
    bool useful_deposition = false;
    for(auto& detector : geo_manager_->getDetectors()) {
        // Do not add sensitive detector for detectors that have no listeners for the deposited charges
        // FIXME Probably the MCParticle has to be checked as well
        if(!messenger_->hasReceiver(this,
                                    std::make_shared<DepositedChargeMessage>(std::vector<DepositedCharge>(), detector))) {
            LOG(INFO) << "Not depositing charges in " << detector->getName()
                      << " because there is no listener for its output";
            continue;
        }
        useful_deposition = true;

        // Get model of the sensitive device
        auto sensitive_detector_action =
            new SensitiveDetectorActionG4(this, detector, messenger_, track_info_manager_.get(), charge_creation_energy);
        auto logical_volume = detector->getExternalObject<G4LogicalVolume>("sensor_log");
        if(logical_volume == nullptr) {
            throw ModuleError("Detector " + detector->getName() + " has no sensitive device (broken Geant4 geometry)");
        }

        // Apply the user limits to this element
        logical_volume->SetUserLimits(user_limits_.get());

        // Add the sensitive detector action
        logical_volume->SetSensitiveDetector(sensitive_detector_action);
        sensors_.push_back(sensitive_detector_action);

        // If requested, prepare output plots
        if(config_.get<bool>("output_plots")) {
            LOG(TRACE) << "Creating output plots";

            // Plot axis are in kilo electrons - convert from framework units!
            int maximum = static_cast<int>(Units::convert(config_.get<int>("output_plots_scale"), "ke"));
            int nbins = 5 * maximum;

            // Create histograms if needed
            std::string plot_name = "deposited_charge_" + sensitive_detector_action->getName();
            charge_per_event_[sensitive_detector_action->getName()] =
                new TH1D(plot_name.c_str(), "deposited charge per event;deposited charge [ke];events", nbins, 0, maximum);
        }
    }

    if(!useful_deposition) {
        LOG(ERROR) << "Not a single listener for deposited charges, module is useless!";
    }

    // Disable verbose messages from processes
    ui_g4->ApplyCommand("/process/verbose 0");
    ui_g4->ApplyCommand("/process/em/verbose 0");
    ui_g4->ApplyCommand("/process/eLoss/verbose 0");
    G4HadronicProcessStore::Instance()->SetVerbose(0);

    // Set the random seed for Geant4 generation
    // NOTE Assumes this is the only Geant4 module using random numbers
    std::string seed_command = "/random/setSeeds ";
    for(int i = 0; i < G4_NUM_SEEDS; ++i) {
        seed_command += std::to_string(static_cast<uint32_t>(getRandomSeed() % INT_MAX));
        if(i != G4_NUM_SEEDS - 1) {
            seed_command += " ";
        }
    }
    ui_g4->ApplyCommand(seed_command);

    // Release the output stream
    RELEASE_STREAM(G4cout);
}

void DepositionGeant4Module::run(unsigned int event_num) {
    // Suppress output stream if not in debugging mode
    IFLOG(DEBUG);
    else {
        SUPPRESS_STREAM(G4cout);
    }

    // Start a single event from the beam
    LOG(TRACE) << "Enabling beam";
    run_manager_g4_->BeamOn(static_cast<int>(config_.get<unsigned int>("number_of_particles", 1)));
    last_event_num_ = event_num;

    // Release the stream (if it was suspended)
    RELEASE_STREAM(G4cout);

    track_info_manager_->createMCTracks();

    // Dispatch the necessary messages
    for(auto& sensor : sensors_) {
        sensor->dispatchMessages();

        // Fill output plots if requested:
        if(config_.get<bool>("output_plots")) {
            double charge = static_cast<double>(Units::convert(sensor->getDepositedCharge(), "ke"));
            charge_per_event_[sensor->getName()]->Fill(charge);
        }
    }

    track_info_manager_->dispatchMessage(this, messenger_);
    track_info_manager_->resetTrackInfoManager();
}

void DepositionGeant4Module::finalize() {
    size_t total_charges = 0;
    for(auto& sensor : sensors_) {
        total_charges += sensor->getTotalDepositedCharge();
    }

    if(config_.get<bool>("output_plots")) {
        // Write histograms
        LOG(TRACE) << "Writing output plots to file";
        for(auto& plot : charge_per_event_) {
            plot.second->Write();
        }
    }

    // Print summary or warns if module did not output any charges
    if(!sensors_.empty() && total_charges > 0 && last_event_num_ > 0) {
        size_t average_charge = total_charges / sensors_.size() / last_event_num_;
        LOG(INFO) << "Deposited total of " << total_charges << " charges in " << sensors_.size() << " sensor(s) (average of "
                  << average_charge << " per sensor for every event)";
    } else {
        LOG(WARNING) << "No charges deposited";
    }
}
<|endoftext|>


<commit_before>#include "DesktopController.h"
#include <QMutexLocker>
#include <QWidgetAction>
#include "Screen.h"
#include "Light.h"

DesktopController::DesktopController(std::shared_ptr<Light> light) :
  LightController(light, "Ambilight"), active(false), brightness(255)
{
}

void DesktopController::activate()
{
  if(!active)
  {
    active = true;
    pLight->moveToThread(this); //take ownership of the light
    QThread::start();
  }
}

void DesktopController::deactivate()
{
  active = false;
  QMutexLocker waitForThread(&threadActive);
}

bool DesktopController::isActive() const
{
  return active;
}

void DesktopController::setBrightness(const unsigned char value)
{
  brightness = value;
}

QWidgetAction *DesktopController::getMenuWidget()
{
  //FIXME
  qWarning("dummy implementation");
  return new QWidgetAction(NULL);
}

void DesktopController::run()
{
  QMutexLocker lock(&threadActive);
  unsigned char currentBrightness = 255;
  //setup screen
  Screen screen;
  screen.initialize(0); //FIXME load from settings
  //FIXME initialize() can fail(returns a boolean)
  //FIXME this works as long as the pixel format from Screen is always ARGB
  QRgb* buffer = new QRgb[screen.getHeight() * screen.getWidth()];
  std::vector<Region> regions;
  generateRegions(regions, screen.getWidth(), screen.getHeight());

  while(active)
  {
    screen.getScreenBitmap(buffer);
    for(const Region& region : regions)
    {
      const QRgb avg = getAvgOfRegion(region.rect, buffer, screen.getWidth());
      pLight->setColor(region.ledIndex, qRed(avg), qGreen(avg), qBlue(avg));
    }
    pLight->sendColors();

    const unsigned char tempBrightness = brightness;//copy to avoid race condition
    if(tempBrightness != currentBrightness)
    {
      currentBrightness = tempBrightness;
      pLight->setBrightness(tempBrightness);
    }

    QThread::msleep(5);
  }
  delete buffer; //FIXME use scoped destruction
}

QRgb DesktopController::getAvgOfRegion(const QRect& region, QRgb* pBuffer, const int screenWidth) const
{
  unsigned long avgR = 0;
  unsigned long avgG = 0;
  unsigned long avgB = 0;
  const int width = screenWidth;
  for(int y = region.top(); y < region.bottom(); ++y)
  { //FIXME pBuffer should be a parameter
    for(int x = region.left(); x < region.right(); ++x)
    {
      QRgb p = pBuffer[width * y + x];
      avgR += qRed(p);
      avgG += qGreen(p);
      avgB += qBlue(p);
    }
  }
  const int count = region.width() * region.height();
  avgR /= count;
  avgG /= count;
  avgB /= count;
  Q_ASSERT(avgR <= 255);
  Q_ASSERT(avgG <= 255);
  Q_ASSERT(avgB <= 255);
  return qRgb(avgR, avgG, avgB);
}

void DesktopController::generateRegions(std::vector<Region>& regions, const int screenWidth, const int screenHeight) const
{
  //FIXME this should be loaded from config file
  regions.clear();

  const int regionWidth = 120; //FIXME parameter
  const int resX = screenWidth;
  const int resY = screenHeight;
  const int horTotalWidth = resX - 2 * regionWidth;
  const int horRegionCount = 20; //FIXME parameter
  const int horRegionWidth = horTotalWidth / horRegionCount;
  const int vertTotalWidth = resY - 2 * regionWidth;
  const int vertRegionCount = 10;
  const int vertRegionWidth = vertTotalWidth / vertRegionCount;

  //top regions
  for(int rIndex = 30, i = 0; i < horRegionCount; ++i, ++rIndex) //FIXME hard coded led index
  {
    const int regionX = regionWidth + i * horRegionWidth;
    const int regionY = 0;
    Region r;
    r.ledIndex = rIndex;
    r.rect = QRect(regionX, regionY, horRegionWidth, regionWidth);
    regions.push_back(r);
  }

  //bottom regions
  for(int rIndex = 19, i = 0; i < horRegionCount; ++i, --rIndex)//FIXME hard coded led index
  {
    const int regionX = regionWidth + i * horRegionWidth;
    const int regionY = resY - regionWidth;
    Region r;
    r.ledIndex = rIndex;
    r.rect = QRect(regionX, regionY, horRegionWidth, regionWidth);
    regions.push_back(r);
  }

  //left regions
  for(int rIndex = 29, i = 0; i < vertRegionCount; ++i, --rIndex)//FIXME hard coded led index
  {
    const int regionX = 0;
    const int regionY = regionWidth + i * vertRegionWidth;
    Region r;
    r.ledIndex = rIndex;
    r.rect = QRect(regionX, regionY, regionWidth, vertRegionWidth);
    regions.push_back(r);
  }

  //right regions
  for(int rIndex = 50, i = 0; i < vertRegionCount; ++i, ++rIndex)//FIXME hard coded led index
  {
    const int regionX = resX - regionWidth;
    const int regionY = regionWidth + i * vertRegionWidth;
    Region r;
    r.ledIndex = rIndex;
    r.rect = QRect(regionX, regionY, regionWidth, vertRegionWidth);
    regions.push_back(r);
  }
}

<commit_msg>DesktopController: Pixel buffer is no longer newed<commit_after>#include "DesktopController.h"
#include <QMutexLocker>
#include <QWidgetAction>
#include "Screen.h"
#include "Light.h"

DesktopController::DesktopController(std::shared_ptr<Light> light) :
  LightController(light, "Ambilight"), active(false), brightness(255)
{
}

void DesktopController::activate()
{
  if(!active)
  {
    active = true;
    pLight->moveToThread(this); //take ownership of the light
    QThread::start();
  }
}

void DesktopController::deactivate()
{
  active = false;
  QMutexLocker waitForThread(&threadActive);
}

bool DesktopController::isActive() const
{
  return active;
}

void DesktopController::setBrightness(const unsigned char value)
{
  brightness = value;
}

QWidgetAction *DesktopController::getMenuWidget()
{
  //FIXME
  qWarning("dummy implementation");
  return new QWidgetAction(NULL);
}

void DesktopController::run()
{
  QMutexLocker lock(&threadActive);
  unsigned char currentBrightness = 255;
  //setup screen
  Screen screen;
  screen.initialize(0); //FIXME load from settings
  //FIXME initialize() can fail(returns a boolean)
  //FIXME this works as long as the pixel format from Screen is always ARGB
  std::vector<QRgb> buffer;
  buffer.resize(screen.getHeight() * screen.getWidth());
  std::vector<Region> regions;
  generateRegions(regions, screen.getWidth(), screen.getHeight());

  while(active)
  {
    screen.getScreenBitmap(buffer.data());
    for(const Region& region : regions)
    {
      const QRgb avg = getAvgOfRegion(region.rect, buffer.data(), screen.getWidth());
      pLight->setColor(region.ledIndex, qRed(avg), qGreen(avg), qBlue(avg));
    }
    pLight->sendColors();

    const unsigned char tempBrightness = brightness;//copy to avoid race condition
    if(tempBrightness != currentBrightness)
    {
      currentBrightness = tempBrightness;
      pLight->setBrightness(tempBrightness);
    }

    QThread::msleep(5);
  }
}

QRgb DesktopController::getAvgOfRegion(const QRect& region, QRgb* pBuffer, const int screenWidth) const
{
  unsigned long avgR = 0;
  unsigned long avgG = 0;
  unsigned long avgB = 0;
  const int width = screenWidth;
  for(int y = region.top(); y < region.bottom(); ++y)
  { //FIXME pBuffer should be a parameter
    for(int x = region.left(); x < region.right(); ++x)
    {
      QRgb p = pBuffer[width * y + x];
      avgR += qRed(p);
      avgG += qGreen(p);
      avgB += qBlue(p);
    }
  }
  const int count = region.width() * region.height();
  avgR /= count;
  avgG /= count;
  avgB /= count;
  Q_ASSERT(avgR <= 255);
  Q_ASSERT(avgG <= 255);
  Q_ASSERT(avgB <= 255);
  return qRgb(avgR, avgG, avgB);
}

void DesktopController::generateRegions(std::vector<Region>& regions, const int screenWidth, const int screenHeight) const
{
  //FIXME this should be loaded from config file
  regions.clear();

  const int regionWidth = 120; //FIXME parameter
  const int resX = screenWidth;
  const int resY = screenHeight;
  const int horTotalWidth = resX - 2 * regionWidth;
  const int horRegionCount = 20; //FIXME parameter
  const int horRegionWidth = horTotalWidth / horRegionCount;
  const int vertTotalWidth = resY - 2 * regionWidth;
  const int vertRegionCount = 10;
  const int vertRegionWidth = vertTotalWidth / vertRegionCount;

  //top regions
  for(int rIndex = 30, i = 0; i < horRegionCount; ++i, ++rIndex) //FIXME hard coded led index
  {
    const int regionX = regionWidth + i * horRegionWidth;
    const int regionY = 0;
    Region r;
    r.ledIndex = rIndex;
    r.rect = QRect(regionX, regionY, horRegionWidth, regionWidth);
    regions.push_back(r);
  }

  //bottom regions
  for(int rIndex = 19, i = 0; i < horRegionCount; ++i, --rIndex)//FIXME hard coded led index
  {
    const int regionX = regionWidth + i * horRegionWidth;
    const int regionY = resY - regionWidth;
    Region r;
    r.ledIndex = rIndex;
    r.rect = QRect(regionX, regionY, horRegionWidth, regionWidth);
    regions.push_back(r);
  }

  //left regions
  for(int rIndex = 29, i = 0; i < vertRegionCount; ++i, --rIndex)//FIXME hard coded led index
  {
    const int regionX = 0;
    const int regionY = regionWidth + i * vertRegionWidth;
    Region r;
    r.ledIndex = rIndex;
    r.rect = QRect(regionX, regionY, regionWidth, vertRegionWidth);
    regions.push_back(r);
  }

  //right regions
  for(int rIndex = 50, i = 0; i < vertRegionCount; ++i, ++rIndex)//FIXME hard coded led index
  {
    const int regionX = resX - regionWidth;
    const int regionY = regionWidth + i * vertRegionWidth;
    Region r;
    r.ledIndex = rIndex;
    r.rect = QRect(regionX, regionY, regionWidth, vertRegionWidth);
    regions.push_back(r);
  }
}

<|endoftext|>