Skip to content

[flang] Match the type of the element size in the box in creating fir.box_elesize #100512

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

Merged
merged 2 commits into from
Aug 6, 2024

Conversation

kkwli
Copy link
Collaborator

@kkwli kkwli commented Jul 25, 2024

Currently, %17 = fir.box_elesize %16 : (!fir.class<!fir.ptr<!fir.type<_QFTt{a:i32,b:i32}>>>) -> i32
is translated to

  %4 = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %1, i32 0, i32 1
  %5 = load i32, ptr %4, align 4

The type of the element size is i64. The load essentially truncates the value and yields incorrect result in the big endian environment. The problem occurs in the storage_size intrinsic on a polymorphic variable.

@kkwli kkwli requested review from clementval and jeanPerier July 25, 2024 05:54
@kkwli kkwli self-assigned this Jul 25, 2024
@kkwli kkwli requested a review from DanielCChen July 25, 2024 05:54
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir labels Jul 25, 2024
@llvmbot
Copy link
Member

llvmbot commented Jul 25, 2024

@llvm/pr-subscribers-flang-codegen

@llvm/pr-subscribers-flang-fir-hlfir

Author: Kelvin Li (kkwli)

Changes

Currently, %17 = fir.box_elesize %16 : (!fir.class&lt;!fir.ptr&lt;!fir.type&lt;_QFTt{a:i32,b:i32}&gt;&gt;&gt;) -&gt; i32
is translated to

  %4 = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %1, i32 0, i32 1
  %5 = load i32, ptr %4, align 4

The type of the element size is i64. The load essentially truncates the value and yields incorrect result in the big endian environment. The problem occurs in the storage_size intrinsic on a polymorphic variable.


Full diff: https://github.com/llvm/llvm-project/pull/100512.diff

4 Files Affected:

  • (modified) flang/lib/Optimizer/Builder/IntrinsicCall.cpp (+3-1)
  • (modified) flang/test/Lower/HLFIR/assumed-rank-inquiries.f90 (+6-4)
  • (modified) flang/test/Lower/Intrinsics/storage_size-2.f90 (+3-2)
  • (modified) flang/test/Lower/Intrinsics/storage_size.f90 (+15-10)
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 0e5e30a7024d8..2d52ba1007496 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -6731,7 +6731,9 @@ IntrinsicLibrary::genStorageSize(mlir::Type resultType,
 
   box = builder.createBox(loc, args[0],
                           /*isPolymorphic=*/args[0].isPolymorphic());
-  mlir::Value eleSize = builder.create<fir::BoxEleSizeOp>(loc, kindTy, box);
+  mlir::Type i64Ty = builder.getIntegerType(64);
+  mlir::Value boxEleSize = builder.create<fir::BoxEleSizeOp>(loc, i64Ty, box);
+  mlir::Value eleSize = builder.createConvert(loc, kindTy, boxEleSize);
   mlir::Value c8 = builder.createIntegerConstant(loc, kindTy, 8);
   return builder.create<mlir::arith::MulIOp>(loc, eleSize, c8);
 }
diff --git a/flang/test/Lower/HLFIR/assumed-rank-inquiries.f90 b/flang/test/Lower/HLFIR/assumed-rank-inquiries.f90
index a1d150a21d149..4a7035a9fea0a 100644
--- a/flang/test/Lower/HLFIR/assumed-rank-inquiries.f90
+++ b/flang/test/Lower/HLFIR/assumed-rank-inquiries.f90
@@ -191,9 +191,10 @@ subroutine c_loc_2(x)
 ! CHECK-SAME:                                      %[[VAL_0:.*]]: !fir.class<!fir.array<*:none>> {fir.bindc_name = "x"}) {
 ! CHECK:           %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
 ! CHECK:           %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "_QFtest_storage_size_1Ex"} : (!fir.class<!fir.array<*:none>>, !fir.dscope) -> (!fir.class<!fir.array<*:none>>, !fir.class<!fir.array<*:none>>)
-! CHECK:           %[[VAL_3:.*]] = fir.box_elesize %[[VAL_2]]#0 : (!fir.class<!fir.array<*:none>>) -> i32
+! CHECK:           %[[VAL_3:.*]] = fir.box_elesize %[[VAL_2]]#0 : (!fir.class<!fir.array<*:none>>) -> i64
+! CHECK:           %[[VAL_3_CONV:.*]] = fir.convert %[[VAL_3]] : (i64) -> i32
 ! CHECK:           %[[VAL_4:.*]] = arith.constant 8 : i32
