Files
tinygo/builder/clang.cpp
T
deadprogram 0ffa3eb748 all: add LLVM 22 support
Builder:
- Update clang.cpp for LLVM 22 API changes: DiagnosticOptions is no
  longer ref-counted, TextDiagnosticPrinter and DiagnosticsEngine take
  references instead of pointers, createDiagnostics() signature changed.
- Update cc1as.cpp: clang/Driver/Options.h moved to
  clang/Options/Options.h, namespace changed from clang::driver::options
  to clang::options, MCInstPrinter now passed as unique_ptr.
- Add new LLVM 22 libraries to GNUmakefile: clangAnalysisLifetimeSafety,
  clangOptions, LLVMDTLTO, and dtlto component.
- Add llvm22 build tag to all build/test commands.

CGo:
- Handle CXType_Unexposed in libclang.go by resolving via canonical
  type. LLVM 22 reports builtin type aliases (e.g. __size_t) as
  Unexposed instead of Typedef.
- Always make C typedefs into Go type aliases. LLVM 22 changed
  getTypedefDeclUnderlyingType to return CXType_Enum directly instead
  of wrapping in an elaborated type.

Compileopts:
- Add build-tag-guarded ClangTriple() to substitute wasm32-unknown-wasi
  with wasm32-unknown-wasip1 for LLVM 22 (deprecated triple).
- Add build-tag-guarded patchFeatures() to map renamed Xtensa features
  (atomctl, memctl, timerint, esp32s3) for LLVM 22.

Targets:
- Remove -zca from RISC-V target feature strings (esp32c3, esp32c6,
  fe310, k210, riscv-qemu, tkey). LLVM 22 now implies +zca from +c.
- Remove -zcd from k210. LLVM 22 now implies +zcd from +c,+d.

Tests:
- Change TestClangAttributes to check individual feature flags instead
  of exact string match, allowing new LLVM features without failures.
- Update TestBinarySize expected values for LLVM 22 codegen.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-07-17 19:06:57 +02:00

99 lines
3.0 KiB
C++

//go:build byollvm
#include <clang/Basic/DiagnosticOptions.h>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/Driver/Compilation.h>
#include <clang/Driver/Driver.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CompilerInvocation.h>
#include <clang/Frontend/FrontendDiagnostic.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/FrontendTool/Utils.h>
#include <llvm/ADT/IntrusiveRefCntPtr.h>
#include <llvm/Option/Option.h>
#include <llvm/TargetParser/Host.h>
using namespace llvm;
using namespace clang;
#include "cc1as.h"
// This file provides C wrappers for the builtin tools cc1 and cc1as
// provided by Clang, and calls them as the driver would call them.
extern "C" {
bool tinygo_clang_driver(int argc, char **argv) {
std::vector<const char*> args(argv, argv + argc);
// The compiler invocation needs a DiagnosticsEngine so it can report problems
clang::DiagnosticOptions DiagOpts;
clang::TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), DiagOpts);
clang::DiagnosticsEngine Diags(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(new clang::DiagnosticIDs()), DiagOpts, &DiagnosticPrinter, false);
// Create the clang driver
clang::driver::Driver TheDriver(args[0], llvm::sys::getDefaultTargetTriple(), Diags);
// Create the set of actions to perform
std::unique_ptr<clang::driver::Compilation> C(TheDriver.BuildCompilation(args));
if (!C) {
return false;
}
const clang::driver::JobList &Jobs = C->getJobs();
// There may be more than one job, for example for .S files
// (preprocessor + assembler).
for (auto Cmd : Jobs) {
// Select the tool: cc1 or cc1as.
const llvm::opt::ArgStringList &CCArgs = Cmd.getArguments();
if (strcmp(*CCArgs.data(), "-cc1") == 0) {
// This is the C frontend.
// Initialize a compiler invocation object from the clang (-cc1) arguments.
std::unique_ptr<clang::CompilerInstance> Clang(new clang::CompilerInstance());
bool success = clang::CompilerInvocation::CreateFromArgs(
Clang->getInvocation(),
CCArgs,
Diags);
if (!success) {
return false;
}
// Create the actual diagnostics engine.
Clang->createDiagnostics();
if (!Clang->hasDiagnostics()) {
return false;
}
// Execute the frontend actions.
success = ExecuteCompilerInvocation(Clang.get());
if (!success) {
return false;
}
} else if (strcmp(*CCArgs.data(), "-cc1as") == 0) {
// This is the assembler frontend. Parse the arguments.
AssemblerInvocation Asm;
ArrayRef<const char *> Argv = llvm::ArrayRef<const char*>(CCArgs);
if (!AssemblerInvocation::CreateFromArgs(Asm, Argv.slice(1), Diags))
return false;
// Execute the invocation, unless there were parsing errors.
bool failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags);
if (failed) {
return false;
}
} else {
// Unknown tool, print the tool and exit.
fprintf(stderr, "unknown tool: %s\n", *CCArgs.data());
return false;
}
}
// Commands executed successfully.
return true;
}
} // extern "C"