﻿//
// Created by 89600 on 2019.12.8.
//

#include "Optimize.h"
#include <algorithm>

Optimize::Optimize(vector<string> &middleCode) : middleCode(middleCode) {}

// 优化主函数
void Optimize::parse() {
    split();

    createSymbolMap();
    constSpread();
    funcInline();
    labelSimplify();

    ofstream outOpt;
    std::locale::global(std::locale(""));
    outOpt.open("17373051.txt"); //_郭骏_优化后中间代码
    for (instr elm : instrs) {
        if (elm.type == funcdef) {
            outOpt << elm.iden0 << ' ' << elm.iden1 << "()" << endl;
        } else {
            outOpt << elm.iden0 << ' ' << elm.iden1 << ' ' << elm.iden2 << ' ' << elm.iden3 << ' ' << elm.iden4 << endl;
        }
    }
    outOpt.close();

    Mips mips(instrs);
    mips.parse();
}

// 拆分中间代码
void Optimize::split() {
    int codePlace = 0;
    string currentCode;
    instr currentInstr;
    while (codePlace < middleCode.size()) {
        currentCode = middleCode.at(codePlace++);
        currentInstr.iden0 = "";
        currentInstr.iden1 = "";
        currentInstr.iden2 = "";
        currentInstr.iden3 = "";
        currentInstr.iden4 = "";
        int i, base = 0, c = 0;
        for (i = base; i < currentCode.size(); i++) {
            if (currentCode[i] == ' ') {
                break;
            }
        }
        string tmpstr = currentCode.substr(0, i);
        if (tmpstr == "ret") {
            currentInstr.type = ret;
        } else if (tmpstr == "const") {
            currentInstr.type = constdef;
        } else if (tmpstr == "var") {
            currentInstr.type = vardef;
        } else if (tmpstr == "int" || tmpstr == "char" || tmpstr == "void") {
            currentInstr.type = funcdef;
        } else if (tmpstr == "para") {
            currentInstr.type = paradef;
        } else if (tmpstr == "push") {
            currentInstr.type = push;
        } else if (tmpstr == "call") {
            currentInstr.type = fcall;
        } else if (tmpstr == "GOTO") {
            currentInstr.type = bgoto;
        } else if (tmpstr == "BNZ") {
            currentInstr.type = bnz;
        } else if (tmpstr == "BZ") {
            currentInstr.type = bz;
        } else if (tmpstr.back() == ':') {
            currentInstr.type = label;
        } else if (tmpstr == "mac") {
            currentInstr.type = mac;
        } else {
            currentInstr.type = cal;
        }
        currentInstr.iden0 = tmpstr;
        if (i == currentCode.size()) {
            instrs.push_back(currentInstr);
            continue;
        }
        while (true) {
            base = i + 1;
            int inquote = 0;
            for (i = base; i < currentCode.size(); i++) {
                if (currentCode[i] == '\"') {
                    inquote = 1 - inquote;
                }
                if (currentCode[i] == ' ' && !inquote) {
                    break;
                }
            }
            tmpstr = currentCode.substr(base, i - base);
            switch (c) {
                case 0:
                    currentInstr.iden1 = tmpstr;
                    if (currentInstr.type == funcdef) {
                        currentInstr.iden1 = tmpstr.substr(0, tmpstr.size() - 2);
                    }
                    break;
                case 1:
                    currentInstr.iden2 = tmpstr;
                    break;
                case 2:
                    currentInstr.iden3 = tmpstr;
                    break;
                case 3:
                    currentInstr.iden4 = tmpstr;
                    break;
                default:
                    break;
            }
            c++;
            if (i == currentCode.size()) {
                break;
            }
        }
        instrs.push_back(currentInstr);
    }
}

// 判断操作数是否为数字
bool isNumber(string str) {
    return str[0] == '+' || str[0] == '-' || isdigit(str[0]);
}

