llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.3k stars 11.68k forks source link

[flang][ICE] Unexpected interaction between two subroutines #97325

Closed pawosm-arm closed 2 weeks ago

pawosm-arm commented 3 months ago

Hello,

I've found a piece of Fortran code which exposes a puzzling behavior of the flang-new compiler:

MODULE minimal

  USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_ptr, c_null_ptr, c_size_t

  INTERFACE
    FUNCTION c_malloc(size) BIND(C, name = 'malloc')
      IMPORT :: c_ptr, c_size_t
      IMPLICIT NONE
      INTEGER(c_size_t), VALUE :: size
      TYPE(c_ptr) :: c_malloc
    END FUNCTION
  END INTERFACE

CONTAINS
  SUBROUTINE something1(la, ia)
    LOGICAL, INTENT(OUT) :: la(1)
    INTEGER, INTENT(IN) :: ia(1)

    la = ia
  END SUBROUTINE

  SUBROUTINE something2()
    TYPE(c_ptr) :: ptr

    ptr = c_malloc(1)
  END SUBROUTINE
END MODULE

Trying to compile this results in an ICE:

error: loc("minimal.f90":19:5): 'llvm.call' op result type mismatch: '!llvm.ptr' != 'i64'
error: Lowering to LLVM IR failed
flang-new: llvm-project/llvm/lib/IR/Instructions.cpp:2444: void llvm::InsertValueInst::init(llvm::Value*, llvm::Value*, llvm::ArrayRef<unsigned int>, const llvm::Twine&): Assertion `ExtractValueInst::getIndexedType(Agg->getType(), Idxs) == Val->getType() && "Inserted value must match indexed type!"' failed.

It is sufficient to either replace the ptr = c_malloc(1) line with the ptr = c_null_ptr line in the something2 subroutine or remove the la = ia line in the something1 subroutine to make this problem go away. Also, replacing the LOGICAL and INTEGER types in something1 with matching types (e.g. with both LOGICAL or both INTEGER) makes the problem go away.

I've also tried the explicit bbc -> tco -> opt -> llc path, and the ICE did not occur.

llvmbot commented 3 months ago

@llvm/issue-subscribers-flang-ir

Author: Paul Osmialowski (pawosm-arm)

Hello, I've found a piece of Fortran code which exposes a puzzling behavior of the flang-new compiler: ``` MODULE minimal USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_ptr, c_null_ptr, c_size_t INTERFACE FUNCTION c_malloc(size) BIND(C, name = 'malloc') IMPORT :: c_ptr, c_size_t IMPLICIT NONE INTEGER(c_size_t), VALUE :: size TYPE(c_ptr) :: c_malloc END FUNCTION END INTERFACE CONTAINS SUBROUTINE something1(la, ia) LOGICAL, INTENT(OUT) :: la(1) INTEGER, INTENT(IN) :: ia(1) la = ia END SUBROUTINE SUBROUTINE something2() TYPE(c_ptr) :: ptr ptr = c_malloc(1) END SUBROUTINE END MODULE ``` Trying to compile this results in an ICE: ``` error: loc("minimal.f90":19:5): 'llvm.call' op result type mismatch: '!llvm.ptr' != 'i64' error: Lowering to LLVM IR failed flang-new: llvm-project/llvm/lib/IR/Instructions.cpp:2444: void llvm::InsertValueInst::init(llvm::Value*, llvm::Value*, llvm::ArrayRef<unsigned int>, const llvm::Twine&): Assertion `ExtractValueInst::getIndexedType(Agg->getType(), Idxs) == Val->getType() && "Inserted value must match indexed type!"' failed. ``` It is sufficient to either replace the `ptr = c_malloc(1)` line with the `ptr = c_null_ptr` line in the `something2` subroutine or remove the `la = ia` line in the `something1` subroutine to make this problem go away. Also, replacing the `LOGICAL` and `INTEGER` types in `something1` with matching types (e.g. with both `LOGICAL` or both `INTEGER`) makes the problem go away. I've also tried the explicit bbc -> tco -> opt -> llc path, and the ICE did not occur.
llvmbot commented 3 months ago

@llvm/issue-subscribers-bug

Author: Paul Osmialowski (pawosm-arm)

