346 lines
14 KiB
C++
346 lines
14 KiB
C++
#pragma once
|
|
#include <string>
|
|
#include <map>
|
|
#include <set>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
|
|
#include "CFGraph.h"
|
|
#include "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); |