FuncInfo.cpp 3.24 KB
Newer Older
刘睿博's avatar
刘睿博 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
#include "FuncInfo.hpp"
#include "Function.hpp"

void FuncInfo::run() {
    for (auto &f : m_->get_functions()) {
        auto func = &f;
        trivial_mark(func);
        if (not is_pure[func])
            worklist.push_back(func);
    }
    while (worklist.empty() == false) {
        auto now = worklist.front();
        worklist.pop_front();
        process(now);
    }
    log();
}

void FuncInfo::log() {
    for (auto it : is_pure) {
        LOG_INFO << it.first->get_name() << " is pure? " << it.second;
    }
}

// 有 store 操作的函数非纯函数来处理
void FuncInfo::trivial_mark(Function *func) {
    if (func->is_declaration() or func->get_name() == "main") {
        is_pure[func] = false;
        return;
    }
    // 只要传入数组,都作为非纯函数处理
    for (auto it = func->get_function_type()->param_begin();
         it != func->get_function_type()->param_end(); ++it) {
        auto arg_type = *it;
        if (arg_type->is_integer_type() == false and
            arg_type->is_float_type() == false) {
            is_pure[func] = false;
            return;
        }
    }
    for (auto &bb : func->get_basic_blocks())
        for (auto &inst : bb.get_instructions()) {
            if (is_side_effect_inst(&inst)) {
                is_pure[func] = false;
                return;
            }
        }
    is_pure[func] = true;
}

void FuncInfo::process(Function *func) {
    for (auto &use : func->get_use_list()) {
        LOG_INFO << use.val_->print() << " uses func: " << func->get_name();
        if (auto inst = dynamic_cast<Instruction *>(use.val_)) {
            auto func = (inst->get_parent()->get_parent());
            if (is_pure[func]) {
                is_pure[func] = false;
                worklist.push_back(func);
            }
        } else
            LOG_WARNING << "Value besides instruction uses a function";
    }
}

// 对局部变量进行 store 没有副作用
bool FuncInfo::is_side_effect_inst(Instruction *inst) {
    if (inst->is_store()) {
        if (is_local_store(dynamic_cast<StoreInst *>(inst)))
            return false;
        return true;
    }
    if (inst->is_load()) {
        if (is_local_load(dynamic_cast<LoadInst *>(inst)))
            return false;
        return true;
    }
    // call 指令的副作用会在后续 bfs 中计算
    return false;
}

bool FuncInfo::is_local_load(LoadInst *inst) {
    auto addr =
        dynamic_cast<Instruction *>(get_first_addr(inst->get_operand(0)));
    if (addr and addr->is_alloca())
        return true;
    return false;
}

bool FuncInfo::is_local_store(StoreInst *inst) {
    auto addr = dynamic_cast<Instruction *>(get_first_addr(inst->get_lval()));
    if (addr and addr->is_alloca())
        return true;
    return false;
}
Value *FuncInfo::get_first_addr(Value *val) {
    if (auto inst = dynamic_cast<Instruction *>(val)) {
        if (inst->is_alloca())
            return inst;
        if (inst->is_gep())
            return get_first_addr(inst->get_operand(0));
        if (inst->is_load())
            return val;
        LOG_WARNING << "FuncInfo: try to determine addr in operands";
        for (auto op : inst->get_operands()) {
            if (op->get_type()->is_pointer_type())
                return get_first_addr(op);
        }
    }
    return val;
}