Files
SAPFOR/src/CFGraph/IR.h
2025-03-12 14:28:04 +03:00

346 lines
14 KiB
C++

#pragma once
#include <string>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include "CFGraph.h"
#include "../Utils/CommonBlock.h"
namespace SAPFOR
{
struct CFG_Settings;
enum class CFG_OP { NONE, ASSIGN, POINTER_ASS, LOAD, STORE, REC_REF_LOAD, REC_REF_STORE, REF, PARAM, IO_PARAM, RANGE, ENTRY, REC_REF,
ADD, MULT, DIV, SUBT, UN_ADD, UN_MINUS, POW, CONCAT, CAST,
JUMP, JUMP_IF,
GE, LE, GT, LT, EQ, NEQV, EQV, EMPTY, OR, AND, NOT,
F_CALL, EXIT,
DVM_DIR, SPF_DIR };
enum class CFG_ARG_TYPE { NONE, REG, VAR, ARRAY, CONST, FUNC, LAB, INSTR, CONST_STR, RECORD, CONSTR_REF };
enum class CFG_MEM_TYPE { NONE_, COMMON_, SAVE_, LOCAL_, MODULE_, FUNC_RES_, FUNC_PARAM_, FILED_ };
static std::vector<std::string> CFG_OP_S = { "--", " = ", " => ", "LOAD ", "STORE ", "LOAD_REF ", "STORE_REF ", "REF ", "PARAM ", "IO_PARAM ", "RANGE ", "ENTRY ", "->",
" + ", " * ", " / ", " - ", " + ", "-", " ** ", " // ", "CAST ",
"GOTO ", "IF_FALSE ",
" >= ", " <= ", " > " , " < ", " == ", " != ", " eqv ", "CONTINUE", " || ", " && ", " ! ",
"F_CALL ", "EXIT ",
" ", " " };
class Argument
{
static int lastNumArg;
private:
int number;
CFG_ARG_TYPE type;
CFG_MEM_TYPE mType;
std::string value;
public:
Argument() : number(lastNumArg++), type(CFG_ARG_TYPE::NONE), value(""), mType(CFG_MEM_TYPE::NONE_) { }
Argument(CFG_ARG_TYPE type, CFG_MEM_TYPE mType) : number(lastNumArg++), type(type), mType(mType), value("") { }
Argument(CFG_ARG_TYPE type, CFG_MEM_TYPE mType, const std::string& value) : number(lastNumArg++), type(type), mType(mType), value(value) { }
Argument(CFG_ARG_TYPE type, const std::string& value) : number(lastNumArg++), type(type), mType(CFG_MEM_TYPE::NONE_), value(value)
{
if (type != CFG_ARG_TYPE::INSTR && type == CFG_ARG_TYPE::LAB &&
type != CFG_ARG_TYPE::NONE && type != CFG_ARG_TYPE::FUNC)
{
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
}
}
void setType(CFG_ARG_TYPE newType) { type = newType; }
CFG_ARG_TYPE getType() const { return type; }
void setMemType(CFG_MEM_TYPE newType) { mType = newType; }
CFG_MEM_TYPE getMemType() const { return mType; }
bool isMemGlobal() const
{
if (mType == CFG_MEM_TYPE::COMMON_ ||
mType == CFG_MEM_TYPE::MODULE_ ||
mType == CFG_MEM_TYPE::SAVE_)
return true;
return false;
}
bool isParameter() const
{
if (mType == CFG_MEM_TYPE::FUNC_RES_ ||
mType == CFG_MEM_TYPE::FUNC_PARAM_)
return true;
return false;
}
void setValue(const std::string& newValue) { value = newValue; }
const std::string getValue() const
{
if (type == CFG_ARG_TYPE::CONST_STR || type == CFG_ARG_TYPE::CONSTR_REF)
return "'" + value + "'";
else
return value;
}
int getNumber() const { return number; }
std::string getMemTypeStr() const
{
if (mType == CFG_MEM_TYPE::NONE_)
return "none";
else if (mType == CFG_MEM_TYPE::COMMON_)
return "common";
else if (mType == CFG_MEM_TYPE::LOCAL_)
return "local";
else if (mType == CFG_MEM_TYPE::MODULE_)
return "module";
else if (mType == CFG_MEM_TYPE::FUNC_RES_)
return "func_res";
else if (mType == CFG_MEM_TYPE::FUNC_PARAM_)
return "func_par";
else if (mType == CFG_MEM_TYPE::SAVE_)
return "save";
else if (mType == CFG_MEM_TYPE::FILED_)
return "filed";
else
return "error";
}
~Argument() { }
};
class Instruction
{
static int lastNumInstr;
private:
int number;
CFG_OP operation;
Argument* arg1;
Argument* arg2;
Argument* result;
SgStatement* st = NULL;
SgExpression* ex = NULL;
std::string getArgValue(Argument* arg) const
{
if (arg == NULL)
return "";
return arg->getValue();
}
public:
Instruction() : number(lastNumInstr++), operation(CFG_OP::NONE), arg1(NULL), arg2(NULL), result(NULL) { }
Instruction(CFG_OP op, Argument* arg1 = NULL, Argument* arg2 = NULL, Argument* res = NULL, SgStatement* st = NULL, SgExpression* ex = NULL) :
number(lastNumInstr++), operation(op), arg1(arg1), arg2(arg2), result(res), st(st), ex(ex) { }
Instruction(CFG_OP op, SgStatement* st) : number(lastNumInstr++), operation(op), arg1(NULL), arg2(NULL), result(NULL), st(st) { }
Instruction(CFG_OP op, int num, Argument* arg1 = NULL, Argument* arg2 = NULL, Argument* res = NULL, SgStatement* st = NULL, SgExpression* ex = NULL) :
number(num), operation(op), arg1(arg1), arg2(arg2), result(res), st(st), ex(ex) { }
void setOperation(CFG_OP op) { operation = op; }
CFG_OP getOperation() const { return operation; }
Argument* getArg1() const { return arg1; }
Argument* getArg2() const { return arg2; }
Argument* getResult() const { return result; }
void setArg1(Argument* arg) { arg1 = arg; }
void setArg2(Argument* arg) { arg2 = arg; }
void setResult(Argument* arg) { result = arg; }
int getNumber() const { return number; }
void shiftNumber(int add) { number += add; }
SgStatement* getOperator() const { return st; }
void setOperator(SgStatement* st_) { st = st_; }
SgExpression* getExpression() const { return ex; }
int getLine() const { return st ? st->lineNumber() : -1; }
bool isAccess() const
{
std::set<CFG_OP> accessOps = { CFG_OP::LOAD , CFG_OP::STORE, CFG_OP::REC_REF_LOAD, CFG_OP::REC_REF_STORE };
return accessOps.find(operation) != accessOps.end();
}
bool isArith() const
{
std::set<CFG_OP> arithOps = { CFG_OP::ADD, CFG_OP::MULT, CFG_OP::DIV, CFG_OP::SUBT, CFG_OP::UN_ADD, CFG_OP::UN_MINUS, CFG_OP::POW, CFG_OP::CONCAT };
//CFG_OP::CAST, CFG_OP::GE, CFG_OP::LE, CFG_OP::GT, CFG_OP::LT, CFG_OP::EQ, CFG_OP::NEQV, CFG_OP::EQV, CFG_OP::OR, CFG_OP::AND, CFG_OP::NOT };
return (arithOps.find(operation) != arithOps.end()) || isIntirinsicCall();
}
bool isIntirinsicCall() const
{
if (operation == CFG_OP::F_CALL)
{
if (ex)
{
if (isIntrinsicFunctionName(ex->symbol()->identifier()))
return true;
}
}
return false;
}
static int getNextInstrNum() { return lastNumInstr; }
static void shiftNextInstrNum(int byNum) { lastNumInstr += byNum; }
std::string dump()
{
std::string res = "";
std::string resultVal = getArgValue(result);
std::string arg1Val = getArgValue(arg1);
std::string arg2Val = getArgValue(arg2);
switch (operation)
{
case CFG_OP::ADD:
case CFG_OP::MULT:
case CFG_OP::DIV:
case CFG_OP::SUBT:
case CFG_OP::GE:
case CFG_OP::LE:
case CFG_OP::GT:
case CFG_OP::LT:
case CFG_OP::EQ:
case CFG_OP::NEQV:
case CFG_OP::EQV:
case CFG_OP::OR:
case CFG_OP::AND:
case CFG_OP::POW:
case CFG_OP::CONCAT:
res = resultVal + " = " + arg1Val + CFG_OP_S[(int)operation] + arg2Val;
break;
case CFG_OP::NOT:
case CFG_OP::UN_MINUS:
case CFG_OP::UN_ADD:
res = resultVal + " = " + CFG_OP_S[(int)operation] + arg1Val;
break;
case CFG_OP::POINTER_ASS:
res = arg1Val + CFG_OP_S[(int)operation] + resultVal;
break;
case CFG_OP::ASSIGN:
if (arg2)
res = resultVal + CFG_OP_S[(int)operation] + arg1Val + " [" + arg2Val + "]";
else
res = resultVal + CFG_OP_S[(int)operation] + arg1Val;
break;
case CFG_OP::JUMP:
case CFG_OP::ENTRY:
res = CFG_OP_S[(int)operation] + arg1Val;
break;
case CFG_OP::JUMP_IF:
res = CFG_OP_S[(int)operation] + arg1Val + " then goto " + arg2Val;
break;
case CFG_OP::EMPTY:
res = CFG_OP_S[(int)operation];
break;
case CFG_OP::LOAD:
case CFG_OP::REC_REF_LOAD:
res = CFG_OP_S[(int)operation] + resultVal + " " + arg1Val + (arg2 ? (" " + arg2Val) : "");
break;
case CFG_OP::REC_REF_STORE:
case CFG_OP::STORE:
res = CFG_OP_S[(int)operation] + arg1Val + (arg2 ? (" " + arg2Val) : "") + " " + resultVal;
break;
case CFG_OP::REC_REF:
res = "LOAD " + resultVal + " " + arg1Val + CFG_OP_S[(int)operation] + arg2Val;
break;
case CFG_OP::REF:
case CFG_OP::PARAM:
case CFG_OP::IO_PARAM:
res = CFG_OP_S[(int)operation] + arg1Val;
break;
case CFG_OP::CAST:
res = resultVal + " = " + CFG_OP_S[(int)operation] + arg1Val;
break;
case CFG_OP::F_CALL:
if (result)
res = resultVal + " = " + CFG_OP_S[(int)operation] + arg1Val + " " + arg2Val;
else
res = CFG_OP_S[(int)operation] + arg1Val + " " + arg2Val;
break;
case CFG_OP::RANGE:
res = CFG_OP_S[(int)operation] + "[ ";
if (arg1)
res += arg1Val;
res += " : ";
if (arg2)
res += arg2Val;
res += " : ";
if (result)
res += resultVal;
res += " ]";
break;
case CFG_OP::DVM_DIR:
case CFG_OP::SPF_DIR:
res = (st != NULL) ? std::string(st->unparse()) : "NULL";
break;
default:
res = CFG_OP_S[(int)operation];
break;
}
return res;
}
};
class IR_Block
{
private:
Instruction* current;
Instruction* jumpTo;
BasicBlock* bblock;
bool header;
public:
IR_Block(Instruction* instr) : current(instr), jumpTo(NULL), bblock(NULL), header(false) { }
IR_Block(const IR_Block& copyFrom)
{
current = new Instruction(*copyFrom.getInstruction());
bblock = NULL;
//need to replace with actual IR
jumpTo = copyFrom.getJump();
header = false;
}
Instruction* getInstruction() const { return current; }
Instruction* getJump() const { return jumpTo; }
BasicBlock* getBasicBlock() const { return bblock; }
int getNumber() const { return current->getNumber(); }
void setJump(Instruction* instr) { jumpTo = instr; }
void setBasicBlock(BasicBlock* newBlock) { bblock = newBlock; }
void setHeader() { header = true; }
bool isHeader() const { return header; }
int getLine() const { return current->getLine(); }
~IR_Block() { delete current; }
};
class BasicBlock;
}
std::string createName(const std::vector<std::pair<const Variable*, CommonBlock*>>& commonVars, const FuncInfo* func,
SgSymbol* s, SgStatement* scope, SAPFOR::CFG_MEM_TYPE& mType);
std::string getNameByArg(SAPFOR::Argument* arg);
SgSymbol* getSybolByArg(SAPFOR::Argument* arg);
SAPFOR::Argument* createArg(const std::string& fullName, const std::string& name, SAPFOR::CFG_MEM_TYPE mType);
std::vector<SAPFOR::IR_Block*> buildIR(SgStatement* function, const FuncInfo* func, const std::vector<std::pair<const Variable*, CommonBlock*>>& commonVars, const SAPFOR::CFG_Settings settings);
SAPFOR::Instruction* getInstructionByNumber(const std::vector<SAPFOR::IR_Block*>& blocks, int num);
std::pair<SAPFOR::Instruction*, SAPFOR::BasicBlock*> getInstructionAndBlockByNumber(const std::map<FuncInfo*, std::vector<SAPFOR::BasicBlock*>>& CFGraph, int num);
std::pair<SAPFOR::Instruction*, SAPFOR::BasicBlock*> getInstructionAndBlockByStatement(const std::map<FuncInfo*, std::vector<SAPFOR::BasicBlock*>>& CFGraph, SgStatement* stmt);
int getParamIndex(SAPFOR::Argument* func_param, int max_index);