https://github.com/jsjodin updated https://github.com/llvm/llvm-project/pull/178515
>From ba8ef2f036e3f32a46021db19a8fbec197eb35e2 Mon Sep 17 00:00:00 2001 From: Jan Leyonberg <[email protected]> Date: Wed, 28 Jan 2026 15:59:48 -0500 Subject: [PATCH 1/2] [CIR][OpenMP] Enable lowering of the OpenMP dialect to LLVM IR This patch adds the OpenMP dialect to be part of the lowering to LLVM IR. A couple of minor changes were made to compensate for not yet implemented features. --- clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp | 12 ++- clang/lib/CIR/CodeGen/CIRGenerator.cpp | 4 +- .../CIR/Lowering/DirectToLLVM/CMakeLists.txt | 1 + .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 2 + .../CIR/CodeGenOpenMP/not-yet-implemented.c | 3 +- clang/test/CIR/CodeGenOpenMP/parallel.c | 14 +++- clang/test/CIR/Lowering/omp.cir | 80 +++++++++++++++++++ clang/tools/cir-opt/cir-opt.cpp | 3 +- clang/tools/cir-translate/cir-translate.cpp | 4 +- 9 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 clang/test/CIR/Lowering/omp.cir diff --git a/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp b/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp index ee25f7caec619..0d3b44db98307 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp @@ -14,7 +14,7 @@ #include "CIRGenFunction.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "clang/AST/StmtOpenMP.h" - +#include "llvm/Frontend/OpenMP/OMPConstants.h" using namespace clang; using namespace clang::CIRGen; @@ -53,9 +53,13 @@ CIRGenFunction::emitOMPParallelDirective(const OMPParallelDirective &s) { if (s.getTaskReductionRefExpr()) getCIRGenModule().errorNYI(s.getBeginLoc(), "OpenMP Parallel with Task Reduction"); - - res = emitStmt(s.getAssociatedStmt(), /*useCurrentScope=*/true); - + // Don't lower the captured statement directly since this will be + // special-cased depending on the kind of OpenMP directive that is the + // parent, also the non-OpenMP context captured statements lowering does + // not apply directly. + const CapturedStmt *cs = s.getCapturedStmt(llvm::omp::OMPD_parallel); + const Stmt *bodyStmt = cs->getCapturedStmt(); + res = emitStmt(bodyStmt, /*useCurrentScope=*/true); mlir::omp::TerminatorOp::create(builder, end); } return res; diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp index 8c5d81bd61505..afa1599af8e40 100644 --- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp @@ -149,9 +149,7 @@ void CIRGenerator::HandleTagDeclDefinition(TagDecl *d) { // inline initializers as definitions. if (astContext->getTargetInfo().getCXXABI().isMicrosoft()) cgm->errorNYI(d->getSourceRange(), "HandleTagDeclDefinition: MSABI"); - // For OpenMP emit declare reduction functions, if required. - if (astContext->getLangOpts().OpenMP) - cgm->errorNYI(d->getSourceRange(), "HandleTagDeclDefinition: OpenMP"); + // TODO(OMP): For OpenMP emit declare reduction functions, if required. } void CIRGenerator::HandleTagDeclRequiredDefinition(const TagDecl *D) { diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt index 2525e02ae8f85..c7467fe40ba30 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt +++ b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt @@ -21,6 +21,7 @@ add_clang_library(clangCIRLoweringDirectToLLVM MLIRCIRTargetLowering MLIRBuiltinToLLVMIRTranslation MLIRLLVMToLLVMIRTranslation + MLIROpenMPToLLVMIRTranslation MLIRIR ) diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 4877508b1c3da..6e3fc705ea350 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -29,6 +29,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/CIRAttrs.h" @@ -4431,6 +4432,7 @@ lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp mlirModule, LLVMContext &llvmCtx) { mlir::registerBuiltinDialectTranslation(*mlirCtx); mlir::registerLLVMDialectTranslation(*mlirCtx); + mlir::registerOpenMPDialectTranslation(*mlirCtx); mlir::registerCIRDialectTranslation(*mlirCtx); llvm::TimeTraceScope translateScope("translateModuleToLLVMIR"); diff --git a/clang/test/CIR/CodeGenOpenMP/not-yet-implemented.c b/clang/test/CIR/CodeGenOpenMP/not-yet-implemented.c index 78a0bc8b2d416..6d59f45d6e5e4 100644 --- a/clang/test/CIR/CodeGenOpenMP/not-yet-implemented.c +++ b/clang/test/CIR/CodeGenOpenMP/not-yet-implemented.c @@ -12,8 +12,7 @@ void do_things() { int i; // TODO(OMP): We might consider overloading operator<< for OMPClauseKind in // the future if we want to improve this. - // expected-error@+2{{ClangIR code gen Not Yet Implemented: OpenMPClause : if}} - // expected-error@+2{{ClangIR code gen Not Yet Implemented: emitStmt: CapturedStmt}} + // expected-error@+1{{ClangIR code gen Not Yet Implemented: OpenMPClause : if}} #pragma omp parallel if(i) {} } diff --git a/clang/test/CIR/CodeGenOpenMP/parallel.c b/clang/test/CIR/CodeGenOpenMP/parallel.c index a2bfc8f4ce82e..3b43fff62c5a4 100644 --- a/clang/test/CIR/CodeGenOpenMP/parallel.c +++ b/clang/test/CIR/CodeGenOpenMP/parallel.c @@ -23,6 +23,8 @@ void emit_simple_parallel() { during(i); } // CHECK-NEXT: omp.parallel { + // CHECK-NEXT: {{.*}} = cir.load align(4) %{{.*}} : !cir.ptr<!s32i>, !s32i + // CHECK-NEXT: cir.call @during(%{{.*}}) : (!s32i) -> () // CHECK-NEXT: omp.terminator // CHECK-NEXT: } @@ -41,10 +43,18 @@ void parallel_with_operations() { // lines will need updating. #pragma omp parallel shared(a) firstprivate(b) { - ++a; - ++b; + a = a + 1; + b = b + 1; } // CHECK-NEXT: omp.parallel { + // CHECK-NEXT: cir.load align(4) %{{.*}} + // CHECK-NEXT: cir.const #cir.int<1> : !s32i + // CHECK-NEXT: cir.binop(add, %{{.*}}, %{{.*}}) nsw : !s32i + // CHECK-NEXT: cir.store align(4) %{{.*}}, %{{.*}} : !s32i, !cir.ptr<!s32i> + // CHECK-NEXT: cir.load align(4) %{{.*}} + // CHECK-NEXT: cir.const #cir.int<1> : !s32i + // CHECK-NEXT: cir.binop(add, %{{.*}}, %{{.*}}) nsw : !s32i + // CHECK-NEXT: cir.store align(4) %{{.*}}, %{{.*}} : !s32i, !cir.ptr<!s32i> // CHECK-NEXT: omp.terminator // CHECK-NEXT: } } diff --git a/clang/test/CIR/Lowering/omp.cir b/clang/test/CIR/Lowering/omp.cir new file mode 100644 index 0000000000000..78ff4cf6444c4 --- /dev/null +++ b/clang/test/CIR/Lowering/omp.cir @@ -0,0 +1,80 @@ +// RUN: cir-opt %s -cir-to-llvm -o - | FileCheck %s -check-prefix=MLIR +// RUN: cir-translate %s -cir-to-llvmir --target x86_64-unknown-linux-gnu --disable-cc-lowering | FileCheck %s -check-prefix=LLVM +!s32i = !cir.int<s, 32> + +// MLIR-LABEL: llvm.func @main() -> i32 +// MLIR-SAME: attributes {dso_local, no_inline, no_proto} +// MLIR: %[[C1:.*]] = llvm.mlir.constant(1 : i64) : i64 +// MLIR: %[[ALLOCA1:.*]] = llvm.alloca %[[C1]] x i32 {alignment = 4 : i64} +// MLIR: %[[ALLOCA2:.*]] = llvm.alloca %{{.*}} x i32 {alignment = 4 : i64} +// MLIR: %[[ALLOCA3:.*]] = llvm.alloca %{{.*}} x i32 {alignment = 4 : i64} +// MLIR: omp.parallel { +// MLIR: llvm.br ^bb{{[0-9]+}} +// MLIR: ^bb{{[0-9]+}}: +// MLIR: %[[ZERO1:.*]] = llvm.mlir.constant(0 : i32) : i32 +// MLIR: llvm.store %[[ZERO1]], %{{.*}} {alignment = 4 : i64} +// MLIR: llvm.br ^bb{{[0-9]+}} +// MLIR: ^bb{{[0-9]+}}: +// MLIR: %[[LOAD1:.*]] = llvm.load %{{.*}} {alignment = 4 : i64} +// MLIR: %[[C10000:.*]] = llvm.mlir.constant(10000 : i32) : i32 +// MLIR: %[[CMP:.*]] = llvm.icmp "slt" %[[LOAD1]], %[[C10000]] : i32 +// MLIR: llvm.cond_br %[[CMP]], ^bb{{[0-9]+}}, ^bb{{[0-9]+}} +// MLIR: ^bb{{[0-9]+}}: +// MLIR: %[[ZERO2:.*]] = llvm.mlir.constant(0 : i32) : i32 +// MLIR: llvm.store %[[ZERO2]], %{{.*}} {alignment = 4 : i64} +// MLIR: llvm.br ^bb{{[0-9]+}} +// MLIR: ^bb{{[0-9]+}}: +// MLIR: %[[LOAD2:.*]] = llvm.load %{{.*}} {alignment = 4 : i64} +// MLIR: %[[C1_I32:.*]] = llvm.mlir.constant(1 : i32) : i32 +// MLIR: %[[ADD:.*]] = llvm.add %[[LOAD2]], %[[C1_I32]] overflow<nsw> : i32 +// MLIR: llvm.store %[[ADD]], %{{.*}} {alignment = 4 : i64} +// MLIR: llvm.br ^bb{{[0-9]+}} +// MLIR: ^bb{{[0-9]+}}: +// MLIR: llvm.br ^bb{{[0-9]+}} +// MLIR: ^bb{{[0-9]+}}: +// MLIR: omp.terminator +// MLIR: %[[ZERO3:.*]] = llvm.mlir.constant(0 : i32) : i32 +// MLIR: llvm.store %[[ZERO3]], %{{.*}} {alignment = 4 : i64} +// MLIR: %[[RETVAL:.*]] = llvm.load %{{.*}} {alignment = 4 : i64} +// MLIR: llvm.return %[[RETVAL]] : i32 + +// Test only key runtime calls for LLVM IR CodeGen +// LLVM: call i32 @__kmpc_global_thread_num +// LLVM: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @1, i32 1, ptr @main..omp_par, ptr %structArg) +// LLVM: define internal void @main..omp_par(ptr noalias %tid.addr, ptr noalias %zero.addr, ptr %{{.*}}) + +module { + cir.func no_inline no_proto dso_local @main() -> !s32i { + %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] {alignment = 4 : i64} + %1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["j"] {alignment = 4 : i64} + omp.parallel { + cir.scope { + %4 = cir.alloca !s32i, !cir.ptr<!s32i>, ["i", init] {alignment = 4 : i64} + %5 = cir.const #cir.int<0> : !s32i + cir.store align(4) %5, %4 : !s32i, !cir.ptr<!s32i> + cir.for : cond { + %6 = cir.load align(4) %4 : !cir.ptr<!s32i>, !s32i + %7 = cir.const #cir.int<10000> : !s32i + %8 = cir.cmp(lt, %6, %7) : !s32i, !cir.bool + cir.condition(%8) + } body { + %6 = cir.const #cir.int<0> : !s32i + cir.store align(4) %6, %1 : !s32i, !cir.ptr<!s32i> + cir.yield + } step { + %6 = cir.load align(4) %4 : !cir.ptr<!s32i>, !s32i + %7 = cir.const #cir.int<1> : !s32i + %8 = cir.binop(add, %6, %7) nsw : !s32i + cir.store align(4) %8, %4 : !s32i, !cir.ptr<!s32i> + cir.yield + } + } + omp.terminator + } + %2 = cir.const #cir.int<0> : !s32i + cir.store %2, %0 : !s32i, !cir.ptr<!s32i> + %3 = cir.load %0 : !cir.ptr<!s32i>, !s32i + cir.return %3 : !s32i + } +} + diff --git a/clang/tools/cir-opt/cir-opt.cpp b/clang/tools/cir-opt/cir-opt.cpp index ee42015bb38e9..edadfeec09a2a 100644 --- a/clang/tools/cir-opt/cir-opt.cpp +++ b/clang/tools/cir-opt/cir-opt.cpp @@ -17,6 +17,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/BuiltinDialect.h" #include "mlir/Pass/PassManager.h" #include "mlir/Pass/PassOptions.h" @@ -35,7 +36,7 @@ int main(int argc, char **argv) { mlir::DialectRegistry registry; registry.insert<mlir::BuiltinDialect, cir::CIRDialect, mlir::memref::MemRefDialect, mlir::LLVM::LLVMDialect, - mlir::DLTIDialect>(); + mlir::DLTIDialect, mlir::omp::OpenMPDialect>(); ::mlir::registerPass([]() -> std::unique_ptr<::mlir::Pass> { return mlir::createCIRCanonicalizePass(); diff --git a/clang/tools/cir-translate/cir-translate.cpp b/clang/tools/cir-translate/cir-translate.cpp index 29a310a89de09..2b00d1bd62e4a 100644 --- a/clang/tools/cir-translate/cir-translate.cpp +++ b/clang/tools/cir-translate/cir-translate.cpp @@ -13,6 +13,7 @@ #include "mlir/Dialect/DLTI/DLTI.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/IR/MLIRContext.h" #include "mlir/InitAllTranslations.h" @@ -105,7 +106,8 @@ llvm::LogicalResult prepareCIRModuleDataLayout(mlir::ModuleOp mod, std::string layoutString = targetInfo->getDataLayoutString(); // Registered dialects may not be loaded yet, ensure they are. - context->loadDialect<mlir::DLTIDialect, mlir::LLVM::LLVMDialect>(); + context->loadDialect<mlir::DLTIDialect, mlir::LLVM::LLVMDialect, + mlir::omp::OpenMPDialect>(); mlir::DataLayoutSpecInterface dlSpec = mlir::translateDataLayout(llvm::DataLayout(layoutString), context); >From 8cd4678270c21dea43d11541e1c2ac7ef38e4c15 Mon Sep 17 00:00:00 2001 From: Jan Leyonberg <[email protected]> Date: Fri, 30 Jan 2026 10:49:19 -0500 Subject: [PATCH 2/2] Refine the OpenMP checks so that we error out if the specific cases are encountered. --- clang/lib/CIR/CodeGen/CIRGenerator.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp index afa1599af8e40..6453f3565c33d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp @@ -149,7 +149,22 @@ void CIRGenerator::HandleTagDeclDefinition(TagDecl *d) { // inline initializers as definitions. if (astContext->getTargetInfo().getCXXABI().isMicrosoft()) cgm->errorNYI(d->getSourceRange(), "HandleTagDeclDefinition: MSABI"); - // TODO(OMP): For OpenMP emit declare reduction functions, if required. + + // For OpenMP emit declare reduction functions or declare mapper, if + // required. + if (astContext->getLangOpts().OpenMP) { + for (Decl *member : d->decls()) { + if (auto *drd = dyn_cast<OMPDeclareReductionDecl>(member)) { + if (astContext->DeclMustBeEmitted(drd)) + cgm->errorNYI(d->getSourceRange(), + "HandleTagDeclDefinition: OMPDeclareReductionDecl"); + } else if (auto *dmd = dyn_cast<OMPDeclareMapperDecl>(member)) { + if (astContext->DeclMustBeEmitted(dmd)) + cgm->errorNYI(d->getSourceRange(), + "HandleTagDeclDefinition: OMPDeclareMapperDecl"); + } + } + } } void CIRGenerator::HandleTagDeclRequiredDefinition(const TagDecl *D) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
