[flang-commits] [flang] 411bd2d - [flang][OpenMP] Support lowering parse-tree to MLIR for threadprivate directive
via flang-commits
flang-commits at lists.llvm.org
Tue Jun 7 00:10:22 PDT 2022
Author: Peixin-Qiao
Date: 2022-06-07T15:08:17+08:00
New Revision: 411bd2d40788c8cb869dc4fdc37e01a57213cda9
URL: https://github.com/llvm/llvm-project/commit/411bd2d40788c8cb869dc4fdc37e01a57213cda9
DIFF: https://github.com/llvm/llvm-project/commit/411bd2d40788c8cb869dc4fdc37e01a57213cda9.diff
LOG: [flang][OpenMP] Support lowering parse-tree to MLIR for threadprivate directive
This supports lowering parse-tree to MLIR for threadprivate directive
following the OpenMP 5.1 [2.21.2] standard. Take the following as an
example:
```
program m
integer, save :: i
!$omp threadprivate(i)
call sub(i)
!$omp parallel
call sub(i)
!$omp end parallel
end
```
```
func.func @_QQmain() {
%0 = fir.address_of(@_QFEi) : !fir.ref<i32>
%1 = omp.threadprivate %0 : !fir.ref<i32> -> !fir.ref<i32>
fir.call @_QPsub(%1) : (!fir.ref<i32>) -> ()
omp.parallel {
%2 = omp.threadprivate %0 : !fir.ref<i32> -> !fir.ref<i32>
fir.call @_QPsub(%2) : (!fir.ref<i32>) -> ()
omp.terminator
}
return
}
```
A threadprivate operation (omp.threadprivate) is created for all
references to a threadprivate variable. The runtime will appropriately
return a threadprivate var (%1 as above) or its copy (%2 as above)
depending on whether it is outside or inside a parallel region. For
threadprivate access outside the parallel region, the threadprivate
operation is created in instantiateVar. Inside the parallel region, it
is created in createBodyOfOp.
One new utility function collectSymbolSet is created for collecting
all the variables with a property within a evaluation, which may be one
Fortran, or OpenMP, or OpenACC construct.
Reviewed By: kiranchandramohan
Differential Revision: https://reviews.llvm.org/D124226
Added:
flang/test/Lower/OpenMP/threadprivate-char-array-chararray.f90
flang/test/Lower/OpenMP/threadprivate-commonblock.f90
flang/test/Lower/OpenMP/threadprivate-integer-different-kinds.f90
flang/test/Lower/OpenMP/threadprivate-pointer-allocatable.f90
flang/test/Lower/OpenMP/threadprivate-real-logical-complex-derivedtype.f90
flang/test/Lower/OpenMP/threadprivate-use-association.f90
Modified:
flang/include/flang/Lower/AbstractConverter.h
flang/include/flang/Lower/OpenMP.h
flang/include/flang/Lower/PFTBuilder.h
flang/lib/Lower/Bridge.cpp
flang/lib/Lower/OpenMP.cpp
flang/lib/Lower/PFTBuilder.cpp
Removed:
flang/test/Lower/OpenMP/Todo/omp-threadprivate.f90
################################################################################
diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h
index 52c9c282192a6..525d4e4473639 100644
--- a/flang/include/flang/Lower/AbstractConverter.h
+++ b/flang/include/flang/Lower/AbstractConverter.h
@@ -16,6 +16,7 @@
#include "flang/Common/Fortran.h"
#include "flang/Lower/PFTDefs.h"
#include "flang/Optimizer/Builder/BoxValue.h"
+#include "flang/Semantics/symbol.h"
#include "mlir/IR/BuiltinOps.h"
#include "llvm/ADT/ArrayRef.h"
@@ -76,6 +77,9 @@ class AbstractConverter {
/// Get the mlir instance of a symbol.
virtual mlir::Value getSymbolAddress(SymbolRef sym) = 0;
+ virtual fir::ExtendedValue
+ getSymbolExtendedValue(const Fortran::semantics::Symbol &sym) = 0;
+
/// Get the binding of an implied do variable by name.
virtual mlir::Value impliedDoBinding(llvm::StringRef name) = 0;
@@ -99,6 +103,12 @@ class AbstractConverter {
virtual void copyHostAssociateVar(const Fortran::semantics::Symbol &sym) = 0;
+ /// Collect the set of symbols flagged as \p flag in \p eval region.
+ virtual void collectSymbolSet(
+ pft::Evaluation &eval,
+ llvm::SetVector<const Fortran::semantics::Symbol *> &symbolSet,
+ Fortran::semantics::Symbol::Flag flag) = 0;
+
//===--------------------------------------------------------------------===//
// Expressions
//===--------------------------------------------------------------------===//
diff --git a/flang/include/flang/Lower/OpenMP.h b/flang/include/flang/Lower/OpenMP.h
index c666376c2030f..12cb5f600e414 100644
--- a/flang/include/flang/Lower/OpenMP.h
+++ b/flang/include/flang/Lower/OpenMP.h
@@ -29,6 +29,7 @@ class AbstractConverter;
namespace pft {
struct Evaluation;
+struct Variable;
} // namespace pft
void genOpenMPConstruct(AbstractConverter &, pft::Evaluation &,
@@ -36,6 +37,7 @@ void genOpenMPConstruct(AbstractConverter &, pft::Evaluation &,
void genOpenMPDeclarativeConstruct(AbstractConverter &, pft::Evaluation &,
const parser::OpenMPDeclarativeConstruct &);
int64_t getCollapseValue(const Fortran::parser::OmpClauseList &clauseList);
+void genThreadprivateOp(AbstractConverter &, const pft::Variable &);
} // namespace lower
} // namespace Fortran
diff --git a/flang/include/flang/Lower/PFTBuilder.h b/flang/include/flang/Lower/PFTBuilder.h
index 2fcbdcadeea1e..933d50a0c015b 100644
--- a/flang/include/flang/Lower/PFTBuilder.h
+++ b/flang/include/flang/Lower/PFTBuilder.h
@@ -782,6 +782,11 @@ ParentType *getAncestor(A &node) {
void visitAllSymbols(const FunctionLikeUnit &funit,
std::function<void(const semantics::Symbol &)> callBack);
+/// Call the provided \p callBack on all symbols that are referenced inside \p
+/// eval region.
+void visitAllSymbols(const Evaluation &eval,
+ std::function<void(const semantics::Symbol &)> callBack);
+
} // namespace Fortran::lower::pft
namespace Fortran::lower {
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index a1100ac0afe36..f81456bc601a7 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -313,6 +313,13 @@ class FirConverter : public Fortran::lower::AbstractConverter {
return lookupSymbol(sym).getAddr();
}
+ fir::ExtendedValue
+ getSymbolExtendedValue(const Fortran::semantics::Symbol &sym) override final {
+ Fortran::lower::SymbolBox sb = localSymbols.lookupSymbol(sym);
+ assert(sb && "symbol box not found");
+ return sb.toExtendedValue();
+ }
+
mlir::Value impliedDoBinding(llvm::StringRef name) override final {
mlir::Value val = localSymbols.lookupImpliedDo(name);
if (!val)
@@ -500,6 +507,18 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// Utility methods
//===--------------------------------------------------------------------===//
+ void collectSymbolSet(
+ Fortran::lower::pft::Evaluation &eval,
+ llvm::SetVector<const Fortran::semantics::Symbol *> &symbolSet,
+ Fortran::semantics::Symbol::Flag flag) override final {
+ auto addToList = [&](const Fortran::semantics::Symbol &sym) {
+ const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
+ if (ultimate.test(flag))
+ symbolSet.insert(&ultimate);
+ };
+ Fortran::lower::pft::visitAllSymbols(eval, addToList);
+ }
+
mlir::Location getCurrentLocation() override final { return toLocation(); }
/// Generate a dummy location.
@@ -2447,6 +2466,10 @@ class FirConverter : public Fortran::lower::AbstractConverter {
void instantiateVar(const Fortran::lower::pft::Variable &var,
Fortran::lower::AggregateStoreMap &storeMap) {
Fortran::lower::instantiateVariable(*this, var, localSymbols, storeMap);
+ if (var.hasSymbol() &&
+ var.getSymbol().test(
+ Fortran::semantics::Symbol::Flag::OmpThreadprivate))
+ Fortran::lower::genThreadprivateOp(*this, var);
}
/// Prepare to translate a new function
diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index 32dd399dfa8de..d53617c7bd59d 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -91,6 +91,103 @@ static void privatizeVars(Fortran::lower::AbstractConverter &converter,
firOpBuilder.restoreInsertionPoint(insPt);
}
+/// The COMMON block is a global structure. \p commonValue is the base address
+/// of the the COMMON block. As the offset from the symbol \p sym, generate the
+/// COMMON block member value (commonValue + offset) for the symbol.
+/// FIXME: Share the code with `instantiateCommon` in ConvertVariable.cpp.
+static mlir::Value
+genCommonBlockMember(Fortran::lower::AbstractConverter &converter,
+ const Fortran::semantics::Symbol &sym,
+ mlir::Value commonValue) {
+ auto &firOpBuilder = converter.getFirOpBuilder();
+ mlir::Location currentLocation = converter.getCurrentLocation();
+ mlir::IntegerType i8Ty = firOpBuilder.getIntegerType(8);
+ mlir::Type i8Ptr = firOpBuilder.getRefType(i8Ty);
+ mlir::Type seqTy = firOpBuilder.getRefType(firOpBuilder.getVarLenSeqTy(i8Ty));
+ mlir::Value base =
+ firOpBuilder.createConvert(currentLocation, seqTy, commonValue);
+ std::size_t byteOffset = sym.GetUltimate().offset();
+ mlir::Value offs = firOpBuilder.createIntegerConstant(
+ currentLocation, firOpBuilder.getIndexType(), byteOffset);
+ mlir::Value varAddr = firOpBuilder.create<fir::CoordinateOp>(
+ currentLocation, i8Ptr, base, mlir::ValueRange{offs});
+ mlir::Type symType = converter.genType(sym);
+ return firOpBuilder.createConvert(currentLocation,
+ firOpBuilder.getRefType(symType), varAddr);
+}
+
+// Get the extended value for \p val by extracting additional variable
+// information from \p base.
+static fir::ExtendedValue getExtendedValue(fir::ExtendedValue base,
+ mlir::Value val) {
+ return base.match(
+ [&](const fir::MutableBoxValue &box) -> fir::ExtendedValue {
+ return fir::MutableBoxValue(val, box.nonDeferredLenParams(), {});
+ },
+ [&](const auto &) -> fir::ExtendedValue {
+ return fir::substBase(base, val);
+ });
+}
+
+static void threadPrivatizeVars(Fortran::lower::AbstractConverter &converter,
+ Fortran::lower::pft::Evaluation &eval) {
+ auto &firOpBuilder = converter.getFirOpBuilder();
+ mlir::Location currentLocation = converter.getCurrentLocation();
+ auto insPt = firOpBuilder.saveInsertionPoint();
+ firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock());
+
+ // Get the original ThreadprivateOp corresponding to the symbol and use the
+ // symbol value from that opeartion to create one ThreadprivateOp copy
+ // operation inside the parallel region.
+ auto genThreadprivateOp = [&](Fortran::lower::SymbolRef sym) -> mlir::Value {
+ mlir::Value symOriThreadprivateValue = converter.getSymbolAddress(sym);
+ mlir::Operation *op = symOriThreadprivateValue.getDefiningOp();
+ assert(mlir::isa<mlir::omp::ThreadprivateOp>(op) &&
+ "The threadprivate operation not created");
+ mlir::Value symValue =
+ mlir::dyn_cast<mlir::omp::ThreadprivateOp>(op).sym_addr();
+ return firOpBuilder.create<mlir::omp::ThreadprivateOp>(
+ currentLocation, symValue.getType(), symValue);
+ };
+
+ llvm::SetVector<const Fortran::semantics::Symbol *> threadprivateSyms;
+ converter.collectSymbolSet(
+ eval, threadprivateSyms,
+ Fortran::semantics::Symbol::Flag::OmpThreadprivate);
+
+ // For a COMMON block, the ThreadprivateOp is generated for itself instead of
+ // its members, so only bind the value of the new copied ThreadprivateOp
+ // inside the parallel region to the common block symbol only once for
+ // multiple members in one COMMON block.
+ llvm::SetVector<const Fortran::semantics::Symbol *> commonSyms;
+ for (std::size_t i = 0; i < threadprivateSyms.size(); i++) {
+ auto sym = threadprivateSyms[i];
+ mlir::Value symThreadprivateValue;
+ if (const Fortran::semantics::Symbol *common =
+ Fortran::semantics::FindCommonBlockContaining(sym->GetUltimate())) {
+ mlir::Value commonThreadprivateValue;
+ if (commonSyms.contains(common)) {
+ commonThreadprivateValue = converter.getSymbolAddress(*common);
+ } else {
+ commonThreadprivateValue = genThreadprivateOp(*common);
+ converter.bindSymbol(*common, commonThreadprivateValue);
+ commonSyms.insert(common);
+ }
+ symThreadprivateValue =
+ genCommonBlockMember(converter, *sym, commonThreadprivateValue);
+ } else {
+ symThreadprivateValue = genThreadprivateOp(*sym);
+ }
+
+ fir::ExtendedValue sexv = converter.getSymbolExtendedValue(*sym);
+ fir::ExtendedValue symThreadprivateExv =
+ getExtendedValue(sexv, symThreadprivateValue);
+ converter.bindSymbol(*sym, symThreadprivateExv);
+ }
+
+ firOpBuilder.restoreInsertionPoint(insPt);
+}
+
static void genObjectList(const Fortran::parser::OmpObjectList &objectList,
Fortran::lower::AbstractConverter &converter,
llvm::SmallVectorImpl<Value> &operands) {
@@ -243,6 +340,9 @@ createBodyOfOp(Op &op, Fortran::lower::AbstractConverter &converter,
// Handle privatization. Do not privatize if this is the outer operation.
if (clauses && !outerCombined)
privatizeVars(converter, *clauses);
+
+ if (std::is_same_v<Op, omp::ParallelOp>)
+ threadPrivatizeVars(converter, eval);
}
static void genOMP(Fortran::lower::AbstractConverter &converter,
@@ -993,6 +1093,42 @@ void Fortran::lower::genOpenMPConstruct(
ompConstruct.u);
}
+void Fortran::lower::genThreadprivateOp(
+ Fortran::lower::AbstractConverter &converter,
+ const Fortran::lower::pft::Variable &var) {
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+ mlir::Location currentLocation = converter.getCurrentLocation();
+
+ const Fortran::semantics::Symbol &sym = var.getSymbol();
+ mlir::Value symThreadprivateValue;
+ if (const Fortran::semantics::Symbol *common =
+ Fortran::semantics::FindCommonBlockContaining(sym.GetUltimate())) {
+ mlir::Value commonValue = converter.getSymbolAddress(*common);
+ if (mlir::isa<mlir::omp::ThreadprivateOp>(commonValue.getDefiningOp())) {
+ // Generate ThreadprivateOp for a common block instead of its members and
+ // only do it once for a common block.
+ return;
+ }
+ // Generate ThreadprivateOp and rebind the common block.
+ mlir::Value commonThreadprivateValue =
+ firOpBuilder.create<mlir::omp::ThreadprivateOp>(
+ currentLocation, commonValue.getType(), commonValue);
+ converter.bindSymbol(*common, commonThreadprivateValue);
+ // Generate the threadprivate value for the common block member.
+ symThreadprivateValue =
+ genCommonBlockMember(converter, sym, commonThreadprivateValue);
+ } else {
+ mlir::Value symValue = converter.getSymbolAddress(sym);
+ symThreadprivateValue = firOpBuilder.create<mlir::omp::ThreadprivateOp>(
+ currentLocation, symValue.getType(), symValue);
+ }
+
+ fir::ExtendedValue sexv = converter.getSymbolExtendedValue(sym);
+ fir::ExtendedValue symThreadprivateExv =
+ getExtendedValue(sexv, symThreadprivateValue);
+ converter.bindSymbol(sym, symThreadprivateExv);
+}
+
void Fortran::lower::genOpenMPDeclarativeConstruct(
Fortran::lower::AbstractConverter &converter,
Fortran::lower::pft::Evaluation &eval,
@@ -1019,7 +1155,8 @@ void Fortran::lower::genOpenMPDeclarativeConstruct(
"OpenMPDeclareTargetConstruct");
},
[&](const Fortran::parser::OpenMPThreadprivate &threadprivate) {
- TODO(converter.getCurrentLocation(), "OpenMPThreadprivate");
+ // The directive is lowered when instantiating the variable to
+ // support the case of threadprivate variable declared in module.
},
},
ompDeclConstruct.u);
diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp
index 70774425760a6..ca0df83997890 100644
--- a/flang/lib/Lower/PFTBuilder.cpp
+++ b/flang/lib/Lower/PFTBuilder.cpp
@@ -1809,3 +1809,12 @@ void Fortran::lower::pft::visitAllSymbols(
parser::Walk(functionParserNode, visitor);
});
}
+
+void Fortran::lower::pft::visitAllSymbols(
+ const Fortran::lower::pft::Evaluation &eval,
+ const std::function<void(const Fortran::semantics::Symbol &)> callBack) {
+ SymbolVisitor visitor{callBack};
+ eval.visit([&](const auto &functionParserNode) {
+ parser::Walk(functionParserNode, visitor);
+ });
+}
diff --git a/flang/test/Lower/OpenMP/Todo/omp-threadprivate.f90 b/flang/test/Lower/OpenMP/Todo/omp-threadprivate.f90
deleted file mode 100644
index da1981a299b71..0000000000000
--- a/flang/test/Lower/OpenMP/Todo/omp-threadprivate.f90
+++ /dev/null
@@ -1,10 +0,0 @@
-! This test checks lowering of OpenMP threadprivate Directive.
-
-// RUN: not flang-new -fc1 -emit-fir -fopenmp %s 2>&1 | FileCheck %s
-
-program main
- integer, save :: x, y
-
-// CHECK: not yet implemented: OpenMPThreadprivate
- !$omp threadprivate(x, y)
-end
diff --git a/flang/test/Lower/OpenMP/threadprivate-char-array-chararray.f90 b/flang/test/Lower/OpenMP/threadprivate-char-array-chararray.f90
new file mode 100644
index 0000000000000..c9aceaa813bec
--- /dev/null
+++ b/flang/test/Lower/OpenMP/threadprivate-char-array-chararray.f90
@@ -0,0 +1,46 @@
+! This test checks lowering of OpenMP Threadprivate Directive.
+! Test for character, array, and character array.
+
+!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s
+
+module test
+ character :: x
+ integer :: y(5)
+ character(5) :: z(5)
+
+ !$omp threadprivate(x, y, z)
+
+!CHECK-DAG: fir.global @_QMtestEx : !fir.char<1> {
+!CHECK-DAG: fir.global @_QMtestEy : !fir.array<5xi32> {
+!CHECK-DAG: fir.global @_QMtestEz : !fir.array<5x!fir.char<1,5>> {
+
+contains
+ subroutine sub()
+!CHECK-DAG: [[ADDR0:%.*]] = fir.address_of(@_QMtestEx) : !fir.ref<!fir.char<1>>
+!CHECK-DAG: [[NEWADDR0:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<!fir.char<1>> -> !fir.ref<!fir.char<1>>
+!CHECK-DAG: [[ADDR1:%.*]] = fir.address_of(@_QMtestEy) : !fir.ref<!fir.array<5xi32>>
+!CHECK-DAG: [[NEWADDR1:%.*]] = omp.threadprivate [[ADDR1]] : !fir.ref<!fir.array<5xi32>> -> !fir.ref<!fir.array<5xi32>>
+!CHECK-DAG: [[ADDR2:%.*]] = fir.address_of(@_QMtestEz) : !fir.ref<!fir.array<5x!fir.char<1,5>>>
+!CHECK-DAG: [[NEWADDR2:%.*]] = omp.threadprivate [[ADDR2]] : !fir.ref<!fir.array<5x!fir.char<1,5>>> -> !fir.ref<!fir.array<5x!fir.char<1,5>>>
+!CHECK-DAG: %{{.*}} = fir.convert [[NEWADDR0]] : (!fir.ref<!fir.char<1>>) -> !fir.ref<i8>
+!CHECK-DAG: %{{.*}} = fir.embox [[NEWADDR1]](%{{.*}}) : (!fir.ref<!fir.array<5xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<5xi32>>
+!CHECK-DAG: %{{.*}} = fir.embox [[NEWADDR2]](%{{.*}}) : (!fir.ref<!fir.array<5x!fir.char<1,5>>>, !fir.shape<1>) -> !fir.box<!fir.array<5x!fir.char<1,5>>>
+ print *, x, y, z
+
+ !$omp parallel
+!CHECK-DAG: [[ADDR33:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<!fir.char<1>> -> !fir.ref<!fir.char<1>>
+!CHECK-DAG: [[ADDR34:%.*]] = omp.threadprivate [[ADDR1]] : !fir.ref<!fir.array<5xi32>> -> !fir.ref<!fir.array<5xi32>>
+!CHECK-DAG: [[ADDR35:%.*]] = omp.threadprivate [[ADDR2]] : !fir.ref<!fir.array<5x!fir.char<1,5>>> -> !fir.ref<!fir.array<5x!fir.char<1,5>>>
+!CHECK-DAG: %{{.*}} = fir.convert [[ADDR33]] : (!fir.ref<!fir.char<1>>) -> !fir.ref<i8>
+!CHECK-DAG: %{{.*}} = fir.embox [[ADDR34]](%{{.*}}) : (!fir.ref<!fir.array<5xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<5xi32>>
+!CHECK-DAG: %{{.*}} = fir.embox [[ADDR35]](%{{.*}}) : (!fir.ref<!fir.array<5x!fir.char<1,5>>>, !fir.shape<1>) -> !fir.box<!fir.array<5x!fir.char<1,5>>>
+ print *, x, y, z
+ !$omp end parallel
+
+!CHECK-DAG: %{{.*}} = fir.convert [[NEWADDR0]] : (!fir.ref<!fir.char<1>>) -> !fir.ref<i8>
+!CHECK-DAG: %{{.*}} = fir.embox [[NEWADDR1]](%{{.*}}) : (!fir.ref<!fir.array<5xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<5xi32>>
+!CHECK-DAG: %{{.*}} = fir.embox [[NEWADDR2]](%{{.*}}) : (!fir.ref<!fir.array<5x!fir.char<1,5>>>, !fir.shape<1>) -> !fir.box<!fir.array<5x!fir.char<1,5>>>
+ print *, x, y, z
+
+ end
+end
diff --git a/flang/test/Lower/OpenMP/threadprivate-commonblock.f90 b/flang/test/Lower/OpenMP/threadprivate-commonblock.f90
new file mode 100644
index 0000000000000..39ea0c1cbd266
--- /dev/null
+++ b/flang/test/Lower/OpenMP/threadprivate-commonblock.f90
@@ -0,0 +1,91 @@
+! This test checks lowering of OpenMP Threadprivate Directive.
+! Test for common block.
+
+!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s
+
+module test
+ integer:: a
+ real :: b(2)
+ complex, pointer :: c, d(:)
+ character(5) :: e, f(2)
+ common /blk/ a, b, c, d, e, f
+
+ !$omp threadprivate(/blk/)
+
+!CHECK: fir.global common @_QBblk(dense<0> : vector<103xi8>) : !fir.array<103xi8>
+
+contains
+ subroutine sub()
+!CHECK: [[ADDR0:%.*]] = fir.address_of(@_QBblk) : !fir.ref<!fir.array<103xi8>>
+!CHECK: [[NEWADDR0:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<!fir.array<103xi8>> -> !fir.ref<!fir.array<103xi8>>
+!CHECK-DAG: [[ADDR1:%.*]] = fir.convert [[NEWADDR0]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[C0:%.*]] = arith.constant 0 : index
+!CHECK-DAG: [[ADDR2:%.*]] = fir.coordinate_of [[ADDR1]], [[C0]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR3:%.*]] = fir.convert [[ADDR2]] : (!fir.ref<i8>) -> !fir.ref<i32>
+!CHECK-DAG: [[ADDR4:%.*]] = fir.convert [[NEWADDR0]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[C1:%.*]] = arith.constant 4 : index
+!CHECK-DAG: [[ADDR5:%.*]] = fir.coordinate_of [[ADDR4]], [[C1]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR6:%.*]] = fir.convert [[ADDR5]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<2xf32>>
+!CHECK-DAG: [[ADDR7:%.*]] = fir.convert [[NEWADDR0]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[C2:%.*]] = arith.constant 16 : index
+!CHECK-DAG: [[ADDR8:%.*]] = fir.coordinate_of [[ADDR7]], [[C2]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR9:%.*]] = fir.convert [[ADDR8]] : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<!fir.complex<4>>>>
+!CHECK-DAG: [[ADDR10:%.*]] = fir.convert [[NEWADDR0]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[C3:%.*]] = arith.constant 40 : index
+!CHECK-DAG: [[ADDR11:%.*]] = fir.coordinate_of [[ADDR10]], [[C3]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR12:%.*]] = fir.convert [[ADDR11]] : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.complex<4>>>>>
+!CHECK-DAG: [[ADDR13:%.*]] = fir.convert [[NEWADDR0]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[C4:%.*]] = arith.constant 88 : index
+!CHECK-DAG: [[ADDR14:%.*]] = fir.coordinate_of [[ADDR13]], [[C4]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR15:%.*]] = fir.convert [[ADDR14]] : (!fir.ref<i8>) -> !fir.ref<!fir.char<1,5>>
+!CHECK-DAG: [[ADDR16:%.*]] = fir.convert [[NEWADDR0]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[C5:%.*]] = arith.constant 93 : index
+!CHECK-DAG: [[ADDR17:%.*]] = fir.coordinate_of [[ADDR16]], [[C5]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR18:%.*]] = fir.convert [[ADDR17]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<2x!fir.char<1,5>>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR3]] : !fir.ref<i32>
+!CHECK-DAG: %{{.*}} = fir.embox [[ADDR6]](%{{.*}}) : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<2xf32>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR9]] : !fir.ref<!fir.box<!fir.ptr<!fir.complex<4>>>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR12]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.complex<4>>>>>
+!CHECK-DAG: %{{.*}} = fir.convert [[ADDR15]] : (!fir.ref<!fir.char<1,5>>) -> !fir.ref<i8>
+!CHECK-DAG: %{{.*}} = fir.embox [[ADDR18]](%{{.*}}) : (!fir.ref<!fir.array<2x!fir.char<1,5>>>, !fir.shape<1>) -> !fir.box<!fir.array<2x!fir.char<1,5>>>
+ print *, a, b, c, d, e, f
+
+ !$omp parallel
+!CHECK: [[ADDR77:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<!fir.array<103xi8>> -> !fir.ref<!fir.array<103xi8>>
+!CHECK-DAG: [[ADDR78:%.*]] = fir.convert [[ADDR77]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[ADDR79:%.*]] = fir.coordinate_of [[ADDR78]], [[C0:%.*]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR80:%.*]] = fir.convert [[ADDR79:%.*]] : (!fir.ref<i8>) -> !fir.ref<i32>
+!CHECK-DAG: [[ADDR81:%.*]] = fir.convert [[ADDR77]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[ADDR82:%.*]] = fir.coordinate_of [[ADDR81]], [[C1:%.*]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR83:%.*]] = fir.convert [[ADDR82:%.*]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<2xf32>>
+!CHECK-DAG: [[ADDR84:%.*]] = fir.convert [[ADDR77]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[ADDR85:%.*]] = fir.coordinate_of [[ADDR84]], [[C2:%.*]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR86:%.*]] = fir.convert [[ADDR85:%.*]] : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<!fir.complex<4>>>>
+!CHECK-DAG: [[ADDR87:%.*]] = fir.convert [[ADDR77]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[ADDR88:%.*]] = fir.coordinate_of [[ADDR87]], [[C3:%.*]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR89:%.*]] = fir.convert [[ADDR88:%.*]] : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.complex<4>>>>>
+!CHECK-DAG: [[ADDR90:%.*]] = fir.convert [[ADDR77]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[ADDR91:%.*]] = fir.coordinate_of [[ADDR90]], [[C4:%.*]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR92:%.*]] = fir.convert [[ADDR91:%.*]] : (!fir.ref<i8>) -> !fir.ref<!fir.char<1,5>>
+!CHECK-DAG: [[ADDR93:%.*]] = fir.convert [[ADDR77]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[ADDR94:%.*]] = fir.coordinate_of [[ADDR93]], [[C5:%.*]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR95:%.*]] = fir.convert [[ADDR94:%.*]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<2x!fir.char<1,5>>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR80]] : !fir.ref<i32>
+!CHECK-DAG: %{{.*}} = fir.embox [[ADDR83]](%{{.*}}) : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<2xf32>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR86]] : !fir.ref<!fir.box<!fir.ptr<!fir.complex<4>>>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR89]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.complex<4>>>>>
+!CHECK-DAG: %{{.*}} = fir.convert [[ADDR92]] : (!fir.ref<!fir.char<1,5>>) -> !fir.ref<i8>
+!CHECK-DAG: %{{.*}} = fir.embox [[ADDR95]](%{{.*}}) : (!fir.ref<!fir.array<2x!fir.char<1,5>>>, !fir.shape<1>) -> !fir.box<!fir.array<2x!fir.char<1,5>>>
+ print *, a, b, c, d, e, f
+ !$omp end parallel
+
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR3]] : !fir.ref<i32>
+!CHECK-DAG: %{{.*}} = fir.embox [[ADDR6]](%{{.*}}) : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<2xf32>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR9]] : !fir.ref<!fir.box<!fir.ptr<!fir.complex<4>>>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR12]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.complex<4>>>>>
+!CHECK-DAG: %{{.*}} = fir.convert [[ADDR15]] : (!fir.ref<!fir.char<1,5>>) -> !fir.ref<i8>
+!CHECK-DAG: %{{.*}} = fir.embox [[ADDR18]](%{{.*}}) : (!fir.ref<!fir.array<2x!fir.char<1,5>>>, !fir.shape<1>) -> !fir.box<!fir.array<2x!fir.char<1,5>>>
+ print *, a, b, c, d, e, f
+
+ end
+end
diff --git a/flang/test/Lower/OpenMP/threadprivate-integer-
diff erent-kinds.f90 b/flang/test/Lower/OpenMP/threadprivate-integer-
diff erent-kinds.f90
new file mode 100644
index 0000000000000..a403f181afe37
--- /dev/null
+++ b/flang/test/Lower/OpenMP/threadprivate-integer-
diff erent-kinds.f90
@@ -0,0 +1,67 @@
+! This test checks lowering of OpenMP Threadprivate Directive.
+! Test for variables with
diff erent kind.
+
+!REQUIRES: shell
+!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s
+
+program test
+ integer, save :: i
+ integer(kind=1), save :: i1
+ integer(kind=2), save :: i2
+ integer(kind=4), save :: i4
+ integer(kind=8), save :: i8
+ integer(kind=16), save :: i16
+
+!CHECK-DAG: [[ADDR0:%.*]] = fir.address_of(@_QFEi) : !fir.ref<i32>
+!CHECK-DAG: [[NEWADDR0:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<i32> -> !fir.ref<i32>
+!CHECK-DAG: [[ADDR1:%.*]] = fir.address_of(@_QFEi1) : !fir.ref<i8>
+!CHECK-DAG: [[NEWADDR1:%.*]] = omp.threadprivate [[ADDR1]] : !fir.ref<i8> -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR2:%.*]] = fir.address_of(@_QFEi16) : !fir.ref<i128>
+!CHECK-DAG: [[NEWADDR2:%.*]] = omp.threadprivate [[ADDR2]] : !fir.ref<i128> -> !fir.ref<i128>
+!CHECK-DAG: [[ADDR3:%.*]] = fir.address_of(@_QFEi2) : !fir.ref<i16>
+!CHECK-DAG: [[NEWADDR3:%.*]] = omp.threadprivate [[ADDR3]] : !fir.ref<i16> -> !fir.ref<i16>
+!CHECK-DAG: [[ADDR4:%.*]] = fir.address_of(@_QFEi4) : !fir.ref<i32>
+!CHECK-DAG: [[NEWADDR4:%.*]] = omp.threadprivate [[ADDR4]] : !fir.ref<i32> -> !fir.ref<i32>
+!CHECK-DAG: [[ADDR5:%.*]] = fir.address_of(@_QFEi8) : !fir.ref<i64>
+!CHECK-DAG: [[NEWADDR5:%.*]] = omp.threadprivate [[ADDR5]] : !fir.ref<i64> -> !fir.ref<i64>
+ !$omp threadprivate(i, i1, i2, i4, i8, i16)
+
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR0]] : !fir.ref<i32>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR1]] : !fir.ref<i8>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR2]] : !fir.ref<i128>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR3]] : !fir.ref<i16>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR4]] : !fir.ref<i32>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR5]] : !fir.ref<i64>
+ print *, i, i1, i2, i4, i8, i16
+
+ !$omp parallel
+!CHECK-DAG: [[ADDR39:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<i32> -> !fir.ref<i32>
+!CHECK-DAG: [[ADDR40:%.*]] = omp.threadprivate [[ADDR1]] : !fir.ref<i8> -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR41:%.*]] = omp.threadprivate [[ADDR2]] : !fir.ref<i128> -> !fir.ref<i128>
+!CHECK-DAG: [[ADDR42:%.*]] = omp.threadprivate [[ADDR3]] : !fir.ref<i16> -> !fir.ref<i16>
+!CHECK-DAG: [[ADDR43:%.*]] = omp.threadprivate [[ADDR4]] : !fir.ref<i32> -> !fir.ref<i32>
+!CHECK-DAG: [[ADDR44:%.*]] = omp.threadprivate [[ADDR5]] : !fir.ref<i64> -> !fir.ref<i64>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR39]] : !fir.ref<i32>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR40]] : !fir.ref<i8>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR41]] : !fir.ref<i128>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR42]] : !fir.ref<i16>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR43]] : !fir.ref<i32>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR44]] : !fir.ref<i64>
+ print *, i, i1, i2, i4, i8, i16
+ !$omp end parallel
+
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR0]] : !fir.ref<i32>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR1]] : !fir.ref<i8>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR2]] : !fir.ref<i128>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR3]] : !fir.ref<i16>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR4]] : !fir.ref<i32>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR5]] : !fir.ref<i64>
+ print *, i, i1, i2, i4, i8, i16
+
+!CHECK-DAG: fir.global internal @_QFEi : i32 {
+!CHECK-DAG: fir.global internal @_QFEi1 : i8 {
+!CHECK-DAG: fir.global internal @_QFEi16 : i128 {
+!CHECK-DAG: fir.global internal @_QFEi2 : i16 {
+!CHECK-DAG: fir.global internal @_QFEi4 : i32 {
+!CHECK-DAG: fir.global internal @_QFEi8 : i64 {
+end
diff --git a/flang/test/Lower/OpenMP/threadprivate-pointer-allocatable.f90 b/flang/test/Lower/OpenMP/threadprivate-pointer-allocatable.f90
new file mode 100644
index 0000000000000..31f9e061c2de1
--- /dev/null
+++ b/flang/test/Lower/OpenMP/threadprivate-pointer-allocatable.f90
@@ -0,0 +1,51 @@
+! This test checks lowering of OpenMP Threadprivate Directive.
+! Test for allocatable and pointer variables.
+
+!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s
+
+module test
+ integer, pointer :: x(:), m
+ real, allocatable :: y(:), n
+
+ !$omp threadprivate(x, y, m, n)
+
+!CHECK-DAG: fir.global @_QMtestEm : !fir.box<!fir.ptr<i32>> {
+!CHECK-DAG: fir.global @_QMtestEn : !fir.box<!fir.heap<f32>> {
+!CHECK-DAG: fir.global @_QMtestEx : !fir.box<!fir.ptr<!fir.array<?xi32>>> {
+!CHECK-DAG: fir.global @_QMtestEy : !fir.box<!fir.heap<!fir.array<?xf32>>> {
+
+contains
+ subroutine sub()
+!CHECK-DAG: [[ADDR0:%.*]] = fir.address_of(@_QMtestEm) : !fir.ref<!fir.box<!fir.ptr<i32>>>
+!CHECK-DAG: [[NEWADDR0:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<!fir.box<!fir.ptr<i32>>> -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+!CHECK-DAG: [[ADDR1:%.*]] = fir.address_of(@_QMtestEn) : !fir.ref<!fir.box<!fir.heap<f32>>>
+!CHECK-DAG: [[NEWADDR1:%.*]] = omp.threadprivate [[ADDR1]] : !fir.ref<!fir.box<!fir.heap<f32>>> -> !fir.ref<!fir.box<!fir.heap<f32>>>
+!CHECK-DAG: [[ADDR2:%.*]] = fir.address_of(@_QMtestEx) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+!CHECK-DAG: [[NEWADDR2:%.*]] = omp.threadprivate [[ADDR2]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>> -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+!CHECK-DAG: [[ADDR3:%.*]] = fir.address_of(@_QMtestEy) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+!CHECK-DAG: [[NEWADDR3:%.*]] = omp.threadprivate [[ADDR3]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR2]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR3]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR0]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR1]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ print *, x, y, m, n
+
+ !$omp parallel
+!CHECK-DAG: [[ADDR54:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<!fir.box<!fir.ptr<i32>>> -> !fir.ref<!fir.box<!fir.ptr<i32>>>
+!CHECK-DAG: [[ADDR55:%.*]] = omp.threadprivate [[ADDR1]] : !fir.ref<!fir.box<!fir.heap<f32>>> -> !fir.ref<!fir.box<!fir.heap<f32>>>
+!CHECK-DAG: [[ADDR56:%.*]] = omp.threadprivate [[ADDR2]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>> -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+!CHECK-DAG: [[ADDR57:%.*]] = omp.threadprivate [[ADDR3]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR56]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR57]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR54]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR55]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ print *, x, y, m, n
+ !$omp end parallel
+
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR2]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR3]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR0]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR1]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ print *, x, y, m, n
+ end
+end
diff --git a/flang/test/Lower/OpenMP/threadprivate-real-logical-complex-derivedtype.f90 b/flang/test/Lower/OpenMP/threadprivate-real-logical-complex-derivedtype.f90
new file mode 100644
index 0000000000000..eda6a729428b4
--- /dev/null
+++ b/flang/test/Lower/OpenMP/threadprivate-real-logical-complex-derivedtype.f90
@@ -0,0 +1,58 @@
+! This test checks lowering of OpenMP Threadprivate Directive.
+! Test for real, logical, complex, and derived type.
+
+!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s
+
+module test
+ type my_type
+ integer :: t_i
+ real :: t_arr(5)
+ end type my_type
+ real :: x
+ complex :: y
+ logical :: z
+ type(my_type) :: t
+
+ !$omp threadprivate(x, y, z, t)
+
+!CHECK-DAG: fir.global @_QMtestEt : !fir.type<_QMtestTmy_type{t_i:i32,t_arr:!fir.array<5xf32>}> {
+!CHECK-DAG: fir.global @_QMtestEx : f32 {
+!CHECK-DAG: fir.global @_QMtestEy : !fir.complex<4> {
+!CHECK-DAG: fir.global @_QMtestEz : !fir.logical<4> {
+
+contains
+ subroutine sub()
+!CHECK-DAG: [[ADDR0:%.*]] = fir.address_of(@_QMtestEt) : !fir.ref<!fir.type<_QMtestTmy_type{t_i:i32,t_arr:!fir.array<5xf32>}>>
+!CHECK-DAG: [[NEWADDR0:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<!fir.type<_QMtestTmy_type{t_i:i32,t_arr:!fir.array<5xf32>}>> -> !fir.ref<!fir.type<_QMtestTmy_type{t_i:i32,t_arr:!fir.array<5xf32>}>>
+!CHECK-DAG: [[ADDR1:%.*]] = fir.address_of(@_QMtestEx) : !fir.ref<f32>
+!CHECK-DAG: [[NEWADDR1:%.*]] = omp.threadprivate [[ADDR1]] : !fir.ref<f32> -> !fir.ref<f32>
+!CHECK-DAG: [[ADDR2:%.*]] = fir.address_of(@_QMtestEy) : !fir.ref<!fir.complex<4>>
+!CHECK-DAG: [[NEWADDR2:%.*]] = omp.threadprivate [[ADDR2]] : !fir.ref<!fir.complex<4>> -> !fir.ref<!fir.complex<4>>
+!CHECK-DAG: [[ADDR3:%.*]] = fir.address_of(@_QMtestEz) : !fir.ref<!fir.logical<4>>
+!CHECK-DAG: [[NEWADDR3:%.*]] = omp.threadprivate [[ADDR3]] : !fir.ref<!fir.logical<4>> -> !fir.ref<!fir.logical<4>>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR1]] : !fir.ref<f32>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR2]] : !fir.ref<!fir.complex<4>>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR3]] : !fir.ref<!fir.logical<4>>
+!CHECK-DAG: %{{.*}} = fir.coordinate_of [[NEWADDR0]]
+ print *, x, y, z, t%t_i
+
+ !$omp parallel
+!CHECK-DAG: [[ADDR38:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<!fir.type<_QMtestTmy_type{t_i:i32,t_arr:!fir.array<5xf32>}>> -> !fir.ref<!fir.type<_QMtestTmy_type{t_i:i32,t_arr:!fir.array<5xf32>}>>
+!CHECK-DAG: [[ADDR39:%.*]] = omp.threadprivate [[ADDR1]] : !fir.ref<f32> -> !fir.ref<f32>
+!CHECK-DAG: [[ADDR40:%.*]] = omp.threadprivate [[ADDR2]] : !fir.ref<!fir.complex<4>> -> !fir.ref<!fir.complex<4>>
+!CHECK-DAG: [[ADDR41:%.*]] = omp.threadprivate [[ADDR3]] : !fir.ref<!fir.logical<4>> -> !fir.ref<!fir.logical<4>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR39]] : !fir.ref<f32>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR40]] : !fir.ref<!fir.complex<4>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR41]] : !fir.ref<!fir.logical<4>>
+!CHECK-DAG: %{{.*}} = fir.coordinate_of [[ADDR38]]
+ print *, x, y, z, t%t_i
+ !$omp end parallel
+
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR1]] : !fir.ref<f32>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR2]] : !fir.ref<!fir.complex<4>>
+!CHECK-DAG: %{{.*}} = fir.load [[NEWADDR3]] : !fir.ref<!fir.logical<4>>
+!CHECK-DAG: %{{.*}} = fir.coordinate_of [[NEWADDR0]]
+ print *, x, y, z, t%t_i
+
+ end
+end
diff --git a/flang/test/Lower/OpenMP/threadprivate-use-association.f90 b/flang/test/Lower/OpenMP/threadprivate-use-association.f90
new file mode 100644
index 0000000000000..a8ecfd13c46d1
--- /dev/null
+++ b/flang/test/Lower/OpenMP/threadprivate-use-association.f90
@@ -0,0 +1,74 @@
+! This test checks lowering of OpenMP Threadprivate Directive.
+! Test for threadprivate variable in use association.
+
+!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s
+
+!CHECK-DAG: fir.global common @_QBblk(dense<0> : vector<24xi8>) : !fir.array<24xi8>
+!CHECK-DAG: fir.global @_QMtestEy : f32 {
+
+module test
+ integer :: x
+ real :: y, z(5)
+ common /blk/ x, z
+
+ !$omp threadprivate(y, /blk/)
+
+contains
+ subroutine sub()
+! CHECK-LABEL: @_QMtestPsub
+!CHECK-DAG: [[ADDR0:%.*]] = fir.address_of(@_QBblk) : !fir.ref<!fir.array<24xi8>>
+!CHECK-DAG: [[NEWADDR0:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<!fir.array<24xi8>> -> !fir.ref<!fir.array<24xi8>>
+!CHECK-DAG: [[ADDR1:%.*]] = fir.address_of(@_QMtestEy) : !fir.ref<f32>
+!CHECK-DAG: [[NEWADDR1:%.*]] = omp.threadprivate [[ADDR1]] : !fir.ref<f32> -> !fir.ref<f32>
+
+ !$omp parallel
+!CHECK-DAG: [[ADDR2:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<!fir.array<24xi8>> -> !fir.ref<!fir.array<24xi8>>
+!CHECK-DAG: [[ADDR3:%.*]] = omp.threadprivate [[ADDR1]] : !fir.ref<f32> -> !fir.ref<f32>
+!CHECK-DAG: [[ADDR4:%.*]] = fir.convert [[ADDR2]] : (!fir.ref<!fir.array<24xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[ADDR5:%.*]] = fir.coordinate_of [[ADDR4]], %{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR6:%.*]] = fir.convert [[ADDR5:%.*]] : (!fir.ref<i8>) -> !fir.ref<i32>
+!CHECK-DAG: [[ADDR7:%.*]] = fir.convert [[ADDR2]] : (!fir.ref<!fir.array<24xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[ADDR8:%.*]] = fir.coordinate_of [[ADDR7]], %{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR9:%.*]] = fir.convert [[ADDR8:%.*]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<5xf32>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR6]] : !fir.ref<i32>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR3]] : !fir.ref<f32>
+!CHECK-DAG: %{{.*}} = fir.embox [[ADDR9]](%{{.*}}) : (!fir.ref<!fir.array<5xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<5xf32>>
+ print *, x, y, z
+ !$omp end parallel
+ end
+end
+
+program main
+ use test
+ integer :: x1
+ real :: z1(5)
+ common /blk/ x1, z1
+
+ !$omp threadprivate(/blk/)
+
+ call sub()
+
+! CHECK-LABEL: @_QQmain()
+!CHECK-DAG: [[ADDR0:%.*]] = fir.address_of(@_QBblk) : !fir.ref<!fir.array<24xi8>>
+!CHECK-DAG: [[NEWADDR0:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<!fir.array<24xi8>> -> !fir.ref<!fir.array<24xi8>>
+!CHECK-DAG: [[ADDR1:%.*]] = fir.address_of(@_QBblk) : !fir.ref<!fir.array<24xi8>>
+!CHECK-DAG: [[NEWADDR1:%.*]] = omp.threadprivate [[ADDR1]] : !fir.ref<!fir.array<24xi8>> -> !fir.ref<!fir.array<24xi8>>
+!CHECK-DAG: [[ADDR2:%.*]] = fir.address_of(@_QMtestEy) : !fir.ref<f32>
+!CHECK-DAG: [[NEWADDR2:%.*]] = omp.threadprivate [[ADDR2]] : !fir.ref<f32> -> !fir.ref<f32>
+
+ !$omp parallel
+!CHECK-DAG: [[ADDR4:%.*]] = omp.threadprivate [[ADDR1]] : !fir.ref<!fir.array<24xi8>> -> !fir.ref<!fir.array<24xi8>>
+!CHECK-DAG: [[ADDR5:%.*]] = omp.threadprivate [[ADDR2]] : !fir.ref<f32> -> !fir.ref<f32>
+!CHECK-DAG: [[ADDR6:%.*]] = fir.convert [[ADDR4]] : (!fir.ref<!fir.array<24xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[ADDR7:%.*]] = fir.coordinate_of [[ADDR6]], %{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR8:%.*]] = fir.convert [[ADDR7:%.*]] : (!fir.ref<i8>) -> !fir.ref<i32>
+!CHECK-DAG: [[ADDR9:%.*]] = fir.convert [[ADDR4]] : (!fir.ref<!fir.array<24xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK-DAG: [[ADDR10:%.*]] = fir.coordinate_of [[ADDR9]], %{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR11:%.*]] = fir.convert [[ADDR10:%.*]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<5xf32>>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR8]] : !fir.ref<i32>
+!CHECK-DAG: %{{.*}} = fir.load [[ADDR5]] : !fir.ref<f32>
+!CHECK-DAG: %{{.*}} = fir.embox [[ADDR11]](%{{.*}}) : (!fir.ref<!fir.array<5xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<5xf32>>
+ print *, x1, y, z1
+ !$omp end parallel
+
+end
More information about the flang-commits
mailing list