AXPY End-to-End Runbook with Clang/Flang¶
This note captures the steps, roadblocks, and fixes required to get a pure C++ AXPY example working end-to-end with the experimental Clang frontend in REX.
Toolchain & Build¶
- Configured a fresh
build-clangtree withclang-20,clang++-20, andflangas the backend compilers:cmake -S . -B build-clang \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=/usr/lib/llvm-20/bin/clang \ -DCMAKE_CXX_COMPILER=/usr/lib/llvm-20/bin/clang++ \ -DCMAKE_Fortran_COMPILER=/usr/lib/llvm-20/bin/flang \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DENABLE-C=ON -DENABLE-FORTRAN=ON cmake --build build-clang -j$(nproc) - All invocations of
rose-compilerrequireLD_LIBRARY_PATHto point at the freshly builtbuild-clang/libdirectory.
Source Example¶
- Added
tests/nonsmoke/functional/CompileTests/Cxx_tests/rex_test2025_issue160_axpy_system_headers.cppas a C++ example that now exercises common standard headers (<array>,<numeric>,<cmath>) to validate language default initialisation. - The program initialises two fixed-size buffers with
std::array, performs the AXPY loop, and returns0/1based on a relative-error check (no runtime I/O needed).
Frontend Issues & Fixes¶
- Missing language defaults for C++
- Symptom: Including even
<cmath>produced thousands of errors likeunknown type name 'bool'and missing__builtin_*intrinsics. - Root cause: We were never initialising
clang::LangOptionswith C++ defaults; the invocation inherited C-like settings fromCompilerInvocation::CreateFromArgs. -
Fix: Call
clang::LangOptions::setLangDefaultswith the host triple andlang_gnucxx17(seesrc/frontend/CxxFrontend/Clang/clang-frontend.cpp:268). We collect any implicit include paths returned by that helper and append them back into the activePreprocessorOptions. -
Unhandled
LinkageSpecDecl(extern "C"/"C++") - Symptom: Declarations inside
extern "C"could be dropped from the ROSE AST (unreachable / missing from the owning scope), and linkage information could be lost during unparsing. -
Fix:
VisitLinkageSpecDeclnow always attaches translated inner declarations to the current scope and preserves language linkage on those declarations (e.g.,set_linkage("C")+setExtern()forextern "C" T f()forms). Brace-formextern "C" { ... }is preserved via the existing preprocessing-info mechanism (and marked viasetExternBrace()on the contained declarations) so the unparser round-trips the original structure. -
Anonymous namespace handling
- Symptom: The translator asserted inside
buildDefiningFunctionDeclaration_Twhen processing a file that declared helper routines insidenamespace { ... }. - Workaround: Keep helper routines at global scope and mark them
static. This sidesteps unimplemented namespace support in the current frontend. - Duplicate scope symbols triggering name-qualification warnings
- Symptom:
nameQualificationSupportwarned on almost every reference to block-local variables (notablyfor-loop indices). - Root cause: The Clang bridge manually pushed a
SgVariableSymbolinto the current scope after callingSageBuilder::buildVariableDeclaration_nfi, but the builder already inserts the symbol. This double insertion inflated the scope's symbol table and fooled the unparser into thinking multiple declarations existed. - Fix: Drop the extra
insert_symboland rely onSageBuilderto manage the symbol table. The unparser now uses the scope counts directly with no custom filtering, so only real ambiguities surface.
Validation Flow¶
- Run the translator to generate
rose_rex_test2025_issue160_axpy_system_headers.cpp:Output appears at the repository root.LD_LIBRARY_PATH=$PWD/build-clang/lib \ ./build-clang/bin/rose-compiler tests/nonsmoke/functional/CompileTests/Cxx_tests/rex_test2025_issue160_axpy_system_headers.cpp - Verify both the original and generated sources compile and execute cleanly:
clang++ tests/nonsmoke/functional/CompileTests/Cxx_tests/rex_test2025_issue160_axpy_system_headers.cpp -O2 -o /tmp/axpy_orig clang++ rose_rex_test2025_issue160_axpy_system_headers.cpp -O2 -o /tmp/axpy_rose /tmp/axpy_orig && /tmp/axpy_rose # both exit 0
Limitations & Next Steps¶
- Future hardening: it is still worthwhile to tighten the Clang bridge so loop induction variables are stored under the
SgForInitStatementscope, but the immediate user-facing problem is gone.
Known Gaps¶
- The frontend still struggles with large swaths of the C++ standard library (heavy template specialisations, allocator traits, etc.). The builtin/runtime mismatches are gone, but expect additional traversal failures until those visitors are implemented.
May 2025 Status & Next Steps¶
- Bug fixed: the Clang driver now initialises
LangOptionsfor C++ input, picking a GNU C++17 default, injecting implicit headers, and enabling builtin intrinsics. This unblocks<cmath>/__builtin_*usage and lines up with the intended Clang invocation (clang-frontend.cpp:267-395,clang-to-dot.cpp:264-325). - AXPY sample: the smoke test in
tests/nonsmoke/functional/CompileTests/Cxx_tests/rex_test2025_issue160_axpy_system_headers.cppnow exercises<array>,<numeric>,<cmath>, and<cstddef>. It compiles and runs with stockclang++, but the current Clang→ROSE bridge still aborts when walking the resulting libstdc++ AST. - Translator gaps: namespace traversal, template declarations/specialisations,
and many type/statement visitors remain stubs. With real system headers enabled
the translator quickly encounters
std::arrayscaffolding and dies. Skipping or generating opaque stand-ins for those nodes is the next prerequisite before we can ingest richer C++. - Proposed short-term plan
- Teach
VisitNamespaceDeclto record namespace shells while continuing to walk child declarations safely (no early aborts). - Add minimal handling for class/function/alias/var template decls: traverse the
templated declaration, create an opaque
SgType, and store symbols so later lookups succeed. - Extend record/typedef/type visitors to fall back to
buildOpaqueTypeand unblockstd::arraybasics; do the same for critical statement/expression visitors (DeclRefExpr,MemberExpr,CallExprinto template instantiations). - Re-run the AXPY sample end-to-end, then incrementally admit additional headers.
- Risks: without better symbol management we risk leaking thousands of opaque placeholders or emitting unusable ASTs. Each fallback should log once (guarded by a debug knob) so production runs stay quiet.
Roadmap (Follow-Through Checklist)¶
The following sequence should be executed top-to-bottom for any future engineer continuing this work. Do not re-investigate the fixed language-default bug; the remaining tasks are strictly around AST translation hardening:
- Namespace scaffolding
- Finish implementation of
VisitNamespaceDeclto emit an actualSgNamespaceDeclarationStatementwhile preserving child traversal. - Verify we no longer produce
SgNullStatementplaceholders for namespace IR. - Template declaration handling
- Implement stub visitors for class/function/type-alias/variable templates that fabricate opaque types + symbols in scope.
- Ensure specialisations (full/partial) are walked, even if they degrade to placeholders.
- Type fallback coverage
- Harden
VisitRecordType,VisitTemplateSpecializationType, andVisitTypedefTypeto avoid assertions; emitbuildOpaqueTypeorbuildUnknownTypewith deterministic naming. - Add exhaustive unit logging behind a debug flag so missing cases are easy to trace.
- Expression/statement wiring
- Handle the common expression forms produced by
std::arrayand friends:DeclRefExpr,MemberExpr,CXXConstructExpr,CallExpr, etc. - Reuse existing SageBuilder helpers where possible; skip unhandled nodes with
buildNullExpression()rather than abort. - Regression loop
- Re-run
rose-compiler tests/nonsmoke/functional/CompileTests/Cxx_tests/rex_test2025_issue160_axpy_system_headers.cppuntil it produces a translated file without crashing. - Expand coverage gradually (
<vector>,<algorithm>, etc.) using the same smoke-test pattern. - Linkage specifications are flattened; follow-up work is needed if downstream
analyses require exact
externmetadata.