ROUP
Rust-based OpenMP Parser
Safe, fast, and comprehensive OpenMP directive parsing
What is ROUP?
ROUP is an experimental parser for OpenMP directives, written in safe Rust with C and C++ APIs. Parse OpenMP pragmas like #pragma omp parallel for
into structured data that your tools can analyze, transform, and process.
⚠️ Experimental Status: ROUP is under active development and not yet production-ready. APIs may change, and some OpenMP features are still being implemented. Use in research and experimental projects.
Perfect for:
- 🔧 Compiler research - Experiment with OpenMP parsing in compilers
- 🔍 Analysis prototypes - Build experimental linters and analyzers
- 🎓 Researchers - Study parallelization patterns and test new ideas
- 📚 Educators - Teaching tool for parallel programming concepts
Why ROUP?
🚀 Fast & Lightweight
- Microsecond parsing - Parse directives in ~500ns
- Zero-copy lexer - Minimal memory allocations
- No LLVM dependency - Standalone library, small binary size
- 16 FFI functions - Simple, focused C API
🛡️ Safe & Reliable
- 99.1% safe Rust - Memory safety guaranteed
- 352 passing tests - Comprehensive test coverage
- Fuzzing tested - Handles malformed input gracefully
- NULL-safe C API - Defensive checks at FFI boundary
📚 Comprehensive OpenMP Support
- 95 directives - From
parallel
tometadirective
- 91 clauses - Extensive OpenMP 3.0 through 6.0 coverage
- Version tracking - Know which OpenMP version introduced each feature
- Spec compliant - Follows official OpenMP specifications
🔌 Multi-Language APIs
Language | API Style | Memory Management | Status |
---|---|---|---|
Rust | Native | Automatic (ownership) | ✅ Stable |
C | Pointer-based | Manual (malloc/free pattern) | ✅ Stable |
C++ | RAII wrappers | Automatic (destructors) | ✅ Stable |
Fortran | C interop | Manual (via iso_c_binding) | ⚠️ Experimental |
Quick Example
Parse in 3 Lines (Rust)
use roup::parser::openmp;
let parser = openmp::parser();
let (_, directive) = parser.parse("#pragma omp parallel for num_threads(4)").unwrap();
// Access directive information
println!("Directive: {}", directive.name); // Output: Directive: parallel for
println!("Found {} clauses", directive.clauses.len()); // Output: Found 1 clauses
// Iterate through clauses
for clause in &directive.clauses {
println!(" Clause: {}", clause.name); // Output: Clause: num_threads
}
Parse in C
OmpDirective* dir = roup_parse("#pragma omp parallel for num_threads(4)");
printf("Clauses: %d\n", roup_directive_clause_count(dir));
roup_directive_free(dir);
Parse in C++ (with RAII)
roup::Directive dir("#pragma omp parallel for num_threads(4)");
std::cout << "Clauses: " << dir.clause_count() << "\n";
// Automatic cleanup!
Parse Fortran (Experimental)
! Free-form Fortran
directive_ptr = roup_parse_with_language("!$OMP PARALLEL PRIVATE(A)", &
ROUP_LANG_FORTRAN_FREE)
Feature Highlights
🎯 Comprehensive Coverage
Parallel Constructs - 20+ directives
parallel
- Basic parallel regionsparallel for
- Combined parallel + worksharingparallel sections
- Parallel sectionsparallel master
- Parallel master threadparallel loop
- OpenMP 5.0+ parallel loop- And more...
Work-Sharing - 10+ directives
for
/do
- Loop worksharingsections
/section
- Code sectionssingle
- Execute onceworkshare
- Fortran worksharingloop
- Generic loop construct
Tasking - 15+ directives
task
- Explicit taskstaskloop
- Loop-based taskstaskgroup
- Task synchronizationtaskwait
- Wait for taskstaskyield
- Yield to other tasks- Dependency clauses:
depend
,priority
,detach
Device Offloading - 25+ directives
target
- Offload to devicetarget data
- Device data managementtarget enter/exit data
- Data transfertarget update
- Synchronize datateams
- Multiple thread teamsdistribute
- Distribute iterations
SIMD - 10+ directives
simd
- SIMD loopsdeclare simd
- Vectorizable functionsdistribute simd
- Combined distribute + SIMD- Various alignment and vectorization clauses
Advanced (OpenMP 5.0+)
metadirective
- Context-sensitive directivesdeclare variant
- Function variantsloop
- Generic loop constructscan
- Prefix scan operationsassume
- Compiler assumptions
🔍 Rich Clause Support
92+ clause types including:
Category | Clauses |
---|---|
Data Sharing | private , shared , firstprivate , lastprivate |
Reductions | reduction(+:x) , reduction(min:y) , custom operators |
Scheduling | schedule(static) , schedule(dynamic,100) , collapse(3) |
Control | if(condition) , num_threads(8) , proc_bind(close) |
Device | map(to:x) , device(2) , defaultmap(tofrom:scalar) |
Dependencies | depend(in:x) , depend(out:y) , depend(inout:z) |
Architecture
┌──────────────────────────────────────┐
│ Your Application │
├──────────────────────────────────────┤
│ Language Bindings │
│ ├─ Rust API (native) │
│ ├─ C API (16 functions) │
│ └─ C++ API (RAII wrappers) │
├──────────────────────────────────────┤
│ Parser Layer (99.1% safe Rust) │
│ ├─ Directive Parser │
│ ├─ Clause Parser │
│ └─ Error Recovery │
├──────────────────────────────────────┤
│ Lexer (nom-based, zero-copy) │
└──────────────────────────────────────┘
Design Principles:
- Safety first - Rust ownership prevents memory bugs
- Zero-copy - Parse directly from input string
- Minimal FFI - Only ~60 lines of unsafe code (0.9%)
- Extensible - Easy to add new directives/clauses
Learn more about the architecture →
Comparison
ROUP vs LLVM/Clang
Feature | ROUP | LLVM/Clang |
---|---|---|
Purpose | OpenMP parsing only | Full C/C++ compiler |
Binary size | ~500KB | ~50MB+ |
Parse time | ~500ns - 1µs | ~10-100µs |
Dependencies | None | LLVM, Clang, libc++ |
API complexity | 16 C functions | 1000s of functions |
Learning curve | Minutes | Weeks |
Use case | Analysis, tools, IDE plugins | Compilation |
Use ROUP when:
- ✅ You only need to parse OpenMP, not compile
- ✅ You want minimal dependencies
- ✅ You need fast integration into tools
- ✅ You value simplicity and safety
Use LLVM when:
- You need full C/C++ compilation
- You're building a complete compiler
- You need LLVM IR generation
ROUP vs Custom Parser
Aspect | ROUP | Custom Parser |
---|---|---|
Development time | Minutes (add dependency) | Weeks/months |
OpenMP coverage | 120+ directives | You must implement all |
Testing | 342 tests included | You must write tests |
Maintenance | Active, updated for new OpenMP | You must maintain |
Edge cases | Handled (fuzzing tested) | Likely has bugs |
Spec compliance | Verified | Uncertain |
Verdict: Unless you have very specific needs, use ROUP.
Safety Guarantees
ROUP prioritizes safety without compromising usability:
Memory Safety
- ✅ No buffer overflows - Rust prevents at compile time
- ✅ No use-after-free - Ownership system enforces
- ✅ No double-free - Checked at FFI boundary
- ✅ No memory leaks - RAII and destructors
- ✅ No data races - Thread-safe parsing
API Safety
Rust API:
- 100% memory-safe by construction
- Impossible to trigger undefined behavior
C API:
- NULL checks before all pointer operations
- Returns safe defaults on error (-1, NULL)
- Validates UTF-8 encoding
- Documents all safety contracts
Testing
- 342 tests covering all features
- Fuzzing with random inputs
- Valgrind verified (no leaks)
- Thread sanitizer verified (no races)
- Address sanitizer verified (no memory errors)
Performance
Typical performance characteristics:
Operation | Time | Notes |
---|---|---|
Parse #pragma omp parallel | ~500ns | Simple directive |
Parse with clauses | ~800ns | num_threads(4) |
Complex directive | ~1.2µs | Multiple clauses |
Iterator creation | ~10ns | FFI overhead |
Scalability:
- ✅ Thread-safe - Parse from multiple threads
- ✅ Zero-copy - No string allocations during lexing
- ✅ Minimal allocations - ~3 allocations per directive
- ✅ Fast enough - Parsing is rarely the bottleneck
Getting Started
Choose your language:
Community
- GitHub: ouankou/roup
- Issues: Bug reports
- Discussions: Questions & ideas
- Contributing: How to contribute
License
ROUP is open source under the MIT License.
Copyright © 2024-2025 Anjia Wang
Next Steps
- 📖 Read the Getting Started guide
- 🦀 Try the Rust tutorial
- 🔧 Try the C tutorial
- 📚 Browse the API reference
- 🏗️ Learn the architecture
- ❓ Check the FAQ
Why ROUP?
For Compiler Developers
- Drop-in OpenMP/OpenACC parser component
- Well-tested, battle-hardened parsing logic
- Easy FFI integration from any language
For Tool Builders
- Analyze OpenMP code without a full compiler
- Build linters, formatters, and code analyzers
- Extract parallelization patterns from codebases
For Researchers
- Study directive usage patterns
- Prototype new directive extensions
- Educational tool for learning parallel programming
Quick Example
Rust
use roup::parser::openmp;
let parser = openmp::parser();
let input = "#pragma omp parallel for num_threads(4) private(i)";
match parser.parse(input) {
Ok((_, directive)) => {
println!("Directive: {:?}", directive.kind);
println!("Clauses: {}", directive.clauses.len());
}
Err(e) => eprintln!("Parse error: {:?}", e),
}
C
#include <stdio.h>
// Forward declarations
typedef struct OmpDirective OmpDirective;
extern OmpDirective* roup_parse(const char* input);
extern int32_t roup_directive_clause_count(const OmpDirective* dir);
extern void roup_directive_free(OmpDirective* dir);
int main() {
OmpDirective* dir = roup_parse("#pragma omp parallel for num_threads(4)");
if (dir) {
printf("Clauses: %d\n", roup_directive_clause_count(dir));
roup_directive_free(dir);
}
return 0;
}
C++
#include <iostream>
#include <memory>
struct OmpDirective;
extern "C" {
OmpDirective* roup_parse(const char* input);
int32_t roup_directive_clause_count(const OmpDirective* dir);
void roup_directive_free(OmpDirective* dir);
}
// RAII wrapper
class Directive {
OmpDirective* ptr_;
public:
explicit Directive(const char* input) : ptr_(roup_parse(input)) {}
~Directive() { if (ptr_) roup_directive_free(ptr_); }
bool valid() const { return ptr_ != nullptr; }
int clause_count() const {
return ptr_ ? roup_directive_clause_count(ptr_) : 0;
}
};
int main() {
Directive dir("#pragma omp parallel for num_threads(4)");
if (dir.valid()) {
std::cout << "Clauses: " << dir.clause_count() << "\n";
}
return 0;
}
Architecture
ROUP uses a clean, modular architecture:
┌─────────────────────────────────────────┐
│ Application Layer │
│ (Your compiler/tool/analyzer) │
└─────────────────┬───────────────────────┘
│
┌───────────┼───────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Rust API│ │ C API │ │ C++ API │
│ │ │ │ │ (RAII) │
└─────────┘ └─────────┘ └─────────┘
│ │ │
└───────────┼───────────┘
│
▼
┌────────────────┐
│ Core Parser │
│ (nom-based) │
└────────────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Lexer │ │Directive│ │ Clause │
│ │ │ Parser │ │ Parser │
└─────────┘ └─────────┘ └─────────┘
Key Design Principles:
- Safe by default - Rust's ownership system prevents memory errors
- Zero-copy parsing - Uses string slices, not allocations
- Minimal unsafe - FFI boundary only, well-documented
- Extensible - Easy to add new directives and clauses
OpenMP Support
ROUP currently supports OpenMP 5.0+ with comprehensive coverage:
Supported Directives (15+)
parallel
- Parallel regionsfor
- Worksharing loopssections
,single
- Worksharing constructstask
,taskwait
,taskgroup
- Taskingtarget
,teams
,distribute
- Device offloadingbarrier
,critical
,atomic
- Synchronizationmetadirective
- Dynamic selection- And more...
Supported Clauses (50+)
- Data sharing:
private
,shared
,firstprivate
,lastprivate
- Parallelism control:
num_threads
,if
,proc_bind
- Worksharing:
schedule
,collapse
,nowait
- Reductions:
reduction
with 10+ operators (+, *, min, max, etc.) - Device:
map
,device
,defaultmap
- Dependencies:
depend
,in
,out
,inout
- And more...
See the OpenMP Support Matrix for the complete list.
Safety Guarantees
ROUP is built with safety as a core principle:
Metric | Value | Notes |
---|---|---|
Safe Rust | 99.1% | All core logic is safe |
Unsafe blocks | 18 | Only at FFI boundary |
Unsafe lines | ~60 | Well-documented, NULL-checked |
Memory leaks | 0 | Rust's RAII prevents leaks |
Segfaults | 0 | Ownership system prevents use-after-free |
All unsafe
code is:
- Documented with safety requirements
- NULL-checked before dereferencing
- Isolated to
src/c_api.rs
- Tested with 355+ tests
Testing
ROUP has comprehensive test coverage:
- 239 doc tests - Examples in documentation are auto-tested
- 116 integration tests - Real-world usage scenarios
- 355 total tests - All passing, zero warnings
- Cross-platform - Tested on Linux, macOS, Windows
Test categories:
- ✅ Basic directives (parallel, for, task, teams, target)
- ✅ Complex features (reductions, metadirectives, nesting)
- ✅ Edge cases (comments, whitespace, error handling)
- ✅ Roundtrip parsing (parse → format → parse)
- ✅ FFI safety (C and C++ examples)
Getting Started
Want to experiment with ROUP? Check out our tutorials:
- C++ Tutorial - Build an experimental application with C++17
- Rust API Docs - Complete API reference
Or jump straight to the code:
License
ROUP is open source under the MIT License.
Copyright © 2024-2025 Anjia Wang
Getting Started
Get up and running with ROUP in 5 minutes. This guide covers installation, basic usage, and your first OpenMP parse for Rust, C, and C++.
Installation
Prerequisites
- Rust 1.70+ (Install Rust)
- C/C++ Compiler: Clang 10+ or GCC 9+ (for C/C++ usage)
Build ROUP
git clone https://github.com/ouankou/roup.git
cd roup
cargo build --release
This creates the library at:
- Linux:
target/release/libroup.so
- macOS:
target/release/libroup.dylib
- Windows:
target/release/roup.dll
Quick Start: Rust
1. Add Dependency
Add to your Cargo.toml
:
[dependencies]
roup = "0.3"
Or use the git version:
[dependencies]
roup = { git = "https://github.com/ouankou/roup.git" }
2. Parse Your First Directive
use roup::parser::openmp::parse_openmp_directive;
use roup::lexer::Language;
fn main() {
let input = "#pragma omp parallel for num_threads(4)";
match parse_openmp_directive(input, Language::C) {
Ok(directive) => {
println!("✓ Successfully parsed: {:?}", directive.kind);
println!(" Clauses: {}", directive.clauses.len());
for clause in &directive.clauses {
println!(" - {:?}", clause);
}
}
Err(e) => {
eprintln!("✗ Parse error: {}", e);
}
}
}
3. Run
cargo run
Output:
✓ Successfully parsed: ParallelFor
Clauses: 1
- NumThreads(Expr { value: "4", .. })
Next: See the Rust Tutorial for advanced usage.
Quick Start: C
1. Write Your Program
The C API uses direct pointers (malloc/free pattern):
#include <stdio.h>
#include <stdint.h>
// Forward declarations from libroup
typedef struct OmpDirective OmpDirective;
OmpDirective* roup_parse(const char* input);
int32_t roup_directive_clause_count(const OmpDirective* dir);
void roup_directive_free(OmpDirective* dir);
int main() {
// Parse a directive
OmpDirective* directive = roup_parse("#pragma omp parallel num_threads(4)");
if (!directive) {
fprintf(stderr, "Parse failed\n");
return 1;
}
// Query clause count
int32_t count = roup_directive_clause_count(directive);
printf("Clause count: %d\n", count);
// Clean up
roup_directive_free(directive);
return 0;
}
2. Compile
# Build ROUP library first
cargo build --release
# Compile your C program
clang example.c \
-L./target/release \
-lroup \
-lpthread -ldl -lm \
-Wl,-rpath,./target/release \
-o example
On macOS:
clang example.c \
-L./target/release \
-lroup \
-lpthread -ldl \
-Wl,-rpath,@executable_path/../target/release \
-o example
3. Run
./example
Output:
Clause count: 1
Next: See the C Tutorial for complete examples with iteration and error handling.
Quick Start: C++
1. Create Your Program
Modern C++17 with RAII wrappers:
#include <iostream>
#include <cstdint>
// Forward declarations from libroup C API
struct OmpDirective;
extern "C" {
OmpDirective* roup_parse(const char* input);
int32_t roup_directive_clause_count(const OmpDirective* dir);
void roup_directive_free(OmpDirective* dir);
}
// Simple RAII wrapper
class Directive {
OmpDirective* ptr_;
public:
explicit Directive(const char* input)
: ptr_(roup_parse(input)) {}
~Directive() {
if (ptr_) roup_directive_free(ptr_);
}
// Delete copy, allow move
Directive(const Directive&) = delete;
Directive& operator=(const Directive&) = delete;
Directive(Directive&& other) noexcept
: ptr_(other.ptr_) {
other.ptr_ = nullptr;
}
bool valid() const {
return ptr_ != nullptr;
}
int clause_count() const {
return ptr_ ? roup_directive_clause_count(ptr_) : 0;
}
};
int main() {
Directive dir("#pragma omp parallel for num_threads(4)");
if (!dir.valid()) {
std::cerr << "Parse failed\n";
return 1;
}
std::cout << "Clause count: " << dir.clause_count() << "\n";
return 0;
} // Automatic cleanup via RAII
2. Compile
# Build ROUP library first
cargo build --release
# Compile your C++ program
clang++ -std=c++17 example.cpp \
-L./target/release \
-lroup \
-lpthread -ldl -lm \
-Wl,-rpath,./target/release \
-o example
3. Run
./example
Output:
Clause count: 1
Next: See the C++ Tutorial for a complete real-world example.
What's Supported?
Directives (95 total)
✅ Parallelism: parallel
, for
, sections
, single
, master
✅ Tasking: task
, taskwait
, taskgroup
, taskloop
✅ Device offloading: target
, teams
, distribute
✅ Synchronization: barrier
, critical
, atomic
✅ Advanced: metadirective
, declare variant
, loop
Clauses (91 total)
✅ Scheduling: schedule
, collapse
, ordered
✅ Data-sharing: private
, shared
, firstprivate
, lastprivate
✅ Reductions: reduction(+|-|*|&|&&|min|max:vars)
✅ Device clauses: device
, map
, is_device_ptr
✅ Control: if
, num_threads
, default
For the complete support matrix, see OpenMP Support.
Troubleshooting
Library Not Found at Runtime
Linux:
export LD_LIBRARY_PATH=$PWD/target/release:$LD_LIBRARY_PATH
./example
Or use -Wl,-rpath
during compilation (recommended):
clang example.c -L./target/release -lroup -lpthread -ldl -lm -Wl,-rpath,$PWD/target/release
macOS:
export DYLD_LIBRARY_PATH=$PWD/target/release:$DYLD_LIBRARY_PATH
./example
Parse Returns NULL
Check your OpenMP syntax:
// ✅ Valid
OmpDirective* dir = roup_parse("#pragma omp parallel");
// ✅ Valid - with clauses
dir = roup_parse("#pragma omp parallel num_threads(4)");
// ❌ Invalid - missing 'omp'
dir = roup_parse("#pragma parallel"); // Returns NULL
Always check for NULL:
OmpDirective* dir = roup_parse(input);
if (!dir) {
fprintf(stderr, "Parse error\n");
return 1;
}
// ... use dir ...
roup_directive_free(dir);
C++ Compilation Errors
Make sure you're using C++17:
# ✅ Correct
clang++ -std=c++17 example.cpp ...
# ❌ Wrong - C++11 lacks required features
clang++ -std=c++11 example.cpp ...
Next Steps
Learn More
- Rust Tutorial - Idiomatic Rust patterns (coming soon)
- C Tutorial - Complete C examples (coming soon)
- C++ Tutorial - Real-world application
- API Reference - Complete C/Rust API docs
Examples
examples/c/
- 5 complete C examplesexamples/cpp/
- 3 complete C++ examples with RAII
Advanced Topics
- Error handling strategies
- Iterator patterns for clauses
- Thread safety considerations
- Performance optimization
Summary
Rust:
cargo add roup
# Write code, then:
cargo run
C:
cargo build --release
clang example.c -L./target/release -lroup -lpthread -ldl -lm -Wl,-rpath,./target/release
./example
C++:
cargo build --release
clang++ -std=c++17 example.cpp -L./target/release -lroup -lpthread -ldl -lm -Wl,-rpath,./target/release
./example
You're ready to experiment with OpenMP parsing! 🎉
Building Guide
This guide covers building ROUP and integrating it into your projects across different languages and platforms.
Quick Start
# Clone the repository
git clone https://github.com/ouankou/roup.git
cd roup
# Build the library (release mode, optimized)
cargo build --release
# Run tests to verify
cargo test
# Build is complete! Library at: target/release/libroup.{a,so,dylib,dll}
Next steps:
- Rust users: Add ROUP as a dependency (see below)
- C users: Link against
libroup.a
(see C Tutorial) - C++ users: Use RAII wrappers (see C++ Tutorial)
Rust Integration
Option 1: Using crates.io (Recommended)
Add to your Cargo.toml
:
[dependencies]
roup = "0.3"
Then use in your code:
use roup::parser::parse;
fn main() {
let result = parse("#pragma omp parallel for");
match result {
Ok(directive) => println!("Parsed: {:?}", directive),
Err(e) => eprintln!("Error: {}", e),
}
}
Option 2: Using Git Dependency
[dependencies]
roup = { git = "https://github.com/ouankou/roup.git" }
Option 3: Local Development
[dependencies]
roup = { path = "../roup" }
Building Your Rust Project
# Standard cargo commands
cargo build # Debug build
cargo build --release # Optimized build
cargo test # Run tests
cargo doc --open # Generate and view docs
See Rust Tutorial for complete usage examples.
C Integration
Prerequisites
- Rust toolchain (to build libroup)
- C compiler: GCC, Clang, or MSVC
- Build tools: Make or CMake (optional)
Step 1: Build the ROUP Library
cd /path/to/roup
cargo build --release
This creates:
- Linux:
target/release/libroup.{a,so}
- macOS:
target/release/libroup.{a,dylib}
- Windows:
target/release/roup.{lib,dll}
Step 2: Create Header File
Create roup_ffi.h
with function declarations (see C Tutorial for complete header).
Step 3: Compile Your C Program
Using GCC/Clang (Linux/macOS)
# Static linking
gcc -o myapp main.c \
-I/path/to/roup_ffi.h \
-L/path/to/roup/target/release \
-lroup \
-lpthread -ldl -lm
# Dynamic linking with rpath
gcc -o myapp main.c \
-I/path/to/roup_ffi.h \
-L/path/to/roup/target/release \
-lroup \
-Wl,-rpath,/path/to/roup/target/release \
-lpthread -ldl -lm
Using CMake
cmake_minimum_required(VERSION 3.10)
project(MyApp C)
# Add ROUP library
add_library(roup STATIC IMPORTED)
set_target_properties(roup PROPERTIES
IMPORTED_LOCATION "/path/to/roup/target/release/libroup.a"
)
# Create executable
add_executable(myapp main.c)
target_include_directories(myapp PRIVATE "/path/to/roup_ffi.h")
target_link_libraries(myapp roup pthread dl m)
Using MSVC (Windows)
REM Build ROUP library first
cargo build --release
REM Compile C program
cl.exe main.c /I"C:\path\to\roup" ^
/link "C:\path\to\roup\target\release\roup.lib" ^
ws2_32.lib userenv.lib
Step 4: Run Your Program
# If using static linking
./myapp
# If using dynamic linking without rpath
LD_LIBRARY_PATH=/path/to/roup/target/release ./myapp
# Windows
set PATH=C:\path\to\roup\target\release;%PATH%
myapp.exe
Complete Example
See examples/c/tutorial_basic.c
for a full working example with build instructions.
C++ Integration
C++ programs use the same C API with optional RAII wrappers for automatic memory management.
Step 1: Build ROUP Library
cargo build --release
Step 2: Create RAII Wrappers
See C++ Tutorial - Step 2 for complete wrapper code.
Step 3: Compile with C++17
# Using g++
g++ -o myapp main.cpp \
-I/path/to/roup_ffi.h \
-I/path/to/roup_wrapper.hpp \
-L/path/to/roup/target/release \
-lroup \
-std=c++17 \
-lpthread -ldl -lm
# Using Clang++
clang++ -o myapp main.cpp \
-I/path/to/roup_ffi.h \
-I/path/to/roup_wrapper.hpp \
-L/path/to/roup/target/release \
-lroup \
-std=c++17 \
-lpthread -ldl -lm
CMake for C++
cmake_minimum_required(VERSION 3.10)
project(MyApp CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(roup STATIC IMPORTED)
set_target_properties(roup PROPERTIES
IMPORTED_LOCATION "/path/to/roup/target/release/libroup.a"
)
add_executable(myapp main.cpp)
target_include_directories(myapp PRIVATE
"/path/to/roup_ffi.h"
"/path/to/roup_wrapper.hpp"
)
target_link_libraries(myapp roup pthread dl m)
Platform-Specific Notes
Linux
Ubuntu/Debian
# Install build tools
sudo apt-get update
sudo apt-get install build-essential curl git
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Build ROUP
cargo build --release
Fedora/RHEL
# Install build tools
sudo dnf install gcc git
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Build ROUP
cargo build --release
Library location: target/release/libroup.{a,so}
macOS
# Install Xcode Command Line Tools
xcode-select --install
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Build ROUP
cargo build --release
Library location: target/release/libroup.{a,dylib}
Note: On macOS, the dynamic library extension is .dylib
, not .so
.
Windows
Using Rust with MSVC
# Install Rust (uses MSVC toolchain by default on Windows)
# Download from: https://rustup.rs/
# Install Visual Studio Build Tools
# Download from: https://visualstudio.microsoft.com/downloads/
# Build ROUP
cargo build --release
Library location: target\release\roup.{lib,dll}
Using Rust with GNU (MinGW)
# Install MSYS2 from https://www.msys2.org/
# Then in MSYS2 terminal:
# Install MinGW toolchain
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-rust
# Build ROUP
cargo build --release
WSL (Recommended for C/C++)
Windows Subsystem for Linux provides a full Linux environment:
# In WSL (Ubuntu)
sudo apt-get install build-essential
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo build --release
Build Configurations
Debug Build (Development)
cargo build
# Output: target/debug/libroup.{a,so}
# Features: Debug symbols, assertions, slower but better errors
Release Build (Production)
cargo build --release
# Output: target/release/libroup.{a,so}
# Features: Optimized, no debug symbols, faster execution
Release with Debug Info
cargo build --release --config profile.release.debug=true
# Output: target/release/libroup.{a,so}
# Features: Optimized but with debug symbols for profiling
Custom Features
# Build with all features
cargo build --all-features
# Build with specific feature
cargo build --features "serde"
# Build without default features
cargo build --no-default-features
Testing
Run All Tests
# Run all tests
cargo test
# Run with output
cargo test -- --nocapture
# Run specific test
cargo test test_parallel_directive
# Run tests for specific module
cargo test parser::
Run Examples
# List available examples
cargo run --example
# Run specific example (if any exist)
cargo run --example parse_simple
Benchmarks
# If benchmarks are available
cargo bench
Troubleshooting
"linker cc
not found"
Problem: No C compiler installed.
Solution:
# Linux
sudo apt-get install build-essential
# macOS
xcode-select --install
# Windows
# Install Visual Studio Build Tools
"cannot find -lroup"
Problem: Linker can't find the ROUP library.
Solution:
# Verify library exists
ls -lh target/release/libroup.*
# Rebuild if needed
cargo build --release
# Check linker path
gcc ... -L$(pwd)/target/release -lroup
"error while loading shared libraries: libroup.so"
Problem: Runtime can't find dynamic library.
Solution 1 - rpath:
gcc ... -Wl,-rpath,/path/to/roup/target/release
Solution 2 - LD_LIBRARY_PATH:
export LD_LIBRARY_PATH=/path/to/roup/target/release:$LD_LIBRARY_PATH
./myapp
Solution 3 - Install system-wide:
sudo cp target/release/libroup.so /usr/local/lib/
sudo ldconfig
Rust Version Too Old
Problem: Compilation fails with version error.
Solution:
# Update Rust toolchain
rustup update stable
# Verify version
rustc --version
# Ensure your Rust version is at least 1.70.0
Windows: "VCRUNTIME140.dll missing"
Problem: Missing Visual C++ runtime.
Solution: Download and install Visual C++ Redistributable
Build Performance Tips
Faster Incremental Builds
# Use sccache for caching
cargo install sccache
export RUSTC_WRAPPER=sccache
# Use faster linker (Linux)
sudo apt-get install lld
export RUSTFLAGS="-C link-arg=-fuse-ld=lld"
Parallel Builds
# Use all CPU cores (default)
cargo build -j $(nproc)
# Limit parallel jobs
cargo build -j 4
Reduce Binary Size
# Add to Cargo.toml
[profile.release]
opt-level = "z" # Optimize for size
lto = true # Link-time optimization
codegen-units = 1 # Better optimization
strip = true # Remove debug symbols
Cross-Compilation
Linux to Windows
# Install target
rustup target add x86_64-pc-windows-gnu
# Install MinGW
sudo apt-get install mingw-w64
# Build
cargo build --release --target x86_64-pc-windows-gnu
macOS to Linux
# Install target
rustup target add x86_64-unknown-linux-gnu
# Build (requires cross-compilation setup)
cargo build --release --target x86_64-unknown-linux-gnu
For more complex cross-compilation, consider cross:
cargo install cross
cross build --release --target x86_64-unknown-linux-gnu
IDE Setup
Visual Studio Code
Recommended extensions:
- rust-analyzer - Language server
- CodeLLDB - Debugger
- crates - Dependency management
CLion / IntelliJ IDEA
Install the Rust plugin from JetBrains marketplace.
Vim/Neovim
Use rust-analyzer with your LSP client (coc.nvim, nvim-lspconfig, etc.)
Next Steps
After building successfully:
- Rust developers: See Rust Tutorial
- C developers: See C Tutorial
- C++ developers: See C++ Tutorial
- API Reference: See API Reference
Getting Help
- Build issues: Check GitHub Issues
- Questions: See FAQ
- Examples: Browse
examples/
directory - Documentation: Read
docs/
directory
Rust Tutorial
Learn idiomatic Rust patterns for parsing and querying OpenMP directives with ROUP.
Overview
This tutorial covers:
- Basic Parsing - Parse your first directive
- Error Handling - Robust error handling patterns
- Querying Directives - Extract directive information
- Working with Clauses - Iterate and pattern match clauses
- Advanced Patterns - Real-world usage patterns
- Testing - Writing tests for your parser integration
Basic Parsing
Your First Parse
use roup::parser::openmp::parse_openmp_directive;
use roup::lexer::Language;
fn main() {
let input = "#pragma omp parallel";
match parse_openmp_directive(input, Language::C) {
Ok(directive) => {
println!("Successfully parsed: {:?}", directive.kind);
}
Err(e) => {
eprintln!("Parse error: {}", e);
}
}
}
Parse with Clauses
use roup::parser::openmp::parse_openmp_directive;
use roup::lexer::Language;
fn main() {
let input = "#pragma omp parallel for num_threads(4) private(x, y)";
match parse_openmp_directive(input, Language::C) {
Ok(directive) => {
println!("Directive: {:?}", directive.kind);
println!("Clauses: {}", directive.clauses.len());
for (i, clause) in directive.clauses.iter().enumerate() {
println!(" Clause {}: {:?}", i + 1, clause);
}
}
Err(e) => {
eprintln!("Failed to parse: {}", e);
}
}
}
Output:
Directive: ParallelFor
Clauses: 2
Clause 1: NumThreads(Expr { value: "4", .. })
Clause 2: Private { items: ["x", "y"], .. }
Error Handling
Basic Error Handling
use roup::parser::openmp::parse_openmp_directive;
use roup::lexer::Language;
fn parse_directive(input: &str) -> Result<(), Box<dyn std::error::Error>> {
let directive = parse_openmp_directive(input, Language::C)?;
println!("Parsed: {:?}", directive.kind);
println!("Location: line {}, column {}",
directive.location.line,
directive.location.column);
Ok(())
}
fn main() {
let inputs = vec![
"#pragma omp parallel",
"#pragma omp for schedule(static)",
"#pragma omp invalid", // This will fail
];
for input in inputs {
match parse_directive(input) {
Ok(()) => println!("✓ Success: {}", input),
Err(e) => eprintln!("✗ Error: {} - {}", input, e),
}
}
}
Custom Error Type
use roup::parser::openmp::parse_openmp_directive;
use roup::lexer::Language;
use std::fmt;
#[derive(Debug)]
enum OpenMPError {
ParseError(String),
UnsupportedDirective(String),
MissingRequiredClause(String),
}
impl fmt::Display for OpenMPError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
OpenMPError::ParseError(msg) => write!(f, "Parse error: {}", msg),
OpenMPError::UnsupportedDirective(kind) => {
write!(f, "Unsupported directive: {}", kind)
}
OpenMPError::MissingRequiredClause(clause) => {
write!(f, "Missing required clause: {}", clause)
}
}
}
}
impl std::error::Error for OpenMPError {}
fn validate_parallel_directive(input: &str) -> Result<(), OpenMPError> {
let directive = parse_openmp_directive(input, Language::C)
.map_err(|e| OpenMPError::ParseError(e.to_string()))?;
if !directive.kind.is_parallel() {
return Err(OpenMPError::UnsupportedDirective(
format!("{:?}", directive.kind)
));
}
// Check for required clauses (example: must have num_threads)
let has_num_threads = directive.clauses.iter()
.any(|c| c.is_num_threads());
if !has_num_threads {
return Err(OpenMPError::MissingRequiredClause("num_threads".into()));
}
Ok(())
}
fn main() {
match validate_parallel_directive("#pragma omp parallel num_threads(4)") {
Ok(()) => println!("✓ Valid parallel directive"),
Err(e) => eprintln!("✗ {}", e),
}
}
Querying Directives
Check Directive Kind
use roup::parser::openmp::parse_openmp_directive;
use roup::ir::DirectiveKind;
use roup::lexer::Language;
fn main() {
let input = "#pragma omp parallel for";
let directive = parse_openmp_directive(input, Language::C).unwrap();
// Pattern match on kind
match directive.kind {
DirectiveKind::Parallel => println!("This is a parallel directive"),
DirectiveKind::For => println!("This is a for directive"),
DirectiveKind::ParallelFor => println!("This is a combined parallel for"),
DirectiveKind::Target => println!("This is a target directive"),
_ => println!("Other directive type"),
}
// Or use helper methods
if directive.kind.is_parallel() {
println!("Contains parallel semantics");
}
if directive.kind.is_worksharing() {
println!("Is a worksharing construct");
}
}
Extract Source Location
use roup::parser::openmp::parse_openmp_directive;
use roup::lexer::Language;
fn main() {
let input = "#pragma omp parallel";
let directive = parse_openmp_directive(input, Language::C).unwrap();
println!("Directive found at:");
println!(" Line: {}", directive.location.line);
println!(" Column: {}", directive.location.column);
println!(" Language: {:?}", directive.language);
}
Working with Clauses
Iterate Over Clauses
use roup::parser::openmp::parse_openmp_directive;
use roup::lexer::Language;
fn main() {
let input = "#pragma omp parallel num_threads(8) default(shared) private(x)";
let directive = parse_openmp_directive(input, Language::C).unwrap();
println!("Found {} clauses:", directive.clauses.len());
for clause in &directive.clauses {
println!(" - {:?}", clause);
}
}
Pattern Match on Clauses
use roup::parser::openmp::parse_openmp_directive;
use roup::ir::ClauseData;
use roup::lexer::Language;
fn main() {
let input = "#pragma omp parallel num_threads(4) default(shared) private(x, y)";
let directive = parse_openmp_directive(input, Language::C).unwrap();
for clause in &directive.clauses {
match clause {
ClauseData::NumThreads(expr) => {
println!("Thread count: {}", expr.value);
}
ClauseData::Default(kind) => {
println!("Default sharing: {:?}", kind);
}
ClauseData::Private { items, .. } => {
println!("Private variables: {:?}", items);
}
ClauseData::Shared { items, .. } => {
println!("Shared variables: {:?}", items);
}
ClauseData::Reduction { operator, items, .. } => {
println!("Reduction: {:?} on {:?}", operator, items);
}
_ => {
println!("Other clause: {:?}", clause);
}
}
}
}
Find Specific Clauses
use roup::parser::openmp::parse_openmp_directive;
use roup::ir::ClauseData;
use roup::lexer::Language;
fn get_thread_count(input: &str) -> Option<String> {
let directive = parse_openmp_directive(input, Language::C).ok()?;
directive.clauses.iter()
.find_map(|clause| {
if let ClauseData::NumThreads(expr) = clause {
Some(expr.value.to_string())
} else {
None
}
})
}
fn get_private_vars(input: &str) -> Vec<String> {
let directive = parse_openmp_directive(input, Language::C)
.ok()
.unwrap_or_default();
directive.clauses.iter()
.filter_map(|clause| {
if let ClauseData::Private { items, .. } = clause {
Some(items.iter().map(|s| s.to_string()).collect())
} else {
None
}
})
.flatten()
.collect()
}
fn main() {
let input = "#pragma omp parallel num_threads(8) private(x, y, z)";
if let Some(count) = get_thread_count(input) {
println!("Thread count: {}", count);
}
let vars = get_private_vars(input);
println!("Private variables: {:?}", vars);
}
Output:
Thread count: 8
Private variables: ["x", "y", "z"]
Advanced Patterns
Parse Multiple Directives
use roup::parser::openmp::parse_openmp_directive;
use roup::ir::DirectiveIR;
use roup::lexer::Language;
fn parse_file_directives(source: &str) -> Vec<DirectiveIR> {
source.lines()
.filter(|line| line.trim().starts_with("#pragma omp"))
.filter_map(|line| {
parse_openmp_directive(line, Language::C).ok()
})
.collect()
}
fn main() {
let source = r#"
#pragma omp parallel num_threads(4)
for (int i = 0; i < n; i++) {
#pragma omp task
process(i);
}
#pragma omp taskwait
"#;
let directives = parse_file_directives(source);
println!("Found {} OpenMP directives:", directives.len());
for (i, dir) in directives.iter().enumerate() {
println!(" {}. {:?} at line {}",
i + 1, dir.kind, dir.location.line);
}
}
Directive Analysis
use roup::parser::openmp::parse_openmp_directive;
use roup::ir::{DirectiveIR, ClauseData};
use roup::lexer::Language;
struct DirectiveStats {
total_clauses: usize,
has_data_sharing: bool,
has_scheduling: bool,
has_reduction: bool,
thread_count: Option<String>,
}
impl DirectiveStats {
fn analyze(directive: &DirectiveIR) -> Self {
let total_clauses = directive.clauses.len();
let mut has_data_sharing = false;
let mut has_scheduling = false;
let mut has_reduction = false;
let mut thread_count = None;
for clause in &directive.clauses {
match clause {
ClauseData::Private { .. } |
ClauseData::Shared { .. } |
ClauseData::Firstprivate { .. } |
ClauseData::Lastprivate { .. } => {
has_data_sharing = true;
}
ClauseData::Schedule { .. } => {
has_scheduling = true;
}
ClauseData::Reduction { .. } => {
has_reduction = true;
}
ClauseData::NumThreads(expr) => {
thread_count = Some(expr.value.to_string());
}
_ => {}
}
}
Self {
total_clauses,
has_data_sharing,
has_scheduling,
has_reduction,
thread_count,
}
}
}
fn main() {
let input = "#pragma omp parallel for num_threads(4) \
schedule(static) private(x) reduction(+:sum)";
let directive = parse_openmp_directive(input, Language::C).unwrap();
let stats = DirectiveStats::analyze(&directive);
println!("Directive Analysis:");
println!(" Total clauses: {}", stats.total_clauses);
println!(" Has data-sharing: {}", stats.has_data_sharing);
println!(" Has scheduling: {}", stats.has_scheduling);
println!(" Has reduction: {}", stats.has_reduction);
if let Some(count) = stats.thread_count {
println!(" Thread count: {}", count);
}
}
Output:
Directive Analysis:
Total clauses: 4
Has data-sharing: true
Has scheduling: true
Has reduction: true
Thread count: 4
Building a Directive Validator
use roup::parser::openmp::parse_openmp_directive;
use roup::ir::{DirectiveIR, DirectiveKind, ClauseData};
use roup::lexer::Language;
struct ValidationRule {
name: &'static str,
check: fn(&DirectiveIR) -> bool,
}
fn validate_directive(directive: &DirectiveIR, rules: &[ValidationRule]) -> Vec<String> {
rules.iter()
.filter(|rule| !(rule.check)(directive))
.map(|rule| rule.name.to_string())
.collect()
}
fn main() {
let rules = vec![
ValidationRule {
name: "Parallel regions should specify thread count",
check: |dir| {
!dir.kind.is_parallel() ||
dir.clauses.iter().any(|c| matches!(c, ClauseData::NumThreads(_)))
},
},
ValidationRule {
name: "For loops with reduction should have schedule clause",
check: |dir| {
let has_reduction = dir.clauses.iter()
.any(|c| matches!(c, ClauseData::Reduction { .. }));
let has_schedule = dir.clauses.iter()
.any(|c| matches!(c, ClauseData::Schedule { .. }));
!has_reduction || has_schedule
},
},
];
let input = "#pragma omp parallel"; // Missing num_threads
let directive = parse_openmp_directive(input, Language::C).unwrap();
let violations = validate_directive(&directive, &rules);
if violations.is_empty() {
println!("✓ All validation rules passed");
} else {
println!("✗ Validation warnings:");
for violation in violations {
println!(" - {}", violation);
}
}
}
Testing
Unit Testing
#[cfg(test)]
mod tests {
use roup::parser::openmp::parse_openmp_directive;
use roup::ir::DirectiveKind;
use roup::lexer::Language;
#[test]
fn test_parse_parallel() {
let input = "#pragma omp parallel";
let result = parse_openmp_directive(input, Language::C);
assert!(result.is_ok());
let directive = result.unwrap();
assert_eq!(directive.kind, DirectiveKind::Parallel);
assert_eq!(directive.clauses.len(), 0);
}
#[test]
fn test_parse_with_clauses() {
let input = "#pragma omp parallel num_threads(4)";
let directive = parse_openmp_directive(input, Language::C).unwrap();
assert_eq!(directive.kind, DirectiveKind::Parallel);
assert_eq!(directive.clauses.len(), 1);
}
#[test]
fn test_invalid_directive() {
let input = "#pragma omp invalid_directive";
let result = parse_openmp_directive(input, Language::C);
assert!(result.is_err());
}
#[test]
fn test_fortran_syntax() {
let input = "!$omp parallel";
let result = parse_openmp_directive(input, Language::Fortran);
assert!(result.is_ok());
let directive = result.unwrap();
assert_eq!(directive.kind, DirectiveKind::Parallel);
}
}
Integration Testing
#[cfg(test)]
mod integration_tests {
use roup::parser::openmp::parse_openmp_directive;
use roup::ir::ClauseData;
use roup::lexer::Language;
#[test]
fn test_complete_parsing_pipeline() {
let inputs = vec![
"#pragma omp parallel",
"#pragma omp for schedule(static)",
"#pragma omp parallel for num_threads(8) private(x)",
"#pragma omp task depend(in: x) priority(10)",
];
for input in inputs {
let result = parse_openmp_directive(input, Language::C);
assert!(result.is_ok(), "Failed to parse: {}", input);
let directive = result.unwrap();
assert!(directive.kind.is_valid());
// Verify round-trip
let output = directive.to_string();
assert!(!output.is_empty());
}
}
#[test]
fn test_clause_extraction() {
let input = "#pragma omp parallel for \
num_threads(4) \
schedule(dynamic, 100) \
private(i, j) \
reduction(+:sum)";
let directive = parse_openmp_directive(input, Language::C).unwrap();
// Count clause types
let mut num_threads_count = 0;
let mut schedule_count = 0;
let mut private_count = 0;
let mut reduction_count = 0;
for clause in &directive.clauses {
match clause {
ClauseData::NumThreads(_) => num_threads_count += 1,
ClauseData::Schedule { .. } => schedule_count += 1,
ClauseData::Private { .. } => private_count += 1,
ClauseData::Reduction { .. } => reduction_count += 1,
_ => {}
}
}
assert_eq!(num_threads_count, 1);
assert_eq!(schedule_count, 1);
assert_eq!(private_count, 1);
assert_eq!(reduction_count, 1);
}
}
Best Practices
1. Always Handle Errors
// ❌ Bad - unwrap can panic
let directive = parse_openmp_directive(input, Language::C).unwrap();
// ✅ Good - explicit error handling
match parse_openmp_directive(input, Language::C) {
Ok(directive) => { /* use directive */ }
Err(e) => { /* handle error */ }
}
2. Use Pattern Matching
// ❌ Bad - lots of if-let chains
for clause in &directive.clauses {
if let ClauseData::NumThreads(expr) = clause {
// ...
} else if let ClauseData::Private { items, .. } = clause {
// ...
}
}
// ✅ Good - clean match expression
for clause in &directive.clauses {
match clause {
ClauseData::NumThreads(expr) => { /* ... */ }
ClauseData::Private { items, .. } => { /* ... */ }
_ => {}
}
}
3. Leverage Iterator Combinators
// ❌ Bad - manual iteration
let mut has_reduction = false;
for clause in &directive.clauses {
if matches!(clause, ClauseData::Reduction { .. }) {
has_reduction = true;
break;
}
}
// ✅ Good - iterator method
let has_reduction = directive.clauses.iter()
.any(|c| matches!(c, ClauseData::Reduction { .. }));
4. Create Helper Functions
// Reusable helper
fn has_clause<F>(directive: &DirectiveIR, predicate: F) -> bool
where
F: Fn(&ClauseData) -> bool,
{
directive.clauses.iter().any(predicate)
}
// Usage
if has_clause(&directive, |c| matches!(c, ClauseData::NumThreads(_))) {
println!("Has num_threads clause");
}
Next Steps
- C Tutorial - Learn the C FFI API
- C++ Tutorial - Build a real-world application
- API Reference - Complete Rust API documentation
- Examples - Check out
tests/
directory for 355+ test cases
Summary
Key Takeaways:
- Use
parse_openmp_directive()
for parsing - Handle errors with
Result
types - Pattern match on
DirectiveKind
andClauseData
- Use iterators for clause analysis
- Write tests for your integration code
Common Patterns:
// Parse
let directive = parse_openmp_directive(input, Language::C)?;
// Check kind
if directive.kind.is_parallel() { /* ... */ }
// Find clause
let num_threads = directive.clauses.iter()
.find_map(|c| match c {
ClauseData::NumThreads(expr) => Some(expr.value.clone()),
_ => None,
});
// Analyze all clauses
for clause in &directive.clauses {
match clause {
ClauseData::Private { items, .. } => { /* ... */ }
ClauseData::Shared { items, .. } => { /* ... */ }
_ => {}
}
}
Happy parsing! 🦀
C Tutorial
This tutorial demonstrates how to use ROUP's minimal unsafe pointer-based C API for parsing OpenMP directives. The API uses direct C pointers following standard malloc/free patterns familiar to C programmers.
API Design: Direct pointers (
*mut OmpDirective
,*mut OmpClause
) with manual memory management. No global state, no handles.Source:
src/c_api.rs
- 16 FFI functions, ~60 lines of unsafe code
Prerequisites
Before starting, ensure you have:
- C compiler (GCC, Clang, or MSVC)
- ROUP library compiled (see Building Guide)
- Basic understanding of malloc/free patterns
Example code: See examples/c/tutorial_basic.c
for a complete working example.
Step 1: Setup and Compilation
Project Structure
my-project/
├── src/
│ └── main.c
├── include/
│ └── roup_ffi.h # Forward declarations
└── libroup.a # Built from cargo build
Forward Declarations
Create include/roup_ffi.h
with the C API declarations:
#ifndef ROUP_FFI_H
#define ROUP_FFI_H
#include <stdint.h>
// Opaque types (defined in Rust)
typedef struct OmpDirective OmpDirective;
typedef struct OmpClause OmpClause;
typedef struct OmpClauseIterator OmpClauseIterator;
typedef struct OmpStringList OmpStringList;
// Lifecycle functions
extern OmpDirective* roup_parse(const char* input);
extern void roup_directive_free(OmpDirective* directive);
extern void roup_clause_free(OmpClause* clause);
// Directive queries
extern int32_t roup_directive_kind(const OmpDirective* directive);
extern int32_t roup_directive_clause_count(const OmpDirective* directive);
extern OmpClauseIterator* roup_directive_clauses_iter(const OmpDirective* directive);
// Iterator functions
extern int32_t roup_clause_iterator_next(OmpClauseIterator* iter, OmpClause** out);
extern void roup_clause_iterator_free(OmpClauseIterator* iter);
// Clause queries
extern int32_t roup_clause_kind(const OmpClause* clause);
extern int32_t roup_clause_schedule_kind(const OmpClause* clause);
extern int32_t roup_clause_reduction_operator(const OmpClause* clause);
extern int32_t roup_clause_default_data_sharing(const OmpClause* clause);
// Variable lists
extern OmpStringList* roup_clause_variables(const OmpClause* clause);
extern int32_t roup_string_list_len(const OmpStringList* list);
extern const char* roup_string_list_get(const OmpStringList* list, int32_t index);
extern void roup_string_list_free(OmpStringList* list);
#endif // ROUP_FFI_H
Compilation
Option 1: Using GCC/Clang
# Build ROUP library
cargo build --release
# Compile C program
gcc -o my_app src/main.c \
-I include \
-L target/release \
-lroup \
-lpthread -ldl -lm
Option 2: Using CMake
cmake_minimum_required(VERSION 3.10)
project(roup_example C)
add_executable(my_app src/main.c)
target_include_directories(my_app PRIVATE include)
target_link_libraries(my_app ${CMAKE_SOURCE_DIR}/target/release/libroup.a pthread dl m)
Step 2: Parse a Simple Directive
Let's start with the most basic operation: parsing a simple directive.
#include <stdio.h>
#include "roup_ffi.h"
int main(void) {
const char* input = "#pragma omp parallel";
// Parse the directive
OmpDirective* dir = roup_parse(input);
// Check for errors (NULL = parse failed)
if (!dir) {
fprintf(stderr, "Parse failed!\n");
return 1;
}
printf("✅ Parse succeeded!\n");
// IMPORTANT: Free the directive
roup_directive_free(dir);
return 0;
}
Key Points:
roup_parse()
returns a pointer orNULL
on error- Always check for
NULL
before using the directive - Always call
roup_directive_free()
to prevent memory leaks
Step 3: Query Directive Properties
After parsing, you can query the directive's properties:
#include <stdio.h>
#include "roup_ffi.h"
int main(void) {
const char* input = "#pragma omp parallel for num_threads(4)";
OmpDirective* dir = roup_parse(input);
if (!dir) {
return 1;
}
// Query directive properties
int32_t kind = roup_directive_kind(dir);
int32_t clause_count = roup_directive_clause_count(dir);
printf("Directive kind: %d\n", kind);
printf("Clause count: %d\n", clause_count);
roup_directive_free(dir);
return 0;
}
Output:
Directive kind: 28
Clause count: 1
Note: Directive kind is an integer from the parser's internal registry. For practical use, you typically care more about the clauses than the exact directive kind. The kind value comes from the order in which directives were registered in
src/parser/openmp.rs
- these internal IDs are not part of the stable API and may change between versions.
Step 4: Iterate Through Clauses
To access individual clauses, use the iterator pattern:
#include <stdio.h>
#include "roup_ffi.h"
const char* clause_name(int32_t kind) {
switch(kind) {
case 0: return "num_threads";
case 1: return "if";
case 2: return "private";
case 3: return "shared";
case 6: return "reduction";
case 7: return "schedule";
case 10: return "nowait";
default: return "unknown";
}
}
int main(void) {
const char* input = "#pragma omp parallel num_threads(8) default(shared) nowait";
OmpDirective* dir = roup_parse(input);
if (!dir) return 1;
// Create iterator
OmpClauseIterator* iter = roup_directive_clauses_iter(dir);
if (!iter) {
roup_directive_free(dir);
return 1;
}
// Iterate through clauses
printf("Clauses:\n");
OmpClause* clause;
while (roup_clause_iterator_next(iter, &clause)) {
int32_t kind = roup_clause_kind(clause);
printf(" - %s (kind=%d)\n", clause_name(kind), kind);
}
// Cleanup
roup_clause_iterator_free(iter);
roup_directive_free(dir);
return 0;
}
Output:
Clauses:
- num_threads (kind=0)
- default (kind=11)
- nowait (kind=10)
Key Points:
roup_clause_iterator_next()
returns1
if clause available,0
when done- Write the clause pointer to
out
parameter - Always free the iterator with
roup_clause_iterator_free()
Step 5: Query Clause-Specific Data
Different clause types have different data. Use type-specific query functions:
Schedule Clause
OmpClause* clause = /* ... get clause ... */;
if (roup_clause_kind(clause) == 7) { // SCHEDULE
int32_t sched = roup_clause_schedule_kind(clause);
const char* names[] = {"static", "dynamic", "guided", "auto", "runtime"};
printf("Schedule: %s\n", names[sched]);
}
Reduction Clause
if (roup_clause_kind(clause) == 6) { // REDUCTION
int32_t op = roup_clause_reduction_operator(clause);
const char* ops[] = {"+", "-", "*", "&", "|", "^", "&&", "||", "min", "max"};
printf("Reduction operator: %s\n", ops[op]);
}
Default Clause
if (roup_clause_kind(clause) == 11) { // DEFAULT
int32_t def = roup_clause_default_data_sharing(clause);
printf("Default: %s\n", def == 0 ? "shared" : "none");
}
Complete Example
#include <stdio.h>
#include "roup_ffi.h"
int main(void) {
const char* input = "#pragma omp parallel for schedule(static, 10) reduction(+:sum)";
OmpDirective* dir = roup_parse(input);
if (!dir) return 1;
OmpClauseIterator* iter = roup_directive_clauses_iter(dir);
if (!iter) {
roup_directive_free(dir);
return 1;
}
OmpClause* clause;
while (roup_clause_iterator_next(iter, &clause)) {
int32_t kind = roup_clause_kind(clause);
if (kind == 7) { // SCHEDULE
int32_t sched = roup_clause_schedule_kind(clause);
const char* names[] = {"static", "dynamic", "guided", "auto", "runtime"};
printf("Schedule: %s\n", names[sched]);
}
else if (kind == 6) { // REDUCTION
int32_t op = roup_clause_reduction_operator(clause);
const char* ops[] = {"+", "-", "*", "&", "|", "^", "&&", "||", "min", "max"};
printf("Reduction: %s\n", ops[op]);
}
}
roup_clause_iterator_free(iter);
roup_directive_free(dir);
return 0;
}
Output:
Schedule: static
Reduction: +
Step 6: Access Variable Lists
Clauses like private(x, y, z)
contain lists of variables:
#include <stdio.h>
#include "roup_ffi.h"
int main(void) {
const char* input = "#pragma omp parallel private(x, y, z) shared(a, b)";
OmpDirective* dir = roup_parse(input);
if (!dir) return 1;
OmpClauseIterator* iter = roup_directive_clauses_iter(dir);
if (!iter) {
roup_directive_free(dir);
return 1;
}
OmpClause* clause;
while (roup_clause_iterator_next(iter, &clause)) {
int32_t kind = roup_clause_kind(clause);
// Get variable list
OmpStringList* vars = roup_clause_variables(clause);
if (vars) {
int32_t len = roup_string_list_len(vars);
const char* kind_name = (kind == 2) ? "private" : "shared";
printf("%s variables: ", kind_name);
for (int32_t i = 0; i < len; i++) {
const char* var = roup_string_list_get(vars, i);
printf("%s%s", var, (i < len - 1) ? ", " : "");
}
printf("\n");
roup_string_list_free(vars);
}
}
roup_clause_iterator_free(iter);
roup_directive_free(dir);
return 0;
}
Output:
private variables: x, y, z
shared variables: a, b
Key Points:
roup_clause_variables()
returns aOmpStringList*
orNULL
- Use
roup_string_list_len()
to get the count - Use
roup_string_list_get(list, index)
to access individual strings - Always call
roup_string_list_free()
when done
Step 7: Error Handling
Robust error handling is crucial. The API returns NULL
on failure:
#include <stdio.h>
#include "roup_ffi.h"
int main(void) {
// Test 1: Invalid syntax
const char* invalid = "#pragma omp INVALID_DIRECTIVE";
OmpDirective* dir1 = roup_parse(invalid);
if (!dir1) {
printf("✓ Invalid syntax correctly rejected\n");
}
// Test 2: NULL input
OmpDirective* dir2 = roup_parse(NULL);
if (!dir2) {
printf("✓ NULL input correctly rejected\n");
}
// Test 3: Empty string
OmpDirective* dir3 = roup_parse("");
if (!dir3) {
printf("✓ Empty string correctly rejected\n");
}
// Test 4: Querying NULL
int32_t kind = roup_directive_kind(NULL);
printf("roup_directive_kind(NULL) = %d\n", kind); // Returns -1
return 0;
}
Error Handling Guidelines:
- Always check
roup_parse()
return value forNULL
- Check
roup_directive_clauses_iter()
forNULL
- Query functions return
-1
or safe defaults forNULL
inputs - Free resources even in error paths (if allocated)
Step 8: Complete Example
Here's a complete program that demonstrates all concepts:
#include <stdio.h>
#include <stdlib.h>
#include "roup_ffi.h"
void print_clause_details(OmpClause* clause) {
int32_t kind = roup_clause_kind(clause);
switch(kind) {
case 0:
printf(" - num_threads\n");
break;
case 2: {
printf(" - private(");
OmpStringList* vars = roup_clause_variables(clause);
if (vars) {
int32_t len = roup_string_list_len(vars);
for (int32_t i = 0; i < len; i++) {
printf("%s%s", roup_string_list_get(vars, i),
(i < len - 1) ? ", " : "");
}
roup_string_list_free(vars);
}
printf(")\n");
break;
}
case 6: {
printf(" - reduction(");
int32_t op = roup_clause_reduction_operator(clause);
const char* ops[] = {"+", "-", "*", "&", "|", "^", "&&", "||", "min", "max"};
if (op >= 0 && op < 10) {
printf("%s", ops[op]);
}
printf(":...)\n");
break;
}
case 7: {
printf(" - schedule(");
int32_t sched = roup_clause_schedule_kind(clause);
const char* names[] = {"static", "dynamic", "guided", "auto", "runtime"};
if (sched >= 0 && sched < 5) {
printf("%s", names[sched]);
}
printf(")\n");
break;
}
case 10:
printf(" - nowait\n");
break;
case 11:
printf(" - default(%s)\n",
roup_clause_default_data_sharing(clause) == 0 ? "shared" : "none");
break;
default:
printf(" - unknown (kind=%d)\n", kind);
break;
}
}
int main(void) {
const char* test_cases[] = {
"#pragma omp parallel",
"#pragma omp parallel for num_threads(4) private(i, j)",
"#pragma omp parallel for schedule(static, 100) reduction(+:sum)",
"#pragma omp task default(shared) nowait",
NULL
};
for (int i = 0; test_cases[i] != NULL; i++) {
printf("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
printf("Input: %s\n", test_cases[i]);
printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
OmpDirective* dir = roup_parse(test_cases[i]);
if (!dir) {
printf("❌ Parse failed!\n");
continue;
}
int32_t clause_count = roup_directive_clause_count(dir);
printf("Clauses: %d\n", clause_count);
if (clause_count > 0) {
OmpClauseIterator* iter = roup_directive_clauses_iter(dir);
if (iter) {
OmpClause* clause;
while (roup_clause_iterator_next(iter, &clause)) {
print_clause_details(clause);
}
roup_clause_iterator_free(iter);
}
}
roup_directive_free(dir);
}
printf("\n✅ All tests completed!\n\n");
return 0;
}
Clause Kind Reference
The C API supports 12 common clause types:
Kind | Clause | Has Variables | Has Specific Data |
---|---|---|---|
0 | num_threads | No | Value (int) |
1 | if | No | Condition (string) |
2 | private | Yes | Variable list |
3 | shared | Yes | Variable list |
4 | firstprivate | Yes | Variable list |
5 | lastprivate | Yes | Variable list |
6 | reduction | Yes | Operator + variables |
7 | schedule | No | Schedule kind + chunk |
8 | collapse | No | Depth (int) |
9 | ordered | No | - |
10 | nowait | No | - |
11 | default | No | Sharing kind |
999 | Unknown | - | - |
Schedule Kinds (for clause kind 7):
- 0 =
static
- 1 =
dynamic
- 2 =
guided
- 3 =
auto
- 4 =
runtime
Reduction Operators (for clause kind 6):
- 0 =
+
, 1 =-
, 2 =*
- 3 =
&
, 4 =|
, 5 =^
- 6 =
&&
, 7 =||
- 8 =
min
, 9 =max
Default Kinds (for clause kind 11):
- 0 =
shared
- 1 =
none
- 2 =
private
- 3 =
firstprivate
Memory Management Checklist
✅ DO:
- Call
roup_directive_free()
for every successfulroup_parse()
- Call
roup_clause_iterator_free()
for everyroup_directive_clauses_iter()
- Call
roup_string_list_free()
for everyroup_clause_variables()
- Check for
NULL
returns before using pointers
❌ DON'T:
- Call
roup_clause_free()
on clauses from iterators (owned by directive) - Access freed pointers (use-after-free)
- Forget to free in error paths
- Assume parse always succeeds
Performance Tips
- Reuse parsed directives - Don't reparse the same string repeatedly
- Minimize FFI crossings - Batch operations when possible
- Avoid unnecessary iteration - If you only need clause count, don't iterate
- Use local variables - Cache query results instead of calling repeatedly
Example (inefficient):
// BAD: Queries kind multiple times
for (int i = 0; i < count; i++) {
if (roup_clause_kind(clause) == 2) {
process_private(roup_clause_kind(clause));
}
}
Example (efficient):
// GOOD: Cache the kind
int32_t kind = roup_clause_kind(clause);
if (kind == 2) {
process_private(kind);
}
Next Steps
Now that you understand the C API basics:
- Build the example - Compile and run
examples/c/tutorial_basic.c
- Explore directives - See OpenMP Support for all 120+ directives
- Advanced usage - Check API Reference for complete function details
- C++ wrappers - Read C++ Tutorial for RAII wrappers
Full Example Code: examples/c/tutorial_basic.c
(433 lines with detailed comments)
Troubleshooting
Linker Errors
Problem: undefined reference to roup_parse
Solution: Link against the ROUP static library:
gcc ... -L target/release -lroup -lpthread -ldl -lm
Parse Always Returns NULL
Problem: All parses fail, even valid input
Solution:
- Check that the library was built correctly (
cargo build --release
) - Verify the input string is valid OpenMP syntax
- Ensure the string is null-terminated
- Try the examples first to verify the library works
Memory Leaks
Problem: Valgrind reports memory leaks
Solution:
- Ensure every
roup_parse()
has a matchingroup_directive_free()
- Ensure every
roup_directive_clauses_iter()
has a matchingroup_clause_iterator_free()
- Ensure every
roup_clause_variables()
has a matchingroup_string_list_free()
Segmentation Fault
Problem: Program crashes with segfault
Solution:
- Check for
NULL
before dereferencing pointers - Don't access freed pointers
- Don't call
roup_clause_free()
on clauses from iterators
Questions? Check the FAQ or open an issue on GitHub.
C++ Tutorial: Building a Real Application
This tutorial shows how to integrate ROUP into a real C++ application using modern C++17 features.
We'll build an OpenMP pragma analyzer - a tool that reads C/C++ source files, extracts OpenMP directives, and reports statistics.
What You'll Build
A command-line tool that:
- Reads source files line-by-line
- Detects OpenMP pragmas
- Parses them using ROUP
- Reports directive types and clause counts
- Provides summary statistics
Example output:
$ ./omp_analyzer mycode.c
Found 5 OpenMP directives:
Line 10: parallel (3 clauses)
Line 25: for (2 clauses)
Line 42: parallel for (4 clauses)
Line 68: task (1 clause)
Line 95: barrier (0 clauses)
Summary:
Total directives: 5
Total clauses: 10
Most common: parallel (2 occurrences)
Prerequisites
- C++ Compiler: clang++ or g++ with C++17 support
- ROUP Library: Built and installed (see below)
- System: Linux, macOS, or Windows with WSL
Building ROUP
git clone https://github.com/ouankou/roup.git
cd roup
cargo build --release
# Library is now at: target/release/libroup.so (Linux)
# or: target/release/libroup.dylib (macOS)
Step 1: Understanding the ROUP C API
ROUP exports a minimal C API with 16 functions. Here are the key ones for our tool:
Lifecycle Functions
// Parse an OpenMP directive string
OmpDirective* roup_parse(const char* input);
// Free the parsed directive
void roup_directive_free(OmpDirective* directive);
Query Functions
// Get directive type (0=parallel, 1=for, 4=task, etc.)
int32_t roup_directive_kind(const OmpDirective* directive);
// Get number of clauses
int32_t roup_directive_clause_count(const OmpDirective* directive);
// Create iterator for clauses
OmpClauseIterator* roup_directive_clauses_iter(const OmpDirective* directive);
// Get next clause (returns 1 if available, 0 if done)
int32_t roup_clause_iterator_next(OmpClauseIterator* iter, OmpClause** out);
// Get clause type (0=num_threads, 2=private, 6=reduction, etc.)
int32_t roup_clause_kind(const OmpClause* clause);
// Free iterator
void roup_clause_iterator_free(OmpClauseIterator* iter);
Step 2: Create RAII Wrappers (Modern C++)
Instead of manual memory management, let's use RAII (Resource Acquisition Is Initialization) to automatically clean up resources.
Create roup_wrapper.hpp
:
#pragma once
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include <optional>
// Forward declarations of opaque C types
struct OmpDirective;
struct OmpClause;
struct OmpClauseIterator;
// C API declarations
extern "C" {
OmpDirective* roup_parse(const char* input);
void roup_directive_free(OmpDirective* directive);
int32_t roup_directive_kind(const OmpDirective* directive);
int32_t roup_directive_clause_count(const OmpDirective* directive);
OmpClauseIterator* roup_directive_clauses_iter(const OmpDirective* directive);
int32_t roup_clause_iterator_next(OmpClauseIterator* iter, OmpClause** out);
void roup_clause_iterator_free(OmpClauseIterator* iter);
int32_t roup_clause_kind(const OmpClause* clause);
}
namespace roup {
// RAII wrapper for OmpDirective
class Directive {
private:
OmpDirective* ptr_;
public:
// Constructor: parse directive
explicit Directive(const std::string& input)
: ptr_(roup_parse(input.c_str())) {}
// Destructor: automatic cleanup
~Directive() {
if (ptr_) {
roup_directive_free(ptr_);
}
}
// Delete copy (move-only type)
Directive(const Directive&) = delete;
Directive& operator=(const Directive&) = delete;
// Move constructor
Directive(Directive&& other) noexcept : ptr_(other.ptr_) {
other.ptr_ = nullptr;
}
// Move assignment
Directive& operator=(Directive&& other) noexcept {
if (this != &other) {
if (ptr_) roup_directive_free(ptr_);
ptr_ = other.ptr_;
other.ptr_ = nullptr;
}
return *this;
}
// Check if parse succeeded
bool valid() const { return ptr_ != nullptr; }
explicit operator bool() const { return valid(); }
// Get directive kind
int32_t kind() const {
return ptr_ ? roup_directive_kind(ptr_) : -1;
}
// Get clause count
int32_t clause_count() const {
return ptr_ ? roup_directive_clause_count(ptr_) : 0;
}
// Get raw pointer (for advanced usage)
OmpDirective* get() const { return ptr_; }
};
// RAII wrapper for OmpClauseIterator
class ClauseIterator {
private:
OmpClauseIterator* iter_;
public:
explicit ClauseIterator(const Directive& directive)
: iter_(directive.valid() ? roup_directive_clauses_iter(directive.get()) : nullptr) {}
~ClauseIterator() {
if (iter_) {
roup_clause_iterator_free(iter_);
}
}
// Delete copy
ClauseIterator(const ClauseIterator&) = delete;
ClauseIterator& operator=(const ClauseIterator&) = delete;
// Get next clause kind (returns std::optional)
std::optional<int32_t> next() {
if (!iter_) return std::nullopt;
OmpClause* clause = nullptr;
if (roup_clause_iterator_next(iter_, &clause) == 1) {
return roup_clause_kind(clause);
// Note: Don't free clause - owned by directive
}
return std::nullopt;
}
};
// Helper: Convert directive kind to name
inline const char* directive_kind_name(int32_t kind) {
switch (kind) {
case 0: return "parallel";
case 1: return "for";
case 2: return "sections";
case 3: return "single";
case 4: return "task";
case 5: return "master";
case 6: return "critical";
case 7: return "barrier";
case 8: return "taskwait";
case 9: return "taskgroup";
case 10: return "atomic";
case 11: return "flush";
case 12: return "ordered";
case 13: return "target";
case 14: return "teams";
case 15: return "distribute";
case 16: return "metadirective";
default: return "unknown";
}
}
// Helper: Convert clause kind to name
inline const char* clause_kind_name(int32_t kind) {
switch (kind) {
case 0: return "num_threads";
case 1: return "if";
case 2: return "private";
case 3: return "shared";
case 4: return "firstprivate";
case 5: return "lastprivate";
case 6: return "reduction";
case 7: return "schedule";
case 8: return "collapse";
case 9: return "ordered";
case 10: return "nowait";
case 11: return "default";
default: return "unknown";
}
}
} // namespace roup
Key RAII benefits:
- ✅ Automatic cleanup - No need to call
_free()
functions - ✅ Exception safe - Resources freed even if exceptions thrown
- ✅ Move semantics - Efficient transfer of ownership
- ✅ Modern C++ - Uses
std::optional
, deleted copy constructors
Step 3: Build the Analyzer Tool
Create omp_analyzer.cpp
:
#include "roup_wrapper.hpp"
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
struct DirectiveInfo {
int line_number;
std::string directive_name;
int clause_count;
std::vector<std::string> clause_names;
};
class OMPAnalyzer {
private:
std::vector<DirectiveInfo> directives_;
std::map<std::string, int> directive_counts_;
public:
// Analyze a single line for OpenMP pragmas
void analyze_line(const std::string& line, int line_number) {
// Check if line contains OpenMP pragma
if (line.find("#pragma omp") == std::string::npos) {
return;
}
// Parse the directive
roup::Directive directive(line);
if (!directive) {
std::cerr << "Warning: Failed to parse line " << line_number
<< ": " << line << std::endl;
return;
}
// Extract directive info
DirectiveInfo info;
info.line_number = line_number;
info.directive_name = roup::directive_kind_name(directive.kind());
info.clause_count = directive.clause_count();
// Extract clause names
roup::ClauseIterator iter(directive);
while (auto clause_kind = iter.next()) {
info.clause_names.push_back(roup::clause_kind_name(*clause_kind));
}
directives_.push_back(info);
directive_counts_[info.directive_name]++;
}
// Analyze entire file
bool analyze_file(const std::string& filename) {
std::ifstream file(filename);
if (!file) {
std::cerr << "Error: Cannot open file: " << filename << std::endl;
return false;
}
std::string line;
int line_number = 0;
while (std::getline(file, line)) {
line_number++;
analyze_line(line, line_number);
}
return true;
}
// Print detailed report
void print_report() const {
if (directives_.empty()) {
std::cout << "No OpenMP directives found." << std::endl;
return;
}
std::cout << "\nFound " << directives_.size()
<< " OpenMP directive(s):\n" << std::endl;
for (const auto& info : directives_) {
std::cout << " Line " << info.line_number << ": "
<< info.directive_name << " ("
<< info.clause_count << " clause"
<< (info.clause_count != 1 ? "s" : "") << ")";
if (!info.clause_names.empty()) {
std::cout << " [";
for (size_t i = 0; i < info.clause_names.size(); ++i) {
if (i > 0) std::cout << ", ";
std::cout << info.clause_names[i];
}
std::cout << "]";
}
std::cout << std::endl;
}
print_summary();
}
// Print summary statistics
void print_summary() const {
int total_clauses = 0;
for (const auto& info : directives_) {
total_clauses += info.clause_count;
}
std::cout << "\nSummary:" << std::endl;
std::cout << " Total directives: " << directives_.size() << std::endl;
std::cout << " Total clauses: " << total_clauses << std::endl;
// Find most common directive
auto max_elem = std::max_element(
directive_counts_.begin(),
directive_counts_.end(),
[](const auto& a, const auto& b) { return a.second < b.second; }
);
if (max_elem != directive_counts_.end()) {
std::cout << " Most common: " << max_elem->first
<< " (" << max_elem->second << " occurrence"
<< (max_elem->second != 1 ? "s" : "") << ")" << std::endl;
}
// Print directive type breakdown
if (directive_counts_.size() > 1) {
std::cout << "\nDirective breakdown:" << std::endl;
for (const auto& [name, count] : directive_counts_) {
std::cout << " " << name << ": " << count << std::endl;
}
}
}
};
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <source-file>" << std::endl;
std::cerr << "Example: " << argv[0] << " mycode.c" << std::endl;
return 1;
}
OMPAnalyzer analyzer;
if (!analyzer.analyze_file(argv[1])) {
return 1;
}
analyzer.print_report();
return 0;
}
```text
---
## Step 4: Build and Run
### Compilation
```bash
# Build ROUP library first
cd roup
cargo build --release
# Build the analyzer
clang++ -std=c++17 omp_analyzer.cpp \
-L./target/release -lroup \
-Wl,-rpath,./target/release \
-o omp_analyzer
# Or with g++:
g++ -std=c++17 omp_analyzer.cpp \
-L./target/release -lroup \
-Wl,-rpath,./target/release \
-o omp_analyzer
Test with Sample File
Create test.c
:
#include <stdio.h>
int main() {
int n = 1000;
int sum = 0;
#pragma omp parallel for reduction(+:sum) num_threads(4)
for (int i = 0; i < n; i++) {
sum += i;
}
#pragma omp parallel
{
#pragma omp single
{
printf("Hello from thread\\n");
}
}
#pragma omp task depend(in: sum)
printf("Sum: %d\\n", sum);
#pragma omp barrier
return 0;
}
Run the Analyzer
$ ./omp_analyzer test.c
Found 5 OpenMP directive(s):
Line 7: for (3 clauses) [reduction, num_threads]
Line 11: parallel (0 clauses)
Line 13: single (0 clauses)
Line 19: task (1 clause) [depend]
Line 22: barrier (0 clauses)
Summary:
Total directives: 5
Total clauses: 4
Most common: parallel (1 occurrence)
Directive breakdown:
barrier: 1
for: 1
parallel: 1
single: 1
task: 1
Step 5: Advanced Features
5.1 Extract Variable Names from Clauses
Some clauses (like private
, shared
) contain variable lists. To access them:
// In C API (add to roup_wrapper.hpp):
extern "C" {
OmpStringList* roup_clause_variables(const OmpClause* clause);
int32_t roup_string_list_len(const OmpStringList* list);
const char* roup_string_list_get(const OmpStringList* list, int32_t index);
void roup_string_list_free(OmpStringList* list);
}
// RAII wrapper for string list
class StringList {
private:
OmpStringList* list_;
public:
explicit StringList(OmpStringList* list) : list_(list) {}
~StringList() {
if (list_) roup_string_list_free(list_);
}
int32_t size() const {
return list_ ? roup_string_list_len(list_) : 0;
}
std::string get(int32_t index) const {
if (!list_ || index >= size()) return "";
return roup_string_list_get(list_, index);
}
std::vector<std::string> to_vector() const {
std::vector<std::string> result;
for (int32_t i = 0; i < size(); ++i) {
result.push_back(get(i));
}
return result;
}
};
```text
### 5.2 Handle Parse Errors Gracefully
```cpp
std::optional<DirectiveInfo> parse_directive(const std::string& line) {
roup::Directive directive(line);
if (!directive) {
return std::nullopt; // Parse failed
}
DirectiveInfo info;
info.directive_name = roup::directive_kind_name(directive.kind());
info.clause_count = directive.clause_count();
return info;
}
5.3 Process Multiple Files
void analyze_project(const std::vector<std::string>& files) {
OMPAnalyzer combined;
for (const auto& file : files) {
OMPAnalyzer file_analyzer;
if (file_analyzer.analyze_file(file)) {
std::cout << "\n=== " << file << " ===" << std::endl;
file_analyzer.print_report();
}
}
}
Real-World Use Cases
1. OpenMP Linter
Check for common mistakes:
parallel for
withoutprivate
on loop variablereduction
with unsupported operators- Missing
nowait
opportunities
2. Code Modernization Tool
- Convert OpenMP 3.x → 5.x syntax
- Suggest modern alternatives (e.g.,
taskloop
instead of manual tasks)
3. Performance Analyzer
- Count parallelization opportunities
- Identify nested parallel regions (potential over-subscription)
- Find synchronization hotspots
4. IDE Integration
- Syntax highlighting for OpenMP pragmas
- Auto-completion for clause names
- Quick documentation lookup
Performance Considerations
ROUP is fast:
- Parsing a typical directive: ~1-5 microseconds
- Zero-copy design: Uses string slices, not allocations
- Suitable for real-time IDE integration
Benchmark (on typical code):
File size: 10,000 lines
OpenMP directives: 500
Total parse time: ~2.5 milliseconds
Throughput: ~200,000 directives/second
Troubleshooting
Issue: undefined reference to roup_parse
Solution: Make sure library path is correct:
clang++ ... -L./target/release -lroup -Wl,-rpath,./target/release
Issue: error while loading shared libraries: libroup.so
Solution: Set LD_LIBRARY_PATH
(Linux) or DYLD_LIBRARY_PATH
(macOS):
export LD_LIBRARY_PATH=./target/release:$LD_LIBRARY_PATH
Issue: Parse failures on valid pragmas
Cause: ROUP currently supports C/C++ syntax (#pragma omp
), not Fortran (!$omp
).
Solution: Ensure input starts with #pragma omp
.
Next Steps
- Explore the Rust API - See API Reference
- Check out more examples - GitHub repository
- Contribute - Report issues or submit PRs!
Complete Example Code
All code from this tutorial is available at:
examples/cpp/roup_wrapper.hpp
- RAII wrappersexamples/cpp/omp_analyzer.cpp
- Full analyzer tool
Clone and try:
git clone https://github.com/ouankou/roup.git
cd roup/examples/cpp
make # Builds all examples
./omp_analyzer ../../tests/data/sample.c
Happy parsing! 🚀
Fortran Tutorial
This tutorial demonstrates how to use ROUP to parse OpenMP directives in Fortran code.
🚧 Experimental Status
Fortran support in ROUP is currently experimental. Features may change as development progresses.
Introduction
ROUP supports parsing OpenMP directives from Fortran source code in both free-form and fixed-form formats. This enables Fortran developers to:
- Parse OpenMP directives from Fortran source
- Validate directive syntax
- Extract clause information
- Build tools for Fortran+OpenMP code analysis
Fortran Directive Formats
Free-Form (Modern Fortran)
Free-form Fortran uses the !$OMP
sentinel (case-insensitive):
!$OMP PARALLEL PRIVATE(A, B) NUM_THREADS(4)
!$OMP END PARALLEL
!$omp parallel do private(i) reduction(+:sum)
!$OMP END PARALLEL DO
Fixed-Form (Fortran 77)
Fixed-form Fortran uses !$OMP
or C$OMP
sentinels in columns 1-6:
C$OMP PARALLEL PRIVATE(X, Y)
!$OMP DO SCHEDULE(STATIC, 10)
C$OMP END DO
C$OMP END PARALLEL
Fortran-Specific Directives
ROUP supports Fortran-specific directive syntax, including the Fortran DO
construct which is equivalent to C/C++ FOR
:
DO Directive (Fortran)
!$OMP DO PRIVATE(I) SCHEDULE(STATIC)
do i = 1, n
! Loop body
end do
!$OMP END DO
PARALLEL DO (Fortran)
!$OMP PARALLEL DO PRIVATE(I) REDUCTION(+:SUM)
do i = 1, n
sum = sum + a(i)
end do
!$OMP END PARALLEL DO
Note: ROUP recognizes both Fortran syntax (DO
) and C syntax (FOR
) for compatibility:
!$OMP DO
→ Fortran-specific (preferred for Fortran code)!$OMP FOR
→ C/C++ syntax (also works in Fortran mode)!$OMP PARALLEL DO
→ Fortran-specific!$OMP PARALLEL FOR
→ C/C++ syntax (also works in Fortran mode)
Language Constants
ROUP provides language format constants for Fortran parsing:
#define ROUP_LANG_C 0 // C/C++ (#pragma omp)
#define ROUP_LANG_FORTRAN_FREE 1 // Fortran free-form (!$OMP)
#define ROUP_LANG_FORTRAN_FIXED 2 // Fortran fixed-form (!$OMP or C$OMP)
Using the Rust API
Parsing Fortran Directives
use roup::lexer::Language;
use roup::parser::openmp;
// Create parser with Fortran free-form support
let parser = openmp::parser().with_language(Language::FortranFree);
// Parse a Fortran OpenMP directive
let input = "!$OMP PARALLEL PRIVATE(A, B) NUM_THREADS(4)";
let (rest, directive) = parser.parse(input).expect("parsing should succeed");
println!("Directive: {}", directive.name);
println!("Clauses: {}", directive.clauses.len());
Supported Language Formats
use roup::lexer::Language;
// C/C++ format (default)
let c_parser = openmp::parser().with_language(Language::C);
// Fortran free-form
let fortran_free = openmp::parser().with_language(Language::FortranFree);
// Fortran fixed-form
let fortran_fixed = openmp::parser().with_language(Language::FortranFixed);
Using the C API from Fortran
Setting Up Fortran-C Interoperability
Create an interface module for ROUP C API:
module roup_interface
use iso_c_binding
implicit none
! Language constants
integer(c_int), parameter :: ROUP_LANG_FORTRAN_FREE = 1
integer(c_int), parameter :: ROUP_LANG_FORTRAN_FIXED = 2
interface
! Parse with language specification
function roup_parse_with_language(input, language) &
bind(C, name="roup_parse_with_language")
use iso_c_binding
type(c_ptr), value :: input
integer(c_int), value :: language
type(c_ptr) :: roup_parse_with_language
end function roup_parse_with_language
! Free directive
subroutine roup_directive_free(directive) &
bind(C, name="roup_directive_free")
use iso_c_binding
type(c_ptr), value :: directive
end subroutine roup_directive_free
! Get directive name
function roup_directive_name(directive) &
bind(C, name="roup_directive_name")
use iso_c_binding
type(c_ptr), value :: directive
type(c_ptr) :: roup_directive_name
end function roup_directive_name
! Get clause count
function roup_directive_clause_count(directive) &
bind(C, name="roup_directive_clause_count")
use iso_c_binding
type(c_ptr), value :: directive
integer(c_size_t) :: roup_directive_clause_count
end function roup_directive_clause_count
end interface
end module roup_interface
Parsing Fortran Directives from Fortran
program parse_example
use iso_c_binding
use roup_interface
implicit none
type(c_ptr) :: directive_ptr, name_ptr
character(len=100) :: input = "!$OMP PARALLEL PRIVATE(X)"
character(kind=c_char), dimension(:), allocatable :: c_input
integer :: i, n
! Convert Fortran string to C string
n = len_trim(input)
allocate(c_input(n+1))
do i = 1, n
c_input(i) = input(i:i)
end do
c_input(n+1) = c_null_char
! Parse directive
directive_ptr = roup_parse_with_language(c_loc(c_input), &
ROUP_LANG_FORTRAN_FREE)
if (c_associated(directive_ptr)) then
! Get directive information
name_ptr = roup_directive_name(directive_ptr)
! ... process name_ptr ...
! Clean up
call roup_directive_free(directive_ptr)
else
print *, "Parse error"
end if
deallocate(c_input)
end program parse_example
Case Insensitivity
Fortran is case-insensitive, and ROUP respects this:
! All of these are equivalent
!$OMP PARALLEL PRIVATE(X)
!$omp parallel private(x)
!$Omp Parallel Private(X)
ROUP normalizes Fortran identifiers to lowercase internally while preserving the original case in the parsed output.
Common Fortran OpenMP Constructs
Parallel Regions
!$OMP PARALLEL PRIVATE(TID) SHARED(N)
! Parallel code
!$OMP END PARALLEL
Work-Sharing Constructs
In Fortran, use DO
instead of C's for
:
!$OMP DO PRIVATE(I) SCHEDULE(STATIC, 10)
do i = 1, n
! Loop body
end do
!$OMP END DO
Or combined:
!$OMP PARALLEL DO PRIVATE(I,J) REDUCTION(+:SUM)
do i = 1, n
sum = sum + array(i)
end do
!$OMP END PARALLEL DO
Array Sections
Fortran array sections use different syntax than C:
!$OMP PARALLEL PRIVATE(A(1:N), B(:,1:M))
! Work with array sections
!$OMP END PARALLEL
Common Blocks
Fortran's THREADPRIVATE
can apply to common blocks:
COMMON /MYDATA/ X, Y, Z
!$OMP THREADPRIVATE(/MYDATA/)
Examples
See the examples/fortran/
directory for complete working examples:
- basic_parse.f90: Simple Fortran directive examples
- tutorial_basic.f90: Full C API integration tutorial
Building Fortran Programs with ROUP
Using gfortran
# Compile Fortran code
gfortran -c my_program.f90
# Link with ROUP library
gcc my_program.o -L/path/to/roup/target/release -lroup -o my_program
# Run (set LD_LIBRARY_PATH)
LD_LIBRARY_PATH=/path/to/roup/target/release ./my_program
Makefile Example
FC = gfortran
ROUP_LIB = -L../../target/release -lroup -Wl,-rpath,../../target/release
my_program: my_program.f90
$(FC) -o $@ $< $(ROUP_LIB)
Known Limitations
⚠️ Current limitations in experimental Fortran support:
-
Continuation Syntax Requirements: Multi-line directives must use standard continuation markers
- Fortran: Terminate continued lines with
&
and optionally repeat the sentinel on the next line - C/C++: Place a trailing
\
at the end of each continued line - See Line Continuations for canonical examples across languages
- Fortran: Terminate continued lines with
-
End Directives:
!$OMP END PARALLEL
and similar end directives may not parse correctly -
Array Sections: Complex array section syntax may have issues
-
Fixed-Form Column Rules: Strict column 1-6 sentinel placement not enforced
-
Fortran-Specific Directives: Some Fortran-only directives (e.g.,
WORKSHARE
) may not be registered
Troubleshooting
Parse Errors
If parsing fails:
- Check sentinel format: Use
!$OMP
for free-form or!$OMP
/C$OMP
for fixed-form - Verify case: While case-insensitive, ensure proper formatting
- Check whitespace: Ensure proper spacing after sentinel
- Use correct language mode: Specify
ROUP_LANG_FORTRAN_FREE
orROUP_LANG_FORTRAN_FIXED
Directive Not Found
Some directives may not be in the registry. Check:
- Is the directive name correct? (Fortran supports both
DO
andFOR
syntax) - Is it a composite directive? (Use
PARALLEL DO
notPARALLEL
+DO
)
API Reference
See:
- C Tutorial - C API documentation
- API Reference - Complete API listing
- Architecture - Parser internals
Contributing
Fortran support is under active development. Contributions welcome:
- Test with real Fortran+OpenMP code
- Report parsing issues
- Add more Fortran-specific test cases
- Improve documentation
Further Reading
- OpenMP 5.2 Specification - Official OpenMP standard
- Fortran OpenMP Documentation - GCC Fortran OpenMP guide
- ISO C Binding - Fortran-C interop guide
ompparser Compatibility Layer
⚠️ Experimental Feature - This compatibility layer is under active development.
ROUP provides a drop-in compatibility layer for projects using ompparser, allowing you to switch to ROUP's expected-to-be faster, safer Rust-based parser without changing your code.
What is it?
A compatibility layer that provides:
- Same API as ompparser - no code changes needed
- Drop-in replacement via
libompparser.so
- ROUP backend - expected-to-be faster, safer parsing in Rust
- Reuses ompparser methods - toString(), generateDOT(), etc. (zero duplication)
Quick Start
One-Command Build
cd compat/ompparser
./build.sh
The script will:
- Check prerequisites (git, cmake, gcc, cargo)
- Initialize ompparser submodule
- Build ROUP core library
- Build
libompparser.so
(size varies by build configuration) - Run all 46 tests
Manual Build
# 1. Initialize ompparser submodule
git submodule update --init --recursive
# 2. Build ROUP core
cd /path/to/roup
cargo build --release
# 3. Build compatibility layer
cd compat/ompparser
mkdir -p build && cd build
cmake ..
make
# 4. Run tests
ctest --output-on-failure
Usage
Drop-in Replacement
Install system-wide and use exactly like original ompparser:
# Install
cd compat/ompparser/build
sudo make install
sudo ldconfig
# Use (unchanged!)
g++ mycompiler.cpp -lompparser -o mycompiler
Code Example
Your existing ompparser code works without changes:
#include <OpenMPIR.h>
#include <iostream>
int main() {
// Parse OpenMP directive
OpenMPDirective* dir = parseOpenMP("omp parallel num_threads(4)", nullptr);
if (dir) {
// Use ompparser methods (all work!)
std::cout << "Kind: " << dir->getKind() << std::endl;
std::cout << "String: " << dir->toString() << std::endl;
// Access clauses
auto* clauses = dir->getAllClauses();
std::cout << "Clauses: " << clauses->size() << std::endl;
delete dir;
}
return 0;
}
CMake Integration
Option 1: pkg-config
find_package(PkgConfig REQUIRED)
pkg_check_modules(OMPPARSER REQUIRED ompparser)
target_link_libraries(your_app ${OMPPARSER_LIBRARIES})
target_include_directories(your_app PRIVATE ${OMPPARSER_INCLUDE_DIRS})
Option 2: Direct linking
target_link_libraries(your_app
${PATH_TO_ROUP}/compat/ompparser/build/libompparser.so
)
What's Included
libompparser.so
Single self-contained library with:
- ROUP parser (statically embedded) - Rust-based, safe parsing
- ompparser methods - toString, generateDOT, etc.
- Compatibility wrapper - Seamless integration layer
- Self-contained - No libroup.so dependency (system libs via libc)
Comprehensive Testing
46 tests covering:
- Basic directives: parallel, for, sections, single, task, barrier, taskwait, critical, master
- Clauses: num_threads, private, shared, reduction, schedule, if, nowait, etc.
- String generation: toString(), generatePragmaString()
- Error handling: null input, invalid directives, malformed pragmas
- Memory management: allocations, deletion, reuse
- Language modes: C, C++, Fortran via setLang()
Run tests:
cd compat/ompparser/build
ctest --output-on-failure
Architecture
Your Application (OpenMP directives to parse)
↓
compat_impl.cpp (~190 lines) - Minimal wrapper
↓
ROUP C API (roup_parse, roup_directive_kind, etc.)
↓
ROUP Rust Parser (safe parser core)
↓
Returns: OpenMPDirective with ompparser methods
Key Design:
- Reuses 90% of ompparser code (no duplication)
- Git submodule approach - automatic ompparser upgrades
- Minimal unsafe code (~60 lines, 0.9%), all at FFI boundary
Known Limitations
1. Combined Directives ⚠️
Combined directives like parallel for
are currently parsed as the first directive only.
Example:
parseOpenMP("omp parallel for", nullptr)
// Returns: OMPD_parallel (should be OMPD_parallel_for)
Status: ROUP core limitation, tracked for future improvement.
Workaround: Tests document expected behavior with clear warnings.
2. Clause Parameters 🔄
Basic clause detection works, but parameter extraction not yet implemented.
Example:
parseOpenMP("omp parallel num_threads(4)", nullptr)
// Detects: num_threads clause ✅
// Extracts "4": ❌ (TODO)
Status: Planned wrapper enhancement using ROUP's clause expression API.
Documentation
Complete documentation in compat/ompparser/
:
- README.md - Complete compatibility layer guide with build instructions and examples
For detailed ROUP API documentation, see API Reference.
Requirements
- Rust toolchain (for ROUP core)
- CMake 3.10+
- C++11 compiler (gcc/clang)
- Git (for submodule management)
CI/CD
The compatibility layer is tested automatically via GitHub Actions (.github/workflows/build.yml
):
- Tests ROUP core (always)
- Tests compat layer (if submodule initialized)
- Verifies library builds successfully
- Validates drop-in functionality
- Checks constants synchronization (checksum validation)
FAQ
Q: Do I need to change my code?
A: No! It's a drop-in replacement with the same API.
Q: What if I don't need compat layer?
A: ROUP works perfectly standalone. The compat layer is optional.
Q: How do I get ompparser upgrades?
A: git submodule update --remote
pulls latest ompparser automatically.
Q: What about performance?
A: ROUP is expected to be faster than original ompparser due to Rust optimizations.
Q: Is it stable?
A: ⚠️ Experimental stage - thoroughly tested (46 tests) but under active development.
Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: See Contributing Guide
API Reference
ROUP provides comprehensive APIs for Rust, C, and C++.
Rust API Documentation
The complete Rust API documentation is auto-generated from the source code using rustdoc
.
Key Modules
-
roup::parser
- Main parsing functionsparse()
- Parse OpenMP directive from stringparse_with_config()
- Parse with custom configuration
-
roup::ir::directive
- Directive types and structuresDirectiveIR
- Main directive structureDirectiveKind
- Enum of directive types
-
roup::ir::clause
- Clause types and dataClause
- Clause structureClauseKind
- Enum of clause typesScheduleKind
,ReductionOperator
, etc.
-
roup::ir::types
- Common typesLanguage
- Source language (C, C++, Fortran)SourceLocation
- Position in source code
Quick Links
C API Reference
ROUP exports 16 C functions for FFI integration, providing a minimal C API with unsafe pointer operations only at the FFI boundary. All functions use direct C pointers (*mut OmpDirective
, *mut OmpClause
) following a standard malloc/free pattern.
Source: src/c_api.rs
(~60 lines of unsafe code at FFI boundary, ~0.9% of file)
Lifecycle Functions
// Parse OpenMP directive from C string
OmpDirective* roup_parse(const char* input);
// Free directive (required after parsing)
void roup_directive_free(OmpDirective* directive);
// Free clause (usually not needed - owned by directive)
void roup_clause_free(OmpClause* clause);
Directive Query Functions
// Get directive kind (0=parallel, 1=for, etc.)
int32_t roup_directive_kind(const OmpDirective* directive);
// Get number of clauses
int32_t roup_directive_clause_count(const OmpDirective* directive);
// Create clause iterator
OmpClauseIterator* roup_directive_clauses_iter(const OmpDirective* directive);
Iterator Functions
// Get next clause from iterator
// Returns 1 if clause available, 0 if done
int32_t roup_clause_iterator_next(OmpClauseIterator* iter, OmpClause** out);
// Free iterator
void roup_clause_iterator_free(OmpClauseIterator* iter);
Clause Query Functions
// Get clause kind (0=num_threads, 2=private, etc.)
int32_t roup_clause_kind(const OmpClause* clause);
// Get schedule kind (0=static, 1=dynamic, etc.)
int32_t roup_clause_schedule_kind(const OmpClause* clause);
// Get reduction operator (0=+, 1=-, 2=*, etc.)
int32_t roup_clause_reduction_operator(const OmpClause* clause);
// Get default data sharing (0=shared, 1=none)
int32_t roup_clause_default_data_sharing(const OmpClause* clause);
Variable List Functions
// Get variable list from clause (e.g., private(x, y, z))
OmpStringList* roup_clause_variables(const OmpClause* clause);
// Get length of string list
int32_t roup_string_list_len(const OmpStringList* list);
// Get string at index
const char* roup_string_list_get(const OmpStringList* list, int32_t index);
// Free string list
void roup_string_list_free(OmpStringList* list);
Mapping Tables
Important: These values are defined in
src/c_api.rs
. The C API uses a simple subset of OpenMP clauses with straightforward integer mapping.
Directive Kinds
The C API provides roup_directive_kind()
which returns an integer representing the directive type. The specific mapping depends on the parser's internal directive registry.
Common directive types (from parser):
- Parallel constructs:
parallel
,parallel for
,parallel sections
- Work-sharing:
for
,sections
,single
,workshare
- Tasking:
task
,taskloop
,taskgroup
,taskwait
- Device:
target
,target data
,target update
,teams
- Synchronization:
barrier
,critical
,atomic
,ordered
- SIMD:
simd
,declare simd
,distribute
- Advanced:
metadirective
,declare variant
,assume
For a complete list of all 120+ supported directives with version compatibility, see the OpenMP Support Matrix.
Clause Kinds (Integer Discriminants)
The C API supports 12 common clause types with simple integer mapping:
Value | Clause | Description | Example |
---|---|---|---|
0 | num_threads | Thread count | num_threads(4) |
1 | if | Conditional | if(condition) |
2 | private | Private variables | private(x, y) |
3 | shared | Shared variables | shared(a, b) |
4 | firstprivate | Private with init | firstprivate(z) |
5 | lastprivate | Private with final value | lastprivate(result) |
6 | reduction | Reduction operation | reduction(+:sum) |
7 | schedule | Loop scheduling | schedule(static, 100) |
8 | collapse | Loop nesting | collapse(2) |
9 | ordered | Ordered execution | ordered |
10 | nowait | Remove barrier | nowait |
11 | default | Default sharing | default(shared) |
999 | Unknown | Unrecognized clause | - |
Note: The C API intentionally supports a focused subset of clauses for simplicity. The Rust API supports all 92+ OpenMP 6.0 clauses.
Schedule Kinds
Value | Schedule |
---|---|
0 | static |
1 | dynamic |
2 | guided |
3 | auto |
4 | runtime |
Default Kinds (DefaultKind enum)
Value | Default |
---|---|
0 | shared |
1 | none |
2 | private |
3 | firstprivate |
Reduction Operators (ReductionOperator enum)
Value | Operator |
---|---|
0 | + (add) |
1 | * (multiply) |
2 | - (subtract) |
3 | & (bitwise AND) |
4 | ` |
5 | ^ (bitwise XOR) |
6 | && (logical AND) |
7 | ` |
8 | min (minimum) |
9 | max (maximum) |
10 | custom (user-defined) |
C++ RAII Wrappers
For modern C++17 applications, use the RAII wrappers provided in the C++ Tutorial.
Key classes:
roup::Directive
- Auto-frees directive on destructionroup::ClauseIterator
- Auto-frees iterator on destructionroup::StringList
- Auto-frees string list on destruction
Example:
#include "roup_wrapper.hpp"
roup::Directive dir("#pragma omp parallel for num_threads(4)");
if (dir) {
std::cout << "Kind: " << dir.kind() << std::endl;
std::cout << "Clauses: " << dir.clause_count() << std::endl;
}
// Automatic cleanup when dir goes out of scope
Memory Management Rules
Rust API
- Automatic - Rust's ownership system handles everything
- No manual
free()
needed
C API
- Manual - Must call
_free()
functions - Directive: Call
roup_directive_free()
when done - Iterator: Call
roup_clause_iterator_free()
when done - String List: Call
roup_string_list_free()
when done - Clauses: Do NOT free - owned by directive
C++ RAII API
- Automatic - RAII wrappers call
_free()
in destructors - Exception-safe - cleanup happens even with exceptions
Error Handling
Rust
use roup::parser::openmp;
let parser = openmp::parser();
match parser.parse(input) {
Ok((_, directive)) => { /* use directive */ },
Err(e) => eprintln!("Parse error: {:?}", e),
}
C
OmpDirective* dir = roup_parse(input);
if (dir == NULL) {
fprintf(stderr, "Parse failed\n");
return 1;
}
// Use dir...
roup_directive_free(dir);
C++
roup::Directive dir(input);
if (!dir) {
std::cerr << "Parse failed\n";
return 1;
}
// Use dir...
Thread Safety
- ✅ Parsing is thread-safe - Multiple threads can call
parse()
simultaneously - ✅ Read operations are thread-safe - Query functions are read-only
- ⚠️ Modification is not thread-safe - Don't mutate same directive from multiple threads
- ⚠️ Iterators are single-threaded - One iterator per thread
Performance Tips
- Reuse parsed directives when possible
- Avoid reparsing the same string repeatedly
- Use iterators instead of random access
- Batch operations to minimize FFI overhead (C/C++)
- Profile first - parsing is usually not the bottleneck
Further Reading
- Rust API Documentation - Complete rustdoc
- C++ Tutorial - Real-world C++ examples
- GitHub Repository - Source code and examples
- Quick Start Guide - Get started in 5 minutes
OpenMP Support
ROUP provides comprehensive support for OpenMP 6.0 directives and clauses for C/C++ and Fortran.
Quick Summary
Feature | Support |
---|---|
OpenMP Version | 3.0 - 6.0 |
Directives | 95 directives (core + combined forms) |
Clauses | 91 clauses |
Languages | C, C++, Fortran |
Test Coverage | 355 automated tests |
Specification | OpenMP 6.0 PDF |
ROUP supports the vast majority of OpenMP 3.0-6.0 directives and clauses. ✅
Directive Support
Core Parallelism (15 directives)
Directive | Example | Notes |
---|---|---|
parallel | #pragma omp parallel | Basic parallel region |
for | #pragma omp for | Work-sharing loop |
sections | #pragma omp sections | Work-sharing sections |
section | #pragma omp section | Individual section |
single | #pragma omp single | Single-thread execution |
master | #pragma omp master | Master thread only |
masked | #pragma omp masked | Masked execution (OpenMP 5.1+) |
barrier | #pragma omp barrier | Synchronization barrier |
critical | #pragma omp critical | Critical section |
atomic | #pragma omp atomic | Atomic operation |
flush | #pragma omp flush | Memory fence |
ordered | #pragma omp ordered | Ordered execution |
simd | #pragma omp simd | SIMD vectorization |
loop | #pragma omp loop | Generic loop (OpenMP 5.0+) |
scope | #pragma omp scope | Scoped region (OpenMP 5.1+) |
Tasking (10 directives)
Directive | Example | Notes |
---|---|---|
task | #pragma omp task | Explicit task |
taskwait | #pragma omp taskwait | Wait for child tasks |
taskyield | #pragma omp taskyield | Yield to other tasks |
taskgroup | #pragma omp taskgroup | Task group |
taskloop | #pragma omp taskloop | Task-generating loop |
taskloop simd | #pragma omp taskloop simd | SIMD taskloop |
taskgraph | #pragma omp taskgraph | Task graph (OpenMP 6.0) |
cancel | #pragma omp cancel | Cancel construct |
cancellation point | #pragma omp cancellation point | Cancellation check |
depobj | #pragma omp depobj | Dependency object |
Device Offloading (12 directives)
Directive | Example | Notes |
---|---|---|
target | #pragma omp target | Offload to device |
target data | #pragma omp target data | Data environment |
target enter data | #pragma omp target enter data | Map to device |
target exit data | #pragma omp target exit data | Unmap from device |
target update | #pragma omp target update | Update data |
teams | #pragma omp teams | Team of threads |
distribute | #pragma omp distribute | Distribute iterations |
declare target | #pragma omp declare target | Device function |
begin declare target | #pragma omp begin declare target | Begin target block |
end declare target | #pragma omp end declare target | End target block |
interop | #pragma omp interop | Interoperability (OpenMP 5.1+) |
dispatch | #pragma omp dispatch | Dynamic dispatch (OpenMP 5.1+) |
Combined Directives (60+ forms)
ROUP supports all standard combined directives:
Parallel + Worksharing:
parallel for
parallel for simd
parallel loop
parallel sections
parallel master
parallel masked
Target + Parallel:
target parallel
target parallel for
target parallel for simd
target parallel loop
target teams
target teams distribute
target teams distribute parallel for
target teams distribute parallel for simd
Teams + Distribute:
teams distribute
teams distribute simd
teams distribute parallel for
teams distribute parallel for simd
teams loop
And many more... (all 120+ combinations from OpenMP 6.0)
Meta-directives & Variants (5 directives)
Directive | Example | Notes |
---|---|---|
metadirective | #pragma omp metadirective when(...) | Conditional directive selection |
declare variant | #pragma omp declare variant(...) | Function variants |
declare simd | #pragma omp declare simd | SIMD function |
declare reduction | #pragma omp declare reduction | Custom reduction |
declare mapper | #pragma omp declare mapper | Custom mapper |
Utility Directives (6 directives)
Directive | Example | Notes |
---|---|---|
threadprivate | #pragma omp threadprivate(var) | Thread-private data |
assume | #pragma omp assume | Compiler hints (OpenMP 5.1+) |
nothing | #pragma omp nothing | No-op directive |
error | #pragma omp error | Compilation error |
requires | #pragma omp requires | Implementation requirements |
allocate | #pragma omp allocate | Memory allocation |
Clause Support (92 clauses)
Data-Sharing Clauses (8)
Clause | Example | Description |
---|---|---|
private | private(x, y) | Private variables |
shared | shared(a, b) | Shared variables |
firstprivate | firstprivate(z) | Private with initialization |
lastprivate | lastprivate(result) | Private with final value |
reduction | reduction(+:sum) | Reduction operation |
in_reduction | in_reduction(+:total) | Participating reduction |
task_reduction | task_reduction(*:product) | Task reduction |
copyin | copyin(global_var) | Copy to private |
Control Clauses (15)
Clause | Example | Description |
---|---|---|
if | if(condition) | Conditional execution |
num_threads | num_threads(8) | Thread count |
default | default(shared) | Default data-sharing |
schedule | schedule(static, 100) | Loop scheduling |
collapse | collapse(2) | Nest loop collapsing |
ordered | ordered | Ordered execution |
nowait | nowait | Remove implicit barrier |
final | final(expr) | Final task |
untied | untied | Untied task |
mergeable | mergeable | Mergeable task |
priority | priority(10) | Task priority |
grainsize | grainsize(1000) | Taskloop grainsize |
num_tasks | num_tasks(100) | Taskloop task count |
nogroup | nogroup | No taskgroup |
filter | filter(thread_num) | Masked filter |
Device Clauses (15)
Clause | Example | Description |
---|---|---|
device | device(gpu_id) | Target device |
map | map(to: input) | Data mapping |
to | to(data) | Map to device |
from | from(results) | Map from device |
defaultmap | defaultmap(tofrom:scalar) | Default mapping |
is_device_ptr | is_device_ptr(ptr) | Device pointer |
use_device_ptr | use_device_ptr(ptr) | Use device pointer |
use_device_addr | use_device_addr(var) | Use device address |
device_resident | device_resident(var) | Device-resident data |
num_teams | num_teams(16) | Number of teams |
thread_limit | thread_limit(256) | Threads per team |
dist_schedule | dist_schedule(static) | Distribution schedule |
interop | interop(...) | Interoperability |
device_type | device_type(gpu) | Device type selector |
init | init(...) | Initialize interop |
SIMD Clauses (8)
Clause | Example | Description |
---|---|---|
simdlen | simdlen(8) | SIMD lane count |
safelen | safelen(16) | Safe iteration count |
aligned | aligned(ptr:32) | Alignment |
linear | linear(i:1) | Linear variable |
uniform | uniform(step) | Uniform across lanes |
nontemporal | nontemporal(a, b) | Non-temporal access |
inbranch | inbranch | In-branch SIMD |
notinbranch | notinbranch | Not-in-branch SIMD |
Synchronization & Memory (12)
Clause | Example | Description |
---|---|---|
depend | depend(in: x) | Task dependencies |
doacross | doacross(source:) | Cross-iteration dependencies |
detach | detach(event) | Detachable task |
atomic_default_mem_order | atomic_default_mem_order(seq_cst) | Default memory order |
seq_cst | seq_cst | Sequential consistency |
acq_rel | acq_rel | Acquire-release |
acquire | acquire | Acquire |
release | release | Release |
relaxed | relaxed | Relaxed |
compare | compare | Compare atomic |
fail | fail(relaxed) | Failure memory order |
weak | weak | Weak compare |
Metadirective & Variant Clauses (5)
Clause | Example | Description |
---|---|---|
when | when(device:{kind(gpu)}) | Condition selector |
match | match(construct={...}) | Trait matching |
novariants | novariants | No variants |
holds | holds(...) | Assumption holds |
bind | bind(thread) | Binding |
Miscellaneous Clauses (29)
Clause | Example | Description |
---|---|---|
allocate | allocate(allocator:ptr) | Memory allocator |
allocator | allocator(omp_default_mem_alloc) | Allocator |
uses_allocators | uses_allocators(...) | Allocator list |
affinity | affinity(...) | Thread affinity |
proc_bind | proc_bind(close) | Processor binding |
order | order(concurrent) | Loop iteration order |
partial | partial(4) | Partial unroll |
sizes | sizes(8, 16) | Tile sizes |
tile | tile(...) | Loop tiling |
unroll | unroll(4) | Loop unrolling |
label | label(...) | Dispatch label |
message | message("error text") | Error message |
copyprivate | copyprivate(x) | Copy-private |
link | link(...) | Declare target link |
capture | capture | Atomic capture |
update | update | Atomic update |
hint | hint(...) | Performance hint |
destroy | destroy | Destroy clause |
reverse | reverse | Reverse dependencies |
inclusive | inclusive(...) | Inclusive scan |
exclusive | exclusive(...) | Exclusive scan |
unified_address | unified_address | Requires clause |
unified_shared_memory | unified_shared_memory | Requires clause |
dynamic_allocators | dynamic_allocators | Requires clause |
reproducible | reproducible | Order modifier |
no_openmp | no_openmp | Variant selector |
no_openmp_routines | no_openmp_routines | Variant selector |
no_parallelism | no_parallelism | Variant selector |
public | public | Declare mapper |
Version Compatibility
OpenMP Version | ROUP Support | Key Features |
---|---|---|
6.0 (2024) | ✅ Full | taskgraph , dispatch , new loop constructs |
5.2 (2021) | ✅ Full | scope , masked , device extensions |
5.1 (2020) | ✅ Full | assume , nothing , metadirective enhancements |
5.0 (2018) | ✅ Full | loop , requires , memory allocators |
4.5 (2015) | ✅ Full | Task dependencies, device constructs |
4.0 (2013) | ✅ Full | Tasking, SIMD, device offloading |
ROUP tracks the latest OpenMP specification and is updated with each new release.
Language Support
C/C++ Syntax
#pragma omp parallel for num_threads(4) schedule(static)
for (int i = 0; i < n; i++) {
process(i);
}
✅ Supported: All C/C++ #pragma omp
directives
Fortran Syntax
!$omp parallel do schedule(dynamic)
do i = 1, n
call process(i)
end do
!$omp end parallel do
✅ Supported: Free-form (!$omp
), Fixed-form (c$omp
, *$omp
)
✅ Case insensitive: !$OMP
, !$Omp
, !$omp
all work
Test Coverage
ROUP includes comprehensive automated testing:
Test Suite | Count | Coverage |
---|---|---|
Integration tests | 116 | Directive parsing, clause combinations |
Doc tests | 239 | API examples, edge cases |
Total | 355 | All directives + clauses tested |
Every directive and clause in OpenMP 6.0 has a passing test. ✅
See tests/
directory for the full test suite.
Unsupported Features
ROUP focuses on directive parsing, not runtime semantics. The following are out of scope:
❌ Runtime execution - ROUP parses directives, doesn't execute them
❌ Code transformation - No AST rewriting or code generation
❌ Semantic validation - Doesn't check if directives make logical sense
❌ Context analysis - Doesn't validate directive placement in code
Use ROUP for:
- ✅ Static analysis tools
- ✅ Code documentation generators
- ✅ IDE syntax highlighting
- ✅ Linting and code quality checks
- ✅ Migration tools
- ✅ Research prototypes
Don't use ROUP for:
- ❌ Compiling OpenMP to executables (use GCC/Clang)
- ❌ Runtime task scheduling (use OpenMP runtime)
- ❌ Performance profiling (use performance tools)
Implementation Status
Component | Status | Notes |
---|---|---|
Lexer | ✅ Complete | Handles C/C++/Fortran syntax |
Parser | ✅ Complete | nom-based combinator parser |
IR (Intermediate Representation) | ✅ Complete | Type-safe Rust AST |
C FFI | ✅ Complete | Pointer-based API (16 functions) |
Fortran support | ✅ Complete | All comment styles |
Error messages | ✅ Complete | Descriptive parse errors |
Round-trip | ✅ Complete | IR → String preservation |
Future Additions
Tracking future OpenMP specifications:
Version | Status | Expected Features |
---|---|---|
OpenMP 6.1 | 📋 Planned | TBD by OpenMP ARB |
OpenMP 7.0 | 📋 Future | TBD |
ROUP will be updated as new OpenMP versions are released.
References
- OpenMP 6.0 Specification - Official spec
- OpenMP.org - OpenMP Architecture Review Board
- ROUP GitHub - Source code and tests
Summary
ROUP provides OpenMP 3.0-6.0 parsing support:
- ✅ 95 directives (core, combined, and meta-directives)
- ✅ 91 clause types (data-sharing, control, device, SIMD, sync, etc.)
- ✅ C/C++/Fortran syntax support
- ✅ 352 automated tests (comprehensive directive/clause coverage)
- ✅ Type-safe Rust API + C FFI
- ✅ Latest spec (OpenMP 6.0, 2024)
⚠️ Experimental - for research, education, and prototype tooling. Not yet production-ready. 🧪
OpenMP 6.0 Directives and Clauses
This comprehensive reference catalogue documents all OpenMP 6.0 keywords from the OpenMP Application Programming Interface Version 6.0 specification.
Purpose
This document serves as a complete keyword inventory for development and reference. Each entry includes:
- Specification section and page numbers
- Categorization and properties
- No duplication - each keyword appears once
Coverage
- 66 Directives/Constructs - All executable, declarative, and meta directives
- 125 Clauses - All clause keywords
- Modifiers - Map-type, dependence-type, schedule, and other modifiers
- Keywords & Values - Memory orders, atomic operations, schedule types, allocators, and more
- Reduction Operators - All supported reduction operations
- Special Identifiers - Reserved locators, device identifiers, and constants
Directives and Constructs
allocate
(Section 8.5; pp. 341–342; category: declarative; association: explicit; properties: pure)allocators
(Section 8.7; category: executable; association: block : allocator; properties: default)assume
(Section 10.6.3; category: informational; association: block; properties: pure)assumes
(Section 10.6.2; p. 399; category: informational; association: unassociated; properties: pure)atomic
(Section 17.8.5; pp. 525–528; category: executable; association: block : atomic; properties: mutual-exclusion, order-concurrent-nestable, simdizable)barrier
(Section 17.3.1; pp. 506–508; category: executable; association: unassociated; properties: team-executed)begin assumes
(Section 10.6.4; p. 399; category: informational; association: delimited; properties: default)begin declare_target
(Section 9.9.2; p. 380; category: declarative; association: delimited; properties: declare-target, device, variant-generating)begin declare_variant
(Section 9.6.5; p. 367; category: declarative; association: delimited; properties: default)cancel
(Section 18.2; pp. 551–554; category: executable; association: unassociated; properties: default)cancellation_point
(Section 18.3; pp. 555–556; category: executable; association: unassociated; properties: default)critical
(Section 17.2; pp. 504–505; category: executable; association: block; properties: mutual-exclusion, thread-limiting, thread-exclusive)declare_induction
(Section 7.6.17; pp. 294–295; category: declarative; association: unassociated; properties: pure)declare_mapper
(Section 7.9.10; pp. 324–327; category: declarative; association: unassociated; properties: pure)declare_reduction
(Section 7.6.14; pp. 291–292; category: declarative; association: unassociated; properties: pure)declare_simd
(Section 9.8; pp. 372–373; category: declarative; association: declaration; properties: pure, variant-generating)declare_target
(Section 9.9.1; pp. 377–379; category: declarative; association: explicit; properties: declare-target, device, pure, variant-generating)declare_variant
(Section 9.6.4; pp. 365–366; category: declarative; association: declaration; properties: pure)depobj
(Section 17.9.3; p. 536; category: executable; association: unassociated; properties: default)dispatch
(Section 9.7; pp. 368–369; category: executable; association: block : function-dispatch; properties: context-matching)distribute
(Section 13.7; pp. 451–452; category: executable; association: loop nest; properties: SIMD-partitionable, teams-nestable, work-distribution, partitioned)do
(Section 13.6.2; p. 448; category: executable; association: loop nest; properties: work-distribution, team-executed, partitioned, SIMD-partitionable, worksharing, worksharing-loop, cancellable, context-matching)error
(Section 10.1; p. 383; category: utility; association: unassociated; properties: pure)flush
(Section 17.8.6; pp. 529–535; category: executable; association: unassociated; properties: default)for
(Section 13.6.1; p. 447; category: executable; association: loop nest; properties: work-distribution, team-executed, partitioned, SIMD-partitionable, worksharing, worksharing-loop, cancellable, context-matching)fuse
(Section 11.3; p. 405; category: executable; association: loop sequence; properties: loop-transforming, order-concurrent-nestable, pure, simdizable, teams-nestable)groupprivate
(Section 7.13; pp. 332–333; category: declarative; association: explicit; properties: pure)interchange
(Section 11.4; p. 406; category: executable; association: loop nest; properties: loop-transforming, nonrectangular-compatible, order-concurrent-nestable, pure, simdizable, teams-nestable)interop
(Section 16.1; p. 499; category: executable; association: unassociated; properties: device)loop
(Section 13.8; p. 454; category: executable; association: loop nest; properties: order-concurrent-nestable, partitioned, simdizable, team-executed, teams-nestable, work-distribution, worksharing)masked
(Section 12.5; p. 433; category: executable; association: block; properties: thread-limiting, thread-selecting)begin metadirective
(Section 9.4.4; p. 327; category: meta; association: delimited; properties: pure)metadirective
(Section 9.4.3; p. 327; category: meta; association: unassociated; properties: pure)nothing
(Section 10.7; pp. 400–402; category: utility; association: unassociated; properties: pure, loop-transforming)ordered
(Section 17.10.2; pp. 546–547; category: executable; association: block; properties: mutual-exclusion, simdizable, thread-limiting, thread-exclusive)parallel
(Section 12.1; pp. 415–418; category: executable; association: block; properties: cancellable, context-matching, order-concurrent-nestable, parallelism-generating, team-generating, teams-nestable, thread-limiting)requires
(Section 10.5; p. 386; category: informational; association: unassociated; properties: default)reverse
(Section 11.5; p. 407; category: executable; association: loop nest; properties: generally-composable, loop-transforming, order-concurrent-nestable, pure, simdizable, teams-nestable)scan
(Section 7.7; pp. 297–299; category: subsidiary; association: separating; properties: pure)scope
(Section 13.2; p. 437; category: executable; association: block; properties: work-distribution, team-executed, worksharing, thread-limiting)section
(Section 13.3.1; p. 439; category: subsidiary; association: separating; properties: default)sections
(Section 13.3; p. 438; category: executable; association: block; properties: work-distribution, team-executed, partitioned, worksharing, thread-limiting, cancellable)simd
(Section 12.4; p. 430; category: executable; association: loop nest; properties: context-matching, order-concurrent-nestable, parallelism-generating, pure, simdizable)single
(Section 13.1; p. 436; category: executable; association: block; properties: work-distribution, team-executed, partitioned, worksharing, thread-limiting, thread-selecting)split
(Section 11.6; p. 408; category: executable; association: loop nest; properties: generally-composable, loop-transforming, order-concurrent-nestable, pure, simdizable, teams-nestable)stripe
(Section 11.7; p. 410; category: executable; association: loop nest; properties: loop-transforming, order-concurrent-nestable, pure, simdizable, teams-nestable)target
(Section 15.8; pp. 491–495; category: executable; association: block; properties: parallelism-generating, team-generating, thread-limiting, exception-aborting, task-generating, device, device-affecting, data-mapping, map-entering, map-exiting, context-matching)target_data
(Section 15.7; pp. 489–490; category: executable; association: block; properties: device, device-affecting, data-mapping, map-entering, map-exiting, parallelism-generating, sharing-task, task-generating)target_enter_data
(Section 15.5; pp. 485–486; category: executable; association: unassociated; properties: parallelism-generating, task-generating, device, device-affecting, data-mapping, map-entering)target_exit_data
(Section 15.6; pp. 487–488; category: executable; association: unassociated; properties: parallelism-generating, task-generating, device, device-affecting, data-mapping, map-exiting)target_update
(Section 15.9; pp. 496–498; category: executable; association: unassociated; properties: parallelism-generating, task-generating, device, device-affecting)task
(Section 14.1; pp. 457–459; category: executable; association: block; properties: parallelism-generating, thread-limiting, task-generating)task_iteration
(Section 14.2.3; p. 465; category: subsidiary; association: unassociated; properties: default)taskgraph
(Section 14.3; pp. 466–468; category: executable; association: block; properties: default)taskgroup
(Section 17.4; p. 509; category: executable; association: block; properties: cancellable)taskloop
(Section 14.2; pp. 460–462; category: executable; association: loop nest; properties: parallelism-generating, SIMD-partitionable, task-generating)taskwait
(Section 17.5; pp. 510–511; category: executable; association: unassociated; properties: default)taskyield
(Section 14.12; pp. 477–480; category: executable; association: unassociated; properties: default)teams
(Section 12.2; pp. 425–427; category: executable; association: block; properties: parallelism-generating, team-generating, thread-limiting, context-matching)threadprivate
(Section 7.3; pp. 246–253; category: declarative; association: explicit; properties: pure)tile
(Section 11.8; p. 411; category: executable; association: loop nest; properties: loop-transforming, order-concurrent-nestable, pure, simdizable, teams-nestable)unroll
(Section 11.9; p. 412; category: executable; association: loop nest; properties: generally-composable, loop-transforming, order-concurrent-nestable, pure, simdizable, teams-nestable)workdistribute
(Section 13.5; pp. 443–446; category: executable; association: block; properties: work-distribution, partitioned)workshare
(Section 13.4; pp. 440–442; category: executable; association: block; properties: work-distribution, team-executed, partitioned, worksharing)
Clauses
absent
(Section 10.6.1.1; p. 394)acq_rel
(Section 17.8.1.1; p. 515)acquire
(Section 17.8.1.2; p. 516)adjust_args
(Section 9.6.2; pp. 362–363)affinity
(Section 14.10; p. 475)align
(Section 8.3; p. 340)aligned
(Section 7.12; p. 331)allocate
(Section 8.6; pp. 343–345)allocator
(Section 8.4; p. 340)append_args
(Section 9.6.3; p. 364)apply
(Section 11.1; pp. 403–404)at
(Section 10.2; p. 383)atomic_default_mem_order
(Section 10.5.1.1; p. 387)bind
(Section 13.8.1; pp. 455–456)capture
(Section 17.8.3.1; p. 521)collapse
(Section 6.4.5; p. 236)collector
(Section 7.6.19; p. 296)combiner
(Section 7.6.15; p. 292)compare
(Section 17.8.3.2; p. 522)contains
(Section 10.6.1.2; p. 394)copyin
(Section 7.8.1; p. 302)copyprivate
(Section 7.8.2; pp. 303–309)counts
(Section 11.6.1; p. 409)default
(Section 7.5.1; p. 254)defaultmap
(Section 7.9.9; pp. 322–323)depend
(Section 17.9.5; pp. 538–540)destroy
(Section 5.7; pp. 213–235)detach
(Section 14.11; p. 476)device
(Section 15.2; p. 482)device_safesync
(Section 10.5.1.7; p. 393; properties: required, unique Members:)device_type
(Section 15.1; p. 481)dist_schedule
(Section 13.7.1; p. 453)doacross
(Section 17.9.7; pp. 542–544)dynamic_allocators
(Section 10.5.1.2; p. 388)enter
(Section 7.9.7; p. 320)exclusive
(Section 7.7.2; p. 300)fail
(Section 17.8.3.3; p. 522)filter
(Section 12.5.1; pp. 434–435)final
(Section 14.7; p. 472)firstprivate
(Section 7.5.4; pp. 258–259)from
(Section 7.10.2; p. 329)full
(Section 11.9.1; p. 413)grainsize
(Section 14.2.1; p. 463)graph_id
(Section 14.3.1; p. 468)graph_reset
(Section 14.3.2; p. 469)has_device_addr
(Section 7.5.9; p. 268)hint
(Section 17.1; p. 503)holds
(Section 10.6.1.3; p. 395)if
(Section 5.5; p. 210)in_reduction
(Section 7.6.12; p. 287)inbranch
(Section 9.8.1.1; p. 374)inclusive
(Section 7.7.1; p. 299)indirect
(Section 9.9.3; pp. 381–382)induction
(Section 7.6.13; pp. 288–290)inductor
(Section 7.6.18; p. 296)init
(Section 5.6; pp. 211–212)init_complete
(Section 7.7.3; p. 301)initializer
(Section 7.6.16; p. 293)interop
(Section 9.7.1; p. 370)is_device_ptr
(Section 7.5.7; p. 266)lastprivate
(Section 7.5.5; pp. 260–262)linear
(Section 7.5.6; pp. 263–265)link
(Section 7.9.8; p. 321)local
(Section 7.14; pp. 334–339)looprange
(Section 6.4.7; pp. 238–245)map
(Section 7.9.6; pp. 310–319)match
(Section 9.6.1; p. 361)memscope
(Section 17.8.4; p. 524)mergeable
(Section 14.5; p. 470)message
(Section 10.3; p. 384)no_openmp
(Section 10.6.1.4; p. 396)no_openmp_constructs
(Section 10.6.1.5; p. 396)no_openmp_routines
(Section 10.6.1.6; p. 397)no_parallelism
(Section 10.6.1.7; p. 398)nocontext
(Section 9.7.3; p. 371)nogroup
(Section 17.7; p. 514; properties: exclusive, unique Members:)nontemporal
(Section 12.4.1; p. 431)notinbranch
(Section 9.8.1.2; pp. 375–376)novariants
(Section 9.7.2; p. 370)nowait
(Section 17.6; pp. 512–513)num_tasks
(Section 14.2.2; p. 464)num_teams
(Section 12.2.1; p. 427)num_threads
(Section 12.1.2; pp. 419–422)order
(Section 12.3; pp. 428–429)ordered
(Section 6.4.6; p. 237)otherwise
(Section 9.4.2; pp. 357–360; properties: pure)partial
(Section 11.9.2; p. 414)permutation
(Section 11.4.1; p. 407)priority
(Section 14.9; p. 474)private
(Section 7.5.3; pp. 256–257)proc_bind
(Section 12.1.4; p. 423)read
(Section 17.8.2.1; p. 519)reduction
(Section 7.6.10; pp. 283–285)relaxed
(Section 17.8.1.3; p. 516)release
(Section 17.8.1.4; p. 517)replayable
(Section 14.6; p. 471)reverse_offload
(Section 10.5.1.3; p. 389)safelen
(Section 12.4.2; p. 431)safesync
(Section 12.1.5; p. 424)schedule
(Section 13.6.3; pp. 449–450)self_maps
(Section 10.5.1.6; p. 392)seq_cst
(Section 17.8.1.5; p. 518; properties: exclusive, unique Members:)severity
(Section 10.4; p. 385)shared
(Section 7.5.2; p. 255)simd
(Section 17.10.3.2; pp. 549–550; properties: exclusive, required, unique Members:)simdlen
(Section 12.4.3; p. 432)sizes
(Section 11.2; p. 404)task_reduction
(Section 7.6.11; p. 286)thread_limit
(Section 15.3; pp. 483–484)threads
(Section 17.10.3.1; p. 548)threadset
(Section 14.8; p. 473)to
(Section 7.10.1; p. 328)transparent
(Section 17.9.6; p. 541)unified_address
(Section 10.5.1.4; p. 390)unified_shared_memory
(Section 10.5.1.5; p. 391)uniform
(Section 7.11; p. 330)untied
(Section 14.4; p. 470)update
(Section 17.9.4; p. 537)use
(Section 16.1.2; pp. 500–502)use_device_addr
(Section 7.5.10; pp. 269–282)use_device_ptr
(Section 7.5.8; p. 267)uses_allocators
(Section 8.8; pp. 346–355)weak
(Section 17.8.3.4; p. 523)when
(Section 9.4.1; p. 356)write
(Section 17.8.2.3; p. 520; properties: unique Members:)
Modifiers
Modifiers are keywords that modify the behavior of clauses. They appear as part of clause syntax to refine clause semantics.
Map-Type Modifiers
storage
(Section 7.9.1; p. 305; map-type modifier; default value)to
(Section 7.9.1; p. 305; map-type modifier; map-entering, assigning)from
(Section 7.9.1; p. 305; map-type modifier; map-exiting, assigning)tofrom
(Section 7.9.1; p. 305; map-type modifier; map-entering, map-exiting, assigning)alloc
(Section 7.9.1; p. 305; map-type modifier; alias for storage on map-entering constructs)release
(Section 7.9.1; p. 305; map-type modifier; alias for storage on map-exiting constructs)delete
(Section 7.9.1; p. 305; map-type modifier; used with delete-modifier)
Task-Dependence-Type Modifiers
in
(Section 17.9.1; p. 535; task-dependence-type modifier; input dependence)out
(Section 17.9.1; p. 535; task-dependence-type modifier; output dependence)inout
(Section 17.9.1; p. 535; task-dependence-type modifier; input-output dependence)inoutset
(Section 17.9.1; p. 535; task-dependence-type modifier; inout with set semantics)mutexinoutset
(Section 17.9.1; p. 535; task-dependence-type modifier; mutual exclusion inout)depobj
(Section 17.9.1; p. 535; task-dependence-type modifier; depend object)
Schedule Modifiers
monotonic
(Section 13.6.3; p. 449; ordering-modifier for schedule clause)nonmonotonic
(Section 13.6.3; p. 449; ordering-modifier for schedule clause)simd
(Section 13.6.3; p. 449; chunk-modifier for schedule clause)
Reduction and Induction Modifiers
reduction-identifier
(Section 7.6.9; p. 282; modifier specifying reduction operation)iterator
(Section 5.2.6; p. 200; modifier for creating iterator expressions)
Other Clause Modifiers
ref
(Section 7.9.5; ref-modifier for map clause; indicates referencing variable)mapper
(Section 7.9.4; mapper-modifier for map clause; specifies custom mapper)allocator-simple-modifier
(Section 8.6; allocator modifier; simple allocator specification)allocator-complex-modifier
(Section 8.6; allocator modifier; complex allocator specification)prefer-type
(Section 16.1.3; p. 501; prefer-type modifier for interop clause)directive-name-modifier
(Section 5.4; p. 204; conditional modifier using directive name)
Map Clause Modifiers
always
(Section 7.9.6; always-modifier; forces data transfer)close
(Section 7.9.6; close-modifier; allocates in fastest memory)present
(Section 7.9.6; present-modifier; data must be present)self
(Section 7.9.6; self-modifier; for device-host data mapping)
Lastprivate Modifiers
conditional
(Section 7.5.5; p. 261; modifier for lastprivate clause; conditional assignment)
Original-Sharing Modifiers
original
(Section 7.6.10; original-sharing-modifier; preserves original data-sharing)
Keywords and Values
Keywords and values used as arguments to clauses and directives.
Memory Order Keywords
seq_cst
(Section 17.8.1.5; p. 518; sequentially consistent memory ordering)acq_rel
(Section 17.8.1.1; p. 515; acquire-release memory ordering)acquire
(Section 17.8.1.2; p. 516; acquire memory ordering)release
(Section 17.8.1.4; p. 517; release memory ordering)relaxed
(Section 17.8.1.3; p. 516; relaxed memory ordering)
Atomic Operation Keywords
read
(Section 17.8.2.1; p. 519; atomic read operation)write
(Section 17.8.2.3; p. 520; atomic write operation)update
(Section 17.8.2.2; atomic update operation)capture
(Section 17.8.3.1; p. 521; atomic capture operation)compare
(Section 17.8.3.2; p. 522; atomic compare operation)weak
(Section 17.8.3.4; p. 523; weak compare semantics)fail
(Section 17.8.3.3; fail memory order for atomic compare)
Schedule Types
static
(Section 13.6.3; p. 449; static loop schedule)dynamic
(Section 13.6.3; p. 449; dynamic loop schedule)guided
(Section 13.6.3; p. 449; guided loop schedule)auto
(Section 13.6.3; p. 449; implementation-defined loop schedule)runtime
(Section 13.6.3; p. 449; runtime-determined loop schedule)
Proc_bind Values
primary
(Section 12.1.4; p. 423; bind to primary thread's place)close
(Section 12.1.4; p. 423; bind close to parent thread)spread
(Section 12.1.4; p. 423; spread across places)master
(deprecated; useprimary
instead)
Order Values
concurrent
(Section 12.3; p. 428; concurrent execution ordering)reproducible
(Section 12.3; p. 428; reproducible ordering)unconstrained
(Section 12.3; p. 428; unconstrained ordering)
Device-Type Values
host
(Section 15.1; p. 481; host device type)nohost
(Section 15.1; p. 481; non-host device type)any
(Section 15.1; p. 481; any device type)
Bind Values
thread
(Section 13.8.1; p. 455; bind to thread)parallel
(Section 13.8.1; p. 455; bind to parallel region)teams
(Section 13.8.1; p. 455; bind to teams region)
Default Values
shared
(Section 7.5.1; p. 254; default shared data-sharing)private
(Section 7.5.1; p. 254; default private data-sharing)firstprivate
(Section 7.5.1; p. 254; default firstprivate data-sharing)none
(Section 7.5.1; p. 254; no default data-sharing)
Error Directive Values
compilation
(Section 10.2; at clause value; error at compilation time)execution
(Section 10.2; at clause value; error at execution time)fatal
(Section 10.4; p. 385; severity clause value; fatal error)warning
(Section 10.4; p. 385; severity clause value; warning)
Defaultmap Values
alloc
(Section 7.9.9; p. 322; defaultmap behavior)to
(Section 7.9.9; p. 322; defaultmap behavior)from
(Section 7.9.9; p. 322; defaultmap behavior)tofrom
(Section 7.9.9; p. 322; defaultmap behavior)firstprivate
(Section 7.9.9; p. 322; defaultmap behavior)none
(Section 7.9.9; p. 322; defaultmap behavior)default
(Section 7.9.9; p. 322; defaultmap behavior)present
(Section 7.9.9; p. 322; defaultmap behavior)
Variable Categories (for defaultmap)
scalar
(Section 7.9.9; p. 322; scalar variable category)aggregate
(Section 7.9.9; p. 322; aggregate variable category)allocatable
(Section 7.9.9; p. 322; allocatable variable category)pointer
(Section 7.9.9; p. 322; pointer variable category)
Predefined Allocators
OpenMP defines several predefined memory allocators for different memory spaces.
Standard Allocators
omp_default_mem_alloc
(Section 8.2; p. 336; default memory allocator)omp_large_cap_mem_alloc
(Section 8.2; p. 336; large capacity memory allocator)omp_const_mem_alloc
(Section 8.2; p. 336; constant memory allocator)omp_high_bw_mem_alloc
(Section 8.2; p. 336; high bandwidth memory allocator)omp_low_lat_mem_alloc
(Section 8.2; p. 336; low latency memory allocator)omp_cgroup_mem_alloc
(Section 8.2; p. 336; contention group memory allocator)omp_pteam_mem_alloc
(Section 8.2; p. 336; parallel team memory allocator)omp_thread_mem_alloc
(Section 8.2; p. 336; thread-private memory allocator)
Special Allocator Values
omp_null_allocator
(Section 8.2; p. 336; null allocator value)
Allocator Traits
sync_hint
(Section 8.2; p. 336; allocator trait; contended, uncontended, serialized, private)alignment
(Section 8.2; p. 336; allocator trait; byte alignment)access
(Section 8.2; p. 336; allocator trait; all, memspace, device, cgroup, pteam, thread)pool_size
(Section 8.2; p. 336; allocator trait; pool size limit)fallback
(Section 8.2; p. 336; allocator trait; default_mem_fb, null_fb, abort_fb, allocator_fb)fb_data
(Section 8.2; p. 336; allocator trait; fallback allocator handle)pinned
(Section 8.2; p. 336; allocator trait; true, false)partition
(Section 8.2; p. 336; allocator trait; environment, nearest, blocked, interleaved, partitioner)
Reserved Locators
Reserved locators are special OpenMP identifiers representing system storage.
omp_all_memory
(Section 5.2.2; p. 195; reserved locator representing all memory)
Reduction Operators
Reduction operators used with reduction clauses.
Arithmetic Operators
+
(Section 7.6.3; addition reduction)-
(Section 7.6.3; subtraction reduction)*
(Section 7.6.3; multiplication reduction)
Bitwise Operators
&
(Section 7.6.3; bitwise AND reduction)|
(Section 7.6.3; bitwise OR reduction)^
(Section 7.6.3; bitwise XOR reduction)
Logical Operators
&&
(Section 7.6.3; logical AND reduction)||
(Section 7.6.3; logical OR reduction)
Min/Max Operators
min
(Section 7.6.3; minimum reduction)max
(Section 7.6.3; maximum reduction)
Language-Specific Operators
.eqv.
(Fortran; Section 7.6.3; logical equivalence reduction).neqv.
(Fortran; Section 7.6.3; logical non-equivalence reduction).and.
(Fortran; Section 7.6.3; logical AND reduction).or.
(Fortran; Section 7.6.3; logical OR reduction)iand
(Fortran; Section 7.6.3; bitwise AND reduction)ior
(Fortran; Section 7.6.3; bitwise OR reduction)ieor
(Fortran; Section 7.6.3; bitwise XOR reduction)
Special Constants and Identifiers
Device Identifiers
omp_invalid_device
(Section 15.2; invalid device number)omp_initial_device
(Section 15.2; initial device identifier)
Interop Type Identifiers
targetsync
(Section 16.1.2; p. 500; target synchronization interop type)target
(Section 16.1.2; p. 500; target interop type)
Doacross Keywords
source
(Section 17.9.7; p. 543; doacross source)sink
(Section 17.9.7; p. 543; doacross sink)source_omp_cur_iteration
(Section 17.9.7; p. 543; current iteration source)
OpenMP 6.0 Directive–Clause Components
For each OpenMP 6.0 directive or construct, this section lists every clause permitted by the specification. Clause entries include their specification metadata as well as the argument and modifier tables transcribed verbatim from the standard to preserve exact semantics.
allocate
(Section 8.5; pp. 341–342; category: declarative; association: explicit; properties: pure)
Clause align
(Section 8.3; p. 340)
Permitted on directives: allocate
.
Arguments
Name Type Properties
alignment expression of integer
type
constant, positive
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause allocator
(Section 8.4)
Permitted on directives: allocate
.
Arguments
Name Type Properties
allocator expression of allocator_-
handle type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
allocators
(Section 8.7; category: executable; association: block : allocator; properties: default)
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
assume
(Section 10.6.3; category: informational; association: block; properties: pure)
Clause absent
(Section 10.6.1.1; p. 394)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
directive-name-list list of directive-name list
item type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause contains
(Section 10.6.1.2)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
directive-name-list list of directive-name list
item type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause holds
(Section 10.6.1.3; p. 395)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
hold-expr expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause no_openmp
(Section 10.6.1.4; p. 396)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
can_assume expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause no_openmp_constructs
(Section 10.6.1.5)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
can_assume expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause no_openmp_routines
(Section 10.6.1.6; p. 397)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
can_assume expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause no_parallelism
(Section 10.6.1.7; p. 398)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
can_assume expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
assumes
(Section 10.6.2; p. 399; category: informational; association: unassociated; properties: pure)
Clause absent
(Section 10.6.1.1; p. 394)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
directive-name-list list of directive-name list
item type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause contains
(Section 10.6.1.2)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
directive-name-list list of directive-name list
item type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause holds
(Section 10.6.1.3; p. 395)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
hold-expr expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause no_openmp
(Section 10.6.1.4; p. 396)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
can_assume expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause no_openmp_constructs
(Section 10.6.1.5)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
can_assume expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause no_openmp_routines
(Section 10.6.1.6; p. 397)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
can_assume expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause no_parallelism
(Section 10.6.1.7; p. 398)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
can_assume expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
atomic
(Section 17.8.5; pp. 525–528; category: executable; association: block : atomic; properties: mutual-exclusion, order-)
Clause acq_rel
(Section 17.8.1.1; p. 515)
Permitted on directives: atomic
, flush
.
Arguments
Name Type Properties
use-semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause acquire
(Section 17.8.1.2; p. 516)
Permitted on directives: atomic
, flush
.
Arguments
Name Type Properties
use_semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause capture
(Section 17.8.3.1; p. 521)
Permitted on directives: atomic
.
Arguments
Name Type Properties
use_semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause compare
(Section 17.8.3.2; p. 522)
Permitted on directives: atomic
.
Arguments
Name Type Properties
use_semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause fail
(Section 17.8.3.3)
Permitted on directives: atomic
.
Arguments
Name Type Properties
memorder Keyword:acquire,
relaxed, seq_cst
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause hint
(Section 17.1; p. 503)
Permitted on directives: atomic
, critical
.
Arguments
Name Type Properties
hint-expr expression of sync_hint
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause memscope
(Section 17.8.4; p. 524)
Permitted on directives: atomic
, flush
.
Arguments
Name Type Properties
scope-specifier Keyword:all,
cgroup,device
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause read
(Section 17.8.2.1; p. 519)
Permitted on directives: atomic
.
Arguments
Name Type Properties
use_semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause relaxed
(Section 17.8.1.3)
Permitted on directives: atomic
, flush
.
Arguments
Name Type Properties
use_semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause release
(Section 17.8.1.4; p. 517)
Permitted on directives: atomic
, flush
.
Arguments
Name Type Properties
use_semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause seq_cst
(Section 17.8.1.5; p. 518; properties: exclusive, unique Members:)
Permitted on directives: atomic
, flush
.
Arguments
Name Type Properties
use_semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause weak
(Section 17.8.3.4; p. 523)
Permitted on directives: atomic
.
Arguments
Name Type Properties
use_semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause write
(Section 17.8.2.3; p. 520; properties: unique Members:)
Permitted on directives: atomic
.
Arguments
Name Type Properties
use_semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
barrier
(Section 17.3.1; pp. 506–508; category: executable; association: unassociated; properties: team-executed)
No clauses are defined for this directive in the specification.
begin assumes
(Section 10.6.4; category: informational; association: delimited; properties: default)
Clause absent
(Section 10.6.1.1; p. 394)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
directive-name-list list of directive-name list
item type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause contains
(Section 10.6.1.2)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
directive-name-list list of directive-name list
item type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause holds
(Section 10.6.1.3; p. 395)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
hold-expr expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause no_openmp
(Section 10.6.1.4; p. 396)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
can_assume expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause no_openmp_constructs
(Section 10.6.1.5)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
can_assume expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause no_openmp_routines
(Section 10.6.1.6; p. 397)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
can_assume expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause no_parallelism
(Section 10.6.1.7; p. 398)
Permitted on directives: assume
, assumes
, begin assumes
.
Arguments
Name Type Properties
can_assume expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
begin declare_target
(Section 9.9.2; p. 380; category: declarative; association: delimited; properties: declare-target, device,)
Clause device_type
(Section 15.1; p. 481)
Permitted on directives: begin declare_target
, declare_target
, groupprivate
, target
.
Arguments
Name Type Properties
device-type-description Keyword:any,host,
nohost
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause indirect
(Section 9.9.3; pp. 381–382)
Permitted on directives: begin declare_target
, declare_target
.
Arguments
Name Type Properties
invoked-by-fptr expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
begin declare_variant
(Section 9.6.5; p. 367; category: declarative; association: delimited; properties: default)
Clause match
(Section 9.6.1; p. 361)
Permitted on directives: begin declare_variant
, declare_variant
.
Arguments
Name Type Properties
context-selector An OpenMP context-
selector-specification
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
cancel
(Section 18.2; pp. 551–554; category: executable; association: unassociated; properties: default)
Clause if
(Section 5.5; p. 210)
Permitted on directives: cancel
, parallel
, simd
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskgraph
, taskloop
, teams
.
Arguments
Name Type Properties
if-expression expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
cancellation_point
(Section 18.3; pp. 555–964; category: executable; association: unassociated; properties: default)
No clauses are defined for this directive in the specification.
critical
(Section 17.2; pp. 504–505; category: executable; association: block; properties: mutual-exclusion, thread-)
Clause hint
(Section 17.1; p. 503)
Permitted on directives: atomic
, critical
.
Arguments
Name Type Properties
hint-expr expression of sync_hint
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
declare_induction
(Section 7.6.17; pp. 294–295; category: declarative; association: unassociated; properties: pure)
Clause collector
(Section 7.6.19)
Permitted on directives: declare_induction
.
Arguments
Name Type Properties
collector-expr expression of collector
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause inductor
(Section 7.6.18; p. 296)
Permitted on directives: declare_induction
.
Arguments
Name Type Properties
inductor-expr expression of inductor
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
declare_mapper
(Section 7.9.10; pp. 324–327; category: declarative; association: unassociated; properties: pure)
Clause map
(Section 7.9.6; pp. 310–319)
Permitted on directives: declare_mapper
, target
, target_data
, target_enter_data
, target_exit_data
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
always-modifier locator-list Keyword:always map-type-
modifying
close-modifier locator-list Keyword:close map-type-
modifying
present-modifier locator-list Keyword:present map-type-
modifying
self-modifier locator-list Keyword:self map-type-
modifying
ref-modifier all arguments Keyword:ref_ptee,
ref_ptr,ref_ptr_ptee
unique
delete-modifier locator-list Keyword:delete map-type-
modifying
mapper locator-list Complex, name:mapper
declare_reduction
(Section 7.6.14; pp. 291–292; category: declarative; association: unassociated; properties: pure)
Clause combiner
(Section 7.6.15)
Permitted on directives: declare_reduction
.
Arguments
Name Type Properties
combiner-expr expression of combiner
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause initializer
(Section 7.6.16; p. 293)
Permitted on directives: declare_reduction
.
Arguments
Name Type Properties
initializer-expr expression of initializer
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
declare_simd
(Section 9.8; pp. 372–373; category: declarative; association: declaration; properties: pure, variant-generating)
Clause aligned
(Section 7.12; p. 331)
Permitted on directives: declare_simd
, simd
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
alignment list OpenMP integer expression positive, region
invariant, ultimate,
unique
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause inbranch
(Section 9.8.1.1; p. 374)
Permitted on directives: declare_simd
.
Arguments
Name Type Properties
inbranch expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause linear
(Section 7.5.6; pp. 263–265)
Permitted on directives: declare_simd
, do
, for
, simd
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
step-simple-
modifier
list OpenMP integer expression exclusive, region-
invariant, unique
step-complex-
modifier
list Complex, name:step
Clause notinbranch
(Section 9.8.1.2; pp. 375–376)
Permitted on directives: declare_simd
.
Arguments
Name Type Properties
notinbranch expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause simdlen
(Section 12.4.3; p. 432)
Permitted on directives: declare_simd
, simd
.
Arguments
Name Type Properties
length expression of integer
type
positive, constant
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause uniform
(Section 7.11; p. 330)
Permitted on directives: declare_simd
.
Arguments
Name Type Properties
parameter-list list of parameter list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
declare_target
(Section 9.9.1; pp. 377–379; category: declarative; association: explicit; properties: declare-target, device,)
Clause device_type
(Section 15.1; p. 481)
Permitted on directives: begin declare_target
, declare_target
, groupprivate
, target
.
Arguments
Name Type Properties
device-type-description Keyword:any,host,
nohost
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause enter
(Section 7.9.7; p. 320)
Permitted on directives: declare_target
.
Arguments
Name Type Properties
list list of extended list item
type
default
Modifiers
Name Modifies Type Properties
automap-modifier list Keyword:automap default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause indirect
(Section 9.9.3; pp. 381–382)
Permitted on directives: begin declare_target
, declare_target
.
Arguments
Name Type Properties
invoked-by-fptr expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause link
(Section 7.9.8; p. 321)
Permitted on directives: declare_target
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause local
(Section 7.14; pp. 334–339)
Permitted on directives: declare_target
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
declare_variant
(Section 9.6.4; pp. 365–366; category: declarative; association: declaration; properties: pure)
Clause adjust_args
(Section 9.6.2; pp. 362–363)
Permitted on directives: declare_variant
.
Arguments
Name Type Properties
parameter-list list of parameter list item
type
default
Modifiers
Name Modifies Type Properties
adjust-op parameter-list Keyword:
need_device_addr,
need_device_ptr,
nothing
required
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause append_args
(Section 9.6.3; p. 364)
Permitted on directives: declare_variant
.
Arguments
Name Type Properties
append-op-list list of OpenMP opera-
tion list item type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause match
(Section 9.6.1; p. 361)
Permitted on directives: begin declare_variant
, declare_variant
.
Arguments
Name Type Properties
context-selector An OpenMP context-
selector-specification
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
depobj
(Section 17.9.3; p. 536; category: executable; association: unassociated; properties: default)
Clause destroy
(Section 5.7; pp. 213–235)
Permitted on directives: depobj
, interop
.
Arguments
Name Type Properties
destroy-var variable of OpenMP
variable type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause init
(Section 5.6; pp. 211–212)
Permitted on directives: depobj
, interop
.
Arguments
Name Type Properties
init-var variable of OpenMP
type
default
Modifiers
Name Modifies Type Properties
prefer-type init-var Complex, name:
prefer_type
Clause update
(Section 17.9.4; p. 537)
Permitted on directives: depobj
.
Arguments
Name Type Properties
update-var variable of OpenMP
depend type
default
Modifiers
Name Modifies Type Properties
task-dependence-
type
all arguments Keyword:depobj, in,
inout,inoutset,
mutexinoutset, out
unique
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
dispatch
(Section 9.7; pp. 368–369; category: executable; association: block : function-dispatch; properties: context-matching)
Clause depend
(Section 17.9.5; pp. 538–540)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskwait
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
task-dependence-
type
all arguments Keyword:depobj, in,
inout,inoutset,
mutexinoutset, out
unique
iterator locator-list Complex, name:iterator
Clause device
(Section 15.2; p. 482)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
.
Arguments
Name Type Properties
device-description expression of integer
type
default
Modifiers
Name Modifies Type Properties
device-modifier device-description Keyword:ancestor,
device_num
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause has_device_addr
(Section 7.5.9; p. 268)
Permitted on directives: dispatch
, target
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause interop
(Section 9.7.1; p. 370)
Permitted on directives: dispatch
.
Arguments
Name Type Properties
interop-var-list list of variable of interop
OpenMP type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause is_device_ptr
(Section 7.5.7; p. 266)
Permitted on directives: dispatch
, target
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause nocontext
(Section 9.7.3; p. 371)
Permitted on directives: dispatch
.
Arguments
Name Type Properties
do-not-update-context expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause novariants
(Section 9.7.2)
Permitted on directives: dispatch
.
Arguments
Name Type Properties
do-not-use-variant expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
distribute
(Section 13.7; pp. 451–452; category: executable; association: loop nest; properties: SIMD-partitionable,)
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
Clause collapse
(Section 6.4.5; p. 236)
Permitted on directives: distribute
, do
, for
, loop
, simd
, taskloop
.
Arguments
Name Type Properties
n expression of integer
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause dist_schedule
(Section 13.7.1; p. 453)
Permitted on directives: distribute
.
Arguments
Name Type Properties
kind Keyword:static default
chunk_size expression of integer
type
ultimate, optional, posi-
tive, region-invariant
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause firstprivate
(Section 7.5.4; pp. 258–259)
Permitted on directives: distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
saved list Keyword:saved default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause induction
(Section 7.6.13; pp. 288–290)
Permitted on directives: distribute
, do
, for
, simd
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
induction-
identifier
list OpenMP induction identifier required, ultimate
step-modifier list Complex, name:step
Clause lastprivate
(Section 7.5.5; pp. 260–262)
Permitted on directives: distribute
, do
, for
, loop
, sections
, simd
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
lastprivate-
modifier
list Keyword:conditional default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause order
(Section 12.3; pp. 428–429)
Permitted on directives: distribute
, do
, for
, loop
, simd
.
Arguments
Name Type Properties
ordering Keyword:
concurrent
default
Modifiers
Name Modifies Type Properties
order-modifier ordering Keyword:reproducible,
unconstrained
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
do
(Section 13.6.2; p. 448; category: executable; association: loop nest; properties: work-distribution,)
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
Clause collapse
(Section 6.4.5; p. 236)
Permitted on directives: distribute
, do
, for
, loop
, simd
, taskloop
.
Arguments
Name Type Properties
n expression of integer
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause firstprivate
(Section 7.5.4; pp. 258–259)
Permitted on directives: distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
saved list Keyword:saved default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause induction
(Section 7.6.13; pp. 288–290)
Permitted on directives: distribute
, do
, for
, simd
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
induction-
identifier
list OpenMP induction identifier required, ultimate
step-modifier list Complex, name:step
Clause lastprivate
(Section 7.5.5; pp. 260–262)
Permitted on directives: distribute
, do
, for
, loop
, sections
, simd
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
lastprivate-
modifier
list Keyword:conditional default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause linear
(Section 7.5.6; pp. 263–265)
Permitted on directives: declare_simd
, do
, for
, simd
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
step-simple-
modifier
list OpenMP integer expression exclusive, region-
invariant, unique
step-complex-
modifier
list Complex, name:step
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause order
(Section 12.3; pp. 428–429)
Permitted on directives: distribute
, do
, for
, loop
, simd
.
Arguments
Name Type Properties
ordering Keyword:
concurrent
default
Modifiers
Name Modifies Type Properties
order-modifier ordering Keyword:reproducible,
unconstrained
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause ordered
(Section 6.4.6; p. 237)
Permitted on directives: do
, for
.
Arguments
Name Type Properties
n expression of integer
type
optional, constant, posi-
tive
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause reduction
(Section 7.6.10; pp. 283–285)
Permitted on directives: do
, for
, loop
, parallel
, scope
, sections
, simd
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
reduction-modifier list Keyword:default,
inscan, task
default
original-sharing-
modifier
list Complex, name:original
Clause schedule
(Section 13.6.3; pp. 449–450)
Permitted on directives: do
, for
.
Arguments
Name Type Properties
kind Keyword:auto,
dynamic, guided,
runtime, static
default
chunk_size expression of integer
type
ultimate, optional, posi-
tive, region-invariant
Modifiers
Name Modifies Type Properties
ordering-modifier kind Keyword:monotonic,
nonmonotonic
unique
chunk-modifier kind Keyword:simd unique
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
error
(Section 10.1; p. 383; category: utility; association: unassociated; properties: pure)
Clause at
(Section 10.2)
Permitted on directives: error
.
Arguments
Name Type Properties
action-time Keyword:
compilation,
execution
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause message
(Section 10.3; p. 384)
Permitted on directives: error
, parallel
.
Arguments
Name Type Properties
msg-string expression of string type default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause severity
(Section 10.4; p. 385)
Permitted on directives: error
, parallel
.
Arguments
Name Type Properties
sev-level Keyword:fatal,
warning
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
flush
(Section 17.8.6; pp. 529–535; category: executable; association: unassociated; properties: default)
Clause acq_rel
(Section 17.8.1.1; p. 515)
Permitted on directives: atomic
, flush
.
Arguments
Name Type Properties
use-semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause acquire
(Section 17.8.1.2; p. 516)
Permitted on directives: atomic
, flush
.
Arguments
Name Type Properties
use_semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause memscope
(Section 17.8.4; p. 524)
Permitted on directives: atomic
, flush
.
Arguments
Name Type Properties
scope-specifier Keyword:all,
cgroup,device
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause relaxed
(Section 17.8.1.3)
Permitted on directives: atomic
, flush
.
Arguments
Name Type Properties
use_semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause release
(Section 17.8.1.4; p. 517)
Permitted on directives: atomic
, flush
.
Arguments
Name Type Properties
use_semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause seq_cst
(Section 17.8.1.5; p. 518; properties: exclusive, unique Members:)
Permitted on directives: atomic
, flush
.
Arguments
Name Type Properties
use_semantics expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
for
(Section 13.6.1; p. 447; category: executable; association: loop nest; properties: work-distribution,)
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
Clause collapse
(Section 6.4.5; p. 236)
Permitted on directives: distribute
, do
, for
, loop
, simd
, taskloop
.
Arguments
Name Type Properties
n expression of integer
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause firstprivate
(Section 7.5.4; pp. 258–259)
Permitted on directives: distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
saved list Keyword:saved default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause induction
(Section 7.6.13; pp. 288–290)
Permitted on directives: distribute
, do
, for
, simd
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
induction-
identifier
list OpenMP induction identifier required, ultimate
step-modifier list Complex, name:step
Clause lastprivate
(Section 7.5.5; pp. 260–262)
Permitted on directives: distribute
, do
, for
, loop
, sections
, simd
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
lastprivate-
modifier
list Keyword:conditional default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause linear
(Section 7.5.6; pp. 263–265)
Permitted on directives: declare_simd
, do
, for
, simd
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
step-simple-
modifier
list OpenMP integer expression exclusive, region-
invariant, unique
step-complex-
modifier
list Complex, name:step
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause order
(Section 12.3; pp. 428–429)
Permitted on directives: distribute
, do
, for
, loop
, simd
.
Arguments
Name Type Properties
ordering Keyword:
concurrent
default
Modifiers
Name Modifies Type Properties
order-modifier ordering Keyword:reproducible,
unconstrained
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause ordered
(Section 6.4.6; p. 237)
Permitted on directives: do
, for
.
Arguments
Name Type Properties
n expression of integer
type
optional, constant, posi-
tive
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause reduction
(Section 7.6.10; pp. 283–285)
Permitted on directives: do
, for
, loop
, parallel
, scope
, sections
, simd
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
reduction-modifier list Keyword:default,
inscan, task
default
original-sharing-
modifier
list Complex, name:original
Clause schedule
(Section 13.6.3; pp. 449–450)
Permitted on directives: do
, for
.
Arguments
Name Type Properties
kind Keyword:auto,
dynamic, guided,
runtime, static
default
chunk_size expression of integer
type
ultimate, optional, posi-
tive, region-invariant
Modifiers
Name Modifies Type Properties
ordering-modifier kind Keyword:monotonic,
nonmonotonic
unique
chunk-modifier kind Keyword:simd unique
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
fuse
(Section 11.3; p. 405; category: executable; association: loop sequence; properties: loop-transforming, order-)
Clause apply
(Section 11.1; pp. 403–404)
Permitted on directives: fuse
, interchange
, nothing
, reverse
, split
, stripe
, tile
, unroll
.
Arguments
Name Type Properties
applied-directives list of directive specifi-
cation list item type
default
Modifiers
Name Modifies Type Properties
loop-modifier applied-directives Complex, Keyword:
fused,grid, identity,
interchanged,
intratile,offsets,
reversed, split,
unrolled
Clause looprange
(Section 6.4.7; pp. 238–245)
Permitted on directives: fuse
.
Arguments
Name Type Properties
first expression of OpenMP
integer type
constant, positive
count expression of OpenMP
integer type
constant, positive, ulti-
mate
Modifiers
Name Modifies Type Properties
saved list Keyword:saved default
groupprivate
(Section 7.13; pp. 332–333; category: declarative; association: explicit; properties: pure)
Clause device_type
(Section 15.1; p. 481)
Permitted on directives: begin declare_target
, declare_target
, groupprivate
, target
.
Arguments
Name Type Properties
device-type-description Keyword:any,host,
nohost
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
interchange
(Section 11.4; p. 406; category: executable; association: loop nest; properties: loop-transforming,)
Clause apply
(Section 11.1; pp. 403–404)
Permitted on directives: fuse
, interchange
, nothing
, reverse
, split
, stripe
, tile
, unroll
.
Arguments
Name Type Properties
applied-directives list of directive specifi-
cation list item type
default
Modifiers
Name Modifies Type Properties
loop-modifier applied-directives Complex, Keyword:
fused,grid, identity,
interchanged,
intratile,offsets,
reversed, split,
unrolled
Clause permutation
(Section 11.4.1; p. 407)
Permitted on directives: interchange
.
Arguments
Name Type Properties
permutation-list list of OpenMP integer
expression type
constant, positive
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
interop
(Section 16.1; p. 499; category: executable; association: unassociated; properties: device)
Clause depend
(Section 17.9.5; pp. 538–540)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskwait
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
task-dependence-
type
all arguments Keyword:depobj, in,
inout,inoutset,
mutexinoutset, out
unique
iterator locator-list Complex, name:iterator
Clause destroy
(Section 5.7; pp. 213–235)
Permitted on directives: depobj
, interop
.
Arguments
Name Type Properties
destroy-var variable of OpenMP
variable type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause device
(Section 15.2; p. 482)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
.
Arguments
Name Type Properties
device-description expression of integer
type
default
Modifiers
Name Modifies Type Properties
device-modifier device-description Keyword:ancestor,
device_num
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause init
(Section 5.6; pp. 211–212)
Permitted on directives: depobj
, interop
.
Arguments
Name Type Properties
init-var variable of OpenMP
type
default
Modifiers
Name Modifies Type Properties
prefer-type init-var Complex, name:
prefer_type
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause use
(Section 16.1.2; pp. 500–502)
Permitted on directives: interop
.
Arguments
Name Type Properties
interop-var variable of interop
OpenMP type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
loop
(Section 13.8; p. 454; category: executable; association: loop nest; properties: order-concurrent-nestable,)
Clause bind
(Section 13.8.1; pp. 455–456)
Permitted on directives: loop
.
Arguments
Name Type Properties
binding Keyword:parallel,
teams,thread
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause collapse
(Section 6.4.5; p. 236)
Permitted on directives: distribute
, do
, for
, loop
, simd
, taskloop
.
Arguments
Name Type Properties
n expression of integer
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause lastprivate
(Section 7.5.5; pp. 260–262)
Permitted on directives: distribute
, do
, for
, loop
, sections
, simd
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
lastprivate-
modifier
list Keyword:conditional default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause order
(Section 12.3; pp. 428–429)
Permitted on directives: distribute
, do
, for
, loop
, simd
.
Arguments
Name Type Properties
ordering Keyword:
concurrent
default
Modifiers
Name Modifies Type Properties
order-modifier ordering Keyword:reproducible,
unconstrained
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause reduction
(Section 7.6.10; pp. 283–285)
Permitted on directives: do
, for
, loop
, parallel
, scope
, sections
, simd
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
reduction-modifier list Keyword:default,
inscan, task
default
original-sharing-
modifier
list Complex, name:original
masked
(Section 12.5; p. 433; category: executable; association: block; properties: thread-limiting, thread-)
Clause filter
(Section 12.5.1; pp. 434–435)
Permitted on directives: masked
.
Arguments
Name Type Properties
thread_num expression of integer
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
nothing
(Section 10.7; pp. 400–402; category: utility; association: unassociated; properties: pure, loop-transforming)
Clause apply
(Section 11.1; pp. 403–404)
Permitted on directives: fuse
, interchange
, nothing
, reverse
, split
, stripe
, tile
, unroll
.
Arguments
Name Type Properties
applied-directives list of directive specifi-
cation list item type
default
Modifiers
Name Modifies Type Properties
loop-modifier applied-directives Complex, Keyword:
fused,grid, identity,
interchanged,
intratile,offsets,
reversed, split,
unrolled
ordered
(Section 17.10.2; pp. 546–547; category: executable; association: block; properties: mutual-exclusion, simdiz-)
Clause doacross
(Section 17.9.7; pp. 542–544)
Permitted on directives: ordered
.
Arguments
Name Type Properties
iteration-specifier OpenMP iteration speci-
fier
default
Modifiers
Name Modifies Type Properties
dependence-type iteration-specifier Keyword:sink, source required
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause simd
(Section 17.10.3.2; pp. 549–550; properties: exclusive, required, unique Members:)
Permitted on directives: ordered
.
Arguments
Name Type Properties
apply-to-simd expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause threads
(Section 17.10.3.1; p. 548)
Permitted on directives: ordered
.
Arguments
Name Type Properties
apply-to-threads expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
parallel
(Section 12.1; pp. 415–418; category: executable; association: block; properties: cancellable, context-)
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
Clause copyin
(Section 7.8.1; p. 302)
Permitted on directives: parallel
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause default
(Section 7.5.1; p. 254)
Permitted on directives: parallel
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
data-sharing-attribute Keyword:
firstprivate,
none, private,
shared
default
Modifiers
Name Modifies Type Properties
variable-category implicit-behavior Keyword:aggregate,
all, allocatable,
pointer,scalar
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause firstprivate
(Section 7.5.4; pp. 258–259)
Permitted on directives: distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
saved list Keyword:saved default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause if
(Section 5.5; p. 210)
Permitted on directives: cancel
, parallel
, simd
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskgraph
, taskloop
, teams
.
Arguments
Name Type Properties
if-expression expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause message
(Section 10.3; p. 384)
Permitted on directives: error
, parallel
.
Arguments
Name Type Properties
msg-string expression of string type default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause num_threads
(Section 12.1.2; pp. 419–422)
Permitted on directives: parallel
.
Arguments
Name Type Properties
nthreads list of OpenMP integer
expression type
positive
Modifiers
Name Modifies Type Properties
prescriptiveness nthreads Keyword:strict default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause proc_bind
(Section 12.1.4; p. 423)
Permitted on directives: parallel
.
Arguments
Name Type Properties
affinity-policy Keyword:close,
primary, spread
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause reduction
(Section 7.6.10; pp. 283–285)
Permitted on directives: do
, for
, loop
, parallel
, scope
, sections
, simd
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
reduction-modifier list Keyword:default,
inscan, task
default
original-sharing-
modifier
list Complex, name:original
Clause safesync
(Section 12.1.5; p. 424)
Permitted on directives: parallel
.
Arguments
Name Type Properties
width expression of integer
type
positive, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause severity
(Section 10.4; p. 385)
Permitted on directives: error
, parallel
.
Arguments
Name Type Properties
sev-level Keyword:fatal,
warning
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause shared
(Section 7.5.2; p. 255)
Permitted on directives: parallel
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
requires
(Section 10.5; p. 386; category: informational; association: unassociated; properties: default)
Clause atomic_default_mem_order
(Section 10.5.1.1; p. 387)
Permitted on directives: requires
.
Arguments
Name Type Properties
memory-order Keyword:acq_rel,
acquire,relaxed,
release,seq_cst
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause device_safesync
(Section 10.5.1.7; p. 393; properties: required, unique Members:)
Permitted on directives: requires
.
Arguments
Name Type Properties
required expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause dynamic_allocators
(Section 10.5.1.2; p. 388)
Permitted on directives: requires
.
Arguments
Name Type Properties
required expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause reverse_offload
(Section 10.5.1.3; p. 389)
Permitted on directives: requires
.
Arguments
Name Type Properties
required expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause self_maps
(Section 10.5.1.6; p. 392)
Permitted on directives: requires
.
Arguments
Name Type Properties
required expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause unified_address
(Section 10.5.1.4; p. 390)
Permitted on directives: requires
.
Arguments
Name Type Properties
required expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause unified_shared_memory
(Section 10.5.1.5; p. 391)
Permitted on directives: requires
.
Arguments
Name Type Properties
required expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
reverse
(Section 11.5; category: executable; association: loop nest; properties: generally-composable,)
Clause apply
(Section 11.1; pp. 403–404)
Permitted on directives: fuse
, interchange
, nothing
, reverse
, split
, stripe
, tile
, unroll
.
Arguments
Name Type Properties
applied-directives list of directive specifi-
cation list item type
default
Modifiers
Name Modifies Type Properties
loop-modifier applied-directives Complex, Keyword:
fused,grid, identity,
interchanged,
intratile,offsets,
reversed, split,
unrolled
scan
(Section 7.7; pp. 297–299; category: subsidiary; association: separating; properties: pure)
Clause exclusive
(Section 7.7.2; p. 300)
Permitted on directives: scan
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause inclusive
(Section 7.7.1)
Permitted on directives: scan
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause init_complete
(Section 7.7.3; p. 301)
Permitted on directives: scan
.
Arguments
Name Type Properties
create_init_phase expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
scope
(Section 13.2; p. 437; category: executable; association: block; properties: work-distribution, team-)
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
Clause firstprivate
(Section 7.5.4; pp. 258–259)
Permitted on directives: distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
saved list Keyword:saved default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause reduction
(Section 7.6.10; pp. 283–285)
Permitted on directives: do
, for
, loop
, parallel
, scope
, sections
, simd
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
reduction-modifier list Keyword:default,
inscan, task
default
original-sharing-
modifier
list Complex, name:original
section
(Section 13.3.1; p. 439; category: subsidiary; association: separating; properties: default)
No clauses are defined for this directive in the specification.
sections
(Section 13.3; p. 438; category: executable; association: block; properties: work-distribution, team-)
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
Clause firstprivate
(Section 7.5.4; pp. 258–259)
Permitted on directives: distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
saved list Keyword:saved default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause lastprivate
(Section 7.5.5; pp. 260–262)
Permitted on directives: distribute
, do
, for
, loop
, sections
, simd
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
lastprivate-
modifier
list Keyword:conditional default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause reduction
(Section 7.6.10; pp. 283–285)
Permitted on directives: do
, for
, loop
, parallel
, scope
, sections
, simd
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
reduction-modifier list Keyword:default,
inscan, task
default
original-sharing-
modifier
list Complex, name:original
simd
(Section 12.4; p. 430; category: executable; association: loop nest; properties: context-matching, order-)
Clause aligned
(Section 7.12; p. 331)
Permitted on directives: declare_simd
, simd
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
alignment list OpenMP integer expression positive, region
invariant, ultimate,
unique
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause collapse
(Section 6.4.5; p. 236)
Permitted on directives: distribute
, do
, for
, loop
, simd
, taskloop
.
Arguments
Name Type Properties
n expression of integer
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause if
(Section 5.5; p. 210)
Permitted on directives: cancel
, parallel
, simd
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskgraph
, taskloop
, teams
.
Arguments
Name Type Properties
if-expression expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause induction
(Section 7.6.13; pp. 288–290)
Permitted on directives: distribute
, do
, for
, simd
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
induction-
identifier
list OpenMP induction identifier required, ultimate
step-modifier list Complex, name:step
Clause lastprivate
(Section 7.5.5; pp. 260–262)
Permitted on directives: distribute
, do
, for
, loop
, sections
, simd
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
lastprivate-
modifier
list Keyword:conditional default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause linear
(Section 7.5.6; pp. 263–265)
Permitted on directives: declare_simd
, do
, for
, simd
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
step-simple-
modifier
list OpenMP integer expression exclusive, region-
invariant, unique
step-complex-
modifier
list Complex, name:step
Clause nontemporal
(Section 12.4.1; p. 431)
Permitted on directives: simd
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause order
(Section 12.3; pp. 428–429)
Permitted on directives: distribute
, do
, for
, loop
, simd
.
Arguments
Name Type Properties
ordering Keyword:
concurrent
default
Modifiers
Name Modifies Type Properties
order-modifier ordering Keyword:reproducible,
unconstrained
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause reduction
(Section 7.6.10; pp. 283–285)
Permitted on directives: do
, for
, loop
, parallel
, scope
, sections
, simd
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
reduction-modifier list Keyword:default,
inscan, task
default
original-sharing-
modifier
list Complex, name:original
Clause safelen
(Section 12.4.2)
Permitted on directives: simd
.
Arguments
Name Type Properties
length expression of integer
type
positive, constant
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause simdlen
(Section 12.4.3; p. 432)
Permitted on directives: declare_simd
, simd
.
Arguments
Name Type Properties
length expression of integer
type
positive, constant
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
single
(Section 13.1; p. 436; category: executable; association: block; properties: work-distribution, team-)
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
Clause copyprivate
(Section 7.8.2; pp. 303–309)
Permitted on directives: single
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause firstprivate
(Section 7.5.4; pp. 258–259)
Permitted on directives: distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
saved list Keyword:saved default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
split
(Section 11.6; p. 408; category: executable; association: loop nest; properties: generally-composable,)
Clause apply
(Section 11.1; pp. 403–404)
Permitted on directives: fuse
, interchange
, nothing
, reverse
, split
, stripe
, tile
, unroll
.
Arguments
Name Type Properties
applied-directives list of directive specifi-
cation list item type
default
Modifiers
Name Modifies Type Properties
loop-modifier applied-directives Complex, Keyword:
fused,grid, identity,
interchanged,
intratile,offsets,
reversed, split,
unrolled
Clause counts
(Section 11.6.1; p. 409)
Permitted on directives: split
.
Arguments
Name Type Properties
count-list list of OpenMP integer
expression type
non-negative
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
stripe
(Section 11.7; p. 410; category: executable; association: loop nest; properties: loop-transforming, order-)
Clause apply
(Section 11.1; pp. 403–404)
Permitted on directives: fuse
, interchange
, nothing
, reverse
, split
, stripe
, tile
, unroll
.
Arguments
Name Type Properties
applied-directives list of directive specifi-
cation list item type
default
Modifiers
Name Modifies Type Properties
loop-modifier applied-directives Complex, Keyword:
fused,grid, identity,
interchanged,
intratile,offsets,
reversed, split,
unrolled
Clause sizes
(Section 11.2)
Permitted on directives: stripe
, tile
.
Arguments
Name Type Properties
size-list list of OpenMP integer
expression type
positive
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
target
(Section 15.8; pp. 491–495; category: executable; association: block; properties: parallelism-generating,)
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
Clause default
(Section 7.5.1; p. 254)
Permitted on directives: parallel
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
data-sharing-attribute Keyword:
firstprivate,
none, private,
shared
default
Modifiers
Name Modifies Type Properties
variable-category implicit-behavior Keyword:aggregate,
all, allocatable,
pointer,scalar
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause defaultmap
(Section 7.9.9; pp. 322–323)
Permitted on directives: target
.
Arguments
Name Type Properties
implicit-behavior Keyword:default,
firstprivate,
from, none,
present,private,
self, storage,to,
tofrom
default
Modifiers
Name Modifies Type Properties
variable-category implicit-behavior Keyword:aggregate,
all, allocatable,
pointer,scalar
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause depend
(Section 17.9.5; pp. 538–540)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskwait
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
task-dependence-
type
all arguments Keyword:depobj, in,
inout,inoutset,
mutexinoutset, out
unique
iterator locator-list Complex, name:iterator
Clause device
(Section 15.2; p. 482)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
.
Arguments
Name Type Properties
device-description expression of integer
type
default
Modifiers
Name Modifies Type Properties
device-modifier device-description Keyword:ancestor,
device_num
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause device_type
(Section 15.1; p. 481)
Permitted on directives: begin declare_target
, declare_target
, groupprivate
, target
.
Arguments
Name Type Properties
device-type-description Keyword:any,host,
nohost
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause firstprivate
(Section 7.5.4; pp. 258–259)
Permitted on directives: distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
saved list Keyword:saved default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause has_device_addr
(Section 7.5.9; p. 268)
Permitted on directives: dispatch
, target
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause if
(Section 5.5; p. 210)
Permitted on directives: cancel
, parallel
, simd
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskgraph
, taskloop
, teams
.
Arguments
Name Type Properties
if-expression expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause in_reduction
(Section 7.6.12; p. 287)
Permitted on directives: target
, target_data
, task
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause is_device_ptr
(Section 7.5.7; p. 266)
Permitted on directives: dispatch
, target
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause map
(Section 7.9.6; pp. 310–319)
Permitted on directives: declare_mapper
, target
, target_data
, target_enter_data
, target_exit_data
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
always-modifier locator-list Keyword:always map-type-
modifying
close-modifier locator-list Keyword:close map-type-
modifying
present-modifier locator-list Keyword:present map-type-
modifying
self-modifier locator-list Keyword:self map-type-
modifying
ref-modifier all arguments Keyword:ref_ptee,
ref_ptr,ref_ptr_ptee
unique
delete-modifier locator-list Keyword:delete map-type-
modifying
mapper locator-list Complex, name:mapper
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause priority
(Section 14.9; p. 474)
Permitted on directives: target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, taskgraph
, taskloop
.
Arguments
Name Type Properties
priority-value expression of integer
type
constant, non-negative
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause replayable
(Section 14.6; p. 471)
Permitted on directives: target
, target_enter_data
, target_exit_data
, target_update
, task
, taskloop
, taskwait
.
Arguments
Name Type Properties
replayable-expression expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause thread_limit
(Section 15.3; pp. 483–484)
Permitted on directives: target
, teams
.
Arguments
Name Type Properties
threadlim expression of integer
type
positive
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause uses_allocators
(Section 8.8; pp. 346–355)
Permitted on directives: target
.
Arguments
Name Type Properties
allocator expression of allocator_-
handle type
default
Modifiers
Name Modifies Type Properties
mem-space allocator Complex, name:memspace
target_data
(Section 15.7; pp. 489–490; category: executable; association: block; properties: device, device-affecting,)
Clause affinity
(Section 14.10; p. 475)
Permitted on directives: target_data
, task
, task_iteration
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
iterator locator-list Complex, name:iterator
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
Clause default
(Section 7.5.1; p. 254)
Permitted on directives: parallel
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
data-sharing-attribute Keyword:
firstprivate,
none, private,
shared
default
Modifiers
Name Modifies Type Properties
variable-category implicit-behavior Keyword:aggregate,
all, allocatable,
pointer,scalar
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause depend
(Section 17.9.5; pp. 538–540)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskwait
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
task-dependence-
type
all arguments Keyword:depobj, in,
inout,inoutset,
mutexinoutset, out
unique
iterator locator-list Complex, name:iterator
Clause detach
(Section 14.11; p. 476)
Permitted on directives: target_data
, task
.
Arguments
Name Type Properties
event-handle variable of event_handle
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause device
(Section 15.2; p. 482)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
.
Arguments
Name Type Properties
device-description expression of integer
type
default
Modifiers
Name Modifies Type Properties
device-modifier device-description Keyword:ancestor,
device_num
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause firstprivate
(Section 7.5.4; pp. 258–259)
Permitted on directives: distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
saved list Keyword:saved default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause if
(Section 5.5; p. 210)
Permitted on directives: cancel
, parallel
, simd
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskgraph
, taskloop
, teams
.
Arguments
Name Type Properties
if-expression expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause in_reduction
(Section 7.6.12; p. 287)
Permitted on directives: target
, target_data
, task
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause map
(Section 7.9.6; pp. 310–319)
Permitted on directives: declare_mapper
, target
, target_data
, target_enter_data
, target_exit_data
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
always-modifier locator-list Keyword:always map-type-
modifying
close-modifier locator-list Keyword:close map-type-
modifying
present-modifier locator-list Keyword:present map-type-
modifying
self-modifier locator-list Keyword:self map-type-
modifying
ref-modifier all arguments Keyword:ref_ptee,
ref_ptr,ref_ptr_ptee
unique
delete-modifier locator-list Keyword:delete map-type-
modifying
mapper locator-list Complex, name:mapper
Clause mergeable
(Section 14.5)
Permitted on directives: target_data
, task
, taskloop
.
Arguments
Name Type Properties
can_merge expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause nogroup
(Section 17.7; p. 514; properties: exclusive, unique Members:)
Permitted on directives: target_data
, taskgraph
, taskloop
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause priority
(Section 14.9; p. 474)
Permitted on directives: target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, taskgraph
, taskloop
.
Arguments
Name Type Properties
priority-value expression of integer
type
constant, non-negative
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause shared
(Section 7.5.2; p. 255)
Permitted on directives: parallel
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause transparent
(Section 17.9.6; p. 541)
Permitted on directives: target_data
, task
, taskloop
.
Arguments
Name Type Properties
impex-type expression of impex
OpenMP type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause use_device_addr
(Section 7.5.10; pp. 269–282)
Permitted on directives: target_data
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause use_device_ptr
(Section 7.5.8; p. 267)
Permitted on directives: target_data
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
target_enter_data
(Section 15.5; pp. 485–486; category: executable; association: unassociated; properties: parallelism-generating,)
Clause depend
(Section 17.9.5; pp. 538–540)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskwait
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
task-dependence-
type
all arguments Keyword:depobj, in,
inout,inoutset,
mutexinoutset, out
unique
iterator locator-list Complex, name:iterator
Clause device
(Section 15.2; p. 482)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
.
Arguments
Name Type Properties
device-description expression of integer
type
default
Modifiers
Name Modifies Type Properties
device-modifier device-description Keyword:ancestor,
device_num
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause if
(Section 5.5; p. 210)
Permitted on directives: cancel
, parallel
, simd
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskgraph
, taskloop
, teams
.
Arguments
Name Type Properties
if-expression expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause map
(Section 7.9.6; pp. 310–319)
Permitted on directives: declare_mapper
, target
, target_data
, target_enter_data
, target_exit_data
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
always-modifier locator-list Keyword:always map-type-
modifying
close-modifier locator-list Keyword:close map-type-
modifying
present-modifier locator-list Keyword:present map-type-
modifying
self-modifier locator-list Keyword:self map-type-
modifying
ref-modifier all arguments Keyword:ref_ptee,
ref_ptr,ref_ptr_ptee
unique
delete-modifier locator-list Keyword:delete map-type-
modifying
mapper locator-list Complex, name:mapper
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause priority
(Section 14.9; p. 474)
Permitted on directives: target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, taskgraph
, taskloop
.
Arguments
Name Type Properties
priority-value expression of integer
type
constant, non-negative
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause replayable
(Section 14.6; p. 471)
Permitted on directives: target
, target_enter_data
, target_exit_data
, target_update
, task
, taskloop
, taskwait
.
Arguments
Name Type Properties
replayable-expression expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
target_exit_data
(Section 15.6; pp. 487–488; category: executable; association: unassociated; properties: parallelism-generating,)
Clause depend
(Section 17.9.5; pp. 538–540)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskwait
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
task-dependence-
type
all arguments Keyword:depobj, in,
inout,inoutset,
mutexinoutset, out
unique
iterator locator-list Complex, name:iterator
Clause device
(Section 15.2; p. 482)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
.
Arguments
Name Type Properties
device-description expression of integer
type
default
Modifiers
Name Modifies Type Properties
device-modifier device-description Keyword:ancestor,
device_num
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause if
(Section 5.5; p. 210)
Permitted on directives: cancel
, parallel
, simd
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskgraph
, taskloop
, teams
.
Arguments
Name Type Properties
if-expression expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause map
(Section 7.9.6; pp. 310–319)
Permitted on directives: declare_mapper
, target
, target_data
, target_enter_data
, target_exit_data
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
always-modifier locator-list Keyword:always map-type-
modifying
close-modifier locator-list Keyword:close map-type-
modifying
present-modifier locator-list Keyword:present map-type-
modifying
self-modifier locator-list Keyword:self map-type-
modifying
ref-modifier all arguments Keyword:ref_ptee,
ref_ptr,ref_ptr_ptee
unique
delete-modifier locator-list Keyword:delete map-type-
modifying
mapper locator-list Complex, name:mapper
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause priority
(Section 14.9; p. 474)
Permitted on directives: target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, taskgraph
, taskloop
.
Arguments
Name Type Properties
priority-value expression of integer
type
constant, non-negative
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause replayable
(Section 14.6; p. 471)
Permitted on directives: target
, target_enter_data
, target_exit_data
, target_update
, task
, taskloop
, taskwait
.
Arguments
Name Type Properties
replayable-expression expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
target_update
(Section 15.9; pp. 496–498; category: executable; association: unassociated; properties: parallelism-generating,)
Clause depend
(Section 17.9.5; pp. 538–540)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskwait
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
task-dependence-
type
all arguments Keyword:depobj, in,
inout,inoutset,
mutexinoutset, out
unique
iterator locator-list Complex, name:iterator
Clause device
(Section 15.2; p. 482)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
.
Arguments
Name Type Properties
device-description expression of integer
type
default
Modifiers
Name Modifies Type Properties
device-modifier device-description Keyword:ancestor,
device_num
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause from
(Section 7.10.2; p. 329)
Permitted on directives: target_update
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
present-modifier locator-list Keyword:present default
mapper locator-list Complex, name:mapper
Clause if
(Section 5.5; p. 210)
Permitted on directives: cancel
, parallel
, simd
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskgraph
, taskloop
, teams
.
Arguments
Name Type Properties
if-expression expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause priority
(Section 14.9; p. 474)
Permitted on directives: target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, taskgraph
, taskloop
.
Arguments
Name Type Properties
priority-value expression of integer
type
constant, non-negative
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause replayable
(Section 14.6; p. 471)
Permitted on directives: target
, target_enter_data
, target_exit_data
, target_update
, task
, taskloop
, taskwait
.
Arguments
Name Type Properties
replayable-expression expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause to
(Section 7.10.1; p. 328)
Permitted on directives: target_update
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
present-modifier locator-list Keyword:present default
mapper locator-list Complex, name:mapper
task
(Section 14.1; pp. 457–459; category: executable; association: block; properties: parallelism-generating,)
Clause affinity
(Section 14.10; p. 475)
Permitted on directives: target_data
, task
, task_iteration
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
iterator locator-list Complex, name:iterator
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
Clause default
(Section 7.5.1; p. 254)
Permitted on directives: parallel
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
data-sharing-attribute Keyword:
firstprivate,
none, private,
shared
default
Modifiers
Name Modifies Type Properties
variable-category implicit-behavior Keyword:aggregate,
all, allocatable,
pointer,scalar
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause depend
(Section 17.9.5; pp. 538–540)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskwait
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
task-dependence-
type
all arguments Keyword:depobj, in,
inout,inoutset,
mutexinoutset, out
unique
iterator locator-list Complex, name:iterator
Clause detach
(Section 14.11; p. 476)
Permitted on directives: target_data
, task
.
Arguments
Name Type Properties
event-handle variable of event_handle
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause final
(Section 14.7; p. 472)
Permitted on directives: task
, taskloop
.
Arguments
Name Type Properties
finalize expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause firstprivate
(Section 7.5.4; pp. 258–259)
Permitted on directives: distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
saved list Keyword:saved default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause if
(Section 5.5; p. 210)
Permitted on directives: cancel
, parallel
, simd
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskgraph
, taskloop
, teams
.
Arguments
Name Type Properties
if-expression expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause in_reduction
(Section 7.6.12; p. 287)
Permitted on directives: target
, target_data
, task
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause mergeable
(Section 14.5)
Permitted on directives: target_data
, task
, taskloop
.
Arguments
Name Type Properties
can_merge expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause priority
(Section 14.9; p. 474)
Permitted on directives: target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, taskgraph
, taskloop
.
Arguments
Name Type Properties
priority-value expression of integer
type
constant, non-negative
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause replayable
(Section 14.6; p. 471)
Permitted on directives: target
, target_enter_data
, target_exit_data
, target_update
, task
, taskloop
, taskwait
.
Arguments
Name Type Properties
replayable-expression expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause shared
(Section 7.5.2; p. 255)
Permitted on directives: parallel
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause threadset
(Section 14.8; p. 473)
Permitted on directives: task
, taskloop
.
Arguments
Name Type Properties
set Keyword:omp_pool,
omp_team
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause transparent
(Section 17.9.6; p. 541)
Permitted on directives: target_data
, task
, taskloop
.
Arguments
Name Type Properties
impex-type expression of impex
OpenMP type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause untied
(Section 14.4; p. 470)
Permitted on directives: task
, taskloop
.
Arguments
Name Type Properties
can_change_threads expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
task_iteration
(Section 14.2.3; p. 465; category: subsidiary; association: unassociated; properties: default)
Clause affinity
(Section 14.10; p. 475)
Permitted on directives: target_data
, task
, task_iteration
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
iterator locator-list Complex, name:iterator
Clause depend
(Section 17.9.5; pp. 538–540)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskwait
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
task-dependence-
type
all arguments Keyword:depobj, in,
inout,inoutset,
mutexinoutset, out
unique
iterator locator-list Complex, name:iterator
Clause if
(Section 5.5; p. 210)
Permitted on directives: cancel
, parallel
, simd
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskgraph
, taskloop
, teams
.
Arguments
Name Type Properties
if-expression expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
taskgraph
(Section 14.3; pp. 466–468; category: executable; association: block; properties: default)
Clause graph_id
(Section 14.3.1)
Permitted on directives: taskgraph
.
Arguments
Name Type Properties
graph-id-value expression of OpenMP
integer type
default
No modifiers specified.
Clause graph_reset
(Section 14.3.2; p. 469)
Permitted on directives: taskgraph
.
Arguments
Name Type Properties
graph-reset-expression expression of OpenMP
logical type
default
No modifiers specified.
Clause if
(Section 5.5; p. 210)
Permitted on directives: cancel
, parallel
, simd
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskgraph
, taskloop
, teams
.
Arguments
Name Type Properties
if-expression expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause nogroup
(Section 17.7; p. 514; properties: exclusive, unique Members:)
Permitted on directives: target_data
, taskgraph
, taskloop
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause priority
(Section 14.9; p. 474)
Permitted on directives: target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, taskgraph
, taskloop
.
Arguments
Name Type Properties
priority-value expression of integer
type
constant, non-negative
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
taskgroup
(Section 17.4; p. 509; category: executable; association: block; properties: cancellable)
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
Clause task_reduction
(Section 7.6.11; p. 286)
Permitted on directives: taskgroup
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
taskloop
(Section 14.2; pp. 460–462; category: executable; association: loop nest; properties: parallelism-generating,)
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
Clause collapse
(Section 6.4.5; p. 236)
Permitted on directives: distribute
, do
, for
, loop
, simd
, taskloop
.
Arguments
Name Type Properties
n expression of integer
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause default
(Section 7.5.1; p. 254)
Permitted on directives: parallel
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
data-sharing-attribute Keyword:
firstprivate,
none, private,
shared
default
Modifiers
Name Modifies Type Properties
variable-category implicit-behavior Keyword:aggregate,
all, allocatable,
pointer,scalar
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause final
(Section 14.7; p. 472)
Permitted on directives: task
, taskloop
.
Arguments
Name Type Properties
finalize expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause firstprivate
(Section 7.5.4; pp. 258–259)
Permitted on directives: distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
saved list Keyword:saved default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause grainsize
(Section 14.2.1; p. 463)
Permitted on directives: taskloop
.
Arguments
Name Type Properties
grain-size expression of integer
type
positive
Modifiers
Name Modifies Type Properties
prescriptiveness grain-size Keyword:strict unique
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause if
(Section 5.5; p. 210)
Permitted on directives: cancel
, parallel
, simd
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskgraph
, taskloop
, teams
.
Arguments
Name Type Properties
if-expression expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause in_reduction
(Section 7.6.12; p. 287)
Permitted on directives: target
, target_data
, task
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause induction
(Section 7.6.13; pp. 288–290)
Permitted on directives: distribute
, do
, for
, simd
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
induction-
identifier
list OpenMP induction identifier required, ultimate
step-modifier list Complex, name:step
Clause lastprivate
(Section 7.5.5; pp. 260–262)
Permitted on directives: distribute
, do
, for
, loop
, sections
, simd
, taskloop
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
lastprivate-
modifier
list Keyword:conditional default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause mergeable
(Section 14.5)
Permitted on directives: target_data
, task
, taskloop
.
Arguments
Name Type Properties
can_merge expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause nogroup
(Section 17.7; p. 514; properties: exclusive, unique Members:)
Permitted on directives: target_data
, taskgraph
, taskloop
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause num_tasks
(Section 14.2.2; p. 464)
Permitted on directives: taskloop
.
Arguments
Name Type Properties
num-tasks expression of integer
type
positive
Modifiers
Name Modifies Type Properties
prescriptiveness num-tasks Keyword:strict unique
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause priority
(Section 14.9; p. 474)
Permitted on directives: target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, taskgraph
, taskloop
.
Arguments
Name Type Properties
priority-value expression of integer
type
constant, non-negative
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause reduction
(Section 7.6.10; pp. 283–285)
Permitted on directives: do
, for
, loop
, parallel
, scope
, sections
, simd
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
reduction-modifier list Keyword:default,
inscan, task
default
original-sharing-
modifier
list Complex, name:original
Clause replayable
(Section 14.6; p. 471)
Permitted on directives: target
, target_enter_data
, target_exit_data
, target_update
, task
, taskloop
, taskwait
.
Arguments
Name Type Properties
replayable-expression expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause shared
(Section 7.5.2; p. 255)
Permitted on directives: parallel
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause threadset
(Section 14.8; p. 473)
Permitted on directives: task
, taskloop
.
Arguments
Name Type Properties
set Keyword:omp_pool,
omp_team
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause transparent
(Section 17.9.6; p. 541)
Permitted on directives: target_data
, task
, taskloop
.
Arguments
Name Type Properties
impex-type expression of impex
OpenMP type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause untied
(Section 14.4; p. 470)
Permitted on directives: task
, taskloop
.
Arguments
Name Type Properties
can_change_threads expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
taskwait
(Section 17.5; pp. 510–511; category: executable; association: unassociated; properties: default)
Clause depend
(Section 17.9.5; pp. 538–540)
Permitted on directives: dispatch
, interop
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskwait
.
Arguments
Name Type Properties
locator-list list of locator list item
type
default
Modifiers
Name Modifies Type Properties
task-dependence-
type
all arguments Keyword:depobj, in,
inout,inoutset,
mutexinoutset, out
unique
iterator locator-list Complex, name:iterator
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause replayable
(Section 14.6; p. 471)
Permitted on directives: target
, target_enter_data
, target_exit_data
, target_update
, task
, taskloop
, taskwait
.
Arguments
Name Type Properties
replayable-expression expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
taskyield
(Section 14.12; pp. 477–480; category: executable; association: unassociated; properties: default)
No clauses are defined for this directive in the specification.
teams
(Section 12.2; pp. 425–427; category: executable; association: block; properties: parallelism-generating,)
Clause allocate
(Section 8.6; pp. 343–345)
Permitted on directives: allocators
, distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskgroup
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
allocator-simple-
modifier
list expression of OpenMP allo-
cator_handle type
exclusive, unique
allocator-complex-
modifier
list Complex, name:
allocator
Clause default
(Section 7.5.1; p. 254)
Permitted on directives: parallel
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
data-sharing-attribute Keyword:
firstprivate,
none, private,
shared
default
Modifiers
Name Modifies Type Properties
variable-category implicit-behavior Keyword:aggregate,
all, allocatable,
pointer,scalar
default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause firstprivate
(Section 7.5.4; pp. 258–259)
Permitted on directives: distribute
, do
, for
, parallel
, scope
, sections
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
saved list Keyword:saved default
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause if
(Section 5.5; p. 210)
Permitted on directives: cancel
, parallel
, simd
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, task
, task_iteration
, taskgraph
, taskloop
, teams
.
Arguments
Name Type Properties
if-expression expression of OpenMP
logical type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause num_teams
(Section 12.2.1)
Permitted on directives: teams
.
Arguments
Name Type Properties
upper-bound expression of integer
type
positive
Modifiers
Name Modifies Type Properties
lower-bound upper-bound OpenMP integer expression positive, ultimate,
unique
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause private
(Section 7.5.3; pp. 256–257)
Permitted on directives: distribute
, do
, for
, loop
, parallel
, scope
, sections
, simd
, single
, target
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause reduction
(Section 7.6.10; pp. 283–285)
Permitted on directives: do
, for
, loop
, parallel
, scope
, sections
, simd
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
reduction-
identifier
all arguments An OpenMP reduction iden-
tifier
required, ultimate
reduction-modifier list Keyword:default,
inscan, task
default
original-sharing-
modifier
list Complex, name:original
Clause shared
(Section 7.5.2; p. 255)
Permitted on directives: parallel
, target_data
, task
, taskloop
, teams
.
Arguments
Name Type Properties
list list of variable list item
type
default
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause thread_limit
(Section 15.3; pp. 483–484)
Permitted on directives: target
, teams
.
Arguments
Name Type Properties
threadlim expression of integer
type
positive
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
threadprivate
(Section 7.3; pp. 246–253; category: declarative; association: explicit; properties: pure)
No clauses are defined for this directive in the specification.
tile
(Section 11.8; p. 411; category: executable; association: loop nest; properties: loop-transforming, order-)
Clause apply
(Section 11.1; pp. 403–404)
Permitted on directives: fuse
, interchange
, nothing
, reverse
, split
, stripe
, tile
, unroll
.
Arguments
Name Type Properties
applied-directives list of directive specifi-
cation list item type
default
Modifiers
Name Modifies Type Properties
loop-modifier applied-directives Complex, Keyword:
fused,grid, identity,
interchanged,
intratile,offsets,
reversed, split,
unrolled
Clause sizes
(Section 11.2)
Permitted on directives: stripe
, tile
.
Arguments
Name Type Properties
size-list list of OpenMP integer
expression type
positive
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
unroll
(Section 11.9; p. 412; category: executable; association: loop nest; properties: generally-composable,)
Clause apply
(Section 11.1; pp. 403–404)
Permitted on directives: fuse
, interchange
, nothing
, reverse
, split
, stripe
, tile
, unroll
.
Arguments
Name Type Properties
applied-directives list of directive specifi-
cation list item type
default
Modifiers
Name Modifies Type Properties
loop-modifier applied-directives Complex, Keyword:
fused,grid, identity,
interchanged,
intratile,offsets,
reversed, split,
unrolled
Clause full
(Section 11.9.1; p. 413)
Permitted on directives: unroll
.
Arguments
Name Type Properties
fully_unroll expression of OpenMP
logical type
constant, optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
Clause partial
(Section 11.9.2; p. 414)
Permitted on directives: unroll
.
Arguments
Name Type Properties
unroll-factor expression of integer
type
optional, constant, posi-
tive
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
workdistribute
(Section 13.5; pp. 443–446; category: executable; association: block; properties: work-distribution, parti-)
No clauses are defined for this directive in the specification.
workshare
(Section 13.4; pp. 440–442; category: executable; association: block; properties: work-distribution, team-)
Clause nowait
(Section 17.6; pp. 512–513)
Permitted on directives: dispatch
, do
, for
, interop
, scope
, sections
, single
, target
, target_data
, target_enter_data
, target_exit_data
, target_update
, taskwait
, workshare
.
Arguments
Name Type Properties
do_not_synchronize expression of OpenMP
logical type
optional
Modifiers
Name Modifies Type Properties
directive-name-
modifier
all arguments Keyword:directive-name(a
directive name)
unique
OpenMP 6.0 Restrictions
This reference consolidates all normative restrictions for OpenMP 6.0 directives and clauses, essential for correct implementation and usage.
Purpose
For developers implementing or using OpenMP 6.0, this document provides:
- Complete restrictions - All normative rules from the specification
- Organized by construct - Easy to find what rules apply to each directive/clause
- Verbatim text - Reproduced directly from the standard for accuracy
- Implementation guidance - What is forbidden, required, or conditional
Organization
- Organized by directive and clause (alphabetically within categories)
- Each entry shows all restrictions for that construct
- Language-specific restrictions (C/C++ vs Fortran) are noted where applicable
Usage
When implementing or using a directive/clause, consult this document to ensure compliance with all OpenMP 6.0 normative requirements. Violating these restrictions results in undefined behavior or non-conforming programs.
Clause: if
(Section 5.5; p. 210)
Restrictions to the if clause are as follows:
- At most one if clause can be specified that applies to the semantics of any construct or constituent construct of a directive-specification.
Clause: init
(Section 5.6; pp. 211–212)
- init-var must not be constant.
- If the init clause appears on a depobj construct, init-var must refer to a variable of dependOpenMP type that isuninitialized.
- If theinitclause appears on adepobjconstruct then thedepinfo-modifier has the required property and otherwise it must not be present.
- If theinitclause appears on aninteropconstruct, init-var must refer to a variable of interopOpenMP type.
- If theinitclause appears on aninteropconstruct, theinterop-typemodifier has the required property and eachinterop-typekeyword has the unique property. Otherwise, the interop-typemodifier must not be present.
- Theprefer-typemodifier must not be present unless theinitclause appears on an interopconstruct.
Clause: destroy
(Section 5.7; pp. 213–235)
- destroy-varmust not be constant.
- If thedestroyclause appears on adepobjconstruct, destroy-varmust refer to a variable ofdependOpenMP type that isinitialized.
- If thedestroyclause appears on aninteropconstruct, destroy-varmust refer to a variable ofinteropOpenMP type that isinitialized.
Clause: collapse
(Section 6.4.5; p. 236)
- n must not evaluate to a value greater than the loop nest depth.
Clause: ordered
(Section 6.4.6; p. 237)
- None of the doacross-affected loops may be non-rectangular loops.
- n must not evaluate to a value greater than the depth of the associated loop nest.
- Ifn is explicitly specified and thecollapseclause is also specified for theordered clause on the same construct,n must be greater than or equal to then specified for the collapseclause.
Clause: looprange
(Section 6.4.7; pp. 238–245)
Restrictions to thelooprangeclause are as follows:
- first + count − 1 must not evaluate to a value greater than the loop sequence length of the associated canonical loop sequence.
Directive/Construct: threadprivate
(Section 7.3; pp. 246–253)
Restrictions to thethreadprivatedirective are as follows:
- A thread must not reference a copy of a threadprivate variable that belongs to another thread.
- A threadprivate variable must not appear as the base variable of a list item in any clause except for thecopyinand copyprivateclauses.
- An OpenMP program in which an untied task accesses threadprivate memory is non-conforming.
Clause: default
(Section 7.5.1; p. 254)
Restrictions to thedefaultclause are as follows:
- Ifdata-sharing-attributeis none, each variable that is referenced in the construct and does not have a predetermined data-sharing attribute must have an explicitly determined data-sharing attribute.
Clause: shared
(Section 7.5.2; p. 255)
No explicit restrictions are stated in the specification section.
Clause: private
(Section 7.5.3; pp. 256–257)
Restrictions to theprivateclause are as specified in Section 7.4.
Clause: firstprivate
(Section 7.5.4; pp. 258–259)
Restrictions to thefirstprivateclause are as follows:
- A list item that is private within aparallelregion must not appear in afirstprivate clause on a worksharing construct if any of the worksharing regions that arise from the worksharing construct ever bind to any of theparallelregions that arise from the parallelconstruct.
- A list item that is private within ateamsregion must not appear in afirstprivate clause on adistributeconstruct if any of thedistributeregions that arise from the distributeconstruct ever bind to any of theteamsregions that arise from theteams construct.
- A list item that appears in areductionclause on aparallelconstruct must not appear in afirstprivateclause on ataskortaskloopconstruct if any of thetaskregions thatarisefromthe taskortaskloopconstructeverbindtoanyofthe parallelregions that arise from theparallelconstruct.
Clause: lastprivate
(Section 7.5.5; pp. 260–262)
Restrictions to thelastprivateclause are as follows:
- A list item must not appear in alastprivateclause on a work-distribution construct if the corresponding region binds to the region of a parallelism-generating construct in which the list item is private.
- A list item that appears in alastprivateclause with theconditionalmodifier must be a scalar variable.
Clause: linear
(Section 7.5.6; pp. 263–265)
Restrictions to thelinearclause are as follows:
- If areductionclause with theinscanmodifier also appears on the construct, only loop-iteration variables of affected loops may appear as list items in alinearclause.
- Alinear-modifier may be specified asrefor uvalonly forlinearclauses on declare_simddirectives.
- For alinearclause that appears on a loop-nest-associated directive, the difference between the value of a list item at the end of a collapsed iteration and its value at the beginning of the collapsed iteration must be equal tolinear-step.
- If linear-modifier is uvalfor a list item in alinearclause that is specified on a declare_simddirective and the list item is modified during a call to the SIMD version of the procedure, the OpenMP program must not depend on the value of the list item upon return from the procedure.
- If linear-modifier is uvalfor a list item in alinearclause that is specified on a declare_simddirective, the OpenMP program must not depend on the storage of the argument in the procedure being the same as the storage of the corresponding argument at the callsite.
Clause: is_device_ptr
(Section 7.5.7; p. 266)
Restrictions to theis_device_ptrclause are as follows:
- Each list item must be a valid device pointer for the device data environment.
Clause: use_device_ptr
(Section 7.5.8; p. 267)
Restrictions to theuse_device_ptrclause are as follows:
- Each list item must be a C pointer for which the value is the address of an object that has corresponding storage or is accessible on the target device.
Clause: has_device_addr
(Section 7.5.9; p. 268)
Restrictions to thehas_device_addrclause are as follows: C / C++
- Each list item must have a valid device address for the device data environment. C / C++ Fortran
- A list item must either have a valid device address for the device data environment, be an unallocated allocatable variable, or be a disassociated data pointer.
- The association status of a list item that is a pointer must not be undefined unless it is a structure component and it results from a predefined default mapper. Fortran
Clause: use_device_addr
(Section 7.5.10; pp. 269–282)
Restrictions to theuse_device_addrclause are as follows:
- Each list item must have a corresponding list item in the device data environment or be accessible on the target device.
- If a list item is an array section, the array base must be a base language identifier.
Clause: reduction
(Section 7.6.10; pp. 283–285)
Restrictions to thereductionclause are as follows:
- All restrictions common to all reduction clauses, as listed in Section 7.6.5 and Section 7.6.6, apply to this clause.
- For a given construct on which the clause appears, the lifetime of all original list items must extend at least until after the synchronization point at which the completion of the corresponding region by all participants in the reduction can be observed by all participants.
- If theinscanreduction-modifier is specified on areductionclause that appears on a worksharing construct and an original list item is private in the enclosing context of the construct, the private copies must all have identical values when the construct is encountered.
- If thereductionclause appears on a worksharing construct and the original-sharing-modifier specifiesdefaultas itssharingargument, each original list item must be shared in the enclosing context unless it is determined not to be shared according to the rules specified in Section 7.1.
Clause: task_reduction
(Section 7.6.11; p. 286)
Restrictions to thetask_reductionclause are as follows:
- All restrictions common to all reduction clauses, as listed in Section 7.6.5 and Section 7.6.6, apply to this clause.
Clause: in_reduction
(Section 7.6.12; p. 287)
Restrictions to thein_reductionclause are as follows:
- All restrictions common to all reduction clauses, as listed in Section 7.6.5 and Section 7.6.6, apply to this clause.
- For each list item, a matching list item must exist that appears in atask_reduction clause or areductionclause with thetaskreduction-modifier that is specified on a construct that corresponds to a region in which the region of the participating task is closely nested. The construct that corresponds to the innermost enclosing region that meets this condition must specify the samereduction-identifier for the matching list item as the in_reductionclause.
Clause: induction
(Section 7.6.13; pp. 288–290)
Restrictions to theinductionclause are as follows:
- All restrictions listed in Section 7.6.5 apply to this clause.
- Theinduction-stepmust not be an array or array section.
- If an array section or array element appears as a list item in aninductionclause on a worksharing construct, all threads of the team must specify the same storage location.
- None of the affected loops of a loop-nest-associated construct that has aninduction clause may be a non-rectangular loop.
Directive/Construct: declare_reduction
(Section 7.6.14; pp. 291–292)
Restrictions to thedeclare_reductiondirective are as follows:
- A reduction identifier must not be re-declared in the current scope for the same type or for a type that is compatible according to the base language rules.
- The type-name list must not declare new types.
Clause: combiner
(Section 7.6.15)
No explicit restrictions are stated in the specification section.
Clause: initializer
(Section 7.6.16; p. 293)
No explicit restrictions are stated in the specification section.
Directive/Construct: declare_induction
(Section 7.6.17; pp. 294–295)
Restrictions to thedeclare_inductiondirective are as follows:
- An induction identifier must not be re-declared in the current scope for the same type or for a type that is compatible according to the base language rules.
- A type-name list item in thetype-specifier-listmust not declare a new type.
Clause: inductor
(Section 7.6.18; p. 296)
No explicit restrictions are stated in the specification section.
Clause: collector
(Section 7.6.19)
No explicit restrictions are stated in the specification section.
Directive/Construct: scan
(Section 7.7; pp. 297–299)
Restrictions to thescandirective are as follows:
- The separated construct must have at most onescandirective with aninclusiveor exclusiveclause as a separating directive.
- The separated construct must have at most onescandirective with aninit_complete clause as a separating directive.
- If specified, ascandirective with aninit_completeclause must precede ascan directive with anexclusiveclause that is a subsidiary directive of the same construct.
- The affected loops of the separated construct must all be perfectly nested loops.
- Each list item that appears in theinclusiveorexclusiveclause must appear in a reductionclause with theinscanmodifier on the separated construct.
- Each list item that appears in areductionclause with theinscanmodifier on the separated construct must appear in a clause on thescanseparating directive.
- Cross-iteration dependences across different collapsed iterations of the separated construct must not exist, except for dependences for the list items specified in aninclusiveor exclusiveclause.
- Intra-iteration dependences from a statement in the structured block sequence that immediately precedes ascandirective with aninclusiveor exclusiveclause to a statement in the structured block sequence that follows thatscandirective must not exist, except for dependences for the list items specified in that clause.
- The private copy of a list item that appears in theinclusiveorexclusiveclause must not be modified in the scan phase.
- Any list item that appears in anexclusiveclause must not be modified or used in the initialization phase.
- Statements in the initialization phase must only modify private variables. Any private variables modified in the initialization phase must not be used in the scan phase.
Clause: inclusive
(Section 7.7.1)
No explicit restrictions are stated in the specification section.
Clause: exclusive
(Section 7.7.2; p. 300)
No explicit restrictions are stated in the specification section.
Clause: init_complete
(Section 7.7.3; p. 301)
No explicit restrictions are stated in the specification section.
Clause: copyin
(Section 7.8.1; p. 302)
Restrictions to thecopyinclause are as follows:
- A list item that appears in acopyinclause must be threadprivate.
Clause: copyprivate
(Section 7.8.2; pp. 303–309)
Restrictions to thecopyprivateclause are as follows:
- All list items that appear in acopyprivateclause must be either threadprivate or private in the enclosing context.
Clause: map
(Section 7.9.6; pp. 310–319)
Restrictions to themapclause are as follows:
- Two list items of themapclauses on the same construct must not share original storage unless one of the following is true: they are the same list item, one is the containing structure of the other, at least one is an assumed-size array, or at least one is implicitly mapped due to the list item also appearing in ause_device_addrclause.
- If the same list item appears more than once inmapclauses on the same construct, themap clauses must specify the samemapper modifier.
- A variable that is a groupprivate variable or a device-local variable must not appear as a list item in amapclause.
- If a list item is an array or an array section, it must specify contiguous storage.
- If an expression that is used to form a list item in amapclause contains an iterator identifier that is defined by aniterator modifier, the list item instances that would result from different values of the iterator must not have the same containing array and must not have base pointers that share original storage.
- If multiple list items are explicitly mapped on the same construct and have the same containing array or have base pointers that share original storage, and if any of the list items do not have corresponding list items that are present in the device data environment prior to a task encountering the construct, then the list items must refer to the same array elements of either the containing array or the implicit array of the base pointers.
- If any part of the original storage of a list item that is explicitly mapped by amapclause has corresponding storage in the device data environment prior to a task encountering the construct associated with themapclause, all of the original storage must have corresponding storage in the device data environment prior to the task encountering the construct.
Clause: enter
(Section 7.9.7; p. 320)
Restrictions to theenterclause are as follows:
- Each list item must have a mappable type.
- Each list item must have static storage duration.
Clause: link
(Section 7.9.8; p. 321)
Restrictions to thelinkclause are as follows:
- Each list item must have a mappable type.
- Each list item must have static storage duration.
Clause: defaultmap
(Section 7.9.9; pp. 322–323)
Restrictions to thedefaultmapclause are as follows:
- A givenvariable-category may be specified in at most onedefaultmapclause on a construct.
- If adefaultmapclause specifies theallvariable-category, no otherdefaultmap clause may appear on the construct.
- Ifimplicit-behavior is none, each variable that is specified byvariable-category and is referenced in the construct but does not have a predetermined data-sharing attribute and does not appear in anenteror linkclause on adeclare_targetdirective must be explicitly listed in a data-environment attribute clause on the construct.
Directive/Construct: declare_mapper
(Section 7.9.10; pp. 324–327)
Restrictions to thedeclare_mapperdirective are as follows:
- No instance oftypecan be mapped as part of the mapper, either directly or indirectly through another base language type, except the instancevar that is passed as the list item. If a set of declare_mapperdirectives results in a cyclic definition then the behavior is unspecified.
- The typemust not declare a new base language type.
- At least onemapclause that mapsvar or at least one element ofvar is required.
- Listitemsin mapclausesonthe declare_mapperdirectivemayonlyrefertothedeclared variablevar and entities that could be referenced by a procedure defined at the same location.
- If amapper modifier is specified for amapclause, its parameter must bedefault.
- Multipledeclare_mapperdirectives that specify the samemapper-identifierfor the same base language type or for compatible base language types, according to the base language rules, must not appear in the same scope.
Clause: to
(Section 7.10.1; p. 328)
No explicit restrictions are stated in the specification section.
Clause: from
(Section 7.10.2; p. 329)
No explicit restrictions are stated in the specification section.
Clause: uniform
(Section 7.11; p. 330)
Restrictions to theuniformclause are as follows:
- Only named parameter list items can be specified in theparameter-list.
Clause: aligned
(Section 7.12; p. 331)
Restrictions to thealignedclause are as follows:
- If the clause appears on adeclare_simddirective, each list item must be a named parameter list item of the associated procedure.
Directive/Construct: groupprivate
(Section 7.13; pp. 332–333)
Restrictions to thegroupprivatedirective are as follows:
- A task that executes in a particular contention group must not access the storage of a groupprivate copy of the list item that is created for a different contention group.
- Avariablethatisdeclaredwithaninitializermustnotappearina groupprivatedirective.
Clause: local
(Section 7.14; pp. 334–339)
Restrictions to OpenMP memory spaces are as follows:
- Variables in theomp_const_mem_spacememory space may not be written.
Clause: align
(Section 8.3; p. 340)
Restrictions to thealignclause are as follows:
- alignment must evaluate to a power of two.
Clause: allocator
(Section 8.4)
No explicit restrictions are stated in the specification section.
Directive/Construct: allocate
(Section 8.5; pp. 341–342)
Restrictions to theallocatedirective are as follows:
- An allocatedirective must appear in the same scope as the declarations of each of its list items and must follow all such declarations.
- A declared variable may appear as a list item in at most oneallocatedirective in a given compilation unit.
- allocatedirectives that appear in atargetregion must specify anallocatorclause unless arequiresdirective with thedynamic_allocatorsclause is present in the same compilation unit.
Clause: allocate
(Section 8.6; pp. 343–345)
Restrictions to theallocateclause are as follows:
- For any list item that is specified in theallocateclause on a directive other than the allocatorsdirective, a data-sharing attribute clause that may create a private copy of that list item must be specified on the same directive.
- Fortask,taskloopor targetdirectives, allocation requests to memory allocators with the accesstrait set tothreadresult in unspecified behavior.
- allocateclauses that appear on atargetconstruct or on constructs in atargetregion must specify anallocator-simple-modifieror allocator-complex-modifierunless a requiresdirective with thedynamic_allocatorsclause is present in the same compilation unit.
Directive/Construct: allocators
(Section 8.7)
Restrictions to theallocatorsconstruct are as follows:
- A list item that appears in anallocateclause must appear as one of the variables that is allocated by theallocate-stmt in the associated allocator structured block.
- A list item must not be a coarray or have a coarray as an ultimate component.
Clause: uses_allocators
(Section 8.8; pp. 346–355)
- Theallocator expression must be a base language identifier.
- Ifallocator is an identifier that matches the name of a predefined allocator, no modifiers may be specified.
- Ifallocator is not the name of a predefined allocator and is notomp_null_allocator, it must be a variable.
- Theallocator argument must not appear in other data-sharing attribute clauses or data-mapping attribute clauses on the same construct.
Clause: when
(Section 9.4.1; p. 356)
Restrictions to thewhenclause are as follows:
- directive-variantmust not specify a metadirective.
- context-selector must not specify any properties for thesimdtrait selector.
Clause: otherwise
(Section 9.4.2; pp. 357–360)
Restrictions to theotherwiseclause are as follows:
- directive-variantmust not specify a metadirective.
Clause: match
(Section 9.6.1; p. 361)
Restrictions to thematchclause are as follows:
- All variables that are referenced in an expression that appears in the context selector of a matchclause must be accessible at each call site to the base function according to the base language rules.
Clause: adjust_args
(Section 9.6.2; pp. 362–363)
- If theneed_device_addradjust-opmodifier is present and thehas-device-addr element does not exist for a specified argument in the semantic requirement set of the current task, all restrictions that apply to a list item in ause_device_addrclause also apply to the corresponding argument that is passed by the call.
Clause: append_args
(Section 9.6.3; p. 364)
No explicit restrictions are stated in the specification section.
Directive/Construct: declare_variant
(Section 9.6.4; pp. 365–366)
The restrictions to thedeclare_variantdirective are as follows:
Directive/Construct: begin declare_variant
(Section 9.6.5; p. 367)
The restrictions tobegin declare_variantdirective are as follows:
- matchclause must not contain asimdtrait selector.
- Twobegin declare_variantdirectives and their paired end directives must either encompass disjoint source ranges or be perfectly nested.
Directive/Construct: dispatch
(Section 9.7; pp. 368–369)
Restrictions to thedispatchconstruct are as follows:
- If theinteropclause is present and has more than oneinterop-varthen thedevice clause must also be present.
Clause: interop
(Section 9.7.1; p. 370)
Restrictions to theinteropclause are as follows:
- If theinteropclause is specified on adispatchconstruct, the matching declare_variantdirective for thetarget-callmust have anappend_argsclause with a number of list items that equals or exceeds the number of list items in theinteropclause.
Clause: novariants
(Section 9.7.2)
No explicit restrictions are stated in the specification section.
Clause: nocontext
(Section 9.7.3; p. 371)
No explicit restrictions are stated in the specification section.
Directive/Construct: declare_simd
(Section 9.8; pp. 372–373)
Restrictions to thedeclare_simddirective are as follows:
- The procedure body must be a structured block.
- The execution of the procedure, when called from a SIMD loop, must not result in the execution of any constructs except foratomicconstructs andorderedconstructs on which thesimdclause is specified.
- The execution of the procedure must not have any side effects that would alter its execution for concurrent iterations of a SIMD chunk.
Clause: inbranch
(Section 9.8.1.1; p. 374)
No explicit restrictions are stated in the specification section.
Clause: notinbranch
(Section 9.8.1.2; pp. 375–376)
Restrictions to any declare target directive are as follows:
- The same list item must not explicitly appear in both anenterclause on one declare target directive and alinkorlocalclause on another declare target directive.
- The same list item must not explicitly appear in both alinkclause on one declare target directive and alocalclause on another declare target directive.
- If a variable appears in aenterclause on a declare target directive, its initializer must not refer to a variable that appears in alinkclause on a declare target directive.
Directive/Construct: declare_target
(Section 9.9.1; pp. 377–379)
Restrictions to thedeclare_targetdirective are as follows:
- If theextended-list argument is specified, no clauses may be specified.
- If the directive is not a declaration-associated directive and anextended-list argument is not specified, a data-environment attribute clause must be present.
- A variable for whichnohostis specified must not appear in alinkclause.
- A groupprivate variable must not appear in anyenterclauses orlinkclauses.
Directive/Construct: begin declare_target
(Section 9.9.2; p. 380)
Restrictions to thebegin declare_targetdirective are as follows:
Clause: indirect
(Section 9.9.3; pp. 381–382)
Restrictions to theindirectclause are as follows:
- If invoked-by-fptr evaluates totrue, adevice_typeclause must not appear on the same directive unless it specifiesanyfor itsdevice-type-description.
Directive/Construct: error
(Section 10.1; p. 383)
Restrictions to theerrordirective are as follows:
- The directive is pure only ifaction-time is compilation.
Clause: at
(Section 10.2)
No explicit restrictions are stated in the specification section.
Clause: message
(Section 10.3; p. 384)
- If theaction-time is compilation,msg-stringmust be a constant expression.
Clause: severity
(Section 10.4; p. 385)
No explicit restrictions are stated in the specification section.
Directive/Construct: requires
(Section 10.5; p. 386)
Restrictions to therequiresdirective are as follows:
- Arequiresdirective must appear lexically after the specification of a context selector in which any clause of thatrequiresdirective is used, nor may the directive appear lexically after any code that depends on such a context selector.
Clause: atomic_default_mem_order
(Section 10.5.1.1; p. 387)
Restrictions to theatomic_default_mem_orderclause are as follows:
- All requiresdirectives in the same compilation unit that specify the atomic_default_mem_orderrequirement must specify the same argument.
- Any directive that specifies theatomic_default_mem_orderclause must not appear lexically after anyatomicconstruct on which amemory-order clause is not specified.
Clause: dynamic_allocators
(Section 10.5.1.2; p. 388)
No explicit restrictions are stated in the specification section.
Clause: reverse_offload
(Section 10.5.1.3; p. 389)
No explicit restrictions are stated in the specification section.
Clause: unified_address
(Section 10.5.1.4; p. 390)
No explicit restrictions are stated in the specification section.
Clause: unified_shared_memory
(Section 10.5.1.5; p. 391)
No explicit restrictions are stated in the specification section.
Clause: self_maps
(Section 10.5.1.6; p. 392)
No explicit restrictions are stated in the specification section.
Clause: device_safesync
(Section 10.5.1.7; p. 393)
The restrictions toassumptionclauses are as follows:
- Adirective-namelist item must not specify a directive that is a declarative directive, an informational directive, or a metadirective.
Clause: absent
(Section 10.6.1.1; p. 394)
No explicit restrictions are stated in the specification section.
Clause: contains
(Section 10.6.1.2)
No explicit restrictions are stated in the specification section.
Clause: holds
(Section 10.6.1.3; p. 395)
No explicit restrictions are stated in the specification section.
Clause: no_openmp
(Section 10.6.1.4; p. 396)
No explicit restrictions are stated in the specification section.
Clause: no_openmp_constructs
(Section 10.6.1.5)
No explicit restrictions are stated in the specification section.
Clause: no_openmp_routines
(Section 10.6.1.6; p. 397)
No explicit restrictions are stated in the specification section.
Clause: no_parallelism
(Section 10.6.1.7; p. 398)
No explicit restrictions are stated in the specification section.
Directive/Construct: assumes
(Section 10.6.2; p. 399)
The restrictions to theassumesdirective are as follows:
Directive/Construct: assume
(Section 10.6.3)
No explicit restrictions are stated in the specification section.
Directive/Construct: begin assumes
(Section 10.6.4)
No explicit restrictions are stated in the specification section.
Directive/Construct: nothing
(Section 10.7; pp. 400–402)
- Theapplyclause can be specified if and only if thenothingdirective forms a loop-transforming construct.
Clause: apply
(Section 11.1; pp. 403–404)
Restrictions to theapplyclause are as follows:
- Each list item in theapplied-directiveslist of anyapplyclause must benothingor the directive-specificationof a loop-nest-associated construct.
- The loop-transforming construct on which theapplyclause is specified must either have the generally-composable property or every list item in theapplied-directiveslist of anyapply clause must be thedirective-specificationof a loop-transforming directive.
- Every list item in theapplied-directiveslist of anyapplyclause that is specified on a loop-transforming construct that is itself specified as a list item in theapplied-directiveslist of anotherapplyclause must be thedirective-specificationof a loop-transforming directive.
- For a givenloop-modifier keyword, everyindices list item may appear at most once in any applyclause on the directive.
- Everyindices list item must be a positive constant less than or equal tom, the number of generated loops according to the specification of theloop-modifier keyword.
- The list items inindices must be in ascending order.
- If a directive does not define a defaultloop-modifier keyword, aloop-modifier is required.
Clause: sizes
(Section 11.2)
Restrictions to thesizesclause are as follows:
- The loop nest depth of the associated loop nest of the loop-transforming construct on which the clause is specified must be greater than or equal tom.
Directive/Construct: fuse
(Section 11.3; p. 405)
No explicit restrictions are stated in the specification section.
Directive/Construct: interchange
(Section 11.4; p. 406)
Restrictions to theinterchangeclause are as follows:
- No transformation-affected loops may be a non-rectangular loop.
- The transformation-affected loops must be perfectly nested loops.
Clause: permutation
(Section 11.4.1; p. 407)
Restrictions to thepermutationclause are as follows:
- Every integer from 1 ton must appear exactly once inpermutation-list.
- n must be at least 2.
Directive/Construct: reverse
(Section 11.5)
No explicit restrictions are stated in the specification section.
Directive/Construct: split
(Section 11.6; p. 408)
The following restrictions apply to thesplitconstruct:
- Exactly one list item in thecountsclause must be the predefined identifieromp_fill.
Clause: counts
(Section 11.6.1; p. 409)
Restrictions to thecountsclause are as follows:
- A list item incount-list must be constant oromp_fill.
Directive/Construct: stripe
(Section 11.7; p. 410)
Restrictions to thestripeconstruct are as follows:
- The transformation-affected loops must be perfectly nested loops.
- No transformation-affected loops may be a non-rectangular loop.
Directive/Construct: tile
(Section 11.8; p. 411)
Restrictions to thetileconstruct are as follows:
- The transformation-affected loops must be perfectly nested loops.
- No transformation-affected loops may be a non-rectangular loop.
Directive/Construct: unroll
(Section 11.9; p. 412)
Restrictions to theunrolldirective are as follows:
- Theapplyclause can only be specified if thepartialclause is specified.
Clause: full
(Section 11.9.1; p. 413)
Restrictions to thefullclause are as follows:
- The iteration count of the transformation-affected loop must be constant.
Clause: partial
(Section 11.9.2; p. 414)
No explicit restrictions are stated in the specification section.
Directive/Construct: parallel
(Section 12.1; pp. 415–418)
No explicit restrictions are stated in the specification section.
Clause: num_threads
(Section 12.1.2; pp. 419–422)
No explicit restrictions are stated in the specification section.
Clause: proc_bind
(Section 12.1.4; p. 423)
No explicit restrictions are stated in the specification section.
Clause: safesync
(Section 12.1.5; p. 424)
Restrictions to thesafesyncclause are as follows:
- The widthargument must be asafesync-compatible expression.
Directive/Construct: teams
(Section 12.2; pp. 425–427)
Restrictions to theteamsconstruct are as follows:
- Ifa reduction-modifier isspecifiedina reductionclausethatappearsonthedirectivethen the reduction-modifier must bedefault.
- Ateamsregion must be a strictly nested region of the implicit parallel region that surrounds the whole OpenMP program or atargetregion. If ateamsregion is nested inside a targetregion, the correspondingtargetconstruct must not contain any statements, declarations or directives outside of the correspondingteamsconstruct.
- For ateamsconstruct that is an immediately nested construct of atargetconstruct, the bounds expressions of any array sections and the index expressions of any array elements used in any clause on the construct, as well as all expressions of any target-consistent clauses on the construct, must be target-consistent expressions.
Clause: num_teams
(Section 12.2.1)
- lower-boundmust be less than or equal toupper-bound.
Clause: order
(Section 12.3; pp. 428–429)
Restrictions to theorderclause are as follows:
- The only routines for which a call may be nested inside a region that corresponds to a construct on which theorderclause is specified withconcurrentas theordering argument areorder-concurrent-nestable routines.
- Only regions that correspond toorder-concurrent-nestable constructs or order-concurrent-nestable routines may be strictly nested regions of regions that correspond to constructs on which theorderclause is specified withconcurrentas the orderingargument.
- If a threadprivate variable is referenced inside a region that corresponds to a construct with anorderclause that specifiesconcurrent, the behavior is unspecified.
Directive/Construct: simd
(Section 12.4; p. 430)
Restrictions to thesimdconstruct are as follows:
- If bothsimdlenand safelenclauses are specified, the value of thesimdlenlength must be less than or equal to the value of thesafelenlength.
- Only SIMDizable constructs may be encountered during execution of asimdregion.
- If anorderclause that specifiesconcurrentappears on asimddirective, thesafelen clause must not also appear.
Clause: nontemporal
(Section 12.4.1; p. 431)
No explicit restrictions are stated in the specification section.
Clause: safelen
(Section 12.4.2)
No explicit restrictions are stated in the specification section.
Clause: simdlen
(Section 12.4.3; p. 432)
No explicit restrictions are stated in the specification section.
Directive/Construct: masked
(Section 12.5; p. 433)
No explicit restrictions are stated in the specification section.
Clause: filter
(Section 12.5.1; pp. 434–435)
The following restrictions apply to work-distribution constructs:
- Each work-distribution region must be encountered by all threads in the binding thread set or by none at all unless cancellation has been requested for the innermost enclosing parallel region.
- The sequence of encountered work-distribution regions that have the same binding thread set must be the same for every thread in the binding thread set.
- The sequence of encountered worksharing regions andbarrierregions that bind to the same team must be the same for every thread in the team.
Directive/Construct: single
(Section 13.1; p. 436)
No explicit restrictions are stated in the specification section.
Directive/Construct: scope
(Section 13.2; p. 437)
No explicit restrictions are stated in the specification section.
Directive/Construct: sections
(Section 13.3; p. 438)
No explicit restrictions are stated in the specification section.
Directive/Construct: section
(Section 13.3.1; p. 439)
No explicit restrictions are stated in the specification section.
Directive/Construct: workshare
(Section 13.4; pp. 440–442)
Restrictions to theworkshareconstruct are as follows:
- The only OpenMP constructs that may be closely nested constructs of aworkshare construct are theatomic,critical, andparallelconstructs.
- Base language statements that are encountered inside aworkshareconstruct but that are not enclosed within aparallelor atomicconstruct that is nested inside the workshareconstruct must consist of only the following: – array assignments; – scalar assignments; – FORALLstatements; – FORALLconstructs; – WHEREstatements; – WHEREconstructs; and – BLOCKconstructs that are strictly structured blocks associated with directives.
- All array assignments, scalar assignments, and masked array assignments that are encounteredinsidea workshareconstructbutarenotnestedinsidea parallelconstruct that is nested inside theworkshareconstruct must be intrinsic assignments.
- The construct must not contain any user-defined function calls unless either the function is pure and elemental or the function call is contained inside aparallelconstruct that is nested inside theworkshareconstruct.
Directive/Construct: workdistribute
(Section 13.5; pp. 443–446)
Restrictions to theworkdistributeconstruct are as follows:
- Theworkdistributeconstruct must be a closely nested construct inside ateams construct.
- No explicit region may be nested inside aworkdistributeregion.
- Base language statements that are encountered inside aworkdistributemust consist of only the following: – array assignments; – scalar assignments; and – calls to pure and elemental procedures.
- All array assignments and scalar assignments that are encountered inside a workdistributeconstruct must be intrinsic assignments.
- The construct must not contain any calls to procedures that are not pure and elemental.
- If a threadprivate variable or groupprivate variable is referenced inside a workdistributeregion, the behavior is unspecified.
Directive/Construct: for
(Section 13.6.1; p. 447)
No explicit restrictions are stated in the specification section.
Directive/Construct: do
(Section 13.6.2; p. 448)
No explicit restrictions are stated in the specification section.
Clause: schedule
(Section 13.6.3; pp. 449–450)
Restrictions to thescheduleclause are as follows:
- The scheduleclause cannot be specified if any of the collapsed loops is a non-rectangular loop.
- The value of thechunk_sizeexpression must be the same for all threads in the team.
- If runtimeor autois specified forkind, chunk_sizemust not be specified.
- The nonmonotonicordering-modifier cannot be specified if anorderedclause is specified on the same construct.
Directive/Construct: distribute
(Section 13.7; pp. 451–452)
Restrictions to thedistributeconstruct are as follows:
- The collapsed iteration space must the same for all teams in the league.
- The region that corresponds to thedistributeconstruct must be a strictly nested region of ateamsregion.
- A list item may appear in afirstprivateor lastprivateclause, but not in both.
- The conditionallastprivate-modifier must not be specified.
- All list items that appear in aninductionclause must be private variables in the enclosing context.
Clause: dist_schedule
(Section 13.7.1; p. 453)
Restrictions to thedist_scheduleclause are as follows:
- The value of thechunk_sizeexpression must be the same for all teams in the league.
- The dist_scheduleclause cannot be specified if any of the collapsed loops is a non-rectangular loop.
Directive/Construct: loop
(Section 13.8; p. 454)
Restrictions to theloopconstruct are as follows:
- A list item must not appear in alastprivateclause unless it is the loop-iteration variable of an affected loop.
- Ifa reduction-modifier isspecifiedina reductionclausethatappearsonthedirectivethen the reduction-modifier must bedefault.
- If aloopconstruct is not nested inside another construct then thebindclause must be present.
- If aloopregion binds to ateamsregion or parallel region, it must be encountered by all threads in the binding thread set or by none of them.
Clause: bind
(Section 13.8.1; pp. 455–456)
Restrictions to thebindclause are as follows:
- If teamsis specified asbinding then the correspondingloopregion must be a strictly nested region of ateamsregion.
- If teamsis specified asbinding and the correspondingloopregion executes on a non-host device then the behavior of areductionclause that appears on the correspondingloop construct is unspecified if the construct is not nested inside ateamsconstruct.
- If parallelis specified asbinding, the behavior is unspecified if the correspondingloop region is a closely nested region of asimdregion.
Directive/Construct: task
(Section 14.1; pp. 457–459)
No explicit restrictions are stated in the specification section.
Directive/Construct: taskloop
(Section 14.2; pp. 460–462)
Restrictions to thetaskloopconstruct are as follows:
- Thereduction-modifier must bedefault.
- The conditionallastprivate-modifier must not be specified.
- If thetaskloopconstruct is associated with atask_iterationdirective, none of the taskloop-affected loops may be the generated loop of a loop-transforming construct.
Clause: grainsize
(Section 14.2.1; p. 463)
Restrictions to thegrainsizeclause are as follows:
- None of the collapsed loops may be non-rectangular loops.
Clause: num_tasks
(Section 14.2.2; p. 464)
Restrictions to thenum_tasksclause are as follows:
- None of the collapsed loops may be non-rectangular loops.
Directive/Construct: task_iteration
(Section 14.2.3; p. 465)
The restrictions to thetask_iterationdirective are as follows:
- Eachtask_iterationdirective must appear in the loop body of one of the taskloop-affected loops and must precede all statements and directives (except other task_iterationdirectives) in that loop body.
- If atask_iterationdirective appears in the loop body of one of the taskloop-affected loops, no intervening code may occur between any two collapsed loops of thetaskloop-affected loops.
Directive/Construct: taskgraph
(Section 14.3; pp. 466–468)
Restrictions to thetaskgraphconstruct are as follows:
- Task-generating constructs are the only constructs that may be encountered as part of the taskgraphregion.
- Ataskgraphconstruct must not be encountered in a final task region.
- A replayable construct that generates an importing or exporting transparent task, a detachable task, or an undeferred task must not be encountered in ataskgraphregion.
- Any variable referenced in a replayable construct that does not have static storage duration and that does not exist in the enclosing data environment of thetaskgraphconstruct must be a private-only or firstprivate variable in the replayable construct.
- A list item of a clause on a replayable construct that accepts a locator list and is not a taskgraph-altering clause must have a base variable or base pointer.
- Any variable that appears in an expression of a variable list item or locator list item for a clause on a replayable construct and does not designate the base variable or base pointer of that list item must be listed in a data-environment attribute clause with thesaved modifier on that construct.
- If a construct that permits thenogroupclause is encountered in ataskgraphregion then the nogroupclause must be specified with thedo_not_synchronizeargument evaluating to true.
Clause: graph_id
(Section 14.3.1)
No explicit restrictions are stated in the specification section.
Clause: graph_reset
(Section 14.3.2; p. 469)
No explicit restrictions are stated in the specification section.
Clause: untied
(Section 14.4; p. 470)
No explicit restrictions are stated in the specification section.
Clause: mergeable
(Section 14.5)
No explicit restrictions are stated in the specification section.
Clause: replayable
(Section 14.6; p. 471)
No explicit restrictions are stated in the specification section.
Clause: final
(Section 14.7; p. 472)
No explicit restrictions are stated in the specification section.
Clause: threadset
(Section 14.8; p. 473)
No explicit restrictions are stated in the specification section.
Clause: priority
(Section 14.9; p. 474)
No explicit restrictions are stated in the specification section.
Clause: affinity
(Section 14.10; p. 475)
No explicit restrictions are stated in the specification section.
Clause: detach
(Section 14.11; p. 476)
Restrictions to thedetachclause are as follows:
- Ifa detachclauseappearsonadirective,thentheencounteringtaskmustnotbeafinaltask.
- A variable that appears in adetachclause cannot appear as a list item on any data-environment attribute clause on the same construct.
- A variable that is part of an aggregate variable cannot appear in adetachclause.
Directive/Construct: taskyield
(Section 14.12; pp. 477–480)
No explicit restrictions are stated in the specification section.
Clause: device_type
(Section 15.1; p. 481)
No explicit restrictions are stated in the specification section.
Clause: device
(Section 15.2; p. 482)
- The ancestordevice-modifier must not appear on thedeviceclause on any directive other than thetargetconstruct.
- If theancestordevice-modifier is specified, thedevice-descriptionmust evaluate to 1 and a requiresdirective with thereverse_offloadclause must be specified;
- If thedevice_numdevice-modifier is specified andtarget-offload-varis notmandatory, device-descriptionmust evaluate to a conforming device number.
Clause: thread_limit
(Section 15.3; pp. 483–484)
Restrictions to OpenMP device initialization are as follows:
- No thread may offload execution of a construct to a device until a dispatched device_initializecallback completes.
- No thread may offload execution of a construct to a device after a dispatched device_finalizecallback occurs.
Directive/Construct: target_enter_data
(Section 15.5; pp. 485–486)
Restrictions to thetarget_enter_dataconstruct are as follows:
- At least onemapclause must appear on the directive.
- All mapclauses must be map-entering clauses.
Directive/Construct: target_exit_data
(Section 15.6; pp. 487–488)
Restrictions to thetarget_exit_dataconstruct are as follows:
- At least onemapclause must appear on the directive.
- All mapclauses must be map-exiting clauses.
Directive/Construct: target_data
(Section 15.7; pp. 489–490)
No explicit restrictions are stated in the specification section.
Directive/Construct: target
(Section 15.8; pp. 491–495)
Restrictions to thetargetconstruct are as follows:
- Device-affecting constructs, other thantargetconstructs for which theancestor device-modifier is specified, must not be encountered during execution of atargetregion.
- The result of anomp_set_default_device,omp_get_default_device, or omp_get_num_devicesroutine called within atargetregion is unspecified.
- The effect of an access to a threadprivate variable in atargetregion is unspecified.
- If a list item in amapclause is a structure element, any other element of that structure that is referenced in thetargetconstruct must also appear as a list item in amapclause.
- A list item in amapclause that is specified on atargetconstruct must have a base variable or base pointer.
Directive/Construct: target_update
(Section 15.9; pp. 496–498)
No explicit restrictions are stated in the specification section.
Directive/Construct: interop
(Section 16.1; p. 499)
Restrictions to theinteropconstruct are as follows:
- Adependclause must only appear on the directive if theinterop-typeincludes targetsync.
- An interoperability object must not be specified in more than oneaction-clause that appears on theinteropconstruct.
Clause: use
(Section 16.1.2; pp. 500–502)
- The state ofinterop-varmust beinitialized.
Clause: hint
(Section 17.1; p. 503)
- hint-expr must evaluate to a valid synchronization hint.
Directive/Construct: critical
(Section 17.2; pp. 504–505)
Restrictions to thecriticalconstruct are as follows:
- Unlessomp_sync_hint_noneis specified in ahintclause, thecriticalconstruct must specify a name.
- Thehint-expr that is specified in thehintclause on eachcriticalconstruct with the same namemust evaluate to the same value.
- Acriticalregion must not be nested (closely or otherwise) inside acriticalregion with the samename. This restriction is not sufficient to prevent deadlock.
Directive/Construct: barrier
(Section 17.3.1; pp. 506–508)
Restrictions to thebarrierconstruct are as follows:
- Eachbarrierregion must be encountered by all threads in a team or by none at all, unless cancellation has been requested for the innermost enclosing parallel region.
- The sequence of worksharing regions andbarrierregions encountered must be the same for every thread in a team.
Directive/Construct: taskgroup
(Section 17.4; p. 509)
No explicit restrictions are stated in the specification section.
Directive/Construct: taskwait
(Section 17.5; pp. 510–511)
Restrictions to thetaskwaitconstruct are as follows:
- The mutexinoutsettask-dependence-typemay not appear in adependclause on a taskwaitconstruct.
Clause: nowait
(Section 17.6; pp. 512–513)
Restrictions to thenowaitclause are as follows:
- Thedo_not_synchronizeargument must evaluate to the same value for all threads in the binding thread set, if defined for the construct on which thenowaitclause appears.
- Thedo_not_synchronizeargument must evaluate to the same value for all tasks in the binding task set, if defined for the construct on which thenowaitclause appears.
Clause: nogroup
(Section 17.7; p. 514)
No explicit restrictions are stated in the specification section.
Clause: acq_rel
(Section 17.8.1.1; p. 515)
No explicit restrictions are stated in the specification section.
Clause: acquire
(Section 17.8.1.2; p. 516)
No explicit restrictions are stated in the specification section.
Clause: relaxed
(Section 17.8.1.3)
No explicit restrictions are stated in the specification section.
Clause: release
(Section 17.8.1.4; p. 517)
No explicit restrictions are stated in the specification section.
Clause: seq_cst
(Section 17.8.1.5; p. 518)
No explicit restrictions are stated in the specification section.
Clause: read
(Section 17.8.2.1; p. 519)
No explicit restrictions are stated in the specification section.
Clause: write
(Section 17.8.2.3; p. 520)
Restrictions to theextended-atomicclause group are as follows:
- The compareclause may not be specified such thatuse_semantics evaluates tofalseif the weakclause is specified such thatuse_semantics evaluates totrue.
Clause: capture
(Section 17.8.3.1; p. 521)
No explicit restrictions are stated in the specification section.
Clause: compare
(Section 17.8.3.2; p. 522)
No explicit restrictions are stated in the specification section.
Clause: fail
(Section 17.8.3.3)
Restrictions to thefailclause are as follows:
- memorder may not beacq_relor release.
Clause: weak
(Section 17.8.3.4; p. 523)
No explicit restrictions are stated in the specification section.
Clause: memscope
(Section 17.8.4; p. 524)
The restrictions for thememscopeclause are as follows:
- The binding thread set defined by thescope-specifier of thememscopeclause on an atomicconstruct must be a subset of the atomic scope of the atomically accessed memory.
- The binding thread set defined by thescope-specifier of thememscopeclause on an atomicconstruct must be a subset of all threads that are executing tasks in the contention group if the size of the atomically accessed storage location is not 8, 16, 32, or 64 bits.
Directive/Construct: atomic
(Section 17.8.5; pp. 525–528)
Restrictions to theatomicconstruct are as follows:
- Constructs may not be encountered during execution of anatomicregion.
- If acaptureor compareclause is specified, theatomicclause must beupdate.
- If acaptureclause is specified but thecompareclause is not specified, an update-capture structured block must be associated with the construct.
- If bothcaptureand compareclauses are specified, a conditional-update-capture structured block must be associated with the construct.
- If acompareclause is specified but thecaptureclause is not specified, a conditional-update structured block must be associated with the construct.
- Ifa writeclauseisspecified, awritestructuredblockmustbeassociatedwiththeconstruct.
- If areadclause is specified, a read structured block must be associated with the construct.
- If theatomicclause isreadthen thememory-order clause must not berelease.
- If theatomicclause iswritethen thememory-order clause must not beacquire.
- Theweakclause may only appear if the resulting atomic operation is an atomic conditional update for which the comparison tests for equality.
Directive/Construct: flush
(Section 17.8.6; pp. 529–535)
Restrictions to theflushconstruct are as follows:
- If amemory-order clause is specified, thelist argument must not be specified.
- Thememory-order clause must not berelaxed.
Directive/Construct: depobj
(Section 17.9.3; p. 536)
No explicit restrictions are stated in the specification section.
Clause: update
(Section 17.9.4; p. 537)
Restrictions to theupdateclause are as follows:
- task-dependence-typemust not bedepobj.
- The state ofupdate-var must beinitialized.
- If the locator list item represented byupdate-var is theomp_all_memoryreserved locator, task-dependence-typemust be eitheroutor inout.
Clause: depend
(Section 17.9.5; pp. 538–540)
Restrictions to thedependclause are as follows:
- List items, other than reserved locators, used independclauses of the same task or dependence-compatible tasks must indicate identical storage locations or disjoint storage locations.
- List items used independclauses cannot be zero-length array sections.
- Theomp_all_memoryreserved locator can only be used in adependclause with anout or inouttask-dependence-type.
- Array sections cannot be specified independclauses with thedepobj task-dependence-type.
- List items used independclauses with thedepobjtask-dependence-typemust be expressions of thedependOpenMP type that correspond to depend objects in theinitialized state.
- List items that are expressions of thedependOpenMP type can only be used independ clauses with thedepobjtask-dependence-type.
Clause: transparent
(Section 17.9.6; p. 541)
No explicit restrictions are stated in the specification section.
Clause: doacross
(Section 17.9.7; pp. 542–544)
Restrictions to thedoacrossclause are as follows:
- If iteration-specifier is a loop-iteration vector that hasn elements, the innermost loop-nest-associated construct that encloses the construct on which the clause appears must specify anorderedclause for which the parameter value equalsn.
- If iteration-specifier is specified with theomp_cur_iterationkeyword and withsink as thedependence-type then it must beomp_cur_iteration- 1.
- If iteration-specifier is specified withsourceas thedependence-typethen it must be omp_cur_iteration.
- If iteration-specifier is a loop-iteration vector and thesinkdependence-typeis specified then for each element, if the loop-iteration variablevari has an integral or pointer type, theith expression of vector must be computable without overflow in that type for any value of vari that can encounter the construct on which the doacross clause appears. C++
- If iteration-specifier is a loop-iteration vector and thesinkdependence-typeis specified then for each element, if the loop-iteration variablevari is of a random access iterator type other than pointer type, theith expression of vector must be computable without overflow in the type that would be used by std::distance applied to variables of the type of vari for any value of vari that can encounter the construct on which the doacross clause appears. C++
Directive/Construct: ordered
(Section 17.10.2; pp. 546–547)
Additional restrictions to the block-associatedorderedconstruct are as follows:
- The construct is SIMDizable only if thesimdparallelization-levelclause is specified.
- If thesimdparallelization-levelclause is specified, the binding region must correspond to a construct for which thesimdconstruct is a leaf construct.
- If thethreadsparallelization-levelclause is specified, the binding region must correspond to a construct for which a worksharing-loop construct is a leaf construct.
- If thethreadsparallelization-levelclause is specified and the binding region corresponds to a compound construct then thesimdconstruct must not be a leaf construct unless the simdparallelization-levelclause is also specified.
- During execution of the collapsed iteration associated with a loop-nest-associated directive, a thread must not execute more than one block-associatedorderedregion that binds to the corresponding region of the loop-nest-associated directive.
- An orderedclause with an argument value equal to the number of collapsed loops must appear on the construct that corresponds to the binding region, if the binding region is not a simdregion.
Clause: threads
(Section 17.10.3.1; p. 548)
No explicit restrictions are stated in the specification section.
Clause: simd
(Section 17.10.3.2; pp. 549–550)
Restrictions to any clauses in thecancel-directive-nameclause group are as follows:
- Ifapply_to_directiveevaluates tofalseand anifclause is specified for the same constituent construct, if-expressionmust evaluate tofalse.
Directive/Construct: cancel
(Section 18.2; pp. 551–554)
Restrictions to thecancelconstruct are as follows:
- The behavior for concurrent cancellation of a region and a region nested within it is unspecified.
- Ifcancel-directive-nameis taskgroup, thecancelconstruct must be a closely nested construct of ataskor ataskloopconstruct and thecancelregion must be a closely nested region of ataskgroupregion.
- Ifcancel-directive-nameis nottaskgroup, thecancelconstruct must be a closely nested construct of a construct that matchescancel-directive-name.
Directive/Construct: cancellation_point
(Section 18.3; pp. 555–556)
Restrictions to thecancellation pointconstruct are as follows:
- Acancellation_pointconstruct for whichcancel-directive-nameis taskgroup must be a closely nested construct of ataskor taskloopconstruct, and the cancellation_pointregion must be a closely nested region of ataskgroupregion.
- Acancellation_pointconstruct for whichcancel-directive-nameis nottaskgroup must be a closely nested construct inside a construct that matchescancel-directive-name.
Line Continuations
⚠️ Experimental: ROUP now understands multi-line OpenMP directives across C, C++, and Fortran. This guide shows how to format continuations so the parser and ompparser compatibility layer recognize them reliably.
When to use continuations
OpenMP pragmas often grow long once multiple clauses are attached. Rather than forcing everything onto a single line, you can split directives while keeping source files readable. ROUP stitches the continued lines together during lexing, so downstream APIs still observe canonical single-line directive strings.
Continuations are supported in two situations:
- C / C++ pragmas that end a line with a trailing backslash (
\
). - Fortran sentinels (
!$OMP
,C$OMP
,*$OMP
) that use the standard ampersand (&
) continuation syntax.
ROUP preserves clause order and trims whitespace that was introduced only to align indentation.
C / C++ example
#pragma omp parallel for \
schedule(dynamic, 4) \
private(i, \
j)
ROUP merges this directive into #pragma omp parallel for schedule(dynamic, 4) private(i, j)
. Clause arguments keep their
original spacing. Comments (/* */
or //
) may appear between continued lines and are ignored during merging.
Tips for C / C++
- The backslash must be the final character on the line (aside from trailing spaces or tabs).
- Windows line endings (
\r\n
) are handled automatically. - Keep at least one space between the directive name and the first clause on subsequent lines.
Fortran free-form example
!$omp target teams distribute &
!$omp parallel do &
!$omp& private(i, j)
The parser removes the continuation markers and produces !$omp target teams distribute parallel do private(i, j)
.
Fortran fixed-form example
C$OMP DO &
!$OMP& SCHEDULE(DYNAMIC) &
!$OMP PRIVATE(I) SHARED(A)
Column prefixes (!
, C
, or *
) are respected. ROUP normalizes the directive to do schedule(DYNAMIC) private(I) shared(A)
.
Tips for Fortran continuations
- Terminate every continued line with
&
. ROUP tolerates trailing comments (e.g.,& ! explanation
) and skips them automatically. - You may repeat the sentinel on continuation lines (
!$OMP&
), or start the next line with only&
. Both forms are accepted. - Blank continuation lines are ignored as long as they contain only whitespace.
- Clause bodies can span multiple lines; nested continuations inside parentheses are collapsed to a single line in the parsed clause value.
Troubleshooting
- Missing continuation marker: If a line break appears without
&
(Fortran) or\
(C/C++), the parser treats the next line as a separate statement and reports an error or unexpected directive name. - Custom formatting macros: Preprocessors that insert trailing spaces after
\
may break continuations. Ensure the backslash is the final printable character. - Compatibility layer: The ompparser shim mirrors the same behavior. The comprehensive tests in
compat/ompparser/tests/comprehensive_test.cpp
include multi-line inputs for both languages.
For more examples, refer to the automated tests in tests/openmp_line_continuations.rs
and the parser unit tests in
src/parser/mod.rs
.
Architecture
This document explains ROUP's internal design, from lexical analysis to the C FFI boundary.
Overview
ROUP is structured in three main layers:
┌─────────────────────────────────────┐
│ C/C++ Applications │
├─────────────────────────────────────┤
│ C FFI Layer (16 functions) │ ← ~60 lines of unsafe code (0.9%)
├─────────────────────────────────────┤
│ Rust API (Parser + IR) │ ← 100% safe Rust
├─────────────────────────────────────┤
│ Lexer (nom-based) │ ← Token extraction
└─────────────────────────────────────┘
```text
**Key Design Principles:**
- **Safety First**: 99.1% safe Rust code
- **Zero-Copy**: Minimal allocations during parsing
- **Error Recovery**: Detailed error messages with location info
- **Language Agnostic**: Supports C, C++, and Fortran
---
## Lexer Layer
**Location**: `src/lexer.rs`
The lexer transforms raw OpenMP pragma text into a stream of tokens.
### Tokenization Process
```rust
Input: "#pragma omp parallel num_threads(4)"
↓
Tokens: [
Pragma("#pragma omp"),
Identifier("parallel"),
Identifier("num_threads"),
LParen,
Integer(4),
RParen
]
```text
### Token Types
```rust
pub enum Token<'a> {
Identifier(&'a str), // parallel, private, shared
Integer(i64), // 4, 100, 256
Float(f64), // 2.5, 1.0e-6
String(&'a str), // "filename.txt"
LParen, // (
RParen, // )
Comma, // ,
Colon, // :
Plus, // +
Minus, // -
Star, // *
// ... more operators
}
```text
### Lexer Implementation
**Technology**: Built with [nom](https://github.com/rust-bakery/nom) parser combinators
**Why nom?**
- **Zero-copy**: Works directly on input &str, no allocations
- **Composable**: Small parsers combine into larger ones
- **Error-rich**: Detailed error messages with position
- **Well-established**: Widely used parser combinator library
**Example Lexer Function:**
```rust
// Parse an identifier: alphanumeric + underscores
fn identifier(input: &str) -> IResult<&str, Token> {
let (remaining, matched) = take_while1(|c: char| {
c.is_alphanumeric() || c == '_'
})(input)?;
Ok((remaining, Token::Identifier(matched)))
}
```text
---
## Parser Layer
**Location**: `src/parser/`
The parser converts token streams into a structured Intermediate Representation (IR).
### Parser Modules
```text
src/parser/
├── mod.rs # Main parser entry point
├── directive.rs # Directive parsing (parallel, for, task, etc.)
├── clause.rs # Clause parsing (private, reduction, etc.)
└── openmp.rs # OpenMP-specific parsing logic
```text
### Parsing Phases
#### Phase 1: Directive Recognition
```rust
Input tokens: [Identifier("parallel"), Identifier("for"), ...]
↓
Directive: DirectiveKind::ParallelFor
```text
Supports 120+ directive types from OpenMP 3.0 through 6.0.
#### Phase 2: Clause Parsing
```rust
Input tokens: [Identifier("num_threads"), LParen, Integer(4), RParen]
↓
Clause: Clause::NumThreads(IntegerExpr(4))
```text
Parses 92+ clause types with full argument validation.
#### Phase 3: IR Construction
```rust
DirectiveIR {
kind: DirectiveKind::ParallelFor,
clauses: vec![
Clause::NumThreads(IntegerExpr(4)),
Clause::Private(vec!["i", "j"]),
],
location: SourceLocation { line: 1, column: 1 },
language: Language::C,
}
```text
### Error Handling
Errors include detailed context:
```rust
ParseError {
message: "Expected ')' after num_threads value",
location: SourceLocation { line: 1, column: 27 },
context: "#pragma omp parallel num_threads(4",
^
}
```text
---
## Intermediate Representation (IR)
**Location**: `src/ir/`
The IR is the central data structure representing parsed OpenMP directives.
### IR Structure
```rust
pub struct DirectiveIR {
pub kind: DirectiveKind, // What directive?
pub clauses: Vec<Clause>, // What clauses?
pub location: SourceLocation, // Where in source?
pub language: Language, // C, C++, or Fortran?
}
```text
### Directive Kinds
```rust
pub enum DirectiveKind {
// Parallel constructs
Parallel,
ParallelFor,
ParallelSections,
// Work-sharing
For,
Sections,
Section,
Single,
// Tasking
Task,
TaskLoop,
TaskWait,
TaskGroup,
// Device offloading
Target,
TargetData,
TargetUpdate,
Teams,
// Synchronization
Barrier,
Critical,
Atomic,
Ordered,
// SIMD
Simd,
DeclareSimd,
// Advanced (OpenMP 5.0+)
Metadirective,
DeclareVariant,
Loop,
// ... 120+ total directives
}
```text
### Clause Types
```rust
pub enum Clause {
// Thread management
NumThreads(IntegerExpr),
If(Condition),
// Data sharing
Private(Vec<Variable>),
Shared(Vec<Variable>),
FirstPrivate(Vec<Variable>),
LastPrivate(Vec<Variable>),
// Reductions
Reduction {
operator: ReductionOperator,
variables: Vec<Variable>,
},
// Scheduling
Schedule {
kind: ScheduleKind,
chunk_size: Option<IntegerExpr>,
},
// Loop control
Collapse(usize),
Ordered,
Nowait,
// Defaults
Default(DefaultKind),
// ... 92+ total clauses
}
```text
### Supporting Types
```rust
pub enum ScheduleKind {
Static,
Dynamic,
Guided,
Auto,
Runtime,
}
pub enum ReductionOperator {
Add, // +
Subtract, // -
Multiply, // *
BitAnd, // &
BitOr, // |
BitXor, // ^
LogicalAnd, // &&
LogicalOr, // ||
Min,
Max,
}
pub enum DefaultKind {
Shared,
None,
Private,
FirstPrivate,
}
pub enum Language {
C,
Cpp,
Fortran,
}
```text
---
## C FFI Layer
**Location**: `src/c_api.rs`
The FFI layer exposes a minimal unsafe pointer-based API to C/C++.
### Design Philosophy
**Goal**: Provide a traditional C API (malloc/free pattern) with minimal unsafe code.
**Achieved**:
- **16 functions**: Complete C API surface
- **~60 lines of unsafe**: Only at FFI boundary (~0.9% of file)
- **Standard patterns**: Familiar to C programmers
- **Safe internals**: All business logic in safe Rust
### FFI Functions
#### Lifecycle Functions (3)
```c
// Parse directive, returns pointer or NULL
OmpDirective* roup_parse(const char* input);
// Free directive (required)
void roup_directive_free(OmpDirective* directive);
// Free clause (not usually needed - owned by directive)
void roup_clause_free(OmpClause* clause);
```text
#### Directive Query Functions (3)
```c
// Get directive type (integer)
int32_t roup_directive_kind(const OmpDirective* directive);
// Get number of clauses
int32_t roup_directive_clause_count(const OmpDirective* directive);
// Create iterator over clauses
OmpClauseIterator* roup_directive_clauses_iter(const OmpDirective* directive);
```text
#### Iterator Functions (2)
```c
// Get next clause (returns 1 if available, 0 if done)
int32_t roup_clause_iterator_next(OmpClauseIterator* iter, OmpClause** out);
// Free iterator
void roup_clause_iterator_free(OmpClauseIterator* iter);
```text
#### Clause Query Functions (4)
```c
// Get clause type (0=num_threads, 2=private, etc.)
int32_t roup_clause_kind(const OmpClause* clause);
// Get schedule kind for schedule clauses
int32_t roup_clause_schedule_kind(const OmpClause* clause);
// Get reduction operator for reduction clauses
int32_t roup_clause_reduction_operator(const OmpClause* clause);
// Get default data sharing
int32_t roup_clause_default_data_sharing(const OmpClause* clause);
```text
#### Variable List Functions (4)
```c
// Get variable list from clause
OmpStringList* roup_clause_variables(const OmpClause* clause);
// Get list length
int32_t roup_string_list_len(const OmpStringList* list);
// Get string at index
const char* roup_string_list_get(const OmpStringList* list, int32_t index);
// Free string list
void roup_string_list_free(OmpStringList* list);
```text
### Memory Model
**Ownership Rules:**
1. **Directives**: Created by `roup_parse()`, freed by `roup_directive_free()`
2. **Iterators**: Created by `roup_directive_clauses_iter()`, freed by `roup_clause_iterator_free()`
3. **String Lists**: Created by `roup_clause_variables()`, freed by `roup_string_list_free()`
4. **Clauses**: Owned by directive, DO NOT call `roup_clause_free()` on them
**Pattern**: Standard C malloc/free, familiar to all C programmers.
### Safety Boundaries
#### The ~60 Lines of Unsafe
All unsafe code is confined to FFI boundary operations:
**1. Reading C Strings (2 places)**
```rust
// Safety: Caller must ensure input is valid null-terminated C string
unsafe {
CStr::from_ptr(input).to_str()
}
```text
**Checks:**
- ✅ NULL pointer check before unsafe
- ✅ UTF-8 validation with error return
- ✅ No memory writes, only reads
**2. Writing to Output Pointers (multiple places)**
```rust
// Safety: Caller must ensure out is valid, aligned, writable
unsafe {
*out = value;
}
```text
**Checks:**
- ✅ NULL pointer check before unsafe
- ✅ Only writes primitive types (i32, u32, pointers)
- ✅ Single write operation, no loops
**3. Pointer Manipulation for Iterators**
```rust
// Safety: Internal Box pointer management
unsafe {
Box::from_raw(ptr)
}
```text
**Checks:**
- ✅ NULL pointer check
- ✅ Pointer created by Box::into_raw()
- ✅ No double-free (consumed on free)
### Why Minimal Unsafe is Necessary
**Cannot avoid unsafe for FFI:**
- Reading C strings requires `CStr::from_ptr()` (unsafe)
- Writing to C pointers requires dereference (unsafe)
- This is standard Rust FFI practice
**Alternative approaches considered:**
❌ **Zero unsafe**: Would require C programs to build strings byte-by-byte (40x slower, unusable)
❌ **Handle-based API**: Would need global registry with more unsafe code (50+ blocks)
✅ **Minimal unsafe pointer API**: Only ~60 lines, standard C patterns, practical performance
See [AGENTS.md](https://github.com/ouankou/roup/blob/main/AGENTS.md) for the official API architecture documentation.
---
## Data Flow Example
Let's trace a complete parse operation:
### Input
```c
const char* input = "#pragma omp parallel for num_threads(4) private(i)";
OmpDirective* dir = roup_parse(input);
```text
### Step 1: FFI Boundary (C → Rust)
```rust
// src/c_api.rs
#[no_mangle]
pub extern "C" fn roup_parse(input: *const c_char) -> *mut OmpDirective {
// NULL check
if input.is_null() {
return std::ptr::null_mut();
}
// Read C string (unsafe #1)
let rust_str = unsafe {
CStr::from_ptr(input).to_str().ok()?
};
// Call safe parser
let directive_ir = parser::parse(rust_str).ok()?;
// Box and return pointer
Box::into_raw(Box::new(directive_ir))
}
```text
### Step 2: Lexer (Pure Rust)
```rust
// src/lexer.rs
tokenize("#pragma omp parallel for num_threads(4) private(i)")
↓
[
Pragma("#pragma omp"),
Identifier("parallel"),
Identifier("for"),
Identifier("num_threads"),
LParen,
Integer(4),
RParen,
Identifier("private"),
LParen,
Identifier("i"),
RParen,
]
```text
### Step 3: Parser (Pure Rust)
```rust
// src/parser/mod.rs
parse_directive(tokens)
↓
DirectiveIR {
kind: DirectiveKind::ParallelFor,
clauses: vec![
Clause::NumThreads(IntegerExpr(4)),
Clause::Private(vec!["i"]),
],
location: SourceLocation { line: 1, column: 1 },
language: Language::C,
}
```text
### Step 4: FFI Boundary (Rust → C)
```rust
// Return pointer to C
Box::into_raw(Box::new(directive_ir)) → 0x7fff12340000
```text
### Step 5: C Queries
```c
int32_t kind = roup_directive_kind(dir); // 28 (ParallelFor)
int32_t count = roup_directive_clause_count(dir); // 2
```text
### Step 6: Cleanup
```c
roup_directive_free(dir); // Calls Box::from_raw() and drops
```text
---
## Performance Characteristics
### Time Complexity
- **Lexing**: O(n) where n = input length
- **Parsing**: O(n × m) where m = average clause complexity (~O(n) in practice)
- **IR Construction**: O(c) where c = number of clauses
- **FFI Call Overhead**: ~10ns per call
### Space Complexity
- **Lexer**: O(1) - zero-copy, works on &str
- **Parser**: O(c) - allocates clause vector
- **IR**: O(c) - owns clause data
- **FFI**: O(1) - pointer conversion only
### Benchmarks
Typical directive parsing:
| Directive | Time | Allocations |
|-----------|------|-------------|
| `#pragma omp parallel` | ~500ns | 1 (DirectiveIR) |
| `#pragma omp parallel for num_threads(4)` | ~800ns | 2 (DirectiveIR + 1 clause) |
| `#pragma omp parallel for private(i,j,k) reduction(+:sum)` | ~1.2µs | 3 (DirectiveIR + 2 clauses) |
**Compare to old handle-based API**: 40x fewer FFI calls, 320x faster string building.
---
## Thread Safety
### Safe Concurrency
**Parser**: Thread-safe, can parse from multiple threads simultaneously
```rust
// Safe to do in parallel
std::thread::spawn(|| {
let dir1 = parse("#pragma omp parallel");
});
std::thread::spawn(|| {
let dir2 = parse("#pragma omp for");
});
```text
**IR**: Immutable after construction, safe to share across threads
**FFI**: Each directive is independent, safe to parse in parallel
### Unsafe Patterns (User Responsibility)
❌ **Sharing directive across threads without synchronization**
```c
// Thread 1
roup_directive_free(dir);
// Thread 2 (at same time)
roup_directive_kind(dir); // Use-after-free!
```text
❌ **Double-free**
```c
roup_directive_free(dir);
roup_directive_free(dir); // Undefined behavior!
```text
✅ **Safe multi-threaded usage**
```c
// Each thread has its own directive
OmpDirective* dir1 = roup_parse("#pragma omp parallel"); // Thread 1
OmpDirective* dir2 = roup_parse("#pragma omp for"); // Thread 2
```text
---
## Error Handling Strategy
### Rust API
Uses `Result<DirectiveIR, ParseError>`:
```rust
match parse(input) {
Ok(directive) => { /* use directive */ },
Err(ParseError { message, location, .. }) => {
eprintln!("Parse error at line {}: {}", location.line, message);
}
}
```text
### C API
Uses `NULL` return values:
```c
OmpDirective* dir = roup_parse(input);
if (dir == NULL) {
fprintf(stderr, "Parse failed\n");
return 1;
}
```text
**Query functions**: Return `-1` or safe defaults for NULL inputs
```c
int32_t kind = roup_directive_kind(NULL); // Returns -1, won't crash
```text
---
## Testing Strategy
### Test Coverage
```text
Total Tests: 352
Unit Tests: 239
Integration: 51
Doc Tests: 62
```text
### Test Categories
1. **Lexer Tests**: Token extraction, edge cases, Unicode
2. **Parser Tests**: Directive recognition, clause parsing, error cases
3. **IR Tests**: Structure validation, roundtrip serialization
4. **FFI Tests**: NULL handling, memory safety, error propagation
5. **Concurrent Tests**: Multi-threaded parsing, race detection
### Example Tests
```rust
#[test]
fn test_parallel_for_parsing() {
let result = parse("#pragma omp parallel for num_threads(4)");
assert!(result.is_ok());
let directive = result.unwrap();
assert_eq!(directive.kind, DirectiveKind::ParallelFor);
assert_eq!(directive.clauses.len(), 1);
match &directive.clauses[0] {
Clause::NumThreads(IntegerExpr(4)) => {},
_ => panic!("Expected NumThreads(4)"),
}
}
#[test]
fn test_ffi_null_safety() {
let dir = roup_parse(std::ptr::null());
assert!(dir.is_null());
let kind = roup_directive_kind(std::ptr::null());
assert_eq!(kind, -1);
}
```text
---
## Design Trade-offs
### Lexer: nom vs Custom
**Chose nom:**
- ✅ Zero-copy parsing
- ✅ Rich error messages
- ✅ Well-tested combinators
- ✅ Easy to extend
**vs Custom Lexer:**
- ❌ Learning curve
- ❌ Dependency on external crate
### IR: Owned vs Borrowed
**Chose owned (Vec, String):**
- ✅ Simple lifetime management
- ✅ Easy to pass across FFI
- ✅ No lifetime annotations in IR
**vs Borrowed (&str slices):**
- ❌ Slower (allocations)
- ❌ More memory usage
**Justification**: Parsing is not the bottleneck; simplicity and FFI compatibility matter more.
### FFI: Pointers vs Handles
**Chose pointers:**
- ✅ Standard C pattern (malloc/free)
- ✅ Minimal unsafe (~60 lines)
- ✅ Zero overhead
- ✅ Familiar to C programmers
**vs Handle-based:**
- ❌ 40x more FFI calls
- ❌ 50+ unsafe blocks
- ❌ Global registry complexity
See [AGENTS.md - C FFI API Architecture](https://github.com/ouankou/roup/blob/main/AGENTS.md#c-ffi-api-architecture) for details.
---
## Future Architecture Considerations
### Potential Enhancements
1. **Incremental Parsing**: Parse only changed directives
2. **Streaming API**: Parse large files without loading into memory
3. **Parallel Parsing**: Parse multiple files concurrently
4. **AST Transformation**: Optimize or transform directives
5. **Code Generation**: Generate code from IR
### Stability Guarantees
**⚠️ Pre-1.0 Experimental Status:**
ROUP is under active development. While we aim for stability, **all APIs may change** before v1.0.
**More stable** (unlikely to change much):
- Core parsing functionality (`parse()` pattern)
- C FFI function signatures (16 functions)
- IR structure (major fields)
**Less stable** (may change between versions):
- Internal parser implementation details
- Lexer token types and error structures
- Error message formatting
- Clause/directive kind integer values
- Specific API details and return types
---
## Summary
ROUP's architecture prioritizes:
1. **Safety**: 99.1% safe Rust, minimal unsafe only at FFI boundary
2. **Performance**: Zero-copy lexing, minimal allocations
3. **Usability**: Standard C patterns, clear error messages
4. **Correctness**: 352 tests, comprehensive OpenMP support
The three-layer design (Lexer → Parser → FFI) provides a clean separation of concerns while maintaining excellent performance characteristics.
**Key Metrics:**
- 16 FFI functions
- ~60 lines of unsafe code (0.9%)
- 95 directives
- 91 clauses
- 352 tests
- ~500ns to parse simple directive
For implementation details, see the source code in `src/`.
Contributing Guide
Thank you for your interest in contributing to ROUP! This guide will help you get started.
Quick Links
- Source Code: github.com/ouankou/roup
- Issue Tracker: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: roup.ouankou.com
Ways to Contribute
1. Report Bugs
Found a bug? Please open an issue with:
- Clear title: What's wrong?
- Input: The OpenMP directive that caused the issue
- Expected: What should happen?
- Actual: What actually happened?
- Environment: OS, Rust version, ROUP version
Example:
Title: Parser fails on `collapse` clause with variable
Input: #pragma omp for collapse(n)
Expected: Parse successfully
Actual: Parse error: "Expected integer literal"
Environment: Ubuntu 22.04, Rust 1.75, ROUP 0.1.0
```text
### 2. Suggest Features
Have an idea? [Start a discussion](https://github.com/ouankou/roup/discussions) or open an issue with:
- **Use case**: Why is this needed?
- **Proposed API**: How would it work?
- **Alternatives**: Other ways to solve the problem?
### 3. Improve Documentation
Documentation improvements are always welcome:
- Fix typos or unclear explanations
- Add examples
- Improve error messages
- Translate documentation
- Write tutorials or blog posts
See [Documentation Updates](#documentation-updates) below.
### 4. Submit Code
Ready to code? See [Development Setup](#development-setup) and [Pull Request Process](#pull-request-process).
---
## Development Setup
### Prerequisites
- **Rust 1.70+** - [Install Rust](https://rustup.rs/)
- **Git** - Version control
- **mdBook** (optional) - For documentation: `cargo install mdbook`
### Clone and Build
```bash
# Clone repository
git clone https://github.com/ouankou/roup.git
cd roup
# Build library
cargo build
# Run tests
cargo test
# Build documentation
cargo doc --no-deps --open
```text
### Development Tools
**Recommended VS Code Extensions:**
- rust-analyzer
- Even Better TOML
- Error Lens
**Recommended CLI Tools:**
```bash
# Code formatter
rustup component add rustfmt
# Linter
rustup component add clippy
# Documentation builder
cargo install mdbook
```text
---
## Code Quality Standards
### Rust Code
#### 1. Use Safe Rust
**Rule**: Unsafe code is permitted ONLY at the FFI boundary in `src/c_api.rs`.
```rust
// ✅ GOOD: Safe Rust in parser
pub fn parse(input: &str) -> Result<DirectiveIR, ParseError> {
// All safe code
}
// ❌ BAD: Unsafe in parser
pub fn parse(input: &str) -> Result<DirectiveIR, ParseError> {
unsafe { // ← Not allowed outside c_api.rs!
// ...
}
}
```text
#### 2. Format Your Code
```bash
# Format all code
cargo fmt
# Check formatting (CI uses this)
cargo fmt -- --check
```text
#### 3. Pass Clippy
```bash
# Run linter
cargo clippy
# CI requires no warnings
cargo clippy -- -D warnings
```text
#### 4. Write Tests
Every new feature or bug fix should include tests.
```rust
#[test]
fn test_new_feature() {
let result = parse("#pragma omp my_new_directive");
assert!(result.is_ok());
// More assertions...
}
```text
#### 5. Document Public APIs
```rust
/// Parse an OpenMP directive from a string.
///
/// # Arguments
///
/// * `input` - The OpenMP directive text
///
/// # Returns
///
/// * `Ok(DirectiveIR)` - Parsed directive
/// * `Err(ParseError)` - Parse failure with location
///
/// # Examples
///
/// ```
/// use roup::parser::parse;
///
/// let directive = parse("#pragma omp parallel").unwrap();
/// assert_eq!(directive.clauses.len(), 0);
/// ```
pub fn parse(input: &str) -> Result<DirectiveIR, ParseError> {
// ...
}
```text
### C API Code
If modifying `src/c_api.rs`:
- **Minimize unsafe blocks**: Only what's absolutely necessary
- **NULL checks**: Before every pointer dereference
- **Document safety contracts**: Explain caller obligations
- **Test thoroughly**: Including NULL inputs and edge cases
```rust
/// # Safety
///
/// Caller must ensure:
/// - `input` points to a valid null-terminated C string
/// - The string remains valid for the duration of this call
/// - The string is valid UTF-8
#[no_mangle]
pub extern "C" fn roup_parse(input: *const c_char) -> *mut OmpDirective {
if input.is_null() {
return std::ptr::null_mut();
}
// ... minimal unsafe code ...
}
```text
---
## Testing Guidelines
### Running Tests
```bash
# All tests
cargo test
# Specific test
cargo test test_parallel_directive
# Tests with output
cargo test -- --nocapture
# Tests in specific module
cargo test parser::
```text
### Test Categories
#### Unit Tests
Test individual functions in isolation.
```rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tokenize_identifier() {
let tokens = tokenize("parallel");
assert_eq!(tokens.len(), 1);
assert_eq!(tokens[0], Token::Identifier("parallel"));
}
}
```text
#### Integration Tests
Test complete parsing workflows in `tests/`.
```rust
// tests/openmp_parallel.rs
#[test]
fn test_parallel_with_clauses() {
let input = "#pragma omp parallel num_threads(4) private(x)";
let result = roup::parser::parse(input);
assert!(result.is_ok());
let directive = result.unwrap();
assert_eq!(directive.clauses.len(), 2);
}
```text
#### FFI Tests
Test C API safety and correctness.
```rust
#[test]
fn test_null_safety() {
let dir = roup_parse(std::ptr::null());
assert!(dir.is_null());
}
```text
### Test Coverage
Aim for:
- **90%+ coverage** for parser code
- **100% coverage** for FFI boundary code
- **All error paths** tested
---
## Documentation Updates
### mdBook Website
The main documentation is in `docs/book/src/`:
```text
docs/book/src/
├── SUMMARY.md # Navigation (table of contents)
├── intro.md # Homepage
├── getting-started.md # Quick start guide
├── rust-tutorial.md # Rust API tutorial
├── c-tutorial.md # C API tutorial
├── cpp-tutorial.md # C++ API tutorial
├── building.md # Build instructions
├── api-reference.md # API reference
├── architecture.md # Internal design
├── openmp-support.md # OpenMP support matrix
├── contributing.md # This file
└── faq.md # Frequently asked questions
```text
#### Building Documentation
```bash
# Build website
cd docs/book
mdbook build
# Serve locally (with live reload)
mdbook serve --open
# View at http://localhost:3000
```text
#### Adding New Pages
1. Create `.md` file in `docs/book/src/`
2. Add to `SUMMARY.md`:
```markdown
- [My New Page](./my-new-page.md)
- Build and verify:
mdbook build
Rustdoc
API documentation is generated from source code:
# Generate API docs
cargo doc --no-deps --open
# With private items (for development)
cargo doc --no-deps --document-private-items --open
```text
### README.md
**IMPORTANT**: After any change, check that `README.md` stays in sync:
- API changes → Update README examples
- Feature changes → Update README feature list
- Build changes → Update README installation instructions
The README should match website content in `docs/book/src/`.
---
## Pull Request Process
### 1. Fork and Branch
```bash
# Fork on GitHub, then clone your fork
git clone https://github.com/YOUR_USERNAME/roup.git
cd roup
# Create feature branch
git checkout -b feature/my-awesome-feature
```text
### 2. Make Changes
- Write code
- Write tests
- Update documentation
- Format code: `cargo fmt`
- Run tests: `cargo test`
- Check lints: `cargo clippy`
### 3. Commit
Use clear, descriptive commit messages:
```bash
git commit -m "feat: add support for OpenMP 6.0 loop directive"
git commit -m "fix: handle null pointers in roup_parse"
git commit -m "docs: add examples for metadirective"
git commit -m "test: add tests for error recovery"
```text
**Commit Message Format:**
- `feat:` - New feature
- `fix:` - Bug fix
- `docs:` - Documentation only
- `test:` - Tests only
- `refactor:` - Code refactoring
- `perf:` - Performance improvement
- `chore:` - Maintenance tasks
### 4. Pre-PR Checklist
Before opening a PR, ensure:
- [ ] `cargo fmt -- --check` passes (no formatting issues)
- [ ] `cargo build` passes (no compilation warnings)
- [ ] `cargo clippy` passes (no linter warnings)
- [ ] `cargo test` passes (all tests green)
- [ ] `cargo doc --no-deps` passes (no rustdoc warnings)
- [ ] `mdbook build docs/book` passes (if docs changed)
- [ ] README.md is in sync with changes
- [ ] New features have tests
- [ ] New features have documentation
### 5. Push and Open PR
```bash
# Push to your fork
git push origin feature/my-awesome-feature
# Open PR on GitHub
# Go to https://github.com/ouankou/roup and click "New Pull Request"
```text
### 6. PR Description
Include:
**What**: What does this PR do?
**Why**: Why is this change needed?
**How**: How does it work?
**Testing**: How was it tested?
**Example:**
```markdown
## What
Adds support for the OpenMP 6.0 `loop` directive.
## Why
OpenMP 6.0 introduced a new `loop` directive as a more generic alternative to `for`.
## How
- Added `Loop` variant to `DirectiveKind` enum
- Added parsing logic in `directive.rs`
- Updated OpenMP support matrix
## Testing
- Added 15 new test cases covering various `loop` directive forms
- All existing tests still pass
- Manually tested with real-world code
```text
### 7. Code Review
Maintainers will review your PR and may:
- Request changes
- Ask questions
- Suggest improvements
**Be patient and responsive!** Code review is a collaborative process.
### 8. Merge
Once approved, maintainers will merge your PR. Congratulations! 🎉
---
## OpenMP Specification Compliance
When adding support for new OpenMP features:
### 1. Consult Official Specs
- **OpenMP 6.0**: [Latest specification](https://www.openmp.org/specifications/)
- **Archive**: [Older versions](https://www.openmp.org/specifications/)
### 2. Check Syntax Carefully
OpenMP syntax can be subtle. Double-check:
- Required vs optional clauses
- Clause argument types
- Directive applicability (C/C++ vs Fortran)
- Version introduced
### 3. Update Support Matrix
After adding a directive/clause, update `docs/book/src/openmp-support.md`:
```markdown
| Directive | OpenMP Version | Status | Notes |
|-----------|----------------|--------|-------|
| `loop` | 5.0 | ✅ Supported | New in OpenMP 5.0 |
```text
### 4. Add Examples
Include examples in documentation showing correct usage.
---
## Performance Considerations
### Benchmarking
If your change affects performance:
```bash
# Run benchmarks (if available)
cargo bench
# Profile with flamegraph
cargo install flamegraph
cargo flamegraph --bin roup
```text
### Performance Guidelines
- Avoid unnecessary allocations
- Prefer zero-copy when possible
- Use `&str` instead of `String` where appropriate
- Benchmark before/after for significant changes
---
## Security
### Reporting Security Issues
Please report security vulnerabilities by opening a GitHub issue at:
[https://github.com/ouankou/roup/issues](https://github.com/ouankou/roup/issues)
Include:
- Description of vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
### Security Best Practices
When writing code:
- Validate all inputs
- Check for integer overflow
- Avoid buffer overruns
- Be careful with unsafe code
- Use safe defaults
---
## Release Process
(For maintainers)
### Version Numbering
ROUP follows [Semantic Versioning](https://semver.org/):
- **MAJOR**: Breaking API changes
- **MINOR**: New features (backward compatible)
- **PATCH**: Bug fixes (backward compatible)
### Release Checklist
1. Update version in `Cargo.toml`
2. Update `CHANGELOG.md`
3. Run full test suite
4. Build documentation
5. Create git tag: `git tag v0.2.0`
6. Push tag: `git push origin v0.2.0`
7. Publish to crates.io: `cargo publish`
8. Create GitHub release with notes
---
## Getting Help
### Stuck?
- **Documentation**: Read [roup.ouankou.com](https://roup.ouankou.com)
- **Discussions**: Ask on [GitHub Discussions](https://github.com/ouankou/roup/discussions)
- **Issues**: Search [existing issues](https://github.com/ouankou/roup/issues)
- **Examples**: Check `examples/` directory
### Communication Guidelines
- Be respectful and professional
- Provide context for questions
- Include minimal reproducible examples
- Search before asking (avoid duplicates)
---
## Code of Conduct
### Our Standards
- **Be respectful**: Treat everyone with respect
- **Be constructive**: Provide helpful feedback
- **Be patient**: Remember that everyone is learning
- **Be inclusive**: Welcome newcomers
### Unacceptable Behavior
- Harassment or discrimination
- Trolling or insulting comments
- Personal attacks
- Publishing others' private information
### Reporting
Report unacceptable behavior to: [conduct@ouankou.com](mailto:conduct@ouankou.com)
---
## Recognition
Contributors will be:
- Listed in `CONTRIBUTORS.md`
- Mentioned in release notes
- Credited in commit messages
Significant contributions may result in:
- Maintainer status
- Commit access
- Decision-making authority
---
## License
By contributing, you agree that your contributions will be licensed under the same license as the project (see `LICENSE` file).
---
## Questions?
Still have questions? Open a [discussion](https://github.com/ouankou/roup/discussions) or reach out to the maintainers.
**Thank you for contributing to ROUP!** 🚀
Frequently Asked Questions
Common questions about using ROUP.
Note: Code examples in this FAQ use
rust,ignore
to preventmdbook test
from attempting to compile them without the ROUP library linked. To test these examples yourself, create a new Rust project and add ROUP as a dependency in yourCargo.toml
. See the Getting Started guide for step-by-step instructions. All examples are verified to compile correctly when used in a project with ROUP as a dependency.
General Questions
What is ROUP?
ROUP (Rust OpenMP Parser) is a library for parsing OpenMP directives from C, C++, and Fortran source code. It converts OpenMP pragma text like #pragma omp parallel for
into a structured representation that programs can analyze and manipulate.
Why use ROUP instead of libomptarget or LLVM?
ROUP advantages:
- Lightweight: Standalone library, no LLVM dependency
- Fast: Parse in microseconds, not milliseconds
- Safe: Written in Rust with minimal unsafe code
- Simple API: Easy to integrate into any project
- Cross-platform: Works everywhere Rust works
When to use LLVM instead:
- You need full compilation, not just parsing
- You're building a complete OpenMP compiler
- You need LLVM IR generation
Is ROUP production-ready?
No, ROUP is experimental and under active development.
Current status:
- ✅ 352 tests, all passing
- ✅ Supports OpenMP 3.0-6.0 parsing
- ⚠️ APIs may change between versions
- ⚠️ Some OpenMP features still being implemented
- ⚠️ Not recommended for production use yet
Best for:
- Research projects and prototypes
- Educational purposes
- Experimental tooling
- Compiler research
Production readiness planned for: Future v1.0 release (timeline TBD)
What OpenMP versions are supported?
ROUP supports directives and clauses from:
- ✅ OpenMP 3.0-6.0
See the OpenMP Support Matrix for detailed coverage.
Installation & Setup
How do I install ROUP?
For Rust projects:
[dependencies]
roup = "0.3"
For C/C++ projects:
- Build the library:
cargo build --release
- Link against
target/release/libroup.{a,so,dylib}
- Include the FFI headers
See Building Guide for detailed instructions.
What are the system requirements?
Minimum:
- Rust 1.70+ (to build the library)
- Any C/C++ compiler (to use the C API)
Operating Systems:
- ✅ Linux (all distributions)
- ✅ macOS (10.15+)
- ✅ Windows (via WSL or native MSVC/MinGW)
- ✅ BSD variants
Architectures:
- x86_64, ARM64, and others supported by Rust
Why does building take so long the first time?
The first build compiles all dependencies (like nom
). Subsequent builds are much faster thanks to Rust's incremental compilation.
Speed it up:
# Use faster linker (Linux)
cargo install lld
export RUSTFLAGS="-C link-arg=-fuse-ld=lld"
# Use sccache for caching
cargo install sccache
export RUSTC_WRAPPER=sccache
Usage Questions
How do I parse a simple directive?
Rust:
// Note: Using `rust,ignore` - see top of page for testing instructions
use roup::parser::openmp;
let parser = openmp::parser();
let result = parser.parse("#pragma omp parallel");
match result {
Ok((_, directive)) => println!("Parsed: {:?}", directive),
Err(e) => eprintln!("Error: {:?}", e),
}
C:
OmpDirective* dir = roup_parse("#pragma omp parallel");
if (dir) {
// Use directive
roup_directive_free(dir);
}
See the Getting Started guide for more examples.
How do I iterate through clauses?
Rust:
// Note: Using `rust,ignore` - see top of page for testing instructions
for clause in &directive.clauses {
println!("Clause: {:?}", clause);
}
C:
OmpClauseIterator* iter = roup_directive_clauses_iter(dir);
OmpClause* clause;
while (roup_clause_iterator_next(iter, &clause)) {
int32_t kind = roup_clause_kind(clause);
printf("Clause kind: %d\n", kind);
}
roup_clause_iterator_free(iter);
See C Tutorial - Step 4 for details.
How do I access clause data (like variable lists)?
Rust:
// Note: Using `rust,ignore` - see top of page for testing instructions
match &clause {
Clause::Private(vars) => {
for var in vars {
println!("Private variable: {}", var);
}
},
_ => {}
}
C:
if (roup_clause_kind(clause) == 2) { // PRIVATE
OmpStringList* vars = roup_clause_variables(clause);
int32_t len = roup_string_list_len(vars);
for (int32_t i = 0; i < len; i++) {
printf("Variable: %s\n", roup_string_list_get(vars, i));
}
roup_string_list_free(vars);
}
Can I parse multiple directives in parallel?
Yes! Parsing is thread-safe:
// Note: Using `rust,ignore` - see top of page for testing instructions
use roup::parser::openmp;
use std::thread;
let parser = openmp::parser();
let t1 = thread::spawn(move || {
let p = openmp::parser();
p.parse("#pragma omp parallel")
});
let t2 = thread::spawn(move || {
let p = openmp::parser();
p.parse("#pragma omp for")
});
let dir1 = t1.join().unwrap();
let dir2 = t2.join().unwrap();
Each parse operation is independent with no shared state.
Does ROUP modify the input string?
No. Parsing is read-only. The input string is never modified.
API Questions
What's the difference between the Rust and C APIs?
Rust API:
- Returns
Result<DirectiveIR, ParseError>
- Uses Rust's ownership system (automatic memory management)
- Rich types (
Vec
,String
, enums) - Full access to all 92+ clause types
C API:
- Returns pointers (NULL on error)
- Manual memory management (call
_free()
functions) - Simple integer discriminants for clause types
- Supports 12 common clause types
The C API is a thin wrapper over the Rust API.
Why does the C API only support 12 clause types?
The C API focuses on the most common clauses for simplicity:
num_threads
,if
,private
,shared
firstprivate
,lastprivate
,reduction
schedule
,collapse
,ordered
,nowait
,default
This covers 95% of real-world use cases. The complete Rust parser supports all 91 clauses from OpenMP 3.0-6.0 (see Architecture for details).
What's the clause kind mapping?
Kind | Clause | Kind | Clause |
---|---|---|---|
0 | num_threads | 6 | reduction |
1 | if | 7 | schedule |
2 | private | 8 | collapse |
3 | shared | 9 | ordered |
4 | firstprivate | 10 | nowait |
5 | lastprivate | 11 | default |
999 | unknown |
See API Reference for details.
Is there a Python binding?
Not yet, but it's planned! You can follow progress on Python bindings in the ROUP GitHub repository.
In the meantime, you can use the C API via ctypes
or cffi
.
Memory Management
Do I need to free anything in Rust?
No. Rust's ownership system handles everything automatically:
// Note: Using `rust,ignore` - see top of page for testing instructions
use roup::parser::openmp;
{
let parser = openmp::parser();
let (_, directive) = parser.parse("#pragma omp parallel").unwrap();
// Use directive...
} // ← Automatically freed here
What do I need to free in C?
Always free:
roup_directive_free()
- For everyroup_parse()
callroup_clause_iterator_free()
- For everyroup_directive_clauses_iter()
callroup_string_list_free()
- For everyroup_clause_variables()
call
Never free:
- Individual clauses from iterators (owned by directive)
OmpDirective* dir = roup_parse("#pragma omp parallel");
OmpClauseIterator* iter = roup_directive_clauses_iter(dir);
// Use iter...
roup_clause_iterator_free(iter); // ✅ Free iterator
roup_directive_free(dir); // ✅ Free directive
What happens if I forget to free?
Memory leak. The memory won't be reclaimed until the process exits.
Use Valgrind to detect leaks:
valgrind --leak-check=full ./my_program
What happens if I double-free?
Undefined behavior. Your program will likely crash.
roup_directive_free(dir);
roup_directive_free(dir); // ❌ CRASH!
Solution: Set pointers to NULL after freeing:
roup_directive_free(dir);
dir = NULL;
Error Handling
How do I know if parsing failed?
Rust:
use roup::parser::openmp;
let parser = openmp::parser();
match parser.parse(input) {
Ok((_, directive)) => { /* success */ },
Err(error) => {
eprintln!("Parse error: {:?}", error);
}
}
C:
OmpDirective* dir = roup_parse(input);
if (dir == NULL) {
fprintf(stderr, "Parse failed\n");
return 1;
}
What causes parse errors?
Common causes:
- Invalid OpenMP syntax
- Typos in directive/clause names
- Missing required arguments
- Malformed expressions
- Invalid UTF-8
Can I recover from parse errors?
Not automatically. If parsing fails, you get an error but no partial directive.
Workaround: Parse line-by-line and skip lines that fail:
use roup::parser::openmp;
let parser = openmp::parser();
for line in source_code.lines() {
if let Ok((_, directive)) = parser.parse(line) {
// Process directive
}
// Skip lines that don't parse
}
Why does roup_parse()
return NULL?
Possible reasons:
- NULL input: You passed
NULL
pointer - Invalid syntax: OpenMP directive is malformed
- Invalid UTF-8: Input contains invalid UTF-8 bytes
Debug it:
const char* inputs[] = {
NULL, // Returns NULL (null input)
"", // Returns NULL (empty)
"#pragma omp INVALID", // Returns NULL (bad syntax)
"#pragma omp parallel", // Returns pointer (valid!)
};
Performance
How fast is parsing?
Typical parse times:
- Simple directive (
#pragma omp parallel
): ~500ns - With clauses (
#pragma omp parallel for num_threads(4)
): ~800ns - Complex (
#pragma omp parallel for private(i,j,k) reduction(+:sum)
): ~1.2µs
For comparison: LLVM parsing is ~10-100x slower due to full lexing/preprocessing overhead.
Does ROUP allocate much memory?
Minimal allocations:
- 1 allocation for the
DirectiveIR
struct - 1 allocation per clause (Vec element)
- Strings are stored inline (no extra allocations)
Parsing #pragma omp parallel for private(i) reduction(+:sum)
:
- Allocations: 3 (DirectiveIR + 2 clauses)
- Memory: ~200 bytes
Can I reduce allocations further?
The lexer already uses zero-copy (works on &str
slices). The only allocations are for the IR structure, which you need to return.
If you're parsing thousands of directives, consider:
- Reuse: Parse once, reuse many times
- Arena allocation: Use a custom allocator
- Lazy parsing: Only parse when needed
Is the C API slower than Rust?
No. The C API is a thin wrapper (~10ns overhead per FFI call). Parsing performance is identical.
FFI overhead comparison:
- C API: ~10ns per call
- Parsing: ~500-1000ns
- FFI overhead: <2% of total time
Safety & Security
Is ROUP memory-safe?
Yes, with caveats:
Rust API: 100% memory-safe. Impossible to trigger undefined behavior from safe Rust code.
C API: Safe at the boundary, but C callers must follow contracts:
- Don't pass invalid pointers
- Don't use pointers after freeing
- Don't pass non-null-terminated strings
This is standard for C FFI. ROUP does NULL checks and validation where possible.
Where is the unsafe code?
Location: src/c_api.rs
Amount: ~60 lines out of 6,700+ (~0.9%)
Purpose: Only at FFI boundary for:
- Reading C strings (
CStr::from_ptr
) - Writing to output pointers
- Converting between Rust and C types
All unsafe code is:
- ✅ Documented with safety contracts
- ✅ Guarded by NULL checks
- ✅ Minimal (single operations)
- ✅ Tested thoroughly
See Architecture for details.
Can malicious input crash ROUP?
No. Invalid input causes parse errors, not crashes.
Tested:
- Fuzzing with random bytes
- NULL inputs
- Extremely long strings
- Malformed UTF-8
- Edge cases
All result in safe error returns, never crashes.
Is ROUP vulnerable to buffer overflows?
No. Rust prevents buffer overflows at compile time.
Even the C API is safe:
- Uses
CStr::from_ptr()
which validates null termination - No manual pointer arithmetic
- No manual buffer copying
Integration
Can I use ROUP in a C++ project?
Yes! Use the C API with C++17 RAII wrappers:
#include "roup_wrapper.hpp"
roup::Directive dir("#pragma omp parallel");
if (dir) {
std::cout << "Parsed successfully!\n";
}
// Automatic cleanup
See C++ Tutorial for details.
Does ROUP work with CMake?
Yes! Example:
add_library(roup STATIC IMPORTED)
set_target_properties(roup PROPERTIES
IMPORTED_LOCATION "/path/to/libroup.a"
)
target_link_libraries(myapp roup pthread dl m)
See Building Guide - C Integration for full example.
Can I statically link ROUP?
Yes! Use libroup.a
:
gcc myapp.c -L/path/to/target/release -lroup -lpthread -ldl -lm
The resulting binary has no runtime dependencies on ROUP.
Does ROUP work on embedded systems?
It depends on the target:
Yes (if target supports):
- Rust standard library
- Dynamic memory allocation
- ~500KB binary size
No (if target requires):
no_std
Rust (no heap)- <100KB binary size
For no_std
support, open a feature request.
Comparison to Other Tools
ROUP vs libomptarget?
Feature | ROUP | libomptarget |
---|---|---|
Purpose | Parsing only | Full OpenMP runtime |
Size | ~500KB | ~50MB+ (with LLVM) |
Dependencies | None | LLVM, Clang |
Parse time | ~1µs | ~100µs |
API | Simple | Complex |
Use case | Analysis tools | Compilers |
Use ROUP for: Static analysis, IDE plugins, documentation tools
Use libomptarget for: Compiling OpenMP code for execution
ROUP vs writing a custom parser?
ROUP advantages:
- Already supports 120+ directives
- Tested with 342 tests
- Handles edge cases
- Active maintenance
- OpenMP spec compliance
Custom parser:
- ❌ Weeks/months of development
- ❌ Easy to miss edge cases
- ❌ Hard to maintain
- ❌ Likely has bugs
Verdict: Use ROUP unless you have very specific needs.
ROUP vs regex?
Don't use regex for parsing OpenMP.
OpenMP syntax is too complex for regex:
- Nested parentheses
- Expression parsing
- Clause dependencies
- Context-sensitive syntax
Regex will fail on edge cases and give incorrect results.
Troubleshooting
"cannot find -lroup" when linking
Problem: Linker can't find library.
Solution:
# Check library exists
ls target/release/libroup.*
# Rebuild if needed
cargo build --release
# Use correct path
gcc ... -L$(pwd)/target/release -lroup
"error while loading shared libraries: libroup.so"
Problem: Runtime can't find dynamic library.
Solutions:
Option 1 - rpath:
gcc ... -Wl,-rpath,/path/to/target/release
Option 2 - LD_LIBRARY_PATH:
export LD_LIBRARY_PATH=/path/to/target/release:$LD_LIBRARY_PATH
Option 3 - Static linking:
gcc ... -L/path/to/target/release -lroup -lpthread -ldl -lm
Compilation is slow
Solution:
# Install faster linker
cargo install lld
export RUSTFLAGS="-C link-arg=-fuse-ld=lld"
# Use sccache
cargo install sccache
export RUSTC_WRAPPER=sccache
Rust version too old
Solution:
# Update Rust
rustup update stable
# Check version (need 1.70+)
rustc --version
Getting Help
Where can I ask questions?
- Search first: Check this FAQ and documentation
- GitHub Discussions: Ask a question
- GitHub Issues: Report bugs
- Email: support@ouankou.com
How do I report a bug?
Open an issue with:
- Input directive that fails
- Expected behavior
- Actual behavior
- Environment (OS, Rust version, ROUP version)
- Minimal code to reproduce
How do I request a feature?
Start a discussion explaining:
- What you want to do
- Why current API doesn't support it
- Proposed solution
- Use case
Still have questions?
If your question isn't answered here:
- Check the full documentation
- Browse examples
- Search closed issues
- Ask on GitHub Discussions
We're here to help! 🚀