Skip to content

Commit

Permalink
[CIR][OpenMP] Initial commit for OpenMP support in CIR (llvm#382)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
fabianmcg authored and lanza committed Mar 20, 2024
1 parent aac54a7 commit 6578b6e
Show file tree
Hide file tree
Showing 21 changed files with 359 additions and 29 deletions.
10 changes: 4 additions & 6 deletions clang/lib/CIR/CodeGen/CIRGenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "CIRGenBuilder.h"
#include "CIRGenCstEmitter.h"
#include "CIRGenFunction.h"
#include "CIRGenOpenMPRuntime.h"
#include "EHScopeStack.h"
#include "UnimplementedFeatureGuarding.h"
#include "mlir/IR/Attributes.h"
Expand All @@ -37,13 +38,8 @@ CIRGenFunction::buildAutoVarAlloca(const VarDecl &D) {
// TODO: (|| Ty.getAddressSpace() == LangAS::opencl_private &&
// getLangOpts().OpenCL))
assert(!UnimplementedFeature::openCL());
assert(!UnimplementedFeature::openMP());
assert(Ty.getAddressSpace() == LangAS::Default);
assert(!Ty->isVariablyModifiedType() && "not implemented");
assert(!getContext()
.getLangOpts()
.OpenMP && // !CGF.getLangOpts().OpenMPIRBuilder
"not implemented");
assert(!D.hasAttr<AnnotateAttr>() && "not implemented");

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

Address address = Address::invalid();
Address allocaAddr = Address::invalid();
Address openMPLocalAddr = Address::invalid();
Address openMPLocalAddr =
getCIRGenModule().getOpenMPRuntime().getAddressOfLocalVariable(*this, &D);
assert(!getLangOpts().OpenMPIsTargetDevice && "NYI");
if (getLangOpts().OpenMP && openMPLocalAddr.isValid()) {
llvm_unreachable("NYI");
} else if (Ty->isConstantSizeType()) {
Expand Down
12 changes: 8 additions & 4 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "CIRGenCstEmitter.h"
#include "CIRGenFunction.h"
#include "CIRGenModule.h"
#include "CIRGenOpenMPRuntime.h"
#include "CIRGenValue.h"
#include "UnimplementedFeatureGuarding.h"

Expand Down Expand Up @@ -759,8 +760,11 @@ LValue CIRGenFunction::buildDeclRefLValue(const DeclRefExpr *E) {
if (auto *FD = LambdaCaptureFields.lookup(VD))
return buildCapturedFieldLValue(*this, FD, CXXABIThisValue);
assert(!UnimplementedFeature::CGCapturedStmtInfo() && "NYI");
llvm_unreachable("NYI");
// TODO[OpenMP]: Find the appropiate captured variable value and return
// it.
// TODO[OpenMP]: Set non-temporal information in the captured LVal.
// LLVM codegen:
assert(!UnimplementedFeature::openMP());
// Address addr = GetAddrOfBlockDecl(VD);
// return MakeAddrLValue(addr, T, AlignmentSource::Decl);
}
Expand Down Expand Up @@ -910,9 +914,9 @@ LValue CIRGenFunction::buildBinaryOperatorLValue(const BinaryOperator *E) {
} else {
buildStoreThroughLValue(RV, LV);
}

assert(!getContext().getLangOpts().OpenMP &&
"last priv cond not implemented");
if (getLangOpts().OpenMP)
CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this,
E->getLHS());
return LV;
}

Expand Down
5 changes: 4 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "CIRDataLayout.h"
#include "CIRGenFunction.h"
#include "CIRGenModule.h"
#include "CIRGenOpenMPRuntime.h"
#include "UnimplementedFeatureGuarding.h"

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

assert(!CGF.getLangOpts().OpenMP && "Not implemented");
if (CGF.getLangOpts().OpenMP)
CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF,
E->getLHS());
return LHSLV;
}

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "CIRGenFunction.h"
#include "CIRGenCXXABI.h"
#include "CIRGenModule.h"
#include "CIRGenOpenMPRuntime.h"
#include "UnimplementedFeatureGuarding.h"

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

if (getLangOpts().OpenMP && CurCodeDecl)
llvm_unreachable("NYI");
CGM.getOpenMPRuntime().emitFunctionProlog(*this, CurCodeDecl);

