| Issue |
87046
|
| Summary |
[Flang] Segmentation fault on MAX/MIN
|
| Labels |
flang
|
| Assignees |
|
| Reporter |
JumpMasterJJ
|
In the process of trying to solve #78089, I found that besides `ishftc`, `max/min` may cause segment fault when passing the parameter with optional attribute.
```fortran
! max/min
module m
implicit none
contains
function maxTest1 (a, b, c) result(r)
integer(4) :: a
integer(4) :: b
integer(2), optional :: c
integer(4) :: r
r = max(a, b, c)
end
end module m
program p
use m
implicit none
integer(4) :: num
num = maxTest1(1, 2)
end program p
```
```shell
$ flang-new max.f90 -o max
$ ./max
Segmentation fault (core dumped)
```
By debugging flang, it appears that the problem lies here: `Fortran::evaluate::MayBePassedAsAbsentOptional`.
https://github.com/llvm/llvm-project/blob/abfc5efb55267689f1852fd7ce3e0a38876aa259/flang/lib/Evaluate/tools.cpp#L1254-L1262
This function seems to incorrectly determine the optional attribute of parameters other than `integer(4)`. And Causing the generated IR to directly load a `None` variable without determining `Some/None`.
Generated IR details:
```mlir
module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<f16, dense<16> : vector<2xi64>>, #dlti.dl_entry<f64, dense<64> : vector<2xi64>>, #dlti.dl_entry<i32, dense<32> : vector<2xi64>>, #dlti.dl_entry<i16, dense<16> : vector<2xi64>>, #dlti.dl_entry<i8, dense<8> : vector<2xi64>>, #dlti.dl_entry<i1, dense<8> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi64>>, #dlti.dl_entry<f80, dense<128> : vector<2xi64>>, #dlti.dl_entry<i128, dense<128> : vector<2xi64>>, #dlti.dl_entry<i64, dense<64> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr<272>, dense<64> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<271>, dense<32> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<270>, dense<32> : vector<4xi64>>, #dlti.dl_entry<f128, dense<128> : vector<2xi64>>, #dlti.dl_entry<"dlti.endianness", "little">, #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>>, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.target_triple = "x86_64-unknown-linux-gnu"} {
func.func @_QMmPmaxtest1(%arg0: !fir.ref<i32> {fir.bindc_name = "a"}, %arg1: !fir.ref<i32> {fir.bindc_name = "b"}, %arg2: !fir.ref<i16> {fir.bindc_name = "c", fir.optional}) -> i32 {
%0 = fir.declare %arg0 {uniq_name = "_QMmFmaxtest1Ea"} : (!fir.ref<i32>) -> !fir.ref<i32>
%1 = fir.declare %arg1 {uniq_name = "_QMmFmaxtest1Eb"} : (!fir.ref<i32>) -> !fir.ref<i32>
%2 = fir.declare %arg2 {fortran_attrs = #fir.var_attrs<optional>, uniq_name = "_QMmFmaxtest1Ec"} : (!fir.ref<i16>) -> !fir.ref<i16>
%3 = fir.alloca i32 {bindc_name = "r", uniq_name = "_QMmFmaxtest1Er"}
%4 = fir.declare %3 {uniq_name = "_QMmFmaxtest1Er"} : (!fir.ref<i32>) -> !fir.ref<i32>
// it should be "%7 = fir.is_present %2 : (!fir.ref<i32>) -> i1",
// just like "integer(4)", but it directly load the None.
%5 = fir.load %2 : !fir.ref<i16>
%6 = fir.convert %5 : (i16) -> i32
%7 = fir.load %0 : !fir.ref<i32>
%8 = fir.load %1 : !fir.ref<i32>
%9 = arith.cmpi sgt, %7, %8 : i32
%10 = arith.select %9, %7, %8 : i32
%11 = arith.cmpi sgt, %10, %6 : i32
%12 = arith.select %11, %10, %6 : i32
fir.store %12 to %4 : !fir.ref<i32>
%13 = fir.load %4 : !fir.ref<i32>
return %13 : i32
}
func.func @_QQmain() attributes {fir.bindc_name = "p"} {
%0 = fir.alloca i32 {adapt.valuebyref}
%1 = fir.alloca i32 {adapt.valuebyref}
%c2_i32 = arith.constant 2 : i32
%c1_i32 = arith.constant 1 : i32
%2 = fir.alloca i32 {bindc_name = "num", uniq_name = "_QFEnum"}
%3 = fir.declare %2 {uniq_name = "_QFEnum"} : (!fir.ref<i32>) -> !fir.ref<i32>
fir.store %c1_i32 to %1 : !fir.ref<i32>
%false = arith.constant false
fir.store %c2_i32 to %0 : !fir.ref<i32>
%false_0 = arith.constant false
%4 = fir.absent !fir.ref<i16>
%5 = fir.call @_QMmPmaxtest1(%1, %0, %4) fastmath<contract> : (!fir.ref<i32>, !fir.ref<i32>, !fir.ref<i16>) -> i32
fir.store %5 to %3 : !fir.ref<i32>
return
}
fir.global @_QQEnvironmentDefaults constant : !fir.ref<tuple<i32, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>> {
%0 = fir.zero_bits !fir.ref<tuple<i32, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>
fir.has_value %0 : !fir.ref<tuple<i32, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>
}
}
```
It appears that `associated` will also have similar issues after implementation, as it also uses `Fortran::evaluate::MayBePassedAsAbsentOptional`.
```fortran
module m
implicit none
contains
function associatedTest1 (ptr, tar) result(r)
integer, pointer :: ptr
integer, target, optional :: tar
logical(4) :: r
r = associated(ptr, tar)
end
end module m
program p
use m
implicit none
logical :: b
integer, pointer :: ptr
b = associatedTest1(ptr)
end program p
```
```shell
$ flang-new max.f90 -o associated
$ ./associated
error: loc("/home/jump/llvm-project/flang/reproduced/associated.f90":10:5): /home/jump/llvm-project/flang/lib/Lower/ConvertCall.cpp:2434: not yet implemented: Inquired non-optional arg to intrinsic with custom handling
LLVM ERROR: aborting
```
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs