[llvm-branch-commits] [flang] [flang][hlfir] optimize hlfir.eval_in_mem bufferization (PR #118069)
https://github.com/jeanPerier created https://github.com/llvm/llvm-project/pull/118069 This patch extends the optimize bufferization to deal with the new hlfir.eval_in_mem and move the evaluation contained in its body to operate directly over the LHS when it can prove there are no access to the LHS inside the region (and that the LHS is contiguous). This will allow the array function call optimization when lowering is changed to produce an hlfir.eval_in_mem in the next patch. >From 6be998ec6f74937820e350f51796490b41a76d46 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Thu, 28 Nov 2024 08:26:39 -0800 Subject: [PATCH] [flang][hlfir] optimize hlfir.eval_in_mem bufferization --- .../lib/Optimizer/Analysis/AliasAnalysis.cpp | 14 ++- .../Transforms/OptimizedBufferization.cpp | 108 ++ .../HLFIR/opt-bufferization-eval_in_mem.fir | 67 +++ 3 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 flang/test/HLFIR/opt-bufferization-eval_in_mem.fir diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp index 2b24791d6c7c52..c561285b9feef5 100644 --- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp +++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp @@ -91,6 +91,13 @@ bool AliasAnalysis::Source::isDummyArgument() const { return false; } +static bool isEvaluateInMemoryBlockArg(mlir::Value v) { + if (auto evalInMem = llvm::dyn_cast_or_null( + v.getParentRegion()->getParentOp())) +return evalInMem.getMemory() == v; + return false; +} + bool AliasAnalysis::Source::isData() const { return origin.isData; } bool AliasAnalysis::Source::isBoxData() const { return mlir::isa(fir::unwrapRefType(valueType)) && @@ -698,7 +705,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v, breakFromLoop = true; }); } - if (!defOp && type == SourceKind::Unknown) + if (!defOp && type == SourceKind::Unknown) { // Check if the memory source is coming through a dummy argument. if (isDummyArgument(v)) { type = SourceKind::Argument; @@ -708,7 +715,12 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v, if (isPointerReference(ty)) attributes.set(Attribute::Pointer); +} else if (isEvaluateInMemoryBlockArg(v)) { + // hlfir.eval_in_mem block operands is allocated by the operation. + type = SourceKind::Allocate; + ty = v.getType(); } + } if (type == SourceKind::Global) { return {{global, instantiationPoint, followingData}, diff --git a/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp b/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp index a0160b233e3cd1..e8c15a256b9da0 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp @@ -1108,6 +1108,113 @@ class ReductionMaskConversion : public mlir::OpRewritePattern { } }; +class EvaluateIntoMemoryAssignBufferization +: public mlir::OpRewritePattern { + +public: + using mlir::OpRewritePattern::OpRewritePattern; + + llvm::LogicalResult + matchAndRewrite(hlfir::EvaluateInMemoryOp, + mlir::PatternRewriter &rewriter) const override; +}; + +static bool mayReadOrWrite(mlir::Region ®ion, mlir::Value var) { + fir::AliasAnalysis aliasAnalysis; + for (mlir::Operation &op : region.getOps()) { +if (op.hasTrait()) { + for (mlir::Region &subRegion : op.getRegions()) +if (mayReadOrWrite(subRegion, var)) + return true; + // In MLIR, RecursiveMemoryEffects can be combined with + // MemoryEffectOpInterface to describe extra effects on top of the + // effects of the nested operations. However, the presence of + // RecursiveMemoryEffects and the absence of MemoryEffectOpInterface + // implies the operation has no other memory effects than the one of its + // nested operations. + if (!mlir::isa(op)) +continue; +} +if (!aliasAnalysis.getModRef(&op, var).isNoModRef()) + return true; + } + return false; +} + +static llvm::LogicalResult +tryUsingAssignLhsDirectly(hlfir::EvaluateInMemoryOp evalInMem, + mlir::PatternRewriter &rewriter) { + mlir::Location loc = evalInMem.getLoc(); + hlfir::DestroyOp destroy; + hlfir::AssignOp assign; + for (auto user : llvm::enumerate(evalInMem->getUsers())) { +if (user.index() > 2) + return mlir::failure(); +mlir::TypeSwitch(user.value()) +.Case([&](hlfir::AssignOp op) { assign = op; }) +.Case([&](hlfir::DestroyOp op) { destroy = op; }); + } + if (!assign || !destroy || destroy.mustFinalizeExpr() || + assign.isAllocatableAssignment()) +return mlir::failure(); + + hlfir::Entity lhs{assign.getLhs()}; + // EvaluateInMemoryOp memory is contiguous, so in general, it can only be + // replace by the LHS if the LHS is contiguous. + if (!lhs.isS
[llvm-branch-commits] [flang] [flang][hlfir] optimize hlfir.eval_in_mem bufferization (PR #118069)
llvmbot wrote: @llvm/pr-subscribers-flang-fir-hlfir Author: None (jeanPerier) Changes This patch extends the optimize bufferization to deal with the new hlfir.eval_in_mem and move the evaluation contained in its body to operate directly over the LHS when it can prove there are no access to the LHS inside the region (and that the LHS is contiguous). This will allow the array function call optimization when lowering is changed to produce an hlfir.eval_in_mem in the next patch. --- Full diff: https://github.com/llvm/llvm-project/pull/118069.diff 3 Files Affected: - (modified) flang/lib/Optimizer/Analysis/AliasAnalysis.cpp (+13-1) - (modified) flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp (+108) - (added) flang/test/HLFIR/opt-bufferization-eval_in_mem.fir (+67) ``diff diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp index 2b24791d6c7c52..c561285b9feef5 100644 --- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp +++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp @@ -91,6 +91,13 @@ bool AliasAnalysis::Source::isDummyArgument() const { return false; } +static bool isEvaluateInMemoryBlockArg(mlir::Value v) { + if (auto evalInMem = llvm::dyn_cast_or_null( + v.getParentRegion()->getParentOp())) +return evalInMem.getMemory() == v; + return false; +} + bool AliasAnalysis::Source::isData() const { return origin.isData; } bool AliasAnalysis::Source::isBoxData() const { return mlir::isa(fir::unwrapRefType(valueType)) && @@ -698,7 +705,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v, breakFromLoop = true; }); } - if (!defOp && type == SourceKind::Unknown) + if (!defOp && type == SourceKind::Unknown) { // Check if the memory source is coming through a dummy argument. if (isDummyArgument(v)) { type = SourceKind::Argument; @@ -708,7 +715,12 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v, if (isPointerReference(ty)) attributes.set(Attribute::Pointer); +} else if (isEvaluateInMemoryBlockArg(v)) { + // hlfir.eval_in_mem block operands is allocated by the operation. + type = SourceKind::Allocate; + ty = v.getType(); } + } if (type == SourceKind::Global) { return {{global, instantiationPoint, followingData}, diff --git a/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp b/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp index a0160b233e3cd1..e8c15a256b9da0 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/OptimizedBufferization.cpp @@ -1108,6 +1108,113 @@ class ReductionMaskConversion : public mlir::OpRewritePattern { } }; +class EvaluateIntoMemoryAssignBufferization +: public mlir::OpRewritePattern { + +public: + using mlir::OpRewritePattern::OpRewritePattern; + + llvm::LogicalResult + matchAndRewrite(hlfir::EvaluateInMemoryOp, + mlir::PatternRewriter &rewriter) const override; +}; + +static bool mayReadOrWrite(mlir::Region ®ion, mlir::Value var) { + fir::AliasAnalysis aliasAnalysis; + for (mlir::Operation &op : region.getOps()) { +if (op.hasTrait()) { + for (mlir::Region &subRegion : op.getRegions()) +if (mayReadOrWrite(subRegion, var)) + return true; + // In MLIR, RecursiveMemoryEffects can be combined with + // MemoryEffectOpInterface to describe extra effects on top of the + // effects of the nested operations. However, the presence of + // RecursiveMemoryEffects and the absence of MemoryEffectOpInterface + // implies the operation has no other memory effects than the one of its + // nested operations. + if (!mlir::isa(op)) +continue; +} +if (!aliasAnalysis.getModRef(&op, var).isNoModRef()) + return true; + } + return false; +} + +static llvm::LogicalResult +tryUsingAssignLhsDirectly(hlfir::EvaluateInMemoryOp evalInMem, + mlir::PatternRewriter &rewriter) { + mlir::Location loc = evalInMem.getLoc(); + hlfir::DestroyOp destroy; + hlfir::AssignOp assign; + for (auto user : llvm::enumerate(evalInMem->getUsers())) { +if (user.index() > 2) + return mlir::failure(); +mlir::TypeSwitch(user.value()) +.Case([&](hlfir::AssignOp op) { assign = op; }) +.Case([&](hlfir::DestroyOp op) { destroy = op; }); + } + if (!assign || !destroy || destroy.mustFinalizeExpr() || + assign.isAllocatableAssignment()) +return mlir::failure(); + + hlfir::Entity lhs{assign.getLhs()}; + // EvaluateInMemoryOp memory is contiguous, so in general, it can only be + // replace by the LHS if the LHS is contiguous. + if (!lhs.isSimplyContiguous()) +return mlir::failure(); + // Character assignment may involves truncation/padding, so the LHS + // cannot be used to evaluate RHS in place without proving the LHS
[llvm-branch-commits] [flang] [flang] optimize array function calls using hlfir.eval_in_mem (PR #118070)
https://github.com/jeanPerier created https://github.com/llvm/llvm-project/pull/118070 This patch encapsulate array function call lowering into hlfir.eval_in_mem and allows directly evaluating the call into the LHS when possible. The conditions are: LHS is contiguous, not accessed inside the function, it is not a whole allocatable, and the function results needs not to be finalized. All these conditions are tested in the previous [hlfir.eval_in_mem optimization patch](https://github.com/llvm/llvm-project/pull/118069) that is leveraging [the extension of getModRef to handle function calls](https://github.com/llvm/llvm-project/pull/117164)). This yields a 25% speed-up on polyhedron channel2 benchmark (from 1min to 45s measured on an X86-64 Zen 2). >From 4debf91864773ba805a9439cde9b74fc44315acc Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Thu, 28 Nov 2024 08:28:21 -0800 Subject: [PATCH] [flang] optimize array function calls using hlfir.eval_in_mem --- flang/include/flang/Lower/ConvertCall.h | 6 +- .../flang/Optimizer/HLFIR/HLFIRDialect.h | 4 + flang/lib/Lower/ConvertCall.cpp | 102 +- flang/lib/Lower/ConvertExpr.cpp | 13 +- flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp | 15 ++ flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp | 11 +- .../order_assignments/where-scheduling.f90| 2 +- .../test/Lower/HLFIR/calls-array-results.f90 | 131 ++ flang/test/Lower/HLFIR/where-nonelemental.f90 | 38 ++--- .../Lower/explicit-interface-results-2.f90| 2 - .../test/Lower/explicit-interface-results.f90 | 8 +- flang/test/Lower/forall/array-constructor.f90 | 2 +- 12 files changed, 260 insertions(+), 74 deletions(-) create mode 100644 flang/test/Lower/HLFIR/calls-array-results.f90 diff --git a/flang/include/flang/Lower/ConvertCall.h b/flang/include/flang/Lower/ConvertCall.h index bc082907e61760..2c51a887010c87 100644 --- a/flang/include/flang/Lower/ConvertCall.h +++ b/flang/include/flang/Lower/ConvertCall.h @@ -24,6 +24,10 @@ namespace Fortran::lower { +struct LoweredResult { + std::variant result; +}; + /// Given a call site for which the arguments were already lowered, generate /// the call and return the result. This function deals with explicit result /// allocation and lowering if needed. It also deals with passing the host @@ -32,7 +36,7 @@ namespace Fortran::lower { /// It is only used for HLFIR. /// The returned boolean indicates if finalization has been emitted in /// \p stmtCtx for the result. -std::pair genCallOpAndResult( +std::pair genCallOpAndResult( mlir::Location loc, Fortran::lower::AbstractConverter &converter, Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx, Fortran::lower::CallerInterface &caller, mlir::FunctionType callSiteType, diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h index 3830237f96f3cc..447d5fbab89998 100644 --- a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h +++ b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h @@ -61,6 +61,10 @@ inline mlir::Type getFortranElementOrSequenceType(mlir::Type type) { return type; } +/// Build the hlfir.expr type for the value held in a variable of type \p +/// variableType. +mlir::Type getExprType(mlir::Type variableType); + /// Is this a fir.box or fir.class address type? inline bool isBoxAddressType(mlir::Type type) { type = fir::dyn_cast_ptrEleTy(type); diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp index e84e7afbe82e09..088d8f96caa410 100644 --- a/flang/lib/Lower/ConvertCall.cpp +++ b/flang/lib/Lower/ConvertCall.cpp @@ -284,7 +284,8 @@ static void remapActualToDummyDescriptors( } } -std::pair Fortran::lower::genCallOpAndResult( +std::pair +Fortran::lower::genCallOpAndResult( mlir::Location loc, Fortran::lower::AbstractConverter &converter, Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx, Fortran::lower::CallerInterface &caller, mlir::FunctionType callSiteType, @@ -326,6 +327,11 @@ std::pair Fortran::lower::genCallOpAndResult( } } + const bool isExprCall = + converter.getLoweringOptions().getLowerToHighLevelFIR() && + callSiteType.getNumResults() == 1 && + llvm::isa(callSiteType.getResult(0)); + mlir::IndexType idxTy = builder.getIndexType(); auto lowerSpecExpr = [&](const auto &expr) -> mlir::Value { mlir::Value convertExpr = builder.createConvert( @@ -333,6 +339,8 @@ std::pair Fortran::lower::genCallOpAndResult( return fir::factory::genMaxWithZero(builder, loc, convertExpr); }; llvm::SmallVector resultLengths; + mlir::Value arrayResultShape; + hlfir::EvaluateInMemoryOp evaluateInMemory; auto allocatedResult = [&]() -> std::optional { llvm::SmallVector extents; llvm::SmallVector lengths; @@ -366,6 +374,18 @@ std::pair Fortran::lower::genCallOpAndResult(
[llvm-branch-commits] [flang] [flang] optimize array function calls using hlfir.eval_in_mem (PR #118070)
llvmbot wrote: @llvm/pr-subscribers-flang-fir-hlfir Author: None (jeanPerier) Changes This patch encapsulate array function call lowering into hlfir.eval_in_mem and allows directly evaluating the call into the LHS when possible. The conditions are: LHS is contiguous, not accessed inside the function, it is not a whole allocatable, and the function results needs not to be finalized. All these conditions are tested in the previous [hlfir.eval_in_mem optimization patch](https://github.com/llvm/llvm-project/pull/118069) that is leveraging [the extension of getModRef to handle function calls](https://github.com/llvm/llvm-project/pull/117164)). This yields a 25% speed-up on polyhedron channel2 benchmark (from 1min to 45s measured on an X86-64 Zen 2). --- Patch is 34.18 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/118070.diff 12 Files Affected: - (modified) flang/include/flang/Lower/ConvertCall.h (+5-1) - (modified) flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h (+4) - (modified) flang/lib/Lower/ConvertCall.cpp (+69-33) - (modified) flang/lib/Lower/ConvertExpr.cpp (+8-5) - (modified) flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp (+15) - (modified) flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp (+1-10) - (modified) flang/test/HLFIR/order_assignments/where-scheduling.f90 (+1-1) - (added) flang/test/Lower/HLFIR/calls-array-results.f90 (+131) - (modified) flang/test/Lower/HLFIR/where-nonelemental.f90 (+21-17) - (modified) flang/test/Lower/explicit-interface-results-2.f90 (-2) - (modified) flang/test/Lower/explicit-interface-results.f90 (+4-4) - (modified) flang/test/Lower/forall/array-constructor.f90 (+1-1) ``diff diff --git a/flang/include/flang/Lower/ConvertCall.h b/flang/include/flang/Lower/ConvertCall.h index bc082907e61760..2c51a887010c87 100644 --- a/flang/include/flang/Lower/ConvertCall.h +++ b/flang/include/flang/Lower/ConvertCall.h @@ -24,6 +24,10 @@ namespace Fortran::lower { +struct LoweredResult { + std::variant result; +}; + /// Given a call site for which the arguments were already lowered, generate /// the call and return the result. This function deals with explicit result /// allocation and lowering if needed. It also deals with passing the host @@ -32,7 +36,7 @@ namespace Fortran::lower { /// It is only used for HLFIR. /// The returned boolean indicates if finalization has been emitted in /// \p stmtCtx for the result. -std::pair genCallOpAndResult( +std::pair genCallOpAndResult( mlir::Location loc, Fortran::lower::AbstractConverter &converter, Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx, Fortran::lower::CallerInterface &caller, mlir::FunctionType callSiteType, diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h index 3830237f96f3cc..447d5fbab89998 100644 --- a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h +++ b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h @@ -61,6 +61,10 @@ inline mlir::Type getFortranElementOrSequenceType(mlir::Type type) { return type; } +/// Build the hlfir.expr type for the value held in a variable of type \p +/// variableType. +mlir::Type getExprType(mlir::Type variableType); + /// Is this a fir.box or fir.class address type? inline bool isBoxAddressType(mlir::Type type) { type = fir::dyn_cast_ptrEleTy(type); diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp index e84e7afbe82e09..088d8f96caa410 100644 --- a/flang/lib/Lower/ConvertCall.cpp +++ b/flang/lib/Lower/ConvertCall.cpp @@ -284,7 +284,8 @@ static void remapActualToDummyDescriptors( } } -std::pair Fortran::lower::genCallOpAndResult( +std::pair +Fortran::lower::genCallOpAndResult( mlir::Location loc, Fortran::lower::AbstractConverter &converter, Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx, Fortran::lower::CallerInterface &caller, mlir::FunctionType callSiteType, @@ -326,6 +327,11 @@ std::pair Fortran::lower::genCallOpAndResult( } } + const bool isExprCall = + converter.getLoweringOptions().getLowerToHighLevelFIR() && + callSiteType.getNumResults() == 1 && + llvm::isa(callSiteType.getResult(0)); + mlir::IndexType idxTy = builder.getIndexType(); auto lowerSpecExpr = [&](const auto &expr) -> mlir::Value { mlir::Value convertExpr = builder.createConvert( @@ -333,6 +339,8 @@ std::pair Fortran::lower::genCallOpAndResult( return fir::factory::genMaxWithZero(builder, loc, convertExpr); }; llvm::SmallVector resultLengths; + mlir::Value arrayResultShape; + hlfir::EvaluateInMemoryOp evaluateInMemory; auto allocatedResult = [&]() -> std::optional { llvm::SmallVector extents; llvm::SmallVector lengths; @@ -366,6 +374,18 @@ std::pair Fortran::lower::genCallOpAndResult( resultLengths = lengths; } +if (!extents.empty()) + arrayResultShap
[llvm-branch-commits] [flang] [flang] optimize array function calls using hlfir.eval_in_mem (PR #118070)
jeanPerier wrote: Note that this is a "classic" Fortran compiler optimization, you can verify that at least all of gfortran, ifx, and nvfortran are doing it on something very easy like: ``` subroutine test interface function foo() real :: foo(100) end function end interface real x(100) x = foo() call bar(x) end subroutine ``` https://github.com/llvm/llvm-project/pull/118070 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/19.x: [clang-repl] Fix generation of wasm binaries while running clang-repl in browser (#117978) (PR #118077)
llvmbot wrote: @vgvassilev What do you think about merging this PR to the release branch? https://github.com/llvm/llvm-project/pull/118077 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/19.x: [clang-repl] Fix generation of wasm binaries while running clang-repl in browser (#117978) (PR #118077)
https://github.com/llvmbot milestoned https://github.com/llvm/llvm-project/pull/118077 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/19.x: [clang-repl] Fix generation of wasm binaries while running clang-repl in browser (#117978) (PR #118077)
https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/118077 Backport a174aa1e416c4e27945f5a8c646b119126dc8441 Requested by: @anutosh491 >From d181adec32cf3c5e6dfee26f2b4b5d9aa543ea6a Mon Sep 17 00:00:00 2001 From: Anutosh Bhat Date: Fri, 29 Nov 2024 15:31:02 +0530 Subject: [PATCH] [clang-repl] Fix generation of wasm binaries while running clang-repl in browser (#117978) Co-authored-by: Vassil Vassilev (cherry picked from commit a174aa1e416c4e27945f5a8c646b119126dc8441) --- clang/lib/Interpreter/CMakeLists.txt | 2 + clang/lib/Interpreter/Interpreter.cpp | 1 + clang/lib/Interpreter/Wasm.cpp| 57 --- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt index 0a2d60757c216d..85efa4b0f984f4 100644 --- a/clang/lib/Interpreter/CMakeLists.txt +++ b/clang/lib/Interpreter/CMakeLists.txt @@ -15,6 +15,7 @@ set(LLVM_LINK_COMPONENTS if (EMSCRIPTEN AND "lld" IN_LIST LLVM_ENABLE_PROJECTS) set(WASM_SRC Wasm.cpp) set(WASM_LINK lldWasm) + set(COMMON_LINK lldCommon) endif() add_clang_library(clangInterpreter @@ -45,6 +46,7 @@ add_clang_library(clangInterpreter clangSema clangSerialization ${WASM_LINK} + ${COMMON_LINK} ) if ((MINGW OR CYGWIN) AND BUILD_SHARED_LIBS) diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index c0b8bfebb43437..985d0b7c0ef311 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -193,6 +193,7 @@ IncrementalCompilerBuilder::CreateCpp() { Argv.push_back("-target"); Argv.push_back("wasm32-unknown-emscripten"); Argv.push_back("-shared"); + Argv.push_back("-fvisibility=default"); #endif Argv.insert(Argv.end(), UserArgs.begin(), UserArgs.end()); diff --git a/clang/lib/Interpreter/Wasm.cpp b/clang/lib/Interpreter/Wasm.cpp index 79efbaa03982d0..aa10b160ccf847 100644 --- a/clang/lib/Interpreter/Wasm.cpp +++ b/clang/lib/Interpreter/Wasm.cpp @@ -23,6 +23,31 @@ #include namespace lld { +enum Flavor { + Invalid, + Gnu, // -flavor gnu + MinGW, // -flavor gnu MinGW + WinLink, // -flavor link + Darwin, // -flavor darwin + Wasm,// -flavor wasm +}; + +using Driver = bool (*)(llvm::ArrayRef, llvm::raw_ostream &, +llvm::raw_ostream &, bool, bool); + +struct DriverDef { + Flavor f; + Driver d; +}; + +struct Result { + int retCode; + bool canRunAgain; +}; + +Result lldMain(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, + llvm::raw_ostream &stderrOS, llvm::ArrayRef drivers); + namespace wasm { bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); @@ -51,13 +76,14 @@ llvm::Error WasmIncrementalExecutor::addModule(PartialTranslationUnit &PTU) { llvm::TargetMachine *TargetMachine = Target->createTargetMachine( PTU.TheModule->getTargetTriple(), "", "", TO, llvm::Reloc::Model::PIC_); PTU.TheModule->setDataLayout(TargetMachine->createDataLayout()); - std::string OutputFileName = PTU.TheModule->getName().str() + ".wasm"; + std::string ObjectFileName = PTU.TheModule->getName().str() + ".o"; + std::string BinaryFileName = PTU.TheModule->getName().str() + ".wasm"; std::error_code Error; - llvm::raw_fd_ostream OutputFile(llvm::StringRef(OutputFileName), Error); + llvm::raw_fd_ostream ObjectFileOutput(llvm::StringRef(ObjectFileName), Error); llvm::legacy::PassManager PM; - if (TargetMachine->addPassesToEmitFile(PM, OutputFile, nullptr, + if (TargetMachine->addPassesToEmitFile(PM, ObjectFileOutput, nullptr, llvm::CodeGenFileType::ObjectFile)) { return llvm::make_error( "Wasm backend cannot produce object.", llvm::inconvertibleErrorCode()); @@ -69,27 +95,30 @@ llvm::Error WasmIncrementalExecutor::addModule(PartialTranslationUnit &PTU) { llvm::inconvertibleErrorCode()); } - OutputFile.close(); + ObjectFileOutput.close(); std::vector LinkerArgs = {"wasm-ld", "-shared", "--import-memory", - "--no-entry", - "--export-all", "--experimental-pic", "--stack-first", "--allow-undefined", - OutputFileName.c_str(), + ObjectFileName.c_str(), "-o", - OutputFileName.c_str()}; - int Result = - lld::wasm::link(LinkerArgs, llvm::outs(), llvm::errs(), false, false); - if (!Result) +
[llvm-branch-commits] [clang] release/19.x: [clang-repl] Fix generation of wasm binaries while running clang-repl in browser (#117978) (PR #118077)
llvmbot wrote: @llvm/pr-subscribers-clang Author: None (llvmbot) Changes Backport a174aa1e416c4e27945f5a8c646b119126dc8441 Requested by: @anutosh491 --- Full diff: https://github.com/llvm/llvm-project/pull/118077.diff 3 Files Affected: - (modified) clang/lib/Interpreter/CMakeLists.txt (+2) - (modified) clang/lib/Interpreter/Interpreter.cpp (+1) - (modified) clang/lib/Interpreter/Wasm.cpp (+43-14) ``diff diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt index 0a2d60757c216d..85efa4b0f984f4 100644 --- a/clang/lib/Interpreter/CMakeLists.txt +++ b/clang/lib/Interpreter/CMakeLists.txt @@ -15,6 +15,7 @@ set(LLVM_LINK_COMPONENTS if (EMSCRIPTEN AND "lld" IN_LIST LLVM_ENABLE_PROJECTS) set(WASM_SRC Wasm.cpp) set(WASM_LINK lldWasm) + set(COMMON_LINK lldCommon) endif() add_clang_library(clangInterpreter @@ -45,6 +46,7 @@ add_clang_library(clangInterpreter clangSema clangSerialization ${WASM_LINK} + ${COMMON_LINK} ) if ((MINGW OR CYGWIN) AND BUILD_SHARED_LIBS) diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index c0b8bfebb43437..985d0b7c0ef311 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -193,6 +193,7 @@ IncrementalCompilerBuilder::CreateCpp() { Argv.push_back("-target"); Argv.push_back("wasm32-unknown-emscripten"); Argv.push_back("-shared"); + Argv.push_back("-fvisibility=default"); #endif Argv.insert(Argv.end(), UserArgs.begin(), UserArgs.end()); diff --git a/clang/lib/Interpreter/Wasm.cpp b/clang/lib/Interpreter/Wasm.cpp index 79efbaa03982d0..aa10b160ccf847 100644 --- a/clang/lib/Interpreter/Wasm.cpp +++ b/clang/lib/Interpreter/Wasm.cpp @@ -23,6 +23,31 @@ #include namespace lld { +enum Flavor { + Invalid, + Gnu, // -flavor gnu + MinGW, // -flavor gnu MinGW + WinLink, // -flavor link + Darwin, // -flavor darwin + Wasm,// -flavor wasm +}; + +using Driver = bool (*)(llvm::ArrayRef, llvm::raw_ostream &, +llvm::raw_ostream &, bool, bool); + +struct DriverDef { + Flavor f; + Driver d; +}; + +struct Result { + int retCode; + bool canRunAgain; +}; + +Result lldMain(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, + llvm::raw_ostream &stderrOS, llvm::ArrayRef drivers); + namespace wasm { bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); @@ -51,13 +76,14 @@ llvm::Error WasmIncrementalExecutor::addModule(PartialTranslationUnit &PTU) { llvm::TargetMachine *TargetMachine = Target->createTargetMachine( PTU.TheModule->getTargetTriple(), "", "", TO, llvm::Reloc::Model::PIC_); PTU.TheModule->setDataLayout(TargetMachine->createDataLayout()); - std::string OutputFileName = PTU.TheModule->getName().str() + ".wasm"; + std::string ObjectFileName = PTU.TheModule->getName().str() + ".o"; + std::string BinaryFileName = PTU.TheModule->getName().str() + ".wasm"; std::error_code Error; - llvm::raw_fd_ostream OutputFile(llvm::StringRef(OutputFileName), Error); + llvm::raw_fd_ostream ObjectFileOutput(llvm::StringRef(ObjectFileName), Error); llvm::legacy::PassManager PM; - if (TargetMachine->addPassesToEmitFile(PM, OutputFile, nullptr, + if (TargetMachine->addPassesToEmitFile(PM, ObjectFileOutput, nullptr, llvm::CodeGenFileType::ObjectFile)) { return llvm::make_error( "Wasm backend cannot produce object.", llvm::inconvertibleErrorCode()); @@ -69,27 +95,30 @@ llvm::Error WasmIncrementalExecutor::addModule(PartialTranslationUnit &PTU) { llvm::inconvertibleErrorCode()); } - OutputFile.close(); + ObjectFileOutput.close(); std::vector LinkerArgs = {"wasm-ld", "-shared", "--import-memory", - "--no-entry", - "--export-all", "--experimental-pic", "--stack-first", "--allow-undefined", - OutputFileName.c_str(), + ObjectFileName.c_str(), "-o", - OutputFileName.c_str()}; - int Result = - lld::wasm::link(LinkerArgs, llvm::outs(), llvm::errs(), false, false); - if (!Result) + BinaryFileName.c_str()}; + + const lld::DriverDef WasmDriver = {lld::Flavor::Wasm, &lld::wasm::link}; + std::vector WasmDriverArgs; + WasmDriverArgs.push_back(WasmDriver); + lld::Result Result = + lld::lldMain(LinkerArgs, llvm::outs(), llvm::errs(), WasmDriverArgs); + + if (Re
[llvm-branch-commits] [clang] release/19.x: [clang-repl] Fix generation of wasm binaries while running clang-repl in browser (#117978) (PR #118077)
https://github.com/vgvassilev approved this pull request. This is a low risk feature as it is maintained at a best effort basis at the moment. LGTM! https://github.com/llvm/llvm-project/pull/118077 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] release/19.x: [clang-repl] Fix generation of wasm binaries while running clang-repl in browser (#117978) (PR #118077)
anutosh491 wrote: Hi @tru Just curious as to know when a 19.1.5 release is scheduled ? https://github.com/llvm/llvm-project/pull/118077 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [compiler-rt] [TySan] Fix struct access with different bases (PR #108385)
https://github.com/gbMattN updated https://github.com/llvm/llvm-project/pull/108385 >From 4f5a7f198988a45fe64b9d1ba88e68a6d7f14e32 Mon Sep 17 00:00:00 2001 From: Matthew Nagy Date: Thu, 12 Sep 2024 12:36:57 + Subject: [PATCH 1/4] [TySan] Fix struct access with different bases --- compiler-rt/lib/tysan/tysan.cpp | 5 +++ .../tysan/struct-offset-different-base.cpp| 33 +++ 2 files changed, 38 insertions(+) create mode 100644 compiler-rt/test/tysan/struct-offset-different-base.cpp diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp index f1b6bdcf0d8261..c339a0fca11397 100644 --- a/compiler-rt/lib/tysan/tysan.cpp +++ b/compiler-rt/lib/tysan/tysan.cpp @@ -129,6 +129,11 @@ static bool isAliasingLegalUp(tysan_type_descriptor *TDA, break; } + // This offset can't be negative. Therefore we must be accessing something + // partially inside the last type + if (TDA->Struct.Members[Idx].Offset > OffsetA) +Idx -= 1; + OffsetA -= TDA->Struct.Members[Idx].Offset; TDA = TDA->Struct.Members[Idx].Type; } else { diff --git a/compiler-rt/test/tysan/struct-offset-different-base.cpp b/compiler-rt/test/tysan/struct-offset-different-base.cpp new file mode 100644 index 00..3e1d6f2a6a42f5 --- /dev/null +++ b/compiler-rt/test/tysan/struct-offset-different-base.cpp @@ -0,0 +1,33 @@ +// RUN: %clangxx_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// Modified reproducer from https://github.com/llvm/llvm-project/issues/105960 + +#include + +struct inner { + char buffer; + int i; +}; + +void init_inner(inner *iPtr) { + iPtr->i = 0; +} + +struct outer { + inner foo; +char buffer; +}; + +int main(void) { +outer *l = new outer(); + +init_inner(&l->foo); + +int access_offsets_with_different_base = l->foo.i; +printf("%d\n", access_offsets_with_different_base); + +return 0; +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation >From 6f795458c4c16522533dbdcb4d8ace299bfda9ff Mon Sep 17 00:00:00 2001 From: gbMattN Date: Tue, 12 Nov 2024 17:05:44 + Subject: [PATCH 2/4] Changed test to check for output --- compiler-rt/test/tysan/struct-offset-different-base.cpp | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler-rt/test/tysan/struct-offset-different-base.cpp b/compiler-rt/test/tysan/struct-offset-different-base.cpp index 3e1d6f2a6a42f5..4563f7025bea48 100644 --- a/compiler-rt/test/tysan/struct-offset-different-base.cpp +++ b/compiler-rt/test/tysan/struct-offset-different-base.cpp @@ -1,5 +1,5 @@ // RUN: %clangxx_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 -// RUN: FileCheck %s < %t.out +// RUN: FileCheck %s --implicit-check-not ERROR < %t.out // Modified reproducer from https://github.com/llvm/llvm-project/issues/105960 @@ -11,7 +11,7 @@ struct inner { }; void init_inner(inner *iPtr) { - iPtr->i = 0; + iPtr->i = 200; } struct outer { @@ -25,9 +25,9 @@ int main(void) { init_inner(&l->foo); int access_offsets_with_different_base = l->foo.i; -printf("%d\n", access_offsets_with_different_base); +printf("Accessed value is %d\n", access_offsets_with_different_base); return 0; } -// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation +// CHECK: Accessed value is 200 >From 3e2499197f82a53d8eb44239598d5276638a80f9 Mon Sep 17 00:00:00 2001 From: gbMattN Date: Tue, 26 Nov 2024 16:44:43 + Subject: [PATCH 3/4] More format changes --- compiler-rt/lib/tysan/tysan.cpp | 2 +- .../tysan/struct-offset-different-base.cpp| 28 +-- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp index c339a0fca11397..c032bd1c0a5f7c 100644 --- a/compiler-rt/lib/tysan/tysan.cpp +++ b/compiler-rt/lib/tysan/tysan.cpp @@ -133,7 +133,7 @@ static bool isAliasingLegalUp(tysan_type_descriptor *TDA, // partially inside the last type if (TDA->Struct.Members[Idx].Offset > OffsetA) Idx -= 1; - + OffsetA -= TDA->Struct.Members[Idx].Offset; TDA = TDA->Struct.Members[Idx].Type; } else { diff --git a/compiler-rt/test/tysan/struct-offset-different-base.cpp b/compiler-rt/test/tysan/struct-offset-different-base.cpp index 4563f7025bea48..da0efd2cb6503c 100644 --- a/compiler-rt/test/tysan/struct-offset-different-base.cpp +++ b/compiler-rt/test/tysan/struct-offset-different-base.cpp @@ -6,28 +6,26 @@ #include struct inner { - char buffer; - int i; + char buffer; + int i; }; -void init_inner(inner *iPtr) { - iPtr->i = 200; -} +void init_inner(inner *iPtr) { iPtr->i = 200; } struct outer { - inner foo; -char buffer; + inner foo; + char buffer; }; int main(void) { -outer *l = new outer(); - -init_inner(&l->foo); - -i
[llvm-branch-commits] [compiler-rt] [TySan] Fixed false positive when accessing offset member variables (PR #95387)
https://github.com/gbMattN updated https://github.com/llvm/llvm-project/pull/95387 >From 620ee820a39ac1e92ee86f64d290ad32b8d426be Mon Sep 17 00:00:00 2001 From: Matthew Nagy Date: Fri, 28 Jun 2024 16:12:31 + Subject: [PATCH 1/2] [TySan] Fixed false positive when accessing global object's member variables --- compiler-rt/lib/tysan/tysan.cpp | 19 +++- .../test/tysan/global-struct-members.c| 31 +++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 compiler-rt/test/tysan/global-struct-members.c diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp index f1b6bdcf0d8261..5ba967c0782e08 100644 --- a/compiler-rt/lib/tysan/tysan.cpp +++ b/compiler-rt/lib/tysan/tysan.cpp @@ -226,7 +226,24 @@ __tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) { OldTDPtr -= i; OldTD = *OldTDPtr; -if (!isAliasingLegal(td, OldTD, i)) +// When shadow memory is set for global objects, the entire object is tagged with the struct type +// This means that when you access a member variable, tysan reads that as you accessing a struct midway +// through, with 'i' being the offset +// Therefore, if you are accessing a struct, we need to find the member type. We can go through the +// members of the struct type and see if there is a member at the offset you are accessing the struct by. +// If there is indeed a member starting at offset 'i' in the struct, we should check aliasing legality +// with that type. If there isn't, we run alias checking on the struct with will give us the correct error. +tysan_type_descriptor *InternalMember = OldTD; +if (OldTD->Tag == TYSAN_STRUCT_TD) { + for (int j = 0; j < OldTD->Struct.MemberCount; j++) { +if (OldTD->Struct.Members[j].Offset == i) { + InternalMember = OldTD->Struct.Members[j].Type; + break; +} + } +} + +if (!isAliasingLegal(td, InternalMember, i)) reportError(addr, size, td, OldTD, AccessStr, "accesses part of an existing object", -i, pc, bp, sp); diff --git a/compiler-rt/test/tysan/global-struct-members.c b/compiler-rt/test/tysan/global-struct-members.c new file mode 100644 index 00..76ea3c431dd7bc --- /dev/null +++ b/compiler-rt/test/tysan/global-struct-members.c @@ -0,0 +1,31 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +struct X { + int a, b, c; +} x; + +static struct X xArray[2]; + +int main() { + x.a = 1; + x.b = 2; + x.c = 3; + + printf("%d %d %d\n", x.a, x.b, x.c); + // CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation + + for (size_t i = 0; i < 2; i++) { +xArray[i].a = 1; +xArray[i].b = 1; +xArray[i].c = 1; + } + + struct X *xPtr = (struct X *)&(xArray[0].c); + xPtr->a = 1; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int (in X at offset 0) accesses an existing object of type int (in X at offset 8) + // CHECK: {{#0 0x.* in main .*struct-members.c:}}[[@LINE-3]] +} >From 9a2c70c7e6c8e78116068b729d129f152bc398b6 Mon Sep 17 00:00:00 2001 From: gbMattN Date: Tue, 12 Nov 2024 16:52:27 + Subject: [PATCH 2/2] [style] Tidied up comments, formatting, and polished test --- compiler-rt/lib/tysan/tysan.cpp | 24 ++- .../test/tysan/global-struct-members.c| 7 +++--- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp index 5ba967c0782e08..d9029751208ea9 100644 --- a/compiler-rt/lib/tysan/tysan.cpp +++ b/compiler-rt/lib/tysan/tysan.cpp @@ -226,24 +226,26 @@ __tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) { OldTDPtr -= i; OldTD = *OldTDPtr; -// When shadow memory is set for global objects, the entire object is tagged with the struct type -// This means that when you access a member variable, tysan reads that as you accessing a struct midway -// through, with 'i' being the offset -// Therefore, if you are accessing a struct, we need to find the member type. We can go through the -// members of the struct type and see if there is a member at the offset you are accessing the struct by. -// If there is indeed a member starting at offset 'i' in the struct, we should check aliasing legality -// with that type. If there isn't, we run alias checking on the struct with will give us the correct error. -tysan_type_descriptor *InternalMember = OldTD; +// When shadow memory is set for global objects, the entire object is tagged +// with the struct type This means that when you access a member variable, +// tysan reads that as you accessing a struct midway through, with 'i' being +// the offset Therefore, if you are accessing a struct, we need to find the +// member type. W
[llvm-branch-commits] [flang] [flang][hlfir] optimize hlfir.eval_in_mem bufferization (PR #118069)
https://github.com/tblah approved this pull request. LGTM. Just some nitpicks. It is really good seeing how cleanly HLFIR extends to this new optimization. https://github.com/llvm/llvm-project/pull/118069 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [flang][hlfir] optimize hlfir.eval_in_mem bufferization (PR #118069)
https://github.com/tblah edited https://github.com/llvm/llvm-project/pull/118069 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [flang][hlfir] optimize hlfir.eval_in_mem bufferization (PR #118069)
@@ -1108,6 +1108,113 @@ class ReductionMaskConversion : public mlir::OpRewritePattern { } }; +class EvaluateIntoMemoryAssignBufferization +: public mlir::OpRewritePattern { + +public: + using mlir::OpRewritePattern::OpRewritePattern; + + llvm::LogicalResult + matchAndRewrite(hlfir::EvaluateInMemoryOp, + mlir::PatternRewriter &rewriter) const override; +}; + +static bool mayReadOrWrite(mlir::Region ®ion, mlir::Value var) { tblah wrote: Please could you add documentation explaining that the side effects you are interested in cannot be modeled by `mlir::MemoryEffectOpInterface`. Without that information this function is surprising because it is checking mlir memory effect interfaces but without using the read or write effects from that interface (instead using the alias analysis to determine memory effects). Maybe we need something in the name to make is clear this uses the high-cost high-precision model as a fallback when more precision is needed than just querying the mlir memory effects. Perhaps `mayReadOrWriteAA`. https://github.com/llvm/llvm-project/pull/118069 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [flang][hlfir] optimize hlfir.eval_in_mem bufferization (PR #118069)
@@ -1108,6 +1108,113 @@ class ReductionMaskConversion : public mlir::OpRewritePattern { } }; +class EvaluateIntoMemoryAssignBufferization +: public mlir::OpRewritePattern { + +public: + using mlir::OpRewritePattern::OpRewritePattern; + + llvm::LogicalResult + matchAndRewrite(hlfir::EvaluateInMemoryOp, + mlir::PatternRewriter &rewriter) const override; +}; + +static bool mayReadOrWrite(mlir::Region ®ion, mlir::Value var) { + fir::AliasAnalysis aliasAnalysis; + for (mlir::Operation &op : region.getOps()) { +if (op.hasTrait()) { + for (mlir::Region &subRegion : op.getRegions()) +if (mayReadOrWrite(subRegion, var)) + return true; + // In MLIR, RecursiveMemoryEffects can be combined with + // MemoryEffectOpInterface to describe extra effects on top of the + // effects of the nested operations. However, the presence of + // RecursiveMemoryEffects and the absence of MemoryEffectOpInterface + // implies the operation has no other memory effects than the one of its + // nested operations. + if (!mlir::isa(op)) +continue; +} +if (!aliasAnalysis.getModRef(&op, var).isNoModRef()) + return true; + } + return false; +} + +static llvm::LogicalResult +tryUsingAssignLhsDirectly(hlfir::EvaluateInMemoryOp evalInMem, + mlir::PatternRewriter &rewriter) { + mlir::Location loc = evalInMem.getLoc(); + hlfir::DestroyOp destroy; + hlfir::AssignOp assign; + for (auto user : llvm::enumerate(evalInMem->getUsers())) { +if (user.index() > 2) + return mlir::failure(); +mlir::TypeSwitch(user.value()) +.Case([&](hlfir::AssignOp op) { assign = op; }) +.Case([&](hlfir::DestroyOp op) { destroy = op; }); + } + if (!assign || !destroy || destroy.mustFinalizeExpr() || + assign.isAllocatableAssignment()) +return mlir::failure(); + + hlfir::Entity lhs{assign.getLhs()}; + // EvaluateInMemoryOp memory is contiguous, so in general, it can only be + // replace by the LHS if the LHS is contiguous. + if (!lhs.isSimplyContiguous()) +return mlir::failure(); + // Character assignment may involves truncation/padding, so the LHS + // cannot be used to evaluate RHS in place without proving the LHS and + // RHS lengths are the same. + if (lhs.isCharacter()) +return mlir::failure(); + + // The region must not read or write the LHS. + if (mayReadOrWrite(evalInMem.getBody(), lhs)) tblah wrote: Please could you add a comment explaining that currently this is used for optimizing function calls, and mlir memory effects aren't helpful for fir.call so there's no benefit in first filtering by mlir memory effects as is done below. https://github.com/llvm/llvm-project/pull/118069 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [flang] optimize array function calls using hlfir.eval_in_mem (PR #118070)
@@ -134,7 +134,7 @@ end function f !CHECK-NEXT: run 1 save: where/mask !CHECK-NEXT: run 2 evaluate: where/region_assign1 !CHECK-LABEL: scheduling where in _QPonly_once -!CHECK-NEXT: unknown effect: %{{[0-9]+}} = llvm.intr.stacksave : !llvm.ptr +!CHECK-NEXT: unknown effect: %11 = fir.call @_QPcall_me_only_once() fastmath : () -> !fir.array<10x!fir.logical<4>> tblah wrote: Why did this change? https://github.com/llvm/llvm-project/pull/118070 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [flang] optimize array function calls using hlfir.eval_in_mem (PR #118070)
@@ -24,6 +24,10 @@ namespace Fortran::lower { +struct LoweredResult { + std::variant result; +}; tblah wrote: nit: Could this be simplified to ```c++ using LoweredResult = std::variant result; ``` This way callers wouldn't have to add a `.result`. https://github.com/llvm/llvm-project/pull/118070 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [flang] optimize array function calls using hlfir.eval_in_mem (PR #118070)
@@ -134,7 +134,7 @@ end function f !CHECK-NEXT: run 1 save: where/mask !CHECK-NEXT: run 2 evaluate: where/region_assign1 !CHECK-LABEL: scheduling where in _QPonly_once -!CHECK-NEXT: unknown effect: %{{[0-9]+}} = llvm.intr.stacksave : !llvm.ptr +!CHECK-NEXT: unknown effect: %11 = fir.call @_QPcall_me_only_once() fastmath : () -> !fir.array<10x!fir.logical<4>> jeanPerier wrote: Because the llvm.intr.stacksave is not emitted anymore (at that point and in general). At the point of the pipeline where the FORALL/WHERE logic is optimized/implemented, the call is now wrapped inside an hlfir.eval_in_mem, so it has not yet been decided if and how to allocate the storage, so there is no point emitting those ops in lowering anymore. In general because hlfir.eval_in_mem now uses heap allocation for dynamically sized results like all other temps created in bufferization (it is more consistent and easier). The analysis stops at the first unknow side effects, so the unknown side effect of the function call is not new, but it is now the first one encountered (which is an improvement if anything). https://github.com/llvm/llvm-project/pull/118070 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [flang] [flang][OpenMP] Use new modifiers in IF/LASTPRIVATE (PR #118128)
https://github.com/kparzysz created https://github.com/llvm/llvm-project/pull/118128 The usual changes, added more references to OpenMP specs. >From cfcf8d1e7ffdcec92dc0dfffccb3c620a2df804f Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Wed, 27 Nov 2024 08:34:33 -0600 Subject: [PATCH] [flang][OpenMP] Use new modifiers in IF/LASTPRIVATE The usual changes, added more references to OpenMP specs. --- flang/examples/FeatureList/FeatureList.cpp| 3 +- .../FlangOmpReport/FlangOmpReportVisitor.cpp | 5 +- .../FlangOmpReport/FlangOmpReportVisitor.h| 2 +- flang/include/flang/Parser/dump-parse-tree.h | 7 +- flang/include/flang/Parser/parse-tree.h | 50 ++-- .../flang/Semantics/openmp-modifiers.h| 2 + flang/lib/Lower/OpenMP/Clauses.cpp| 36 ++ flang/lib/Parser/CMakeLists.txt | 1 + flang/lib/Parser/openmp-parsers.cpp | 73 --- flang/lib/Parser/unparse.cpp | 15 ++- flang/lib/Semantics/check-omp-structure.cpp | 121 +++--- flang/lib/Semantics/openmp-modifiers.cpp | 34 + .../test/Parser/OpenMP/if-clause-unparse.f90 | 20 +-- flang/test/Parser/OpenMP/if-clause.f90| 22 ++-- .../test/Parser/OpenMP/lastprivate-clause.f90 | 4 +- .../Semantics/OpenMP/clause-validity01.f90| 4 +- flang/test/Semantics/OpenMP/if-clause.f90 | 64 - 17 files changed, 297 insertions(+), 166 deletions(-) diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp index c5cb8c8fdf40bb..41a6255207976d 100644 --- a/flang/examples/FeatureList/FeatureList.cpp +++ b/flang/examples/FeatureList/FeatureList.cpp @@ -492,7 +492,8 @@ struct NodeVisitor { READ_FEATURE(OmpPrescriptiveness) READ_FEATURE(OmpPrescriptiveness::Value) READ_FEATURE(OmpIfClause) - READ_FEATURE(OmpIfClause::DirectiveNameModifier) + READ_FEATURE(OmpIfClause::Modifier) + READ_FEATURE(OmpDirectiveNameModifier) READ_FEATURE(OmpLinearClause) READ_FEATURE(OmpLinearClause::WithModifier) READ_FEATURE(OmpLinearClause::WithoutModifier) diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp index afabd564ad5bdc..2dc480f0c901b1 100644 --- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp +++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp @@ -8,6 +8,7 @@ #include "FlangOmpReportVisitor.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Frontend/OpenMP/OMP.h" namespace Fortran { namespace parser { @@ -238,9 +239,9 @@ void OpenMPCounterVisitor::Post(const OmpScheduleClause::Kind &c) { clauseDetails += "type=" + std::string{OmpScheduleClause::EnumToString(c)} + ";"; } -void OpenMPCounterVisitor::Post(const OmpIfClause::DirectiveNameModifier &c) { +void OpenMPCounterVisitor::Post(const OmpDirectiveNameModifier &c) { clauseDetails += - "name_modifier=" + std::string{OmpIfClause::EnumToString(c)} + ";"; + "name_modifier=" + llvm::omp::getOpenMPDirectiveName(c.v).str() + ";"; } void OpenMPCounterVisitor::Post(const OmpCancelType::Type &c) { clauseDetails += "type=" + std::string{OmpCancelType::EnumToString(c)} + ";"; diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h index ed202e8ed2a4c7..59bdac8594cb7c 100644 --- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h +++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h @@ -77,7 +77,7 @@ struct OpenMPCounterVisitor { void Post(const OmpTaskDependenceType::Value &c); void Post(const OmpMapType::Value &c); void Post(const OmpScheduleClause::Kind &c); - void Post(const OmpIfClause::DirectiveNameModifier &c); + void Post(const OmpDirectiveNameModifier &c); void Post(const OmpCancelType::Type &c); void Post(const OmpClause &c); void PostClauseCommon(const ClauseInfo &ci); diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index 1ec38de29b85d6..b0b8d8d7ccc556 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -548,10 +548,13 @@ class ParseTreeDumper { NODE(OmpFromClause, Modifier) NODE(parser, OmpExpectation) NODE_ENUM(OmpExpectation, Value) + NODE(parser, OmpDirectiveNameModifier) NODE(parser, OmpIfClause) - NODE_ENUM(OmpIfClause, DirectiveNameModifier) - NODE_ENUM(OmpLastprivateClause, LastprivateModifier) + NODE(OmpIfClause, Modifier) NODE(parser, OmpLastprivateClause) + NODE(OmpLastprivateClause, Modifier) + NODE(parser, OmpLastprivateModifier) + NODE_ENUM(OmpLastprivateModifier, Value) NODE(parser, OmpLinearClause) NODE(OmpLinearClause, WithModifier) NODE(OmpLinearClause, WithoutModifier) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index c00560b1f1726a..06c32831d2c60c 100644 --- a/flang
[llvm-branch-commits] [flang] [flang][OpenMP] Use new modifiers in IF/LASTPRIVATE (PR #118128)
llvmbot wrote: @llvm/pr-subscribers-flang-semantics Author: Krzysztof Parzyszek (kparzysz) Changes The usual changes, added more references to OpenMP specs. --- Patch is 42.91 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/118128.diff 17 Files Affected: - (modified) flang/examples/FeatureList/FeatureList.cpp (+2-1) - (modified) flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp (+3-2) - (modified) flang/examples/FlangOmpReport/FlangOmpReportVisitor.h (+1-1) - (modified) flang/include/flang/Parser/dump-parse-tree.h (+5-2) - (modified) flang/include/flang/Parser/parse-tree.h (+41-9) - (modified) flang/include/flang/Semantics/openmp-modifiers.h (+2) - (modified) flang/lib/Lower/OpenMP/Clauses.cpp (+11-25) - (modified) flang/lib/Parser/CMakeLists.txt (+1) - (modified) flang/lib/Parser/openmp-parsers.cpp (+55-18) - (modified) flang/lib/Parser/unparse.cpp (+8-7) - (modified) flang/lib/Semantics/check-omp-structure.cpp (+77-44) - (modified) flang/lib/Semantics/openmp-modifiers.cpp (+34) - (modified) flang/test/Parser/OpenMP/if-clause-unparse.f90 (+10-10) - (modified) flang/test/Parser/OpenMP/if-clause.f90 (+11-11) - (modified) flang/test/Parser/OpenMP/lastprivate-clause.f90 (+2-2) - (modified) flang/test/Semantics/OpenMP/clause-validity01.f90 (+2-2) - (modified) flang/test/Semantics/OpenMP/if-clause.f90 (+32-32) ``diff diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp index c5cb8c8fdf40bb..41a6255207976d 100644 --- a/flang/examples/FeatureList/FeatureList.cpp +++ b/flang/examples/FeatureList/FeatureList.cpp @@ -492,7 +492,8 @@ struct NodeVisitor { READ_FEATURE(OmpPrescriptiveness) READ_FEATURE(OmpPrescriptiveness::Value) READ_FEATURE(OmpIfClause) - READ_FEATURE(OmpIfClause::DirectiveNameModifier) + READ_FEATURE(OmpIfClause::Modifier) + READ_FEATURE(OmpDirectiveNameModifier) READ_FEATURE(OmpLinearClause) READ_FEATURE(OmpLinearClause::WithModifier) READ_FEATURE(OmpLinearClause::WithoutModifier) diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp index afabd564ad5bdc..2dc480f0c901b1 100644 --- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp +++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp @@ -8,6 +8,7 @@ #include "FlangOmpReportVisitor.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Frontend/OpenMP/OMP.h" namespace Fortran { namespace parser { @@ -238,9 +239,9 @@ void OpenMPCounterVisitor::Post(const OmpScheduleClause::Kind &c) { clauseDetails += "type=" + std::string{OmpScheduleClause::EnumToString(c)} + ";"; } -void OpenMPCounterVisitor::Post(const OmpIfClause::DirectiveNameModifier &c) { +void OpenMPCounterVisitor::Post(const OmpDirectiveNameModifier &c) { clauseDetails += - "name_modifier=" + std::string{OmpIfClause::EnumToString(c)} + ";"; + "name_modifier=" + llvm::omp::getOpenMPDirectiveName(c.v).str() + ";"; } void OpenMPCounterVisitor::Post(const OmpCancelType::Type &c) { clauseDetails += "type=" + std::string{OmpCancelType::EnumToString(c)} + ";"; diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h index ed202e8ed2a4c7..59bdac8594cb7c 100644 --- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h +++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h @@ -77,7 +77,7 @@ struct OpenMPCounterVisitor { void Post(const OmpTaskDependenceType::Value &c); void Post(const OmpMapType::Value &c); void Post(const OmpScheduleClause::Kind &c); - void Post(const OmpIfClause::DirectiveNameModifier &c); + void Post(const OmpDirectiveNameModifier &c); void Post(const OmpCancelType::Type &c); void Post(const OmpClause &c); void PostClauseCommon(const ClauseInfo &ci); diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index 1ec38de29b85d6..b0b8d8d7ccc556 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -548,10 +548,13 @@ class ParseTreeDumper { NODE(OmpFromClause, Modifier) NODE(parser, OmpExpectation) NODE_ENUM(OmpExpectation, Value) + NODE(parser, OmpDirectiveNameModifier) NODE(parser, OmpIfClause) - NODE_ENUM(OmpIfClause, DirectiveNameModifier) - NODE_ENUM(OmpLastprivateClause, LastprivateModifier) + NODE(OmpIfClause, Modifier) NODE(parser, OmpLastprivateClause) + NODE(OmpLastprivateClause, Modifier) + NODE(parser, OmpLastprivateModifier) + NODE_ENUM(OmpLastprivateModifier, Value) NODE(parser, OmpLinearClause) NODE(OmpLinearClause, WithModifier) NODE(OmpLinearClause, WithoutModifier) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index c00560b1f1726a..06c32831d2c60c 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang
[llvm-branch-commits] [flang] [flang][OpenMP] Use new modifiers in IF/LASTPRIVATE (PR #118128)
https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/118128 >From cfcf8d1e7ffdcec92dc0dfffccb3c620a2df804f Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Wed, 27 Nov 2024 08:34:33 -0600 Subject: [PATCH 1/2] [flang][OpenMP] Use new modifiers in IF/LASTPRIVATE The usual changes, added more references to OpenMP specs. --- flang/examples/FeatureList/FeatureList.cpp| 3 +- .../FlangOmpReport/FlangOmpReportVisitor.cpp | 5 +- .../FlangOmpReport/FlangOmpReportVisitor.h| 2 +- flang/include/flang/Parser/dump-parse-tree.h | 7 +- flang/include/flang/Parser/parse-tree.h | 50 ++-- .../flang/Semantics/openmp-modifiers.h| 2 + flang/lib/Lower/OpenMP/Clauses.cpp| 36 ++ flang/lib/Parser/CMakeLists.txt | 1 + flang/lib/Parser/openmp-parsers.cpp | 73 --- flang/lib/Parser/unparse.cpp | 15 ++- flang/lib/Semantics/check-omp-structure.cpp | 121 +++--- flang/lib/Semantics/openmp-modifiers.cpp | 34 + .../test/Parser/OpenMP/if-clause-unparse.f90 | 20 +-- flang/test/Parser/OpenMP/if-clause.f90| 22 ++-- .../test/Parser/OpenMP/lastprivate-clause.f90 | 4 +- .../Semantics/OpenMP/clause-validity01.f90| 4 +- flang/test/Semantics/OpenMP/if-clause.f90 | 64 - 17 files changed, 297 insertions(+), 166 deletions(-) diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp index c5cb8c8fdf40bb..41a6255207976d 100644 --- a/flang/examples/FeatureList/FeatureList.cpp +++ b/flang/examples/FeatureList/FeatureList.cpp @@ -492,7 +492,8 @@ struct NodeVisitor { READ_FEATURE(OmpPrescriptiveness) READ_FEATURE(OmpPrescriptiveness::Value) READ_FEATURE(OmpIfClause) - READ_FEATURE(OmpIfClause::DirectiveNameModifier) + READ_FEATURE(OmpIfClause::Modifier) + READ_FEATURE(OmpDirectiveNameModifier) READ_FEATURE(OmpLinearClause) READ_FEATURE(OmpLinearClause::WithModifier) READ_FEATURE(OmpLinearClause::WithoutModifier) diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp index afabd564ad5bdc..2dc480f0c901b1 100644 --- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp +++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp @@ -8,6 +8,7 @@ #include "FlangOmpReportVisitor.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Frontend/OpenMP/OMP.h" namespace Fortran { namespace parser { @@ -238,9 +239,9 @@ void OpenMPCounterVisitor::Post(const OmpScheduleClause::Kind &c) { clauseDetails += "type=" + std::string{OmpScheduleClause::EnumToString(c)} + ";"; } -void OpenMPCounterVisitor::Post(const OmpIfClause::DirectiveNameModifier &c) { +void OpenMPCounterVisitor::Post(const OmpDirectiveNameModifier &c) { clauseDetails += - "name_modifier=" + std::string{OmpIfClause::EnumToString(c)} + ";"; + "name_modifier=" + llvm::omp::getOpenMPDirectiveName(c.v).str() + ";"; } void OpenMPCounterVisitor::Post(const OmpCancelType::Type &c) { clauseDetails += "type=" + std::string{OmpCancelType::EnumToString(c)} + ";"; diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h index ed202e8ed2a4c7..59bdac8594cb7c 100644 --- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h +++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h @@ -77,7 +77,7 @@ struct OpenMPCounterVisitor { void Post(const OmpTaskDependenceType::Value &c); void Post(const OmpMapType::Value &c); void Post(const OmpScheduleClause::Kind &c); - void Post(const OmpIfClause::DirectiveNameModifier &c); + void Post(const OmpDirectiveNameModifier &c); void Post(const OmpCancelType::Type &c); void Post(const OmpClause &c); void PostClauseCommon(const ClauseInfo &ci); diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index 1ec38de29b85d6..b0b8d8d7ccc556 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -548,10 +548,13 @@ class ParseTreeDumper { NODE(OmpFromClause, Modifier) NODE(parser, OmpExpectation) NODE_ENUM(OmpExpectation, Value) + NODE(parser, OmpDirectiveNameModifier) NODE(parser, OmpIfClause) - NODE_ENUM(OmpIfClause, DirectiveNameModifier) - NODE_ENUM(OmpLastprivateClause, LastprivateModifier) + NODE(OmpIfClause, Modifier) NODE(parser, OmpLastprivateClause) + NODE(OmpLastprivateClause, Modifier) + NODE(parser, OmpLastprivateModifier) + NODE_ENUM(OmpLastprivateModifier, Value) NODE(parser, OmpLinearClause) NODE(OmpLinearClause, WithModifier) NODE(OmpLinearClause, WithoutModifier) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index c00560b1f1726a..06c32831d2c60c 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/