// TODO: buildFunctionProlog

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,9 @@ class CIRGenFunction : public CIRGenTypeCache {
mlir::LogicalResult buildBreakStmt(const clang::BreakStmt &S);
mlir::LogicalResult buildContinueStmt(const clang::ContinueStmt &S);

// OpenMP gen functions:
mlir::LogicalResult buildOMPParallelDirective(const OMPParallelDirective &S);

LValue buildOpaqueValueLValue(const OpaqueValueExpr *e);

/// Emit code to compute a designator that specifies the location
Expand Down
74 changes: 59 additions & 15 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "CIRGenCXXABI.h"
#include "CIRGenCstEmitter.h"
#include "CIRGenFunction.h"
#include "CIRGenOpenMPRuntime.h"
#include "CIRGenTypes.h"
#include "CIRGenValue.h"
#include "TargetInfo.h"
Expand Down Expand Up @@ -103,7 +104,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &context,
codeGenOpts(CGO),
theModule{mlir::ModuleOp::create(builder.getUnknownLoc())}, Diags(Diags),
target(astCtx.getTargetInfo()), ABI(createCXXABI(*this)), genTypes{*this},
VTables{*this} {
VTables{*this}, openMPRuntime(new CIRGenOpenMPRuntime(*this)) {

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

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

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

// If OpenMP is enabled and threadprivates must be generated like TLS, delay
// codegen for global variables, because they may be marked as threadprivate.
if (langOpts.OpenMP && langOpts.OpenMPUseTLS &&
getASTContext().getTargetInfo().isTLSSupported() &&
isa<VarDecl>(Global) &&
!Global->getType().isConstantStorage(getASTContext(), false, false) &&
!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(Global))
return false;

assert((FD || VD) &&
"Only FunctionDecl and VarDecl should hit this path so far.");
return true;
Expand All @@ -347,7 +368,22 @@ void CIRGenModule::buildGlobal(GlobalDecl GD) {
assert(!Global->hasAttr<IFuncAttr>() && "NYI");
assert(!Global->hasAttr<CPUDispatchAttr>() && "NYI");
assert(!langOpts.CUDA && "NYI");
assert(!langOpts.OpenMP && "NYI");

if (langOpts.OpenMP) {
// If this is OpenMP, check if it is legal to emit this global normally.
if (openMPRuntime && openMPRuntime->emitTargetGlobal(GD)) {
assert(!UnimplementedFeature::openMPRuntime());
return;
}
if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(Global)) {
assert(!UnimplementedFeature::openMP());
return;
}
if (auto *DMD = dyn_cast<OMPDeclareMapperDecl>(Global)) {
assert(!UnimplementedFeature::openMP());
return;
}
}

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

if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd && D)
assert(0 && "not implemented");
if (langOpts.OpenMP && !langOpts.OpenMPSimd && D)
getOpenMPRuntime().registerTargetGlobalVariable(D, Entry);

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

// Handle things which are present even on external declarations.
auto &LangOpts = getLangOpts();
if (D) {
if (LangOpts.OpenMP && !LangOpts.OpenMPSimd)
assert(0 && "not implemented");
if (langOpts.OpenMP && !langOpts.OpenMPSimd && D)
getOpenMPRuntime().registerTargetGlobalVariable(D, Entry);

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

// If this is OpenMP, check if it is legal to emit this global normally.
if (getLangOpts().OpenMP) {
llvm_unreachable("NYI");
}
if (getLangOpts().OpenMP && openMPRuntime &&
openMPRuntime->emitTargetGlobal(D))
return;

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

// Emit code for any potentially referenced deferred decls. Since a previously
// unused static decl may become used during the generation of code for a
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ namespace cir {
class CIRGenFunction;
class CIRGenCXXABI;
class TargetCIRGenInfo;
class CIRGenOpenMPRuntime;

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

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

/// Holds the OpenMP runtime
std::unique_ptr<CIRGenOpenMPRuntime> openMPRuntime;

/// Per-function codegen information. Updated everytime buildCIR is called
/// for FunctionDecls's.
CIRGenFunction *CurCGF = nullptr;
Expand Down Expand Up @@ -626,6 +630,12 @@ class CIRGenModule : public CIRGenTypeCache {
/// Print out an error that codegen doesn't support the specified decl yet.
void ErrorUnsupported(const Decl *D, const char *Type);

/// Return a reference to the configured OpenMP runtime.
CIRGenOpenMPRuntime &getOpenMPRuntime() {
assert(openMPRuntime != nullptr);
return *openMPRuntime;
}

private:
// An ordered map of canonical GlobalDecls to their mangled names.
llvm::MapVector<clang::GlobalDecl, llvm::StringRef> MangledDeclNames;
Expand Down
54 changes: 54 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//===--- CIRGenStmtOpenMP.cpp - Interface to OpenMP Runtimes --------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This provides a class for OpenMP runtime MLIR code generation.
//
//===----------------------------------------------------------------------===//

#include "CIRGenOpenMPRuntime.h"
#include "CIRGenFunction.h"
#include "CIRGenModule.h"

using namespace cir;
using namespace clang;

CIRGenOpenMPRuntime::CIRGenOpenMPRuntime(CIRGenModule &CGM) : CGM(CGM) {}

Address CIRGenOpenMPRuntime::getAddressOfLocalVariable(CIRGenFunction &CGF,
const VarDecl *VD) {
assert(!UnimplementedFeature::openMPRuntime());
return Address::invalid();
}

void CIRGenOpenMPRuntime::checkAndEmitLastprivateConditional(
CIRGenFunction &CGF, const Expr *LHS) {
assert(!UnimplementedFeature::openMPRuntime());
return;
}

void CIRGenOpenMPRuntime::registerTargetGlobalVariable(
const clang::VarDecl *VD, mlir::cir::GlobalOp globalOp) {
assert(!UnimplementedFeature::openMPRuntime());
return;
}

void CIRGenOpenMPRuntime::emitDeferredTargetDecls() const {
assert(!UnimplementedFeature::openMPRuntime());
return;
}

void CIRGenOpenMPRuntime::emitFunctionProlog(CIRGenFunction &CGF,
const clang::Decl *D) {
assert(!UnimplementedFeature::openMPRuntime());
return;
}

bool CIRGenOpenMPRuntime::emitTargetGlobal(clang::GlobalDecl &GD) {
assert(!UnimplementedFeature::openMPRuntime());
return false;
}
Loading

0 comments on commit 6578b6e

Please sign in to comment.