-! CHECK:           %[[VAL_5:.*]] = arith.muli %[[VAL_3]], %[[VAL_4]] : i32
+! CHECK:           %[[VAL_5:.*]] = arith.muli %[[VAL_3_CONV]], %[[VAL_4]] : i32
 ! CHECK:           %[[VAL_6:.*]]:3 = hlfir.associate %[[VAL_5]] {adapt.valuebyref} : (i32) -> (!fir.ref<i32>, !fir.ref<i32>, i1)
 ! CHECK:           fir.call @_QPtakes_integer(%[[VAL_6]]#1) fastmath<contract> : (!fir.ref<i32>) -> ()
 ! CHECK:           hlfir.end_associate %[[VAL_6]]#1, %[[VAL_6]]#2 : !fir.ref<i32>, i1
@@ -213,9 +214,10 @@ subroutine c_loc_2(x)
 ! CHECK:             %[[VAL_13:.*]] = fir.call @_FortranAReportFatalUserError
 ! CHECK:           }
 ! CHECK:           %[[VAL_14:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref<!fir.class<!fir.ptr<!fir.array<*:none>>>>
-! CHECK:           %[[VAL_15:.*]] = fir.box_elesize %[[VAL_14]] : (!fir.class<!fir.ptr<!fir.array<*:none>>>) -> i32
+! CHECK:           %[[VAL_15:.*]] = fir.box_elesize %[[VAL_14]] : (!fir.class<!fir.ptr<!fir.array<*:none>>>) -> i64
+! CHECK:           %[[VAL_15_CONV:.*]] = fir.convert %[[VAL_15]] : (i64) -> i32
 ! CHECK:           %[[VAL_16:.*]] = arith.constant 8 : i32
-! CHECK:           %[[VAL_17:.*]] = arith.muli %[[VAL_15]], %[[VAL_16]] : i32
+! CHECK:           %[[VAL_17:.*]] = arith.muli %[[VAL_15_CONV]], %[[VAL_16]] : i32
 ! CHECK:           %[[VAL_18:.*]]:3 = hlfir.associate %[[VAL_17]] {adapt.valuebyref} : (i32) -> (!fir.ref<i32>, !fir.ref<i32>, i1)
 ! CHECK:           fir.call @_QPtakes_integer(%[[VAL_18]]#1) fastmath<contract> : (!fir.ref<i32>) -> ()
 ! CHECK:           hlfir.end_associate %[[VAL_18]]#1, %[[VAL_18]]#2 : !fir.ref<i32>, i1
diff --git a/flang/test/Lower/Intrinsics/storage_size-2.f90 b/flang/test/Lower/Intrinsics/storage_size-2.f90
index d6fb68df70ea9..7fd26d28a2e09 100644
--- a/flang/test/Lower/Intrinsics/storage_size-2.f90
+++ b/flang/test/Lower/Intrinsics/storage_size-2.f90
@@ -17,9 +17,10 @@ function return_char(l)
 ! CHECK: %[[expr:.*]] = hlfir.as_expr %[[res]]#0 move %[[false]] : (!fir.boxchar<1>, i1) -> !hlfir.expr<!fir.char<1,?>>
 ! CHECK: %[[assoc:.*]]:3 = hlfir.associate %[[expr]] typeparams %[[res_len]] {adapt.valuebyref} : (!hlfir.expr<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>, i1)
 ! CHECK: %[[val_18:.*]] = fir.embox %[[assoc]]#1 typeparams %[[res_len]] : (!fir.ref<!fir.char<1,?>>, index) -> !fir.box<!fir.char<1,?>>
-! CHECK: %[[val_19:.*]] = fir.box_elesize %[[val_18]] : (!fir.box<!fir.char<1,?>>) -> i32
+! CHECK: %[[val_19:.*]] = fir.box_elesize %[[val_18]] : (!fir.box<!fir.char<1,?>>) -> i64
+! CHECK: %[[val_19_conv:.*]] = fir.convert %[[val_19]] : (i64) -> i32
 ! CHECK: %[[val_20:.*]] = arith.constant 8 : i32
-! CHECK: %[[val_21:.*]] = arith.muli %[[val_19]], %[[val_20]] : i32
+! CHECK: %[[val_21:.*]] = arith.muli %[[val_19_conv]], %[[val_20]] : i32
 ! CHECK: fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[val_21]])
 end subroutine
 
diff --git a/flang/test/Lower/Intrinsics/storage_size.f90 b/flang/test/Lower/Intrinsics/storage_size.f90
index b0c9d51f95328..24709e4640727 100644
--- a/flang/test/Lower/Intrinsics/storage_size.f90
+++ b/flang/test/Lower/Intrinsics/storage_size.f90
@@ -32,9 +32,10 @@ integer function unlimited_polymorphic_pointer(p) result(size)
 ! CHECK:   %{{.*}} = fir.call @_FortranAReportFatalUserError(%{{.*}}, %{{.*}}, %{{.*}}) {{.*}} : (!fir.ref<i8>, !fir.ref<i8>, i32) -> none
 ! CHECK: }
 ! CHECK: %[[LOAD_P:.*]] = fir.load %[[P]] : !fir.ref<!fir.class<!fir.ptr<none>>>
