Skip to content

Commit 6578b6e

Browse files
fabianmcglanza
authored andcommitted
[CIR][OpenMP] Initial commit for OpenMP support in CIR (llvm#382)
This patch introduces initial support for: ``` pragma omp parallel ``` This patch doesn't add support for any of the `parallel` clauses, including variable privatization; thus, all variables are handled as shared. This PR fixes issue llvm#285.
1 parent aac54a7 commit 6578b6e

21 files changed

+359
-29
lines changed

clang/lib/CIR/CodeGen/CIRGenDecl.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "CIRGenBuilder.h"
1515
#include "CIRGenCstEmitter.h"
1616
#include "CIRGenFunction.h"
17+
#include "CIRGenOpenMPRuntime.h"
1718
#include "EHScopeStack.h"
1819
#include "UnimplementedFeatureGuarding.h"
1920
#include "mlir/IR/Attributes.h"
@@ -37,13 +38,8 @@ CIRGenFunction::buildAutoVarAlloca(const VarDecl &D) {
3738
// TODO: (|| Ty.getAddressSpace() == LangAS::opencl_private &&
3839
// getLangOpts().OpenCL))
3940
assert(!UnimplementedFeature::openCL());
40-
assert(!UnimplementedFeature::openMP());
4141
assert(Ty.getAddressSpace() == LangAS::Default);
4242
assert(!Ty->isVariablyModifiedType() && "not implemented");
43-
assert(!getContext()
44-
.getLangOpts()
45-
.OpenMP && // !CGF.getLangOpts().OpenMPIRBuilder
46-
"not implemented");
4743
assert(!D.hasAttr<AnnotateAttr>() && "not implemented");
4844

4945
auto loc = getLoc(D.getSourceRange());
@@ -59,7 +55,9 @@ CIRGenFunction::buildAutoVarAlloca(const VarDecl &D) {
5955

6056
Address address = Address::invalid();
6157
Address allocaAddr = Address::invalid();
62-
Address openMPLocalAddr = Address::invalid();
58+
Address openMPLocalAddr =
59+
getCIRGenModule().getOpenMPRuntime().getAddressOfLocalVariable(*this, &D);
60+
assert(!getLangOpts().OpenMPIsTargetDevice && "NYI");
6361
if (getLangOpts().OpenMP && openMPLocalAddr.isValid()) {
6462
llvm_unreachable("NYI");
6563
} else if (Ty->isConstantSizeType()) {

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "CIRGenCstEmitter.h"
1616
#include "CIRGenFunction.h"
1717
#include "CIRGenModule.h"
18+
#include "CIRGenOpenMPRuntime.h"
1819
#include "CIRGenValue.h"
1920
#include "UnimplementedFeatureGuarding.h"
2021

@@ -759,8 +760,11 @@ LValue CIRGenFunction::buildDeclRefLValue(const DeclRefExpr *E) {
759760
if (auto *FD = LambdaCaptureFields.lookup(VD))
760761
return buildCapturedFieldLValue(*this, FD, CXXABIThisValue);
761762
assert(!UnimplementedFeature::CGCapturedStmtInfo() && "NYI");
762-
llvm_unreachable("NYI");
763+
// TODO[OpenMP]: Find the appropiate captured variable value and return
764+
// it.
765+
// TODO[OpenMP]: Set non-temporal information in the captured LVal.
763766
// LLVM codegen:
767+
assert(!UnimplementedFeature::openMP());
764768
// Address addr = GetAddrOfBlockDecl(VD);
765769
// return MakeAddrLValue(addr, T, AlignmentSource::Decl);
766770
}
@@ -910,9 +914,9 @@ LValue CIRGenFunction::buildBinaryOperatorLValue(const BinaryOperator *E) {
910914
} else {
911915
buildStoreThroughLValue(RV, LV);
912916
}
913-
914-
assert(!getContext().getLangOpts().OpenMP &&
915-
"last priv cond not implemented");
917+
if (getLangOpts().OpenMP)
918+
CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this,
919+
E->getLHS());
916920
return LV;
917921
}
918922

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "CIRDataLayout.h"
1515
#include "CIRGenFunction.h"
1616
#include "CIRGenModule.h"
17+
#include "CIRGenOpenMPRuntime.h"
1718
#include "UnimplementedFeatureGuarding.h"
1819

1920
#include "clang/AST/StmtVisitor.h"
@@ -1805,7 +1806,9 @@ LValue ScalarExprEmitter::buildCompoundAssignLValue(
18051806
else
18061807
CGF.buildStoreThroughLValue(RValue::get(Result), LHSLV);
18071808

1808-
assert(!CGF.getLangOpts().OpenMP && "Not implemented");
1809+
if (CGF.getLangOpts().OpenMP)
1810+
CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF,
1811+
E->getLHS());
18091812
return LHSLV;
18101813
}
18111814

clang/lib/CIR/CodeGen/CIRGenFunction.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "CIRGenFunction.h"
1414
#include "CIRGenCXXABI.h"
1515
#include "CIRGenModule.h"
16+
#include "CIRGenOpenMPRuntime.h"
1617
#include "UnimplementedFeatureGuarding.h"
1718

1819
#include "clang/AST/ASTLambda.h"
@@ -974,7 +975,7 @@ void CIRGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
974975
// TODO: prologuecleanupdepth
975976

976977
if (getLangOpts().OpenMP && CurCodeDecl)
977-
llvm_unreachable("NYI");
978+
CGM.getOpenMPRuntime().emitFunctionProlog(*this, CurCodeDecl);
978979

979980
// TODO: buildFunctionProlog
980981

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,9 @@ class CIRGenFunction : public CIRGenTypeCache {
928928
mlir::LogicalResult buildBreakStmt(const clang::BreakStmt &S);
929929
mlir::LogicalResult buildContinueStmt(const clang::ContinueStmt &S);
930930

931+
// OpenMP gen functions:
932+
mlir::LogicalResult buildOMPParallelDirective(const OMPParallelDirective &S);
933+
931934
LValue buildOpaqueValueLValue(const OpaqueValueExpr *e);
932935

933936
/// Emit code to compute a designator that specifies the location

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "CIRGenCXXABI.h"
1616
#include "CIRGenCstEmitter.h"
1717
#include "CIRGenFunction.h"
18+
#include "CIRGenOpenMPRuntime.h"
1819
#include "CIRGenTypes.h"
1920
#include "CIRGenValue.h"
2021
#include "TargetInfo.h"
@@ -103,7 +104,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &context,
103104
codeGenOpts(CGO),
104105
theModule{mlir::ModuleOp::create(builder.getUnknownLoc())}, Diags(Diags),
105106
target(astCtx.getTargetInfo()), ABI(createCXXABI(*this)), genTypes{*this},
106-
VTables{*this} {
107+
VTables{*this}, openMPRuntime(new CIRGenOpenMPRuntime(*this)) {
107108

108109
// Initialize CIR signed integer types cache.
109110
SInt8Ty =
@@ -316,7 +317,18 @@ bool CIRGenModule::MustBeEmitted(const ValueDecl *Global) {
316317
}
317318

318319
bool CIRGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
319-
assert(!langOpts.OpenMP && "NYI");
320+
// In OpenMP 5.0 variables and function may be marked as
321+
// device_type(host/nohost) and we should not emit them eagerly unless we sure
322+
// that they must be emitted on the host/device. To be sure we need to have
323+
// seen a declare target with an explicit mentioning of the function, we know
324+
// we have if the level of the declare target attribute is -1. Note that we
325+
// check somewhere else if we should emit this at all.
326+
if (langOpts.OpenMP >= 50 && !langOpts.OpenMPSimd) {
327+
std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
328+
OMPDeclareTargetDeclAttr::getActiveAttr(Global);
329+
if (!ActiveAttr || (*ActiveAttr)->getLevel() != (unsigned)-1)
330+
return false;
331+
}
320332

321333
const auto *FD = dyn_cast<FunctionDecl>(Global);
322334
if (FD) {
@@ -336,6 +348,15 @@ bool CIRGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
336348
ASTContext::InlineVariableDefinitionKind::WeakUnknown &&
337349
"not implemented");
338350

351+
// If OpenMP is enabled and threadprivates must be generated like TLS, delay
352+
// codegen for global variables, because they may be marked as threadprivate.
353+
if (langOpts.OpenMP && langOpts.OpenMPUseTLS &&
354+
getASTContext().getTargetInfo().isTLSSupported() &&
355+
isa<VarDecl>(Global) &&
356+
!Global->getType().isConstantStorage(getASTContext(), false, false) &&
357+
!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(Global))
358+
return false;
359+
339360
assert((FD || VD) &&
340361
"Only FunctionDecl and VarDecl should hit this path so far.");
341362
return true;
@@ -347,7 +368,22 @@ void CIRGenModule::buildGlobal(GlobalDecl GD) {
347368
assert(!Global->hasAttr<IFuncAttr>() && "NYI");
348369
assert(!Global->hasAttr<CPUDispatchAttr>() && "NYI");
349370
assert(!langOpts.CUDA && "NYI");
350-
assert(!langOpts.OpenMP && "NYI");
371+
372+
if (langOpts.OpenMP) {
373+
// If this is OpenMP, check if it is legal to emit this global normally.
374+
if (openMPRuntime && openMPRuntime->emitTargetGlobal(GD)) {
375+
assert(!UnimplementedFeature::openMPRuntime());
376+
return;
377+
}
378+
if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(Global)) {
379+
assert(!UnimplementedFeature::openMP());
380+
return;
381+
}
382+
if (auto *DMD = dyn_cast<OMPDeclareMapperDecl>(Global)) {
383+
assert(!UnimplementedFeature::openMP());
384+
return;
385+
}
386+
}
351387

352388
// Ignore declarations, they will be emitted on their first use.
353389
if (const auto *FD = dyn_cast<FunctionDecl>(Global)) {
@@ -371,7 +407,13 @@ void CIRGenModule::buildGlobal(GlobalDecl GD) {
371407
assert(VD->isFileVarDecl() && "Cannot emit local var decl as global.");
372408
if (VD->isThisDeclarationADefinition() != VarDecl::Definition &&
373409
!astCtx.isMSStaticDataMemberInlineDefinition(VD)) {
374-
assert(!getLangOpts().OpenMP && "not implemented");
410+
if (langOpts.OpenMP) {
411+
// Emit declaration of the must-be-emitted declare target variable.
412+
if (std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
413+
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) {
414+
assert(0 && "OMPDeclareTargetDeclAttr NYI");
415+
}
416+
}
375417
// If this declaration may have caused an inline variable definition
376418
// to change linkage, make sure that it's emitted.
377419
// TODO(cir): probably use GetAddrOfGlobalVar(VD) below?
@@ -576,8 +618,8 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty,
576618
!D->hasAttr<clang::DLLExportAttr>())
577619
assert(!UnimplementedFeature::setDLLStorageClass() && "NYI");
578620

579-
if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd && D)
580-
assert(0 && "not implemented");
621+
if (langOpts.OpenMP && !langOpts.OpenMPSimd && D)
622+
getOpenMPRuntime().registerTargetGlobalVariable(D, Entry);
581623

582624
// TODO(cir): check TargetAS matches Entry address space
583625
if (Entry.getSymType() == Ty &&
@@ -647,10 +689,9 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty,
647689
}
648690

649691
// Handle things which are present even on external declarations.
650-
auto &LangOpts = getLangOpts();
651692
if (D) {
652-
if (LangOpts.OpenMP && !LangOpts.OpenMPSimd)
653-
assert(0 && "not implemented");
693+
if (langOpts.OpenMP && !langOpts.OpenMPSimd && D)
694+
getOpenMPRuntime().registerTargetGlobalVariable(D, Entry);
654695

655696
// FIXME: This code is overly simple and should be merged with other global
656697
// handling.
@@ -2052,8 +2093,11 @@ mlir::cir::FuncOp CIRGenModule::GetOrCreateCIRFunction(
20522093
// Any attempts to use a MultiVersion function should result in retrieving the
20532094
// iFunc instead. Name mangling will handle the rest of the changes.
20542095
if (const auto *FD = cast_or_null<FunctionDecl>(D)) {
2055-
if (getLangOpts().OpenMP)
2056-
llvm_unreachable("open MP NYI");
2096+
// For the device mark the function as one that should be emitted.
2097+
if (getLangOpts().OpenMPIsTargetDevice && FD->isDefined() && !DontDefer &&
2098+
!IsForDefinition) {
2099+
assert(0 && "OpenMP target functions NYI");
2100+
}
20572101
if (FD->isMultiVersion())
20582102
llvm_unreachable("NYI");
20592103
}
@@ -2291,9 +2335,9 @@ void CIRGenModule::buildGlobalDecl(clang::GlobalDecl &D) {
22912335
}
22922336

22932337
// If this is OpenMP, check if it is legal to emit this global normally.
2294-
if (getLangOpts().OpenMP) {
2295-
llvm_unreachable("NYI");
2296-
}
2338+
if (getLangOpts().OpenMP && openMPRuntime &&
2339+
openMPRuntime->emitTargetGlobal(D))
2340+
return;
22972341

22982342
// Otherwise, emit the definition and move on to the next one.
22992343
buildGlobalDefinition(D, Op);
@@ -2302,7 +2346,7 @@ void CIRGenModule::buildGlobalDecl(clang::GlobalDecl &D) {
23022346
void CIRGenModule::buildDeferred(unsigned recursionLimit) {
23032347
// Emit deferred declare target declarations
23042348
if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd)
2305-
llvm_unreachable("NYI");
2349+
getOpenMPRuntime().emitDeferredTargetDecls();
23062350

23072351
// Emit code for any potentially referenced deferred decls. Since a previously
23082352
// unused static decl may become used during the generation of code for a

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ namespace cir {
4646
class CIRGenFunction;
4747
class CIRGenCXXABI;
4848
class TargetCIRGenInfo;
49+
class CIRGenOpenMPRuntime;
4950

5051
enum ForDefinition_t : bool { NotForDefinition = false, ForDefinition = true };
5152

@@ -100,6 +101,9 @@ class CIRGenModule : public CIRGenTypeCache {
100101
/// Holds information about C++ vtables.
101102
CIRGenVTables VTables;
102103

104+
/// Holds the OpenMP runtime
105+
std::unique_ptr<CIRGenOpenMPRuntime> openMPRuntime;
106+
103107
/// Per-function codegen information. Updated everytime buildCIR is called
104108
/// for FunctionDecls's.
105109
CIRGenFunction *CurCGF = nullptr;
@@ -626,6 +630,12 @@ class CIRGenModule : public CIRGenTypeCache {
626630
/// Print out an error that codegen doesn't support the specified decl yet.
627631
void ErrorUnsupported(const Decl *D, const char *Type);
628632

633+
/// Return a reference to the configured OpenMP runtime.
634+
CIRGenOpenMPRuntime &getOpenMPRuntime() {
635+
assert(openMPRuntime != nullptr);
636+
return *openMPRuntime;
637+
}
638+
629639
private:
630640
// An ordered map of canonical GlobalDecls to their mangled names.
631641
llvm::MapVector<clang::GlobalDecl, llvm::StringRef> MangledDeclNames;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//===--- CIRGenStmtOpenMP.cpp - Interface to OpenMP Runtimes --------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This provides a class for OpenMP runtime MLIR code generation.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "CIRGenOpenMPRuntime.h"
14+
#include "CIRGenFunction.h"
15+
#include "CIRGenModule.h"
16+
17+
using namespace cir;
18+
using namespace clang;
19+
20+
CIRGenOpenMPRuntime::CIRGenOpenMPRuntime(CIRGenModule &CGM) : CGM(CGM) {}
21+
22+
Address CIRGenOpenMPRuntime::getAddressOfLocalVariable(CIRGenFunction &CGF,
23+
const VarDecl *VD) {
24+
assert(!UnimplementedFeature::openMPRuntime());
25+
return Address::invalid();
26+
}
27+
28+
void CIRGenOpenMPRuntime::checkAndEmitLastprivateConditional(
29+
CIRGenFunction &CGF, const Expr *LHS) {
30+
assert(!UnimplementedFeature::openMPRuntime());
31+
return;
32+
}
33+
34+
void CIRGenOpenMPRuntime::registerTargetGlobalVariable(
35+
const clang::VarDecl *VD, mlir::cir::GlobalOp globalOp) {
36+
assert(!UnimplementedFeature::openMPRuntime());
37+
return;
38+
}
39+
40+
void CIRGenOpenMPRuntime::emitDeferredTargetDecls() const {
41+
assert(!UnimplementedFeature::openMPRuntime());
42+
return;
43+
}
44+
45+
void CIRGenOpenMPRuntime::emitFunctionProlog(CIRGenFunction &CGF,
46+
const clang::Decl *D) {
47+
assert(!UnimplementedFeature::openMPRuntime());
48+
return;
49+
}
50+
51+
bool CIRGenOpenMPRuntime::emitTargetGlobal(clang::GlobalDecl &GD) {
52+
assert(!UnimplementedFeature::openMPRuntime());
53+
return false;
54+
}

0 commit comments

Comments
 (0)