From c6ac937091249582fce14f02920a4bc94049e713 Mon Sep 17 00:00:00 2001 From: Kiran Chandramohan Date: Mon, 21 Mar 2022 14:09:47 +0000 Subject: [PATCH] [Flang] Add OpenMP Conversion patterns This patch adds the OpenMP conversion patterns to the FIR to LLVM dialect lowering pass in Codegen. Appropriate legalization conditions are also added. This ensures that a mix of FIR and OpenMP dialects can be lowered to LLVM and OpenMP dialects. Also adds two tests. This is part of the upstreaming effort from the fir-dev branch in [1]. [1] https://github.com/flang-compiler/f18-llvm-project Reviewed By: clementval, peixin Differential Revision: https://reviews.llvm.org/D121793 Co-authored-by: Sourabh Singh Tomar Co-authored-by: Eric Schweitz --- flang/lib/Optimizer/CodeGen/CodeGen.cpp | 10 ++++ flang/test/Fir/convert-to-llvm-openmp-and-fir.fir | 71 +++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 flang/test/Fir/convert-to-llvm-openmp-and-fir.fir diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index 55da2d9..5f65eda 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -23,6 +23,7 @@ #include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h" #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h" #include "mlir/Conversion/LLVMCommon/Pattern.h" +#include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h" #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/Matchers.h" #include "mlir/Pass/Pass.h" @@ -3328,12 +3329,21 @@ public: XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(typeConverter, options); mlir::populateFuncToLLVMConversionPatterns(typeConverter, pattern); + mlir::populateOpenMPToLLVMConversionPatterns(typeConverter, pattern); mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, pattern); mlir::cf::populateControlFlowToLLVMConversionPatterns(typeConverter, pattern); mlir::ConversionTarget target{*context}; target.addLegalDialect(); + // The OpenMP dialect is legal for Operations without regions, for those + // which contains regions it is legal if the region contains only the + // LLVM dialect. + target.addDynamicallyLegalOp([&](Operation *op) { + return typeConverter.isLegal(&op->getRegion(0)); + }); + target.addLegalDialect(); // required NOPs for applying a full conversion target.addLegalOp(); diff --git a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir new file mode 100644 index 0000000..f675b66 --- /dev/null +++ b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir @@ -0,0 +1,71 @@ +// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=aarch64-unknown-linux-gnu" %s | FileCheck %s + +func @_QPsb1(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.ref> {fir.bindc_name = "arr"}) { + %c1_i64 = arith.constant 1 : i64 + %c1_i32 = arith.constant 1 : i32 + %0 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFsbEi"} + omp.parallel { + %1 = fir.alloca i32 {adapt.valuebyref, pinned} + %2 = fir.load %arg0 : !fir.ref + omp.wsloop (%arg2) : i32 = (%c1_i32) to (%2) inclusive step (%c1_i32) nowait { + fir.store %arg2 to %1 : !fir.ref + %3 = fir.load %1 : !fir.ref + %4 = fir.convert %3 : (i32) -> i64 + %5 = arith.subi %4, %c1_i64 : i64 + %6 = fir.coordinate_of %arg1, %5 : (!fir.ref>, i64) -> !fir.ref + fir.store %3 to %6 : !fir.ref + omp.yield + } + omp.terminator + } + return +} + +// CHECK-LABEL: _QPsb1 +// CHECK-SAME: %[[N_REF:.*]]: !llvm.ptr {fir.bindc_name = "n"}, %[[ARR_REF:.*]]: !llvm.ptr {fir.bindc_name = "arr"}) { +// CHECK: %[[ONE_1:.*]] = llvm.mlir.constant(1 : i64) : i64 +// CHECK: %[[ONE_2:.*]] = llvm.mlir.constant(1 : i32) : i32 +// CHECK: omp.parallel { +// CHECK: %[[ONE_3:.*]] = llvm.mlir.constant(1 : i64) : i64 +// CHECK: %[[I_VAR:.*]] = llvm.alloca %[[ONE_3]] x i32 {adapt.valuebyref, in_type = i32, operand_segment_sizes = dense<0> : vector<2xi32>, pinned} : (i64) -> !llvm.ptr +// CHECK: %[[N:.*]] = llvm.load %[[N_REF]] : !llvm.ptr +// CHECK: omp.wsloop (%[[I:.*]]) : i32 = (%[[ONE_2]]) to (%[[N]]) inclusive step (%[[ONE_2]]) nowait { +// CHECK: llvm.store %[[I]], %[[I_VAR]] : !llvm.ptr +// CHECK: %[[I1:.*]] = llvm.load %[[I_VAR]] : !llvm.ptr +// CHECK: %[[I1_EXT:.*]] = llvm.sext %[[I1]] : i32 to i64 +// CHECK: %[[I_CSTYLE:.*]] = llvm.sub %[[I1_EXT]], %[[ONE_1]] : i64 +// CHECK: %[[ARR_I_REF:.*]] = llvm.getelementptr %[[ARR_REF]][%[[I_CSTYLE]]] : (!llvm.ptr, i64) -> !llvm.ptr +// CHECK: llvm.store %[[I1]], %[[ARR_I_REF]] : !llvm.ptr +// CHECK: omp.yield +// CHECK: } +// CHECK: omp.terminator +// CHECK: } +// CHECK: llvm.return +// CHECK: } + +// ----- + +func @_QPsb2(%arg0: !fir.ref {fir.bindc_name = "x"}, %arg1: !fir.ref {fir.bindc_name = "n"}) { + omp.parallel { + omp.master { + %0 = fir.load %arg1 : !fir.ref + fir.store %0 to %arg0 : !fir.ref + omp.terminator + } + omp.terminator + } + return +} + +// CHECK-LABEL: _QPsb2 +// CHECK-SAME: %[[X_REF:.*]]: !llvm.ptr {fir.bindc_name = "x"}, %[[N_REF:.*]]: !llvm.ptr {fir.bindc_name = "n"}) { +// CHECK: omp.parallel { +// CHECK: omp.master { +// CHECK: %[[N:.*]] = llvm.load %[[N_REF]] : !llvm.ptr +// CHECK: llvm.store %[[N]], %[[X_REF]] : !llvm.ptr +// CHECK: omp.terminator +// CHECK: } +// CHECK: omp.terminator +// CHECK: } +// CHECK: llvm.return +// CHECK: } -- 2.7.4