mirror of
https://github.com/luau-lang/luau.git
synced 2025-01-09 21:09:10 +00:00
134 lines
3.3 KiB
C++
134 lines
3.3 KiB
C++
|
// 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
|