-! CHECK: %[[ELE_SIZE:.*]] = fir.box_elesize %[[LOAD_P]] : (!fir.class<!fir.ptr<none>>) -> i32
+! CHECK: %[[ELE_SIZE:.*]] = fir.box_elesize %[[LOAD_P]] : (!fir.class<!fir.ptr<none>>) -> i64
+! CHECK: %[[ELE_SIZE_CONV:.*]] = fir.convert %[[ELE_SIZE]] : (i64) -> i32
 ! CHECK: %[[C8:.*]] = arith.constant 8 : i32
-! CHECK: %[[BITS:.*]] = arith.muli %[[ELE_SIZE]], %[[C8]] : i32
+! CHECK: %[[BITS:.*]] = arith.muli %[[ELE_SIZE_CONV]], %[[C8]] : i32
 ! CHECK: fir.store %[[BITS]] to %[[SIZE]] : !fir.ref<i32>
 ! CHECK: %[[RES:.*]] = fir.load %[[SIZE]] : !fir.ref<i32>
 ! CHECK: return %[[RES]] : i32
@@ -56,9 +57,10 @@ integer function unlimited_polymorphic_allocatable(p) result(size)
 ! CHECK:   %{{.*}} = fir.call @_FortranAReportFatalUserError(%{{.*}}, %{{.*}}, %{{.*}}) {{.*}} : (!fir.ref<i8>, !fir.ref<i8>, i32) -> none
 ! CHECK: }
 ! CHECK: %[[LOAD_P:.*]] = fir.load %[[P]] : !fir.ref<!fir.class<!fir.heap<none>>>
-! CHECK: %[[ELE_SIZE:.*]] = fir.box_elesize %[[LOAD_P]] : (!fir.class<!fir.heap<none>>) -> i32
+! CHECK: %[[ELE_SIZE:.*]] = fir.box_elesize %[[LOAD_P]] : (!fir.class<!fir.heap<none>>) -> i64
+! CHECK: %[[ELE_SIZE_CONV:.*]] = fir.convert %[[ELE_SIZE]] : (i64) -> i32
 ! CHECK: %[[C8:.*]] = arith.constant 8 : i32
-! CHECK: %[[BITS:.*]] = arith.muli %[[ELE_SIZE]], %[[C8]] : i32
+! CHECK: %[[BITS:.*]] = arith.muli %[[ELE_SIZE_CONV]], %[[C8]] : i32
 ! CHECK: fir.store %[[BITS]] to %[[SIZE]] : !fir.ref<i32>
 ! CHECK: %[[RES:.*]] = fir.load %[[SIZE]] : !fir.ref<i32>
 ! CHECK: return %[[RES]] : i32
