#pragma once #include #include #include #include #include #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 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 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 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>& 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 buildIR(SgStatement* function, const FuncInfo* func, const std::vector>& commonVars, const SAPFOR::CFG_Settings settings); SAPFOR::Instruction* getInstructionByNumber(const std::vector& blocks, int num); std::pair getInstructionAndBlockByNumber(const std::map>& CFGraph, int num); std::pair getInstructionAndBlockByStatement(const std::map>& CFGraph, SgStatement* stmt); int getParamIndex(SAPFOR::Argument* func_param, int max_index);