/*
* Copyright © 2012 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Author: Benjamin Segovia
*/
/**
* \file liveness.cpp
* \author Benjamin Segovia
*/
#include "ir/liveness.hpp"
#include
namespace gbe {
namespace ir {
Liveness::Liveness(Function &fn) : fn(fn) {
// Initialize UEVar and VarKill for each block
fn.foreachBlock([this](const BasicBlock &bb) { this->initBlock(bb); });
// Now with iterative analysis, we compute liveout sets
this->computeLiveOut();
}
Liveness::~Liveness(void) {
for (auto &pair : liveness) GBE_SAFE_DELETE(pair.second);
}
void Liveness::initBlock(const BasicBlock &bb) {
GBE_ASSERT(liveness.contains(&bb) == false);
BlockInfo *info = GBE_NEW(BlockInfo, bb);
// Traverse all instructions to handle UEVar and VarKill
const_cast(bb).foreach([this, info](const Instruction &insn) {
this->initInstruction(*info, insn);
});
liveness[&bb] = info;
}
void Liveness::initInstruction(BlockInfo &info, const Instruction &insn) {
const uint32_t srcNum = insn.getSrcNum();
const uint32_t dstNum = insn.getDstNum();
// First look for used before killed
for (uint32_t srcID = 0; srcID < srcNum; ++srcID) {
const Register reg = insn.getSrc(srcID);
// Not killed -> it is really an upward use
if (info.varKill.contains(reg) == false)
info.upwardUsed.insert(reg);
}
// A destination is a killed value
for (uint32_t dstID = 0; dstID < dstNum; ++dstID) {
const Register reg = insn.getDst(dstID);
info.varKill.insert(reg);
}
}
void Liveness::computeLiveOut(void) {
// First insert the UEVar from the successors
foreach([](BlockInfo &info, const BlockInfo &succ) {
const UEVar &ueVarSet = succ.upwardUsed;
// Iterate over all the registers in the UEVar of our successor
for (auto ueVar : ueVarSet) info.liveOut.insert(ueVar);
});
// Now iterate on liveOut
bool changed = true;
while (changed) {
changed = false;
foreach([&changed](BlockInfo &info, const BlockInfo &succ) {
const UEVar &killSet = succ.varKill;
const LiveOut &liveOut = succ.liveOut;
// Iterate over all the registers in the UEVar of our successor
for (auto living : liveOut) {
if (killSet.contains(living)) continue;
if (info.liveOut.contains(living)) continue;
info.liveOut.insert(living);
changed = true;
}
});
}
}
/*! To pretty print the livfeness info */
static const uint32_t prettyInsnStrSize = 48;
static const uint32_t prettyRegStrSize = 5;
/*! Describe how the register is used */
static const uint32_t USE_NONE = 0;
static const uint32_t USE_READ = 1 << 0;
static const uint32_t USE_WRITTEN = 1 << 1;
enum UsePosition {
POS_BEFORE = 0,
POS_HERE = 1,
POS_AFTER = 2
};
} /* namespace ir */
} /* namespace gbe */