// 0.建立优化前的符号表
void Optimize::createSymbolMap() {
    int currentAddr = 0;
    int currentStack = 0;
    int currentString = 0;
    string currentFunc = ".global";
    SymbolMap *currentMap = new SymbolMap(nullptr, currentFunc);
    for (auto it = instrs.begin(); it != instrs.end(); it++) {
        instr elm = *it;
        switch (elm.type) {
            case funcdef:
                currentFunc = elm.iden1;
                if (currentMap->getPrev() != nullptr) {
                    currentMap = currentMap->getPrev();
                }
                if (elm.iden0 == "int") {
                    currentMap->addFunc(elm.iden1, func_int, 0, 0);
                } else if (elm.iden0 == "char") {
                    currentMap->addFunc(elm.iden1, func_char, 0, 0);
                } else { // void
                    currentMap->addFunc(elm.iden1, func_void, 0, 0);
                }
                currentMap = currentMap->getNext(elm.iden1);
                currentStack = 0;
                break;
            case constdef:
                if (currentFunc == ".global") {
                    if (elm.iden1 == "int") {
//                        it->iden2 = "__global_" + elm.iden2;
//                        currentMap->define(elm.iden2, sym_int, place_data, currentAddr);
//                        currentAddr += 4;
                        it->iden2 = "__global_" + elm.iden2;
                        currentMap->define(elm.iden2, sym_int, place_const, stoi(elm.iden4));
                    } else if (elm.iden1 == "char") {
                        it->iden2 = "__global_" + elm.iden2;
                        currentMap->define(elm.iden2, sym_char, place_data, currentAddr);
                        currentAddr += 4;
                    } else { // string
                        currentMap->define(elm.iden2, sym_string, place_sp, currentString++);
                    }
                } else {
                    if (elm.iden1 == "int") {
//                        currentMap->define(elm.iden2, sym_int, place_sp, currentStack);
//                        currentStack -= 4;
                        currentMap->define(elm.iden2, sym_int, place_const, stoi(elm.iden4));
                    } else if (elm.iden1 == "char") {
                        currentMap->define(elm.iden2, sym_char, place_sp, currentStack);
                        currentStack -= 4;
                    } else { // string
                        currentMap->define(elm.iden2, sym_string, place_sp, currentString++);
                    }
                }
                break;
            case vardef:
                if (currentFunc == ".global") {
                    if (elm.iden1 == "int") {
                        it->iden2 = "__global_" + elm.iden2;
                        if (elm.iden2.back() == ']') {
                            int i;
                            for (i = 0; i < elm.iden2.size(); i++) {
                                if (elm.iden2.at(i) == '[') {
                                    break;
                                }
                            }
                            int n = stoi(elm.iden2.substr(i + 1, elm.iden2.size() - i - 1));
                            for (int j = 0; j < n; j++) {
                                currentMap->define(elm.iden2.substr(0, i) + "[" + to_string(j) + "]", sym_int,
                                                   place_data, currentAddr);
                                currentAddr += 4;
                            }
                        } else {
                            currentMap->define(elm.iden2, sym_int, place_data, currentAddr);
                            currentAddr += 4;
                        }
                    } else if (elm.iden1 == "char") {
                        it->iden2 = "__global_" + elm.iden2;
                        if (elm.iden2.back() == ']') {
                            int i;
                            for (i = 0; i < elm.iden2.size(); i++) {
                                if (elm.iden2.at(i) == '[') {
                                    break;
                                }
                            }
                            int n = stoi(elm.iden2.substr(i + 1, elm.iden2.size() - i - 1));
                            for (int j = 0; j < n; j++) {
                                currentMap->define(elm.iden2.substr(0, i) + "[" + to_string(j) + "]", sym_char,
                                                   place_data, currentAddr);
                                currentAddr += 4;
                            }
                        } else {
                            currentMap->define(elm.iden2, sym_char, place_data, currentAddr);
                            currentAddr += 4;
                        }
                    }
                } else {
                    if (elm.iden1 == "int") {
                        if (elm.iden2.back() == ']') {
                            int i;
                            for (i = 0; i < elm.iden2.size(); i++) {
                                if (elm.iden2.at(i) == '[') {
                                    break;
                                }
                            }
                            int n = stoi(elm.iden2.substr(i + 1, elm.iden2.size() - i - 1));
                            for (int j = 0; j < n; j++) {
                                currentMap->define(elm.iden2.substr(0, i) + "[" + to_string(j) + "]", sym_int,
                                                   place_sp, currentStack);
                                currentStack -= 4;
                            }
                        } else {
                            currentMap->define(elm.iden2, sym_int, place_sp, currentStack);
                            currentStack -= 4;
                        }
                    } else if (elm.iden1 == "char") {
                        if (elm.iden2.back() == ']') {
                            int i;
                            for (i = 0; i < elm.iden2.size(); i++) {
                                if (elm.iden2.at(i) == '[') {
                                    break;
                                }
                            }
                            int n = stoi(elm.iden2.substr(i + 1, elm.iden2.size() - i - 1));
                            for (int j = 0; j < n; j++) {
                                currentMap->define(elm.iden2.substr(0, i) + "[" + to_string(j) + "]", sym_char,
                                                   place_sp, currentStack);
                                currentStack -= 4;
                            }
                        } else {
                            currentMap->define(elm.iden2, sym_char, place_sp, currentStack);
                            currentStack -= 4;
                        }
                    }
                }
                break;
            case paradef:
                if (currentFunc == ".global") {
                    if (elm.iden2[0] != '#') {
                        currentMap->searchFunc(currentFunc)->paras++;
                    }
                    if (elm.iden1 == "int") {
                        if (currentMap->define(elm.iden2, sym_int, place_data, currentAddr)) {
                            currentAddr += 4;
                        }
                    } else {
                        if (currentMap->define(elm.iden2, sym_char, place_data, currentAddr)) {
                            currentAddr += 4;
                        }
                    }
                } else {
                    if (elm.iden2[0] != '#') {
                        currentMap->searchFunc(currentFunc)->paras++;
                    }
                    if (elm.iden1 == "int") {
                        if (currentMap->define(elm.iden2, sym_int, place_sp, currentStack)) {
                            currentStack -= 4;
                        }
                    } else {
                        if (currentMap->define(elm.iden2, sym_char, place_sp, currentStack)) {
                            currentStack -= 4;
                        }
                    }
                }
                break;
            default:
                break;
        }
    }

    currentFunc = ".global";

    for (auto it = instrs.begin(); it != instrs.end(); it++) {
        instr elm = *it;
        switch (elm.type) {
            case funcdef:
                currentFunc = elm.iden1;
                if (currentMap->getPrev() != nullptr) {
                    currentMap = currentMap->getPrev();
                }
                currentMap = currentMap->getNext(elm.iden1);
                currentStack = -currentMap->getStackSize();
                break;
            case cal:
                if (!elm.iden4.empty()) {
                    if (elm.iden3 != "[]") {
                        if (currentMap->add(elm.iden0, sym_int, place_sp, currentStack)) {
                            currentStack -= 4;
                        }
                    } else {
                        if (currentMap->add(elm.iden0, currentMap->getType(elm.iden2), place_sp, currentStack)) {
                            currentStack -= 4;
                        }
                    }
                    if (!isNumber(elm.iden0) && currentMap->search(elm.iden0)->place == place_data) {
                        it->iden0 = "__global_" + elm.iden0;
                    }
                    if (!isNumber(elm.iden2) && currentMap->search(elm.iden2)->place == place_data) {
                        it->iden2 = "__global_" + elm.iden2;
                    }
                    if (!isNumber(elm.iden4) && currentMap->search(elm.iden4)->place == place_data) {
                        it->iden4 = "__global_" + elm.iden4;
                    }
                    if (!isNumber(elm.iden2) && currentMap->search(elm.iden2)->place == place_const) {
                        it->iden2 = to_string(currentMap->search(elm.iden2)->addr);
                    }
                    if (!isNumber(elm.iden4) && currentMap->search(elm.iden4)->place == place_const) {
                        it->iden4 = to_string(currentMap->search(elm.iden4)->addr);
                    }
                } else {
                    SymbolType typee = currentMap->getType(elm.iden2);
                    if (currentMap->add(elm.iden0, typee, place_sp, currentStack)) {
                        currentStack -= 4;
                    }
                    if (!isNumber(elm.iden0) && currentMap->search(elm.iden0)->place == place_data) {
                        it->iden0 = "__global_" + elm.iden0;
                    }
                    if (!isNumber(elm.iden2) && currentMap->search(elm.iden2)->place == place_data) {
                        it->iden2 = "__global_" + elm.iden2;
                    }
                    if (!isNumber(elm.iden2) && currentMap->search(elm.iden2)->place == place_const) {
                        it->iden2 = to_string(currentMap->search(elm.iden2)->addr);
                    }
                }
                break;
            case fcall:
                if (currentMap->add("#RET", sym_int, place_sp, currentStack))
                    currentStack -= 4;
                break;
            case mac:
                if (!elm.iden2.empty() && currentMap->search(elm.iden2)->place == place_data) {
                    it->iden2 = "__global_" + elm.iden2;
                }
                break;
            default:
                break;
        }
    }

    for (auto it = instrs.begin(); it != instrs.end(); it++) {
        if (it->type == constdef && it->iden1 == "int") {
            it = instrs.erase(it);
            if (it == instrs.end()) {
                break;
            }
        }
    }

}

