Skip to content

Commit e3349fa

Browse files
banach-spaceschweitzpgijeanPerier
committed
[flang][CodeGen] Transform fir.{store|load} to llvm.{store|load}
This patch extends the `FIRToLLVMLowering` pass in Flang by adding a hook to transform `fir.store`/`fir.load` to `llvm.store`/`fir.load`, respectively. This is part of the upstreaming effort from the `fir-dev` branch in [1]. [1] https://github.com/flang-compiler/f18-llvm-project Differential Revision: https://reviews.llvm.org/D113090 Patch originally written by: Co-authored-by: Eric Schweitz <eschweitz@nvidia.com> Co-authored-by: Jean Perier <jperier@nvidia.com>
1 parent 0aabdad commit e3349fa

File tree

2 files changed

+111
-10
lines changed

2 files changed

+111
-10
lines changed

flang/lib/Optimizer/CodeGen/CodeGen.cpp

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,29 @@ struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
366366
}
367367
};
368368

369+
/// `fir.load` --> `llvm.load`
370+
struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
371+
using FIROpConversion::FIROpConversion;
372+
373+
mlir::LogicalResult
374+
matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
375+
mlir::ConversionPatternRewriter &rewriter) const override {
376+
// fir.box is a special case because it is considered as an ssa values in
377+
// fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
378+
// and fir.box end up being the same llvm types and loading a
379+
// fir.ref<fir.box> is actually a no op in LLVM.
380+
if (load.getType().isa<fir::BoxType>()) {
381+
rewriter.replaceOp(load, adaptor.getOperands()[0]);
382+
} else {
383+
mlir::Type ty = convertType(load.getType());
384+
ArrayRef<NamedAttribute> at = load->getAttrs();
385+
rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
386+
load, ty, adaptor.getOperands(), at);
387+
}
388+
return success();
389+
}
390+
};
391+
369392
/// conversion of fir::SelectRankOp to an if-then-else ladder
370393
struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
371394
using FIROpConversion::FIROpConversion;
@@ -378,7 +401,31 @@ struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
378401
}
379402
};
380403

381-
// convert to LLVM IR dialect `undef`
404+
/// `fir.store` --> `llvm.store`
405+
struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
406+
using FIROpConversion::FIROpConversion;
407+
408+
mlir::LogicalResult
409+
matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
410+
mlir::ConversionPatternRewriter &rewriter) const override {
411+
if (store.value().getType().isa<fir::BoxType>()) {
412+
// fir.box value is actually in memory, load it first before storing it.
413+
mlir::Location loc = store.getLoc();
414+
mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
415+
auto val = rewriter.create<mlir::LLVM::LoadOp>(
416+
loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
417+
adaptor.getOperands()[0]);
418+
rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
419+
store, val, adaptor.getOperands()[1]);
420+
} else {
421+
rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
422+
store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
423+
}
424+
return success();
425+
}
426+
};
427+
428+
/// convert to LLVM IR dialect `undef`
382429
struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
383430
using FIROpConversion::FIROpConversion;
384431

@@ -391,7 +438,7 @@ struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
391438
}
392439
};
393440

394-
// convert to LLVM IR dialect `unreachable`
441+
/// `fir.unreachable` --> `llvm.unreachable`
395442
struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
396443
using FIROpConversion::FIROpConversion;
397444

@@ -788,14 +835,14 @@ class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
788835
auto *context = getModule().getContext();
789836
fir::LLVMTypeConverter typeConverter{getModule()};
790837
mlir::OwningRewritePatternList pattern(context);
791-
pattern
792-
.insert<AddcOpConversion, AddrOfOpConversion, CallOpConversion,
793-
ConvertOpConversion, DivcOpConversion, ExtractValueOpConversion,
794-
HasValueOpConversion, GlobalOpConversion,
795-
InsertOnRangeOpConversion, InsertValueOpConversion,
796-
NegcOpConversion, MulcOpConversion, SelectOpConversion,
797-
SelectRankOpConversion, SubcOpConversion, UndefOpConversion,
798-
UnreachableOpConversion, ZeroOpConversion>(typeConverter);
838+
pattern.insert<AddcOpConversion, AddrOfOpConversion, CallOpConversion,
839+
ConvertOpConversion, DivcOpConversion,
840+
ExtractValueOpConversion, HasValueOpConversion,
841+
GlobalOpConversion, InsertOnRangeOpConversion,
842+
InsertValueOpConversion, LoadOpConversion, NegcOpConversion,
843+
MulcOpConversion, SelectOpConversion, SelectRankOpConversion,
844+
StoreOpConversion, SubcOpConversion, UndefOpConversion,
845+
UnreachableOpConversion, ZeroOpConversion>(typeConverter);
799846
mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
800847
mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
801848
pattern);

