From aad9410dbbb8514cc1684eca0431666535480147 Mon Sep 17 00:00:00 2001 From: Dominic Poerio Date: Sat, 29 May 2021 14:59:50 -0400 Subject: [PATCH] Update subroutine methods to match functions --- integration_tests/CMakeLists.txt | 1 + integration_tests/return_03.f90 | 17 +++++++ src/lfortran/codegen/asr_to_llvm.cpp | 41 +++++++++++----- tests/reference/llvm-return_03-fd5ee01.json | 13 +++++ tests/reference/llvm-return_03-fd5ee01.stdout | 48 +++++++++++++++++++ tests/tests.toml | 4 ++ 6 files changed, 113 insertions(+), 11 deletions(-) create mode 100644 integration_tests/return_03.f90 create mode 100644 tests/reference/llvm-return_03-fd5ee01.json create mode 100644 tests/reference/llvm-return_03-fd5ee01.stdout diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 2e97464aab..84992c177a 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -279,3 +279,4 @@ RUN(NAME recursion_01 LABELS gfortran llvm) RUN(NAME return_01 LABELS gfortran llvm) RUN(NAME return_02 LABELS gfortran llvm) +RUN(NAME return_03 LABELS gfortran llvm) diff --git a/integration_tests/return_03.f90 b/integration_tests/return_03.f90 new file mode 100644 index 0000000000..fdcc801427 --- /dev/null +++ b/integration_tests/return_03.f90 @@ -0,0 +1,17 @@ +program main + integer :: main_out = 999 + call main1(main_out) + print *, "main1 called" + contains + subroutine main1(out_var) + integer :: out_var + integer :: i = 10 + if (i .GT. 5) then + out_var = i + print *, "early return" + return + end if + print *, "normal return" + out_var = i + end subroutine main1 +end program diff --git a/src/lfortran/codegen/asr_to_llvm.cpp b/src/lfortran/codegen/asr_to_llvm.cpp index 1e92dec5ae..18cd9f6d24 100644 --- a/src/lfortran/codegen/asr_to_llvm.cpp +++ b/src/lfortran/codegen/asr_to_llvm.cpp @@ -1318,27 +1318,19 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor void generate_subroutine(const ASR::Subroutine_t &x){ - uint32_t h = get_hash((ASR::asr_t*)&x); bool interactive = (x.m_abi == ASR::abiType::Interactive); if (x.m_deftype == ASR::deftypeType::Implementation) { if (interactive) return; if (!prototype_only) { - llvm::Function* F = llvm_symtab_fn[h]; - llvm::BasicBlock *BB = llvm::BasicBlock::Create(context, - ".entry", F); - builder->SetInsertPoint(BB); - - declare_args(x, *F); - - declare_local_vars(x); + define_subroutine_entry(x); for (size_t i=0; ivisit_stmt(*x.m_body[i]); } - builder->CreateRetVoid(); + define_subroutine_exit(x); } } } @@ -1414,7 +1406,20 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor declare_local_vars(x); } - inline void define_function_exit(const ASR::Function_t& x) { + + inline void define_subroutine_entry(const ASR::Subroutine_t& x) { + uint32_t h = get_hash((ASR::asr_t*)&x); + llvm::Function* F = llvm_symtab_fn[h]; + llvm::BasicBlock *BB = llvm::BasicBlock::Create(context, + ".entry", F); + builder->SetInsertPoint(BB); + + declare_args(x, *F); + + declare_local_vars(x); + } + + inline void define_function_exit(const ASR::Function_t& x) { if (early_return) { builder->CreateBr(if_return); } @@ -1433,6 +1438,20 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor builder->CreateRet(ret_val2); } + + inline void define_subroutine_exit(const ASR::Subroutine_t& /*x*/) { + if (early_return) { + builder->CreateBr(if_return); + } + + if (early_return) { + builder->SetInsertPoint(if_return); + early_return = false; + } + + builder->CreateRetVoid(); + } + void generate_function(const ASR::Function_t &x){ bool interactive = (x.m_abi == ASR::abiType::Interactive); if (x.m_deftype == ASR::deftypeType::Implementation ) { diff --git a/tests/reference/llvm-return_03-fd5ee01.json b/tests/reference/llvm-return_03-fd5ee01.json new file mode 100644 index 0000000000..5e0d738303 --- /dev/null +++ b/tests/reference/llvm-return_03-fd5ee01.json @@ -0,0 +1,13 @@ +{ + "basename": "llvm-return_03-fd5ee01", + "cmd": "lfortran --show-llvm {infile} -o {outfile}", + "infile": "tests/../integration_tests/return_03.f90", + "infile_hash": "7d4898b23c807b105723b597c037469040fba56ee6c9891c93947d14", + "outfile": null, + "outfile_hash": null, + "stdout": "llvm-return_03-fd5ee01.stdout", + "stdout_hash": "f5de0548d6690b15f07d47f1b94e6af28ecf80b55404c37a4ea9f4e5", + "stderr": null, + "stderr_hash": null, + "returncode": 0 +} \ No newline at end of file diff --git a/tests/reference/llvm-return_03-fd5ee01.stdout b/tests/reference/llvm-return_03-fd5ee01.stdout new file mode 100644 index 0000000000..395b542c66 --- /dev/null +++ b/tests/reference/llvm-return_03-fd5ee01.stdout @@ -0,0 +1,48 @@ +; ModuleID = 'LFortran' +source_filename = "LFortran" + +@0 = private unnamed_addr constant [13 x i8] c"early return\00", align 1 +@1 = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 +@2 = private unnamed_addr constant [14 x i8] c"normal return\00", align 1 +@3 = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 +@4 = private unnamed_addr constant [13 x i8] c"main1 called\00", align 1 +@5 = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 + +define void @main1(i32* %out_var) { +.entry: + %i = alloca i32, align 4 + store i32 10, i32* %i, align 4 + %0 = load i32, i32* %i, align 4 + %1 = icmp sgt i32 %0, 5 + br i1 %1, label %then, label %else + +then: ; preds = %.entry + %2 = load i32, i32* %i, align 4 + store i32 %2, i32* %out_var, align 4 + call void (i8*, ...) @_lfortran_printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @1, i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @0, i32 0, i32 0)) + br label %return + +return: ; preds = %ifcont, %then + ret void + +else: ; preds = %.entry + br label %ifcont + +ifcont: ; preds = %else + call void (i8*, ...) @_lfortran_printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @3, i32 0, i32 0), i8* getelementptr inbounds ([14 x i8], [14 x i8]* @2, i32 0, i32 0)) + %3 = load i32, i32* %i, align 4 + store i32 %3, i32* %out_var, align 4 + br label %return +} + +declare void @_lfortran_printf(i8*, ...) + +define i32 @main() { +.entry: + %main_out = alloca i32, align 4 + store i32 999, i32* %main_out, align 4 + call void @main1(i32* %main_out) + call void (i8*, ...) @_lfortran_printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @5, i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @4, i32 0, i32 0)) + ret i32 0 +} + diff --git a/tests/tests.toml b/tests/tests.toml index 22060c0dcd..c169f46f41 100644 --- a/tests/tests.toml +++ b/tests/tests.toml @@ -1082,6 +1082,10 @@ llvm = true filename = "../integration_tests/return_02.f90" llvm = true +[[test]] +filename = "../integration_tests/return_03.f90" +llvm = true + [[test]] filename = "../integration_tests/modules_13.f90" llvm = true