diff options
author | jeanPerier <jperier@nvidia.com> | 2024-06-19 10:12:19 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-19 10:12:19 +0200 |
commit | a786919256a37e9a462582fe365eb4ea92b1a9f9 (patch) | |
tree | 68761932ba59eb2982c656c498cc8abb8d478131 /flang | |
parent | bdc7840c5758076e63719d45427c3c756c630ddd (diff) | |
download | llvm-a786919256a37e9a462582fe365eb4ea92b1a9f9.zip llvm-a786919256a37e9a462582fe365eb4ea92b1a9f9.tar.gz llvm-a786919256a37e9a462582fe365eb4ea92b1a9f9.tar.bz2 |
[flang] allow assumed-rank box in fir.store (#95980)
Codegen is done with a memcpy using the rank from the "value" descriptor
like for the fir.load case.
Rational described in
https://github.com/llvm/llvm-project/blob/main/flang/docs/AssumedRank.md.
Diffstat (limited to 'flang')
-rw-r--r-- | flang/lib/Optimizer/CodeGen/CodeGen.cpp | 31 | ||||
-rw-r--r-- | flang/lib/Optimizer/Dialect/FIROps.cpp | 2 | ||||
-rw-r--r-- | flang/test/Fir/convert-to-llvm.fir | 19 | ||||
-rw-r--r-- | flang/test/Fir/tbaa.fir | 19 |
4 files changed, 58 insertions, 13 deletions
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index 4448224..803d9e6 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -3143,23 +3143,32 @@ struct StoreOpConversion : public fir::FIROpConversion<fir::StoreOp> { mlir::ConversionPatternRewriter &rewriter) const override { mlir::Location loc = store.getLoc(); mlir::Type storeTy = store.getValue().getType(); - mlir::LLVM::StoreOp newStoreOp; + mlir::Value llvmValue = adaptor.getValue(); + mlir::Value llvmMemref = adaptor.getMemref(); + mlir::LLVM::AliasAnalysisOpInterface newOp; if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(storeTy)) { - // fir.box value is actually in memory, load it first before storing it. mlir::Type llvmBoxTy = lowerTy().convertBoxTypeAsStruct(boxTy); - auto val = rewriter.create<mlir::LLVM::LoadOp>(loc, llvmBoxTy, - adaptor.getOperands()[0]); - attachTBAATag(val, boxTy, boxTy, nullptr); - newStoreOp = rewriter.create<mlir::LLVM::StoreOp>( - loc, val, adaptor.getOperands()[1]); + // fir.box value is actually in memory, load it first before storing it, + // or do a memcopy for assumed-rank descriptors. + if (boxTy.isAssumedRank()) { + TypePair boxTypePair{boxTy, llvmBoxTy}; + mlir::Value boxSize = + computeBoxSize(loc, boxTypePair, llvmValue, rewriter); + newOp = rewriter.create<mlir::LLVM::MemcpyOp>( + loc, llvmMemref, llvmValue, boxSize, /*isVolatile=*/false); + } else { + auto val = + rewriter.create<mlir::LLVM::LoadOp>(loc, llvmBoxTy, llvmValue); + attachTBAATag(val, boxTy, boxTy, nullptr); + newOp = rewriter.create<mlir::LLVM::StoreOp>(loc, val, llvmMemref); + } } else { - newStoreOp = rewriter.create<mlir::LLVM::StoreOp>( - loc, adaptor.getOperands()[0], adaptor.getOperands()[1]); + newOp = rewriter.create<mlir::LLVM::StoreOp>(loc, llvmValue, llvmMemref); } if (std::optional<mlir::ArrayAttr> optionalTag = store.getTbaa()) - newStoreOp.setTBAATags(*optionalTag); + newOp.setTBAATags(*optionalTag); else - attachTBAATag(newStoreOp, storeTy, storeTy, nullptr); + attachTBAATag(newOp, storeTy, storeTy, nullptr); rewriter.eraseOp(store); return mlir::success(); } diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp index 6cf0dd2..7b5f4fd 100644 --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -3791,8 +3791,6 @@ void fir::StoreOp::print(mlir::OpAsmPrinter &p) { mlir::LogicalResult fir::StoreOp::verify() { if (getValue().getType() != fir::dyn_cast_ptrEleTy(getMemref().getType())) return emitOpError("store value type must match memory reference type"); - if (fir::isa_unknown_size_box(getValue().getType())) - return emitOpError("cannot store !fir.box of unknown rank or type"); return mlir::success(); } diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir index 857d5b2..c951445 100644 --- a/flang/test/Fir/convert-to-llvm.fir +++ b/flang/test/Fir/convert-to-llvm.fir @@ -895,6 +895,25 @@ func.func @store_unlimited_polymorphic_box(%arg0 : !fir.class<none>, %arg1 : !fi // ----- +func.func @store_assumed_rank_box(%box: !fir.box<!fir.array<*:f32>>, %ref: !fir.ref<!fir.box<!fir.array<*:f32>>>) { + fir.store %box to %ref : !fir.ref<!fir.box<!fir.array<*:f32>>> + return +} + +// CHECK-LABEL: llvm.func @store_assumed_rank_box( +// CHECK-SAME: %[[VAL_0:[^:]*]]: !llvm.ptr, +// CHECK-SAME: %[[VAL_1:.*]]: !llvm.ptr) { +// CHECK: %[[VAL_2:.*]] = llvm.mlir.constant(24 : i32) : i32 +// CHECK: %[[VAL_3:.*]] = llvm.getelementptr %[[VAL_0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<15 x array<3 x i64>>)> +// CHECK: %[[VAL_4:.*]] = llvm.load %[[VAL_3]] : !llvm.ptr -> i8 +// CHECK: %[[VAL_5:.*]] = llvm.sext %[[VAL_4]] : i8 to i32 +// CHECK: %[[VAL_6:.*]] = llvm.mlir.constant(24 : i32) : i32 +// CHECK: %[[VAL_7:.*]] = llvm.mul %[[VAL_6]], %[[VAL_5]] : i32 +// CHECK: %[[VAL_8:.*]] = llvm.add %[[VAL_2]], %[[VAL_7]] : i32 +// CHECK: "llvm.intr.memcpy"(%[[VAL_1]], %[[VAL_0]], %[[VAL_8]]) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> () + +// ----- + // Test `fir.load` --> `llvm.load` conversion func.func @test_load_index(%addr : !fir.ref<index>) { diff --git a/flang/test/Fir/tbaa.fir b/flang/test/Fir/tbaa.fir index 5800e60..89679af 100644 --- a/flang/test/Fir/tbaa.fir +++ b/flang/test/Fir/tbaa.fir @@ -407,3 +407,22 @@ func.func private @some_assumed_rank_func(!fir.box<!fir.array<*:f64>>) -> () // CHECK: %[[VAL_9:.*]] = llvm.add %[[VAL_3]], %[[VAL_8]] : i32 // CHECK: "llvm.intr.memcpy"(%[[VAL_2]], %[[VAL_0]], %[[VAL_9]]) <{isVolatile = false, tbaa = [#[[$BOXT]]]}> : (!llvm.ptr, !llvm.ptr, i32) -> () // CHECK: llvm.call @some_assumed_rank_func(%[[VAL_2]]) : (!llvm.ptr) -> () + +// ----- + +func.func @store_assumed_rank_box(%box: !fir.box<!fir.array<*:f32>>, %ref: !fir.ref<!fir.box<!fir.array<*:f32>>>) { + fir.store %box to %ref : !fir.ref<!fir.box<!fir.array<*:f32>>> + return +} + +// CHECK-DAG: #[[ROOT:.*]] = #llvm.tbaa_root<id = "Flang function root "> +// CHECK-DAG: #[[ANYACC:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT]], 0>}> +// CHECK-DAG: #[[BOXMEM:.*]] = #llvm.tbaa_type_desc<id = "descriptor member", members = {<#[[ANYACC]], 0>}> +// CHECK-DAG: #[[$BOXT:.*]] = #llvm.tbaa_tag<base_type = #[[BOXMEM]], access_type = #[[BOXMEM]], offset = 0> + +// CHECK-LABEL: llvm.func @store_assumed_rank_box( +// CHECK-SAME: %[[VAL_0:[^:]*]]: !llvm.ptr, +// CHECK-SAME: %[[VAL_1:.*]]: !llvm.ptr) { +// CHECK: %[[VAL_3:.*]] = llvm.getelementptr %[[VAL_0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<15 x array<3 x i64>>)> +// CHECK: %[[VAL_4:.*]] = llvm.load %[[VAL_3]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i8 +// CHECK: "llvm.intr.memcpy"(%[[VAL_1]], %[[VAL_0]], %{{.*}}) <{isVolatile = false, tbaa = [#[[$BOXT]]]}> : (!llvm.ptr, !llvm.ptr, i32) -> () |