代碼總框架:
一、第一層函數 :RemoveStructMain()
其中changBC是主要處理函數,函數findStruct()是用於檢測BC文件是否存在structType,以後會用while循環處理。
void RemoveStruct::RemoveStructMain(){
changeBC();
if (findStruct()){
cout<<"RemoveStructMain(): exist structure value!"<<endl;
changeBC();
} else {
outs() << "RemoveStructMain(): Success! " << "\n";
}
}
二、第二層函數:changeBC()
第一個函數pretreatment()對bc進行預處理,將BC中組合語句split開,方便後續處理。
第二個函數getIRStructType()是對module中所有定義的StructTypes進行讀取,並將其與其分解出的StructType都存入DAG中。
第三個函數SaveRootGlobalVar(); Traverse the module_ global list to find structure gv and save gv in structDAG
(DAG由多個vertex組成)
struct Vertex{
StructType *struct_Type_;
std::map<Value *, vector<Value *> > vertex_value_;
// vector<Value *> is the resolved values of Value
std::set<Vertex *> vertex_children_;
std::set<Vertex *> vertex_parent_;
};
第四個函數AllocaInstr(); Traverse the module_ allocaInst list to find structure allocaInst and save allocaInst in structDAG
以上全部爲構建DAG爲處理struct做準備。
第五個函數TopologicalSort(); 通過SaveRootGlobalVar();和 AllocaInstr();這兩個函數已經把struct value都存入DAG,下一步則是分解處理。
void RemoveStruct::changeBC() {
//split instruction for serving process struct
while (pretreatment()) {};
if(findStruct()){
getIRStructType();
SaveRootGlobalVar();
AllocaInstr();
StructDAG_->printStructType();
cout<<"DAG construction completed!"<<endl;
TopologicalSort();
//DelUnuseGlobalVarAndAlloca();
}
//assert(findStruct());
//valueMapPrint();
}
三、第三層函數:TopologicalSort()
(1)遍歷DAP中的vertex,找出入度爲零的vertex,並將其存入隊列q。
queue<StructDAG::Vertex*> q;
//q storage vertexs which's indegree are zero
StructDAG_->FindZeroIndegreeVertex(q);
(2)對每個vertex中的struct value進行分解替換處理,並將該struct value刪除。
while (!q.empty()) {
StructDAG::Vertex *v = q.front();
q.pop();
//process p
//(2.1)renew the current vertex relations with others
//(2.2)process structure values in current vertex
}
(2.1)當前的vertex V入度爲零,對其children vertex進行遍歷,renew the current vertex relations with its children,children vertex入度爲零 push至queue。最後將V的children vertex set清空。
(ps此時V上兩個set清空,只有map上的 std::map<Value *, vector<Value *> > vertex_value_;)
(2.2)
firstly,對同類型StructType的vertex V中所有Value進行resolveValue,此時當前subValue已得到。
secondly,此時已經將Value分解完畢,sub_value在其children vector上,通過user對Value相關指令進行替換和修改。並將V中map上的處理完畢的Value存入list。
(其中有兩次processVertexValue(iter->first);第一次是正常處理BC中原本的struct,第二次是爲了處理我在處理第一次struct生成與struct相關instruction。)
thirdly,通過list刪除所有的Value,對當前的V的map進行清空,對有效位的set進行clear。
(3)
函數function_map_process()爲了刪除oldFunction,然後對StructDAG進行clear。此時將生成最終無struct的BC。
function_map_process();
StructDAG_->printStructType();
StructDAG_->DestroyVertex();
四、第四層函數: processVertexValue()
主要處理一下五個函數,對應的五條指令都是由DAG上的struct value遍歷找到的instruction。
(一)首先處理GetElementPtrInstProcess()函數。
分情況討論:
1、當GetElementPtrInst的getOperand(0)爲IsStructVal時
情況一:NumOperands爲2時,assert。
情況二:NumOperands > 2時,進行GetelementptrStructProcess(instr),該函數就是將subValue代替structValue。
2、當GetElementPtrInst的getOperand(0)爲IsArrayStructVal時
進行GetelementptrArrayProcess(instr, array_layers);array_layers爲當前array層數。
情況一:instr->getNumOperands() < array_layers + 2,
// %120 = getelementptr inbounds [2 x [2 x %struct.point]], [2 x [2 x %struct.point]]* @global_8, i64 0, i64 1
// %121 = bitcast [2 x %struct.point]* %120 to i16*
getelementptr +bitcast 進行BitCastInstProcess(inst);
//%3 = getelementptr inbounds [2 x %struct.str], [2 x %struct.str]* %1, i64 0, i64 0
//%4 = call fastcc i32 @sum(%struct.str* nonnull %3) #4
getelementptr +call 進行GetElementPtrInstAsCallInstProcess(call_inst, instr);
未寫代碼打算參考callprocess()進行嫁接
情況二:instr->getNumOperands() == array_layers + 2
// %52 = getelementptr inbounds [2 x %struct.point], [2 x %struct.point]* %global_0, i64 0, i64 1
// %53 = bitcast %struct.point* %52 to i16*
getelementptr +bitcast 進行BitCastInstProcess(inst);
//%3 = getelementptr inbounds [2 x %struct.str], [2 x %struct.str]* %1, i64 0, i64 0, i64 0
//%4 = call fastcc i32 @sum(%struct.str* nonnull %3) #4
getelementptr +call 進行GetElementPtrInstAsCallInstProcess(call_inst, instr);
未寫代碼打算參考callprocess()進行嫁接
//%47 = getelementptr inbounds %struct.str, %struct.str* %0, i64 0, i32 8
//%48 = getelementptr inbounds [2 x %struct.point], [2 x %struct.point]* %47, i64 0, i64 0, i32 0
進行DoubleGetElementPtrProcess()兩條指令進行合併,卻沒有進行分解替換。
看看情況一情況二是否可以合併!!
情況三:正常情況分解。
// %6 = getelementptr inbounds [2 x [2 x %struct.str]], [2 x [2 x %struct.str]]* @global, i64 0, i64 0, i64 0, i32 0
3、未發現StructType,assert(0),情況不可能。
(二)其次處理MemcpyInstrProcess()函數。
取出需要copy的目標value memcpy_dest。memcpy比較獨立。
// get IntrinsicInst op_0 memcpy_dest
Value *memcpy_dest = MemcpyDestValue(instr);
memcpy_src分情況討論:
情況一:memcpy_src is ConstantExpr
MemcpyToConstantExpr(memcpy_dest, instr_src, instr);
情況二:memcpy_src is GetElementPtrInst
memcpyToGetElementPtrInst(memcpy_dest, getelementptr_src, instr);
情況三:memcpy_src is BitCastInst
memcpyToBitCast(memcpy_dest, bitcast_src, instr);
(三)接着處理LoadInstProcess()函數。
只有一種情況:
load的參數爲ConstantExpr
ConstantExpr可以分爲bitcast和GetElementPtr,但是一般bitcast在預處理split開了,load中會存在GetElementPtr。直接用GetElementPtrInstProcess(get_inst);處理一下就好。
(四)再處理BitCastInstProcess()函數。
遍歷BitCastInst的user種類
情況一:BitcastNextLoadProcess(),重點。
情況二:MemcpyInstrProcess();用之前的處理函數。
情況三:StoreInstProcess(),這個就是做拼接指令的。
(五)最後處理FunctionProcess()函數。
存在於callInst中的structValue,通過callInst找到對應的Function,
llvm::CallInst *inst = llvm::dyn_cast<llvm::CallInst>(CI);
CollectFunctionList(inst, FunctionList, val);
CollectFunctionList():structValue->CallInst->Function->CallInsts
這種需要修改,修改爲先用function_map_記錄新舊Function,最後進行刪除舊的Function。