flang/test/Fir/convert-to-llvm.fir

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,3 +632,57 @@ func @convert_complex16(%arg0 : !fir.complex<16>) -> !fir.complex<2> {
632632
// CHECK: %[[STRUCT1:.*]] = llvm.insertvalue %[[CONVERTX]], %[[STRUCT0]][0 : i32] : !llvm.struct<(f16, f16)>
633633
// CHECK: %[[STRUCT2:.*]] = llvm.insertvalue %[[CONVERTY]], %[[STRUCT1]][1 : i32] : !llvm.struct<(f16, f16)>
634634
// CHECK: llvm.return %[[STRUCT2]] : !llvm.struct<(f16, f16)>
635+
636+
// -----
637+
638+
// Test `fir.store` --> `llvm.store` conversion
639+
640+
func @test_store_index(%val_to_store : index, %addr : !fir.ref<index>) {
641+
fir.store %val_to_store to %addr : !fir.ref<index>
642+
return
643+
}
644+
645+
// CHECK-LABEL: llvm.func @test_store_index
646+
// CHECK-SAME: (%[[arg0:.*]]: i64, %[[arg1:.*]]: !llvm.ptr<i64>) {
647+
// CHECK-NEXT: llvm.store %[[arg0]], %[[arg1]] : !llvm.ptr<i64>
648+
// CHECK-NEXT: llvm.return
649+
// CHECK-NEXT: }
650+
651+
func @test_store_box(%array : !fir.ref<!fir.box<!fir.array<?x?xf32>>>, %box : !fir.box<!fir.array<?x?xf32>>) {
652+
fir.store %box to %array : !fir.ref<!fir.box<!fir.array<?x?xf32>>>
653+
return
654+
}
655+
656+
// CHECK-LABEL: llvm.func @test_store_box
657+
// CHECK-SAME: (%[[arg0:.*]]: !llvm.ptr<struct<(ptr<f{{.*}}>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i{{.*}}>>)>>,
658+
// CHECK-SAME: %[[arg1:.*]]: !llvm.ptr<struct<(ptr<f{{.*}}>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i{{.*}}>>)>>) {
659+
// CHECK-NEXT: %[[box_to_store:.*]] = llvm.load %arg1 : !llvm.ptr<struct<(ptr<f{{.*}}>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i{{.*}}>>)>>
660+
// CHECK-NEXT: llvm.store %[[box_to_store]], %[[arg0]] : !llvm.ptr<struct<(ptr<f{{.*}}>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<2 x array<3 x i{{.*}}>>)>>
661+
// CHECK-NEXT: llvm.return
662+
// CHECK-NEXT: }
663+
664+
// -----
665+
666+
// Test `fir.load` --> `llvm.load` conversion
667+
668+
func @test_load_index(%addr : !fir.ref<index>) {
669+
%0 = fir.load %addr : !fir.ref<index>
670+
return
671+
}
672+
673+
// CHECK-LABEL: llvm.func @test_load_index(
674+
// CHECK-SAME: %[[arg1:.*]]: !llvm.ptr<i64>) {
675+
// CHECK-NEXT: %0 = llvm.load %[[arg1]] : !llvm.ptr<i64>
676+
// CHECK-NEXT: llvm.return
677+
// CHECK-NEXT: }
678+
679+
func @test_load_box(%addr : !fir.ref<!fir.box<!fir.array<10xf32>>>) {
680+
%0 = fir.load %addr : !fir.ref<!fir.box<!fir.array<10xf32>>>
681+
return
682+
}
683+
684+
// Loading a `fir.ref<!fir.box>> is a no-op
685+
// CHECK-LABEL: llvm.func @test_load_box
686+
// CHECK-SAME: (%{{.*}}: !llvm.ptr<struct<(ptr<array<10 x f{{.*}}>>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>)>>) {
687+
// CHECK-NEXT: llvm.return
688+
// CHECK-NEXT: }

0 commit comments

Comments
 (0)