diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -79,6 +79,22 @@ } }; +// `fir.call` -> `llvm.call` +struct CallOpConversion : public FIROpConversion { + using FIROpConversion::FIROpConversion; + + mlir::LogicalResult + matchAndRewrite(fir::CallOp call, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + SmallVector resultTys; + for (auto r : call.getResults()) + resultTys.push_back(convertType(r.getType())); + rewriter.replaceOpWithNewOp( + call, resultTys, adaptor.getOperands(), call->getAttrs()); + return success(); + } +}; + /// Lower `fir.has_value` operation to `llvm.return` operation. struct HasValueOpConversion : public FIROpConversion { using FIROpConversion::FIROpConversion; @@ -489,10 +505,11 @@ fir::LLVMTypeConverter typeConverter{getModule()}; mlir::OwningRewritePatternList pattern(context); pattern.insert< - AddrOfOpConversion, ExtractValueOpConversion, HasValueOpConversion, - GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion, - SelectOpConversion, SelectRankOpConversion, UndefOpConversion, - UnreachableOpConversion, ZeroOpConversion>(typeConverter); + AddrOfOpConversion, CallOpConversion, ExtractValueOpConversion, + HasValueOpConversion, GlobalOpConversion, InsertOnRangeOpConversion, + InsertValueOpConversion, SelectOpConversion, SelectRankOpConversion, + UndefOpConversion, UnreachableOpConversion, ZeroOpConversion>( + typeConverter); mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern); mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, pattern); diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir --- a/flang/test/Fir/convert-to-llvm.fir +++ b/flang/test/Fir/convert-to-llvm.fir @@ -323,3 +323,56 @@ // CHECK-SAME: %[[TUPLE:.*]]: !llvm.struct<(i32, f32)> // CHECK: %{{.*}} = llvm.insertvalue %{{.*}}, %[[TUPLE]][1 : index] : !llvm.struct<(i32, f32)> // CHECK: llvm.return + +// ----- +// Test `fir.call` -> `llvm.call` conversion for functions that take no arguments +// and return nothing + +func @dummy_basic() { + return +} + +func @test_call_basic() { + fir.call @dummy_basic() : () -> () + return +} + +// CHECK-LABEL: func @test_call_basic() { +// CHECK-NEXT: llvm.call @dummy_basic() : () -> () +// CHECK-NEXT: return +// CHECK-NEXT: } + +// Test `fir.call` -> `llvm.call` conversion for functions that take one +// argument and return nothing + +func @dummy_with_arg(%arg0 : i32) { + return +} + +func @test_call_with_arg(%arg0 : i32) { + fir.call @dummy_with_arg(%arg0) : (i32) -> () + return +} + +// CHECK-LABEL: llvm.func @test_call_with_arg(%arg0: i32) { +// CHECK-NEXT: llvm.call @dummy_with_arg(%arg0) : (i32) -> () +// CHECK-NEXT: llvm.return +// CHECK-NEXT: } + +// Test `fir.call` -> `llvm.call` conversion for functions that take no +// arguments, but return a value + +func @dummy_return_val() -> i32 { + %1 = arith.constant 123 : i32 + return %1 : i32 +} + +func @test_call_return_val() -> i32 { + %1 = fir.call @dummy_return_val() : () -> (i32) + return %1 : i32 +} + +// CHECK-LABEL: llvm.func @test_call_return_val() -> i32 { +// CHECK-NEXT: %0 = llvm.call @dummy_return_val() : () -> i32 +// CHECK-NEXT: llvm.return %0 : i32 +// CHECK-NEXT: }