// 1.常量传播
void Optimize::constSpread() {

    DETAIL("-------------------------------Constant Spread------------------------------")
    while (true) {
        int count1 = 0, count2 = 0;
        auto it = instrs.begin();
        while (it != instrs.end()) {
            if (isNumber(it->iden2) && isNumber(it->iden4) && it->iden3 != "[]=") {
                count1++;
                switch (it->iden3[0]) {
                    case '+':
                        it->iden2 = to_string(stoi(it->iden2) + stoi(it->iden4));
                        it->iden4 = "";
                        it->iden3 = "";
                        break;
                    case '-':
                        it->iden2 = to_string(stoi(it->iden2) - stoi(it->iden4));
                        it->iden4 = "";
                        it->iden3 = "";
                        break;
                    case '*':
                        it->iden2 = to_string(stoi(it->iden2) * stoi(it->iden4));
                        it->iden4 = "";
                        it->iden3 = "";
                        break;
                    case '/':
                        it->iden2 = to_string(stoi(it->iden2) / stoi(it->iden4));
                        it->iden4 = "";
                        it->iden3 = "";
                        break;
                    default:
                        break;
                }
            }
            it++;
        }

        DETAIL("Calculate " << count1 << " group(s) of constant expressions.")

        // t1 = a
        // b = t1 + c or b = t1
        it = instrs.begin();
        map<string, string> tmpValueList;
        while (it != instrs.end()) {
            if ((it->iden0.substr(0, 4) == "#tmp") && isNumber(it->iden2) &&
                it->iden4.empty()) {
                tmpValueList.insert(make_pair(it->iden0, it->iden2));
                count2++;
                it = instrs.erase(it);
            } else {
                it++;
            }
        }

        it = instrs.begin();
        while (it != instrs.end()) {
            if (tmpValueList.find(it->iden2) != tmpValueList.end()) {
                it->iden2 = tmpValueList[it->iden2];
            }
            if (tmpValueList.find(it->iden4) != tmpValueList.end()) {
                it->iden4 = tmpValueList[it->iden4];
            }
            it++;
        }

        // t1 = a + b
        // c = t1
        it = instrs.begin();
        map<string, vector<instr>::iterator> tmpInstrList;
        while (it != instrs.end()) {
            if (it->iden0.substr(0, 4) == "#tmp") {
                tmpInstrList.insert(make_pair(it->iden0, it));
            }
            it++;
        }

        it = instrs.begin();
        while (it != instrs.end()) {
            if (tmpInstrList.find(it->iden2) != tmpInstrList.end() && it->iden4.empty()) {
                tmpInstrList[it->iden2]->type = instr_error;
                instr tmpit = *tmpInstrList[it->iden2];
                it->iden2 = tmpit.iden2;
                it->iden3 = tmpit.iden3;
                it->iden4 = tmpit.iden4;
            }
            it++;
        }

        it = instrs.begin();
        while (it != instrs.end()) {
            if (it->type == instr_error) {
                count2++;
                it = instrs.erase(it);
            } else {
                it++;
            }
        }

        DETAIL("Move " << count2 << " temporary variable(s).")

        if (count1 == 0 && count2 == 0) {
            DETAIL("\nNo more constants can be spreaded. End loop.")
            break;
        }
    }
}

