Week 10

For Week 10, I was working on the symbolic ASR pass. Reiterating the idea behing the pass, we want to introduce such an ASR->ASR pass to lift the symbolic support from the C backend and extend its functionality to all other backends like LLVM. The Pull Request for the same can be viewed here

So we would essentially want to treat Program 1 as Program 2 and make changes in the ASR from Program 1 accordingly.

# Program 1             
from lpython import S
from sympy import pi

def main0():
    x: S = pi

main0()

# Program 2
from lpython import ccall, CPtr, p_c_pointer, pointer, i64, empty_c_void_p
import os

@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib")
def basic_new_stack(x: CPtr) -> None:
    pass

@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib")
def basic_const_pi(x: CPtr) -> None:
    pass

def main0():
    _x: i64 = i64(0)
    x: CPtr = empty_c_void_p()
    p_c_pointer(pointer(_x, i64), x)
    basic_new_stack(x)
    basic_const_pi(x)

main0()

To achieve the following there are few things which need to be addressed

  • We need to replace the originally declared x:S variable by another variable of the form x:CPtr either by completely creating a new variable or by editing the type of the first one. We also need a placeholder variable declared for all initially declared symbolic variables, something of the form _x:i64.
  • Once the above change has been initiated, we know that we need the basic_new_stack for allocating memory to a SymEngine basic variable and hence we need to introduce the basic_new_stack function in the Symbol Table of the Module node.
  • The next step here would be to change the function body of the main0 function and introduce the statements responsible for declaring the basic variable x and allot memory to it.
  • This should be followed by handling the assignment statement through a visit_Assignment function in the replace_symbolic pass . Once we identify the value and the symbolic intrinsic function being used like Symbolicpi or SymbolicAdd , we need to introduce basic_const_pi function or the basic_add function respectively.

I was able to achieve the first 3 points mentioned above and will be addressing the 4th point soon. Hence we currently have the following.

(lf) anutosh491@spbhat68:~/lpython/lpython$ cat examples/expr2.py 
from lpython import S
from sympy import pi

def main0():
    x: S = pi

main0()
(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --show-asr --pass=symbolic examples/expr2.py 
(TranslationUnit
    (SymbolTable
        1
        {
            __main__:
                (Module
                    (SymbolTable
                        2
                        {
                            .....
                            basic_new_stack:
                                (Function
                                    (SymbolTable
                                        6
                                        {
                                            x:
                                                (Variable
                                                    6
                                                    x
                                                    []
                                                    In
                                                    ()
                                                    ()
                                                    Default
                                                    (CPtr)
                                                    ()
                                                    BindC
                                                    Public
                                                    Required
                                                    .true.
                                                )
                                        })
                                    basic_new_stack
                                    (FunctionType
                                        [(CPtr)]
                                        ()
                                        BindC
                                        Interface
                                        "basic_new_stack"
                                        .false.
                                        .false.
                                        .false.
                                        .false.
                                        .false.
                                        []
                                        .false.
                                    )
                                    []
                                    [(Var 6 x)]
                                    []
                                    ()
                                    Public
                                    .false.
                                    .false.
                                    "symengine/cwrapper.h"
                                ),
                            main0:
                                (Function
                                    (SymbolTable
                                        3
                                        {
                                            _x:
                                                (Variable
                                                    3
                                                    _x
                                                    []
                                                    Local
                                                    ()
                                                    ()
                                                    Default
                                                    (Integer 8)
                                                    ()
                                                    Source
                                                    Public
                                                    Required
                                                    .false.
                                                ),
                                            x:
                                                (Variable
                                                    3
                                                    x
                                                    []
                                                    Local
                                                    ()
                                                    ()
                                                    Default
                                                    (CPtr)
                                                    ()
                                                    Source
                                                    Public
                                                    Required
                                                    .false.
                                                )
                                        })
                                    main0
                                    (FunctionType
                                        []
                                        ()
                                        Source
                                        Implementation
                                        ()
                                        .false.
                                        .false.
                                        .false.
                                        .false.
                                        .false.
                                        []
                                        .false.
                                    )
                                    [basic_new_stack]
                                    []
                                    [(=
                                        (Var 3 _x)
                                        (Cast
                                            (IntegerConstant 0 (Integer 4))
                                            IntegerToInteger
                                            (Integer 8)
                                            (IntegerConstant 0 (Integer 8))
                                        )
                                        ()
                                    )
                                    (=
                                        (Var 3 x)
                                        (PointerNullConstant
                                            (CPtr)
                                        )
                                        ()
                                    )
                                    (=
                                        (Var 3 x)
                                        (PointerToCPtr
                                            (GetPointer
                                                (Var 3 _x)
                                                (Pointer
                                                    (Integer 8)
                                                )
                                                ()
                                            )
                                            (CPtr)
                                            ()
                                        )
                                        ()
                                    )
                                    (SubroutineCall
                                        2 basic_new_stack
                                        2 basic_new_stack
                                        [((Var 3 x))]
                                        ()
                                    )
                                    (=
                                        (Var 3 x)
                                        (IntrinsicFunction
                                            SymbolicPi
                                            []
                                            0
                                            (SymbolicExpression)
                                            ()
                                        )
                                        ()
                                    )]
                                    ()
                                    Public
                                    .false.
                                    .false.
                                    ()
                                )
                        })
                    __main__
                    []
                    .false.
                    .false.
                )

As y’all can see, after addressing the 4th point, block 1 would be converted to block 2.

# block 1
        (=
            (Var 3 x)
            (IntrinsicFunction
                SymbolicPi
                []
                0
                (SymbolicExpression)
                ()
            )
            ()
        )

# block 2
        (SubroutineCall
            2 basic_const_pi
            ()
            [((Var 12 x))]
            ()
        )

Once, the above functionality has been added, the symbolic ASR pass should be in a good position and after some testing and refactoring the first Pull Request should be ready. I would like to thank Thirumalai Shaktivel, a fellow experienced contributor who has been helping me extensively with all my doubts and helping me out whenever I face any blocker.

Talking about my plans for the next week.

  • Have a concrete implementation for the pass we discussed in this blog.

Thank You for going through the blog. I hope you like it. Stick around for what’s next to come. Moving into Week 11!

Address

Mumbai, Maharashtra, India