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
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>
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>
Unified data was counted as managed data in the data transfer predicate,
so assignments between unified sides, or between unified and host data,
became synchronous copies.
Unified data is host memory that the device can also access, so it now
takes the place of host data there: the assignment is a copy only when
the other side is device or constant data, or a whole managed array, and
is done on the host otherwise.
This matches the reference compiler for whole arrays, sections,
elements, scalars, allocatables, components and expressions.
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.
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.
An assignment to a whole allocatable was lowered as a host assignment to
keep reallocation semantics, without checking the memory kind, so a
device allocatable assigned from a managed array wrote device memory
from the host and segfaulted.
Keep the transfer when either side is device or constant data. CUDA
Fortran Programming Guide 3.4.1 makes an assignment between managed and
device data a copy in both directions, with no exception for an
allocatable left-hand side.
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.
Assignments involving managed or unified data are lowered to
`cuf.data_transfer`, a synchronous copy. The predicate only excluded
scalar left-hand sides, so array sections were transferred too, turning
a loop that assigns one section per
iteration into a sequence of blocking copies.
Key the decision on the managed operand instead: a transfer when the
managed variable or array is whole, host code when it is a section or an
element. Managed data is host-addressable, so the host assignment is
safe. Managed function results and assignments involving device memory
are unaffected.
This is the behavior specified in the CUDA Fortran Programming Guide
3.4.1:
> An assignment statement where the right hand side is a managed array
section and
> the left hand side is any host or managed variable copies data using
generated
> host code.
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
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
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.
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
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.
First part of generalisations requested in #207377.
The split-sum eligibility check rejected any RHS containing explicit
parentheses or subtraction, even though the Add flattener already
preserves every non-Add subtree as one opaque term.
Remove those blanket guards and their unused predicates. Document the
opaque-term invariant and extend the test to cover parenthesized
additions and subtractions, whole-RHS parentheses, and subtraction
terms.
I did not observe any benchmark result changes as a result of this
patch.
Assisted-by: Codex
The legacy (non-HLFIR) lowering was removed in cc4922b276 (#196205),
but ConvertExpr.cpp and its ComponentPath/IterationSpace support files
were left behind. Their last callers have since been migrated or removed
(#210385: OpenMP iterator subscripts via genExprValue; #210621: initial
values via ConvertConstant; #210639: unreachable FORALL/WHERE machinery
deleted from Bridge.cpp), so nothing outside these files references them
anymore.
- Delete ConvertExpr.{cpp,h}, ComponentPath.{cpp,h},
IterationSpace.{cpp,h}. (createArrayLoads/createArrayMergeStores are
declared in IterationSpace.h but were defined in ConvertExpr.cpp - they
die together; no external callers.)
- CMakeLists.txt: drop the three sources and the ConvertExpr.h /
IterationSpace.h PRECOMPILE_HEADERS entries.
- Remove stale includes (verified symbol-free): IO.cpp,
OpenMP/OpenMP.cpp, DirectivesCommon.h (ConvertExpr.h); Allocatable.cpp,
Support/Utils.cpp (IterationSpace.h).
- Support/Utils.{h,cpp}: remove the ExplicitSpaceArrayBases alias and
its getHashValue/isEqual overloads; the SomeExpr* and Component*
variants stay (live via ExprToValueMap and HLFIR lowering).
This also deletes six small Optimizer/Builder helpers whose last callers
were in ConvertExpr.cpp — fir:🏭:genLenOfCharacter,
getNonDeferredLenParams, getExtentFromTriplet (FIRBuilder),
getExtentAtDimension (BoxValue), fir:🏭:getRealloc
(LowLevelIntrinsics), and the genCharacterCopy template (Factory.h).
Their removal orphans nothing further; Factory.h and LowLevelIntrinsics
retain their live content.
- Docs: drop the ConvertExpr.cpp section from fstack-arrays.md and the
stale ConvertExpr.cpp TODO inventories from ParameterizedDerivedTypes.md
and ProcedurePointer.md.
No functional change: everything removed is unreachable. Downstream
forks using the deleted entry points will break at compile time; this is
intended (precedent: cc4922b276).
Assisted-by: AI
Preserve the full bit width of integer attributes when extracting
constants from FIR values. Return llvm::APInt directly and update
fixed-width consumers to use checked signed extraction.
This avoids truncating or asserting on constants wider than 64 bits
while retaining existing fallback behavior at int64_t boundaries.
This should be NFC everywhere we didn't have a latent overflow bug. I
didn't go so far as updating the interfaces of every function built on
top of getIntIfConstant: this is mostly to make an APInt version
available because it looks useful for another PR. Fixing the builder API
to use APInt would be a larger change - let me know if anyone wants to
see that.
Assisted-by: Codex
Problem
-------
Under -mmlir --wrap-unstructured-constructs-in-execute-region, branch
lowering hit a null Evaluation::block for body statements inside an
OpenMP loop. genMultiwayBranch tripped
Bridge.cpp: Assertion `block && "missing multiway branch block"' failed
and genFIR(SelectCaseStmt) tripped
Bridge.cpp: Assertion `e->block && "missing CaseStmt block"' failed
The wrap machinery decides an unstructured DO/IF is wrappable and stops
propagating its isUnstructured flag to the enclosing OpenMPConstruct.
The OMP construct's isUnstructured stays false, so the top-level
createEmptyBlocks treats it as a structured directive with nested
evaluations — it allocates only the OMP construct's first-nested block
and does not recurse into the DO body. Then OMP loop lowering takes
over the body via createEmptyRegionBlocks, which was written to
*re-parent* pre-existing blocks into its region and silently skipped
evals whose .block was still null. Body targets (e.g. label 17's
ContinueStmt, or a SelectCase's CaseStmts) therefore had no block when
the consumer read evalOfLabel(...).block, tripping the asserts.
Solution
--------
Restore the invariant that consumers of eval.block can trust it at
lowering time. In createEmptyRegionBlocks (DirectivesCommon.h), when an
eval has isNewBlock but no .block, create one in the current region
alongside the existing re-parenting path. The OMP lowering path then
finds pre-allocated blocks for the whole body — matching the state that
existed before the wrap feature changed isUnstructured propagation —
without any lazy-allocation logic at consumer sites.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Enable CUDA device procedures to call !$acc routine procedures.
- Treat ACC routines as device-callable during CUDA semantic checking.
- Apply implicit-device dummy argument handling to ACC routines called
from CUDA device code.
- Defer CUDA cloning of ACC routines until ACC lowering materializes and
moves the specialized routine into the GPU module.
- Add a CUF device-function transform regression test.
Reland of combined #208528 and #210753.
Fixes#199092 - Flang previously rejected intervening code between
associated loops in a collapsed nest (e.g. collapse(2) with statements
between the outer and inner DO). This patch removes that restriction and
implements correct lowering.
Global and component initial values were lowered with
`createSomeInitializerExpression` (the legacy, non-HLFIR expression
lowering). Route them through ConvertConstant instead, which is
self-contained and safe inside a fir.global initializer region: it never
consults the symbol map, allocates temporaries, or outlines constants
into memory.
Observable IR change: fir.no_reassoc no longer appears in fir.global
initializer regions for parenthesized scalar/derived constants. Update
global-initialization-parens.f90 -- previously a pre-commit baseline
pinning the old fir.no_reassoc behavior -- to assert the new folded
form, and add common-block-derived-initialization.f90 (a
DATA-initialized common block with a derived-type member).
Assisted-by: AI
Fold fir.box_addr and constant-dimension fir.box_dims of a descriptor
built by fir.create_box back to the operands that built it, so the
create_box can die when nothing consumes it as a real descriptor.
fir.array_coor is intentionally not folded through create_box, since
that would drop its explicit byte strides.
Assisted-by: Cursor
A missing `parallel_loop` directive in the `nestedTeamsAllowedSet`
currently causes code like the following to report a semantics issue:
```f90
!$omp teams
!$omp parallel loop
do i=1, 10
end do
!$omp end teams
```
This patch makes sure to accept it, since `parallel` is an allowed
construct to be immediately nested inside of `teams`, even when combined
with another construct.
Example:
```fortran
do i = lb, ub, step
...
end do
```
Flang lowers this with the DO variable as a redundant `iter_arg`, which
hides memory recurrences from later analyses. Simply removing it would
require converting the `index` IV to the source integer type each
iteration, potentially blocking vectorization.
Fix: allow `fir.do_loop` to use the DO variable’s integer type directly.
Trip-count and post-loop calculations remain in `index`. This removes
the redundant `iter_arg` without introducing per-iteration conversions.
`do concurrent` and unstructured loops are unaffected.
Example:
```fortran
program main
use cudafor
integer, allocatable, device :: b(:)
integer :: istat
allocate(b(1024))
b = 2
istat = cudaDeviceReset()
end program
```
Managed descriptors and main-program allocatable data could leak. After
`cudaDeviceReset()`, compiler-generated scope-exit cleanup could also
access
stale descriptors or recreate a CUDA context.
Fix: free device data and descriptors in the correct order, and avoid
unnecessary
managed temporary descriptors. Each routine’s CUDA scope-exit cleanup is
grouped
under one `CUFDeviceIsActive()` check using
`cuDevicePrimaryCtxGetState`.
Routines without CUDA cleanup—and individual runtime frees—incur no
query.
Extend the PFT-to-MLIR (HLFIR/FIR) lowering so unstructured DO and IF
constructs are emitted inside scf.execute_region, hiding their
multi-block CFG behind a single op. OpenACC lowerings that reject
multi-block content (e.g. the "unstructured do loop in combined acc
construct" TODO in OpenACC.cpp) now see a structured op instead.
The main goal is to prevent propagating the "unstructured" property up
the evaluation tree just because one nested evaluation is unstructured;
which is the current behavior.
Flag: -mmlir --wrap-unstructured-constructs-in-execute-region (default
on).
An evaluation is wrappable iff all of the following hold:
* wrap flag on
* eval is parser::DoConstruct or parser::IfConstruct
* eval.isUnstructured
* branchesAreInternal(eval) -- every controlSuccessor in the subtree
targets a nested eval or the constructExit
* !hasIncomingBranch(eval) -- no outside eval branches into the body
(PFT's synthetic IfConstruct around `if(c) goto X` absorbs label targets
between the IF and X; the incoming-branch check excludes such wrappers
when an outer GOTO names one of those labels)
* does not contain a ReturnStmt -- its lowering creates the function's
final block in the current region, which would mis-parent func.return
* not an infinite DO and does not contain one (no LoopControl in any
nested DO): the wrap's yield is unreachable and the body has no
write-shaped side effects, so RegionDCE treats the wrap as trivially
dead and drops it. Excluding the whole enclosing construct keeps such
infinite loops visible in the parent CFG.
* not the body DO of an enclosing OpenACCLoopConstruct or
OpenACCCombinedConstruct -- nor one of the N collapsed iterator DOs
reached by walking down through `collapse(N)`. Such DOs are driven
directly into acc.loop by the OpenACC lowering, so wrapping them would
hide the iteration from the acc.loop op.
Diagnostics
-----------
Emit per-wrap and per-function diagnostics on stderr so the wrapping is
observable from a single compile invocation:
[wrap-unstructured] wrapped DO at <loc>
[wrap-unstructured] wrapped IF at <loc>
[wrap-unstructured] summary: N execute_region(s) wrapping unstructured
constructs at <loc>
The counter is reset per function and the summary is suppressed when no
wraps fire.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Hoist initializer-less constant globals out of OpenACC compute regions
so implicit data mapping handles them. This avoids unresolved device
symbols for PARAMETER arrays defined in separately compiled modules,
while retaining implicit declare for initialized constants. Add
regression coverage and a global initializer query to the OpenACC
interface.
This patch adds `fir.create_box` operation that allows
creating `!fir.box<>` values with arbitrary byte strides.
It can be used to recreate boxes describing non-contiguous
arrays from descriptor components (base_addr/lbs/extents/strides)
across offload regions.
This is just initial definition and code generation code.
The folders and passes producing this operation will be added
later.