luau/CodeGen/src/IrUtils.cpp

134 lines
3.3 KiB
C++
Raw Normal View History

2023-02-10 18:50:54 +00:00
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/IrUtils.h"
namespace Luau
{
namespace CodeGen
{
static uint32_t getBlockEnd(IrFunction& function, uint32_t start)
{
uint32_t end = start;
// Find previous block terminator
while (!isBlockTerminator(function.instructions[end].cmd))
end++;
return end;
}
static void addUse(IrFunction& function, IrOp op)
{
if (op.kind == IrOpKind::Inst)
function.instructions[op.index].useCount++;
else if (op.kind == IrOpKind::Block)
function.blocks[op.index].useCount++;
}
static void removeUse(IrFunction& function, IrOp op)
{
if (op.kind == IrOpKind::Inst)
removeUse(function, function.instructions[op.index]);
else if (op.kind == IrOpKind::Block)
removeUse(function, function.blocks[op.index]);
}
void kill(IrFunction& function, IrInst& inst)
{
LUAU_ASSERT(inst.useCount == 0);
inst.cmd = IrCmd::NOP;
removeUse(function, inst.a);
removeUse(function, inst.b);
removeUse(function, inst.c);
removeUse(function, inst.d);
removeUse(function, inst.e);
}
void kill(IrFunction& function, uint32_t start, uint32_t end)
{
// Kill instructions in reverse order to avoid killing instructions that are still marked as used
for (int i = int(end); i >= int(start); i--)
{
IrInst& curr = function.instructions[i];
if (curr.cmd == IrCmd::NOP)
continue;
kill(function, curr);
}
}
void kill(IrFunction& function, IrBlock& block)
{
LUAU_ASSERT(block.useCount == 0);
block.kind = IrBlockKind::Dead;
uint32_t start = block.start;
uint32_t end = getBlockEnd(function, start);
kill(function, start, end);
}
void removeUse(IrFunction& function, IrInst& inst)
{
LUAU_ASSERT(inst.useCount);
inst.useCount--;
if (inst.useCount == 0)
kill(function, inst);
}
void removeUse(IrFunction& function, IrBlock& block)
{
LUAU_ASSERT(block.useCount);
block.useCount--;
if (block.useCount == 0)
kill(function, block);
}
void replace(IrFunction& function, IrOp& original, IrOp replacement)
{
// Add use before removing new one if that's the last one keeping target operand alive
addUse(function, replacement);
removeUse(function, original);
original = replacement;
}
void replace(IrFunction& function, uint32_t instIdx, IrInst replacement)
{
IrInst& inst = function.instructions[instIdx];
IrCmd prevCmd = inst.cmd;
// Add uses before removing new ones if those are the last ones keeping target operand alive
addUse(function, replacement.a);
addUse(function, replacement.b);
addUse(function, replacement.c);
addUse(function, replacement.d);
addUse(function, replacement.e);
removeUse(function, inst.a);
removeUse(function, inst.b);
removeUse(function, inst.c);
removeUse(function, inst.d);
removeUse(function, inst.e);
inst = replacement;
// If we introduced an earlier terminating instruction, all following instructions become dead
if (!isBlockTerminator(prevCmd) && isBlockTerminator(inst.cmd))
{
uint32_t start = instIdx + 1;
uint32_t end = getBlockEnd(function, start);
kill(function, start, end);
}
}
} // namespace CodeGen
} // namespace Luau