[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 <SourabhSingh.Tomar@amd.com>
Co-authored-by: Eric Schweitz <eschweitz@nvidia.com>
This commit is contained in:
Kiran Chandramohan 2022-03-21 14:09:47 +00:00
parent 7a2e12e0a7
commit c6ac937091
2 changed files with 81 additions and 0 deletions

View file

@ -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<mlir::LLVM::LLVMDialect>();
// 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<mlir::omp::ParallelOp, mlir::omp::WsLoopOp,
mlir::omp::MasterOp>([&](Operation *op) {
return typeConverter.isLegal(&op->getRegion(0));
});
target.addLegalDialect<mlir::omp::OpenMPDialect>();
// required NOPs for applying a full conversion
target.addLegalOp<mlir::ModuleOp>();

View file

@ -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<i32> {fir.bindc_name = "n"}, %arg1: !fir.ref<!fir.array<?xi32>> {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<i32>
omp.wsloop (%arg2) : i32 = (%c1_i32) to (%2) inclusive step (%c1_i32) nowait {
fir.store %arg2 to %1 : !fir.ref<i32>
%3 = fir.load %1 : !fir.ref<i32>
%4 = fir.convert %3 : (i32) -> i64
%5 = arith.subi %4, %c1_i64 : i64
%6 = fir.coordinate_of %arg1, %5 : (!fir.ref<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
fir.store %3 to %6 : !fir.ref<i32>
omp.yield
}
omp.terminator
}
return
}
// CHECK-LABEL: _QPsb1
// CHECK-SAME: %[[N_REF:.*]]: !llvm.ptr<i32> {fir.bindc_name = "n"}, %[[ARR_REF:.*]]: !llvm.ptr<i32> {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<i32>
// CHECK: %[[N:.*]] = llvm.load %[[N_REF]] : !llvm.ptr<i32>
// CHECK: omp.wsloop (%[[I:.*]]) : i32 = (%[[ONE_2]]) to (%[[N]]) inclusive step (%[[ONE_2]]) nowait {
// CHECK: llvm.store %[[I]], %[[I_VAR]] : !llvm.ptr<i32>
// CHECK: %[[I1:.*]] = llvm.load %[[I_VAR]] : !llvm.ptr<i32>
// 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<i32>, i64) -> !llvm.ptr<i32>
// CHECK: llvm.store %[[I1]], %[[ARR_I_REF]] : !llvm.ptr<i32>
// CHECK: omp.yield
// CHECK: }
// CHECK: omp.terminator
// CHECK: }
// CHECK: llvm.return
// CHECK: }
// -----
func @_QPsb2(%arg0: !fir.ref<i32> {fir.bindc_name = "x"}, %arg1: !fir.ref<i32> {fir.bindc_name = "n"}) {
omp.parallel {
omp.master {
%0 = fir.load %arg1 : !fir.ref<i32>
fir.store %0 to %arg0 : !fir.ref<i32>
omp.terminator
}
omp.terminator
}
return
}
// CHECK-LABEL: _QPsb2
// CHECK-SAME: %[[X_REF:.*]]: !llvm.ptr<i32> {fir.bindc_name = "x"}, %[[N_REF:.*]]: !llvm.ptr<i32> {fir.bindc_name = "n"}) {
// CHECK: omp.parallel {
// CHECK: omp.master {
// CHECK: %[[N:.*]] = llvm.load %[[N_REF]] : !llvm.ptr<i32>
// CHECK: llvm.store %[[N]], %[[X_REF]] : !llvm.ptr<i32>
// CHECK: omp.terminator
// CHECK: }
// CHECK: omp.terminator
// CHECK: }
// CHECK: llvm.return
// CHECK: }