// 2.函数内联
void Optimize::funcInline() {
    int i = 0;
    string currentFunc;
    string typp;
    int start = 0, end = 0;
    int canInline = 0;
    int paras = 0;
    int count1 = 0;
    int count2 = 0;
    vector<string> recurs;
    DETAIL("-------------------------------Function Inline------------------------------")
    while (true) {
        for (; i < instrs.size(); i++) {
            if (instrs.at(i).type == funcdef &&
                find(recurs.begin(), recurs.end(), instrs.at(i).iden1) == recurs.end()) {
                currentFunc = instrs.at(i).iden1;
                typp = instrs.at(i).iden0;
                start = i;
                canInline = 1;
                paras = 0;
                DETAIL("Scanning for function " << currentFunc);
                break;
            }
        }
        i++;
        if (currentFunc == "main") {
            DETAIL("Reach main function, process ends.\n")
            break;
        }
        for (; i < instrs.size(); i++) {
            if (instrs.at(i).type == funcdef) {
                end = i;
                DETAIL("Function " << currentFunc << " can inline.")
                count1++;
                break;
            } else if (instrs.at(i).type == fcall && instrs.at(i).iden1 == currentFunc) {
                canInline = 0;
                DETAIL("Got recursive sentence. Function " << currentFunc << " cannot inline.")
                recurs.push_back(currentFunc);
                break;
            } else if (instrs.at(i).type == paradef && instrs.at(i).iden2.substr(0, 7) != "#inline") {
                paras++;
            }
        }

        if (canInline) {
            for (auto it = instrs.begin(); it != instrs.end(); it++) {
                if (it->type == fcall && it->iden1 == currentFunc) {
                    DETAIL("Got call of function " << currentFunc << ". Replace it with inline sentences.")
                    count2++;
                    auto ait = it;
                    int aparas = paras;
                    while (aparas) {
                        if (ait->type == push) {
                            ait->iden2 = ait->iden1;
                            ait->iden1 = "=";
                            ait->iden0 = "#inline" + to_string(count2) + "#" + instrs.at(start + aparas).iden2;
                            ait->type = cal;
                            aparas--;
                        }
                        ait--;
                    }
                    vector<string> paraList;
                    if (instrs.at(start).iden0 != "void") {
                        paraList.emplace_back("#retval");
                    }
                    // 可能需要思考中间变量的影响
                    vector<instr> addInstrs;
                    for (i = start + 1; i < end; i++) {
                        if (instrs.at(i).type == paradef ||
                            (instrs.at(i).type == constdef && instrs.at(i).iden1 != "string") ||
                            instrs.at(i).type == vardef) {
                            instr tmpins;
                            tmpins.type = instrs.at(i).type;
                            tmpins.iden0 = instrs.at(i).iden0;
                            tmpins.iden1 = instrs.at(i).iden1;
                            tmpins.iden2 = instrs.at(i).iden2;
                            tmpins.iden3 = instrs.at(i).iden3;
                            tmpins.iden4 = instrs.at(i).iden4;
                            if (instrs.at(i).iden2.back() == ']') {
                                int j;
                                for (j = 0; j < instrs.at(i).iden2.size(); j++) {
                                    if (instrs.at(i).iden2.at(j) == '[') {
                                        break;
                                    }
                                }
                                int n = stoi(instrs.at(i).iden2.substr(j + 1, instrs.at(i).iden2.size() - j - 1));
                                for (int k = 0; k < n; k++) {
                                    paraList.push_back(instrs.at(i).iden2.substr(0, j) + "[" + to_string(k) + "]");
                                }
                            } else {
                                paraList.push_back(instrs.at(i).iden2);
                            }
                            tmpins.iden2 = "#inline" + to_string(count2) + "#" + instrs.at(i).iden2;
                            addInstrs.push_back(tmpins);
                        }
                    }

                    for (i = start + 1; i < end; i++) {
                        instr tmpins;
                        tmpins.type = instrs.at(i).type;
                        tmpins.iden0 = instrs.at(i).iden0;
                        tmpins.iden1 = instrs.at(i).iden1;
                        tmpins.iden2 = instrs.at(i).iden2;
                        tmpins.iden3 = instrs.at(i).iden3;
                        tmpins.iden4 = instrs.at(i).iden4;
                        if (instrs.at(i).type == cal) {
                            int i0 = 0, i2 = 0, i4 = 0;
//                            if (instrs.at(i).iden0[0] == '#') {
//                                tmpins.iden0 = "#inline" + to_string(count2) + "#" + instrs.at(i).iden0;
//                                i0 = 1;
//                            }
//                            if (instrs.at(i).iden2[0] == '#') {
//                                tmpins.iden2 = "#inline" + to_string(count2) + "#" + instrs.at(i).iden2;
//                                i2 = 1;
//                            }
//                            if (!instrs.at(i).iden4.empty() && instrs.at(i).iden4[0] == '#') {
//                                tmpins.iden4 = "#inline" + to_string(count2) + "#" + instrs.at(i).iden4;
//                                i4 = 1;
//                            }
                            if (instrs.at(i).iden1 != "=") {
                                tmpins.iden0 = "#inline" + to_string(count2) + "#" + instrs.at(i).iden0;
                                tmpins.iden2 = "#inline" + to_string(count2) + "#" + instrs.at(i).iden2;
                            } else {
                                if (tmpins.iden0.size() >= 6 &&
                                    tmpins.iden0.substr(tmpins.iden0.size() - 6, 5) == "#cond") {
                                    tmpins.iden0 = "#inline" + to_string(count2) + "#" + instrs.at(i).iden0;
                                }
                                for (string elm : paraList) {
                                    if (!i0 && elm == instrs.at(i).iden0) {
                                        tmpins.iden0 = "#inline" + to_string(count2) + "#" + instrs.at(i).iden0;
                                    }
                                    if (!i2 && elm == instrs.at(i).iden2) {
                                        tmpins.iden2 = "#inline" + to_string(count2) + "#" + instrs.at(i).iden2;
                                    }
                                    if (!i4 && !instrs.at(i).iden4.empty() && elm == instrs.at(i).iden4) {
                                        tmpins.iden4 = "#inline" + to_string(count2) + "#" + instrs.at(i).iden4;
                                    }
                                }
                            }
                            addInstrs.push_back(tmpins);
                        } else if (instrs.at(i).type == ret && instrs.at(i).iden1.empty()) {
                            tmpins.type = bgoto;
                            tmpins.iden0 = "GOTO";
                            tmpins.iden1 = "label_inline_end_" + to_string(count2);
                            addInstrs.push_back(tmpins);
                        } else if (instrs.at(i).type == ret && !instrs.at(i).iden1.empty()) {
                            instr newins;
                            newins.type = cal;
                            newins.iden0 = "#inline" + to_string(count2) + "##retval";
                            newins.iden1 = "=";
                            newins.iden2 = "#inline" + to_string(count2) + "#" + instrs.at(i).iden1;
                            addInstrs.push_back(newins);
                            tmpins.type = bgoto;
                            tmpins.iden0 = "GOTO";
                            tmpins.iden1 = "label_inline_end_" + to_string(count2);
                            addInstrs.push_back(tmpins);
                        } else if (instrs.at(i).type == push) {
                            for (string elm : paraList) {
                                if (elm == instrs.at(i).iden1) { //instrs.at(i).iden1[0] == '#' ||
                                    instrs.at(i).iden1 = "#inline" + to_string(count2) + "#" + instrs.at(i).iden1;
                                }
                            }
                            addInstrs.push_back(tmpins);
                        } else if (instrs.at(i).type == label) {
                            tmpins.iden0 = instrs.at(i).iden0.substr(0, instrs.at(i).iden0.size() - 1)
                                           + "_inline_" + to_string(count2) + ":";
                            addInstrs.push_back(tmpins);
                        } else if (instrs.at(i).type == bnz || instrs.at(i).type == bz || instrs.at(i).type == bgoto) {
                            tmpins.iden1 = instrs.at(i).iden1 + "_inline_" + to_string(count2);
                            addInstrs.push_back(tmpins);
                        } else if (instrs.at(i).type == mac) {
                            for (string elm : paraList) {
                                if (!instrs.at(i).iden2.empty() &&
                                    (elm == instrs.at(i).iden2)) { // || instrs.at(i).iden2[0] == '#'
                                    instrs.at(i).iden2 = "#inline" + to_string(count2) + "#" + instrs.at(i).iden2;
                                }
                            }
                            addInstrs.push_back(tmpins);
                        } else if (instrs.at(i).type == fcall) {
                            addInstrs.push_back(tmpins);
                        }
                    }
                    Instr endins;
                    endins.type = label;
                    endins.iden0 = "label_inline_end_" + to_string(count2) + ":";
                    addInstrs.push_back(endins);
                    it = instrs.erase(it);
                    it = instrs.insert(it, addInstrs.begin(), addInstrs.end());
                    // 随后紧跟的一定是对RET的处理
                    it += addInstrs.size();
                    if (typp != "void") {
                        instr newins;
                        newins.type = vardef;
                        newins.iden0 = "var";
                        newins.iden1 = typp;
                        newins.iden2 = "#inline" + to_string(count2) + "##retval";
                        it = instrs.insert(it, newins);
                        it++;
                    }
                    if (it->iden2 == "#RET") {
                        if (instrs.at(start).iden0 != "void") {
                            it->iden2 = "#inline" + to_string(count2) + "##retval";
                        } else {
                            it = instrs.erase(it) - 1;
                        }
                    } else {
                        DETAIL("What's wrong?")
                    }
                }
            }
            instrs.erase(instrs.begin() + start, instrs.begin() + end);
            i = 0;
        }
        DETAIL("")
    }

}