Hello, I've found a piece of Fortran code which exposes a puzzling behavior of the flang-new compiler: ``` MODULE minimal USE, INTRINSIC :: ISO_C_BINDING, ONLY: c_ptr, c_null_ptr, c_size_t INTERFACE FUNCTION c_malloc(size) BIND(C, name = 'malloc') IMPORT :: c_ptr, c_size_t IMPLICIT NONE INTEGER(c_size_t), VALUE :: size TYPE(c_ptr) :: c_malloc END FUNCTION END INTERFACE CONTAINS SUBROUTINE something1(la, ia) LOGICAL, INTENT(OUT) :: la(1) INTEGER, INTENT(IN) :: ia(1) la = ia END SUBROUTINE SUBROUTINE something2() TYPE(c_ptr) :: ptr ptr = c_malloc(1) END SUBROUTINE END MODULE ``` Trying to compile this results in an ICE: ``` error: loc("minimal.f90":19:5): 'llvm.call' op result type mismatch: '!llvm.ptr' != 'i64' error: Lowering to LLVM IR failed flang-new: llvm-project/llvm/lib/IR/Instructions.cpp:2444: void llvm::InsertValueInst::init(llvm::Value*, llvm::Value*, llvm::ArrayRef<unsigned int>, const llvm::Twine&): Assertion `ExtractValueInst::getIndexedType(Agg->getType(), Idxs) == Val->getType() && "Inserted value must match indexed type!"' failed. ``` It is sufficient to either replace the `ptr = c_malloc(1)` line with the `ptr = c_null_ptr` line in the `something2` subroutine or remove the `la = ia` line in the `something1` subroutine to make this problem go away. Also, replacing the `LOGICAL` and `INTEGER` types in `something1` with matching types (e.g. with both `LOGICAL` or both `INTEGER`) makes the problem go away. I've also tried the explicit bbc -> tco -> opt -> llc path, and the ICE did not occur.
pawosm-arm commented 3 months ago

I've tried this with gfortran, but it's very explicit regarding integer types, so it needed a slight change in the something2 subroutine:

  SUBROUTINE something2()
    TYPE(c_ptr) :: ptr
    INTEGER(c_size_t), PARAMETER :: size = 1

    ptr = c_malloc(size)
  END SUBROUTINE

Nevertheless, this slight change does not prevent the ICE in flang-new, while gfortran is able to compile the entire module.

pawosm-arm commented 3 months ago

Turned out, tco works with -O2 by default. I've tried to compile this code with flang-new -O2 and it worked!

Leporacanthicus commented 3 months ago

Turned out, tco works with -O2 by default. I've tried to compile this code with flang-new -O2 and it worked!

Worked as in "compiles to something that doesn't ICE" - does it actually make sense? And does it fail with -O1 in tco?

pawosm-arm commented 3 months ago

Sadly, -O2 has been hardcoded https://github.com/llvm/llvm-project/blob/5ee53d417f41e8f452255ded1ff6a522afe17f08/flang/tools/tco/tco.cpp#L136

Leporacanthicus commented 3 months ago

Sadly, -O2 has been hardcoded

https://github.com/llvm/llvm-project/blob/5ee53d417f41e8f452255ded1ff6a522afe17f08/flang/tools/tco/tco.cpp#L136

Oh, that's not useful... I wonder if we should make a change - but I guess it's more important to figure out why it fails in -O1 (which I think is the default in flang-new)

jeanPerier commented 3 months ago

The issue may be exposed by O2, but this is not related. You can crash with flang-new -c [edit: regardless of -O levels] if you add the following to your example:

  subroutine test(x, y)
    real :: x(:), y(:)
    call bar(x+y)
  end subroutine

We should change the way TYPE(C_PTR) results are handled in FIR. The AbstractResult pass is rewriting them here to integer results, which is "OK" if this hits the assembly stage without meeting a conflicting usage. But malloc is inserted with the correct signature when lowering fir.allocmem (and probably other things), which conflicts.

edit: The -O difference probably comes from the fact that fir.allocmem are "raised" to alloca when possible here, which prevents the introduction of the conflicting malloc usage.

hakostra commented 2 weeks ago

I tested the original code/problem on a recent flang-new compiled from main branch, and the code compiles without any errors now.

$ flang-new --version
flang-new version 20.0.0git (https://github.com/llvm/llvm-project.git 7792b4ae79e5ac9355ee13b01f16e25455f8427f)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /opt/llvm/llvm-project/install/bin
pawosm-arm commented 2 weeks ago

There's nothing more to do here, closing it.