lfortran / lfortran

Official main repository for LFortran
https://lfortran.org/
Other
962 stars 155 forks source link

Faulty LLVM handover #648

Open konradha opened 2 years ago

konradha commented 2 years ago

When trying to compile scipy/stats/statlib/swilk.f from current main, LFortran yields an empty object file -- upon inspection and running lfortran --implicit-typing --fixed-form --show-llvm --indent ../../scipy/scipy/stats/statlib/swilk.f we see

lfortran: /opt/anaconda3/envs/lf/include/llvm/IR/Instructions.h:897: llvm::Type* llvm::checkGEPType(llvm::Type*): Assertion `Ty && "Invalid GetElementPtrInst indices for type!"' failed.
Traceback (most recent call last):
  Binary file "/home/konrad/code/forks/lfortran/src/bin/lfortran", in _start()
  File "./csu/../csu/libc-start.c", line 392, in __libc_start_main_impl()
  File "./csu/../sysdeps/nptl/libc_start_call_main.h", line 58, in __libc_start_call_main()
  File "/home/konrad/code/forks/lfortran/src/bin/lfortran.cpp", line 1651, in ??
    return emit_llvm(arg_file, lfortran_pass_manager,
  File "/home/konrad/code/forks/lfortran/src/bin/lfortran.cpp", line 663, in ??
    = fe.get_llvm(input, lm, pass_manager, diagnostics);
  File "/home/konrad/code/forks/lfortran/src/lfortran/fortran_evaluator.cpp", line 264, in LFortran::FortranEvaluator::get_llvm(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, LFortran::LocationManager&, LCompilers::PassManager&, LFortran::diag::Diagnostics&)
    Result<std::unique_ptr<LLVMModule>> res = get_llvm2(code, lm, pass_manager, diagnostics);
  File "/home/konrad/code/forks/lfortran/src/lfortran/fortran_evaluator.cpp", line 285, in LFortran::FortranEvaluator::get_llvm2(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, LFortran::LocationManager&, LCompilers::PassManager&, LFortran::diag::Diagnostics&)
    Result<std::unique_ptr<LLVMModule>> res = get_llvm3(*asr.result, pass_manager, diagnostics);
  File "/home/konrad/code/forks/lfortran/src/lfortran/fortran_evaluator.cpp", line 318, in LFortran::FortranEvaluator::get_llvm3(LFortran::ASR::TranslationUnit_t&, LCompilers::PassManager&, LFortran::diag::Diagnostics&)
    compiler_options.platform, run_fn);
  File "/home/konrad/code/forks/lfortran/src/libasr/codegen/asr_to_llvm.cpp", line 5355, in LFortran::asr_to_llvm(LFortran::ASR::TranslationUnit_t&, LFortran::diag::Diagnostics&, llvm::LLVMContext&, Allocator&, LCompilers::PassManager&, LFortran::Platform, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
    v.visit_asr((ASR::asr_t&)asr);
  File "/home/konrad/code/forks/lfortran/src/libasr/../libasr/asr.h", line 3728, in LFortran::ASR::BaseVisitor<LFortran::ASRToLLVMVisitor>::visit_asr(LFortran::ASR::asr_t const&)
    void visit_asr(const asr_t &b) { visit_asr_t(b, self()); }
  File "/home/konrad/code/forks/lfortran/src/libasr/../libasr/asr.h", line 3706, in ??
    case asrType::unit: { v.visit_unit((const unit_t &)x); return; }
  File "/home/konrad/code/forks/lfortran/src/libasr/../libasr/asr.h", line 3729, in LFortran::ASR::BaseVisitor<LFortran::ASRToLLVMVisitor>::visit_unit(LFortran::ASR::unit_t const&)
    void visit_unit(const unit_t &b) { visit_unit_t(b, self()); }
  File "/home/konrad/code/forks/lfortran/src/libasr/../libasr/asr.h", line 3506, in ??
    case unitType::TranslationUnit: { v.visit_TranslationUnit((const TranslationUnit_t &)x); return; }
  File "/home/konrad/code/forks/lfortran/src/libasr/codegen/asr_to_llvm.cpp", line 1058, in LFortran::ASRToLLVMVisitor::visit_TranslationUnit(LFortran::ASR::TranslationUnit_t const&)
    visit_symbol(*item.second);
  File "/home/konrad/code/forks/lfortran/src/libasr/../libasr/asr.h", line 3731, in LFortran::ASR::BaseVisitor<LFortran::ASRToLLVMVisitor>::visit_symbol(LFortran::ASR::symbol_t const&)
    void visit_symbol(const symbol_t &b) { visit_symbol_t(b, self()); }
  File "/home/konrad/code/forks/lfortran/src/libasr/../libasr/asr.h", line 3516, in ??
    case symbolType::Function: { v.visit_Function((const Function_t &)x); return; }
  File "/home/konrad/code/forks/lfortran/src/libasr/codegen/asr_to_llvm.cpp", line 2407, in LFortran::ASRToLLVMVisitor::visit_Function(LFortran::ASR::Function_t const&)
    generate_function(x);
  File "/home/konrad/code/forks/lfortran/src/libasr/codegen/asr_to_llvm.cpp", line 2662, in LFortran::ASRToLLVMVisitor::generate_function(LFortran::ASR::Function_t const&)
    this->visit_stmt(*x.m_body[i]);
  File "/home/konrad/code/forks/lfortran/src/libasr/../libasr/asr.h", line 3744, in LFortran::ASR::BaseVisitor<LFortran::ASRToLLVMVisitor>::visit_stmt(LFortran::ASR::stmt_t const&)
    void visit_stmt(const stmt_t &b) { visit_stmt_t(b, self()); }
  File "/home/konrad/code/forks/lfortran/src/libasr/../libasr/asr.h", line 3535, in ??
    case stmtType::Assignment: { v.visit_Assignment((const Assignment_t &)x); return; }
  File "/home/konrad/code/forks/lfortran/src/libasr/codegen/asr_to_llvm.cpp", line 2947, in LFortran::ASRToLLVMVisitor::visit_Assignment(LFortran::ASR::Assignment_t const&)
    this->visit_expr(*x.m_target);
  File "/home/konrad/code/forks/lfortran/src/libasr/../libasr/asr.h", line 3786, in LFortran::ASR::BaseVisitor<LFortran::ASRToLLVMVisitor>::visit_expr(LFortran::ASR::expr_t const&)
    void visit_expr(const expr_t &b) { visit_expr_t(b, self()); }
  File "/home/konrad/code/forks/lfortran/src/libasr/../libasr/asr.h", line 3626, in ??
    case exprType::ArrayItem: { v.visit_ArrayItem((const ArrayItem_t &)x); return; }
  File "/home/konrad/code/forks/lfortran/src/libasr/codegen/asr_to_llvm.cpp", line 1373, in LFortran::ASRToLLVMVisitor::visit_ArrayItem(LFortran::ASR::ArrayItem_t const&)
    tmp = arr_descr->get_single_element(array, indices, x.n_args,
  File "/home/konrad/code/forks/lfortran/src/libasr/codegen/llvm_array_utils.cpp", line 474, in LFortran::LLVMArrUtils::SimpleCMODescriptor::get_single_element(llvm::Value*, std::vector<llvm::Value*, std::allocator<llvm::Value*> >&, int, bool, llvm::Value**)
    idx = cmo_convertor_single_element(array, m_args, n_args, check_for_bounds);
  File "/home/konrad/code/forks/lfortran/src/libasr/codegen/llvm_array_utils.cpp", line 423, in LFortran::LLVMArrUtils::SimpleCMODescriptor::cmo_convertor_single_element(llvm::Value*, std::vector<llvm::Value*, std::allocator<llvm::Value*> >&, int, bool)
    llvm::Value* dim_des_arr_ptr = LLVM::CreateLoad(*builder, llvm_utils->create_gep(arr, 2));
  File "/home/konrad/code/forks/lfortran/src/libasr/codegen/llvm_utils.cpp", line 82, in LFortran::LLVMUtils::create_gep(llvm::Value*, int)
    return LLVM::CreateGEP(*builder, ds, idx_vec);
  File "/home/konrad/code/forks/lfortran/src/libasr/codegen/llvm_utils.cpp", line 25, in LFortran::LLVM::CreateGEP(llvm::IRBuilder<llvm::ConstantFolder, llvm::IRBuilderDefaultInserter>&, llvm::Value*, std::vector<llvm::Value*, std::allocator<llvm::Value*> >&)
    return builder.CreateGEP(t2, x, idx);
  File "/opt/anaconda3/envs/lf/include/llvm/IR/IRBuilder.h", line 1773, in llvm::IRBuilderBase::CreateGEP(llvm::Type*, llvm::Value*, llvm::ArrayRef<llvm::Value*>, llvm::Twine const&)
    return Insert(GetElementPtrInst::Create(Ty, Ptr, IdxList), Name);
  File "/opt/anaconda3/envs/lf/include/llvm/IR/Instructions.h", line 943, in llvm::GetElementPtrInst::Create(llvm::Type*, llvm::Value*, llvm::ArrayRef<llvm::Value*>, llvm::Twine const&, llvm::Instruction*)
    NameStr, InsertBefore);
  File "/opt/anaconda3/envs/lf/include/llvm/IR/Instructions.h", line 1147, in llvm::GetElementPtrInst::GetElementPtrInst(llvm::Type*, llvm::Value*, llvm::ArrayRef<llvm::Value*>, unsigned int, llvm::Twine const&, llvm::Instruction*)
    ResultElementType(getIndexedType(PointeeType, IdxList)) {
  File "/opt/anaconda3/envs/lf/include/llvm/IR/Instructions.h", line 1074, in llvm::GetElementPtrInst::getGEPReturnType(llvm::Type*, llvm::Value*, llvm::ArrayRef<llvm::Value*>)
    Type *PtrTy = PointerType::get(checkGEPType(getIndexedType(ElTy, IdxList)),
  File "/opt/anaconda3/envs/lf/include/llvm/IR/Instructions.h", line 897, in llvm::checkGEPType(llvm::Type*)
    assert(Ty && "Invalid GetElementPtrInst indices for type!");
  File "./assert/assert.c", line 101, in __GI___assert_fail()
  File "./assert/assert.c", line 92, in __assert_fail_base()
  File "./stdlib/abort.c", line 79, in __GI_abort()
  File "./signal/../sysdeps/posix/raise.c", line 26, in __GI_raise()
  File "./nptl/pthread_kill.c", line 43, in __pthread_kill_implementation()
  Binary file "/lib/x86_64-linux-gnu/libc.so.6", in __GI___sigaction()
Abort: Signal SIGABRT (abort) received

and core gets dumped.

konradha commented 2 years ago

Some notes:

The problematic function seems to be CreateGEP in libasr/codegen/llvm_utils.cpp . There seems to be a bug in how a double precision variable is initialized that is named identical to an intrinsic:

(value)     %zexp = alloca double, align 8
(wrapped) i32 0 i32 2 

(zexp is an intrinsic; ZEXP in swilk.f is a double precision variable; the "wrapped" value are the content of the idx container in CreateGEP).

konradha commented 2 years ago

So here's the minimal reproducer called t_llvmir_double.f:

      program main
      double precision zexp,z
      zexp(z) = dexp(z)
      end program

gfortran -fdump-parse-tree t_llvmir_double.f yields

Namespace: A-H: (REAL 4) I-N: (INTEGER 4) O-Z: (REAL 4)
procedure name = main
  symtree: 'dexp'        || symbol: 'dexp'         
    type spec : (REAL 4)
    attributes: (PROCEDURE INTRINSIC-PROC  FUNCTION IMPLICIT-TYPE ARRAY-OUTER-DEPENDENCY)
    result: dexp
  symtree: 'main'        || symbol: 'main'         
    type spec : (UNKNOWN 0)
    attributes: (PROGRAM PUBLIC  SUBROUTINE IS-MAIN-PROGRAM)
  symtree: 'z'           || symbol: 'z'            
    type spec : (REAL 8)
    attributes: (VARIABLE )
  symtree: 'zexp'        || symbol: 'zexp'         
    type spec : (REAL 8)
    attributes: (PROCEDURE STATEMENT-PROC  FUNCTION)
    value: __exp_r8[[((main:z))]]
    Formal arglist: z

  code:

and LFortran's corresponding ASR looks like this:

(TranslationUnit 
    (SymbolTable
        1
        {
            iso_c_binding:
                (IntrinsicModule lfortran_intrinsic_iso_c_binding), 
            iso_fortran_env:
                (IntrinsicModule lfortran_intrinsic_iso_fortran_env), 
            lfortran_intrinsic_builtin:
                (IntrinsicModule lfortran_intrinsic_builtin), 
            lfortran_intrinsic_math:
                (IntrinsicModule lfortran_intrinsic_math), 
            main:
                (Program 
                    (SymbolTable
                        2
                        {
                            dexp:
                                (ExternalSymbol 
                                    2 
                                    dexp 
                                    4 dexp 
                                    lfortran_intrinsic_math 
                                    [] 
                                    dexp 
                                    Private
                                ), 
                            z:
                                (Variable 
                                    2 
                                    z 
                                    Local 
                                    () 
                                    () 
                                    Default 
                                    (Real 8 []) 
                                    Source 
                                    Public 
                                    Required 
                                    .false.
                                ), 
                            zexp:
                                (Variable 
                                    2 
                                    zexp 
                                    Local 
                                    () 
                                    () 
                                    Default 
                                    (Real 8 []) 
                                    Source 
                                    Public 
                                    Required 
                                    .false.
                                )

                        }) 
                    main 
                    [] 
                    [(= 
                        (ArrayItem 
                            (Var 2 zexp) 
                            [(() 
                            (Var 2 z) 
                            ())] 
                            (Real 8 []) 
                            ()
                        ) 
                        (FunctionCall 
                            2 dexp 
                            () 
                            [((Var 2 z))] 
                            (Real 8 []) 
                            () 
                            ()
                        ) 
                        ()
                    )]
                )

        }) 
    []
)
certik commented 2 years ago

I think this is an example of a statement function, which we need to implement according to https://github.com/lfortran/lfortran/issues/814.