如何创建高可读性的IR代码

在LLVM中创建可读性较高的IR代码是让人头疼的,即使你使用了LLVM官方提供的IRBuilder,你任然无法逃脱它扁平化的表示,尤其是BB之间错综复杂的关系,一旦代码量达到一个数量级后,维护这样的代码让人痛不欲生。如果让我总结在LLVM中创建IR的感觉:“只比直接写汇编语言强一点”。

笔者利用C++ lambda以及运算符重载特性简化了这一操作,使用lambda嵌套,恰好可以表示控制流中的作用域,有序的代码缩进也能提高代码的可读性,利用这一点可以让你轻松创建与高级语言类似的控制流语句。

运算符重载则可以简化二元表达式的创建。

代码在Github gits中托管,地址:

注意:请勿用于您的生产环境,此项目任然为演示项目,还有很多未实现的功能,以及未实现的测试用例。

以下为两个Demo:

// Demo: Generate Fibonacci sequence.
// C version:
int fib(int n) {
    if (n==1||n==2)
        return 1;
    return fib(n-1) + fib(n-2);
}
 
// IR version:
Function *F = createFn("fib");
IRMaker M(F);

Val N = M.arg(0);
M.when(N == 1 || N == 2, [&](IRMaker &IfM) {
    IfM.ret(IfM.i32(1))
});
M.ret(M.call(F, {N-1}) + M.call(F, {N-2});

// Demo: Binary tree search with stack.
// C Version:
Node *BTS(Node *node, int v) {
    Node *stack[100];
    int stackIdx = 0;
    stack[0] = node;
    while (stackIdx >=0 ) {
        Node *top = stack[stackIdx--];
        if (top->v == v)
            return top;
        if (top->right)
            stack[++stackIdx] = top->right;
        if (top->left)
            stack[++stackIdx] = top->left;
    }

    return NULL;
}

// IR version:
Function *F = createFn("BTS");
IRMaker M(F);
Val Node = M.arg(0);
Val V = M.arg(1);

Val StackSize = M.i32(100);
Val StackPtr = M.alloc(NodePtrTy, &StackSize); // Alloc array with 100 elements.
Val StackIdxPtr = M.alloc(M.i32(0)); // Alloc i32 variable with initial value 0.
StackPtr.store(0, Node);  // stack[0] = node

// while (stackIdx >=0 )
M.loopWhen([&](IRMaker &CondM) {
    return *StackIdxPtr >= 0;
}, [&](IRMaker &LoopM) {
    Val TopPtr = StackPtr.load(*StackIdxPtr); // top = stack[stackIdx]
    StackIdxPtr.store(*StackIdxPtr - 1); // stackIdx --
    M.when(TopPtr.load(Idx_Node_Value) == V, [&](IRMaker &IfM) {
        IfM.ret(TopPtr);
    });

    // Push right if needed.
    M.when(TopPtr.load(Idx_Node_Right).isNotNull(), [&](IRMaker &IfM) {
        StackIdxPtr.store(*StackIdxPtr + 1); // stackIdx ++
        StackPtr.store(*StackIdxPtr, TopPtr.load(Idx_Node_Right)); // stack[stackIdx] = top->right;
    });

    // Push left if needed.
    M.when(TopPtr.load(Idx_Node_Left).isNotNull(), [&](IRMaker &IfM) {
        StackIdxPtr.store(*StackIdxPtr + 1); // stackIdx ++
        StackPtr.store(*StackIdxPtr, TopPtr.load(Idx_Node_Left)); // stack[stackIdx] = top->left;
    });
});

M.retNull();
4 个赞

前排支持 紫薯布丁

1 个赞

前排支持 紫薯布丁

前排支持 紫薯布丁

感觉不如重新维护LLVM C-Backend

您不要欺负新同学

前排支持 紫薯布丁

我老想学会LLVM了, 令人感叹