The ragged-array machinery served the legacy FORALL mask temporaries,
whose lowering was removed with the legacy expression lowering (#210639,
#210873) and the array-value-copy pass (#212643). The builders
(fir::runtime::genRaggedArrayAllocate/Deallocate) and the
getRaggedArrayHeaderType helper have no compiler callers left; only
their own unit test exercised them. Delete the builders, the helper, and
the unit test.
The flang-rt runtime entry points
(RaggedArrayAllocate/RaggedArrayDeallocate in
flang-rt/lib/runtime/ragged.cpp and their declarations in
flang/include/flang/Runtime/ragged.h) are ABI and remain.
Assisted-by: AI
Nothing in flang has produced fir.array_load, fir.array_fetch,
fir.array_update, fir.array_modify, fir.array_access, fir.array_amend,
or fir.array_merge_store since the legacy (non-HLFIR) expression
lowering was deleted (#210385, #210621, #210639, #210873), and the
array-value-copy pass that legalized them is gone (#211816, #212643).
Delete the operations and the surface that existed only for them:
- FIROps.td: the "Array value operations" section including the
copy-in/copy-out design comment; FIROps.cpp: the ops verifiers, effects
and getExtents. fir.array_coor is unrelated and stays, as does the
validTypeParams helper shared with fir.pack_array.
- Tests: the ops roundtrip/verifier blocks in fir-ops.fir and
invalid.fir; scaffolding rewrites in inline-elemental.fir (store via
hlfir.designate; hlfir.apply-in-do_loop coverage preserved),
loop-versioning.fir @test4 (the versioned loops are untouched), and
simplifyintrinsics.fir (inert copy-back loops dropped; no CHECK lines
affected).
- Docs: FIRArrayOperations.md (+ the index.md toctree line); past-tense
updates in HighLevelFIR.md; a stale comment in MutableBox.h; a
release-note entry recording the removal for downstream projects.
FIRLangRef is generated from FIROps.td and follows automatically.
Assisted-by: AI
`fir.select`, `fir.select_case`, `fir.select_rank`, and
`fir.select_type` are lowered to cf.* earlier in the pipeline
(`--fir-select-ops-conversion` and `--fir-polymorphic-op`). Their
FIR-to-LLVM conversion patterns are dead in a correct pipeline. Replace
them with a single templated stub
`SelectShouldHaveBeenConvertedStub<OP>` that emits `"'fir.<op>' op
should have already been converted"` and fails legalization, so running
`--fir-to-llvm-ir` standalone on stale IR reports a clear diagnostic
instead of "unable to legalize".
`Fir/convert-to-llvm.fir`'s six select* test blocks are removed (the
lowering no longer runs; CF-level coverage lives in
`Fir/SelectOpsConversion/`). `Fir/convert-to-llvm-invalid.fir` gains a
stub-error test per op. `Fir/Todo/select_case_with_character.fir` is
retargeted to check the equivalent diagnostic now emitted by
`--fir-select-ops-conversion`.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
PR Stack:
* https://github.com/llvm/llvm-project/pull/212977
* ▶️https://github.com/llvm/llvm-project/pull/212978
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When a CUDA kernel is launched inside an OpenACC data region, it does
not properly get the device pointers and instead uses host data. This PR
adds a pass to get the device pointers set up by the OpenACC data
construct and pass them explicitly to the CUDA kernel.
Note: A possibly non-contiguous array argument is currently not supported. This pass will skip these cases.
---------
Co-authored-by: Yebin Chon <ychon@nvidia.com>
PR #201063 breaks the `flang` build on Solaris:
```
flang/lib/Evaluate/intrinsics-library.cpp:225:26: error: address of overloaded function 'acos' does not match required type '__float128 (__float128)'
flang/lib/Evaluate/intrinsics-library.cpp:225:26: error: address of overloaded function 'acos' does not match required type '_Complex __float128 (_Complex __float128)'
```
There are two problems here:
- The `__float128` support in `intrinsics-library.cpp` is guarded by the
POSIX.1 >= 2001/XPG >= 6 check, but only depends on `HAVE_QUADMATHLIB`.
- That check is done incorrectly: it tests for `_POSIX_C_SOURCE >=
200112L` or `_XOPEN_SOURCE >= 600`, which are no longer defined on
Solaris after the PR above. This check is due a misunderstanding of
those feature test macros: as detailed in [The Open Group Base
Specifications Issue 8, 2.2.1 POSIX.1
Symbols](https://pubs.opengroup.org/onlinepubs/9799919799/functions/V2_chap02.html),
those macros are expected to be **defined** by the user to ensure that
the features introduced by a particular version of POSIX.1 or XPG are
enabled, and only be checked by system headers. To test if they actually
are supported, the values of `_POSIX_VERSION` or `_XOPEN_VERSION` need
to be checked instead, as explained in [2.1.3.1 POSIX System
Interfaces](https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap02.html).
The feature test macros being defined by the system headers is a
non-portable glibc/AIX extension, it seems.
If the XPG6 features required for `flang` are present by default in a
compilation environment, `_POSIX_VERSION` or `_XOPEN_VERSION` will be
defined to the required values even without defining `_POSIX_C_SOURCE`
or `_XOPEN_SOURCE`.
Tested on `amd64-pc-solaris2.11`, `sparcv9-sun-solaris2.11`, and
`x86_64-pc-linux-gnu`.
Introduces `--fir-select-ops-conversion`, which lowers `fir.select`,
`fir.select_case`, and `fir.select_rank` to the control-flow dialect
(`cf.switch` / `cf.cond_br` / `cf.br`) while preserving the CFG shape.
`fir.select_case` becomes an if-then-else ladder of `arith.cmpi` +
`cf.cond_br`; Fortran `UNSIGNED` selectors use `ule`. Signed / unsigned
FIR integer values are normalized to signless via `fir.convert` first.
`fir.select_type` is not handled here — it is already lowered by
`--fir-polymorphic-op` (`PolymorphicOpConversion`).
The pass runs in the default FIR optimizer pipeline right after
`PolymorphicOpConversion`. Pipeline-check tests are updated to expect
`SelectOpsConversion` in the sequence; `Fir/select.fir` and
`Lower/volatile3.f90` are relaxed to accept the newly-canonicalized form
of the lowered output.
The main purpose of moving these conversion pattern earlier in the MLIR
pipeline and target `cf` instead of directly `llvm` is to be able to
later on use control-flow to structured-control-flow lifting:
https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/Conversion/Passes.td#L402.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
PR Stack:
* ▶️https://github.com/llvm/llvm-project/pull/212977
* https://github.com/llvm/llvm-project/pull/212978
---------
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Currently, only gpu.launch_func supports stream-based asynchronicity. This
patch adds the same mode to gpu.launch, and makes kernel outlining preserve
that when converting to gpu.launch_func.
This patch also documents the stream-based model in the operations description,
which was previously missing.
This patch changes the builders for the two launch operations:
To retain the current behavior for gpu.launch one needs to add a `nullptr` for
the new `Value asyncObject` argument after the `ValueRange asyncDependencies`,
and make sure to pass a valid type for the `Type asyncTokenType` parameter if
dependency-based async behavior is intended.
For gpu.launch_func, both stream-based and dependency-based async models now go
through the same builders, which take all three `Type asyncTokenType,
ValueRange asyncDependencies, Value asyncObject` arguments. To retain
stream-based behavior, pass `nullptr, {}` to the first two parameters, while to
retain dependency-based behavior, pass `nullptr` to the third parameter.
Assisted-by: Claude Code
Since the removal of the legacy expression lowering (#210385, #210621,
#210639, #210873) nothing in flang produces the array-value operations
this pass legalizes, and #211816 already removed it from the default
pipeline. Delete the pass and the pieces that existed solely for it:
- ArrayValueCopy.cpp, its Passes.td definition,
createArrayValueCopyPass, and the (duplicated) CMake source entries.
- Optimizer/Builder/Factory.h in its entirety: the pass was its only
includer, and its contents (attrFortranArrayOffsets,
getExtents/getOrigins on shape values, originateIndices) have no other
users.
- The getTypeParams(fir::ArrayLoadOp) overload (sole caller was the
pass) and the ArrayLoadOp forward declaration in BoxValue.h.
- The pass LIT tests (array-value-copy*.fir, array-copies-pointers.fir,
array-modify.fir); stack-arrays-hlfir.f90 drops the --array-value-copy
stage from its RUN pipeline.
- The pass-describing paragraphs in fstack-arrays.md and the stale
ArrayValueCopy TODO entry in ParameterizedDerivedTypes.md.
The array-value operations themselves (fir.array_load and friends; not
fir.array_coor) remain in the dialect and will be deleted in a
follow-up.
Assisted-by: AI
Under the new experimental pass that can move automatic arrays to the
heap, "mock" result storage may be promoted to allocmem before
AbstractResult removes them and replace them by a hidden result.
Add a fir.must_be_stack attribute to these mock alloca so they are never
promoted. So that passes dealing with array function results ABI can
expect to find an fir.alloca and remove it.
This was a minor change upstreamed in the original PR:
https://github.com/llvm/llvm-project/pull/208133
However, it is a modification that needs a little more thought from a
specification perspective before it is rolled out, there's a number of
code bases that depend on the presence modifier being applied only to
the underlying data. However, this leads to inconsistencies when a user
makes use of any reference semantic modifiers when mapping as they
SHOULD be allowed to specify present applying to the descriptor. So, we
need to work out what the correct defualt behaviour is, and regardless
of the default support a user intentionally specifying presence
application on a descriptor via reference semantics.
For now, we will revert to previous state.
Always use the cuf operation under -gpu=unified as registration might be
differed to the backend. Add a UnitAttr to distinguish device resident
variable that will not use cudaRegisterHostVar but cudaRegisterVar.
Fortran 2023 7.6.1 errata f23/013 changes R762 so an interoperable
enumerator may be a named-constant initialized by a
boz-literal-constant, and specifies the value as
INT(boz-literal-constant, C_INT).
Handle that named-constant restriction directly in enum resolution while
preserving the usual scalar integer expression checks for non-enumerator
contexts. This mirrors the general named-constant initializer path,
which already converts BOZ values through the declared type before
folding.
The problem is that the automatic object was used as the
threadprivate argument.
Solution:
From the documentation (J3/24-007):
> C814 An automatic data object shall not have the SAVE attribute.
> C862 The SAVE attribute shall not be specified for a dummy argument,
> a function result, an automatic data object, or an object
> that is in a common block.
The bare SAVE statement makes any valid local variables tagged
with the SAVE attribute. As the restriction mentioned above, the
automatic object cannot have a SAVE attribute and shall not be
used as the THREADPRIVATE argument. This patch adds semantic
checks for dummy arguments, function results, and automatic data
objects in both THREADPRIVATE and DECLARE TARGET directives.
[flang][OpenMP] Fix DECLARE TARGET to reject distinct result name
When a function uses a distinct result name (e.g. result(res)),
DECLARE TARGET(res) was not diagnosed because ResolveOmpDesignator
rebound it to the procedure, skipping the IsFunctionResult check.
The check added for F2023 19.4 p2 (statement function dummy argument
name may be the same as an accessible name only if that name is a scalar
variable) looked the name up through the whole host scope chain and,
failing that, in the global scope. Both lookups overshoot what is
"accessible" in the scoping unit:
* Per F2023 19.5.1.4 p2 item (11), the appearance of a name as a
dummy-arg-name in a stmt-function-stmt makes any host entity of that
name inaccessible by host association throughout the scoping unit, so a
host entity can never conflict with the dummy.
* A global entity to which the scoping unit makes no reference at all is
not accessible in it; otherwise conformance would depend on whether
unrelated program units happen to be compiled in the same file.
This caused bogus errors on conforming code such as
```
program p
logical, external :: x
contains
subroutine s
real :: f
f(x) = x * x ! 'x' is an implicitly typed real dummy here
end
end
```
where the dummy 'x' must be implicitly typed real (both NAG and gfortran
accept this and type it that way; flang already typed it correctly, but
rejected the program).
Restrict the lookup to names made visible by the scoping unit itself
(declared, referenced, or USE-associated there), matching the lookup
HandleStmtFunction already uses to type the dummies.
Assisted-by: AI
Example:
```fortran
z(:, 3:2:-1) = z(:, 1:2)
```
In this code, reverse-section indexing lowers `idx*step` / `diff+adj`
with `nuw`. A negative step can make the product negative, so `nuw` is
invalid and LLVM `-O2` can drop the stores.
Fix: keep `nsw|nuw` only for known positive steps; otherwise keep `nsw`
and drop `nuw` (negative, zero, or unknown).
The UPDATE clause has the same spelling on both of these directives, but
functionally it's two different clauses. Split them into "update", and
"update_depend_objects" to be able to tie their properties to their enum
ids.
This should make it easier to implement auto-generating of clause
properties in the future by avoiding spelling conflicts.
---------
Co-authored-by: Alexey Bataev <a.bataev@outlook.com>
Add a hidden -enable-allocation-placement flag that, when set, replaces
the stack-arrays and memory-allocation-opt passes in the default FIR
optimizer pipeline with the unified allocation-placement pass. The flag
is off by default, so the legacy passes remain the default path and
behavior is unchanged.
When enabled, the pass runs with its default byte-size thresholds; the
-fstack-arrays strategy is forwarded through the new stackArrays option.
Assisted-by: AI
Introduce a new function-level pass, allocation-placement, that unifies
the stack/heap placement decisions currently split between the
stack-arrays and memory-allocation-opt passes. For each array allocation
it consults a policy to decide whether it should live on the stack
(fir.alloca) or the heap (fir.allocmem) and rewrites it accordingly,
reusing fir::replaceAllocas for stack-to-heap and the StackArrays
analysis/rewrite for heap-to-stack (so heap-to-stack only happens where
it is provably safe).
The default policy (AllocationPlacementPolicy.h) is threshold-driven:
- small constant-size arrays go on the stack within a per-function stack
budget, otherwise on the heap;
- big constant-size arrays: user variables stay on the stack,
temporaries go on the heap;
- runtime-sized arrays go on the heap;
- an aggressive mode places all arrays on the stack (best effort). User
variables are distinguished from compiler temporaries via the presence
of a uniqued name. A hook lets downstream users override the thresholds
per allocation (e.g. for device routines or parallel regions).
The pass is not wired into any pipeline yet; it is reachable through
fir-opt and covered by isolated tests.
Assisted-by: AI
This change builds on top of the work done in PR #203959
- Diagnose interop destroy without an interop variable
- Lower array-element / derived-component interop-vars via their
designator
- Require interop-var to be a scalar integer of omp_interop_kind
- Remove "hsa" prefer_type (no omp_ifr_hsa in the runtime)
- Fix a latent bug in Parser/OpenMP/interop-construct.f90
Since the removal of the legacy expression lowering (#210385, #210621,
#210639, #210873), nothing in flang produces the array-value operations
(fir.array_load and friends) that the array-value-copy pass legalizes,
so the pass runs as a guaranteed no-op on every function. Remove it from
the default pipeline (addAVC and the disable-avc mlir option); the pass
itself and its fir-opt tests remain and still run via fir-opt
--array-value-copy.
The array-value operations themselves and the pass are planned for
removal in follow-up patches.
flang/test/Fir/arrexp.fir is deleted rather than updated: it feeds
legacy array-value ops through tco's full pipeline, which no longer
legalizes them (the ops have no codegen patterns), and the file
exercises no live feature beyond that legalization.
Assisted-by: AI
Move InsertionPoint, StackArraysAnalysisWrapper, and AllocMemConversion
out of the anonymous namespace in StackArrays.cpp into a new
StackArrays.h header (in namespace fir), so the "which fir.allocmem can
be safely moved to the stack, and where" analysis and the heap-to-stack
rewrite pattern can be reused by other passes.
The dataflow internals (AllocationState, LatticePoint,
AllocationAnalysis), the command-line options, and all method
definitions remain in the .cpp. No functional change intended.
RFC:
https://discourse.llvm.org/t/rfc-flang-improving-temporary-and-local-array-allocations-unify-stackarray-memoryallocation/91353
Assisted-by: AI
Add an OpenACC MLIR pass that emits not-yet-implemented messages for
unsupported directives immediately after HLFIR generation. This allows
OpenACC dialect operations to be emitted with -emit-hlfir while making
full compilation fail early with clear diagnostics, instead of later
when unhandled OpenACC operations reach LLVM dialect conversion.
Elemental operands are conformable, so their extents are identical and
the result shape may be taken from either operand. This patch prefers an
operand whose shape is a compile-time constant, producing a statically
shaped result. The left operand is checked first to avoid churn in lit
test expectations.
Statement functions are inlined during lowering, so they should not be
treated as host procedure calls. Recursively validate their expressions
to reject any host procedure calls within the body.
Breaking cyclic global initializers by removing an initializer produced
an
external declaration, which could leave references unresolved during
device
linking.
Replace selected cyclic initializers with zero initializers instead.
This
breaks the NVPTX dependency cycle while preserving device symbol
definitions.
## Summary
This PR fixes https://github.com/llvm/llvm-project/issues/200922 - a
compile-time regression affecting firstprivate clauses on simple arrays
in OpenMP target regions.
When `InlineHLFIRAssign` checks whether to inline `hlfir.assign`
operations in `omp.private` copy regions, the alias analysis
conservatively returns `MayAlias` for the copy region block arguments
(`%arg0` mold vs `%arg1` private). This prevents inlining and forces a
fallback to `fir.call @_FortranAAssign`, which:
- Pulls in 89 runtime functions via LTO
- Creates 550K+ abstract attributes in OpenMPOpt
- Causes severe compile-time degradation (60%+ increase in some cases)
**Example:**
```fortran
!$omp target firstprivate(array)
! ... use array ...
!$omp end target
```
The firstprivate copy generates an `omp.private` copy region where the
assignment from the original array to the private copy cannot be inlined
due to conservative aliasing assumptions.
## Root Cause and Solution
The FIR alias analysis did not recognize that `omp.private` copy region
block arguments are guaranteed by the OpenMP specification to reference
different memory locations:
- `%arg0` (mold) - the original variable
- `%arg1` (private) - freshly allocated private storage created in the
init region
Since the private copy is allocated fresh, these arguments **cannot
alias**.
So, this PR adds special-case handling in
`flang/lib/Optimizer/Analysis/AliasAnalysis.cpp` to recognize
`omp.private` copy region block arguments and correctly return
`NoAlias`. This allows `InlineHLFIRAssign` to inline the assignment into
an element-wise loop, avoiding the expensive runtime call entirely.
Assisted by: Claude Sonnet
---------
Co-authored-by: Claude Sonnet 4 <noreply@anthropic.com>
In `HandleAttributeStmt`, when an `ASYNCHRONOUS` or `VOLATILE` statement
names a variable not already in the current scope, flang creates a
host-association symbol — but only for `Subprogram` and `BlockConstruct`
scopes. Submodule scopes have kind `Module`, so the check excluded them.
This caused a fresh `EntityDetails` symbol (zero-initialized) to be
created instead of a `HostAssocDetails` symbol pointing at the ancestor
module variable, producing value 0 instead of the initialized value.
Fix: extend the condition to also fire when `currScope().IsSubmodule()`.
`Scope::FindSymbol` already traverses into the parent module for
submodules, so the host variable is found correctly.
Note: the `volatile`/`asynchronous` `fortran_attrs` are not propagated
to `hlfir.declare` for host-associated variables in general
(subprograms,
BLOCK constructs, and submodules); that is a separate lowering issue
tracked in #208588.
Fixes#208362
Assisted-By: AI
`AccAttributeVisitor::Post(Name)` "adjusts" every name referenced inside
an OpenACC region to the symbol found in the current scope. A construct
entity -- a `DO CONCURRENT`/`FORALL` index-name, or a variable declared
in a `BLOCK` construct -- lives in its own scope nested within the
region, but the visitor's current scope does not descend into that
construct scope. `FindSymbol` therefore resolves the name to a
like-named variable in an enclosing scope and rebinds the reference to
it.
When such an entity shadows an enclosing DO variable and the loop is
associated with an OpenACC construct, this makes the entity alias that
active DO variable, so referencing or defining it wrongly triggers
"Cannot redefine DO variable" -- even though the code is legal and
compiles without error when OpenACC is disabled. This affected a `DO
CONCURRENT` index-name as well as a variable declared in a `BLOCK`
construct nested in the loop, e.g.:
```fortran
do i = 1, m
!$acc parallel loop gang vector collapse(2) independent
do concurrent (j = 1:n, ii = 1:m)
block
integer :: i ! shadows the enclosing `do i`
i = ii
a(i,j) = b(i,j)
end block
end do
end do
```
Skip the adjustment when the resolved symbol is owned by a scope
contained in the current scope, i.e. it was declared within the region;
name resolution already bound it correctly. The `DO CONCURRENT`
induction variables are then privatized as their own construct-local
entities rather than the shadowed enclosing variable, as reflected in
the updated `acc-loop.f90` lowering test.
Add a Semantics regression test covering the `DO CONCURRENT` and `BLOCK`
cases.
Flang does not enforce `DEFAULT(NONE)` for variables referenced in a
loop
associated with a standalone METADIRECTIVE. Consequently, it accepts
invalid
programs when a potentially selectable loop variant specifies
DEFAULT(NONE) but
omits a referenced variable from its data-sharing clauses. This change
checks the
associated loop for each potentially selectable `DEFAULT(NONE)` variant
and
diagnoses missing data-sharing attributes as it does for ordinary OpenMP
loop
constructs.
Standalone metadirectives and their associated loops are separate
parse-tree
nodes. For example:
```fortran
!$omp metadirective &
!$omp& when(implementation={vendor(llvm)}: &
!$omp& parallel do default(none) shared(n, a)) default(nothing)
do i = 1, n
a(i) = x
end do
```
Unlike an ordinary `PARALLEL DO`, the loop is not nested under the
directive:
```text
METADIRECTIVE
`-- WHEN
`-- PARALLEL DO DEFAULT(NONE) SHARED(n, a)
DO
`-- a(i) = x
```
Name resolution therefore leaves the variant context before visiting the
loop and
does not diagnose the missing data-sharing attribute for `x`.
After associating a metadirective with its loop, validate DEFAULT(NONE)
for each
potentially selectable loop variant. Preserve the existing rules for
predetermined and explicit data-sharing attributes, static locals,
nested
constructs, specification expressions, and statically inapplicable
variants.
Assisted with codex.
Assignments that read or write device/managed/unified data are
synchronous data transfers on stream 0 that wait for previously launched
kernels. Previously, whole-array managed = managed / host = managed
assignments, and assignments consuming a managed/unified/device function
result, were lowered as host copies (hlfir.assign), which can race an
asynchronous kernel that produced the data.
Emit cuf.data_transfer for these cases. Element-wise (scalar) accesses
and right-hand-side expressions involving managed data remain host
operations (the latter avoids materializing a temporary), and a
whole-allocatable left-hand side keeps reallocation semantics.
Example:
```fortran
subroutine sum_loop(a, n)
integer :: a(n), i
do i = 1, n
a(i) = i
end do
end
```
In this code, the DO induction variable `i` is stepped each iteration.
`FIRToSCF` lowered that increment to a plain `arith.addi` with no
overflow flag — unlike the CFG-conversion path (`ControlFlowConverter`),
which marks it `overflow<nsw>` — so LLVM must assume the IV may wrap and
cannot form an affine recurrence, blocking analysis/vectorization of
loops lowered via `fir-to-scf`.
Fix: add a `set-nsw` pass option (default `true`, disabled under
`-fwrapv`) and mark the typed-IV, reconstructed final-value, and
`iterate_while` increments `nsw`, matching `ControlFlowConverter`;
`FirToSCF` lit tests updated accordingly.
## [flang][OpenMP] Implement the `error` directive
### Summary
Implements the OpenMP `error` directive (OpenMP 5.1, 2.5.4) in Flang.
The directive prints a message and, with `severity(fatal)`, stops.
Handling depends on the `at` clause:
- **`at(compilation)`** (the default): handled in semantics. Emits a
compile-time warning or error and produces no IR.
- **`at(execution)`**: lowered to a new `omp.error` op, which becomes a
call to `__kmpc_error`.
Before this patch the directive was unimplemented and hit a `not yet
implemented: OmpErrorDirective` error during lowering.
Fixes#204240.
### Details
Changes go through the compiler pipeline.
**Flang semantics**
- `Enter(OmpErrorDirective)` emits the compile-time diagnostic for the
`at(compilation)` form, using the directive's severity and the `MESSAGE`
text when present.
- `Enter(OmpClause::Message)` checks that the `MESSAGE` expression is a
scalar, default-kind `CHARACTER`, which is required to pass it to the
runtime as a `const char*`.
**Flang lowering**
- `genErrorDirective` lowers the `at(execution)` form only.
- A constant message is stored in the `message` attribute. A
non-constant message is copied to a null-terminated buffer
(`genNullTerminatedString`) and passed as the `message_expr` operand,
because `__kmpc_error` expects a NUL-terminated string.
**New `omp.error` op (MLIR OpenMP dialect)**
- Adds a `ClauseSeverity` enum (`warning = 1`, `fatal = 2`, matching the
`__kmpc_error` argument) and `ClauseSeverityAttr`.
- `omp.error` takes a required `severity` attribute and an optional
message, given either as:
- `message` — a constant string attribute, or
- `message_expr` — a pointer to a null-terminated string.
- A verifier rejects providing both `message` and `message_expr`.
**MLIR → LLVM IR translation**
- Translates `omp.error` to `__kmpc_error(ident_t *, i32 severity, ptr
message)`.
**OMPIRBuilder**
- Adds `OpenMPIRBuilder::createError(...)`, which builds the call, maps
`fatal`→`2` and `warning`→`1`, and passes a null pointer when there is
no message.
### Tests
- **Parser** (`error-unparse.f90`): unparse and parse-tree output.
`at(compilation) severity(fatal)` cases that would stop compilation were
moved to `at(execution)`.
- **Semantics** (`Semantics/OpenMP/error.f90`): compilation
warning/error/default-severity cases, plus the new `MESSAGE` type, rank,
and kind errors.
- **Lowering** (`Lower/OpenMP/error.f90`): constant message, no message,
empty message, runtime `message_expr`, and `at(compilation)` cases that
must not produce `omp.error`. The old `Lower/OpenMP/Todo/error.f90` test
is removed.
- **MLIR** (`ops.mlir`, `invalid.mlir`): round-trip of each `omp.error`
form and the both-messages verifier error.
- **LLVM IR** (`openmp-llvm.mlir`): `__kmpc_error` calls for warning and
fatal, constant and runtime messages, and the null-message cases.
Assisted-by: Github Copilot
This will remove the hardcoded dependence of DirectiveStructureChecker
on
the common::EnumSet class. Both consumers of it will be able to use
their
own type for the clause set.
The only complication was the ClauseSetToString member function, whose
implementation depended on the specifics of common::EnumSet, namely the
IterateOverMembers member function. It was moved out of the class, and
turned into a function template to make it possible to provide different
specializations for common::EnumSet and llvm::EnumSet.
Replace uses of OmpDirectiveSet (defined in terms of common::EnumSet)
with the common llvm::omp::DirectiveSet (defined via llvm::EnumSet).
The llvm::omp::DirectiveSet class will also be used in openmp-parsers,
where OmpDirectiveSet was an instance of llvm::Bitset.
Reduction lowering (genReductions in flang/lib/Lower/OpenACC.cpp) only
remapped the reduced symbol to the acc.reduction result when the object
was a whole array (`isWholeSymbol` guard). For sections, the remap was
skipped, so hlfir.designate for element accesses inside the compute
region kept resolving through the original host declare's box instead of
the private reduction copy — the reduction ran on a private buffer that
never got read back.
Checked and confirmed dropping the boolean is safe for: non-1-starting
sections (recipe already compensates via a deliberate base-pointer
shift), SIZE/UBOUND/LBOUND inside privatized sections (intended
semantics), OPTIONAL dummies (pre-existing TODO, now fails loudly
instead of silently), combined constructs.
`CUFPredefinedVarToGPU` rewrites references to the predefined CUDA
builtins (`threadidx`/`blockidx`/`blockdim`/`griddim`) into GPU special-register
reads. For each predefined-var `fir.declare` it also erased the declare's
backing `fir.address_of`. That assumed every declare owns a
private `address_of`, which is only true before CSE. Once a single
`fir.address_of` of a builtin is shared by several `fir.declare`s — e.g.
after a `device` routine is inlined into a `global` kernel and CSE coalesces the
duplicated `address_of` ops — the pass queued that one op for deletion
once per declare and erased it while another declare still used it, thus aborting
compilation with `'fir.address_of' op operation destroyed but still has uses` error.
With this PR, the backing ops are collected into a de-duplicated set and
erased after all predefined declares are gone, and only when `use_empty()`.
This makes the deletion safe regardless of how many declares share an
`address_of`, and leaves it untouched if any other user remains.