2024-01-09 18:28:50 +03:00
|
|
|
#include "dead_code.h"
|
|
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <set>
|
2024-01-30 19:40:14 +03:00
|
|
|
#include <algorithm>
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2025-09-23 08:21:05 +03:00
|
|
|
#include "../CFGraph/CFGraph.h"
|
2025-06-18 16:26:43 +03:00
|
|
|
|
2024-01-09 18:28:50 +03:00
|
|
|
using std::map;
|
|
|
|
|
using std::string;
|
|
|
|
|
using std::vector;
|
|
|
|
|
using std::set;
|
|
|
|
|
|
2024-01-30 19:40:14 +03:00
|
|
|
using std::remove_if;
|
|
|
|
|
|
2024-03-22 12:00:01 +03:00
|
|
|
#define PRINT_USELESS_STATEMENTS 1
|
2024-04-05 16:03:18 +03:00
|
|
|
#define DEBUG_IR 0
|
|
|
|
|
|
2024-01-09 18:28:50 +03:00
|
|
|
static void updateUseDefForInstruction(SAPFOR::BasicBlock* block, SAPFOR::Instruction* instr,
|
|
|
|
|
set<SAPFOR::Argument*>& use, set<SAPFOR::Argument*>& def,
|
|
|
|
|
vector<SAPFOR::Argument*>& formal_parameters,
|
2024-04-10 22:03:27 +03:00
|
|
|
vector<SAPFOR::Argument*>& arg_stack, int& arg_stack_index, int& arg_stack_size,
|
2024-02-02 15:52:36 +03:00
|
|
|
string& fName, const map<string, FuncInfo*>& funcByName,
|
2024-04-10 22:03:27 +03:00
|
|
|
bool& useful, bool& last_stack_op_useful,
|
2024-01-09 18:28:50 +03:00
|
|
|
set<SAPFOR::Argument*>& usedByThisBlock)
|
|
|
|
|
{
|
|
|
|
|
set<SAPFOR::Argument*> res, args;
|
2024-04-10 22:03:27 +03:00
|
|
|
bool last_stack_op;
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2024-01-12 16:11:21 +03:00
|
|
|
vector<LIVE_VARIABLES::LiveDeadVarsForCall> fcalls;
|
2024-01-09 18:28:50 +03:00
|
|
|
|
|
|
|
|
getUseDefForInstruction(block, instr,
|
|
|
|
|
args, res,
|
|
|
|
|
formal_parameters, fcalls,
|
2024-04-10 22:03:27 +03:00
|
|
|
arg_stack, arg_stack_index, arg_stack_size,
|
|
|
|
|
last_stack_op,
|
2024-02-02 15:52:36 +03:00
|
|
|
fName, funcByName,
|
2024-01-09 18:28:50 +03:00
|
|
|
false
|
|
|
|
|
);
|
|
|
|
|
|
2024-04-10 22:03:27 +03:00
|
|
|
const auto instr_operation = instr->getOperation();
|
|
|
|
|
|
2024-01-09 18:28:50 +03:00
|
|
|
if (!useful)
|
|
|
|
|
{
|
|
|
|
|
for (SAPFOR::Argument* r : res)
|
|
|
|
|
{
|
2024-04-03 21:13:56 +03:00
|
|
|
if (use.find(r) != use.end() ||
|
|
|
|
|
r->getMemType() != SAPFOR::CFG_MEM_TYPE::LOCAL_ ||
|
2024-04-04 20:37:34 +03:00
|
|
|
!(r->getType() == SAPFOR::CFG_ARG_TYPE::VAR || r->getType() == SAPFOR::CFG_ARG_TYPE::REG))
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
|
|
|
|
useful = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!useful)
|
|
|
|
|
{
|
2024-04-10 19:04:25 +03:00
|
|
|
static const set<SAPFOR::CFG_OP> always_useful =
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
|
|
|
|
SAPFOR::CFG_OP::POINTER_ASS,
|
|
|
|
|
SAPFOR::CFG_OP::STORE,
|
|
|
|
|
SAPFOR::CFG_OP::REC_REF_STORE,
|
|
|
|
|
SAPFOR::CFG_OP::RANGE,
|
|
|
|
|
SAPFOR::CFG_OP::ENTRY,
|
|
|
|
|
SAPFOR::CFG_OP::EXIT,
|
|
|
|
|
SAPFOR::CFG_OP::DVM_DIR,
|
2024-04-13 18:14:28 +03:00
|
|
|
SAPFOR::CFG_OP::SPF_DIR,
|
|
|
|
|
SAPFOR::CFG_OP::IO_PARAM
|
2024-01-09 18:28:50 +03:00
|
|
|
};
|
|
|
|
|
|
2024-04-10 22:03:27 +03:00
|
|
|
if (always_useful.find(instr_operation) != always_useful.end())
|
2024-01-09 18:28:50 +03:00
|
|
|
useful = true;
|
2024-04-10 22:03:27 +03:00
|
|
|
else if (instr_operation == SAPFOR::CFG_OP::F_CALL)
|
2024-02-02 15:52:36 +03:00
|
|
|
{
|
|
|
|
|
auto func_it = funcByName.find(instr->getArg1()->getValue());
|
|
|
|
|
useful |= func_it == funcByName.end() || !(func_it->second->isPure);
|
|
|
|
|
}
|
2024-04-10 22:03:27 +03:00
|
|
|
else if (instr_operation == SAPFOR::CFG_OP::PARAM ||
|
|
|
|
|
instr_operation == SAPFOR::CFG_OP::REF)
|
|
|
|
|
useful |= last_stack_op_useful;
|
2024-01-09 18:28:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (useful)
|
|
|
|
|
{
|
2024-04-10 22:03:27 +03:00
|
|
|
if (instr_operation == SAPFOR::CFG_OP::F_CALL ||
|
|
|
|
|
instr_operation == SAPFOR::CFG_OP::LOAD ||
|
|
|
|
|
instr_operation == SAPFOR::CFG_OP::STORE)
|
|
|
|
|
last_stack_op_useful = true;
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2025-06-18 16:26:43 +03:00
|
|
|
for (auto& e : res)
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
|
|
|
|
def.insert(e);
|
|
|
|
|
use.erase(e);
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-18 16:26:43 +03:00
|
|
|
for (auto& e : args)
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
|
|
|
|
use.insert(e);
|
|
|
|
|
def.erase(e);
|
|
|
|
|
}
|
2024-04-03 21:13:56 +03:00
|
|
|
|
2024-04-05 16:03:18 +03:00
|
|
|
usedByThisBlock.insert(args.begin(), args.end());
|
2024-01-09 18:28:50 +03:00
|
|
|
}
|
2024-02-02 15:52:36 +03:00
|
|
|
|
2024-04-10 22:03:27 +03:00
|
|
|
if (last_stack_op)
|
|
|
|
|
last_stack_op_useful = false;
|
2024-01-09 18:28:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Build use and def sets of block. Result are stored in use and def
|
|
|
|
|
static void buildUseDef(SAPFOR::BasicBlock* block, set<SAPFOR::Argument*>& use, set<SAPFOR::Argument*>& def,
|
|
|
|
|
vector<SAPFOR::Argument*>& formal_parameters, vector<bool>& useful,
|
2024-02-02 15:52:36 +03:00
|
|
|
set<SAPFOR::Argument*>& usedByThisBlock, const map<string, FuncInfo*>& funcByName)
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
|
|
|
|
set<SAPFOR::Argument*> use_with_regs = use, def_with_regs = def;
|
|
|
|
|
|
2024-04-10 22:03:27 +03:00
|
|
|
vector<SAPFOR::Argument*> arg_stack;
|
|
|
|
|
int arg_stack_index = 0, arg_stack_size = 0;
|
2024-01-09 18:28:50 +03:00
|
|
|
string fName = "";
|
|
|
|
|
bool last_fcall_useful = false;
|
|
|
|
|
|
|
|
|
|
const auto& instructions = block->getInstructions();
|
|
|
|
|
int instr_size = instructions.size();
|
|
|
|
|
|
|
|
|
|
for (int i = instr_size - 1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
bool u = useful[i];
|
|
|
|
|
|
|
|
|
|
updateUseDefForInstruction(block, instructions[i]->getInstruction(),
|
|
|
|
|
use_with_regs, def_with_regs,
|
|
|
|
|
formal_parameters,
|
2024-04-10 22:03:27 +03:00
|
|
|
arg_stack, arg_stack_index, arg_stack_size,
|
2024-02-02 15:52:36 +03:00
|
|
|
fName, funcByName,
|
2024-01-09 18:28:50 +03:00
|
|
|
u, last_fcall_useful,
|
|
|
|
|
usedByThisBlock
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
useful[i] = u;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-05 16:03:18 +03:00
|
|
|
use.insert(use_with_regs.begin(), use_with_regs.end());
|
|
|
|
|
def.insert(def_with_regs.begin(), def_with_regs.end());
|
2024-01-09 18:28:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-04-04 20:15:56 +03:00
|
|
|
class DeadCodeAnalysisNode : public DataFlowAnalysisNode<map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>>>
|
|
|
|
|
{
|
2024-01-09 18:28:50 +03:00
|
|
|
private:
|
|
|
|
|
vector<bool> useful;
|
|
|
|
|
bool useful_block = false;
|
|
|
|
|
set<DeadCodeAnalysisNode*> next_notempty_in, next_notempty_out;
|
|
|
|
|
bool useful_jump = false;
|
|
|
|
|
|
|
|
|
|
vector<SAPFOR::Argument*>& formal_parameters;
|
2024-02-02 15:52:36 +03:00
|
|
|
const map<string, FuncInfo*>& funcByName;
|
2024-01-09 18:28:50 +03:00
|
|
|
public:
|
|
|
|
|
bool updateJumpStatus()
|
|
|
|
|
{
|
|
|
|
|
bool res = false;
|
|
|
|
|
const auto& prev = getPrevBlocks();
|
|
|
|
|
if (prev.size() > 1 && !useful.back() &&
|
|
|
|
|
getBlock()->getInstructions().back()->getInstruction()->getOperation() == SAPFOR::CFG_OP::JUMP_IF)
|
|
|
|
|
{
|
|
|
|
|
const auto& example = dynamic_cast<DeadCodeAnalysisNode*>(*prev.begin())->next_notempty_out;
|
|
|
|
|
|
2025-06-18 16:26:43 +03:00
|
|
|
for (auto& p : prev)
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
|
|
|
|
DeadCodeAnalysisNode* next = dynamic_cast<DeadCodeAnalysisNode*>(p);
|
|
|
|
|
|
|
|
|
|
if (next->next_notempty_out != example)
|
|
|
|
|
{
|
|
|
|
|
useful.back() = true;
|
|
|
|
|
res = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool updateNextNotEmpty()
|
|
|
|
|
{
|
|
|
|
|
bool updated = false;
|
|
|
|
|
|
|
|
|
|
if(!useful_block)
|
|
|
|
|
{
|
|
|
|
|
set<DeadCodeAnalysisNode*> current = {};
|
|
|
|
|
|
2025-06-18 16:26:43 +03:00
|
|
|
for (auto& nextP : getPrevBlocks())
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
|
|
|
|
DeadCodeAnalysisNode* next = dynamic_cast<DeadCodeAnalysisNode*>(nextP);
|
|
|
|
|
|
|
|
|
|
if(!next)
|
|
|
|
|
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
|
|
|
|
|
|
|
|
|
current.insert(next->next_notempty_out.begin(), next->next_notempty_out.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (current != next_notempty_in)
|
|
|
|
|
{
|
|
|
|
|
next_notempty_in = current;
|
|
|
|
|
updated = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return updated;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-04 20:15:56 +03:00
|
|
|
map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>> getIn()
|
|
|
|
|
{
|
2024-01-09 18:28:50 +03:00
|
|
|
return getBlock()->getLiveOut();
|
2024-01-14 13:26:21 +03:00
|
|
|
}
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2024-04-04 20:15:56 +03:00
|
|
|
map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>> getOut()
|
|
|
|
|
{
|
2024-01-09 18:28:50 +03:00
|
|
|
return getBlock()->getLiveIn();
|
2024-01-14 13:26:21 +03:00
|
|
|
}
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2024-04-04 20:15:56 +03:00
|
|
|
bool addIn(const map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>>& data)
|
|
|
|
|
{
|
|
|
|
|
return getBlock()->addLiveOut(data);
|
2024-01-14 13:26:21 +03:00
|
|
|
}
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2024-04-04 20:15:56 +03:00
|
|
|
bool addOut(const map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>>& data)
|
|
|
|
|
{
|
2024-01-09 18:28:50 +03:00
|
|
|
return getBlock()->addLiveIn(data);
|
2024-01-14 13:26:21 +03:00
|
|
|
}
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2024-04-04 20:15:56 +03:00
|
|
|
bool updateState()
|
|
|
|
|
{
|
2024-04-03 21:13:56 +03:00
|
|
|
bool updated = false;
|
|
|
|
|
|
|
|
|
|
if (!useful_block)
|
|
|
|
|
updated |= updateNextNotEmpty();
|
|
|
|
|
|
2024-05-22 10:33:58 +03:00
|
|
|
if (!useful_block)
|
|
|
|
|
{
|
|
|
|
|
if (next_notempty_in != next_notempty_out)
|
|
|
|
|
{
|
|
|
|
|
updated = true;
|
|
|
|
|
next_notempty_out = next_notempty_in;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-03 21:13:56 +03:00
|
|
|
updated |= updateJumpStatus();
|
2024-04-10 18:58:46 +03:00
|
|
|
|
|
|
|
|
if(updated)
|
|
|
|
|
this->forwardData({ });
|
2024-04-03 21:13:56 +03:00
|
|
|
|
|
|
|
|
return updated;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-22 10:33:58 +03:00
|
|
|
DATA_FLOW_UPD_STATUS forwardData(const map<SAPFOR::Argument*, vector<SAPFOR::BasicBlock*>>& data)
|
2024-04-04 20:15:56 +03:00
|
|
|
{
|
2024-05-22 20:28:13 +03:00
|
|
|
bool inserted_prop = false, inserted_gen = false;
|
2024-05-22 10:33:58 +03:00
|
|
|
|
2024-04-13 18:14:28 +03:00
|
|
|
SAPFOR::BasicBlock* bb = getBlock();
|
2024-01-09 18:28:50 +03:00
|
|
|
|
|
|
|
|
set<SAPFOR::Argument*> use, def;
|
|
|
|
|
|
|
|
|
|
for (const auto& byArg : data)
|
|
|
|
|
use.insert(byArg.first);
|
|
|
|
|
|
|
|
|
|
set<SAPFOR::Argument*> usedByThisBlock;
|
2024-02-02 15:52:36 +03:00
|
|
|
buildUseDef(bb, use, def, this->formal_parameters, useful, usedByThisBlock, funcByName);
|
2024-01-09 18:28:50 +03:00
|
|
|
|
|
|
|
|
auto in = bb->getLiveIn(), out = bb->getLiveOut();
|
|
|
|
|
|
|
|
|
|
for (SAPFOR::Argument* arg : use)
|
|
|
|
|
{
|
2024-04-07 17:40:30 +03:00
|
|
|
if(arg && (arg->getType() == SAPFOR::CFG_ARG_TYPE::VAR || arg->getType() == SAPFOR::CFG_ARG_TYPE::REG))
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
2024-04-05 16:03:18 +03:00
|
|
|
bool this_block = usedByThisBlock.find(arg) != usedByThisBlock.end();
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2024-04-05 16:03:18 +03:00
|
|
|
if (!this_block)
|
|
|
|
|
{
|
|
|
|
|
auto data_it = data.find(arg);
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2024-04-05 16:03:18 +03:00
|
|
|
if (data_it == data.end())
|
|
|
|
|
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
|
|
|
|
|
2024-05-22 20:28:13 +03:00
|
|
|
inserted_prop |= bb->addLiveIn({ *data_it });
|
2024-04-05 16:03:18 +03:00
|
|
|
}
|
|
|
|
|
else
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
2024-04-05 16:03:18 +03:00
|
|
|
auto in_it = in.find(arg);
|
|
|
|
|
bool skip = false;
|
|
|
|
|
if (in_it != in.end())
|
|
|
|
|
{
|
|
|
|
|
if (in_it->second.size() == 1 && *(in_it->second.begin()) == bb)
|
|
|
|
|
skip = true; // nothing to do, inserted = false
|
|
|
|
|
else
|
|
|
|
|
bb->removeLiveIn(arg);
|
|
|
|
|
}
|
|
|
|
|
if(!skip)
|
2024-05-22 20:28:13 +03:00
|
|
|
inserted_gen |= bb->addLiveIn({ { arg, { bb } } });
|
2024-01-09 18:28:50 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!useful_block)
|
|
|
|
|
{
|
|
|
|
|
for(bool status : useful)
|
|
|
|
|
{
|
|
|
|
|
if (status)
|
|
|
|
|
{
|
|
|
|
|
useful_block = true;
|
|
|
|
|
|
2024-05-22 20:28:13 +03:00
|
|
|
inserted_gen = true;
|
2024-01-09 18:28:50 +03:00
|
|
|
next_notempty_out = { this };
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-22 20:28:13 +03:00
|
|
|
if(inserted_gen)
|
|
|
|
|
return DATA_FLOW_UPD_STATUS::GENERATED;
|
|
|
|
|
else if(inserted_prop)
|
|
|
|
|
return DATA_FLOW_UPD_STATUS::PROPAGATED;
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2024-05-22 10:33:58 +03:00
|
|
|
return DATA_FLOW_UPD_STATUS::NO_CHANGE;
|
2024-01-14 13:26:21 +03:00
|
|
|
}
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2024-02-02 15:52:36 +03:00
|
|
|
DeadCodeAnalysisNode(SAPFOR::BasicBlock* block,
|
|
|
|
|
vector<SAPFOR::Argument*>& formal_parameters,
|
2024-04-07 17:40:30 +03:00
|
|
|
const map<string, FuncInfo*>& funcByName)
|
2024-02-02 15:52:36 +03:00
|
|
|
:
|
|
|
|
|
formal_parameters(formal_parameters),
|
2024-04-07 17:40:30 +03:00
|
|
|
funcByName(funcByName)
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
|
|
|
|
setBlock(block);
|
|
|
|
|
useful.resize(block->getInstructions().size(), false);
|
2024-04-10 18:58:46 +03:00
|
|
|
this->forwardData({ });
|
2024-01-09 18:28:50 +03:00
|
|
|
}
|
|
|
|
|
|
2024-01-14 13:26:21 +03:00
|
|
|
const vector<bool>& getResult() { return useful; }
|
2024-01-09 18:28:50 +03:00
|
|
|
};
|
|
|
|
|
|
2024-04-04 20:15:56 +03:00
|
|
|
class DeadCodeAnalysis : public BackwardDataFlowAnalysis<DeadCodeAnalysisNode>
|
|
|
|
|
{
|
2024-01-09 18:28:50 +03:00
|
|
|
protected:
|
|
|
|
|
vector<SAPFOR::Argument*>& formal_parameters;
|
2024-02-02 15:52:36 +03:00
|
|
|
const map<string, FuncInfo*>& funcByName;
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2024-04-04 20:15:56 +03:00
|
|
|
DeadCodeAnalysisNode* createNode(SAPFOR::BasicBlock* block) override
|
|
|
|
|
{
|
2024-04-07 17:40:30 +03:00
|
|
|
return new DeadCodeAnalysisNode(block, formal_parameters, funcByName);
|
2024-01-14 13:26:21 +03:00
|
|
|
}
|
2024-01-09 18:28:50 +03:00
|
|
|
public:
|
2024-04-05 16:03:18 +03:00
|
|
|
DeadCodeAnalysis(vector<SAPFOR::Argument*>& formal_parameters,
|
2024-04-07 17:40:30 +03:00
|
|
|
const map<string, FuncInfo*>& funcByName)
|
2024-02-02 15:52:36 +03:00
|
|
|
:
|
|
|
|
|
formal_parameters(formal_parameters),
|
2024-04-07 17:40:30 +03:00
|
|
|
funcByName(funcByName)
|
2024-01-14 13:26:21 +03:00
|
|
|
{ }
|
2024-01-09 18:28:50 +03:00
|
|
|
};
|
|
|
|
|
|
2024-04-14 21:30:09 +03:00
|
|
|
static bool hasCalls(SgExpression* ex)
|
|
|
|
|
{
|
|
|
|
|
if (ex)
|
|
|
|
|
{
|
|
|
|
|
if (ex->variant() == FUNC_CALL)
|
|
|
|
|
return true;
|
|
|
|
|
return hasCalls(ex->lhs()) || hasCalls(ex->rhs());
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//TODO: add check for side effects for function calls
|
|
|
|
|
static bool hasCalls(SgStatement* stat)
|
|
|
|
|
{
|
|
|
|
|
if (stat->variant() == FOR_NODE)
|
|
|
|
|
{
|
|
|
|
|
auto forSt = isSgForStmt(stat);
|
|
|
|
|
return hasCalls(forSt->start()) || hasCalls(forSt->end()) || hasCalls(forSt->step());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return hasCalls(stat->expr(0)) || hasCalls(stat->expr(1)) || hasCalls(stat->expr(2));
|
|
|
|
|
}
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2024-05-02 11:05:56 +03:00
|
|
|
static void moveComment(SgStatement* stat)
|
|
|
|
|
{
|
|
|
|
|
const char* comm = stat->comments();
|
|
|
|
|
if (comm)
|
|
|
|
|
{
|
|
|
|
|
SgStatement* next = stat->lastNodeOfStmt()->lexNext();
|
|
|
|
|
if (next)
|
|
|
|
|
{
|
|
|
|
|
const char* commNext = next->comments();
|
|
|
|
|
if (commNext)
|
|
|
|
|
{
|
|
|
|
|
string newComm(comm);
|
|
|
|
|
newComm += commNext;
|
|
|
|
|
|
|
|
|
|
next->delComments();
|
|
|
|
|
next->addComment(newComm.c_str());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
next->addComment(comm);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-09 16:41:48 +03:00
|
|
|
int removeDeadCode(SgStatement* func,
|
|
|
|
|
const map<string, vector<FuncInfo*>>& allFuncs,
|
|
|
|
|
const map<string, CommonBlock*>& commonBlocks,
|
|
|
|
|
SgStatement* intervalDelStart, SgStatement* intervalDelEnd)
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
2024-04-09 16:41:48 +03:00
|
|
|
int countOfTransform = 0;
|
2024-03-22 12:00:01 +03:00
|
|
|
if (intervalDelStart && !intervalDelEnd || !intervalDelStart && intervalDelEnd)
|
|
|
|
|
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
|
|
|
|
|
2024-01-09 18:28:50 +03:00
|
|
|
SgProgHedrStmt* prog = isSgProgHedrStmt(func);
|
|
|
|
|
|
2024-03-22 12:00:01 +03:00
|
|
|
if (intervalDelStart)
|
|
|
|
|
if (intervalDelStart->lineNumber() < prog->lineNumber() || intervalDelStart->lineNumber() > prog->lastNodeOfStmt()->lineNumber())
|
|
|
|
|
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
|
|
|
|
|
|
|
|
|
if (intervalDelEnd)
|
|
|
|
|
if (intervalDelEnd->lineNumber() < prog->lineNumber() || intervalDelEnd->lineNumber() > prog->lastNodeOfStmt()->lineNumber())
|
|
|
|
|
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
|
|
|
|
|
2024-01-09 18:28:50 +03:00
|
|
|
auto cfg = buildCFGforCurrentFunc(func, SAPFOR::CFG_Settings(true, false, false, false, false, false, false), commonBlocks, allFuncs);
|
|
|
|
|
|
|
|
|
|
if(cfg.size() != 1)
|
|
|
|
|
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
|
|
|
|
|
2024-01-30 19:40:14 +03:00
|
|
|
auto& cfg_pair = *(cfg.begin());
|
2025-06-18 16:26:43 +03:00
|
|
|
removedUnreachableBlocks(cfg_pair.second);
|
2024-01-30 19:40:14 +03:00
|
|
|
|
2024-04-05 16:03:18 +03:00
|
|
|
#if DEBUG_IR
|
|
|
|
|
dumpCFG({ cfg_pair }, false);
|
|
|
|
|
#endif
|
2024-01-30 19:40:14 +03:00
|
|
|
// detect useless code
|
2024-01-09 18:28:50 +03:00
|
|
|
vector<SAPFOR::Argument*> func_parameters(cfg_pair.first->funcParams.countOfPars, NULL);
|
|
|
|
|
|
2024-02-02 15:52:36 +03:00
|
|
|
map<string, FuncInfo*> funcByName;
|
|
|
|
|
|
|
|
|
|
for (auto& byFile : allFuncs)
|
2025-06-18 16:26:43 +03:00
|
|
|
for (auto& byFunc : byFile.second)
|
2024-02-02 15:52:36 +03:00
|
|
|
funcByName[byFunc->funcName] = byFunc;
|
|
|
|
|
|
2024-04-07 17:40:30 +03:00
|
|
|
DeadCodeAnalysis analysis_object(func_parameters, funcByName);
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2024-01-14 15:36:52 +03:00
|
|
|
analysis_object.fit(cfg_pair.second);
|
|
|
|
|
analysis_object.analyze();
|
2024-01-09 18:28:50 +03:00
|
|
|
|
2024-01-30 19:40:14 +03:00
|
|
|
// detect dead statements
|
|
|
|
|
|
2024-01-09 18:28:50 +03:00
|
|
|
set<SgStatement*> useful;
|
|
|
|
|
|
2024-01-14 15:36:52 +03:00
|
|
|
for (DeadCodeAnalysisNode* byNode : analysis_object.getNodes())
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
|
|
|
|
const auto& instructions = byNode->getBlock()->getInstructions();
|
|
|
|
|
const auto& statuses = byNode->getResult();
|
|
|
|
|
|
|
|
|
|
int size = instructions.size();
|
|
|
|
|
|
|
|
|
|
if(size != statuses.size())
|
|
|
|
|
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < size; i++)
|
|
|
|
|
{
|
|
|
|
|
if(statuses[i])
|
|
|
|
|
{
|
|
|
|
|
SgStatement* stmt = instructions[i]->getInstruction()->getOperator();
|
|
|
|
|
|
|
|
|
|
while(stmt && useful.insert(stmt).second)
|
|
|
|
|
stmt = stmt->controlParent();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-28 21:57:06 +03:00
|
|
|
|
2024-01-30 19:40:14 +03:00
|
|
|
// remove dead statements
|
2024-04-10 19:04:25 +03:00
|
|
|
static const set<int> removable =
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
2024-02-02 15:52:36 +03:00
|
|
|
ASSIGN_STAT,
|
|
|
|
|
PROC_STAT,
|
|
|
|
|
WRITE_STAT,
|
|
|
|
|
READ_STAT
|
2024-01-09 18:28:50 +03:00
|
|
|
};
|
|
|
|
|
|
2024-03-22 12:00:01 +03:00
|
|
|
vector<SgStatement*> remove;
|
2024-03-28 21:57:06 +03:00
|
|
|
SgStatement* start = intervalDelStart ? intervalDelStart : func;
|
|
|
|
|
SgStatement* end = intervalDelEnd ? intervalDelEnd : func->lastNodeOfStmt();
|
|
|
|
|
|
2024-04-12 15:25:48 +03:00
|
|
|
for (auto st = start; st != end; st = st->lexNext())
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
2024-04-12 15:25:48 +03:00
|
|
|
const int var = st->variant();
|
|
|
|
|
if (removable.find(var) != removable.end() && useful.find(st) == useful.end())
|
2024-03-22 12:00:01 +03:00
|
|
|
{
|
|
|
|
|
remove.push_back(st);
|
|
|
|
|
st = st->lastNodeOfStmt();
|
|
|
|
|
}
|
2024-04-12 15:25:48 +03:00
|
|
|
|
|
|
|
|
if (var == CONTAINS_STMT)
|
|
|
|
|
break;
|
2024-03-22 12:00:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto& rem : remove)
|
|
|
|
|
{
|
|
|
|
|
__spf_print(PRINT_USELESS_STATEMENTS, "[Useless statement on line %d and file %s]\n", rem->lineNumber(), rem->fileName());
|
2024-04-14 21:30:09 +03:00
|
|
|
|
|
|
|
|
auto cp = rem->controlParent();
|
|
|
|
|
if (cp->variant() == LOGIF_NODE)
|
|
|
|
|
{
|
|
|
|
|
if (hasCalls(cp))
|
|
|
|
|
{
|
|
|
|
|
((SgLogIfStmt*)cp)->convertLogicIf();
|
|
|
|
|
rem->deleteStmt();
|
|
|
|
|
}
|
|
|
|
|
else
|
2024-04-16 20:17:02 +03:00
|
|
|
{
|
|
|
|
|
moveLabelBefore(cp);
|
2024-05-02 11:05:56 +03:00
|
|
|
moveComment(cp);
|
2024-04-14 21:30:09 +03:00
|
|
|
cp->deleteStmt();
|
2024-04-16 20:17:02 +03:00
|
|
|
}
|
2024-04-14 21:30:09 +03:00
|
|
|
}
|
|
|
|
|
else
|
2024-04-16 20:17:02 +03:00
|
|
|
{
|
|
|
|
|
moveLabelBefore(rem);
|
2024-05-02 11:05:56 +03:00
|
|
|
moveComment(rem);
|
2024-04-14 21:30:09 +03:00
|
|
|
rem->deleteStmt();
|
2024-04-16 20:17:02 +03:00
|
|
|
}
|
2024-03-22 12:00:01 +03:00
|
|
|
}
|
2024-04-09 16:41:48 +03:00
|
|
|
countOfTransform += remove.size();
|
|
|
|
|
|
2024-04-06 18:04:59 +03:00
|
|
|
//remove empty blocks
|
|
|
|
|
do
|
2024-03-22 12:00:01 +03:00
|
|
|
{
|
2024-04-06 18:04:59 +03:00
|
|
|
remove.clear();
|
2024-04-12 15:25:48 +03:00
|
|
|
for (auto st = start; st != end; st = st->lexNext())
|
2024-01-09 18:28:50 +03:00
|
|
|
{
|
2024-04-06 18:04:59 +03:00
|
|
|
const int var = st->variant();
|
|
|
|
|
if ((var == FOR_NODE || var == WHILE_NODE || var == SWITCH_NODE) &&
|
|
|
|
|
st->lexNext()->variant() == CONTROL_END)
|
|
|
|
|
{
|
2024-04-14 21:30:09 +03:00
|
|
|
if (!hasCalls(st))
|
|
|
|
|
remove.push_back(st);
|
2024-04-06 18:04:59 +03:00
|
|
|
}
|
|
|
|
|
else if (var == IF_NODE)
|
|
|
|
|
{
|
2024-04-14 21:30:09 +03:00
|
|
|
if (!hasCalls(st))
|
|
|
|
|
{
|
|
|
|
|
bool hasCalls_ = false;
|
|
|
|
|
SgStatement* ifS = st;
|
|
|
|
|
while (ifS->lexNext()->variant() == ELSEIF_NODE)
|
|
|
|
|
{
|
|
|
|
|
hasCalls_ |= hasCalls(ifS->lexNext());
|
|
|
|
|
ifS = ifS->lexNext();
|
|
|
|
|
}
|
2024-04-06 17:00:29 +03:00
|
|
|
|
2024-04-14 21:30:09 +03:00
|
|
|
SgStatement* lastNode = ifS->lastNodeOfStmt();
|
2024-04-06 18:04:59 +03:00
|
|
|
ifS = ifS->lexNext();
|
2024-04-06 17:00:29 +03:00
|
|
|
|
2024-04-14 21:30:09 +03:00
|
|
|
while (ifS->variant() == CONTROL_END && ifS != lastNode)
|
|
|
|
|
ifS = ifS->lexNext();
|
|
|
|
|
|
|
|
|
|
if (ifS == lastNode && !hasCalls_)
|
|
|
|
|
remove.push_back(st);
|
|
|
|
|
}
|
2024-04-06 18:04:59 +03:00
|
|
|
}
|
2024-01-14 15:36:52 +03:00
|
|
|
|
2024-04-14 21:30:09 +03:00
|
|
|
//TODO: other block statements
|
2024-04-12 15:25:48 +03:00
|
|
|
|
|
|
|
|
if (var == CONTAINS_STMT)
|
|
|
|
|
break;
|
2024-01-09 18:28:50 +03:00
|
|
|
}
|
|
|
|
|
|
2024-04-15 09:31:25 +03:00
|
|
|
bool mainRemoved = false;
|
2024-04-06 18:04:59 +03:00
|
|
|
for (auto& rem : remove)
|
|
|
|
|
{
|
|
|
|
|
__spf_print(PRINT_USELESS_STATEMENTS, "[Useless block statement on line %d and file %s]\n", rem->lineNumber(), rem->fileName());
|
2024-04-16 20:17:02 +03:00
|
|
|
moveLabelBefore(rem);
|
2024-05-02 11:05:56 +03:00
|
|
|
moveComment(rem);
|
2024-04-06 18:04:59 +03:00
|
|
|
rem->deleteStmt();
|
2024-04-15 09:31:25 +03:00
|
|
|
if (rem == start)
|
|
|
|
|
mainRemoved = true;
|
2024-04-06 18:04:59 +03:00
|
|
|
}
|
2024-04-09 16:41:48 +03:00
|
|
|
countOfTransform += remove.size();
|
2024-04-15 09:31:25 +03:00
|
|
|
if (mainRemoved)
|
|
|
|
|
break;
|
2024-04-06 18:04:59 +03:00
|
|
|
} while (remove.size());
|
2024-01-14 15:36:52 +03:00
|
|
|
|
|
|
|
|
deleteCFG(cfg);
|
2024-04-09 16:41:48 +03:00
|
|
|
return countOfTransform;
|
2024-01-09 18:28:50 +03:00
|
|
|
}
|