From 0bda8cb2b53335e4d4c541db5e7456f070349d87 Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Thu, 18 Jan 2024 15:34:21 -0800 Subject: [PATCH 1/3] [CIR] Add cir.resume op and use it in cir.catch - Add an extra CatchOp region to hold fallback (where EH usually resumes or rethrows as part of try/catch). - Emit `cir.resume` on the fallback region. Incremental step into the next assertion, still missing pieces before adding the first testcase. --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 25 +++++++++ .../include/clang/CIR/Dialect/IR/CIRTypes.td | 2 +- clang/lib/CIR/CodeGen/CIRGenException.cpp | 52 +++++++++++++++++-- clang/lib/CIR/CodeGen/CIRGenFunction.h | 3 +- 4 files changed, 77 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 15e1ae1d6f3e..c0d23698d449 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -718,6 +718,31 @@ def ContinueOp : CIR_Op<"continue", [Terminator]> { let hasVerifier = 1; } +//===----------------------------------------------------------------------===// +// Resume +//===----------------------------------------------------------------------===// + +def ResumeOp : CIR_Op<"resume", [ReturnLike, Terminator, + ParentOneOf<["CatchOp"]>]> { + let summary = "Resumes execution after not catching exceptions"; + let description = [{ + The `cir.resume` operation terminates a region on `cir.catch`, "resuming" + or continuing the unwind process. The incoming argument is of !cir.eh_info + populated by `cir.try_call` and available in `cir.catch`. + + Examples: + ```mlir + cir.catch %4 { + ... + fallback { cir.resume(%0) }; + } + ``` + }]; + + let arguments = (ins ExceptionInfoPtr:$ptr); + let assemblyFormat = "$ptr attr-dict"; +} + //===----------------------------------------------------------------------===// // ScopeOp //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index 7e85d3ddeff3..341de9406c22 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -283,7 +283,7 @@ def ExceptionInfoPtr : Type< ]>, "void*">, BuildableType< "mlir::cir::PointerType::get($_builder.getContext()," - "mlir::cir::ExceptionInfo::get($_builder.getContext()))"> { + "mlir::cir::ExceptionInfoType::get($_builder.getContext()))"> { } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp index 8a604453870e..0316536e7393 100644 --- a/clang/lib/CIR/CodeGen/CIRGenException.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp @@ -251,6 +251,36 @@ void CIRGenFunction::buildAnyExprToExn(const Expr *e, Address addr) { DeactivateCleanupBlock(cleanup, op); } +mlir::Block *CIRGenFunction::getEHResumeBlock(bool isCleanup) { + // Just like some other try/catch related logic: return the basic block + // pointer but only use it to denote we're tracking things, but there + // shouldn't be any changes to that block after work done in this function. + auto catchOp = currExceptionInfo.catchOp; + assert(catchOp.getNumRegions() && "expected at least one region"); + auto &fallbackRegion = catchOp.getRegion(catchOp.getNumRegions() - 1); + + auto *resumeBlock = &fallbackRegion.getBlocks().back(); + if (!resumeBlock->empty()) + return resumeBlock; + + auto ip = getBuilder().saveInsertionPoint(); + getBuilder().setInsertionPointToStart(resumeBlock); + + const EHPersonality &Personality = EHPersonality::get(*this); + + // This can always be a call because we necessarily didn't find + // anything on the EH stack which needs our help. + const char *RethrowName = Personality.CatchallRethrowFn; + if (RethrowName != nullptr && !isCleanup) { + llvm_unreachable("NYI"); + } + + getBuilder().create(catchOp.getLoc(), + currExceptionInfo.exceptionAddr); + getBuilder().restoreInsertionPoint(ip); + return resumeBlock; +} + mlir::LogicalResult CIRGenFunction::buildCXXTryStmt(const CXXTryStmt &S) { const llvm::Triple &T = getTarget().getTriple(); // If we encounter a try statement on in an OpenMP target region offloaded to @@ -288,7 +318,9 @@ mlir::LogicalResult CIRGenFunction::buildCXXTryStmt(const CXXTryStmt &S) { [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &result) { mlir::OpBuilder::InsertionGuard guard(b); - for (int i = 0, e = numHandlers; i != e; ++i) { + // Once for each handler and one for fallback (which could be a + // resume or rethrow). + for (int i = 0, e = numHandlers + 1; i != e; ++i) { auto *r = result.addRegion(); builder.createBlock(r); } @@ -346,11 +378,25 @@ static void buildCatchDispatchBlock(CIRGenFunction &CGF, // Check for address space mismatch: if (typeValue->getType() != argTy) assert(!UnimplementedFeature::addressSpace()); + bool nextIsEnd = false; // If this is the last handler, we're at the end, and the next // block is the block for the enclosing EH scope. Make sure to call // getEHDispatchBlock for caching it. - if (i + 1 == e) + if (i + 1 == e) { (void)CGF.getEHDispatchBlock(catchScope.getEnclosingEHScope()); + nextIsEnd = true; + + // If the next handler is a catch-all, we're at the end, and the + // next block is that handler. + } else if (catchScope.getHandler(i + 1).isCatchAll()) { + // Block already created when creating CatchOp, just mark this + // is the end. + nextIsEnd = true; + } + + // If the next handler is a catch-all, we're completely done. + if (nextIsEnd) + return; } } @@ -549,7 +595,7 @@ CIRGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) { // The dispatch block for the end of the scope chain is a block that // just resumes unwinding. if (si == EHStack.stable_end()) - llvm_unreachable("NYI"); + return getEHResumeBlock(true); // Otherwise, we should look at the actual scope. EHScope &scope = *EHStack.find(si); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 64f48ba97aeb..02d7b26cd48b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1503,8 +1503,9 @@ class CIRGenFunction : public CIRGenTypeCache { bool isConditional() const { return IsConditional; } }; - /// Emits landing pad information for the current EH stack. + /// Emits try/catch information for the current EH stack. mlir::Operation *buildLandingPad(); + mlir::Block *getEHResumeBlock(bool isCleanup); mlir::Block *getEHDispatchBlock(EHScopeStack::stable_iterator scope); mlir::Operation *getInvokeDestImpl(); From b42f8847437bc5e9a619db4dbb14137f588d661d Mon Sep 17 00:00:00 2001 From: Sirui Mu Date: Fri, 19 Jan 2024 08:23:11 +0800 Subject: [PATCH 2/3] [CIR][CIRGen] Support wide string literals (#399) This commit supports the codegen of wide string literals, including `wchar_t` string literals, `char16_t` string literals, and `char32_t` string literals. I'm not following the proposal in #374. The clang frontend doesn't record the literal string. It only records the encoded code units for wide string literals. So I believe that a dedicated string attribute with an encoding tag as described in #374 may not be that helpful as I thought. --- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 33 ++++++++++++++++++++++++-- clang/test/CIR/CodeGen/wide-string.cpp | 26 ++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 clang/test/CIR/CodeGen/wide-string.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 7eab7323d70f..9b7f11d37ce2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -1103,8 +1103,37 @@ CIRGenModule::getConstantArrayFromStringLiteral(const StringLiteral *E) { return builder.getString(Str, eltTy, finalSize); } - assert(0 && "not implemented"); - return {}; + auto arrayTy = + getTypes().ConvertType(E->getType()).dyn_cast(); + assert(arrayTy && "string literals must be emitted as an array type"); + + auto arrayEltTy = arrayTy.getEltType().dyn_cast(); + assert(arrayEltTy && + "string literal elements must be emitted as integral type"); + + auto arraySize = arrayTy.getSize(); + auto literalSize = E->getLength(); + + // Collect the code units. + SmallVector elementValues; + elementValues.reserve(arraySize); + for (unsigned i = 0; i < literalSize; ++i) + elementValues.push_back(E->getCodeUnit(i)); + elementValues.resize(arraySize); + + // If the string is full of null bytes, emit a #cir.zero instead. + if (std::all_of(elementValues.begin(), elementValues.end(), + [](uint32_t x) { return x == 0; })) + return builder.getZeroAttr(arrayTy); + + // Otherwise emit a constant array holding the characters. + SmallVector elements; + elements.reserve(arraySize); + for (uint64_t i = 0; i < arraySize; ++i) + elements.push_back(mlir::cir::IntAttr::get(arrayEltTy, elementValues[i])); + + auto elementsAttr = mlir::ArrayAttr::get(builder.getContext(), elements); + return builder.getConstArray(elementsAttr, arrayTy); } // TODO(cir): this could be a common AST helper for both CIR and LLVM codegen. diff --git a/clang/test/CIR/CodeGen/wide-string.cpp b/clang/test/CIR/CodeGen/wide-string.cpp new file mode 100644 index 000000000000..e7fc719647ab --- /dev/null +++ b/clang/test/CIR/CodeGen/wide-string.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir-enable -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +const char16_t *test_utf16() { + return u"你好世界"; +} + +// CHECK: cir.global "private" constant internal @{{.+}} = #cir.const_array<[#cir.int<20320> : !u16i, #cir.int<22909> : !u16i, #cir.int<19990> : !u16i, #cir.int<30028> : !u16i, #cir.int<0> : !u16i]> : !cir.array + +const char32_t *test_utf32() { + return U"你好世界"; +} + +// CHECK: cir.global "private" constant internal @{{.+}} = #cir.const_array<[#cir.int<20320> : !u32i, #cir.int<22909> : !u32i, #cir.int<19990> : !u32i, #cir.int<30028> : !u32i, #cir.int<0> : !u32i]> : !cir.array + +const char16_t *test_zero16() { + return u"\0\0\0\0"; +} + +// CHECK: cir.global "private" constant internal @{{.+}} = #cir.zero : !cir.array + +const char32_t *test_zero32() { + return U"\0\0\0\0"; +} + +// CHECK: cir.global "private" constant internal @{{.+}} = #cir.zero : !cir.array From ef3f6a5259ff485996f032f81402621d4945949a Mon Sep 17 00:00:00 2001 From: Fabian Mora Date: Mon, 22 Jan 2024 14:13:55 -0500 Subject: [PATCH 3/3] [CIR][OpenMP] Initial commit for OpenMP support in CIR (#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 #285. --- clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 10 +-- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 12 ++- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 5 +- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 3 +- clang/lib/CIR/CodeGen/CIRGenFunction.h | 3 + clang/lib/CIR/CodeGen/CIRGenModule.cpp | 74 ++++++++++++++---- clang/lib/CIR/CodeGen/CIRGenModule.h | 10 +++ clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.cpp | 54 +++++++++++++ clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.h | 77 +++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 5 +- clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp | 45 +++++++++++ clang/lib/CIR/CodeGen/CIRGenerator.cpp | 2 + clang/lib/CIR/CodeGen/CMakeLists.txt | 3 + .../CodeGen/UnimplementedFeatureGuarding.h | 2 + .../CIR/Lowering/DirectToLLVM/CMakeLists.txt | 2 + .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 2 + .../CIR/Lowering/ThroughMLIR/CMakeLists.txt | 2 + .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 2 + clang/test/CIR/CodeGen/openmp.cpp | 36 +++++++++ clang/test/CIR/Lowering/openmp.cir | 35 +++++++++ clang/tools/cir-opt/cir-opt.cpp | 4 +- 21 files changed, 359 insertions(+), 29 deletions(-) create mode 100644 clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.cpp create mode 100644 clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.h create mode 100644 clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp create mode 100644 clang/test/CIR/CodeGen/openmp.cpp create mode 100644 clang/test/CIR/Lowering/openmp.cir diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 662d24cd63a9..dd86a854e01c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -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" @@ -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() && "not implemented"); auto loc = getLoc(D.getSourceRange()); @@ -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()) { diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index fc5bdc052f47..950ac54d6f96 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -15,6 +15,7 @@ #include "CIRGenCstEmitter.h" #include "CIRGenFunction.h" #include "CIRGenModule.h" +#include "CIRGenOpenMPRuntime.h" #include "CIRGenValue.h" #include "UnimplementedFeatureGuarding.h" @@ -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); } @@ -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; } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 68e2ca82c2ff..0f85e0da58dd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -14,6 +14,7 @@ #include "CIRDataLayout.h" #include "CIRGenFunction.h" #include "CIRGenModule.h" +#include "CIRGenOpenMPRuntime.h" #include "UnimplementedFeatureGuarding.h" #include "clang/AST/StmtVisitor.h" @@ -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; } diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 11f562680e08..776a4cf0a305 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -13,6 +13,7 @@ #include "CIRGenFunction.h" #include "CIRGenCXXABI.h" #include "CIRGenModule.h" +#include "CIRGenOpenMPRuntime.h" #include "UnimplementedFeatureGuarding.h" #include "clang/AST/ASTLambda.h" @@ -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 diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 02d7b26cd48b..de0f20718980 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -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 diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 9b7f11d37ce2..8888459e5cc2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -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" @@ -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 = @@ -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 ActiveAttr = + OMPDeclareTargetDeclAttr::getActiveAttr(Global); + if (!ActiveAttr || (*ActiveAttr)->getLevel() != (unsigned)-1) + return false; + } const auto *FD = dyn_cast(Global); if (FD) { @@ -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(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; @@ -347,7 +368,22 @@ void CIRGenModule::buildGlobal(GlobalDecl GD) { assert(!Global->hasAttr() && "NYI"); assert(!Global->hasAttr() && "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(Global)) { + assert(!UnimplementedFeature::openMP()); + return; + } + if (auto *DMD = dyn_cast(Global)) { + assert(!UnimplementedFeature::openMP()); + return; + } + } // Ignore declarations, they will be emitted on their first use. if (const auto *FD = dyn_cast(Global)) { @@ -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 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? @@ -576,8 +618,8 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty, !D->hasAttr()) 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 && @@ -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. @@ -2051,8 +2092,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(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"); } @@ -2290,9 +2334,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); @@ -2301,7 +2345,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 diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index e468c53e58d4..900210a7c24a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -46,6 +46,7 @@ namespace cir { class CIRGenFunction; class CIRGenCXXABI; class TargetCIRGenInfo; +class CIRGenOpenMPRuntime; enum ForDefinition_t : bool { NotForDefinition = false, ForDefinition = true }; @@ -100,6 +101,9 @@ class CIRGenModule : public CIRGenTypeCache { /// Holds information about C++ vtables. CIRGenVTables VTables; + /// Holds the OpenMP runtime + std::unique_ptr openMPRuntime; + /// Per-function codegen information. Updated everytime buildCIR is called /// for FunctionDecls's. CIRGenFunction *CurCGF = nullptr; @@ -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 MangledDeclNames; diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.cpp new file mode 100644 index 000000000000..2060ce8e2d31 --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.cpp @@ -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; +} diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.h b/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.h new file mode 100644 index 000000000000..c4a53db44c92 --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenOpenMPRuntime.h @@ -0,0 +1,77 @@ +//===--- CIRGenOpenMPRuntime.h - 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. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENOPENMPRUNTIME_H +#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENOPENMPRUNTIME_H + +#include "CIRGenValue.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" + +namespace clang { +class Decl; +class Expr; +class GlobalDecl; +class VarDecl; +} // namespace clang + +namespace cir { +class CIRGenModule; +class CIRGenFunction; + +class CIRGenOpenMPRuntime { +public: + explicit CIRGenOpenMPRuntime(CIRGenModule &CGM); + virtual ~CIRGenOpenMPRuntime() {} + + /// Gets the OpenMP-specific address of the local variable. + virtual Address getAddressOfLocalVariable(CIRGenFunction &CGF, + const clang::VarDecl *VD); + + /// Checks if the provided \p LVal is lastprivate conditional and emits the + /// code to update the value of the original variable. + /// \code + /// lastprivate(conditional: a) + /// ... + /// a; + /// lp_a = ...; + /// #pragma omp critical(a) + /// if (last_iv_a <= iv) { + /// last_iv_a = iv; + /// global_a = lp_a; + /// } + /// \endcode + virtual void checkAndEmitLastprivateConditional(CIRGenFunction &CGF, + const clang::Expr *LHS); + + /// Checks if the provided global decl \a GD is a declare target variable and + /// registers it when emitting code for the host. + virtual void registerTargetGlobalVariable(const clang::VarDecl *VD, + mlir::cir::GlobalOp globalOp); + + /// Emit deferred declare target variables marked for deferred emission. + void emitDeferredTargetDecls() const; + + /// Emits OpenMP-specific function prolog. + /// Required for device constructs. + virtual void emitFunctionProlog(CIRGenFunction &CGF, const clang::Decl *D); + + /// Emit the global \a GD if it is meaningful for the target. Returns + /// if it was emitted successfully. + /// \param GD Global to scan. + virtual bool emitTargetGlobal(clang::GlobalDecl &D); + +protected: + CIRGenModule &CGM; +}; +} // namespace cir + +#endif // LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENOPENMPRUNTIME_H diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp index 7d2802c646ba..4e8a36edcfbd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp @@ -187,6 +187,10 @@ mlir::LogicalResult CIRGenFunction::buildStmt(const Stmt *S, case Stmt::GCCAsmStmtClass: case Stmt::MSAsmStmtClass: return buildAsmStmt(cast(*S)); + // OMP directives: + case Stmt::OMPParallelDirectiveClass: + return buildOMPParallelDirective(cast(*S)); + // Unsupported AST nodes: case Stmt::CapturedStmtClass: case Stmt::ObjCAtTryStmtClass: case Stmt::ObjCAtThrowStmtClass: @@ -197,7 +201,6 @@ mlir::LogicalResult CIRGenFunction::buildStmt(const Stmt *S, case Stmt::OMPMetaDirectiveClass: case Stmt::OMPCanonicalLoopClass: case Stmt::OMPErrorDirectiveClass: - case Stmt::OMPParallelDirectiveClass: case Stmt::OMPSimdDirectiveClass: case Stmt::OMPScopeDirectiveClass: case Stmt::OMPTileDirectiveClass: diff --git a/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp b/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp new file mode 100644 index 000000000000..3874ef3dcee6 --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp @@ -0,0 +1,45 @@ +//===--- CIRGenStmtOpenMP.cpp - Emit MLIR Code from OpenMP Statements -----===// +// +// 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 contains code to emit OpenMP Stmt nodes as MLIR code. +// +//===----------------------------------------------------------------------===// + +#include "CIRGenFunction.h" +#include "CIRGenOpenMPRuntime.h" +#include "mlir/Dialect/OpenMP/OpenMPDialect.h" + +using namespace cir; +using namespace clang; +using namespace mlir::omp; + +mlir::LogicalResult +CIRGenFunction::buildOMPParallelDirective(const OMPParallelDirective &S) { + mlir::LogicalResult res = mlir::success(); + auto scopeLoc = getLoc(S.getSourceRange()); + // Create a `omp.parallel` op. + auto parallelOp = builder.create(scopeLoc); + mlir::Block &block = parallelOp.getRegion().emplaceBlock(); + mlir::OpBuilder::InsertionGuard guardCase(builder); + builder.setInsertionPointToEnd(&block); + // Create a scope for the OpenMP region. + builder.create( + scopeLoc, /*scopeBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + LexicalScope lexScope{*this, scopeLoc, builder.getInsertionBlock()}; + // Emit the body of the region. + if (buildStmt(S.getCapturedStmt(OpenMPDirectiveKind::OMPD_parallel) + ->getCapturedStmt(), + /*useCurrentScope=*/true) + .failed()) + res = mlir::failure(); + }); + // Add the terminator for `omp.parallel`. + builder.create(getLoc(S.getSourceRange().getEnd())); + return res; +} diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp index 4fe46c923dda..4d6a6c6c5d84 100644 --- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp @@ -16,6 +16,7 @@ #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/MemRef/IR/MemRef.h" +#include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "mlir/IR/MLIRContext.h" #include "mlir/Target/LLVMIR/Import.h" @@ -58,6 +59,7 @@ void CIRGenerator::Initialize(ASTContext &astCtx) { mlirCtx->getOrLoadDialect(); mlirCtx->getOrLoadDialect(); mlirCtx->getOrLoadDialect(); + mlirCtx->getOrLoadDialect(); CGM = std::make_unique(*mlirCtx.get(), astCtx, codeGenOpts, Diags); auto mod = CGM->getModule(); diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 62df7a8d3d68..4c11e3eb8368 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -26,7 +26,9 @@ add_clang_library(clangCIR CIRGenFunction.cpp CIRGenItaniumCXXABI.cpp CIRGenModule.cpp + CIRGenOpenMPRuntime.cpp CIRGenStmt.cpp + CIRGenStmtOpenMP.cpp CIRGenTBAA.cpp CIRGenTypes.cpp CIRGenVTables.cpp @@ -58,6 +60,7 @@ add_clang_library(clangCIR MLIRIR MLIRLLVMCommonConversion MLIRLLVMDialect + MLIROpenMPDialect MLIRLLVMToLLVMIRTranslation MLIRMemRefDialect MLIRMemRefToLLVM diff --git a/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h b/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h index 1e5d1dfe7526..6c699c709ab3 100644 --- a/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h +++ b/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h @@ -121,6 +121,8 @@ struct UnimplementedFeature { static bool cxxABI() { return false; } static bool openCL() { return false; } static bool openMP() { return false; } + static bool openMPRuntime() { return false; } + static bool openMPTarget() { return false; } static bool ehStack() { return false; } static bool isVarArg() { return false; } static bool setNonGC() { return false; } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt index 14b879ee1c44..eb6991852332 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt +++ b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt @@ -34,4 +34,6 @@ add_clang_library(clangCIRLoweringDirectToLLVM MLIRTransforms MLIRSupport MLIRMemRefDialect + MLIROpenMPDialect + MLIROpenMPToLLVMIRTranslation ) diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 242f3eecb377..005d907cc202 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -42,6 +42,7 @@ #include "mlir/Support/LogicalResult.h" #include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" +#include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Export.h" #include "mlir/Transforms/DialectConversion.h" #include "clang/CIR/Dialect/IR/CIRAttrs.h" @@ -2341,6 +2342,7 @@ lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp theModule, LLVMContext &llvmCtx, mlir::registerBuiltinDialectTranslation(*mlirCtx); mlir::registerLLVMDialectTranslation(*mlirCtx); + mlir::registerOpenMPDialectTranslation(*mlirCtx); registerCIRDialectTranslation(*mlirCtx); auto ModuleName = theModule.getName(); diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/CMakeLists.txt b/clang/lib/CIR/Lowering/ThroughMLIR/CMakeLists.txt index d4a945ab7915..b92ae800918f 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/CMakeLists.txt +++ b/clang/lib/CIR/Lowering/ThroughMLIR/CMakeLists.txt @@ -34,4 +34,6 @@ add_clang_library(clangCIRLoweringThroughMLIR MLIRTransforms MLIRSupport MLIRMemRefDialect + MLIROpenMPDialect + MLIROpenMPToLLVMIRTranslation ) diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index e0a06c5bf401..948d0a34e376 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -33,6 +33,7 @@ #include "mlir/Pass/PassManager.h" #include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" +#include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Export.h" #include "mlir/Transforms/DialectConversion.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" @@ -679,6 +680,7 @@ lowerFromCIRToMLIRToLLVMIR(mlir::ModuleOp theModule, mlir::registerBuiltinDialectTranslation(*mlirCtx); mlir::registerLLVMDialectTranslation(*mlirCtx); + mlir::registerOpenMPDialectTranslation(*mlirCtx); auto llvmModule = mlir::translateModuleToLLVMIR(theModule, llvmCtx); diff --git a/clang/test/CIR/CodeGen/openmp.cpp b/clang/test/CIR/CodeGen/openmp.cpp new file mode 100644 index 000000000000..59a2c82e4efb --- /dev/null +++ b/clang/test/CIR/CodeGen/openmp.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fopenmp -fclangir-enable -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +// CHECK: cir.func +void omp_parallel_1() { +// CHECK: omp.parallel { +// CHECK-NEXT: cir.scope { +// CHECK-NEXT: } +// CHECK-NEXT: omp.terminator +// CHECK-NEXT: } +#pragma omp parallel +{ +} +} +// CHECK: cir.func +void omp_parallel_2() { +// CHECK: %[[YVarDecl:.+]] = {{.*}} ["y", init] +// CHECK: omp.parallel { +// CHECK-NEXT: cir.scope { +// CHECK-NEXT: %[[XVarDecl:.+]] = {{.*}} ["x", init] +// CHECK-NEXT: %[[C1:.+]] = cir.const(#cir.int<1> : !s32i) +// CHECK-NEXT: cir.store %[[C1]], %[[XVarDecl]] +// CHECK-NEXT: %[[XVal:.+]] = cir.load %[[XVarDecl]] +// CHECK-NEXT: %[[COne:.+]] = cir.const(#cir.int<1> : !s32i) +// CHECK-NEXT: %[[BinOpVal:.+]] = cir.binop(add, %[[XVal]], %[[COne]]) +// CHECK-NEXT: cir.store %[[BinOpVal]], %[[YVarDecl]] +// CHECK-NEXT: } +// CHECK-NEXT: omp.terminator +// CHECK-NEXT: } + int y = 0; +#pragma omp parallel +{ + int x = 1; + y = x + 1; +} +} diff --git a/clang/test/CIR/Lowering/openmp.cir b/clang/test/CIR/Lowering/openmp.cir new file mode 100644 index 000000000000..73b3155252cc --- /dev/null +++ b/clang/test/CIR/Lowering/openmp.cir @@ -0,0 +1,35 @@ +// RUN: cir-translate %s -cir-to-llvmir | FileCheck %s + +!s32i = !cir.int +module { + cir.func @omp_parallel() { + %0 = cir.alloca !s32i, cir.ptr , ["y", init] {alignment = 4 : i64} + %1 = cir.const(#cir.int<0> : !s32i) : !s32i + cir.store %1, %0 : !s32i, cir.ptr + omp.parallel { + cir.scope { + %2 = cir.alloca !s32i, cir.ptr , ["x", init] {alignment = 4 : i64} + %3 = cir.const(#cir.int<1> : !s32i) : !s32i + cir.store %3, %2 : !s32i, cir.ptr + %4 = cir.load %2 : cir.ptr , !s32i + %5 = cir.const(#cir.int<1> : !s32i) : !s32i + %6 = cir.binop(add, %4, %5) : !s32i + cir.store %6, %0 : !s32i, cir.ptr + } + omp.terminator + } + cir.return + } +} +// CHECK-LABEL: omp_parallel +// CHECK: call void (ptr, i32, ptr, ...) @__kmpc_fork_call({{.*}}, ptr @omp_parallel..omp_par, +// CHECK: ret void +// CHECK-NEXT: } +// CHECK: define{{.*}} void @omp_parallel..omp_par(ptr +// CHECK: %[[YVar:.*]] = load ptr, ptr %{{.*}}, align 8 +// CHECK: %[[XVar:.*]] = alloca i32, i64 1, align 4 +// CHECK: store i32 1, ptr %[[XVar]], align 4 +// CHECK: %[[XVal:.*]] = load i32, ptr %[[XVar]], align 4 +// CHECK: %[[BinOp:.*]] = add i32 %[[XVal]], 1 +// CHECK: store i32 %[[BinOp]], ptr %[[YVar]], align 4 +// CHECK: ret diff --git a/clang/tools/cir-opt/cir-opt.cpp b/clang/tools/cir-opt/cir-opt.cpp index 67de6a1c99be..deee67afa8a4 100644 --- a/clang/tools/cir-opt/cir-opt.cpp +++ b/clang/tools/cir-opt/cir-opt.cpp @@ -18,6 +18,7 @@ #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/MemRef/IR/MemRef.h" +#include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "mlir/InitAllPasses.h" #include "mlir/Pass/PassRegistry.h" #include "mlir/Tools/mlir-opt/MlirOptMain.h" @@ -30,7 +31,8 @@ int main(int argc, char **argv) { mlir::DialectRegistry registry; registry.insert(); + mlir::LLVM::LLVMDialect, mlir::DLTIDialect, + mlir::omp::OpenMPDialect>(); ::mlir::registerPass([]() -> std::unique_ptr<::mlir::Pass> { return cir::createConvertMLIRToLLVMPass();