// 3.标签简化
void Optimize::labelSimplify() {
    int count1 = 0, count2 = 0;
    DETAIL("-------------------------------Label Simplify-------------------------------")
    auto it = instrs.begin();
    while (it != instrs.end() - 1) {
        if (it->type == label && (it + 1)->type == label) {
            // 删除it+1位置代表的所有标签
            string label1 = it->iden0.substr(0, (it)->iden0.size() - 1);
            string label2 = (it + 1)->iden0.substr(0, (it + 1)->iden0.size() - 1);
            DETAIL("Get duplicated label: " << label1 << " and " << label2)
            count1++;
            for (auto ins = instrs.begin(); ins != instrs.end(); ins++) {
                if (ins->type == bz || ins->type == bnz || ins->type == bgoto) {
                    if (ins->iden1 == label2) {
                        DETAIL("Found use of " << label2 << ", try to replace it with " << label1)
                        count2++;
                        ins->iden1 = label1;
                    }
                }
            }
            it = instrs.erase(it + 1) - 1;
            if (it == instrs.end() - 1) {
                break;
            }

        } else {
            it++;
        }
    }
    DETAIL("\nThere are " << count1 << " pairs of duplicated label(s), and it affect " << count2
                          << " branch(es) or jump(s).\n");

    it = instrs.begin();
    count1 = 0;
    while (it != instrs.end() - 1) {
        if (it->type == bgoto && (it + 1)->type == label &&
            it->iden1 == (it + 1)->iden0.substr(0, (it + 1)->iden0.size() - 1)) {
            // 删除it位置的goto
            string label = (it + 1)->iden0.substr(0, (it + 1)->iden0.size() - 1);
            DETAIL("Get duplicated jump for: " << label)
            count1++;
            it = instrs.erase(it);
            if (it == instrs.end() - 1) {
                break;
            }
        } else {
            it++;
        }
    }
    DETAIL("\nDelete " << count1 << " pairs of duplicated jump(s).\n");

    it = instrs.begin();
    count1 = 0;
    vector<string> labelList;
    while (it != instrs.end()) {
        if (it->type == bgoto || it->type == bnz || it->type == bz) {
            labelList.push_back(it->iden1 + ":");
        }
        it++;
    }

    it = instrs.begin();
    while (it != instrs.end()) {
        if (it->type == label) {
            if (find(labelList.begin(), labelList.end(), it->iden0) == labelList.end()) {
                DETAIL("Get duplicated label: " << it->iden0.substr(0, it->iden0.size() - 1));
                it = instrs.erase(it);
                count1++;
            } else {
                it++;
            }
        } else {
            it++;
        }
    }

    DETAIL("\nDelete " << count1 << " pairs of duplicated label(s).\n");
}