@@ -72,9 +74,10 @@ integer function polymorphic_pointer(p) result(size)
 ! CHECK-SAME: %[[P:.*]]: !fir.ref<!fir.class<!fir.ptr<!fir.type<_QMstorage_size_testTp1{a:i32}>>>> {fir.bindc_name = "p"}) -> i32 {
 ! CHECK: %[[SIZE:.*]] = fir.alloca i32 {bindc_name = "size", uniq_name = "_QMstorage_size_testFpolymorphic_pointerEsize"}
 ! CHECK: %[[LOAD_P:.*]] = fir.load %[[P]] : !fir.ref<!fir.class<!fir.ptr<!fir.type<_QMstorage_size_testTp1{a:i32}>>>>
-! CHECK: %[[ELE_SIZE:.*]] = fir.box_elesize %[[LOAD_P]] : (!fir.class<!fir.ptr<!fir.type<_QMstorage_size_testTp1{a:i32}>>>) -> i32
+! CHECK: %[[ELE_SIZE:.*]] = fir.box_elesize %[[LOAD_P]] : (!fir.class<!fir.ptr<!fir.type<_QMstorage_size_testTp1{a:i32}>>>) -> i64
+! CHECK: %[[ELE_SIZE_CONV:.*]] = fir.convert %[[ELE_SIZE]] : (i64) -> i32
 ! CHECK: %[[C8:.*]] = arith.constant 8 : i32
-! CHECK: %[[BITS:.*]] = arith.muli %[[ELE_SIZE]], %[[C8]] : i32
+! CHECK: %[[BITS:.*]] = arith.muli %[[ELE_SIZE_CONV]], %[[C8]] : i32
 ! CHECK: fir.store %[[BITS]] to %[[SIZE]] : !fir.ref<i32>
 ! CHECK: %[[RES:.*]] = fir.load %[[SIZE]] : !fir.ref<i32>
 ! CHECK: return %[[RES]] : i32
@@ -87,9 +90,10 @@ integer function polymorphic(p) result(size)
 ! CHECK-LABEL: func.func @_QMstorage_size_testPpolymorphic(
 ! CHECK-SAME: %[[P:.*]]: !fir.class<!fir.type<_QMstorage_size_testTp1{a:i32}>> {fir.bindc_name = "p"}) -> i32 {
 ! CHECK: %[[SIZE:.*]] = fir.alloca i32 {bindc_name = "size", uniq_name = "_QMstorage_size_testFpolymorphicEsize"}
-! CHECK: %[[ELE_SIZE:.*]] = fir.box_elesize %[[P]] : (!fir.class<!fir.type<_QMstorage_size_testTp1{a:i32}>>) -> i32
+! CHECK: %[[ELE_SIZE:.*]] = fir.box_elesize %[[P]] : (!fir.class<!fir.type<_QMstorage_size_testTp1{a:i32}>>) -> i64
+! CHECK: %[[ELE_SIZE_CONV:.*]] = fir.convert %[[ELE_SIZE]] : (i64) -> i32
 ! CHECK: %[[C8:.*]] = arith.constant 8 : i32
-! CHECK: %[[BITS:.*]] = arith.muli %[[ELE_SIZE]], %[[C8]] : i32
+! CHECK: %[[BITS:.*]] = arith.muli %[[ELE_SIZE_CONV]], %[[C8]] : i32
 ! CHECK: fir.store %[[BITS]] to %[[SIZE]] : !fir.ref<i32>
 ! CHECK: %[[RES:.*]] = fir.load %[[SIZE]] : !fir.ref<i32>
 ! CHECK: return %[[RES]] : i32
@@ -127,9 +131,10 @@ integer function polymorphic_value(t) result(size)
 ! CHECK: %[[IDX:.*]] = arith.subi %[[C1]], %[[DIMI64]] : i64
 ! CHECK: %[[COORD_OF:.*]] = fir.coordinate_of %[[LOAD_COORD_P]], %[[IDX]] : (!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMstorage_size_testTp1{a:i32}>>>>, i64) -> !fir.ref<!fir.type<_QMstorage_size_testTp1{a:i32}>>
 ! CHECK: %[[BOXED:.*]] = fir.embox %[[COORD_OF]] source_box %[[LOAD_COORD_P]] : (!fir.ref<!fir.type<_QMstorage_size_testTp1{a:i32}>>, !fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMstorage_size_testTp1{a:i32}>>>>) -> !fir.class<!fir.type<_QMstorage_size_testTp1{a:i32}>>
-! CHECK: %[[ELE_SIZE:.*]] = fir.box_elesize %[[BOXED]] : (!fir.class<!fir.type<_QMstorage_size_testTp1{a:i32}>>) -> i32
+! CHECK: %[[ELE_SIZE:.*]] = fir.box_elesize %[[BOXED]] : (!fir.class<!fir.type<_QMstorage_size_testTp1{a:i32}>>) -> i64
+! CHECK: %[[ELE_SIZE_CONV:.*]] = fir.convert %[[ELE_SIZE]] : (i64) -> i32
 ! CHECK: %[[C8:.*]] = arith.constant 8 : i32
-! CHECK: %[[SIZE:.*]] = arith.muli %[[ELE_SIZE]], %[[C8]] : i32
+! CHECK: %[[SIZE:.*]] = arith.muli %[[ELE_SIZE_CONV]], %[[C8]] : i32
 ! CHECK: fir.store %[[SIZE]] to %[[ALLOCA]] : !fir.ref<i32>
 ! CHECK: %[[RET:.*]] = fir.load %[[ALLOCA]] : !fir.ref<i32>
 ! CHECK: return %[[RET]] : i32

Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

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

Thanks for finding this bug.

I would rather the bug to be fixed where it is in codegen.cpp: the GEP + load should use the descriptor type and a cast should be inserted. That way, there is no need to assume the type inside the descriptor in lowering, and future creation of fir.box_elesize will be safe.

@kkwli
Copy link
Collaborator Author

kkwli commented Jul 25, 2024

@jeanPerier Thanks for the review. I update the patch. Instead of fixing it in genStorageSize, the change is in getValueBox that insert a cast after the load.

@kkwli kkwli requested a review from jeanPerier July 30, 2024 14:44
@kkwli
Copy link
Collaborator Author

kkwli commented Aug 1, 2024

Ping

Copy link
Contributor

@clementval clementval left a comment

Choose a reason for hiding this comment

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

LGTM

@kkwli kkwli merged commit ce2a3d9 into llvm:main Aug 6, 2024
8 checks passed
@kkwli kkwli deleted the fix-storage-size branch August 6, 2024 22:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:codegen flang:fir-hlfir flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants