Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace BlockCall symbol with the one in current scope #1688

Merged

Conversation

Thirumalai-Shaktivel
Copy link
Collaborator

Fixes: #1668

@Thirumalai-Shaktivel
Copy link
Collaborator Author

Thirumalai-Shaktivel commented Apr 9, 2023

The issue was in the inline_function_calls pass:

def func() -> i32:
     return 30

def test() -> i32:
    temp: i32 = func()
    return temp

x : i32 
x = test()
print(x)
(TranslationUnit
    (SymbolTable
        1
        {
            _global_symbols:
                (Module
                    (SymbolTable
                        6
                        {
                            _lpython_main_program:
                                (Function
                                    (SymbolTable
                                        5
                                        {
                                            _lpython_return_variable_func_test:
                                                (Variable
                                                    5
                                                    _lpython_return_variable_func_test
                                                    []
                                                    Local
                                                    ()
                                                    ()
                                                    Default
                                                    (Integer 4 [])
                                                    Source
                                                    Public
                                                    Required
                                                    .false.
                                                ),
                                            _lpython_return_variable_test:
                                                (Variable
                                                    5
                                                    _lpython_return_variable_test
                                                    []
                                                    Local
                                                    ()
                                                    ()
                                                    Default
                                                    (Integer 4 [])
                                                    Source
                                                    Public
                                                    Required
                                                    .false.
                                                ),
                                            temp_test:
                                                (Variable
                                                    5
                                                    temp_test
                                                    []
                                                    Local
                                                    ()
                                                    ()
                                                    Default
                                                    (Integer 4 [])
                                                    Source
                                                    Public
                                                    Required
                                                    .false.
                                                ),
                                            ~empty_block:
                                                (Block
                                                    (SymbolTable
                                                        8
                                                        {
                                                            
                                                        })
                                                    ~empty_block
                                                    []
                                                )
                                        })
                                    _lpython_main_program
                                    (FunctionType
                                        []
                                        ()
                                        Source
                                        Implementation
                                        ()
                                        .false.
                                        .false.
                                        .false.
                                        .false.
                                        .false.
                                        []
                                        []
                                        .false.
                                    )
                                    []
                                    []
                                    [(=
                                        (Var 5 _lpython_return_variable_func_test)
                                        (IntegerConstant 30 (Integer 4 []))
                                        ()
                                    )
                                    (GoTo
                                        1
                                        __1
                                    )
                                    (BlockCall
                                        1
                                        3 ~empty_block                ! < ------------- Here is the issue
                                    )
                                    (=
                                        (Var 5 temp_test)
                                        (Var 5 _lpython_return_variable_func_test)
                                        ()
                                    )
                                    (=
                                        (Var 5 _lpython_return_variable_test)
                                        (Var 5 temp_test)
                                        ()
                                    )
                                    (GoTo
                                        2
                                        __2
                                    )
                                    (BlockCall
                                        2
                                        5 ~empty_block
                                    )
                                    (=
                                        (Var 6 x)
                                        (Var 5 _lpython_return_variable_test)
                                        ()
                                    )
                                    (Print
                                        ()
                                        [(Var 6 x)]
                                        ()
                                        ()
                                    )]
                                    ()
                                    Public
                                    .false.
                                    .false.
                                ),
                            func:
                                (Function
                                    (SymbolTable
                                        2
                                        {
                                            _lpython_return_variable:
                                                (Variable
                                                    2
                                                    _lpython_return_variable
                                                    []
                                                    ReturnVar
                                                    ()
                                                    ()
                                                    Default
                                                    (Integer 4 [])
                                                    Source
                                                    Public
                                                    Required
                                                    .false.
                                                )
                                        })
                                    func
                                    (FunctionType
                                        []
                                        (Integer 4 [])
                                        Source
                                        Implementation
                                        ()
                                        .false.
                                        .false.
                                        .false.
                                        .false.
                                        .false.
                                        []
                                        []
                                        .false.
                                    )
                                    []
                                    []
                                    [(=
                                        (Var 2 _lpython_return_variable)
                                        (IntegerConstant 30 (Integer 4 []))
                                        ()
                                    )
                                    (Return)]
                                    (Var 2 _lpython_return_variable)
                                    Public
                                    .false.
                                    .false.
                                ),
                            test:
                                (Function
                                    (SymbolTable
                                        3
                                        {
                                            _lpython_return_variable:
                                                (Variable
                                                    3
                                                    _lpython_return_variable
                                                    []
                                                    ReturnVar
                                                    ()
                                                    ()
                                                    Default
                                                    (Integer 4 [])
                                                    Source
                                                    Public
                                                    Required
                                                    .false.
                                                ),
                                            _lpython_return_variable_func:
                                                (Variable
                                                    3
                                                    _lpython_return_variable_func
                                                    []
                                                    Local
                                                    ()
                                                    ()
                                                    Default
                                                    (Integer 4 [])
                                                    Source
                                                    Public
                                                    Required
                                                    .false.
                                                ),
                                            temp:
                                                (Variable
                                                    3
                                                    temp
                                                    []
                                                    Local
                                                    ()
                                                    ()
                                                    Default
                                                    (Integer 4 [])
                                                    Source
                                                    Public
                                                    Required
                                                    .false.
                                                ),
                                            ~empty_block:
                                                (Block
                                                    (SymbolTable
                                                        7
                                                        {
                                                            
                                                        })
                                                    ~empty_block
                                                    []
                                                )
                                        })
                                    test
                                    (FunctionType
                                        []
                                        (Integer 4 [])
                                        Source
                                        Implementation
                                        ()
                                        .false.
                                        .false.
                                        .false.
                                        .false.
                                        .false.
                                        []
                                        []
                                        .false.
                                    )
                                    []
                                    []
                                    [(=
                                        (Var 3 _lpython_return_variable_func)
                                        (IntegerConstant 30 (Integer 4 []))
                                        ()
                                    )
                                    (GoTo
                                        1
                                        __1
                                    )
                                    (BlockCall
                                        1
                                        3 ~empty_block
                                    )
                                    (=
                                        (Var 3 temp)
                                        (Var 3 _lpython_return_variable_func)
                                        ()
                                    )
                                    (=
                                        (Var 3 _lpython_return_variable)
                                        (Var 3 temp)
                                        ()
                                    )
                                    (Return)]
                                    (Var 3 _lpython_return_variable)
                                    Public
                                    .false.
                                    .false.
                                ),
                            x:
                                (Variable
                                    6
                                    x
                                    []
                                    Local
                                    ()
                                    ()
                                    Default
                                    (Integer 4 [])
                                    Source
                                    Public
                                    Required
                                    .false.
                                )
                        })
                    _global_symbols
                    []
                    .false.
                    .false.
                ),
            main_program:
                (Program
                    (SymbolTable
                        4
                        {
                            _lpython_main_program:
                                (ExternalSymbol
                                    4
                                    _lpython_main_program
                                    6 _lpython_main_program
                                    _global_symbols
                                    []
                                    _lpython_main_program
                                    Public
                                )
                        })
                    main_program
                    [_global_symbols]
                    [(SubroutineCall
                        4 _lpython_main_program
                        ()
                        []
                        ()
                    )]
                )
        })
    []
)

Here the statements from the func function were copied into the test() function (which included the BlockCall and Goto statements used by the previous function inline.)

@gptsarthak
Copy link
Contributor

Thank you. Please check if this also fixes #1677

@certik
Copy link
Contributor

certik commented Apr 9, 2023

We need to be careful here, I think you want to duplicate it, don't you?

@Thirumalai-Shaktivel
Copy link
Collaborator Author

Thirumalai-Shaktivel commented Apr 9, 2023

I thought the BlockCall and Goto is specific to one function.

If we duplicate it, should we create an ExternalSymbol for the Block?

...
_lpython_main_program:
    (Function
        (SymbolTable
            5
            {
                ...
                (BlockCall
                    1
                    3 ~empty_block     ! < ---- This is created in another function symtab
                )
                ...
                (BlockCall
                    2
                    5 ~empty_block
                )
...

@certik
Copy link
Contributor

certik commented Apr 9, 2023

I don't know. I agree that goto is specific to a function. But removing it seems to make the code incorrect. So we need to figure out how to solve this.

@Thirumalai-Shaktivel Thirumalai-Shaktivel marked this pull request as draft April 10, 2023 03:53
@czgdp1807
Copy link
Collaborator

Correct. We need to duplicate it and then edit BlockCall and Goto statements in the duplicated body. It should be doable and not that hard AFAICT as of now.

@Thirumalai-Shaktivel
Copy link
Collaborator Author

I'm not sure if this new change was a correct fix.

What does the Block symbol store?
What is BlockCall used for?

std::string block_name = ASRUtils::symbol_name(bc->m_m);
LCOMPILERS_ASSERT(current_scope->get_symbol(block_name))
bc->m_m = current_scope->get_symbol(block_name);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of doing the edit here, you need to follow the same pattern as in visit_Var (add visit_BlockCall and then edit its symbol, if the code is exactly the same then add a macro to generate code for each method).

void visit_Var(const ASR::Var_t& x) {
ASR::Var_t& xx = const_cast<ASR::Var_t&>(x);
std::string x_var_name = std::string(ASRUtils::symbol_name(x.m_v));
// If anything is not local to a function being inlined
// then do not inline the function by setting
// fixed_duplicated_expr_stmt to false.
// To be supported later.
if( current_routine_scope &&
current_routine_scope->get_symbol(x_var_name) == nullptr ) {
fixed_duplicated_expr_stmt = false;
return ;
}
if( x.m_v->type == ASR::symbolType::Variable ) {
ASR::Variable_t* x_var = ASR::down_cast<ASR::Variable_t>(x.m_v);
if( arg2value.find(x_var_name) != arg2value.end() ) {
x_var = ASR::down_cast<ASR::Variable_t>(arg2value[x_var_name]);
if( current_scope->get_symbol(std::string(x_var->m_name)) != nullptr ) {
xx.m_v = arg2value[x_var_name];
}
x_var = ASR::down_cast<ASR::Variable_t>(x.m_v);
}
} else {
fixed_duplicated_expr_stmt = false;
}
}

@certik
Copy link
Contributor

certik commented Apr 12, 2023

I think the bug is in the inline pass. It must create a unique name for the ~empty_block block.

@certik
Copy link
Contributor

certik commented Apr 12, 2023

Rather, it looks like the issue is that the Block symbol points to the old location and BlockCall is calling it from the old location, so one gets the following error message:

ASR verify pass error: ASR verify: Block ~empty_block should resolve in current scope.

caused by:

    void visit_BlockCall(const BlockCall_t& x) {
        require(x.m_m != nullptr, "Block call made to inexisting block");
        require(symtab_in_scope(current_symtab, x.m_m),
            "Block " + std::string(ASRUtils::symbol_name(x.m_m)) +
            " should resolve in current scope.");
...

So it looks like the nested function pass needs to copy over the Block symbol (duplicate).

@czgdp1807
Copy link
Collaborator

czgdp1807 commented Apr 12, 2023

#1688 (comment) is the correct approach. If one is not doing it fully then ASR verify pass errors will always be there. Also I think editing is not happening correctly for BlockCall. https://github.com/lcompilers/lpython/pull/1688/files#r1161810225 isn’t addressed yet.

@Thirumalai-Shaktivel
Copy link
Collaborator Author

This seems to fix the issue.
@czgdp1807 Please review this carefully; I removed some assignments that were not used. If you feel like reverting something, let me know, and I will make the required changes.

@Thirumalai-Shaktivel Thirumalai-Shaktivel marked this pull request as ready for review April 14, 2023 06:38
@czgdp1807
Copy link
Collaborator

Please review this carefully; I removed some assignments that were not used. If you feel like reverting something, let me know, and I will make the required changes.

If you are not sure then apply changes to LFortran and see if they work there. If they do then we are good. More testing should ensure that we are not facing any bugs.

@czgdp1807
Copy link
Collaborator

Also, I think we should have a llvm-fast option in integration_tests/CMakeLists.txt. We should enable it in all the tests possible to make sure that our optimisation passes are also working as expected all the times.

@czgdp1807 czgdp1807 marked this pull request as draft April 14, 2023 13:13
@certik
Copy link
Contributor

certik commented Apr 14, 2023

Yes, we need --fast testing in both LFortran and LPython for all llvm tests. I created an issue for this at lfortran/lfortran#1560.

@Thirumalai-Shaktivel
Copy link
Collaborator Author

LFortran PR: lfortran/lfortran#1566

@czgdp1807 czgdp1807 marked this pull request as ready for review April 17, 2023 16:56
@czgdp1807 czgdp1807 changed the title Skip duplicating of BlockCall and Goto nodes in inline_function_calls Replace BlockCall symbol with the one in current scope Apr 17, 2023
@Thirumalai-Shaktivel Thirumalai-Shaktivel enabled auto-merge (squash) April 18, 2023 10:46
@Thirumalai-Shaktivel Thirumalai-Shaktivel merged commit 90be4b0 into lcompilers:main Apr 18, 2023
@Thirumalai-Shaktivel Thirumalai-Shaktivel deleted the inline_func branch May 4, 2023 08:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Error : Verify Failed , when using --fast
4 participants