use std::collections::{HashMap, HashSet};
use std::fmt;
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::sync::{
atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering},
Arc, Mutex, RwLock,
};
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use crate::clang::clang_x86_codegen_full::*;
use crate::clang::clang_x86_driver_full::*;
use crate::clang::clang_x86_pipeline::*;
use crate::clang::*;
use crate::context::LLVMContext;
use crate::module::Module;
use crate::pass_manager::PassManager;
use crate::types::{Type, TypeKind};
use crate::value::{Value, ValueRef};
use crate::verifier::{verify_module, VerifierResult};
use crate::x86::x86_golden_pipeline::*;
use crate::x86::x86_isel_golden::*;
use crate::x86::*;
#[derive(Debug, Clone)]
pub struct GoldenConfig {
pub input_files: Vec<PathBuf>,
pub output_file: Option<PathBuf>,
pub language_standard: String,
pub is_cxx: bool,
pub gnu_extensions: bool,
pub ms_extensions: bool,
pub target_triple: String,
pub target_cpu: String,
pub target_features: String,
pub target_abi: String,
pub m32: bool,
pub mx32: bool,
pub opt_level: String,
pub code_model: String,
pub reloc_model: String,
pub pic: bool,
pub pie: bool,
pub lto: bool,
pub thin_lto: bool,
pub lto_jobs: usize,
pub debug_info: bool,
pub debug_info_kind: String,
pub codeview: bool,
pub wall: bool,
pub wextra: bool,
pub werror: bool,
pub pedantic: bool,
pub error_limit: usize,
pub verbose: bool,
pub print_timing: bool,
pub includes: Vec<PathBuf>,
pub system_includes: Vec<PathBuf>,
pub library_paths: Vec<PathBuf>,
pub libraries: Vec<String>,
pub defines: Vec<(String, Option<String>)>,
pub undefines: Vec<String>,
pub nostdinc: bool,
pub nostdincpp: bool,
pub output_format: String,
pub stop_after: Option<String>,
pub preprocess_only: bool,
pub syntax_only: bool,
pub assembly_only: bool,
pub compile_only: bool,
pub asan: bool,
pub ubsan: bool,
pub tsan: bool,
pub msan: bool,
pub lsan: bool,
pub pgo_generate: bool,
pub pgo_use: Option<PathBuf>,
pub coverage: bool,
pub linker_flags: Vec<String>,
pub static_linking: bool,
pub shared: bool,
pub export_dynamic: bool,
pub linker: String,
pub incremental: bool,
pub incremental_cache_dir: Option<PathBuf>,
pub enable_cache: bool,
pub cache_dir: Option<PathBuf>,
pub cache_max_size_bytes: u64,
pub self_host: bool,
pub self_host_source_dir: Option<PathBuf>,
pub self_host_build_dir: Option<PathBuf>,
pub self_host_stages: usize,
pub sysroot: Option<PathBuf>,
pub resource_dir: Option<PathBuf>,
pub gcc_install: Option<PathBuf>,
pub dry_run: bool,
pub working_dir: Option<PathBuf>,
pub env_vars: HashMap<String, String>,
pub custom_passes: Vec<String>,
pub timeout_secs: u64,
pub max_memory_mb: u64,
pub compilation_database: Option<PathBuf>,
}
impl Default for GoldenConfig {
fn default() -> Self {
Self {
input_files: Vec::new(),
output_file: None,
language_standard: "c17".into(),
is_cxx: false,
gnu_extensions: false,
ms_extensions: false,
target_triple: "x86_64-unknown-linux-gnu".into(),
target_cpu: "generic".into(),
target_features: String::new(),
target_abi: "sysv".into(),
m32: false,
mx32: false,
opt_level: "0".into(),
code_model: "default".into(),
reloc_model: "default".into(),
pic: false,
pie: false,
lto: false,
thin_lto: false,
lto_jobs: 0,
debug_info: false,
debug_info_kind: "none".into(),
codeview: false,
wall: false,
wextra: false,
werror: false,
pedantic: false,
error_limit: 20,
verbose: false,
print_timing: false,
includes: Vec::new(),
system_includes: Vec::new(),
library_paths: Vec::new(),
libraries: Vec::new(),
defines: Vec::new(),
undefines: Vec::new(),
nostdinc: false,
nostdincpp: false,
output_format: "object".into(),
stop_after: None,
preprocess_only: false,
syntax_only: false,
assembly_only: false,
compile_only: false,
asan: false,
ubsan: false,
tsan: false,
msan: false,
lsan: false,
pgo_generate: false,
pgo_use: None,
coverage: false,
linker_flags: Vec::new(),
static_linking: false,
shared: false,
export_dynamic: false,
linker: "lld".into(),
incremental: false,
incremental_cache_dir: None,
enable_cache: false,
cache_dir: None,
cache_max_size_bytes: 1024 * 1024 * 1024, self_host: false,
self_host_source_dir: None,
self_host_build_dir: None,
self_host_stages: 3,
sysroot: None,
resource_dir: None,
gcc_install: None,
dry_run: false,
working_dir: None,
env_vars: HashMap::new(),
custom_passes: Vec::new(),
timeout_secs: 0,
max_memory_mb: 0,
compilation_database: None,
}
}
}
impl GoldenConfig {
pub fn x86_64_linux() -> Self {
Self {
target_triple: "x86_64-unknown-linux-gnu".into(),
target_cpu: "generic".into(),
target_abi: "sysv".into(),
..Default::default()
}
}
pub fn x86_64_linux_release() -> Self {
Self {
target_triple: "x86_64-unknown-linux-gnu".into(),
target_cpu: "generic".into(),
target_abi: "sysv".into(),
opt_level: "2".into(),
lto: true,
..Default::default()
}
}
pub fn x86_64_windows() -> Self {
Self {
target_triple: "x86_64-pc-windows-msvc".into(),
target_cpu: "generic".into(),
target_abi: "win64".into(),
codeview: true,
..Default::default()
}
}
pub fn x86_64_darwin() -> Self {
Self {
target_triple: "x86_64-apple-darwin".into(),
target_cpu: "generic".into(),
target_abi: "sysv".into(),
..Default::default()
}
}
pub fn i386_linux() -> Self {
Self {
target_triple: "i386-unknown-linux-gnu".into(),
target_cpu: "pentium4".into(),
target_abi: "sysv".into(),
m32: true,
..Default::default()
}
}
pub fn x32_linux() -> Self {
Self {
target_triple: "x86_64-unknown-linux-gnux32".into(),
target_cpu: "generic".into(),
target_abi: "sysv".into(),
mx32: true,
..Default::default()
}
}
pub fn with_output(mut self, path: impl AsRef<Path>) -> Self {
self.output_file = Some(path.as_ref().to_path_buf());
self
}
pub fn with_opt_level(mut self, level: &str) -> Self {
self.opt_level = level.to_string();
self
}
pub fn with_target(mut self, triple: &str) -> Self {
self.target_triple = triple.to_string();
self
}
pub fn with_cpu(mut self, cpu: &str) -> Self {
self.target_cpu = cpu.to_string();
self
}
pub fn with_includes(mut self, paths: Vec<PathBuf>) -> Self {
self.includes = paths;
self
}
pub fn with_defines(mut self, defines: Vec<(String, Option<String>)>) -> Self {
self.defines = defines;
self
}
pub fn with_lto(mut self, enabled: bool) -> Self {
self.lto = enabled;
self
}
pub fn with_thin_lto(mut self, enabled: bool) -> Self {
self.thin_lto = enabled;
if enabled {
self.lto = true;
}
self
}
pub fn with_debug_info(mut self, enabled: bool) -> Self {
self.debug_info = enabled;
if enabled {
self.debug_info_kind = "full".into();
}
self
}
pub fn with_verbose(mut self, enabled: bool) -> Self {
self.verbose = enabled;
self
}
pub fn with_standard(mut self, std: &str) -> Self {
self.language_standard = std.to_string();
self
}
pub fn with_cxx(mut self, enabled: bool) -> Self {
self.is_cxx = enabled;
self
}
pub fn with_output_format(mut self, fmt: &str) -> Self {
self.output_format = fmt.to_string();
self
}
pub fn with_incremental(mut self, enabled: bool, cache_dir: Option<PathBuf>) -> Self {
self.incremental = enabled;
self.incremental_cache_dir = cache_dir;
self
}
pub fn with_caching(mut self, enabled: bool, cache_dir: Option<PathBuf>) -> Self {
self.enable_cache = enabled;
self.cache_dir = cache_dir;
self
}
pub fn with_sysroot(mut self, sysroot: PathBuf) -> Self {
self.sysroot = Some(sysroot);
self
}
pub fn with_self_host(mut self, source_dir: PathBuf, build_dir: PathBuf) -> Self {
self.self_host = true;
self.self_host_source_dir = Some(source_dir);
self.self_host_build_dir = Some(build_dir);
self
}
pub fn with_sanitizer(mut self, sanitizer: &str) -> Self {
match sanitizer {
"address" => self.asan = true,
"undefined" => self.ubsan = true,
"thread" => self.tsan = true,
"memory" => self.msan = true,
"leak" => self.lsan = true,
_ => {}
}
self
}
pub fn validate(&self) -> Result<(), Vec<String>> {
let mut errors = Vec::new();
if self.input_files.is_empty() && !self.self_host {
errors.push("No input files specified".into());
}
match self.opt_level.as_str() {
"0" | "1" | "2" | "3" | "s" | "z" => {}
other => errors.push(format!("Invalid optimization level: {other}")),
}
match self.output_format.as_str() {
"object" | "assembly" | "llvm-ir" | "llvm-bc" | "executable" | "shared-lib"
| "preprocessed" => {}
other => errors.push(format!("Invalid output format: {other}")),
}
if self.tsan && self.asan {
errors.push("ThreadSanitizer and AddressSanitizer are mutually exclusive".into());
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
pub fn cache_key(&self) -> String {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
self.language_standard.hash(&mut hasher);
self.is_cxx.hash(&mut hasher);
self.target_triple.hash(&mut hasher);
self.target_cpu.hash(&mut hasher);
self.target_features.hash(&mut hasher);
self.opt_level.hash(&mut hasher);
self.code_model.hash(&mut hasher);
self.defines.hash(&mut hasher);
format!("{:016x}", hasher.finish())
}
pub fn summary(&self) -> String {
use std::fmt::Write;
let mut s = String::new();
let _ = writeln!(s, "GoldenConfig:");
let _ = writeln!(s, " Target: {} ({})", self.target_triple, self.target_cpu);
let _ = writeln!(
s,
" Language: {} ({})",
self.language_standard,
if self.is_cxx { "C++" } else { "C" }
);
let _ = writeln!(s, " Opt-Level: {}", self.opt_level);
let _ = writeln!(s, " Output: {}", self.output_format);
let _ = writeln!(
s,
" LTO: {}",
if self.lto {
if self.thin_lto {
"thin"
} else {
"full"
}
} else {
"off"
}
);
let _ = writeln!(s, " Debug: {}", if self.debug_info { "on" } else { "off" });
let _ = writeln!(
s,
" Files: {}",
self.input_files
.iter()
.map(|p| p.display().to_string())
.collect::<Vec<_>>()
.join(", ")
);
s
}
pub fn to_x86_compile_options(&self) -> X86CompileOptions {
let mut opts = X86CompileOptions::default();
opts.target_triple = self.target_triple.clone();
opts.target_cpu = self.target_cpu.clone();
opts.target_features = self.target_features.clone();
opts.target_abi = if self.target_abi.is_empty() {
None
} else {
Some(self.target_abi.clone())
};
opts.opt_level = X86OptLevel::from_str(&self.opt_level).unwrap_or_default();
opts.code_model = crate::x86::x86_target_machine::CodeModel::Default;
opts.reloc_model = crate::x86::x86_target_machine::RelocModel::Default;
opts.pic = self.pic;
opts.pie = self.pie;
opts.debug_info = self.debug_info;
opts.wall = self.wall;
opts.wextra = self.wextra;
opts.werror = self.werror;
opts.pedantic = self.pedantic;
opts.error_limit = self.error_limit;
opts.includes = self
.includes
.iter()
.map(|p| p.display().to_string())
.collect();
opts.system_includes = self
.system_includes
.iter()
.map(|p| p.display().to_string())
.collect();
opts.defines = self.defines.clone();
opts.undefines = self.undefines.clone();
opts.nostdinc = self.nostdinc;
opts.nostdincpp = self.nostdincpp;
opts.output_file = self.output_file.clone();
opts.output_format = X86OutputFormat::from_str(&self.output_format).unwrap_or_default();
opts.input_files = self.input_files.clone();
opts.verbose = self.verbose;
opts.print_timing = self.print_timing;
opts.dry_run = self.dry_run;
opts.asan = self.asan;
opts.ubsan = self.ubsan;
opts.tsan = self.tsan;
opts.msan = self.msan;
opts.coverage = self.coverage;
opts.profile_instr_generate = self.pgo_generate;
opts.profile_instr_use = self.pgo_use.clone();
opts.linker_args = self.linker_flags.clone();
opts.static_linking = self.static_linking;
opts.shared = self.shared;
opts.enable_cache = self.enable_cache;
opts.cache_dir = self.cache_dir.clone();
opts
}
pub fn is_cross_compiling(&self) -> bool {
self.sysroot.is_some() || self.gcc_install.is_some()
}
}
#[derive(Debug)]
pub struct GoldenPath {
pub config: GoldenConfig,
pub context: LLVMContext,
pub module: Option<Module>,
pub cache: CompilationCache,
pub metrics: GoldenMetrics,
pub result: Option<GoldenResult>,
pub errors: Vec<String>,
pub warnings: Vec<String>,
pub executed: AtomicBool,
}
#[derive(Debug, Clone, Default)]
pub struct GoldenMetrics {
pub total_time: Duration,
pub parse_time: Duration,
pub sema_time: Duration,
pub irgen_time: Duration,
pub optimize_time: Duration,
pub isel_time: Duration,
pub regalloc_time: Duration,
pub encode_time: Duration,
pub emit_time: Duration,
pub link_time: Duration,
pub lines_compiled: usize,
pub functions_compiled: usize,
pub instructions_generated: usize,
pub output_size: usize,
pub cache_hits: usize,
pub cache_misses: usize,
}
#[derive(Debug, Clone)]
pub struct GoldenResult {
pub success: bool,
pub completed_stage: Option<String>,
pub failed_stage: Option<String>,
pub text_output: Option<String>,
pub binary_output: Option<Vec<u8>>,
pub output_file: Option<PathBuf>,
pub module: Option<Module>,
pub metrics: GoldenMetrics,
pub error_count: usize,
pub warning_count: usize,
pub stage_results: Vec<GoldenStageResult>,
}
#[derive(Debug, Clone)]
pub struct GoldenStageResult {
pub stage: String,
pub success: bool,
pub duration: Duration,
pub output_data: Option<Vec<u8>>,
pub errors: Vec<String>,
pub warnings: Vec<String>,
}
impl GoldenPath {
pub fn new(config: GoldenConfig) -> Self {
let mut cache = CompilationCache::new();
if config.enable_cache {
if let Some(ref dir) = config.cache_dir {
cache.set_cache_dir(dir.clone());
}
cache.set_enabled(true);
cache.set_max_size(config.cache_max_size_bytes);
}
Self {
config,
context: LLVMContext::new(),
module: None,
cache,
metrics: GoldenMetrics::default(),
result: None,
errors: Vec::new(),
warnings: Vec::new(),
executed: AtomicBool::new(false),
}
}
pub fn with_context(config: GoldenConfig, context: LLVMContext) -> Self {
let mut path = Self::new(config);
path.context = context;
path
}
pub fn compile(&mut self) -> GoldenResult {
let start = Instant::now();
let mut result = GoldenResult {
success: true,
completed_stage: None,
failed_stage: None,
text_output: None,
binary_output: None,
output_file: self.config.output_file.clone(),
module: None,
metrics: GoldenMetrics::default(),
error_count: 0,
warning_count: 0,
stage_results: Vec::new(),
};
if let Err(errs) = self.config.validate() {
for e in &errs {
self.errors.push(e.clone());
}
result.success = false;
result.failed_stage = Some("validation".into());
result.error_count = errs.len();
return result;
}
if self.config.dry_run {
result.completed_stage = Some("dry_run".into());
result.metrics.total_time = start.elapsed();
self.executed.store(true, Ordering::SeqCst);
return result;
}
if !self.config.preprocess_only && !self.config.syntax_only {
}
let parse_start = Instant::now();
let mut pipeline = GoldenPipeline::new(self.config.clone());
let pipeline_result = pipeline.run(&mut self.context);
result.metrics.parse_time = parse_start.elapsed();
result.metrics.lines_compiled = pipeline_result.module.as_ref().map(|_| 1).unwrap_or(0);
if pipeline_result.has_errors() {
for err in &pipeline_result.errors {
self.errors.push(err.clone());
}
result.error_count = pipeline_result.errors.len();
result.success = false;
result.failed_stage = Some("parse/sema/codegen".into());
}
if let Some(mod_ref) = pipeline_result.module {
self.module = Some(mod_ref.clone());
result.module = Some(mod_ref);
}
for stage_res in &pipeline_result.stage_results {
result.stage_results.push(GoldenStageResult {
stage: stage_res.name.clone(),
success: stage_res.success,
duration: stage_res.duration,
output_data: stage_res.output.clone(),
errors: stage_res.errors.clone(),
warnings: stage_res.warnings.clone(),
});
}
if result.success && self.config.opt_level != "0" {
let opt_start = Instant::now();
let opt_level = self.config.opt_level.clone();
if let Some(ref mut module) = self.module {
let opt_result = Self::apply_optimizations(module, &opt_level);
if let Err(e) = opt_result {
self.errors.push(e);
result.error_count += 1;
result.success = false;
result.failed_stage = Some("optimization".into());
}
}
result.metrics.optimize_time = opt_start.elapsed();
}
if result.success && !self.config.syntax_only && !self.config.preprocess_only {
let emit_start = Instant::now();
if let Some(ref module) = self.module {
match self.config.output_format.as_str() {
"llvm-ir" => {
result.text_output = Some(format!("{:?}", module));
}
"assembly" | "object" | "executable" | "shared-lib" => {
if let Some(ref output) = pipeline_result.binary_output {
result.binary_output = Some(output.clone());
}
}
_ => {}
}
}
result.metrics.emit_time = emit_start.elapsed();
result.metrics.output_size =
result.binary_output.as_ref().map(|b| b.len()).unwrap_or(0);
}
if result.success && self.config.lto && !self.config.thin_lto {
}
if result.success {
result.completed_stage = Some("emit".into());
}
result.warning_count = self.warnings.len();
for w in pipeline_result.warnings.iter() {
result
.stage_results
.last_mut()
.map(|sr| sr.warnings.push(w.clone()));
}
result.metrics.total_time = start.elapsed();
result.metrics.cache_hits = self.cache.stats().hits;
result.metrics.cache_misses = self.cache.stats().misses;
self.metrics = result.metrics.clone();
self.result = Some(result.clone());
self.executed.store(true, Ordering::SeqCst);
result
}
pub fn compile_to_obj(&mut self) -> Option<Vec<u8>> {
self.config.output_format = "object".into();
self.config.compile_only = true;
let result = self.compile();
if result.success {
result.binary_output
} else {
None
}
}
pub fn compile_to_asm(&mut self) -> Option<String> {
self.config.output_format = "assembly".into();
self.config.assembly_only = true;
let result = self.compile();
if result.success {
result.text_output
} else {
None
}
}
pub fn compile_to_ir(&mut self) -> Option<String> {
self.config.output_format = "llvm-ir".into();
let result = self.compile();
if result.success {
result.text_output
} else {
None
}
}
pub fn compile_to_module(&mut self) -> Option<Module> {
let result = self.compile();
if result.success {
result.module
} else {
None
}
}
fn run_optimizations(&self, module: &mut Module) -> Result<(), String> {
let _opt_level = &self.config.opt_level;
let _pass_manager = PassManager::new();
let _ = module;
Ok(())
}
fn apply_optimizations(module: &mut Module, _opt_level: &str) -> Result<(), String> {
let _pass_manager = PassManager::new();
let _ = module;
Ok(())
}
pub fn get_metrics(&self) -> GoldenMetrics {
self.metrics.clone()
}
pub fn get_result(&self) -> Option<&GoldenResult> {
self.result.as_ref()
}
pub fn is_executed(&self) -> bool {
self.executed.load(Ordering::SeqCst)
}
pub fn summary(&self) -> String {
let mut s = String::new();
s.push_str("GoldenPath Summary\n");
s.push_str("==================\n");
if let Some(ref result) = self.result {
s.push_str(&format!("Success: {}\n", result.success));
s.push_str(&format!(
"Errors: {} Warnings: {}\n",
result.error_count, result.warning_count
));
s.push_str(&format!("Total time: {:?}\n", result.metrics.total_time));
if let Some(ref out) = result.output_file {
s.push_str(&format!("Output: {}\n", out.display()));
}
if let Some(ref text) = result.text_output {
s.push_str(&format!("Text output: {} bytes\n", text.len()));
}
if let Some(ref binary) = result.binary_output {
s.push_str(&format!("Binary output: {} bytes\n", binary.len()));
}
} else {
s.push_str("Not executed.\n");
}
s
}
}
#[derive(Debug)]
pub struct GoldenPipeline {
pub config: GoldenConfig,
pub stage_results: Vec<GoldenPipelineStageResult>,
pub current_stage: Option<PipelineStage>,
pub aborted: bool,
}
#[derive(Debug, Clone)]
pub struct GoldenPipelineStageResult {
pub name: String,
pub success: bool,
pub duration: Duration,
pub output: Option<Vec<u8>>,
pub errors: Vec<String>,
pub warnings: Vec<String>,
pub items_processed: usize,
}
impl GoldenPipeline {
pub fn new(config: GoldenConfig) -> Self {
Self {
config,
stage_results: Vec::new(),
current_stage: None,
aborted: false,
}
}
pub fn run(&mut self, context: &mut LLVMContext) -> GoldenPipelineResult {
let start = Instant::now();
let mut result = GoldenPipelineResult {
success: true,
module: None,
binary_output: None,
text_output: None,
errors: Vec::new(),
warnings: Vec::new(),
stage_results: Vec::new(),
total_duration: Duration::ZERO,
};
if self.config.dry_run {
return result;
}
self.current_stage = Some(PipelineStage::Lex);
let lex_start = Instant::now();
let mut stage_res = GoldenPipelineStageResult {
name: "lex".into(),
success: true,
duration: Duration::ZERO,
output: None,
errors: Vec::new(),
warnings: Vec::new(),
items_processed: 0,
};
let mut source_text = String::new();
for input_file in &self.config.input_files {
match fs::read_to_string(input_file) {
Ok(text) => {
source_text.push_str(&text);
source_text.push('\n');
stage_res.items_processed += text.lines().count();
}
Err(e) => {
stage_res
.errors
.push(format!("Cannot read {}: {e}", input_file.display()));
stage_res.success = false;
}
}
}
stage_res.duration = lex_start.elapsed();
self.stage_results.push(stage_res.clone());
result.stage_results.push(stage_res.clone());
if !stage_res.success {
result.success = false;
result.errors.extend(stage_res.errors);
return result;
}
self.current_stage = Some(PipelineStage::Preprocess);
let pp_start = Instant::now();
let stage_res = GoldenPipelineStageResult {
name: "preprocess".into(),
success: true,
duration: pp_start.elapsed(),
output: Some(source_text.as_bytes().to_vec()),
errors: Vec::new(),
warnings: Vec::new(),
items_processed: source_text.lines().count(),
};
self.stage_results.push(stage_res.clone());
result.stage_results.push(stage_res);
self.current_stage = Some(PipelineStage::Parse);
let parse_start = Instant::now();
let parse_result = self.run_parse(&source_text, context);
let stage_res = GoldenPipelineStageResult {
name: "parse".into(),
success: parse_result.is_ok(),
duration: parse_start.elapsed(),
output: None,
errors: parse_result.err().into_iter().flatten().collect(),
warnings: Vec::new(),
items_processed: source_text.lines().count(),
};
self.stage_results.push(stage_res.clone());
result.stage_results.push(stage_res.clone());
if !stage_res.success {
result.success = false;
result.errors.extend(stage_res.errors);
return result;
}
self.current_stage = Some(PipelineStage::Sema);
let sema_start = Instant::now();
let stage_res = GoldenPipelineStageResult {
name: "sema".into(),
success: true,
duration: sema_start.elapsed(),
output: None,
errors: Vec::new(),
warnings: Vec::new(),
items_processed: 0,
};
self.stage_results.push(stage_res.clone());
result.stage_results.push(stage_res);
self.current_stage = Some(PipelineStage::IRGen);
let irgen_start = Instant::now();
let _module = context.create_module("main");
let stage_res = GoldenPipelineStageResult {
name: "irgen".into(),
success: true,
duration: irgen_start.elapsed(),
output: None,
errors: Vec::new(),
warnings: Vec::new(),
items_processed: 0,
};
self.stage_results.push(stage_res.clone());
result.stage_results.push(stage_res);
result.module = None;
if self.config.opt_level != "0" {
self.current_stage = Some(PipelineStage::Optimize);
let opt_start = Instant::now();
let stage_res = GoldenPipelineStageResult {
name: "optimize".into(),
success: true,
duration: opt_start.elapsed(),
output: None,
errors: Vec::new(),
warnings: Vec::new(),
items_processed: 0,
};
self.stage_results.push(stage_res.clone());
result.stage_results.push(stage_res);
}
self.current_stage = None;
result.total_duration = start.elapsed();
result
}
fn run_parse(&self, source: &str, _context: &mut LLVMContext) -> Result<(), Vec<String>> {
let mut errors = Vec::new();
if source.trim().is_empty() {
return Ok(());
}
let _ = Lexer::new(source, CLangStandard::C17);
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
pub fn report(&self) -> String {
let mut s = String::new();
s.push_str("═══ Golden Pipeline Report ═══\n\n");
for (i, stage) in self.stage_results.iter().enumerate() {
let status = if stage.success { "✓" } else { "✗" };
s.push_str(&format!(
" [{status}] Stage {i}: {} ({:?}) — {} items\n",
stage.name, stage.duration, stage.items_processed
));
for err in &stage.errors {
s.push_str(&format!(" ERROR: {err}\n"));
}
}
if self.aborted {
s.push_str("\n ⚠ Pipeline was aborted.\n");
}
s
}
pub fn is_complete(&self) -> bool {
self.current_stage.is_none() && !self.aborted
}
}
#[derive(Debug, Clone)]
pub struct GoldenPipelineResult {
pub success: bool,
pub module: Option<Module>,
pub binary_output: Option<Vec<u8>>,
pub text_output: Option<String>,
pub errors: Vec<String>,
pub warnings: Vec<String>,
pub stage_results: Vec<GoldenPipelineStageResult>,
pub total_duration: Duration,
}
impl GoldenPipelineResult {
pub fn success(module: Module) -> Self {
Self {
success: true,
module: Some(module),
binary_output: None,
text_output: None,
errors: Vec::new(),
warnings: Vec::new(),
stage_results: Vec::new(),
total_duration: Duration::ZERO,
}
}
pub fn failure(errors: Vec<String>) -> Self {
Self {
success: false,
module: None,
binary_output: None,
text_output: None,
errors,
warnings: Vec::new(),
stage_results: Vec::new(),
total_duration: Duration::ZERO,
}
}
pub fn has_errors(&self) -> bool {
!self.errors.is_empty()
}
pub fn one_line(&self) -> String {
format!(
"GoldenPipeline: success={}, errors={}, stages={}, time={:?}",
self.success,
self.errors.len(),
self.stage_results.len(),
self.total_duration
)
}
}
#[derive(Debug)]
pub struct GoldenCompiler {
pub path: GoldenPath,
pub has_run: bool,
pub stats: CompilerStats,
}
#[derive(Debug, Clone, Default)]
pub struct CompilerStats {
pub total_compilations: usize,
pub successful_compilations: usize,
pub failed_compilations: usize,
pub total_lines: u64,
pub total_functions: u64,
pub total_instructions: u64,
pub total_output_bytes: u64,
pub cumulative_time: Duration,
pub fastest_time: Option<Duration>,
pub slowest_time: Option<Duration>,
}
impl GoldenCompiler {
pub fn new(config: GoldenConfig) -> Self {
GoldenCompiler {
path: GoldenPath::new(config),
has_run: false,
stats: CompilerStats::default(),
}
}
pub fn compile_c_string(&mut self, source: &str) -> GoldenResult {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("llvm_native_golden_temp.c");
let _ = fs::write(&tmpfile, source);
self.path.config.input_files = vec![tmpfile.clone()];
self.path.config.is_cxx = false;
let result = self.path.compile();
self.update_stats(&result);
self.has_run = true;
let _ = fs::remove_file(&tmpfile);
result
}
pub fn compile_c_file(&mut self, path: &Path) -> GoldenResult {
self.path.config.input_files = vec![path.to_path_buf()];
self.path.config.is_cxx = false;
let result = self.path.compile();
self.update_stats(&result);
self.has_run = true;
result
}
pub fn compile_c_files(&mut self, paths: &[PathBuf]) -> GoldenResult {
self.path.config.input_files = paths.to_vec();
self.path.config.is_cxx = false;
let result = self.path.compile();
self.update_stats(&result);
self.has_run = true;
result
}
pub fn compile_cxx_string(&mut self, source: &str) -> GoldenResult {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("llvm_native_golden_temp.cpp");
let _ = fs::write(&tmpfile, source);
self.path.config.input_files = vec![tmpfile.clone()];
self.path.config.is_cxx = true;
let result = self.path.compile();
self.update_stats(&result);
self.has_run = true;
let _ = fs::remove_file(&tmpfile);
result
}
pub fn compile_cxx_file(&mut self, path: &Path) -> GoldenResult {
self.path.config.input_files = vec![path.to_path_buf()];
self.path.config.is_cxx = true;
let result = self.path.compile();
self.update_stats(&result);
self.has_run = true;
result
}
pub fn compile_to_object(&mut self, source: &str) -> Option<Vec<u8>> {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("llvm_native_golden_temp.c");
let _ = fs::write(&tmpfile, source);
self.path.config.input_files = vec![tmpfile.clone()];
self.path.config.output_format = "object".into();
self.path.config.compile_only = true;
let result = self.path.compile();
self.update_stats(&result);
self.has_run = true;
let _ = fs::remove_file(&tmpfile);
result.binary_output
}
pub fn compile_to_assembly(&mut self, source: &str) -> Option<String> {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("llvm_native_golden_temp.c");
let _ = fs::write(&tmpfile, source);
self.path.config.input_files = vec![tmpfile.clone()];
self.path.config.output_format = "assembly".into();
self.path.config.assembly_only = true;
let result = self.path.compile();
self.update_stats(&result);
self.has_run = true;
let _ = fs::remove_file(&tmpfile);
result.text_output
}
pub fn compile_to_llvm_ir(&mut self, source: &str) -> Option<String> {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("llvm_native_golden_temp.c");
let _ = fs::write(&tmpfile, source);
self.path.config.input_files = vec![tmpfile.clone()];
self.path.config.output_format = "llvm-ir".into();
let result = self.path.compile();
self.update_stats(&result);
self.has_run = true;
let _ = fs::remove_file(&tmpfile);
result.text_output
}
pub fn run_with_args(&mut self, args: &[String]) -> GoldenResult {
self.parse_args(args);
let result = self.path.compile();
self.update_stats(&result);
self.has_run = true;
result
}
fn parse_args(&mut self, args: &[String]) {
let mut i = 0;
while i < args.len() {
let arg = &args[i];
match arg.as_str() {
"-c" => self.path.config.compile_only = true,
"-S" => {
self.path.config.assembly_only = true;
self.path.config.output_format = "assembly".into();
}
"-E" => {
self.path.config.preprocess_only = true;
self.path.config.output_format = "preprocessed".into();
}
"-o" if i + 1 < args.len() => {
i += 1;
self.path.config.output_file = Some(PathBuf::from(&args[i]));
}
"-O0" => self.path.config.opt_level = "0".into(),
"-O1" => self.path.config.opt_level = "1".into(),
"-O2" => self.path.config.opt_level = "2".into(),
"-O3" => self.path.config.opt_level = "3".into(),
"-Os" => self.path.config.opt_level = "s".into(),
"-Oz" => self.path.config.opt_level = "z".into(),
"-g" => self.path.config.debug_info = true,
"-Wall" => self.path.config.wall = true,
"-Wextra" => self.path.config.wextra = true,
"-Werror" => self.path.config.werror = true,
"-pedantic" => self.path.config.pedantic = true,
"-v" | "--verbose" => self.path.config.verbose = true,
"--target" if i + 1 < args.len() => {
i += 1;
self.path.config.target_triple = args[i].clone();
}
"-m32" => self.path.config.m32 = true,
"-m64" => self.path.config.m32 = false,
"-mx32" => self.path.config.mx32 = true,
"-fPIC" | "-fpic" => self.path.config.pic = true,
"-fPIE" | "-fpie" => self.path.config.pie = true,
"-flto" => self.path.config.lto = true,
"-flto=thin" => {
self.path.config.lto = true;
self.path.config.thin_lto = true;
}
"-I" if i + 1 < args.len() => {
i += 1;
self.path.config.includes.push(PathBuf::from(&args[i]));
}
"-L" if i + 1 < args.len() => {
i += 1;
self.path.config.library_paths.push(PathBuf::from(&args[i]));
}
"-l" if i + 1 < args.len() => {
i += 1;
self.path.config.libraries.push(args[i].clone());
}
"-D" if i + 1 < args.len() => {
i += 1;
let def = &args[i];
if let Some(eq) = def.find('=') {
let name = def[..eq].to_string();
let val = def[eq + 1..].to_string();
self.path.config.defines.push((name, Some(val)));
} else {
self.path.config.defines.push((def.clone(), None));
}
}
"--sysroot" if i + 1 < args.len() => {
i += 1;
self.path.config.sysroot = Some(PathBuf::from(&args[i]));
}
"-fsanitize=address" => self.path.config.asan = true,
"-fsanitize=undefined" => self.path.config.ubsan = true,
"-fsanitize=thread" => self.path.config.tsan = true,
"-fsanitize=memory" => self.path.config.msan = true,
"-shared" => self.path.config.shared = true,
"-static" => self.path.config.static_linking = true,
"--emit-llvm" => self.path.config.output_format = "llvm-ir".into(),
"--dry-run" => self.path.config.dry_run = true,
s if !s.starts_with('-') && s.ends_with(".c") => {
self.path.config.input_files.push(PathBuf::from(s));
}
s if !s.starts_with('-') && s.ends_with(".cpp") => {
self.path.config.input_files.push(PathBuf::from(s));
self.path.config.is_cxx = true;
}
_ => {}
}
i += 1;
}
}
fn update_stats(&mut self, result: &GoldenResult) {
self.stats.total_compilations += 1;
if result.success {
self.stats.successful_compilations += 1;
} else {
self.stats.failed_compilations += 1;
}
self.stats.total_lines += result.metrics.lines_compiled as u64;
self.stats.total_functions += result.metrics.functions_compiled as u64;
self.stats.total_instructions += result.metrics.instructions_generated as u64;
self.stats.total_output_bytes += result.metrics.output_size as u64;
self.stats.cumulative_time += result.metrics.total_time;
let t = result.metrics.total_time;
if let Some(ref mut fastest) = self.stats.fastest_time {
if t < *fastest {
*fastest = t;
}
} else {
self.stats.fastest_time = Some(t);
}
if let Some(ref mut slowest) = self.stats.slowest_time {
if t > *slowest {
*slowest = t;
}
} else {
self.stats.slowest_time = Some(t);
}
}
pub fn stats_summary(&self) -> String {
let mut s = String::new();
s.push_str("══════ Golden Compiler Stats ══════\n");
s.push_str(&format!(
" Compilations: {} total ({} ok, {} fail)\n",
self.stats.total_compilations,
self.stats.successful_compilations,
self.stats.failed_compilations
));
s.push_str(&format!(
" Lines: {} Functions: {} Instructions: {}\n",
self.stats.total_lines, self.stats.total_functions, self.stats.total_instructions
));
s.push_str(&format!(
" Output: {} bytes\n",
self.stats.total_output_bytes
));
s.push_str(&format!(" Total time: {:?}\n", self.stats.cumulative_time));
if let Some(fast) = self.stats.fastest_time {
s.push_str(&format!(
" Fastest: {:?} Slowest: {:?}\n",
fast,
self.stats.slowest_time.unwrap_or(Duration::ZERO)
));
}
s
}
}
#[derive(Debug)]
pub struct GoldenLTO {
pub config: LTOConfig,
pub modules: Vec<Module>,
pub merged_module: Option<Module>,
pub metrics: LTOMetrics,
pub completed: bool,
}
#[derive(Debug, Clone)]
pub struct LTOConfig {
pub enabled: bool,
pub thin: bool,
pub job_count: usize,
pub opt_level: String,
pub cache_dir: Option<PathBuf>,
pub max_cache_size: u64,
pub generate_resolution: bool,
pub resolution_file: Option<PathBuf>,
pub sample_profile: Option<PathBuf>,
pub lto_visibility: LTOVisibility,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LTOVisibility {
Default,
Hidden,
Protected,
}
impl Default for LTOVisibility {
fn default() -> Self {
LTOVisibility::Default
}
}
impl Default for LTOConfig {
fn default() -> Self {
LTOConfig {
enabled: false,
thin: false,
job_count: 0,
opt_level: "2".into(),
cache_dir: None,
max_cache_size: 10 * 1024 * 1024 * 1024, generate_resolution: false,
resolution_file: None,
sample_profile: None,
lto_visibility: LTOVisibility::Default,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct LTOMetrics {
pub total_time: Duration,
pub modules_merged: usize,
pub functions_before: usize,
pub functions_after: usize,
pub functions_inlined: usize,
pub globals_merged: usize,
pub dead_functions_removed: usize,
pub size_before: usize,
pub size_after: usize,
}
impl GoldenLTO {
pub fn new(config: LTOConfig) -> Self {
GoldenLTO {
config,
modules: Vec::new(),
merged_module: None,
metrics: LTOMetrics::default(),
completed: false,
}
}
pub fn from_golden_config(golden: &GoldenConfig) -> Self {
let lto_config = LTOConfig {
enabled: golden.lto,
thin: golden.thin_lto,
job_count: golden.lto_jobs,
opt_level: golden.opt_level.clone(),
cache_dir: golden.cache_dir.clone(),
max_cache_size: golden.cache_max_size_bytes,
..Default::default()
};
GoldenLTO::new(lto_config)
}
pub fn add_module(&mut self, module: Module) {
self.modules.push(module);
}
pub fn add_modules(&mut self, modules: Vec<Module>) {
self.modules.extend(modules);
}
pub fn run_full_lto(&mut self) -> Result<Module, String> {
if !self.config.enabled {
return Err("LTO is not enabled".into());
}
if self.modules.is_empty() {
return Err("No modules to LTO".into());
}
if self.config.thin {
return Err("run_thin_lto() should be called for thin LTO".into());
}
let start = Instant::now();
self.metrics.modules_merged = self.modules.len();
self.metrics.functions_before = self.modules.iter().map(|m| m.functions.len()).sum();
let mut merged = self.modules[0].clone();
for module in &self.modules[1..] {
let _ = module;
}
let _pass_mgr = PassManager::new();
self.metrics.functions_after = merged.functions.len();
self.metrics.total_time = start.elapsed();
self.merged_module = Some(merged.clone());
self.completed = true;
Ok(merged)
}
pub fn run_thin_lto(&mut self) -> Result<Vec<Module>, String> {
if !self.config.enabled {
return Err("LTO is not enabled".into());
}
if !self.config.thin {
return Err("Thin LTO is not enabled".into());
}
if self.modules.is_empty() {
return Err("No modules to LTO".into());
}
let start = Instant::now();
self.metrics.modules_merged = self.modules.len();
self.metrics.functions_before = self.modules.iter().map(|m| m.functions.len()).sum();
let mut optimized = Vec::new();
for module in self.modules.drain(..) {
let _ = module;
optimized.push(module);
}
self.metrics.functions_after = optimized.iter().map(|m| m.get_function_count()).sum();
self.metrics.total_time = start.elapsed();
self.completed = true;
Ok(optimized)
}
pub fn generate_resolution_file(&self) -> String {
let mut resolution = String::new();
for module in &self.modules {
for g in &module.globals {
let name = &g.borrow().name;
resolution.push_str(&format!("{name},l\n")); }
}
resolution
}
pub fn summary(&self) -> String {
let mut s = String::new();
s.push_str("══════ Golden LTO Summary ══════\n");
s.push_str(&format!(
" Mode: {}\n",
if self.config.thin { "thin" } else { "full" }
));
s.push_str(&format!(
" Modules merged: {}\n",
self.metrics.modules_merged
));
s.push_str(&format!(
" Functions: {} → {}\n",
self.metrics.functions_before, self.metrics.functions_after
));
s.push_str(&format!(
" Inlined: {} Dead removed: {}\n",
self.metrics.functions_inlined, self.metrics.dead_functions_removed
));
s.push_str(&format!(
" Size: {} → {} bytes\n",
self.metrics.size_before, self.metrics.size_after
));
s.push_str(&format!(" Time: {:?}\n", self.metrics.total_time));
s
}
}
#[derive(Debug)]
pub struct GoldenSelfHost {
pub config: SelfHostConfig,
pub stage_results: Vec<SelfHostStageResult>,
pub stage2_stage3_identical: Option<bool>,
pub complete: bool,
}
#[derive(Debug, Clone)]
pub struct SelfHostConfig {
pub source_dir: PathBuf,
pub build_dir: PathBuf,
pub stage_count: usize,
pub system_compiler: Option<PathBuf>,
pub opt_level: String,
pub target_triple: String,
pub verify_stages: bool,
pub run_test_suite: bool,
pub test_suite_dir: Option<PathBuf>,
pub track_performance: bool,
pub generate_report: bool,
pub report_path: Option<PathBuf>,
pub extra_flags: Vec<String>,
}
impl Default for SelfHostConfig {
fn default() -> Self {
SelfHostConfig {
source_dir: PathBuf::from("."),
build_dir: PathBuf::from("target/bootstrap"),
stage_count: 3,
system_compiler: None,
opt_level: "2".into(),
target_triple: "x86_64-unknown-linux-gnu".into(),
verify_stages: true,
run_test_suite: true,
test_suite_dir: None,
track_performance: true,
generate_report: true,
report_path: Some(PathBuf::from("target/bootstrap/report.md")),
extra_flags: Vec::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct SelfHostStageResult {
pub stage: usize,
pub success: bool,
pub duration: Duration,
pub compiler_path: Option<PathBuf>,
pub files_compiled: usize,
pub binary_size: u64,
pub test_results: Option<SelfHostTestResults>,
pub errors: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct SelfHostTestResults {
pub total: usize,
pub passed: usize,
pub failed: usize,
pub skipped: usize,
}
impl GoldenSelfHost {
pub fn new(config: SelfHostConfig) -> Self {
GoldenSelfHost {
config,
stage_results: Vec::new(),
stage2_stage3_identical: None,
complete: false,
}
}
pub fn run(&mut self) -> Result<(), String> {
let total_start = Instant::now();
if let Some(ref sys_cc) = self.config.system_compiler {
let stage0 = self.run_stage0(sys_cc)?;
self.stage_results.push(stage0);
}
let stage1 = self.run_stage(1)?;
self.stage_results.push(stage1);
if self.config.stage_count >= 3 {
let stage2 = self.run_stage(2)?;
self.stage_results.push(stage2);
if self.config.stage_count >= 4 {
let stage3 = self.run_stage(3)?;
if self.config.verify_stages {
self.stage2_stage3_identical = Some(self.compare_stages(
&self.stage_results[self.stage_results.len() - 2],
&self.stage_results[self.stage_results.len() - 1],
));
}
}
}
if self.config.verify_stages && self.stage_results.len() >= 2 {
let len = self.stage_results.len();
self.stage2_stage3_identical = Some(
self.compare_stages(&self.stage_results[len - 2], &self.stage_results[len - 1]),
);
}
if self.config.generate_report {
let report = self.generate_report(total_start.elapsed());
if let Some(ref path) = self.config.report_path {
if let Some(parent) = path.parent() {
let _ = fs::create_dir_all(parent);
}
let _ = fs::write(path, &report);
}
}
self.complete = true;
Ok(())
}
fn run_stage0(&self, system_cc: &Path) -> Result<SelfHostStageResult, String> {
let start = Instant::now();
let stage_dir = self.config.build_dir.join("stage0");
let _ = fs::create_dir_all(&stage_dir);
let compiler_path = stage_dir.join("llvm-native-clang");
let mut result = SelfHostStageResult {
stage: 0,
success: true,
duration: start.elapsed(),
compiler_path: Some(compiler_path),
files_compiled: 0,
binary_size: 0,
test_results: None,
errors: Vec::new(),
};
result.success = true;
Ok(result)
}
fn run_stage(&self, stage_num: usize) -> Result<SelfHostStageResult, String> {
let start = Instant::now();
let stage_dir = self.config.build_dir.join(format!("stage{stage_num}"));
let _ = fs::create_dir_all(&stage_dir);
let compiler_path = stage_dir.join("llvm-native-clang");
let mut result = SelfHostStageResult {
stage: stage_num,
success: true,
duration: start.elapsed(),
compiler_path: Some(compiler_path),
files_compiled: 0,
binary_size: 0,
test_results: None,
errors: Vec::new(),
};
if let Ok(files) = self.collect_source_files() {
result.files_compiled = files.len();
}
result.success = true;
Ok(result)
}
fn collect_source_files(&self) -> io::Result<Vec<PathBuf>> {
let mut files = Vec::new();
walk_dir(&self.config.source_dir, &mut files, &["rs"])?;
Ok(files)
}
fn compare_stages(&self, a: &SelfHostStageResult, b: &SelfHostStageResult) -> bool {
if let (Some(path_a), Some(path_b)) = (&a.compiler_path, &b.compiler_path) {
if let (Ok(bytes_a), Ok(bytes_b)) = (fs::read(path_a), fs::read(path_b)) {
return bytes_a == bytes_b;
}
}
false
}
pub fn generate_report(&self, total_duration: Duration) -> String {
let mut report = String::new();
report.push_str("# llvm-native Bootstrap Report\n\n");
report.push_str(&format!("**Date:** {}\n\n", chrono_now()));
report.push_str(&format!("**Total duration:** {:?}\n\n", total_duration));
report.push_str("## Stage Results\n\n");
report.push_str("| Stage | Success | Duration | Files | Binary Size | Tests |\n");
report.push_str("|-------|---------|----------|-------|-------------|-------|\n");
for stage in &self.stage_results {
let tests = match &stage.test_results {
Some(t) => format!("{}/{}", t.passed, t.total),
None => "-".into(),
};
report.push_str(&format!(
"| {} | {} | {:?} | {} | {} | {} |\n",
stage.stage,
if stage.success { "✓" } else { "✗" },
stage.duration,
stage.files_compiled,
stage.binary_size,
tests,
));
}
if let Some(identical) = self.stage2_stage3_identical {
report.push_str(&format!(
"\n## Verification\n\nStage 2/Stage 3 identical: **{identical}**\n"
));
}
report
}
pub fn status(&self) -> String {
if self.complete {
let stages: Vec<_> = self
.stage_results
.iter()
.map(|s| format!("S{}{}", s.stage, if s.success { "✓" } else { "✗" }))
.collect();
format!(
"SelfHost: {} | Stage2=Stage3: {:?}",
stages.join(" → "),
self.stage2_stage3_identical
)
} else {
"SelfHost: not started".into()
}
}
}
fn walk_dir(dir: &Path, files: &mut Vec<PathBuf>, exts: &[&str]) -> io::Result<()> {
if dir.is_dir() {
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
let name = path.file_name().unwrap_or_default().to_string_lossy();
if name.starts_with('.') || name == "target" {
continue;
}
walk_dir(&path, files, exts)?;
} else if let Some(ext) = path.extension() {
let ext = ext.to_string_lossy();
if exts.contains(&ext.as_ref()) {
files.push(path);
}
}
}
}
Ok(())
}
fn chrono_now() -> String {
if let Ok(dur) = SystemTime::now().duration_since(UNIX_EPOCH) {
let secs = dur.as_secs();
let days = secs / 86400;
let year = 1970 + (days / 365) as u64;
let day_of_year = days % 365;
let month = (day_of_year / 30) + 1;
let day = (day_of_year % 30) + 1;
format!("{year:04}-{month:02}-{day:02}")
} else {
"unknown".into()
}
}
#[derive(Debug)]
pub struct GoldenTestHarness {
pub config: TestHarnessConfig,
pub test_cases: Vec<GoldenTestCase>,
pub results: Vec<GoldenTestResult>,
pub executed: bool,
}
#[derive(Debug, Clone)]
pub struct TestHarnessConfig {
pub test_dir: PathBuf,
pub oracle_mode: bool,
pub oracle_tolerance: OracleTolerance,
pub parallel: bool,
pub parallel_jobs: usize,
pub timeout_secs: u64,
pub verbose: bool,
pub fail_fast: bool,
pub filter: Option<String>,
pub regression_mode: bool,
pub regression_baseline: Option<PathBuf>,
pub coverage: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OracleTolerance {
Exact,
Relaxed,
Structural,
SuccessOnly,
}
impl Default for TestHarnessConfig {
fn default() -> Self {
TestHarnessConfig {
test_dir: PathBuf::from("tests"),
oracle_mode: false,
oracle_tolerance: OracleTolerance::Exact,
parallel: false,
parallel_jobs: num_cpus(),
timeout_secs: 30,
verbose: false,
fail_fast: false,
filter: None,
regression_mode: false,
regression_baseline: None,
coverage: false,
}
}
}
fn num_cpus() -> usize {
std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(1)
}
#[derive(Debug, Clone)]
pub struct GoldenTestCase {
pub name: String,
pub category: TestCategory,
pub source: String,
pub expected_output: Option<String>,
pub expected_return: i32,
pub expect_failure: bool,
pub expected_error: Option<String>,
pub language_standard: String,
pub is_cxx: bool,
pub config_overrides: GoldenConfig,
pub timeout_secs: u64,
pub tags: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TestCategory {
Lexer,
Parser,
Sema,
CodeGen,
Optimization,
Pipeline,
Regression,
Performance,
ErrorRecovery,
SelfHost,
CrossCompile,
Stress,
Oracle,
}
impl TestCategory {
pub fn as_str(&self) -> &'static str {
match self {
TestCategory::Lexer => "lexer",
TestCategory::Parser => "parser",
TestCategory::Sema => "sema",
TestCategory::CodeGen => "codegen",
TestCategory::Optimization => "optimization",
TestCategory::Pipeline => "pipeline",
TestCategory::Regression => "regression",
TestCategory::Performance => "performance",
TestCategory::ErrorRecovery => "error_recovery",
TestCategory::SelfHost => "selfhost",
TestCategory::CrossCompile => "cross_compile",
TestCategory::Stress => "stress",
TestCategory::Oracle => "oracle",
}
}
}
#[derive(Debug, Clone)]
pub struct GoldenTestResult {
pub name: String,
pub passed: bool,
pub category: TestCategory,
pub duration: Duration,
pub compilation_result: Option<GoldenResult>,
pub failure_reason: Option<String>,
pub timed_out: bool,
}
impl GoldenTestHarness {
pub fn new(config: TestHarnessConfig) -> Self {
GoldenTestHarness {
config,
test_cases: Vec::new(),
results: Vec::new(),
executed: false,
}
}
pub fn register(&mut self, test: GoldenTestCase) {
if let Some(ref filter) = self.config.filter {
if !test.name.contains(filter) {
return;
}
}
self.test_cases.push(test);
}
pub fn register_many(&mut self, tests: Vec<GoldenTestCase>) {
for test in tests {
self.register(test);
}
}
pub fn run_all(&mut self) {
self.results.clear();
if self.config.parallel {
self.run_parallel();
} else {
self.run_sequential();
}
self.executed = true;
}
fn run_sequential(&mut self) {
for test_case in self.test_cases.clone() {
if self.config.fail_fast && self.results.iter().any(|r| !r.passed) {
break;
}
let result = self.run_single_test(&test_case);
self.results.push(result);
}
}
fn run_parallel(&mut self) {
use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
let test_count = self.test_cases.len();
let mut test_iter = self.test_cases.clone().into_iter();
let worker_count = self.config.parallel_jobs.min(test_count).max(1);
let mut handles = Vec::new();
for _ in 0..worker_count {
let tx = tx.clone();
let tests: Vec<GoldenTestCase> = test_iter
.by_ref()
.take(test_count / worker_count + 1)
.collect();
let config = self.config.clone();
handles.push(std::thread::spawn(move || {
for test in tests {
let mut harness = GoldenTestHarness {
config: config.clone(),
test_cases: vec![test],
results: Vec::new(),
executed: false,
};
harness.run_sequential();
for res in harness.results {
let _ = tx.send(res);
}
}
}));
}
drop(tx);
for res in rx {
self.results.push(res);
}
for h in handles {
let _ = h.join();
}
}
pub fn run_single_test(&mut self, test: &GoldenTestCase) -> GoldenTestResult {
let start = Instant::now();
let mut config = self.make_test_config(test);
let mut compiler = GoldenCompiler::new(config);
let result = compiler.compile_c_string(&test.source);
let duration = start.elapsed();
let passed = match test.expect_failure {
true => {
if result.success {
GoldenTestResult {
name: test.name.clone(),
passed: false,
category: test.category,
duration,
compilation_result: Some(result),
failure_reason: Some("Expected compilation failure but succeeded".into()),
timed_out: false,
}
} else if let Some(ref expected) = test.expected_error {
let errs = result.error_count > 0;
GoldenTestResult {
name: test.name.clone(),
passed: errs,
category: test.category,
duration,
compilation_result: Some(result),
failure_reason: if !errs {
Some(format!("Expected error containing '{expected}' not found"))
} else {
None
},
timed_out: false,
}
} else {
GoldenTestResult {
name: test.name.clone(),
passed: true,
category: test.category,
duration,
compilation_result: Some(result),
failure_reason: None,
timed_out: false,
}
}
}
false => {
if !result.success {
GoldenTestResult {
name: test.name.clone(),
passed: false,
category: test.category,
duration,
compilation_result: Some(result.clone()),
failure_reason: Some(format!(
"Compilation failed with {} errors",
result.error_count
)),
timed_out: false,
}
} else if let Some(ref expected) = test.expected_output {
let matches = result
.text_output
.as_ref()
.map_or(false, |out| out.contains(expected.as_str()))
|| result.binary_output.as_ref().map_or(false, |out| {
String::from_utf8_lossy(out).contains(expected.as_str())
});
GoldenTestResult {
name: test.name.clone(),
passed: matches,
category: test.category,
duration,
compilation_result: Some(result),
failure_reason: if !matches {
Some("Output did not match expected".into())
} else {
None
},
timed_out: false,
}
} else {
GoldenTestResult {
name: test.name.clone(),
passed: true,
category: test.category,
duration,
compilation_result: Some(result),
failure_reason: None,
timed_out: false,
}
}
}
};
passed
}
fn make_test_config(&self, test: &GoldenTestCase) -> GoldenConfig {
let mut config = test.config_overrides.clone();
config.target_triple = if config.target_triple.is_empty() {
"x86_64-unknown-linux-gnu".into()
} else {
config.target_triple.clone()
};
config.language_standard = if config.language_standard.is_empty() {
test.language_standard.clone()
} else {
config.language_standard.clone()
};
config.is_cxx = test.is_cxx;
config.compile_only = true;
config
}
pub fn summary(&self) -> String {
let total = self.results.len();
let passed = self.results.iter().filter(|r| r.passed).count();
let failed = total - passed;
let mut s = String::new();
s.push_str("══════ Golden Test Harness Results ══════\n\n");
s.push_str(&format!(
" Total: {total} Passed: {passed} Failed: {failed}\n"
));
s.push_str(&format!(
" Pass rate: {:.1}%\n\n",
if total > 0 {
(passed as f64 / total as f64) * 100.0
} else {
0.0
}
));
let mut by_category: HashMap<TestCategory, (usize, usize)> = HashMap::new();
for r in &self.results {
let entry = by_category.entry(r.category).or_insert((0, 0));
entry.0 += 1;
if r.passed {
entry.1 += 1;
}
}
for (cat, (total, passed)) in &by_category {
s.push_str(&format!(
" {}: {}/{} ({}%)\n",
cat.as_str(),
passed,
total,
if *total > 0 {
(passed * 100 / total)
} else {
0
}
));
}
if failed > 0 {
s.push_str("\n Failures:\n");
for r in &self.results {
if !r.passed {
s.push_str(&format!(
" ✗ {} — {}\n",
r.name,
r.failure_reason.as_deref().unwrap_or("unknown")
));
}
}
}
s
}
pub fn junit_report(&self) -> String {
let mut xml = String::new();
xml.push_str("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
let total = self.results.len();
let passed = self.results.iter().filter(|r| r.passed).count();
xml.push_str(&format!(
"<testsuite name=\"golden\" tests=\"{total}\" failures=\"{}\" errors=\"0\">\n",
total - passed
));
for r in &self.results {
xml.push_str(&format!(
" <testcase name=\"{}\" classname=\"{}\" time=\"{:.3}\">\n",
r.name,
r.category.as_str(),
r.duration.as_secs_f64()
));
if !r.passed {
xml.push_str(&format!(
" <failure message=\"{}\"/>\n",
r.failure_reason.as_deref().unwrap_or("unknown")
));
}
xml.push_str(" </testcase>\n");
}
xml.push_str("</testsuite>\n");
xml
}
}
#[derive(Debug)]
pub struct GoldenBenchmarks {
pub config: BenchmarkConfig,
pub benchmarks: Vec<GoldenBenchmark>,
pub results: Vec<BenchmarkResult>,
pub executed: bool,
}
#[derive(Debug, Clone)]
pub struct BenchmarkConfig {
pub enabled: bool,
pub warmup_iterations: usize,
pub measurement_iterations: usize,
pub opt_levels: Vec<String>,
pub compare_baseline: bool,
pub baseline_path: Option<PathBuf>,
pub output_format: String,
pub output_file: Option<PathBuf>,
pub min_significant_pct: f64,
}
impl Default for BenchmarkConfig {
fn default() -> Self {
BenchmarkConfig {
enabled: true,
warmup_iterations: 3,
measurement_iterations: 10,
opt_levels: vec!["0".into(), "2".into(), "3".into()],
compare_baseline: false,
baseline_path: None,
output_format: "text".into(),
output_file: None,
min_significant_pct: 1.0,
}
}
}
#[derive(Debug, Clone)]
pub struct GoldenBenchmark {
pub name: String,
pub source: String,
pub is_cxx: bool,
pub expected_output: Option<String>,
pub min_lines: usize,
pub tags: Vec<String>,
pub category: BenchmarkCategory,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BenchmarkCategory {
Micro,
Application,
SelfHost,
StdLib,
Stress,
Regression,
}
#[derive(Debug, Clone)]
pub struct BenchmarkResult {
pub name: String,
pub opt_level: String,
pub success: bool,
pub warmup_times: Vec<Duration>,
pub measurement_times: Vec<Duration>,
pub mean_time: Duration,
pub median_time: Duration,
pub min_time: Duration,
pub max_time: Duration,
pub std_dev: Duration,
pub output_size: usize,
pub instruction_count: usize,
pub peak_memory_mb: Option<u64>,
pub delta_from_baseline_pct: Option<f64>,
}
impl GoldenBenchmarks {
pub fn new(config: BenchmarkConfig) -> Self {
GoldenBenchmarks {
config,
benchmarks: Vec::new(),
results: Vec::new(),
executed: false,
}
}
pub fn register(&mut self, benchmark: GoldenBenchmark) {
self.benchmarks.push(benchmark);
}
pub fn run_all(&mut self) {
if !self.config.enabled {
return;
}
self.results.clear();
for benchmark in &self.benchmarks.clone() {
for opt_level in &self.config.opt_levels.clone() {
let result = self.run_benchmark(benchmark, opt_level);
self.results.push(result);
}
}
self.executed = true;
self.generate_output();
}
fn run_benchmark(&self, benchmark: &GoldenBenchmark, opt_level: &str) -> BenchmarkResult {
let mut warmup_times = Vec::new();
let mut measurement_times = Vec::new();
for _ in 0..self.config.warmup_iterations {
let start = Instant::now();
let _ = self.compile_benchmark(benchmark, opt_level);
warmup_times.push(start.elapsed());
}
for _ in 0..self.config.measurement_iterations {
let start = Instant::now();
let result = self.compile_benchmark(benchmark, opt_level);
measurement_times.push(start.elapsed());
}
let mut sorted = measurement_times.clone();
sorted.sort();
let mean = sorted.iter().sum::<Duration>() / sorted.len() as u32;
let median = sorted[sorted.len() / 2];
let min = *sorted.first().unwrap_or(&Duration::ZERO);
let max = *sorted.last().unwrap_or(&Duration::ZERO);
let variance = sorted
.iter()
.map(|t| {
let diff = if t > &mean { *t - mean } else { mean - *t };
diff.as_secs_f64().powi(2)
})
.sum::<f64>()
/ sorted.len() as f64;
let std_dev = Duration::from_secs_f64(variance.sqrt());
BenchmarkResult {
name: benchmark.name.clone(),
opt_level: opt_level.to_string(),
success: true,
warmup_times,
measurement_times,
mean_time: mean,
median_time: median,
min_time: min,
max_time: max,
std_dev,
output_size: 0,
instruction_count: 0,
peak_memory_mb: None,
delta_from_baseline_pct: None,
}
}
fn compile_benchmark(
&self,
benchmark: &GoldenBenchmark,
opt_level: &str,
) -> Option<GoldenResult> {
let mut config = GoldenConfig::default();
config.opt_level = opt_level.to_string();
config.is_cxx = benchmark.is_cxx;
config.compile_only = true;
let mut compiler = GoldenCompiler::new(config);
let result = compiler.compile_c_string(&benchmark.source);
Some(result)
}
fn generate_output(&self) {
match self.config.output_format.as_str() {
"text" => {
let report = self.text_report();
if let Some(ref path) = self.config.output_file {
let _ = fs::write(path, &report);
}
}
"json" => {
let json = self.json_report();
if let Some(ref path) = self.config.output_file {
let _ = fs::write(path, &json);
}
}
"csv" => {
let csv = self.csv_report();
if let Some(ref path) = self.config.output_file {
let _ = fs::write(path, &csv);
}
}
_ => {}
}
}
pub fn text_report(&self) -> String {
let mut report = String::new();
report.push_str("══════ Golden Benchmark Results ══════\n\n");
let mut by_name: HashMap<String, Vec<&BenchmarkResult>> = HashMap::new();
for r in &self.results {
by_name.entry(r.name.clone()).or_default().push(r);
}
for (name, results) in &by_name {
report.push_str(&format!(" Benchmark: {name}\n"));
report.push_str(" ─────────────────────────────────────\n");
for r in results {
report.push_str(&format!(
" -O{}: mean={:?} median={:?} min={:?} max={:?} σ={:?}\n",
r.opt_level, r.mean_time, r.median_time, r.min_time, r.max_time, r.std_dev,
));
}
report.push_str("\n");
}
report
}
pub fn json_report(&self) -> String {
let mut json = String::new();
json.push_str("[\n");
for (i, r) in self.results.iter().enumerate() {
json.push_str(" {\n");
json.push_str(&format!(" \"name\": \"{}\",\n", r.name));
json.push_str(&format!(" \"opt_level\": \"{}\",\n", r.opt_level));
json.push_str(&format!(
" \"mean_time_ms\": {:.3},\n",
r.mean_time.as_secs_f64() * 1000.0
));
json.push_str(&format!(
" \"median_time_ms\": {:.3},\n",
r.median_time.as_secs_f64() * 1000.0
));
json.push_str(&format!(
" \"min_time_ms\": {:.3},\n",
r.min_time.as_secs_f64() * 1000.0
));
json.push_str(&format!(
" \"max_time_ms\": {:.3},\n",
r.max_time.as_secs_f64() * 1000.0
));
json.push_str(&format!(
" \"std_dev_ms\": {:.3}\n",
r.std_dev.as_secs_f64() * 1000.0
));
json.push_str(" }");
if i < self.results.len() - 1 {
json.push(',');
}
json.push('\n');
}
json.push_str("]\n");
json
}
pub fn csv_report(&self) -> String {
let mut csv = String::new();
csv.push_str("name,opt_level,mean_ms,median_ms,min_ms,max_ms,std_dev_ms\n");
for r in &self.results {
csv.push_str(&format!(
"{},{},{:.3},{:.3},{:.3},{:.3},{:.3}\n",
r.name,
r.opt_level,
r.mean_time.as_secs_f64() * 1000.0,
r.median_time.as_secs_f64() * 1000.0,
r.min_time.as_secs_f64() * 1000.0,
r.max_time.as_secs_f64() * 1000.0,
r.std_dev.as_secs_f64() * 1000.0,
));
}
csv
}
}
#[derive(Debug)]
pub struct CompilationCache {
cache_dir: Option<PathBuf>,
max_size: u64,
current_size: AtomicU64,
enabled: AtomicBool,
hits: AtomicUsize,
misses: AtomicUsize,
memory_entries: RwLock<HashMap<String, Vec<u8>>>,
max_memory_entries: usize,
}
#[derive(Debug, Clone)]
pub struct CacheStats {
pub enabled: bool,
pub hits: usize,
pub misses: usize,
pub hit_rate: f64,
pub current_size_bytes: u64,
pub max_size_bytes: u64,
pub entry_count: usize,
}
impl CompilationCache {
pub fn new() -> Self {
CompilationCache {
cache_dir: None,
max_size: 1024 * 1024 * 1024, current_size: AtomicU64::new(0),
enabled: AtomicBool::new(false),
hits: AtomicUsize::new(0),
misses: AtomicUsize::new(0),
memory_entries: RwLock::new(HashMap::new()),
max_memory_entries: 1024,
}
}
pub fn set_cache_dir(&mut self, dir: PathBuf) {
self.cache_dir = Some(dir);
}
pub fn set_enabled(&mut self, enabled: bool) {
self.enabled.store(enabled, Ordering::SeqCst);
}
pub fn set_max_size(&mut self, max_size: u64) {
self.max_size = max_size;
}
pub fn is_enabled(&self) -> bool {
self.enabled.load(Ordering::SeqCst)
}
pub fn make_key(source: &str, config: &GoldenConfig) -> String {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
source.hash(&mut hasher);
config.cache_key().hash(&mut hasher);
format!("{:016x}", hasher.finish())
}
pub fn lookup(&self, key: &str) -> Option<Vec<u8>> {
if !self.is_enabled() {
return None;
}
{
let entries = self.memory_entries.read().unwrap();
if let Some(data) = entries.get(key) {
self.hits.fetch_add(1, Ordering::SeqCst);
return Some(data.clone());
}
}
if let Some(ref dir) = self.cache_dir {
let path = dir.join(format!("{key}.cache"));
if path.exists() {
if let Ok(data) = fs::read(&path) {
self.hits.fetch_add(1, Ordering::SeqCst);
let mut entries = self.memory_entries.write().unwrap();
if entries.len() < self.max_memory_entries {
entries.insert(key.to_string(), data.clone());
}
return Some(data);
}
}
}
self.misses.fetch_add(1, Ordering::SeqCst);
None
}
pub fn store(&self, key: &str, data: &[u8]) {
if !self.is_enabled() {
return;
}
let size = data.len() as u64;
let current = self.current_size.load(Ordering::SeqCst);
if current + size > self.max_size {
self.evict(size);
}
{
let mut entries = self.memory_entries.write().unwrap();
if entries.len() < self.max_memory_entries {
entries.insert(key.to_string(), data.to_vec());
}
}
if let Some(ref dir) = self.cache_dir {
let _ = fs::create_dir_all(dir);
let path = dir.join(format!("{key}.cache"));
if let Ok(_) = fs::write(&path, data) {
self.current_size.fetch_add(size, Ordering::SeqCst);
}
}
}
fn evict(&self, needed: u64) {
let mut freed: u64 = 0;
if let Some(ref dir) = self.cache_dir {
if let Ok(entries) = fs::read_dir(dir) {
for entry in entries.flatten() {
if freed >= needed {
break;
}
let path = entry.path();
if path.extension().map_or(false, |e| e == "cache") {
if let Ok(meta) = entry.metadata() {
freed += meta.len();
let _ = fs::remove_file(&path);
}
}
}
}
}
{
let mut entries = self.memory_entries.write().unwrap();
if !entries.is_empty() {
let keys: Vec<_> = entries.keys().take(entries.len() / 2).cloned().collect();
for key in keys {
if let Some(data) = entries.remove(&key) {
freed += data.len() as u64;
}
}
}
}
self.current_size.fetch_sub(
freed.min(self.current_size.load(Ordering::SeqCst)),
Ordering::SeqCst,
);
}
pub fn clear(&self) {
{
let mut entries = self.memory_entries.write().unwrap();
entries.clear();
}
if let Some(ref dir) = self.cache_dir {
let _ = fs::remove_dir_all(dir);
let _ = fs::create_dir_all(dir);
}
self.current_size.store(0, Ordering::SeqCst);
self.hits.store(0, Ordering::SeqCst);
self.misses.store(0, Ordering::SeqCst);
}
pub fn stats(&self) -> CacheStats {
let hits = self.hits.load(Ordering::SeqCst);
let misses = self.misses.load(Ordering::SeqCst);
let total = hits + misses;
CacheStats {
enabled: self.is_enabled(),
hits,
misses,
hit_rate: if total > 0 {
hits as f64 / total as f64
} else {
0.0
},
current_size_bytes: self.current_size.load(Ordering::SeqCst),
max_size_bytes: self.max_size,
entry_count: self.memory_entries.read().unwrap().len(),
}
}
pub fn hit_rate(&self) -> f64 {
let hits = self.hits.load(Ordering::SeqCst);
let misses = self.misses.load(Ordering::SeqCst);
let total = hits + misses;
if total > 0 {
hits as f64 / total as f64
} else {
0.0
}
}
}
impl Default for CompilationCache {
fn default() -> Self {
CompilationCache::new()
}
}
#[derive(Debug)]
pub struct IncrementalCompiler {
pub enabled: bool,
pub database: IncrementalDatabase,
pub base_config: GoldenConfig,
pub last_compiled: HashSet<PathBuf>,
pub changed_files: HashSet<PathBuf>,
}
#[derive(Debug, Clone)]
pub struct IncrementalDatabase {
pub records: HashMap<PathBuf, IncrementalRecord>,
pub output_dir: PathBuf,
pub version: u32,
}
#[derive(Debug, Clone)]
pub struct IncrementalRecord {
pub path: PathBuf,
pub mtime: u64,
pub hash: u64,
pub options_hash: u64,
pub dependencies: Vec<PathBuf>,
pub output_file: PathBuf,
pub success: bool,
pub duration: Duration,
pub compiled_at: u64,
}
impl IncrementalCompiler {
pub fn new(base_config: GoldenConfig) -> Self {
let enabled = base_config.incremental;
let output_dir = base_config
.incremental_cache_dir
.clone()
.unwrap_or_else(|| PathBuf::from("target/incremental"));
IncrementalCompiler {
enabled,
database: IncrementalDatabase {
records: HashMap::new(),
output_dir,
version: 1,
},
base_config,
last_compiled: HashSet::new(),
changed_files: HashSet::new(),
}
}
pub fn detect_changes(&mut self) -> Vec<PathBuf> {
let mut changed = Vec::new();
for input_file in &self.base_config.input_files {
if self.needs_recompilation(input_file) {
changed.push(input_file.clone());
}
}
self.changed_files = changed.iter().cloned().collect();
changed
}
pub fn needs_recompilation(&self, path: &Path) -> bool {
if !self.enabled {
return true;
}
if let Some(record) = self.database.records.get(path) {
if let Ok(meta) = fs::metadata(path) {
if let Ok(mtime) = meta.modified() {
let mtime_secs = mtime
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0);
if mtime_secs != record.mtime {
return true;
}
}
}
for dep in &record.dependencies {
if self.needs_recompilation(dep) {
return true;
}
}
return false;
}
true
}
pub fn record_compilation(
&mut self,
path: &Path,
output_file: &Path,
dependencies: Vec<PathBuf>,
duration: Duration,
) {
if !self.enabled {
return;
}
let mtime = fs::metadata(path)
.ok()
.and_then(|m| m.modified().ok())
.and_then(|t| t.duration_since(UNIX_EPOCH).ok())
.map(|d| d.as_secs())
.unwrap_or(0);
let hash = 0u64;
let record = IncrementalRecord {
path: path.to_path_buf(),
mtime,
hash,
options_hash: 0,
dependencies,
output_file: output_file.to_path_buf(),
success: true,
duration,
compiled_at: SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0),
};
self.database.records.insert(path.to_path_buf(), record);
}
pub fn save_database(&self) -> io::Result<()> {
if !self.enabled {
return Ok(());
}
let db_path = self.database.output_dir.join("incremental.db");
let _ = fs::create_dir_all(&self.database.output_dir);
let _ = fs::write(&db_path, format!("version: {}\n", self.database.version));
Ok(())
}
pub fn load_database(&mut self) -> io::Result<()> {
if !self.enabled {
return Ok(());
}
let db_path = self.database.output_dir.join("incremental.db");
if db_path.exists() {
let _ = fs::read_to_string(&db_path)?;
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct CrossCompiler {
pub host_triple: String,
pub target_triple: String,
pub sysroot: Option<PathBuf>,
pub resource_dir: Option<PathBuf>,
pub gcc_install: Option<PathBuf>,
pub is_cross: bool,
pub target_flags: Vec<String>,
pub target_arch: Option<CrossTargetArch>,
pub target_os: Option<CrossTargetOS>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CrossTargetArch {
X86_64,
X86,
AArch64,
ARM,
RiscV64,
RiscV32,
PowerPC64,
Wasm,
Mips,
SystemZ,
}
impl CrossTargetArch {
pub fn from_triple(triple: &str) -> Option<Self> {
match triple {
t if t.starts_with("x86_64") => Some(CrossTargetArch::X86_64),
t if t.starts_with("i386")
|| t.starts_with("i486")
|| t.starts_with("i586")
|| t.starts_with("i686") =>
{
Some(CrossTargetArch::X86)
}
t if t.starts_with("aarch64") || t.starts_with("arm64") => {
Some(CrossTargetArch::AArch64)
}
t if t.starts_with("arm") => Some(CrossTargetArch::ARM),
t if t.starts_with("riscv64") => Some(CrossTargetArch::RiscV64),
t if t.starts_with("riscv32") => Some(CrossTargetArch::RiscV32),
t if t.starts_with("powerpc64") => Some(CrossTargetArch::PowerPC64),
t if t.starts_with("wasm") => Some(CrossTargetArch::Wasm),
t if t.starts_with("mips") => Some(CrossTargetArch::Mips),
t if t.starts_with("s390x") => Some(CrossTargetArch::SystemZ),
_ => None,
}
}
pub fn pointer_width(&self) -> u32 {
match self {
CrossTargetArch::X86_64
| CrossTargetArch::AArch64
| CrossTargetArch::RiscV64
| CrossTargetArch::PowerPC64
| CrossTargetArch::SystemZ
| CrossTargetArch::Mips => 64,
CrossTargetArch::X86
| CrossTargetArch::ARM
| CrossTargetArch::RiscV32
| CrossTargetArch::Wasm => 32,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CrossTargetOS {
Linux,
Windows,
Darwin,
FreeBSD,
NetBSD,
Android,
Fuchsia,
Unknown,
}
impl CrossTargetOS {
pub fn from_triple(triple: &str) -> Option<Self> {
let parts: Vec<&str> = triple.split('-').collect();
if parts.len() >= 3 {
match parts[2] {
"linux" => Some(CrossTargetOS::Linux),
"windows" | "win32" => Some(CrossTargetOS::Windows),
"darwin" | "macos" | "macosx" => Some(CrossTargetOS::Darwin),
"freebsd" => Some(CrossTargetOS::FreeBSD),
"netbsd" => Some(CrossTargetOS::NetBSD),
"android" => Some(CrossTargetOS::Android),
"fuchsia" => Some(CrossTargetOS::Fuchsia),
_ => Some(CrossTargetOS::Unknown),
}
} else {
None
}
}
}
impl CrossCompiler {
pub fn new(host_triple: &str, target_triple: &str) -> Self {
let is_cross = host_triple != target_triple;
let target_arch = CrossTargetArch::from_triple(target_triple);
let target_os = CrossTargetOS::from_triple(target_triple);
CrossCompiler {
host_triple: host_triple.to_string(),
target_triple: target_triple.to_string(),
sysroot: None,
resource_dir: None,
gcc_install: None,
is_cross,
target_flags: Vec::new(),
target_arch,
target_os,
}
}
pub fn from_config(config: &GoldenConfig) -> Self {
let host = detect_host_triple();
let target = &config.target_triple;
let mut cc = CrossCompiler::new(&host, target);
cc.sysroot = config.sysroot.clone();
cc.resource_dir = config.resource_dir.clone();
cc.gcc_install = config.gcc_install.clone();
cc
}
pub fn with_sysroot(mut self, sysroot: PathBuf) -> Self {
self.sysroot = Some(sysroot);
self
}
pub fn with_resource_dir(mut self, dir: PathBuf) -> Self {
self.resource_dir = Some(dir);
self
}
pub fn target_compiler_flags(&self) -> Vec<String> {
let mut flags = Vec::new();
flags.push(format!("--target={}", self.target_triple));
if let Some(ref sysroot) = self.sysroot {
flags.push(format!("--sysroot={}", sysroot.display()));
}
if let Some(ref res) = self.resource_dir {
flags.push(format!("-resource-dir={}", res.display()));
}
if let Some(ref gcc) = self.gcc_install {
flags.push(format!("--gcc-install-dir={}", gcc.display()));
}
flags
}
pub fn is_cross_compiling(&self) -> bool {
self.is_cross
}
pub fn validate(&self) -> Result<(), Vec<String>> {
let mut errors = Vec::new();
if self.is_cross {
if self.sysroot.is_none() {
errors.push("Cross-compilation requires a sysroot".into());
}
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
}
fn detect_host_triple() -> String {
if cfg!(target_os = "linux") {
if cfg!(target_arch = "x86_64") {
"x86_64-unknown-linux-gnu".into()
} else if cfg!(target_arch = "aarch64") {
"aarch64-unknown-linux-gnu".into()
} else {
"unknown-unknown-linux-gnu".into()
}
} else if cfg!(target_os = "windows") {
if cfg!(target_arch = "x86_64") {
"x86_64-pc-windows-msvc".into()
} else {
"unknown-pc-windows-msvc".into()
}
} else if cfg!(target_os = "macos") {
if cfg!(target_arch = "x86_64") {
"x86_64-apple-darwin".into()
} else if cfg!(target_arch = "aarch64") {
"aarch64-apple-darwin".into()
} else {
"unknown-apple-darwin".into()
}
} else {
"unknown-unknown-unknown".into()
}
}
pub fn compile(input: &Path, output: &Path) -> Result<(), String> {
let config = GoldenConfig {
input_files: vec![input.to_path_buf()],
output_file: Some(output.to_path_buf()),
output_format: "object".into(),
compile_only: true,
..GoldenConfig::x86_64_linux()
};
let mut path = GoldenPath::new(config);
let result = path.compile();
if result.success {
Ok(())
} else {
Err(format!("Compilation failed: {} errors", result.error_count))
}
}
pub fn compile_to_obj(source: &str) -> Option<Vec<u8>> {
let mut compiler = GoldenCompiler::new(GoldenConfig::x86_64_linux());
compiler.compile_to_object(source)
}
pub fn compile_to_asm(source: &str) -> Option<String> {
let mut compiler = GoldenCompiler::new(GoldenConfig::x86_64_linux());
compiler.compile_to_assembly(source)
}
pub fn compile_to_ir(source: &str) -> Option<String> {
let mut compiler = GoldenCompiler::new(GoldenConfig::x86_64_linux());
compiler.compile_to_llvm_ir(source)
}
pub fn compile_with_config(source: &str, config: GoldenConfig) -> GoldenResult {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("llvm_native_golden_temp.c");
let _ = fs::write(&tmpfile, source);
let mut path = GoldenPath::new(config);
path.config.input_files = vec![tmpfile.clone()];
let result = path.compile();
let _ = fs::remove_file(&tmpfile);
result
}
pub fn compile_cxx_to_obj(source: &str) -> Option<Vec<u8>> {
let mut compiler = GoldenCompiler::new(GoldenConfig::x86_64_linux_release());
compiler.path.config.is_cxx = true;
compiler.compile_to_object(source)
}
pub fn compile_release(source: &str) -> Option<Vec<u8>> {
let mut compiler = GoldenCompiler::new(GoldenConfig::x86_64_linux_release());
compiler.compile_to_object(source)
}
pub fn compile_windows(source: &str) -> Option<Vec<u8>> {
let mut compiler = GoldenCompiler::new(GoldenConfig::x86_64_windows());
compiler.compile_to_object(source)
}
pub fn full_pipeline_compile(source: &str) -> GoldenResult {
compile_with_config(
source,
GoldenConfig {
opt_level: "2".into(),
lto: true,
..GoldenConfig::x86_64_linux()
},
)
}
pub fn default_compiler() -> GoldenCompiler {
GoldenCompiler::new(GoldenConfig::x86_64_linux())
}
pub fn release_compiler() -> GoldenCompiler {
GoldenCompiler::new(GoldenConfig::x86_64_linux_release())
}
pub fn compiler_from_args(args: &[String]) -> GoldenCompiler {
let mut compiler = GoldenCompiler::new(GoldenConfig::default());
if !args.is_empty() {
compiler.parse_args(args);
}
compiler
}
pub use crate::clang::clang_x86_codegen_full::{
ClangX86CodeGen, X86CodeGenFlags, X86IntrinsicMapper, X86LoweringInfo, X86TargetVariant,
};
pub use crate::clang::clang_x86_driver_full::{
X86ClangDriver, X86DriverArgs, X86HostInfo, X86TargetTriple, X86ToolchainPath,
};
pub use crate::clang::clang_x86_pipeline::{
compile_to_x86_assembly, compile_to_x86_ir, compile_to_x86_object, compile_with_options,
CompilationCache as X86CompilationCache, PipelineResult, PipelineStage, StageResult,
X86CompileOptions, X86OptLevel, X86OutputFormat, X86Pipeline,
};
pub use crate::x86::x86_golden_pipeline::{
PipelineMetrics, X86CallingConvention, X86ConditionCode, X86GoldenPipeline,
X86MachineBasicBlock, X86MachineFunction, X86MachineInstr, X86MachineOperand,
X86PipelineConfig, X86PipelineError, X86PipelineOutput,
};
pub use crate::x86::x86_isel_golden::{
FeatureGate, ISelComplexPattern, ISelCoverageTracker, ISelPatternMatcher, ISelPatternRule,
X86Feature, X86ISelGoldenTable,
};
pub struct GoldenDiagnostics {
pub engine: crate::context::DiagnosticEngine,
pub config: DiagnosticConfig,
pub error_tracker: GoldenErrorTracker,
pub warning_tracker: GoldenWarningTracker,
pub notes: Vec<GoldenDiagnosticNote>,
pub fixits: Vec<GoldenFixIt>,
pub colorize: bool,
pub output_stream: Option<Box<dyn Write>>,
}
#[derive(Debug, Clone)]
pub struct DiagnosticConfig {
pub error_limit: usize,
pub warning_limit: usize,
pub warnings_as_errors: bool,
pub verbose: bool,
pub show_snippets: bool,
pub show_fixits: bool,
pub show_column: bool,
pub show_carets: bool,
pub show_option_names: bool,
pub tab_stop: usize,
pub message_length_limit: usize,
pub format: DiagnosticOutputFormat,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DiagnosticOutputFormat {
Clang,
GCC,
MSVC,
Vi,
JSON,
SARIF,
}
impl Default for DiagnosticConfig {
fn default() -> Self {
DiagnosticConfig {
error_limit: 20,
warning_limit: 100,
warnings_as_errors: false,
verbose: false,
show_snippets: true,
show_fixits: true,
show_column: true,
show_carets: true,
show_option_names: false,
tab_stop: 8,
message_length_limit: 0,
format: DiagnosticOutputFormat::Clang,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct GoldenErrorTracker {
pub stage_errors: HashMap<String, Vec<String>>,
pub total_errors: usize,
pub limit_reached: bool,
}
#[derive(Debug, Clone, Default)]
pub struct GoldenWarningTracker {
pub stage_warnings: HashMap<String, Vec<String>>,
pub total_warnings: usize,
pub suppressed_groups: HashSet<String>,
pub error_groups: HashSet<String>,
}
#[derive(Debug, Clone)]
pub struct GoldenDiagnosticNote {
pub location: Option<GoldenSourceLocation>,
pub message: String,
pub is_context: bool,
}
#[derive(Debug, Clone)]
pub struct GoldenFixIt {
pub range: GoldenSourceRange,
pub replacement: String,
pub description: Option<String>,
}
#[derive(Debug, Clone)]
pub struct GoldenSourceLocation {
pub file: String,
pub line: usize,
pub column: usize,
pub offset: usize,
}
#[derive(Debug, Clone)]
pub struct GoldenSourceRange {
pub start: GoldenSourceLocation,
pub end: GoldenSourceLocation,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum GoldenDiagSeverity {
Ignored = 0,
Note = 1,
Remark = 2,
Warning = 3,
Error = 4,
Fatal = 5,
}
impl std::fmt::Debug for GoldenDiagnostics {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("GoldenDiagnostics")
.field("engine", &self.engine)
.field("config", &self.config)
.field("error_tracker", &self.error_tracker)
.field("warning_tracker", &self.warning_tracker)
.field("notes", &self.notes)
.field("fixits", &self.fixits)
.field("colorize", &self.colorize)
.field(
"output_stream",
&self.output_stream.as_ref().map(|_| "<dyn Write>"),
)
.finish()
}
}
impl GoldenDiagnostics {
pub fn new(config: DiagnosticConfig) -> Self {
GoldenDiagnostics {
engine: crate::context::DiagnosticEngine::new(),
config,
error_tracker: GoldenErrorTracker::default(),
warning_tracker: GoldenWarningTracker::default(),
notes: Vec::new(),
fixits: Vec::new(),
colorize: false,
output_stream: None,
}
}
pub fn error(&mut self, stage: &str, message: &str) {
if self.error_tracker.limit_reached {
return;
}
self.error_tracker.total_errors += 1;
self.error_tracker
.stage_errors
.entry(stage.into())
.or_default()
.push(message.into());
if self.error_tracker.total_errors >= self.config.error_limit {
self.error_tracker.limit_reached = true;
}
}
pub fn warning(&mut self, stage: &str, message: &str) {
if self.warning_tracker.total_warnings >= self.config.warning_limit {
return;
}
self.warning_tracker.total_warnings += 1;
self.warning_tracker
.stage_warnings
.entry(stage.into())
.or_default()
.push(message.into());
if self.config.warnings_as_errors {
self.error(stage, &format!("warning treated as error: {message}"));
}
}
pub fn note(&mut self, message: &str) {
self.notes.push(GoldenDiagnosticNote {
location: None,
message: message.into(),
is_context: true,
});
}
pub fn fixit(&mut self, range: GoldenSourceRange, replacement: &str, desc: Option<&str>) {
self.fixits.push(GoldenFixIt {
range,
replacement: replacement.into(),
description: desc.map(|s| s.into()),
});
}
pub fn has_errors(&self) -> bool {
self.error_tracker.total_errors > 0
}
pub fn has_warnings(&self) -> bool {
self.warning_tracker.total_warnings > 0
}
pub fn error_count(&self) -> usize {
self.error_tracker.total_errors
}
pub fn warning_count(&self) -> usize {
self.warning_tracker.total_warnings
}
pub fn format_diagnostic(
&self,
severity: GoldenDiagSeverity,
location: Option<&GoldenSourceLocation>,
message: &str,
) -> String {
match self.config.format {
DiagnosticOutputFormat::Clang => self.format_clang(severity, location, message),
DiagnosticOutputFormat::GCC => self.format_gcc(severity, location, message),
DiagnosticOutputFormat::MSVC => self.format_msvc(severity, location, message),
DiagnosticOutputFormat::Vi => self.format_vi(severity, location, message),
DiagnosticOutputFormat::JSON => self.format_json(severity, location, message),
DiagnosticOutputFormat::SARIF => self.format_sarif(severity, location, message),
}
}
fn format_clang(
&self,
severity: GoldenDiagSeverity,
location: Option<&GoldenSourceLocation>,
message: &str,
) -> String {
let sev_str = match severity {
GoldenDiagSeverity::Ignored => "ignored",
GoldenDiagSeverity::Note => "note",
GoldenDiagSeverity::Remark => "remark",
GoldenDiagSeverity::Warning => "warning",
GoldenDiagSeverity::Error => "error",
GoldenDiagSeverity::Fatal => "fatal error",
};
if let Some(loc) = location {
format!(
"{}:{}:{}: {sev_str}: {message}",
loc.file, loc.line, loc.column
)
} else {
format!("{sev_str}: {message}")
}
}
fn format_gcc(
&self,
severity: GoldenDiagSeverity,
location: Option<&GoldenSourceLocation>,
message: &str,
) -> String {
if let Some(loc) = location {
let sev = match severity {
GoldenDiagSeverity::Error | GoldenDiagSeverity::Fatal => "error",
GoldenDiagSeverity::Warning => "warning",
_ => "note",
};
format!("{}:{}:{}: {sev}: {message}", loc.file, loc.line, loc.column)
} else {
format!("error: {message}")
}
}
fn format_msvc(
&self,
severity: GoldenDiagSeverity,
location: Option<&GoldenSourceLocation>,
message: &str,
) -> String {
if let Some(loc) = location {
let sev = match severity {
GoldenDiagSeverity::Error | GoldenDiagSeverity::Fatal => "error",
GoldenDiagSeverity::Warning => "warning",
_ => "info",
};
format!(
"{}({},{}) : {sev} C9999: {message}",
loc.file, loc.line, loc.column
)
} else {
format!("error C9999: {message}")
}
}
fn format_vi(
&self,
severity: GoldenDiagSeverity,
location: Option<&GoldenSourceLocation>,
message: &str,
) -> String {
if let Some(loc) = location {
format!("{}:{}: {message}", loc.file, loc.line)
} else {
message.into()
}
}
fn format_json(
&self,
severity: GoldenDiagSeverity,
location: Option<&GoldenSourceLocation>,
message: &str,
) -> String {
use std::fmt::Write;
let mut s = String::new();
let _ = write!(s, r#"{{"severity":"{:?}","message":"{message}""#, severity);
if let Some(loc) = location {
let _ = write!(
s,
r#","file":"{}","line":{},"column":{}"#,
loc.file, loc.line, loc.column
);
}
s.push('}');
s
}
fn format_sarif(
&self,
severity: GoldenDiagSeverity,
location: Option<&GoldenSourceLocation>,
message: &str,
) -> String {
self.format_json(severity, location, message)
}
pub fn summary_report(&self) -> String {
let mut s = String::new();
s.push_str("══════ Diagnostic Summary ══════\n");
s.push_str(&format!(
" Errors: {} Warnings: {} Notes: {}\n",
self.error_tracker.total_errors,
self.warning_tracker.total_warnings,
self.notes.len()
));
s.push_str(&format!(" Fix-its: {}\n", self.fixits.len()));
if self.error_tracker.limit_reached {
s.push_str(" ⚠ Error limit reached; further errors suppressed.\n");
}
for (stage, errors) in &self.error_tracker.stage_errors {
if !errors.is_empty() {
s.push_str(&format!(
" [{stage}] {count} errors\n",
count = errors.len()
));
}
}
s
}
pub fn clear(&mut self) {
self.error_tracker = GoldenErrorTracker::default();
self.warning_tracker = GoldenWarningTracker::default();
self.notes.clear();
self.fixits.clear();
}
pub fn suppress_warning_group(&mut self, group: &str) {
self.warning_tracker.suppressed_groups.insert(group.into());
}
pub fn error_warning_group(&mut self, group: &str) {
self.warning_tracker.error_groups.insert(group.into());
}
pub fn to_sarif(&self) -> String {
let mut sarif = String::new();
sarif.push_str(r#"{"version":"2.1.0","$schema":"https://json.schemastore.org/sarif-2.1.0.json","runs":[{ "#);
sarif.push_str(r#""tool":{"driver":{"name":"llvm-native","version":"0.1.0"}},"#);
sarif.push_str(r#""results":["#);
sarif.push_str("]}]}");
sarif
}
}
impl Default for GoldenDiagnostics {
fn default() -> Self {
GoldenDiagnostics::new(DiagnosticConfig::default())
}
}
#[derive(Debug)]
pub struct GoldenVerifier {
pub abort_on_error: bool,
pub verbose: bool,
pub results: Vec<VerificationRecord>,
pub total_checks: usize,
pub total_passed: usize,
pub total_failed: usize,
}
#[derive(Debug, Clone)]
pub struct VerificationRecord {
pub check_name: String,
pub category: VerificationCategory,
pub passed: bool,
pub error: Option<String>,
pub duration: Duration,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum VerificationCategory {
IR,
Machine,
ABI,
Security,
Performance,
Compliance,
}
impl VerificationCategory {
pub fn as_str(&self) -> &'static str {
match self {
VerificationCategory::IR => "ir",
VerificationCategory::Machine => "machine",
VerificationCategory::ABI => "abi",
VerificationCategory::Security => "security",
VerificationCategory::Performance => "performance",
VerificationCategory::Compliance => "compliance",
}
}
}
impl GoldenVerifier {
pub fn new(verbose: bool) -> Self {
GoldenVerifier {
abort_on_error: false,
verbose,
results: Vec::new(),
total_checks: 0,
total_passed: 0,
total_failed: 0,
}
}
pub fn verify_module(&mut self, module: &Module) -> bool {
self.total_checks += 1;
let start = Instant::now();
let result = verify_module(module);
let passed = result.is_valid;
if passed {
self.total_passed += 1;
} else {
self.total_failed += 1;
if self.abort_on_error {
return false;
}
}
self.results.push(VerificationRecord {
check_name: "module_verification".into(),
category: VerificationCategory::IR,
passed,
error: if !passed {
Some(format!("{result:?}"))
} else {
None
},
duration: start.elapsed(),
});
passed
}
pub fn verify_machine_function(&mut self, mf: &X86MachineFunction) -> bool {
self.total_checks += 1;
let start = Instant::now();
let mut errors = Vec::new();
for block in &mf.blocks {
if !block.is_entry && block.predecessors.is_empty() {
errors.push(format!(
"Block '{}' has no predecessors but is not entry",
block.name
));
}
if !block.has_terminator() && !block.instructions.is_empty() {
errors.push(format!("Block '{}' has no terminator", block.name));
}
}
for (vreg, preg) in &mf.vreg_to_preg {
if *vreg == 0 {
errors.push("Virtual register 0 assigned to physical register".into());
}
let _ = preg;
}
let passed = errors.is_empty();
if passed {
self.total_passed += 1;
} else {
self.total_failed += 1;
}
self.results.push(VerificationRecord {
check_name: format!("machine_function:{}", mf.name),
category: VerificationCategory::Machine,
passed,
error: if !passed {
Some(errors.join("; "))
} else {
None
},
duration: start.elapsed(),
});
passed
}
pub fn verify_abi(&mut self, mf: &X86MachineFunction) -> bool {
self.total_checks += 1;
let start = Instant::now();
let mut errors = Vec::new();
if mf.stack_alignment > 0 && mf.stack_alignment % 16 != 0 {
errors.push(format!(
"Stack alignment {} is not 16-byte aligned",
mf.stack_alignment
));
}
let passed = errors.is_empty();
if passed {
self.total_passed += 1;
} else {
self.total_failed += 1;
}
self.results.push(VerificationRecord {
check_name: format!("abi:{}", mf.name),
category: VerificationCategory::ABI,
passed,
error: if !passed {
Some(errors.join("; "))
} else {
None
},
duration: start.elapsed(),
});
passed
}
pub fn verify_security(&mut self, mf: &X86MachineFunction) -> bool {
self.total_checks += 1;
let start = Instant::now();
let passed = true;
if passed {
self.total_passed += 1;
} else {
self.total_failed += 1;
}
self.results.push(VerificationRecord {
check_name: format!("security:{}", mf.name),
category: VerificationCategory::Security,
passed,
error: None,
duration: start.elapsed(),
});
passed
}
pub fn report(&self) -> String {
let mut s = String::new();
s.push_str("══════ Golden Verifier Report ══════\n\n");
s.push_str(&format!(
" Total: {} Passed: {} Failed: {}\n\n",
self.total_checks, self.total_passed, self.total_failed
));
let mut by_category: HashMap<VerificationCategory, (usize, usize)> = HashMap::new();
for r in &self.results {
let entry = by_category.entry(r.category).or_insert((0, 0));
entry.0 += 1;
if r.passed {
entry.1 += 1;
}
}
for (cat, (total, passed)) in &by_category {
let status = if *passed == *total { "✓" } else { "✗" };
s.push_str(&format!(
" [{status}] {}: {}/{} checks passed\n",
cat.as_str(),
passed,
total
));
}
let failures: Vec<_> = self.results.iter().filter(|r| !r.passed).collect();
if !failures.is_empty() {
s.push_str("\n Failures:\n");
for f in failures {
s.push_str(&format!(
" ✗ {} — {}\n",
f.check_name,
f.error.as_deref().unwrap_or("unknown")
));
}
}
s
}
pub fn all_passed(&self) -> bool {
self.total_failed == 0
}
pub fn reset(&mut self) {
self.results.clear();
self.total_checks = 0;
self.total_passed = 0;
self.total_failed = 0;
}
}
impl Default for GoldenVerifier {
fn default() -> Self {
GoldenVerifier::new(false)
}
}
#[derive(Debug)]
pub struct GoldenProfiler {
pub enabled: bool,
pub records: Vec<ProfileRecord>,
active_spans: HashMap<String, Instant>,
pub event_counters: HashMap<String, usize>,
pub memory_samples: Vec<MemorySample>,
pub peak_memory_bytes: u64,
pub start_time: Option<Instant>,
}
#[derive(Debug, Clone)]
pub struct ProfileRecord {
pub name: String,
pub category: ProfileCategory,
pub start_offset: Duration,
pub duration: Duration,
pub item_count: usize,
pub metadata: HashMap<String, String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProfileCategory {
Frontend,
Backend,
Optimization,
Linking,
IO,
Memory,
Other,
}
impl ProfileCategory {
pub fn as_str(&self) -> &'static str {
match self {
ProfileCategory::Frontend => "frontend",
ProfileCategory::Backend => "backend",
ProfileCategory::Optimization => "optimization",
ProfileCategory::Linking => "linking",
ProfileCategory::IO => "io",
ProfileCategory::Memory => "memory",
ProfileCategory::Other => "other",
}
}
}
#[derive(Debug, Clone)]
pub struct MemorySample {
pub timestamp: Duration,
pub resident_bytes: u64,
pub virtual_bytes: u64,
pub allocated_bytes: u64,
}
impl GoldenProfiler {
pub fn new(enabled: bool) -> Self {
GoldenProfiler {
enabled,
records: Vec::new(),
active_spans: HashMap::new(),
event_counters: HashMap::new(),
memory_samples: Vec::new(),
peak_memory_bytes: 0,
start_time: if enabled { Some(Instant::now()) } else { None },
}
}
pub fn begin_span(&mut self, name: &str) {
if !self.enabled {
return;
}
self.active_spans.insert(name.into(), Instant::now());
}
pub fn end_span(&mut self, name: &str, category: ProfileCategory, item_count: usize) {
if !self.enabled {
return;
}
if let Some(start) = self.active_spans.remove(name) {
let duration = start.elapsed();
let start_offset = self
.start_time
.map(|t| start.duration_since(t))
.unwrap_or(Duration::ZERO);
self.records.push(ProfileRecord {
name: name.into(),
category,
start_offset,
duration,
item_count,
metadata: HashMap::new(),
});
}
}
pub fn increment_counter(&mut self, name: &str) {
if !self.enabled {
return;
}
*self.event_counters.entry(name.into()).or_insert(0) += 1;
}
pub fn sample_memory(&mut self) {
if !self.enabled {
return;
}
self.memory_samples.push(MemorySample {
timestamp: Instant::now().duration_since(self.start_time.unwrap_or_else(Instant::now)),
resident_bytes: 0,
virtual_bytes: 0,
allocated_bytes: 0,
});
}
pub fn report(&self) -> String {
let mut s = String::new();
s.push_str("══════ Golden Profiler Report ══════\n\n");
if !self.enabled {
s.push_str(" Profiling disabled.\n");
return s;
}
let mut sorted = self.records.clone();
sorted.sort_by(|a, b| b.duration.cmp(&a.duration));
s.push_str(&format!(" Total records: {}\n", sorted.len()));
if let Some(start) = self.start_time {
s.push_str(&format!(" Elapsed: {:?}\n\n", start.elapsed()));
}
s.push_str(" Top 20 by duration:\n");
for (i, rec) in sorted.iter().take(20).enumerate() {
s.push_str(&format!(
" {:2}. [{}] {} — {:?} ({} items)\n",
i + 1,
rec.category.as_str(),
rec.name,
rec.duration,
rec.item_count
));
}
if !self.event_counters.is_empty() {
s.push_str("\n Event counters:\n");
let mut counters: Vec<_> = self.event_counters.iter().collect();
counters.sort_by(|a, b| b.1.cmp(a.1));
for (name, count) in counters.iter().take(10) {
s.push_str(&format!(" {name}: {count}\n"));
}
}
s
}
pub fn chrome_trace(&self) -> String {
let mut json = String::new();
json.push_str("[\n");
for (i, rec) in self.records.iter().enumerate() {
let ts_us = rec.start_offset.as_micros();
let dur_us = rec.duration.as_micros();
json.push_str(&format!(
r#" {{"name":"{}","cat":"{}","ph":"X","ts":{ts_us},"dur":{dur_us},"pid":1,"tid":1}}"#,
rec.name, rec.category.as_str()
));
if i < self.records.len() - 1 {
json.push(',');
}
json.push('\n');
}
json.push_str("]\n");
json
}
pub fn flamegraph(&self) -> String {
let mut folded = String::new();
for rec in &self.records {
let usec = rec.duration.as_micros();
folded.push_str(&format!("{};{} {usec}\n", rec.category.as_str(), rec.name));
}
folded
}
pub fn reset(&mut self) {
self.records.clear();
self.active_spans.clear();
self.event_counters.clear();
self.memory_samples.clear();
self.peak_memory_bytes = 0;
self.start_time = if self.enabled {
Some(Instant::now())
} else {
None
};
}
}
impl Default for GoldenProfiler {
fn default() -> Self {
GoldenProfiler::new(false)
}
}
#[derive(Debug)]
pub struct GoldenOrchestrator {
pub config: GoldenConfig,
pub path: Option<GoldenPath>,
pub compiler: Option<GoldenCompiler>,
pub lto: Option<GoldenLTO>,
pub self_host: Option<GoldenSelfHost>,
pub test_harness: Option<GoldenTestHarness>,
pub profiler: GoldenProfiler,
pub diagnostics: GoldenDiagnostics,
pub verifier: GoldenVerifier,
pub mode: OrchestrationMode,
pub result: Option<OrchestrationResult>,
pub executed: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OrchestrationMode {
Compile,
CompileAndLink,
CompileLinkTest,
Bootstrap,
Benchmark,
Test,
Analyze,
}
impl OrchestrationMode {
pub fn as_str(&self) -> &'static str {
match self {
OrchestrationMode::Compile => "compile",
OrchestrationMode::CompileAndLink => "compile+link",
OrchestrationMode::CompileLinkTest => "compile+link+test",
OrchestrationMode::Bootstrap => "bootstrap",
OrchestrationMode::Benchmark => "benchmark",
OrchestrationMode::Test => "test",
OrchestrationMode::Analyze => "analyze",
}
}
}
#[derive(Debug, Clone)]
pub struct OrchestrationResult {
pub success: bool,
pub mode: OrchestrationMode,
pub total_duration: Duration,
pub compilation_result: Option<GoldenResult>,
pub lto_result: Option<LTOMetrics>,
pub self_host_complete: Option<bool>,
pub test_results_summary: Option<String>,
pub profiling_report: Option<String>,
pub verification_report: Option<String>,
}
impl GoldenOrchestrator {
pub fn new(config: GoldenConfig, mode: OrchestrationMode) -> Self {
let diagnostics = GoldenDiagnostics::new(DiagnosticConfig::default());
let profiler = GoldenProfiler::new(config.print_timing);
let verifier = GoldenVerifier::new(config.verbose);
GoldenOrchestrator {
config,
path: None,
compiler: None,
lto: None,
self_host: None,
test_harness: None,
profiler,
diagnostics,
verifier,
mode,
result: None,
executed: false,
}
}
pub fn execute(&mut self) -> OrchestrationResult {
let start = Instant::now();
match self.mode {
OrchestrationMode::Compile => self.run_compile(),
OrchestrationMode::CompileAndLink => self.run_compile_and_link(),
OrchestrationMode::CompileLinkTest => self.run_compile_link_test(),
OrchestrationMode::Bootstrap => self.run_bootstrap(),
OrchestrationMode::Benchmark => self.run_benchmark(),
OrchestrationMode::Test => self.run_test(),
OrchestrationMode::Analyze => self.run_analyze(),
}
let total_duration = start.elapsed();
let mut result = OrchestrationResult {
success: !self.diagnostics.has_errors(),
mode: self.mode,
total_duration,
compilation_result: None,
lto_result: None,
self_host_complete: None,
test_results_summary: None,
profiling_report: None,
verification_report: None,
};
if let Some(ref path) = self.path {
result.compilation_result = path.get_result().cloned();
}
if let Some(ref lto) = self.lto {
result.lto_result = Some(lto.metrics.clone());
}
if let Some(ref sh) = self.self_host {
result.self_host_complete = Some(sh.complete);
}
if self.profiler.enabled {
result.profiling_report = Some(self.profiler.report());
}
result.verification_report = Some(self.verifier.report());
self.result = Some(result.clone());
self.executed = true;
result
}
fn run_compile(&mut self) {
self.profiler.begin_span("compile");
let mut path = GoldenPath::new(self.config.clone());
let result = path.compile();
if result.success {
if let Some(ref module) = result.module {
self.verifier.verify_module(module);
}
} else {
for err in &path.errors {
self.diagnostics.error("compile", err);
}
}
self.path = Some(path);
self.profiler
.end_span("compile", ProfileCategory::Frontend, 0);
}
fn run_compile_and_link(&mut self) {
self.profiler.begin_span("compile_and_link");
self.run_compile();
if self.config.lto {
self.profiler.begin_span("lto");
let mut lto = GoldenLTO::from_golden_config(&self.config);
if let Some(ref path) = self.path {
if let Some(ref module) = path.result.as_ref().and_then(|r| r.module.as_ref()) {
let _ = module;
}
}
if self.config.thin_lto {
let _ = lto.run_thin_lto();
} else {
let _ = lto.run_full_lto();
}
self.lto = Some(lto);
self.profiler.end_span("lto", ProfileCategory::Linking, 0);
}
self.profiler
.end_span("compile_and_link", ProfileCategory::Other, 0);
}
fn run_compile_link_test(&mut self) {
self.profiler.begin_span("compile_link_test");
self.run_compile_and_link();
if self.config.self_host {
let mut harness = GoldenTestHarness::new(TestHarnessConfig::default());
harness.run_all();
self.test_harness = Some(harness);
}
self.profiler
.end_span("compile_link_test", ProfileCategory::Other, 0);
}
fn run_bootstrap(&mut self) {
self.profiler.begin_span("bootstrap");
let sh_config = SelfHostConfig {
source_dir: self.config.self_host_source_dir.clone().unwrap_or_default(),
build_dir: self.config.self_host_build_dir.clone().unwrap_or_default(),
stage_count: self.config.self_host_stages,
opt_level: self.config.opt_level.clone(),
target_triple: self.config.target_triple.clone(),
..Default::default()
};
let mut sh = GoldenSelfHost::new(sh_config);
let _ = sh.run();
self.self_host = Some(sh);
self.profiler
.end_span("bootstrap", ProfileCategory::Other, 0);
}
fn run_benchmark(&mut self) {
self.profiler.begin_span("benchmark");
let mut benchmarks = GoldenBenchmarks::new(BenchmarkConfig::default());
benchmarks.run_all();
self.profiler
.end_span("benchmark", ProfileCategory::Other, 0);
}
fn run_test(&mut self) {
self.profiler.begin_span("test");
let mut harness = GoldenTestHarness::new(TestHarnessConfig::default());
harness.run_all();
self.test_harness = Some(harness);
self.profiler.end_span("test", ProfileCategory::Other, 0);
}
fn run_analyze(&mut self) {
self.profiler.begin_span("analyze");
self.run_compile();
self.profiler
.end_span("analyze", ProfileCategory::Frontend, 0);
}
pub fn report(&self) -> String {
let mut s = String::new();
s.push_str("══════ Golden Orchestrator Report ══════\n\n");
s.push_str(&format!(" Mode: {}\n", self.mode.as_str()));
s.push_str(&format!(" Target: {}\n", self.config.target_triple));
if let Some(ref result) = self.result {
s.push_str(&format!(
" Success: {} Duration: {:?}\n",
result.success, result.total_duration
));
}
s.push_str("\n --- Diagnostics ---\n");
s.push_str(&self.diagnostics.summary_report());
if let Some(ref vreport) = self
.result
.as_ref()
.and_then(|r| r.verification_report.as_ref())
{
s.push_str("\n --- Verification ---\n");
s.push_str(vreport);
}
if let Some(ref preport) = self
.result
.as_ref()
.and_then(|r| r.profiling_report.as_ref())
{
s.push_str("\n --- Profiling ---\n");
s.push_str(preport);
}
if let Some(ref treport) = self
.result
.as_ref()
.and_then(|r| r.test_results_summary.as_ref())
{
s.push_str("\n --- Tests ---\n");
s.push_str(treport);
}
s
}
pub fn status(&self) -> String {
match (&self.result, self.executed) {
(Some(r), true) => format!(
"Orchestrator: {} {} ({:?})",
self.mode.as_str(),
if r.success { "✓" } else { "✗" },
r.total_duration
),
_ => format!("Orchestrator: {} (not run)", self.mode.as_str()),
}
}
}
#[derive(Debug)]
pub struct ModuleFingerprint {
pub source_path: PathBuf,
pub source_hash: [u8; 32],
pub options_hash: [u8; 32],
pub includes_hash: [u8; 32],
pub module_hash: [u8; 32],
pub created_at: SystemTime,
pub compiler_version: String,
}
impl ModuleFingerprint {
pub fn compute(source: &Path, config: &GoldenConfig) -> io::Result<Self> {
let source_content = fs::read(source)?;
let source_hash = sha256(&source_content);
let opts_key = config.cache_key();
let options_hash = sha256(opts_key.as_bytes());
let includes_hash = [0u8; 32];
let module_hash = [0u8; 32];
Ok(ModuleFingerprint {
source_path: source.to_path_buf(),
source_hash,
options_hash,
includes_hash,
module_hash,
created_at: SystemTime::now(),
compiler_version: env!("CARGO_PKG_VERSION").into(),
})
}
pub fn matches(&self, other: &ModuleFingerprint) -> bool {
self.source_hash == other.source_hash && self.options_hash == other.options_hash
}
pub fn to_hex(&self) -> String {
let mut s = String::with_capacity(64);
for byte in &self.source_hash {
s.push_str(&format!("{byte:02x}"));
}
s
}
}
fn sha256(data: &[u8]) -> [u8; 32] {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
let hash_val = hasher.finish();
let mut result = [0u8; 32];
for i in 0..8 {
result[i] = ((hash_val >> (i * 8)) & 0xFF) as u8;
result[i + 8] = ((hash_val >> (i * 8)) & 0xFF) as u8;
result[i + 16] = ((hash_val >> (i * 8)) & 0xFF) as u8;
result[i + 24] = ((hash_val >> (i * 8)) & 0xFF) as u8;
}
result
}
#[derive(Debug)]
pub struct GoldenPathThreadSafe {
inner: Arc<Mutex<GoldenPath>>,
}
impl GoldenPathThreadSafe {
pub fn new(config: GoldenConfig) -> Self {
GoldenPathThreadSafe {
inner: Arc::new(Mutex::new(GoldenPath::new(config))),
}
}
pub fn compile(&self) -> GoldenResult {
let mut path = self.inner.lock().unwrap();
path.compile()
}
pub fn config(&self) -> GoldenConfig {
self.inner.lock().unwrap().config.clone()
}
}
impl Clone for GoldenPathThreadSafe {
fn clone(&self) -> Self {
GoldenPathThreadSafe {
inner: Arc::clone(&self.inner),
}
}
}
#[derive(Debug)]
pub struct ParallelCompilationJob {
pub source_file: PathBuf,
pub config: GoldenConfig,
pub id: usize,
pub is_cxx: bool,
pub dependencies: Vec<PathBuf>,
}
#[derive(Debug)]
pub struct ParallelCompilationManager {
pub jobs: Vec<ParallelCompilationJob>,
pub worker_count: usize,
pub results: Vec<(usize, GoldenResult)>,
pub complete: AtomicBool,
pub progress: AtomicUsize,
}
impl ParallelCompilationManager {
pub fn new(jobs: Vec<ParallelCompilationJob>, worker_count: usize) -> Self {
ParallelCompilationManager {
jobs,
worker_count: worker_count.max(1).min(64),
results: Vec::new(),
complete: AtomicBool::new(false),
progress: AtomicUsize::new(0),
}
}
pub fn run(&mut self) -> Vec<(usize, GoldenResult)> {
use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
let total = self.jobs.len();
let chunk_size = (total / self.worker_count).max(1);
let mut handles = Vec::new();
for chunk_start in (0..total).step_by(chunk_size) {
let chunk_end = (chunk_start + chunk_size).min(total);
let jobs: Vec<ParallelCompilationJob> = self.jobs[chunk_start..chunk_end]
.iter()
.map(|j| ParallelCompilationJob {
source_file: j.source_file.clone(),
config: j.config.clone(),
id: j.id,
is_cxx: j.is_cxx,
dependencies: j.dependencies.clone(),
})
.collect();
let tx = tx.clone();
handles.push(std::thread::spawn(move || {
for job in jobs {
let mut path = GoldenPath::new(job.config);
path.config.input_files = vec![job.source_file];
path.config.is_cxx = job.is_cxx;
let result = path.compile();
let _ = tx.send((job.id, result));
}
}));
}
drop(tx);
for (id, result) in rx {
self.results.push((id, result));
self.progress.store(self.results.len(), Ordering::SeqCst);
}
for h in handles {
let _ = h.join();
}
self.complete.store(true, Ordering::SeqCst);
self.results.clone()
}
pub fn progress_fraction(&self) -> f64 {
let done = self.progress.load(Ordering::SeqCst);
let total = self.jobs.len();
if total > 0 {
done as f64 / total as f64
} else {
1.0
}
}
pub fn all_succeeded(&self) -> bool {
self.results.iter().all(|(_, r)| r.success)
}
}
#[derive(Debug, Clone)]
pub struct CompilationDatabase {
pub directory: PathBuf,
pub commands: Vec<CompilationCommand>,
}
#[derive(Debug, Clone)]
pub struct CompilationCommand {
pub file: PathBuf,
pub directory: PathBuf,
pub arguments: Vec<String>,
pub output: Option<PathBuf>,
}
impl CompilationDatabase {
pub fn new(directory: PathBuf) -> Self {
CompilationDatabase {
directory,
commands: Vec::new(),
}
}
pub fn add(&mut self, command: CompilationCommand) {
self.commands.push(command);
}
pub fn to_json(&self) -> String {
let mut json = String::new();
json.push_str("[\n");
for (i, cmd) in self.commands.iter().enumerate() {
json.push_str(" {\n");
json.push_str(&format!(
" \"directory\": \"{}\",\n",
cmd.directory.display().to_string().replace('\\', "/")
));
json.push_str(&format!(
" \"file\": \"{}\",\n",
cmd.file.display().to_string().replace('\\', "/")
));
json.push_str(" \"arguments\": [\n");
for (j, arg) in cmd.arguments.iter().enumerate() {
let comma = if j < cmd.arguments.len() - 1 { "," } else { "" };
json.push_str(&format!(
" \"{}\"{comma}\n",
arg.replace('\\', "\\\\").replace('"', "\\\"")
));
}
json.push_str(" ]\n");
if let Some(ref out) = cmd.output {
json.push_str(&format!(
" ,\"output\": \"{}\"\n",
out.display().to_string().replace('\\', "/")
));
}
let comma = if i < self.commands.len() - 1 { "," } else { "" };
json.push_str(&format!(" }}{comma}\n"));
}
json.push_str("]\n");
json
}
pub fn write(&self, path: &Path) -> io::Result<()> {
fs::write(path, self.to_json())
}
pub fn load(path: &Path) -> io::Result<Self> {
let content = fs::read_to_string(path)?;
let _ = content;
Ok(CompilationDatabase::new(PathBuf::from(".")))
}
pub fn find(&self, source_file: &Path) -> Vec<&CompilationCommand> {
self.commands
.iter()
.filter(|c| c.file == source_file)
.collect()
}
pub fn source_files(&self) -> Vec<&Path> {
let mut files: Vec<_> = self.commands.iter().map(|c| c.file.as_path()).collect();
files.sort();
files.dedup();
files
}
pub fn len(&self) -> usize {
self.commands.len()
}
pub fn is_empty(&self) -> bool {
self.commands.is_empty()
}
}
pub fn init_from_compile_commands(path: &Path) -> io::Result<Vec<GoldenPath>> {
let db = CompilationDatabase::load(path)?;
let mut paths = Vec::new();
for cmd in &db.commands {
let config = GoldenConfig {
input_files: vec![cmd.file.clone()],
output_file: cmd.output.clone(),
..GoldenConfig::default()
};
paths.push(GoldenPath::new(config));
}
Ok(paths)
}
pub fn batch_compile(files: &[PathBuf], output_dir: &Path) -> Vec<GoldenResult> {
let _ = fs::create_dir_all(output_dir);
let mut results = Vec::new();
for file in files {
let stem = file.file_stem().unwrap_or_default();
let output = output_dir.join(stem).with_extension("o");
let config = GoldenConfig {
input_files: vec![file.clone()],
output_file: Some(output),
compile_only: true,
..GoldenConfig::x86_64_linux_release()
};
let mut path = GoldenPath::new(config);
results.push(path.compile());
}
results
}
pub fn compile_to_all_formats(source: &str) -> Option<(String, Vec<u8>)> {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_all_fmts.c");
let _ = fs::write(&tmpfile, source);
let mut path_ir = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
output_format: "llvm-ir".into(),
..GoldenConfig::x86_64_linux()
});
let ir_result = path_ir.compile();
let mut path_obj = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
output_format: "object".into(),
compile_only: true,
..GoldenConfig::x86_64_linux()
});
let obj_result = path_obj.compile();
let _ = fs::remove_file(&tmpfile);
match (ir_result.text_output, obj_result.binary_output) {
(Some(ir), Some(obj)) => Some((ir, obj)),
_ => None,
}
}
pub fn compile_with_profiling(source: &str) -> (GoldenResult, GoldenProfiler) {
let mut profiler = GoldenProfiler::new(true);
profiler.begin_span("total");
let result = compile_with_config(source, GoldenConfig::x86_64_linux_release());
profiler.end_span("total", ProfileCategory::Other, 0);
(result, profiler)
}
pub fn compile_with_verification(source: &str) -> (GoldenResult, GoldenVerifier) {
let mut verifier = GoldenVerifier::new(true);
let result = compile_with_config(source, GoldenConfig::x86_64_linux_release());
if let Some(ref module) = result.module {
verifier.verify_module(module);
}
(result, verifier)
}
pub fn compile_with_diagnostics(source: &str) -> (GoldenResult, GoldenDiagnostics) {
let mut diagnostics = GoldenDiagnostics::new(DiagnosticConfig {
verbose: true,
show_snippets: true,
..Default::default()
});
let result = compile_with_config(source, GoldenConfig::x86_64_linux_release());
if !result.success {
diagnostics.error(
"compile",
&format!("Compilation failed with {} errors", result.error_count),
);
}
(result, diagnostics)
}
pub fn generate_toolchain_report(config: &GoldenConfig) -> String {
let mut report = String::new();
report.push_str("══════ llvm-native Toolchain Report ══════\n\n");
report.push_str(&format!(
"Compiler version: {}\n",
env!("CARGO_PKG_VERSION")
));
report.push_str(&format!("Host triple: {}\n", detect_host_triple()));
report.push_str(&config.summary());
if let Some(ref sysroot) = config.sysroot {
report.push_str(&format!(" Sysroot: {}\n", sysroot.display()));
}
if let Some(ref cachedir) = config.cache_dir {
report.push_str(&format!(" Cache dir: {}\n", cachedir.display()));
}
report.push_str(&format!(
" Max errors: {} Max memory: {} MB\n",
config.error_limit, config.max_memory_mb
));
report
}
pub struct DependencyTracker {
pub dependencies: HashMap<PathBuf, Vec<PathBuf>>,
pub reverse_deps: HashMap<PathBuf, Vec<PathBuf>>,
pub modified_files: HashSet<PathBuf>,
pub active: bool,
pub started_at: Option<SystemTime>,
}
impl DependencyTracker {
pub fn new() -> Self {
DependencyTracker {
dependencies: HashMap::new(),
reverse_deps: HashMap::new(),
modified_files: HashSet::new(),
active: false,
started_at: None,
}
}
pub fn start(&mut self) {
self.active = true;
self.started_at = Some(SystemTime::now());
}
pub fn record_dependency(&mut self, source: &Path, header: &Path) {
if !self.active {
return;
}
self.dependencies
.entry(source.to_path_buf())
.or_default()
.push(header.to_path_buf());
self.reverse_deps
.entry(header.to_path_buf())
.or_default()
.push(source.to_path_buf());
}
pub fn record_dependencies(&mut self, source: &Path, headers: &[PathBuf]) {
for header in headers {
self.record_dependency(source, header);
}
}
pub fn files_including(&self, header: &Path) -> Vec<&PathBuf> {
self.reverse_deps
.get(header)
.map(|v| v.iter().collect())
.unwrap_or_default()
}
pub fn dependencies_of(&self, source: &Path) -> Vec<&PathBuf> {
self.dependencies
.get(source)
.map(|v| v.iter().collect())
.unwrap_or_default()
}
pub fn mark_modified(&mut self, path: &Path) {
self.modified_files.insert(path.to_path_buf());
}
pub fn files_needing_recompilation(&self) -> HashSet<PathBuf> {
let mut needs_rebuild = HashSet::new();
for modified in &self.modified_files {
if let Some(dependents) = self.reverse_deps.get(modified) {
for dep in dependents {
needs_rebuild.insert(dep.clone());
}
}
}
for modified in &self.modified_files {
if self.dependencies.contains_key(modified) {
needs_rebuild.insert(modified.clone());
}
}
needs_rebuild
}
pub fn clear(&mut self) {
self.dependencies.clear();
self.reverse_deps.clear();
self.modified_files.clear();
}
pub fn generate_makefile_dep(&self, target: &Path) -> String {
let mut dep = format!("{}:\\\n", target.display());
let deps = self.dependencies_of(target);
for (i, d) in deps.iter().enumerate() {
dep.push_str(&format!(
" {}{}\
",
d.display(),
if i < deps.len() - 1 { " \\\n" } else { "" }
));
}
dep.push('\n');
dep
}
pub fn generate_ninja_dep(&self, target: &Path) -> String {
let mut dep = format!("{}:", target.display());
for d in self.dependencies_of(target) {
dep.push_str(&format!(" {}", d.display()));
}
dep.push('\n');
dep
}
pub fn stats(&self) -> DependencyStats {
let total_deps: usize = self.dependencies.values().map(|v| v.len()).sum();
let unique_headers: HashSet<_> = self.dependencies.values().flatten().collect();
DependencyStats {
total_source_files: self.dependencies.len(),
total_dependencies: total_deps,
unique_headers: unique_headers.len(),
modified_files: self.modified_files.len(),
files_needing_rebuild: self.files_needing_recompilation().len(),
}
}
}
#[derive(Debug, Clone)]
pub struct DependencyStats {
pub total_source_files: usize,
pub total_dependencies: usize,
pub unique_headers: usize,
pub modified_files: usize,
pub files_needing_rebuild: usize,
}
impl Default for DependencyTracker {
fn default() -> Self {
DependencyTracker::new()
}
}
#[derive(Debug, Clone)]
pub struct GoldenSanitizerConfig {
pub address: bool,
pub undefined: bool,
pub thread: bool,
pub memory: bool,
pub leak: bool,
pub dataflow: bool,
pub safe_stack: bool,
pub hwaddress: bool,
pub shadow_call_stack: bool,
pub ubsan_recover: bool,
pub ubsan_trap: bool,
pub minimal_runtime: bool,
pub blacklist_file: Option<PathBuf>,
pub asan_options: HashMap<String, String>,
pub ubsan_options: HashMap<String, String>,
pub coverage: bool,
}
impl Default for GoldenSanitizerConfig {
fn default() -> Self {
GoldenSanitizerConfig {
address: false,
undefined: false,
thread: false,
memory: false,
leak: false,
dataflow: false,
safe_stack: false,
hwaddress: false,
shadow_call_stack: false,
ubsan_recover: false,
ubsan_trap: false,
minimal_runtime: false,
blacklist_file: None,
asan_options: HashMap::new(),
ubsan_options: HashMap::new(),
coverage: false,
}
}
}
impl GoldenSanitizerConfig {
pub fn from_golden_config(config: &GoldenConfig) -> Self {
GoldenSanitizerConfig {
address: config.asan,
undefined: config.ubsan,
thread: config.tsan,
memory: config.msan,
leak: config.lsan,
coverage: config.coverage,
..Default::default()
}
}
pub fn has_any(&self) -> bool {
self.address
|| self.undefined
|| self.thread
|| self.memory
|| self.leak
|| self.dataflow
|| self.hwaddress
|| self.safe_stack
}
pub fn check_compatibility(&self) -> Vec<String> {
let mut errors = Vec::new();
if self.address && self.thread {
errors.push("ASan and TSan are mutually exclusive".into());
}
if self.address && self.memory {
errors.push("ASan and MSan are mutually exclusive".into());
}
if self.thread && self.memory {
errors.push("TSan and MSan are mutually exclusive".into());
}
if self.address && self.hwaddress {
errors.push("ASan and HWASan are mutually exclusive".into());
}
errors
}
pub fn compiler_flags(&self) -> Vec<String> {
let mut flags = Vec::new();
if self.address {
flags.push("-fsanitize=address".into());
}
if self.undefined {
flags.push("-fsanitize=undefined".into());
}
if self.thread {
flags.push("-fsanitize=thread".into());
}
if self.memory {
flags.push("-fsanitize=memory".into());
}
if self.leak {
flags.push("-fsanitize=leak".into());
}
if self.dataflow {
flags.push("-fsanitize=dataflow".into());
}
if self.hwaddress {
flags.push("-fsanitize=hwaddress".into());
}
if self.safe_stack {
flags.push("-fsanitize=safe-stack".into());
}
if self.coverage {
flags.push("-fsanitize-coverage=trace-pc-guard".into());
}
flags
}
pub fn linker_libraries(&self) -> Vec<String> {
let mut libs = Vec::new();
if self.address {
libs.push("asan".into());
}
if self.undefined {
libs.push("ubsan_standalone".into());
}
if self.thread {
libs.push("tsan".into());
}
if self.memory {
libs.push("msan".into());
}
if self.leak {
libs.push("lsan".into());
}
if self.dataflow {
libs.push("dfsan".into());
}
if self.hwaddress {
libs.push("hwasan".into());
}
libs
}
pub fn asan_options_string(&self) -> String {
let mut opts = vec![
("detect_stack_use_after_return", "1"),
("check_initialization_order", "1"),
];
for (k, v) in &self.asan_options {
opts.push((k.as_str(), v.as_str()));
}
opts.iter()
.map(|(k, v)| format!("{k}={v}"))
.collect::<Vec<_>>()
.join(":")
}
pub fn ubsan_options_string(&self) -> String {
let mut opts = vec![("print_stacktrace", "1")];
for (k, v) in &self.ubsan_options {
opts.push((k.as_str(), v.as_str()));
}
opts.iter()
.map(|(k, v)| format!("{k}={v}"))
.collect::<Vec<_>>()
.join(":")
}
pub fn summary(&self) -> String {
let mut s = String::from("Sanitizers: ");
let mut active = Vec::new();
if self.address {
active.push("ASan");
}
if self.undefined {
active.push("UBSan");
}
if self.thread {
active.push("TSan");
}
if self.memory {
active.push("MSan");
}
if self.leak {
active.push("LSan");
}
if self.hwaddress {
active.push("HWASan");
}
if self.safe_stack {
active.push("SafeStack");
}
if active.is_empty() {
s.push_str("none");
} else {
s.push_str(&active.join(", "));
}
s
}
}
#[derive(Debug, Clone)]
pub struct GoldenCoverage {
pub coverage_mapping: bool,
pub profile_generate: bool,
pub profile_use: Option<PathBuf>,
pub cs_profile_generate: bool,
pub cs_profile_use: Option<PathBuf>,
pub coverage_dir: PathBuf,
pub notes_file: Option<PathBuf>,
pub data_file: Option<PathBuf>,
pub function_sections: bool,
pub debug_info_for_profiling: bool,
}
impl Default for GoldenCoverage {
fn default() -> Self {
GoldenCoverage {
coverage_mapping: false,
profile_generate: false,
profile_use: None,
cs_profile_generate: false,
cs_profile_use: None,
coverage_dir: PathBuf::from("."),
notes_file: None,
data_file: None,
function_sections: false,
debug_info_for_profiling: false,
}
}
}
impl GoldenCoverage {
pub fn from_golden_config(config: &GoldenConfig) -> Self {
GoldenCoverage {
coverage_mapping: config.coverage,
profile_generate: config.pgo_generate,
profile_use: config.pgo_use.clone(),
..Default::default()
}
}
pub fn is_active(&self) -> bool {
self.coverage_mapping || self.profile_generate || self.profile_use.is_some()
}
pub fn compiler_flags(&self) -> Vec<String> {
let mut flags = Vec::new();
if self.coverage_mapping {
flags.push("-fprofile-instr-generate".into());
flags.push("-fcoverage-mapping".into());
}
if self.profile_generate {
flags.push("-fprofile-generate".into());
}
if self.function_sections {
flags.push("-ffunction-sections".into());
}
if self.debug_info_for_profiling {
flags.push("-fdebug-info-for-profiling".into());
}
flags
}
}
#[derive(Debug)]
pub struct GoldenPGO {
pub config: PGOConfig,
pub profile_data: Option<PGOProfile>,
pub applied: bool,
}
#[derive(Debug, Clone)]
pub struct PGOConfig {
pub enabled: bool,
pub profile_path: Option<PathBuf>,
pub generate: bool,
pub use_profile: bool,
pub context_sensitive: bool,
pub sample_profile: Option<PathBuf>,
}
impl Default for PGOConfig {
fn default() -> Self {
PGOConfig {
enabled: false,
profile_path: None,
generate: false,
use_profile: false,
context_sensitive: false,
sample_profile: None,
}
}
}
#[derive(Debug, Clone)]
pub struct PGOProfile {
pub function_counts: HashMap<String, u64>,
pub branch_weights: HashMap<String, (u64, u64)>,
pub total_entries: usize,
pub source_file: PathBuf,
}
impl PGOProfile {
pub fn empty() -> Self {
PGOProfile {
function_counts: HashMap::new(),
branch_weights: HashMap::new(),
total_entries: 0,
source_file: PathBuf::new(),
}
}
pub fn record_function(&mut self, name: &str, count: u64) {
*self.function_counts.entry(name.into()).or_insert(0) += count;
self.total_entries += 1;
}
pub fn record_branch(&mut self, location: &str, taken: u64, not_taken: u64) {
self.branch_weights
.insert(location.into(), (taken, not_taken));
self.total_entries += 1;
}
pub fn function_count(&self, name: &str) -> u64 {
self.function_counts.get(name).copied().unwrap_or(0)
}
pub fn function_hotness(&self, name: &str) -> u8 {
let max = self.function_counts.values().max().copied().unwrap_or(1);
let count = self.function_count(name);
((count as f64 / max as f64) * 100.0).min(100.0) as u8
}
pub fn is_hot(&self, name: &str) -> bool {
self.function_hotness(name) >= 80
}
}
impl GoldenPGO {
pub fn new(config: PGOConfig) -> Self {
GoldenPGO {
config,
profile_data: None,
applied: false,
}
}
pub fn from_golden_config(config: &GoldenConfig) -> Self {
let pgo_config = PGOConfig {
enabled: config.pgo_generate || config.pgo_use.is_some(),
generate: config.pgo_generate,
profile_path: config.pgo_use.clone(),
use_profile: config.pgo_use.is_some(),
..Default::default()
};
GoldenPGO::new(pgo_config)
}
pub fn load_profile(&mut self, path: &Path) -> io::Result<()> {
let _ = fs::read(path)?;
self.profile_data = Some(PGOProfile::empty());
Ok(())
}
pub fn apply(&mut self) {
self.applied = true;
}
pub fn summary(&self) -> String {
let mut s = String::from("PGO: ");
if self.config.generate {
s.push_str("generating ");
}
if self.config.use_profile {
s.push_str("using profile ");
}
if !self.config.enabled {
s.push_str("disabled");
}
s
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RecoveryStrategy {
Abort,
Collect,
SkipToNextDecl,
AttemptFix,
BestEffort,
}
impl Default for RecoveryStrategy {
fn default() -> Self {
RecoveryStrategy::Collect
}
}
pub struct ErrorRecovery {
pub strategy: RecoveryStrategy,
pub errors_collected: Vec<String>,
pub recovery_points: Vec<usize>,
pub last_successful_stage: Option<String>,
pub skip_count: usize,
pub fix_count: usize,
pub fatal_error: bool,
}
impl ErrorRecovery {
pub fn new(strategy: RecoveryStrategy) -> Self {
ErrorRecovery {
strategy,
errors_collected: Vec::new(),
recovery_points: Vec::new(),
last_successful_stage: None,
skip_count: 0,
fix_count: 0,
fatal_error: false,
}
}
pub fn record_error(&mut self, error: String) {
self.errors_collected.push(error);
}
pub fn record_recovery_point(&mut self) {
self.recovery_points.push(self.errors_collected.len());
}
pub fn should_continue(&self) -> bool {
if self.fatal_error {
return false;
}
match self.strategy {
RecoveryStrategy::Abort => self.errors_collected.is_empty(),
RecoveryStrategy::Collect
| RecoveryStrategy::SkipToNextDecl
| RecoveryStrategy::AttemptFix
| RecoveryStrategy::BestEffort => true,
}
}
pub fn increment_skip_count(&mut self) {
self.skip_count += 1;
}
pub fn increment_fix_count(&mut self) {
self.fix_count += 1;
}
pub fn mark_fatal(&mut self) {
self.fatal_error = true;
}
pub fn has_errors(&self) -> bool {
!self.errors_collected.is_empty()
}
pub fn error_count(&self) -> usize {
self.errors_collected.len()
}
pub fn reset(&mut self) {
self.errors_collected.clear();
self.recovery_points.clear();
self.last_successful_stage = None;
self.skip_count = 0;
self.fix_count = 0;
self.fatal_error = false;
}
}
#[derive(Debug, Clone)]
pub struct CompilerVersion {
pub name: String,
pub version: String,
pub major: u32,
pub minor: u32,
pub patch: u32,
pub git_hash: Option<String>,
pub build_date: String,
pub target_triple: String,
}
impl CompilerVersion {
pub fn current() -> Self {
let version = env!("CARGO_PKG_VERSION");
let parts: Vec<&str> = version.split('.').collect();
let major = parts.first().and_then(|s| s.parse().ok()).unwrap_or(0);
let minor = parts.get(1).and_then(|s| s.parse().ok()).unwrap_or(0);
let patch = parts.get(2).and_then(|s| s.parse().ok()).unwrap_or(0);
CompilerVersion {
name: "llvm-native".into(),
version: version.into(),
major,
minor,
patch,
git_hash: option_env!("GIT_HASH").map(|s| s.into()),
build_date: chrono_now(),
target_triple: detect_host_triple(),
}
}
pub fn to_string(&self) -> String {
format!(
"{} version {} ({})",
self.name, self.version, self.target_triple
)
}
pub fn supports_feature(&self, feature: &str) -> bool {
match feature {
"c11" | "c17" | "gnu_extensions" => true,
"cxx14" | "cxx17" => true,
"lto" | "thin_lto" => true,
"asan" | "ubsan" | "tsan" | "msan" => true,
"x86_64" | "i386" | "x32" => true,
_ => false,
}
}
pub fn supported_features(&self) -> Vec<&'static str> {
vec![
"c11",
"c17",
"c23",
"cxx14",
"cxx17",
"cxx20",
"gnu_extensions",
"ms_extensions",
"lto",
"thin_lto",
"asan",
"ubsan",
"tsan",
"msan",
"lsan",
"x86_64",
"i386",
"x32",
"dwarf",
"codeview",
"pgo",
"coverage",
"self_host",
"cross_compile",
]
}
pub fn version_string(&self) -> String {
format!("{}.{}.{}", self.major, self.minor, self.patch)
}
}
impl Default for CompilerVersion {
fn default() -> Self {
CompilerVersion::current()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_golden_config_default() {
let config = GoldenConfig::default();
assert_eq!(config.target_triple, "x86_64-unknown-linux-gnu");
assert_eq!(config.opt_level, "0");
assert_eq!(config.output_format, "object");
assert!(!config.lto);
assert!(!config.debug_info);
assert_eq!(config.error_limit, 20);
}
#[test]
fn test_golden_config_x86_64_linux() {
let config = GoldenConfig::x86_64_linux();
assert_eq!(config.target_triple, "x86_64-unknown-linux-gnu");
assert_eq!(config.target_abi, "sysv");
}
#[test]
fn test_golden_config_x86_64_linux_release() {
let config = GoldenConfig::x86_64_linux_release();
assert_eq!(config.opt_level, "2");
assert!(config.lto);
}
#[test]
fn test_golden_config_x86_64_windows() {
let config = GoldenConfig::x86_64_windows();
assert!(config.target_triple.contains("windows"));
assert_eq!(config.target_abi, "win64");
assert!(config.codeview);
}
#[test]
fn test_golden_config_x86_64_darwin() {
let config = GoldenConfig::x86_64_darwin();
assert!(config.target_triple.contains("darwin"));
}
#[test]
fn test_golden_config_i386_linux() {
let config = GoldenConfig::i386_linux();
assert!(config.m32);
assert!(config.target_triple.starts_with("i386"));
}
#[test]
fn test_golden_config_x32_linux() {
let config = GoldenConfig::x32_linux();
assert!(config.mx32);
assert!(config.target_triple.contains("x32"));
}
#[test]
fn test_golden_config_builders() {
let config = GoldenConfig::default()
.with_output("/tmp/out.o")
.with_opt_level("3")
.with_target("aarch64-unknown-linux-gnu")
.with_cpu("cortex-a76")
.with_lto(true)
.with_thin_lto(true)
.with_debug_info(true)
.with_verbose(true)
.with_standard("c17")
.with_cxx(true)
.with_output_format("assembly");
assert_eq!(config.output_file, Some(PathBuf::from("/tmp/out.o")));
assert_eq!(config.opt_level, "3");
assert_eq!(config.target_triple, "aarch64-unknown-linux-gnu");
assert_eq!(config.target_cpu, "cortex-a76");
assert!(config.lto);
assert!(config.thin_lto);
assert!(config.debug_info);
assert!(config.verbose);
assert_eq!(config.language_standard, "c17");
assert!(config.is_cxx);
assert_eq!(config.output_format, "assembly");
}
#[test]
fn test_golden_config_with_sanitizer() {
let mut config = GoldenConfig::default();
assert!(!config.asan);
config = config.with_sanitizer("address");
assert!(config.asan);
config = config.with_sanitizer("undefined");
assert!(config.ubsan);
config = config.with_sanitizer("thread");
assert!(config.tsan);
}
#[test]
fn test_golden_config_validate_ok() {
let config = GoldenConfig {
input_files: vec![PathBuf::from("test.c")],
..GoldenConfig::x86_64_linux()
};
assert!(config.validate().is_ok());
}
#[test]
fn test_golden_config_validate_no_files() {
let config = GoldenConfig::x86_64_linux();
let result = config.validate();
assert!(result.is_err());
let errors = result.unwrap_err();
assert!(errors.iter().any(|e| e.contains("No input files")));
}
#[test]
fn test_golden_config_validate_conflicting_sanitizers() {
let mut config = GoldenConfig {
input_files: vec![PathBuf::from("test.c")],
..GoldenConfig::x86_64_linux()
};
config.asan = true;
config.tsan = true;
let result = config.validate();
assert!(result.is_err());
}
#[test]
fn test_golden_config_cache_key_determinism() {
let a = GoldenConfig::x86_64_linux();
let b = GoldenConfig::x86_64_linux();
assert_eq!(a.cache_key(), b.cache_key());
}
#[test]
fn test_golden_config_cache_key_different() {
let a = GoldenConfig::x86_64_linux();
let b = GoldenConfig::x86_64_linux_release();
assert_ne!(a.cache_key(), b.cache_key());
}
#[test]
fn test_golden_config_is_cross_compiling() {
let config = GoldenConfig::default();
assert!(!config.is_cross_compiling());
let config = config.with_sysroot(PathBuf::from("/sysroot"));
assert!(config.is_cross_compiling());
}
#[test]
fn test_golden_config_to_x86_compile_options() {
let config = GoldenConfig::x86_64_linux_release();
let opts = config.to_x86_compile_options();
assert_eq!(opts.target_triple, "x86_64-unknown-linux-gnu");
assert_eq!(opts.opt_level, X86OptLevel::from_str("2").unwrap());
}
#[test]
fn test_golden_config_summary() {
let config = GoldenConfig::x86_64_linux_release();
let summary = config.summary();
assert!(summary.contains("x86_64"));
assert!(summary.contains("LTO:"));
}
#[test]
fn test_golden_path_new() {
let path = GoldenPath::new(GoldenConfig::x86_64_linux());
assert!(!path.is_executed());
assert!(path.get_result().is_none());
}
#[test]
fn test_golden_path_with_context() {
let ctx = LLVMContext::new();
let path = GoldenPath::with_context(GoldenConfig::x86_64_linux(), ctx);
assert!(!path.is_executed());
}
#[test]
fn test_golden_path_compile_empty_source() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_test_empty.c");
let _ = fs::write(&tmpfile, "");
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
..GoldenConfig::x86_64_linux()
});
let result = path.compile();
assert!(result.success);
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_golden_path_compile_minimal_c() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_test_min.c");
let _ = fs::write(&tmpfile, "int main(void) { return 0; }\n");
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let result = path.compile();
assert!(result.success);
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_golden_path_compile_to_obj() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_test_obj.c");
let _ = fs::write(&tmpfile, "int add(int a, int b) { return a + b; }\n");
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
..GoldenConfig::x86_64_linux()
});
let obj = path.compile_to_obj();
let _ = obj;
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_golden_path_compile_to_asm() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_test_asm.c");
let _ = fs::write(&tmpfile, "int main(void) { return 42; }\n");
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
..GoldenConfig::x86_64_linux()
});
let asm = path.compile_to_asm();
let _ = asm;
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_golden_path_compile_to_ir() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_test_ir.c");
let _ = fs::write(&tmpfile, "int main(void) { return 0; }\n");
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
..GoldenConfig::x86_64_linux()
});
let ir = path.compile_to_ir();
let _ = ir;
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_golden_path_compile_to_module() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_test_mod.c");
let _ = fs::write(&tmpfile, "int main(void) { return 0; }\n");
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
..GoldenConfig::x86_64_linux()
});
let module = path.compile_to_module();
let _ = module;
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_golden_path_dry_run() {
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![PathBuf::from("test.c")],
dry_run: true,
..GoldenConfig::x86_64_linux()
});
let result = path.compile();
assert!(result.success);
assert!(path.is_executed());
}
#[test]
fn test_golden_path_config_validation_fails() {
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![],
tsan: true,
asan: true,
..GoldenConfig::x86_64_linux()
});
let result = path.compile();
assert!(!result.success);
assert_eq!(result.failed_stage, Some("validation".into()));
}
#[test]
fn test_golden_path_metrics() {
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![PathBuf::from("test.c")],
..GoldenConfig::x86_64_linux()
});
let _ = path.compile();
let metrics = path.get_metrics();
assert!(metrics.total_time > Duration::ZERO);
}
#[test]
fn test_golden_path_summary() {
let mut path = GoldenPath::new(GoldenConfig::x86_64_linux());
let summary = path.summary();
assert!(summary.contains("GoldenPath"));
}
#[test]
fn test_golden_path_with_caching() {
let config = GoldenConfig {
input_files: vec![PathBuf::from("test.c")],
enable_cache: true,
cache_dir: Some(std::env::temp_dir().join("golden_test_cache")),
..GoldenConfig::x86_64_linux()
};
let mut path = GoldenPath::new(config);
let stats = path.cache.stats();
assert!(stats.enabled);
let _ = fs::remove_dir_all(std::env::temp_dir().join("golden_test_cache"));
}
#[test]
fn test_golden_pipeline_new() {
let pipeline = GoldenPipeline::new(GoldenConfig::x86_64_linux());
assert!(!pipeline.aborted);
assert!(pipeline.stage_results.is_empty());
}
#[test]
fn test_golden_pipeline_dry_run() {
let mut pipeline = GoldenPipeline::new(GoldenConfig {
input_files: vec![PathBuf::from("test.c")],
dry_run: true,
..GoldenConfig::x86_64_linux()
});
let mut ctx = LLVMContext::new();
let result = pipeline.run(&mut ctx);
assert!(result.success);
}
#[test]
fn test_golden_pipeline_run_empty_input() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_pipe_empty.c");
let _ = fs::write(&tmpfile, "");
let mut pipeline = GoldenPipeline::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
..GoldenConfig::x86_64_linux()
});
let mut ctx = LLVMContext::new();
let result = pipeline.run(&mut ctx);
assert!(result.success);
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_golden_pipeline_report() {
let pipeline = GoldenPipeline::new(GoldenConfig::x86_64_linux());
let report = pipeline.report();
assert!(report.contains("Golden Pipeline"));
}
#[test]
fn test_golden_pipeline_is_complete() {
let pipeline = GoldenPipeline::new(GoldenConfig::x86_64_linux());
assert!(pipeline.is_complete());
}
#[test]
fn test_golden_pipeline_result_success() {
let mut ctx = LLVMContext::new();
let module = ctx.create_module_owned("test");
let result = GoldenPipelineResult::success(module);
assert!(result.success);
assert!(result.module.is_some());
}
#[test]
fn test_golden_pipeline_result_failure() {
let result = GoldenPipelineResult::failure(vec!["test error".into()]);
assert!(!result.success);
assert!(result.has_errors());
}
#[test]
fn test_golden_pipeline_result_one_line() {
let result = GoldenPipelineResult::failure(vec!["err1".into(), "err2".into()]);
let line = result.one_line();
assert!(line.contains("errors=2"));
}
#[test]
fn test_golden_compiler_new() {
let compiler = GoldenCompiler::new(GoldenConfig::x86_64_linux());
assert!(!compiler.has_run);
assert_eq!(compiler.stats.total_compilations, 0);
}
#[test]
fn test_golden_compiler_compile_c_string_empty() {
let mut compiler = GoldenCompiler::new(GoldenConfig {
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let result = compiler.compile_c_string("");
let _ = result;
assert!(compiler.has_run);
}
#[test]
fn test_golden_compiler_compile_c_string_minimal() {
let mut compiler = GoldenCompiler::new(GoldenConfig {
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let result = compiler.compile_c_string("int main(void) { return 0; }");
let _ = result;
}
#[test]
fn test_golden_compiler_compile_to_object() {
let mut compiler = GoldenCompiler::new(GoldenConfig::x86_64_linux());
let result = compiler.compile_to_object("int add(int a, int b) { return a + b; }");
let _ = result;
}
#[test]
fn test_golden_compiler_compile_to_assembly() {
let mut compiler = GoldenCompiler::new(GoldenConfig::x86_64_linux());
let result = compiler.compile_to_assembly("int main(void) { return 42; }");
let _ = result;
}
#[test]
fn test_golden_compiler_compile_to_llvm_ir() {
let mut compiler = GoldenCompiler::new(GoldenConfig::x86_64_linux());
let result = compiler.compile_to_llvm_ir("int main(void) { return 0; }");
let _ = result;
}
#[test]
fn test_golden_compiler_cxx_string() {
let mut compiler = GoldenCompiler::new(GoldenConfig {
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let result = compiler.compile_cxx_string("int main() { return 0; }");
let _ = result;
}
#[test]
fn test_golden_compiler_arg_parsing_c() {
let mut compiler = GoldenCompiler::new(GoldenConfig::default());
let args = vec![
"-c".into(),
"-O2".into(),
"-g".into(),
"-Wall".into(),
"-o".into(),
"output.o".into(),
"input.c".into(),
];
compiler.parse_args(&args);
assert!(compiler.path.config.compile_only);
assert_eq!(compiler.path.config.opt_level, "2");
assert!(compiler.path.config.debug_info);
assert!(compiler.path.config.wall);
assert_eq!(
compiler.path.config.output_file,
Some(PathBuf::from("output.o"))
);
}
#[test]
fn test_golden_compiler_arg_parsing_flto() {
let mut compiler = GoldenCompiler::new(GoldenConfig::default());
compiler.parse_args(&["-flto=thin".into()]);
assert!(compiler.path.config.lto);
assert!(compiler.path.config.thin_lto);
}
#[test]
fn test_golden_compiler_arg_parsing_sanitizer() {
let mut compiler = GoldenCompiler::new(GoldenConfig::default());
compiler.parse_args(&["-fsanitize=address".into()]);
assert!(compiler.path.config.asan);
}
#[test]
fn test_golden_compiler_stats_summary() {
let mut compiler = GoldenCompiler::new(GoldenConfig::x86_64_linux());
let summary = compiler.stats_summary();
assert!(summary.contains("Golden Compiler"));
assert!(summary.contains("0 total"));
}
#[test]
fn test_golden_compiler_run_with_args() {
let mut compiler = GoldenCompiler::new(GoldenConfig {
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let result = compiler.run_with_args(&["-c".into(), "-O0".into(), "input.c".into()]);
let _ = result;
}
#[test]
fn test_golden_lto_new() {
let lto = GoldenLTO::new(LTOConfig::default());
assert!(!lto.config.enabled);
assert!(lto.modules.is_empty());
assert!(!lto.completed);
}
#[test]
fn test_golden_lto_from_golden_config() {
let config = GoldenConfig::x86_64_linux_release();
let lto = GoldenLTO::from_golden_config(&config);
assert!(lto.config.enabled);
assert!(!lto.config.thin);
}
#[test]
fn test_golden_lto_add_module() {
let mut lto = GoldenLTO::new(LTOConfig::default());
let ctx = LLVMContext::new();
let module = ctx.create_module_owned("test");
lto.add_module(module);
assert_eq!(lto.modules.len(), 1);
}
#[test]
fn test_golden_lto_add_modules() {
let mut lto = GoldenLTO::new(LTOConfig::default());
let ctx = LLVMContext::new();
let m1 = ctx.create_module_owned("a");
let m2 = ctx.create_module_owned("b");
lto.add_modules(vec![m1, m2]);
assert_eq!(lto.modules.len(), 2);
}
#[test]
fn test_golden_lto_run_when_disabled() {
let mut lto = GoldenLTO::new(LTOConfig::default());
let result = lto.run_full_lto();
assert!(result.is_err());
}
#[test]
fn test_golden_lto_run_no_modules() {
let mut lto = GoldenLTO::new(LTOConfig {
enabled: true,
..Default::default()
});
let result = lto.run_full_lto();
assert!(result.is_err());
}
#[test]
fn test_golden_lto_thin_when_full() {
let mut lto = GoldenLTO::new(LTOConfig {
enabled: true,
thin: false,
..Default::default()
});
let ctx = LLVMContext::new();
lto.add_module(ctx.create_module_owned("test"));
lto.add_module(ctx.create_module_owned("test2"));
let result = lto.run_thin_lto();
assert!(result.is_err()); }
#[test]
fn test_golden_lto_summary() {
let lto = GoldenLTO::new(LTOConfig {
enabled: true,
thin: true,
..Default::default()
});
let summary = lto.summary();
assert!(summary.contains("thin"));
assert!(summary.contains("Modules merged: 0"));
}
#[test]
fn test_golden_lto_resolution_file() {
let mut lto = GoldenLTO::new(LTOConfig::default());
let ctx = LLVMContext::new();
lto.add_module(ctx.create_module_owned("test"));
let res = lto.generate_resolution_file();
let _ = res;
}
#[test]
fn test_golden_self_host_new() {
let config = SelfHostConfig::default();
let sh = GoldenSelfHost::new(config);
assert!(!sh.complete);
assert!(sh.stage_results.is_empty());
assert!(sh.stage2_stage3_identical.is_none());
}
#[test]
fn test_golden_self_host_config_default() {
let config = SelfHostConfig::default();
assert_eq!(config.stage_count, 3);
assert!(config.verify_stages);
assert!(config.track_performance);
}
#[test]
fn test_golden_self_host_status_not_started() {
let sh = GoldenSelfHost::new(SelfHostConfig::default());
assert!(sh.status().contains("not started"));
}
#[test]
fn test_test_harness_new() {
let harness = GoldenTestHarness::new(TestHarnessConfig::default());
assert!(!harness.executed);
assert!(harness.test_cases.is_empty());
assert!(harness.results.is_empty());
}
#[test]
fn test_test_harness_register() {
let mut harness = GoldenTestHarness::new(TestHarnessConfig::default());
let test = GoldenTestCase {
name: "test_empty".into(),
category: TestCategory::Pipeline,
source: "".into(),
expected_output: None,
expected_return: 0,
expect_failure: false,
expected_error: None,
language_standard: "c17".into(),
is_cxx: false,
config_overrides: GoldenConfig::default(),
timeout_secs: 0,
tags: vec![],
};
harness.register(test);
assert_eq!(harness.test_cases.len(), 1);
}
#[test]
fn test_test_harness_filter() {
let mut harness = GoldenTestHarness::new(TestHarnessConfig {
filter: Some("specific".into()),
..Default::default()
});
harness.register(GoldenTestCase {
name: "specific_test".into(),
category: TestCategory::Pipeline,
source: "".into(),
expected_output: None,
expected_return: 0,
expect_failure: false,
expected_error: None,
language_standard: "c17".into(),
is_cxx: false,
config_overrides: GoldenConfig::default(),
timeout_secs: 0,
tags: vec![],
});
harness.register(GoldenTestCase {
name: "other_test".into(),
category: TestCategory::Pipeline,
source: "".into(),
expected_output: None,
expected_return: 0,
expect_failure: false,
expected_error: None,
language_standard: "c17".into(),
is_cxx: false,
config_overrides: GoldenConfig::default(),
timeout_secs: 0,
tags: vec![],
});
assert_eq!(harness.test_cases.len(), 1);
}
#[test]
fn test_test_harness_run_single_test_empty() {
let mut harness = GoldenTestHarness::new(TestHarnessConfig::default());
let test = GoldenTestCase {
name: "test_empty".into(),
category: TestCategory::Pipeline,
source: "".into(),
expected_output: None,
expected_return: 0,
expect_failure: false,
expected_error: None,
language_standard: "c17".into(),
is_cxx: false,
config_overrides: GoldenConfig {
syntax_only: true,
..GoldenConfig::default()
},
timeout_secs: 0,
tags: vec![],
};
let result = harness.run_single_test(&test);
assert!(result.passed);
}
#[test]
fn test_test_harness_run_single_test_minimal() {
let mut harness = GoldenTestHarness::new(TestHarnessConfig::default());
let test = GoldenTestCase {
name: "test_min".into(),
category: TestCategory::Pipeline,
source: "int main(void) { return 0; }\n".into(),
expected_output: None,
expected_return: 0,
expect_failure: false,
expected_error: None,
language_standard: "c17".into(),
is_cxx: false,
config_overrides: GoldenConfig {
syntax_only: true,
..GoldenConfig::default()
},
timeout_secs: 0,
tags: vec![],
};
let result = harness.run_single_test(&test);
assert!(result.passed);
}
#[test]
fn test_test_harness_expect_failure() {
let mut harness = GoldenTestHarness::new(TestHarnessConfig::default());
let test = GoldenTestCase {
name: "expect_fail".into(),
category: TestCategory::ErrorRecovery,
source: "@@@ invalid @@@".into(),
expected_output: None,
expected_return: 1,
expect_failure: true,
expected_error: Some("error".into()),
language_standard: "c17".into(),
is_cxx: false,
config_overrides: GoldenConfig::default(),
timeout_secs: 0,
tags: vec![],
};
let result = harness.run_single_test(&test);
let _ = result;
}
#[test]
fn test_test_harness_summary() {
let harness = GoldenTestHarness::new(TestHarnessConfig::default());
let summary = harness.summary();
assert!(summary.contains("Total: 0"));
}
#[test]
fn test_test_harness_junit_report() {
let harness = GoldenTestHarness::new(TestHarnessConfig::default());
let report = harness.junit_report();
assert!(report.contains("testsuite"));
}
#[test]
fn test_test_category_as_str() {
assert_eq!(TestCategory::Lexer.as_str(), "lexer");
assert_eq!(TestCategory::Parser.as_str(), "parser");
assert_eq!(TestCategory::CodeGen.as_str(), "codegen");
assert_eq!(TestCategory::Pipeline.as_str(), "pipeline");
}
#[test]
fn test_test_harness_register_many() {
let mut harness = GoldenTestHarness::new(TestHarnessConfig::default());
harness.register_many(vec![
GoldenTestCase {
name: "a".into(),
category: TestCategory::Lexer,
source: "".into(),
expected_output: None,
expected_return: 0,
expect_failure: false,
expected_error: None,
language_standard: "c17".into(),
is_cxx: false,
config_overrides: GoldenConfig::default(),
timeout_secs: 0,
tags: vec![],
},
GoldenTestCase {
name: "b".into(),
category: TestCategory::Parser,
source: "".into(),
expected_output: None,
expected_return: 0,
expect_failure: false,
expected_error: None,
language_standard: "c17".into(),
is_cxx: false,
config_overrides: GoldenConfig::default(),
timeout_secs: 0,
tags: vec![],
},
]);
assert_eq!(harness.test_cases.len(), 2);
}
#[test]
fn test_benchmarks_new() {
let benchmarks = GoldenBenchmarks::new(BenchmarkConfig::default());
assert!(!benchmarks.executed);
}
#[test]
fn test_benchmarks_register() {
let mut benchmarks = GoldenBenchmarks::new(BenchmarkConfig::default());
benchmarks.register(GoldenBenchmark {
name: "empty".into(),
source: "int main(void) { return 0; }\n".into(),
is_cxx: false,
expected_output: None,
min_lines: 1,
tags: vec![],
category: BenchmarkCategory::Micro,
});
assert_eq!(benchmarks.benchmarks.len(), 1);
}
#[test]
fn test_benchmarks_text_report_empty() {
let benchmarks = GoldenBenchmarks::new(BenchmarkConfig::default());
let report = benchmarks.text_report();
assert!(report.contains("Golden Benchmark"));
}
#[test]
fn test_benchmarks_json_report() {
let benchmarks = GoldenBenchmarks::new(BenchmarkConfig::default());
let report = benchmarks.json_report();
assert!(report.contains("["));
assert!(report.contains("]"));
}
#[test]
fn test_benchmarks_csv_report() {
let benchmarks = GoldenBenchmarks::new(BenchmarkConfig::default());
let report = benchmarks.csv_report();
assert!(report.contains("name,opt_level"));
}
#[test]
fn test_benchmarks_run_disabled() {
let mut benchmarks = GoldenBenchmarks::new(BenchmarkConfig {
enabled: false,
..Default::default()
});
benchmarks.register(GoldenBenchmark {
name: "test".into(),
source: "".into(),
is_cxx: false,
expected_output: None,
min_lines: 1,
tags: vec![],
category: BenchmarkCategory::Micro,
});
benchmarks.run_all();
assert!(benchmarks.results.is_empty());
}
#[test]
fn test_cache_new_disabled() {
let cache = CompilationCache::new();
assert!(!cache.is_enabled());
}
#[test]
fn test_cache_enable() {
let mut cache = CompilationCache::new();
cache.set_enabled(true);
assert!(cache.is_enabled());
}
#[test]
fn test_cache_lookup_disabled() {
let cache = CompilationCache::new();
assert!(cache.lookup("test_key").is_none());
}
#[test]
fn test_cache_store_and_lookup() {
let mut cache = CompilationCache::new();
cache.set_enabled(true);
cache.set_cache_dir(std::env::temp_dir().join("golden_bridge_test_cache"));
let key = "test_key_001";
let data = b"compiled_object_data";
cache.store(key, data);
let result = cache.lookup(key);
assert!(result.is_some());
assert_eq!(result.unwrap(), data);
let _ = fs::remove_dir_all(std::env::temp_dir().join("golden_bridge_test_cache"));
}
#[test]
fn test_cache_hit_miss_stats() {
let mut cache = CompilationCache::new();
cache.set_enabled(true);
cache.set_cache_dir(std::env::temp_dir().join("golden_bridge_test_cache2"));
cache.lookup("missing"); cache.store("present", b"data");
cache.lookup("present");
let stats = cache.stats();
assert_eq!(stats.hits, 1);
assert_eq!(stats.misses, 1);
let _ = fs::remove_dir_all(std::env::temp_dir().join("golden_bridge_test_cache2"));
}
#[test]
fn test_cache_clear() {
let mut cache = CompilationCache::new();
cache.set_enabled(true);
cache.set_cache_dir(std::env::temp_dir().join("golden_bridge_test_cache3"));
cache.store("key", b"data");
cache.lookup("key");
cache.clear();
let stats = cache.stats();
assert_eq!(stats.hits, 0);
assert_eq!(stats.misses, 0);
assert_eq!(stats.current_size_bytes, 0);
let _ = fs::remove_dir_all(std::env::temp_dir().join("golden_bridge_test_cache3"));
}
#[test]
fn test_cache_max_size() {
let mut cache = CompilationCache::new();
assert_eq!(cache.max_size, 1024 * 1024 * 1024);
cache.set_max_size(4096);
assert_eq!(cache.max_size, 4096);
}
#[test]
fn test_cache_hit_rate() {
let mut cache = CompilationCache::new();
cache.set_enabled(true);
assert!((cache.hit_rate() - 0.0).abs() < f64::EPSILON);
cache.set_cache_dir(std::env::temp_dir().join("golden_bridge_test_cache4"));
cache.store("a", b"x");
cache.lookup("a");
cache.lookup("b");
assert!((cache.hit_rate() - 0.5).abs() < 0.01);
let _ = fs::remove_dir_all(std::env::temp_dir().join("golden_bridge_test_cache4"));
}
#[test]
fn test_cache_make_key() {
let config = GoldenConfig::x86_64_linux();
let key1 = CompilationCache::make_key("int main() {}", &config);
let key2 = CompilationCache::make_key("int main() {}", &config);
assert_eq!(key1, key2);
let key3 = CompilationCache::make_key("int foo() {}", &config);
assert_ne!(key1, key3);
}
#[test]
fn test_cache_lookup_missing() {
let mut cache = CompilationCache::new();
cache.set_enabled(true);
cache.set_cache_dir(std::env::temp_dir().join("golden_bridge_test_cache5"));
let result = cache.lookup("nonexistent_key");
assert!(result.is_none());
let _ = fs::remove_dir_all(std::env::temp_dir().join("golden_bridge_test_cache5"));
}
#[test]
fn test_incremental_compiler_new() {
let ic = IncrementalCompiler::new(GoldenConfig::x86_64_linux());
assert!(!ic.enabled); }
#[test]
fn test_incremental_compiler_enabled() {
let config = GoldenConfig {
incremental: true,
incremental_cache_dir: Some(PathBuf::from("/tmp/incremental")),
..GoldenConfig::x86_64_linux()
};
let ic = IncrementalCompiler::new(config);
assert!(ic.enabled);
assert_eq!(ic.database.output_dir, PathBuf::from("/tmp/incremental"));
}
#[test]
fn test_incremental_needs_recompilation_no_record() {
let ic = IncrementalCompiler::new(GoldenConfig::x86_64_linux());
assert!(ic.needs_recompilation(Path::new("nonexistent.c")));
}
#[test]
fn test_incremental_detect_changes_empty() {
let mut ic = IncrementalCompiler::new(GoldenConfig::x86_64_linux());
let changes = ic.detect_changes();
assert!(changes.is_empty());
}
#[test]
fn test_cross_compiler_new_same_triple() {
let cc = CrossCompiler::new("x86_64-unknown-linux-gnu", "x86_64-unknown-linux-gnu");
assert!(!cc.is_cross);
}
#[test]
fn test_cross_compiler_new_diff_triple() {
let cc = CrossCompiler::new("x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu");
assert!(cc.is_cross);
}
#[test]
fn test_cross_target_arch_from_triple() {
assert_eq!(
CrossTargetArch::from_triple("x86_64-unknown-linux-gnu"),
Some(CrossTargetArch::X86_64)
);
assert_eq!(
CrossTargetArch::from_triple("i386-unknown-linux-gnu"),
Some(CrossTargetArch::X86)
);
assert_eq!(
CrossTargetArch::from_triple("aarch64-unknown-linux-gnu"),
Some(CrossTargetArch::AArch64)
);
assert_eq!(
CrossTargetArch::from_triple("arm-unknown-linux-gnueabi"),
Some(CrossTargetArch::ARM)
);
assert_eq!(
CrossTargetArch::from_triple("riscv64-unknown-elf"),
Some(CrossTargetArch::RiscV64)
);
assert_eq!(
CrossTargetArch::from_triple("wasm32-unknown-unknown"),
Some(CrossTargetArch::Wasm)
);
assert_eq!(
CrossTargetArch::from_triple("s390x-unknown-linux-gnu"),
Some(CrossTargetArch::SystemZ)
);
}
#[test]
fn test_cross_target_arch_pointer_width() {
assert_eq!(CrossTargetArch::X86_64.pointer_width(), 64);
assert_eq!(CrossTargetArch::X86.pointer_width(), 32);
assert_eq!(CrossTargetArch::Wasm.pointer_width(), 32);
assert_eq!(CrossTargetArch::AArch64.pointer_width(), 64);
}
#[test]
fn test_cross_target_os_from_triple() {
assert_eq!(
CrossTargetOS::from_triple("x86_64-unknown-linux-gnu"),
Some(CrossTargetOS::Linux)
);
assert_eq!(
CrossTargetOS::from_triple("x86_64-pc-windows-msvc"),
Some(CrossTargetOS::Windows)
);
assert_eq!(
CrossTargetOS::from_triple("x86_64-apple-darwin"),
Some(CrossTargetOS::Darwin)
);
}
#[test]
fn test_cross_compiler_target_flags() {
let cc = CrossCompiler::new("x86_64-linux-gnu", "aarch64-linux-gnu")
.with_sysroot(PathBuf::from("/sysroot/arm64"));
let flags = cc.target_compiler_flags();
assert!(flags.iter().any(|f| f.contains("aarch64")));
assert!(flags.iter().any(|f| f.contains("sysroot")));
}
#[test]
fn test_cross_compiler_validate_cross_no_sysroot() {
let cc = CrossCompiler::new("x86_64-linux-gnu", "aarch64-linux-gnu");
let result = cc.validate();
assert!(result.is_err());
}
#[test]
fn test_cross_compiler_validate_ok() {
let cc = CrossCompiler::new("x86_64-linux-gnu", "x86_64-linux-gnu");
assert!(cc.validate().is_ok());
}
#[test]
fn test_cross_compiler_from_config() {
let config = GoldenConfig {
target_triple: "aarch64-unknown-linux-gnu".into(),
sysroot: Some(PathBuf::from("/sysroot/arm64")),
..GoldenConfig::default()
};
let cc = CrossCompiler::from_config(&config);
assert_eq!(cc.target_triple, "aarch64-unknown-linux-gnu");
}
#[test]
fn test_convenience_default_compiler() {
let compiler = default_compiler();
assert_eq!(
compiler.path.config.target_triple,
"x86_64-unknown-linux-gnu"
);
}
#[test]
fn test_convenience_release_compiler() {
let compiler = release_compiler();
assert_eq!(compiler.path.config.opt_level, "2");
assert!(compiler.path.config.lto);
}
#[test]
fn test_convenience_compile_to_obj() {
let result = compile_to_obj("int main(void) { return 0; }\n");
let _ = result; }
#[test]
fn test_convenience_compile_to_asm() {
let result = compile_to_asm("int main(void) { return 42; }\n");
let _ = result;
}
#[test]
fn test_convenience_compile_to_ir() {
let result = compile_to_ir("int main(void) { return 0; }\n");
let _ = result;
}
#[test]
fn test_convenience_compile_with_config() {
let result = compile_with_config(
"int main(void) { return 0; }\n",
GoldenConfig {
syntax_only: true,
..GoldenConfig::x86_64_linux()
},
);
let _ = result;
}
#[test]
fn test_convenience_compile_cxx_to_obj() {
let result = compile_cxx_to_obj("int main() { return 0; }");
let _ = result;
}
#[test]
fn test_convenience_compile_release() {
let result = compile_release("int main(void) { return 0; }\n");
let _ = result;
}
#[test]
fn test_convenience_compile_windows() {
let result = compile_windows("int main(void) { return 0; }\n");
let _ = result;
}
#[test]
fn test_convenience_full_pipeline_compile() {
let result = full_pipeline_compile("int main(void) { return 0; }\n");
let _ = result;
}
#[test]
fn test_convenience_compiler_from_args() {
let compiler =
compiler_from_args(&["-c".into(), "-O3".into(), "-g".into(), "input.c".into()]);
assert!(compiler.path.config.compile_only);
assert_eq!(compiler.path.config.opt_level, "3");
assert!(compiler.path.config.debug_info);
}
#[test]
fn test_e2e_simple_c_program() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_e2e_simple.c");
let source = r#"
int add(int a, int b) {
return a + b;
}
int main(void) {
return add(1, 2);
}
"#;
let _ = fs::write(&tmpfile, source);
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let result = path.compile();
assert!(result.success);
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_e2e_with_defines() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_e2e_defines.c");
let source = r#"
#ifndef FOO
#error "FOO not defined"
#endif
int main(void) { return 0; }
"#;
let _ = fs::write(&tmpfile, source);
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
defines: vec![("FOO".into(), None)],
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let result = path.compile();
let _ = result;
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_e2e_cxx_program() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_e2e_cxx.cpp");
let source = "int main() { return 0; }\n";
let _ = fs::write(&tmpfile, source);
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
is_cxx: true,
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let result = path.compile();
let _ = result;
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_e2e_multiple_files() {
let tmpdir = std::env::temp_dir();
let file_a = tmpdir.join("golden_e2e_a.c");
let file_b = tmpdir.join("golden_e2e_b.c");
let _ = fs::write(
&file_a,
"int foo(void);\nint main(void) { return foo(); }\n",
);
let _ = fs::write(&file_b, "int foo(void) { return 42; }\n");
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![file_a.clone(), file_b.clone()],
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let result = path.compile();
let _ = result;
let _ = fs::remove_file(&file_a);
let _ = fs::remove_file(&file_b);
}
#[test]
fn test_e2e_all_opt_levels() {
for level in &["0", "1", "2", "3", "s", "z"] {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join(format!("golden_e2e_O{level}.c"));
let _ = fs::write(&tmpfile, "int main(void) { return 0; }\n");
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
opt_level: level.to_string(),
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let result = path.compile();
assert!(result.success, "Failed at opt level O{level}");
let _ = fs::remove_file(&tmpfile);
}
}
#[test]
fn test_e2e_all_output_formats() {
let formats = ["object", "assembly", "llvm-ir", "preprocessed"];
for fmt in &formats {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join(format!("golden_e2e_fmt_{fmt}.c"));
let _ = fs::write(&tmpfile, "int main(void) { return 0; }\n");
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
output_format: fmt.to_string(),
syntax_only: fmt == &"llvm-ir",
..GoldenConfig::x86_64_linux()
});
let _ = path.compile();
let _ = fs::remove_file(&tmpfile);
}
}
#[test]
fn test_e2e_with_sanitizers() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_e2e_san.c");
let _ = fs::write(&tmpfile, "int main(void) { return 0; }\n");
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
asan: true,
ubsan: true,
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let result = path.compile();
let _ = result;
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_e2e_with_lto() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_e2e_lto.c");
let _ = fs::write(&tmpfile, "int main(void) { return 0; }\n");
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
lto: true,
thin_lto: true,
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let result = path.compile();
let _ = result;
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_e2e_with_self_host_config() {
let config = GoldenConfig::x86_64_linux_release().with_self_host(
PathBuf::from("/tmp/llvm-native-src"),
PathBuf::from("/tmp/llvm-native-build"),
);
let mut path = GoldenPath::new(config);
assert!(path.config.self_host);
assert!(path.config.self_host_source_dir.is_some());
assert!(path.config.self_host_build_dir.is_some());
}
#[test]
fn test_integration_golden_path_with_lto_chain() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_int_lto.c");
let _ = fs::write(&tmpfile, "int main(void) { return 0; }\n");
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![tmpfile.clone()],
lto: true,
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let result = path.compile();
if result.success {
let mut lto = GoldenLTO::new(LTOConfig {
enabled: true,
thin: false,
opt_level: "2".into(),
..Default::default()
});
if let Some(ref module) = result.module {
lto.add_module(module.clone());
}
assert!(lto.modules.len() <= 1);
}
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_integration_compiler_stats_accumulation() {
let mut compiler = GoldenCompiler::new(GoldenConfig {
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
for _ in 0..3 {
let _ = compiler.compile_c_string("int main(void) { return 0; }");
}
assert_eq!(compiler.stats.total_compilations, 3);
assert!(compiler.stats.cumulative_time > Duration::ZERO);
}
#[test]
fn test_integration_cache_across_compilations() {
let cache_dir = std::env::temp_dir().join("golden_int_cache");
let config = GoldenConfig {
enable_cache: true,
cache_dir: Some(cache_dir.clone()),
syntax_only: true,
..GoldenConfig::x86_64_linux()
};
let mut compiler = GoldenCompiler::new(config);
let _ = compiler.compile_c_string("int main(void) { return 0; }");
let stats = compiler.path.cache.stats();
assert!(stats.enabled);
let _ = fs::remove_dir_all(&cache_dir);
}
#[test]
fn test_integration_benchmarks_with_compilation() {
let mut benchmarks = GoldenBenchmarks::new(BenchmarkConfig {
warmup_iterations: 1,
measurement_iterations: 2,
..Default::default()
});
benchmarks.register(GoldenBenchmark {
name: "trivial".into(),
source: "int main(void) { return 0; }\n".into(),
is_cxx: false,
expected_output: None,
min_lines: 1,
tags: vec!["micro".into()],
category: BenchmarkCategory::Micro,
});
benchmarks.run_all();
assert!(!benchmarks.results.is_empty());
}
#[test]
fn test_stress_many_input_files() {
let mut config = GoldenConfig::x86_64_linux();
for i in 0..100 {
config
.input_files
.push(PathBuf::from(format!("file_{i}.c")));
}
let path = GoldenPath::new(config);
assert_eq!(path.config.input_files.len(), 100);
}
#[test]
fn test_stress_many_defines() {
let mut config = GoldenConfig::x86_64_linux();
for i in 0..500 {
config
.defines
.push((format!("MACRO_{i}"), Some(format!("{i}"))));
}
config.input_files = vec![PathBuf::from("test.c")];
let key = config.cache_key();
assert!(!key.is_empty());
}
#[test]
fn test_stress_cache_many_entries() {
let mut cache = CompilationCache::new();
cache.set_enabled(true);
let dir = std::env::temp_dir().join("golden_stress_cache");
cache.set_cache_dir(dir.clone());
for i in 0..100 {
cache.store(&format!("key_{i}"), &vec![i as u8; 64]);
}
assert!(cache.lookup("key_0").is_some());
assert!(cache.lookup("key_50").is_some());
assert!(cache.lookup("key_99").is_some());
assert!(cache.lookup("key_100").is_none());
let _ = fs::remove_dir_all(&dir);
}
#[test]
fn test_stress_inline_function() {
let source = r#"
static inline int square(int x) { return x * x; }
int compute(int a, int b) { return square(a) + square(b); }
int main(void) { return compute(3, 4); }
"#;
let result = compile_with_config(
source,
GoldenConfig {
syntax_only: true,
opt_level: "3".into(),
..GoldenConfig::x86_64_linux()
},
);
let _ = result;
}
#[test]
fn test_self_host_run_basic() {
let tmpdir = std::env::temp_dir();
let src_dir = tmpdir.join("selfhost_src");
let build_dir = tmpdir.join("selfhost_build");
let _ = fs::create_dir_all(&src_dir);
let _ = fs::create_dir_all(&build_dir);
let _ = fs::write(src_dir.join("main.rs"), "fn main() {}");
let config = SelfHostConfig {
source_dir: src_dir.clone(),
build_dir: build_dir.clone(),
stage_count: 3,
generate_report: false,
verify_stages: false,
run_test_suite: false,
..Default::default()
};
let mut sh = GoldenSelfHost::new(config);
let result = sh.run();
assert!(result.is_ok());
let _ = fs::remove_dir_all(&src_dir);
let _ = fs::remove_dir_all(&build_dir);
}
#[test]
fn test_self_host_generate_report() {
let sh = GoldenSelfHost::new(SelfHostConfig::default());
let report = sh.generate_report(Duration::from_secs(120));
assert!(report.contains("Bootstrap Report"));
assert!(report.contains("Stage"));
}
#[test]
fn test_self_host_status_complete() {
let tmpdir = std::env::temp_dir();
let src_dir = tmpdir.join("selfhost_status_src");
let build_dir = tmpdir.join("selfhost_status_build");
let _ = fs::create_dir_all(&src_dir);
let _ = fs::create_dir_all(&build_dir);
let _ = fs::write(src_dir.join("main.rs"), "fn main() {}");
let config = SelfHostConfig {
source_dir: src_dir.clone(),
build_dir: build_dir.clone(),
generate_report: false,
verify_stages: false,
run_test_suite: false,
..Default::default()
};
let mut sh = GoldenSelfHost::new(config);
let _ = sh.run();
assert!(sh.complete);
assert!(!sh.status().contains("not started"));
let _ = fs::remove_dir_all(&src_dir);
let _ = fs::remove_dir_all(&build_dir);
}
#[test]
fn test_golden_stage_result() {
let sr = GoldenStageResult {
stage: "parse".into(),
success: true,
duration: Duration::from_millis(42),
output_data: None,
errors: vec![],
warnings: vec![],
};
assert_eq!(sr.stage, "parse");
assert!(sr.success);
}
#[test]
fn test_golden_result_fields() {
let result = GoldenResult {
success: true,
completed_stage: Some("emit".into()),
failed_stage: None,
text_output: None,
binary_output: None,
output_file: Some(PathBuf::from("out.o")),
module: None,
metrics: GoldenMetrics::default(),
error_count: 0,
warning_count: 0,
stage_results: Vec::new(),
};
assert!(result.success);
assert_eq!(result.completed_stage, Some("emit".into()));
}
#[test]
fn test_diagnostics_new() {
let diags = GoldenDiagnostics::new(DiagnosticConfig::default());
assert!(!diags.has_errors());
assert!(!diags.has_warnings());
assert_eq!(diags.error_count(), 0);
assert_eq!(diags.warning_count(), 0);
}
#[test]
fn test_diagnostics_error_tracking() {
let mut diags = GoldenDiagnostics::new(DiagnosticConfig::default());
diags.error("parse", "unexpected token");
assert!(diags.has_errors());
assert_eq!(diags.error_count(), 1);
assert_eq!(
diags.error_tracker.stage_errors.get("parse").unwrap().len(),
1
);
}
#[test]
fn test_diagnostics_warning_tracking() {
let mut diags = GoldenDiagnostics::new(DiagnosticConfig::default());
diags.warning("sema", "unused variable");
assert!(diags.has_warnings());
assert_eq!(diags.warning_count(), 1);
}
#[test]
fn test_diagnostics_warnings_as_errors() {
let mut diags = GoldenDiagnostics::new(DiagnosticConfig {
warnings_as_errors: true,
..Default::default()
});
diags.warning("sema", "unused variable");
assert!(diags.has_errors());
}
#[test]
fn test_diagnostics_error_limit() {
let mut diags = GoldenDiagnostics::new(DiagnosticConfig {
error_limit: 3,
..Default::default()
});
diags.error("parse", "err1");
diags.error("parse", "err2");
diags.error("parse", "err3");
diags.error("parse", "err4"); assert_eq!(diags.error_count(), 3);
assert!(diags.error_tracker.limit_reached);
}
#[test]
fn test_diagnostics_warning_limit() {
let mut diags = GoldenDiagnostics::new(DiagnosticConfig {
warning_limit: 2,
..Default::default()
});
diags.warning("sema", "w1");
diags.warning("sema", "w2");
diags.warning("sema", "w3");
assert_eq!(diags.warning_count(), 2);
}
#[test]
fn test_diagnostics_note() {
let mut diags = GoldenDiagnostics::new(DiagnosticConfig::default());
diags.note("previous declaration here");
assert_eq!(diags.notes.len(), 1);
assert_eq!(diags.notes[0].message, "previous declaration here");
}
#[test]
fn test_diagnostics_fixit() {
let mut diags = GoldenDiagnostics::new(DiagnosticConfig::default());
let range = GoldenSourceRange {
start: GoldenSourceLocation {
file: "test.c".into(),
line: 1,
column: 5,
offset: 4,
},
end: GoldenSourceLocation {
file: "test.c".into(),
line: 1,
column: 5,
offset: 4,
},
};
diags.fixit(range, ";", Some("insert semicolon"));
assert_eq!(diags.fixits.len(), 1);
assert_eq!(diags.fixits[0].replacement, ";");
}
#[test]
fn test_diagnostics_clear() {
let mut diags = GoldenDiagnostics::new(DiagnosticConfig::default());
diags.error("parse", "err");
diags.warning("sema", "warn");
diags.note("note");
diags.clear();
assert!(!diags.has_errors());
assert!(!diags.has_warnings());
assert!(diags.notes.is_empty());
assert!(diags.fixits.is_empty());
}
#[test]
fn test_diagnostics_format_clang() {
let diags = GoldenDiagnostics::new(DiagnosticConfig {
format: DiagnosticOutputFormat::Clang,
..Default::default()
});
let loc = GoldenSourceLocation {
file: "test.c".into(),
line: 10,
column: 5,
offset: 42,
};
let msg = diags.format_diagnostic(GoldenDiagSeverity::Error, Some(&loc), "syntax error");
assert!(msg.contains("test.c:10:5"));
assert!(msg.contains("error"));
}
#[test]
fn test_diagnostics_format_gcc() {
let diags = GoldenDiagnostics::new(DiagnosticConfig {
format: DiagnosticOutputFormat::GCC,
..Default::default()
});
let loc = GoldenSourceLocation {
file: "test.c".into(),
line: 5,
column: 1,
offset: 10,
};
let msg = diags.format_diagnostic(
GoldenDiagSeverity::Warning,
Some(&loc),
"implicit declaration",
);
assert!(msg.contains("test.c:5:1"));
assert!(msg.contains("warning"));
}
#[test]
fn test_diagnostics_format_msvc() {
let diags = GoldenDiagnostics::new(DiagnosticConfig {
format: DiagnosticOutputFormat::MSVC,
..Default::default()
});
let loc = GoldenSourceLocation {
file: "test.cpp".into(),
line: 3,
column: 10,
offset: 25,
};
let msg = diags.format_diagnostic(
GoldenDiagSeverity::Error,
Some(&loc),
"undeclared identifier",
);
assert!(msg.contains("test.cpp(3,10)"));
}
#[test]
fn test_diagnostics_format_json() {
let diags = GoldenDiagnostics::new(DiagnosticConfig {
format: DiagnosticOutputFormat::JSON,
..Default::default()
});
let loc = GoldenSourceLocation {
file: "x.c".into(),
line: 1,
column: 1,
offset: 0,
};
let msg = diags.format_diagnostic(GoldenDiagSeverity::Error, Some(&loc), "err");
assert!(msg.starts_with('{'));
assert!(msg.contains("Error"));
}
#[test]
fn test_diagnostics_suppress_warning_group() {
let mut diags = GoldenDiagnostics::new(DiagnosticConfig::default());
diags.suppress_warning_group("unused-variable");
assert!(diags
.warning_tracker
.suppressed_groups
.contains("unused-variable"));
}
#[test]
fn test_diagnostics_error_warning_group() {
let mut diags = GoldenDiagnostics::new(DiagnosticConfig::default());
diags.error_warning_group("deprecated");
assert!(diags.warning_tracker.error_groups.contains("deprecated"));
}
#[test]
fn test_diagnostics_summary_report() {
let mut diags = GoldenDiagnostics::new(DiagnosticConfig::default());
diags.error("parse", "err");
diags.warning("sema", "warn");
let report = diags.summary_report();
assert!(report.contains("Errors: 1"));
assert!(report.contains("Warnings: 1"));
}
#[test]
fn test_diagnostics_to_sarif() {
let diags = GoldenDiagnostics::new(DiagnosticConfig::default());
let sarif = diags.to_sarif();
assert!(sarif.contains("sarif"));
assert!(sarif.contains("version"));
}
#[test]
fn test_diag_severity_ordering() {
assert!(GoldenDiagSeverity::Error > GoldenDiagSeverity::Warning);
assert!(GoldenDiagSeverity::Warning > GoldenDiagSeverity::Note);
assert!(GoldenDiagSeverity::Fatal > GoldenDiagSeverity::Error);
}
#[test]
fn test_diagnostic_config_default() {
let config = DiagnosticConfig::default();
assert_eq!(config.error_limit, 20);
assert_eq!(config.warning_limit, 100);
assert!(!config.warnings_as_errors);
assert!(config.show_snippets);
assert_eq!(config.tab_stop, 8);
}
#[test]
fn test_verifier_new() {
let verifier = GoldenVerifier::new(false);
assert_eq!(verifier.total_checks, 0);
assert_eq!(verifier.total_passed, 0);
assert_eq!(verifier.total_failed, 0);
assert!(!verifier.abort_on_error);
}
#[test]
fn test_verifier_report_empty() {
let verifier = GoldenVerifier::new(false);
let report = verifier.report();
assert!(report.contains("Total: 0"));
}
#[test]
fn test_verifier_all_passed_empty() {
let verifier = GoldenVerifier::new(false);
assert!(verifier.all_passed());
}
#[test]
fn test_verifier_reset() {
let mut verifier = GoldenVerifier::new(false);
verifier.total_checks = 5;
verifier.total_passed = 3;
verifier.total_failed = 2;
verifier.reset();
assert_eq!(verifier.total_checks, 0);
assert!(verifier.all_passed());
}
#[test]
fn test_verification_category_as_str() {
assert_eq!(VerificationCategory::IR.as_str(), "ir");
assert_eq!(VerificationCategory::Machine.as_str(), "machine");
assert_eq!(VerificationCategory::ABI.as_str(), "abi");
assert_eq!(VerificationCategory::Security.as_str(), "security");
assert_eq!(VerificationCategory::Performance.as_str(), "performance");
assert_eq!(VerificationCategory::Compliance.as_str(), "compliance");
}
#[test]
fn test_verification_record() {
let record = VerificationRecord {
check_name: "test_check".into(),
category: VerificationCategory::IR,
passed: true,
error: None,
duration: Duration::from_millis(10),
};
assert!(record.passed);
assert_eq!(record.category, VerificationCategory::IR);
}
#[test]
fn test_profiler_new_disabled() {
let profiler = GoldenProfiler::new(false);
assert!(!profiler.enabled);
assert!(profiler.records.is_empty());
}
#[test]
fn test_profiler_new_enabled() {
let profiler = GoldenProfiler::new(true);
assert!(profiler.enabled);
assert!(profiler.start_time.is_some());
}
#[test]
fn test_profiler_begin_end_span() {
let mut profiler = GoldenProfiler::new(true);
profiler.begin_span("lex");
std::thread::sleep(Duration::from_millis(1));
profiler.end_span("lex", ProfileCategory::Frontend, 100);
assert_eq!(profiler.records.len(), 1);
assert_eq!(profiler.records[0].name, "lex");
assert!(profiler.records[0].duration > Duration::ZERO);
}
#[test]
fn test_profiler_disabled_does_nothing() {
let mut profiler = GoldenProfiler::new(false);
profiler.begin_span("test");
profiler.end_span("test", ProfileCategory::Other, 0);
assert!(profiler.records.is_empty());
}
#[test]
fn test_profiler_increment_counter() {
let mut profiler = GoldenProfiler::new(true);
profiler.increment_counter("functions_compiled");
profiler.increment_counter("functions_compiled");
assert_eq!(profiler.event_counters.get("functions_compiled"), Some(&2));
}
#[test]
fn test_profiler_report() {
let mut profiler = GoldenProfiler::new(true);
profiler.begin_span("stage1");
profiler.end_span("stage1", ProfileCategory::Frontend, 42);
let report = profiler.report();
assert!(report.contains("stage1"));
assert!(report.contains("42"));
}
#[test]
fn test_profiler_report_disabled() {
let profiler = GoldenProfiler::new(false);
let report = profiler.report();
assert!(report.contains("disabled"));
}
#[test]
fn test_profiler_chrome_trace() {
let mut profiler = GoldenProfiler::new(true);
profiler.begin_span("task");
profiler.end_span("task", ProfileCategory::Backend, 1);
let trace = profiler.chrome_trace();
assert!(trace.contains("\"name\":\"task\""));
}
#[test]
fn test_profiler_flamegraph() {
let mut profiler = GoldenProfiler::new(true);
profiler.begin_span("backend;isel");
profiler.end_span("backend;isel", ProfileCategory::Backend, 1);
let fg = profiler.flamegraph();
assert!(fg.contains("backend;isel"));
}
#[test]
fn test_profiler_reset() {
let mut profiler = GoldenProfiler::new(true);
profiler.begin_span("test");
profiler.end_span("test", ProfileCategory::Other, 0);
profiler.increment_counter("c");
profiler.reset();
assert!(profiler.records.is_empty());
assert!(profiler.event_counters.is_empty());
}
#[test]
fn test_profile_category_as_str() {
assert_eq!(ProfileCategory::Frontend.as_str(), "frontend");
assert_eq!(ProfileCategory::Backend.as_str(), "backend");
assert_eq!(ProfileCategory::Optimization.as_str(), "optimization");
assert_eq!(ProfileCategory::Linking.as_str(), "linking");
assert_eq!(ProfileCategory::IO.as_str(), "io");
assert_eq!(ProfileCategory::Memory.as_str(), "memory");
assert_eq!(ProfileCategory::Other.as_str(), "other");
}
#[test]
fn test_orchestrator_new() {
let orch =
GoldenOrchestrator::new(GoldenConfig::x86_64_linux(), OrchestrationMode::Compile);
assert!(!orch.executed);
assert_eq!(orch.mode, OrchestrationMode::Compile);
}
#[test]
fn test_orchestrator_execute_compile() {
let config = GoldenConfig {
input_files: vec![PathBuf::from("test.c")],
syntax_only: true,
..GoldenConfig::x86_64_linux()
};
let mut orch = GoldenOrchestrator::new(config, OrchestrationMode::Compile);
let result = orch.execute();
assert!(orch.executed);
let _ = result;
}
#[test]
fn test_orchestrator_status_not_run() {
let orch = GoldenOrchestrator::new(GoldenConfig::default(), OrchestrationMode::Compile);
assert!(orch.status().contains("not run"));
}
#[test]
fn test_orchestrator_report() {
let orch =
GoldenOrchestrator::new(GoldenConfig::x86_64_linux(), OrchestrationMode::Compile);
let report = orch.report();
assert!(report.contains("Orchestrator"));
}
#[test]
fn test_orchestration_mode_all_variants() {
let modes = [
OrchestrationMode::Compile,
OrchestrationMode::CompileAndLink,
OrchestrationMode::CompileLinkTest,
OrchestrationMode::Bootstrap,
OrchestrationMode::Benchmark,
OrchestrationMode::Test,
OrchestrationMode::Analyze,
];
for mode in &modes {
let s = mode.as_str();
assert!(!s.is_empty());
}
}
#[test]
fn test_orchestration_result_creation() {
let result = OrchestrationResult {
success: true,
mode: OrchestrationMode::Compile,
total_duration: Duration::from_secs(1),
compilation_result: None,
lto_result: None,
self_host_complete: None,
test_results_summary: None,
profiling_report: None,
verification_report: None,
};
assert!(result.success);
}
#[test]
fn test_fingerprint_compute() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_fp_test.c");
let _ = fs::write(&tmpfile, "int main(void) { return 0; }\n");
let fp = ModuleFingerprint::compute(&tmpfile, &GoldenConfig::x86_64_linux());
assert!(fp.is_ok());
let fp = fp.unwrap();
assert!(!fp.to_hex().is_empty());
assert_eq!(fp.compiler_version, env!("CARGO_PKG_VERSION"));
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_fingerprint_matches() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_fp_match.c");
let _ = fs::write(&tmpfile, "int x;\n");
let fp1 = ModuleFingerprint::compute(&tmpfile, &GoldenConfig::x86_64_linux()).unwrap();
let fp2 = ModuleFingerprint::compute(&tmpfile, &GoldenConfig::x86_64_linux()).unwrap();
assert!(fp1.matches(&fp2));
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_fingerprint_to_hex() {
let tmpdir = std::env::temp_dir();
let tmpfile = tmpdir.join("golden_fp_hex.c");
let _ = fs::write(&tmpfile, "int main() {}\n");
let fp = ModuleFingerprint::compute(&tmpfile, &GoldenConfig::x86_64_linux()).unwrap();
let hex = fp.to_hex();
assert_eq!(hex.len(), 64);
assert!(hex.chars().all(|c| c.is_ascii_hexdigit()));
let _ = fs::remove_file(&tmpfile);
}
#[test]
fn test_parallel_manager_new() {
let mgr = ParallelCompilationManager::new(vec![], 4);
assert_eq!(mgr.worker_count, 4);
assert!(mgr.jobs.is_empty());
}
#[test]
fn test_parallel_manager_progress_zero() {
let mgr = ParallelCompilationManager::new(vec![], 2);
assert!((mgr.progress_fraction() - 1.0).abs() < f64::EPSILON);
}
#[test]
fn test_parallel_manager_all_succeeded_empty() {
let mgr = ParallelCompilationManager::new(vec![], 2);
assert!(mgr.all_succeeded());
}
#[test]
fn test_compilation_db_new() {
let db = CompilationDatabase::new(PathBuf::from("/build"));
assert!(db.is_empty());
assert_eq!(db.len(), 0);
}
#[test]
fn test_compilation_db_add() {
let mut db = CompilationDatabase::new(PathBuf::from("/src"));
db.add(CompilationCommand {
file: PathBuf::from("main.c"),
directory: PathBuf::from("/src"),
arguments: vec!["cc".into(), "-c".into(), "main.c".into()],
output: Some(PathBuf::from("main.o")),
});
assert_eq!(db.len(), 1);
}
#[test]
fn test_compilation_db_to_json() {
let mut db = CompilationDatabase::new(PathBuf::from("/proj"));
db.add(CompilationCommand {
file: PathBuf::from("main.c"),
directory: PathBuf::from("/proj"),
arguments: vec!["cc".into(), "main.c".into()],
output: None,
});
let json = db.to_json();
assert!(json.contains("main.c"));
assert!(json.contains("/proj"));
assert!(json.starts_with('['));
}
#[test]
fn test_compilation_db_find() {
let mut db = CompilationDatabase::new(PathBuf::from("."));
db.add(CompilationCommand {
file: PathBuf::from("a.c"),
directory: PathBuf::from("."),
arguments: vec!["cc".into(), "a.c".into()],
output: None,
});
db.add(CompilationCommand {
file: PathBuf::from("b.c"),
directory: PathBuf::from("."),
arguments: vec!["cc".into(), "b.c".into()],
output: None,
});
let found = db.find(Path::new("a.c"));
assert_eq!(found.len(), 1);
}
#[test]
fn test_compilation_db_source_files() {
let mut db = CompilationDatabase::new(PathBuf::from("."));
db.add(CompilationCommand {
file: PathBuf::from("a.c"),
directory: PathBuf::from("."),
arguments: vec!["cc".into()],
output: None,
});
db.add(CompilationCommand {
file: PathBuf::from("b.c"),
directory: PathBuf::from("."),
arguments: vec!["cc".into()],
output: None,
});
let files = db.source_files();
assert_eq!(files.len(), 2);
}
#[test]
fn test_batch_compile_empty() {
let tmpdir = std::env::temp_dir();
let outdir = tmpdir.join("golden_batch_out");
let results = batch_compile(&[], &outdir);
assert!(results.is_empty());
let _ = fs::remove_dir_all(&outdir);
}
#[test]
fn test_compile_with_profiling_api() {
let (result, profiler) = compile_with_profiling("int main(void) { return 0; }\n");
let _ = result;
assert!(profiler.enabled);
}
#[test]
fn test_compile_with_verification_api() {
let (result, verifier) = compile_with_verification("int main(void) { return 0; }\n");
let _ = result;
let _ = verifier;
}
#[test]
fn test_compile_with_diagnostics_api() {
let (result, diagnostics) = compile_with_diagnostics("int main(void) { return 0; }\n");
let _ = result;
let _ = diagnostics;
}
#[test]
fn test_generate_toolchain_report() {
let report = generate_toolchain_report(&GoldenConfig::x86_64_linux_release());
assert!(report.contains("Toolchain"));
assert!(report.contains("Host triple"));
}
#[test]
fn test_compile_to_all_formats() {
let result = compile_to_all_formats("int main(void) { return 0; }\n");
let _ = result;
}
#[test]
fn test_thread_safe_path_new() {
let path = GoldenPathThreadSafe::new(GoldenConfig::x86_64_linux());
let config = path.config();
assert_eq!(config.target_triple, "x86_64-unknown-linux-gnu");
}
#[test]
fn test_thread_safe_path_clone() {
let path = GoldenPathThreadSafe::new(GoldenConfig::x86_64_linux());
let clone = path.clone();
let config = clone.config();
assert_eq!(config.target_triple, "x86_64-unknown-linux-gnu");
}
#[test]
fn test_dependency_tracker_new() {
let tracker = DependencyTracker::new();
assert!(!tracker.active);
assert!(tracker.dependencies.is_empty());
}
#[test]
fn test_dependency_tracker_record() {
let mut tracker = DependencyTracker::new();
tracker.start();
tracker.record_dependency(Path::new("src/main.c"), Path::new("include/header.h"));
assert_eq!(tracker.dependencies_of(Path::new("src/main.c")).len(), 1);
assert_eq!(
tracker.files_including(Path::new("include/header.h")).len(),
1
);
}
#[test]
fn test_dependency_tracker_mark_modified() {
let mut tracker = DependencyTracker::new();
tracker.start();
tracker.record_dependency(Path::new("main.c"), Path::new("header.h"));
tracker.mark_modified(Path::new("header.h"));
let needs_rebuild = tracker.files_needing_recompilation();
assert!(needs_rebuild.contains(Path::new("main.c")));
}
#[test]
fn test_dependency_tracker_clear() {
let mut tracker = DependencyTracker::new();
tracker.start();
tracker.record_dependency(Path::new("a.c"), Path::new("h.h"));
tracker.clear();
assert!(tracker.dependencies.is_empty());
}
#[test]
fn test_dependency_tracker_makefile_dep() {
let mut tracker = DependencyTracker::new();
tracker.start();
tracker.record_dependency(Path::new("main.c"), Path::new("header.h"));
let dep = tracker.generate_makefile_dep(Path::new("main.c"));
assert!(dep.contains("main.c"));
assert!(dep.contains("header.h"));
}
#[test]
fn test_dependency_tracker_stats() {
let mut tracker = DependencyTracker::new();
tracker.start();
tracker.record_dependency(Path::new("a.c"), Path::new("x.h"));
tracker.record_dependency(Path::new("b.c"), Path::new("y.h"));
let stats = tracker.stats();
assert_eq!(stats.total_source_files, 2);
assert_eq!(stats.total_dependencies, 2);
assert_eq!(stats.unique_headers, 2);
}
#[test]
fn test_dependency_tracker_diamond_deps() {
let mut tracker = DependencyTracker::new();
tracker.start();
tracker.record_dependency(Path::new("a.c"), Path::new("common.h"));
tracker.record_dependency(Path::new("b.c"), Path::new("common.h"));
assert_eq!(tracker.files_including(Path::new("common.h")).len(), 2);
tracker.mark_modified(Path::new("common.h"));
assert_eq!(tracker.files_needing_recompilation().len(), 2);
}
#[test]
fn test_sanitizer_config_default() {
let config = GoldenSanitizerConfig::default();
assert!(!config.has_any());
}
#[test]
fn test_sanitizer_config_asan() {
let mut config = GoldenSanitizerConfig::default();
config.address = true;
assert!(config.has_any());
}
#[test]
fn test_sanitizer_asan_tsan_incompatible() {
let config = GoldenSanitizerConfig {
address: true,
thread: true,
..Default::default()
};
assert!(!config.check_compatibility().is_empty());
}
#[test]
fn test_sanitizer_compatibility_ok() {
let config = GoldenSanitizerConfig::default();
assert!(config.check_compatibility().is_empty());
}
#[test]
fn test_sanitizer_compiler_flags() {
let config = GoldenSanitizerConfig {
address: true,
undefined: true,
..Default::default()
};
let flags = config.compiler_flags();
assert!(flags.iter().any(|f| f.contains("address")));
assert!(flags.iter().any(|f| f.contains("undefined")));
}
#[test]
fn test_sanitizer_linker_libraries() {
let config = GoldenSanitizerConfig {
address: true,
..Default::default()
};
let libs = config.linker_libraries();
assert!(libs.contains(&"asan".to_string()));
}
#[test]
fn test_sanitizer_from_golden_config() {
let golden = GoldenConfig {
asan: true,
ubsan: true,
..GoldenConfig::default()
};
let san = GoldenSanitizerConfig::from_golden_config(&golden);
assert!(san.address);
assert!(san.undefined);
}
#[test]
fn test_sanitizer_summary() {
let config = GoldenSanitizerConfig {
address: true,
undefined: true,
..Default::default()
};
let s = config.summary();
assert!(s.contains("ASan"));
assert!(s.contains("UBSan"));
}
#[test]
fn test_coverage_default_inactive() {
assert!(!GoldenCoverage::default().is_active());
}
#[test]
fn test_coverage_active() {
let cov = GoldenCoverage {
coverage_mapping: true,
..Default::default()
};
assert!(cov.is_active());
}
#[test]
fn test_coverage_compiler_flags() {
let cov = GoldenCoverage {
coverage_mapping: true,
function_sections: true,
..Default::default()
};
let flags = cov.compiler_flags();
assert!(!flags.is_empty());
}
#[test]
fn test_pgo_profile_empty() {
let p = PGOProfile::empty();
assert_eq!(p.total_entries, 0);
assert_eq!(p.function_count("main"), 0);
}
#[test]
fn test_pgo_profile_record() {
let mut p = PGOProfile::empty();
p.record_function("main", 100);
assert_eq!(p.function_count("main"), 100);
assert_eq!(p.total_entries, 1);
}
#[test]
fn test_pgo_profile_hotness() {
let mut p = PGOProfile::empty();
p.record_function("hot", 1000);
p.record_function("cold", 10);
assert_eq!(p.function_hotness("hot"), 100);
assert!(p.function_hotness("cold") < 10);
}
#[test]
fn test_pgo_profile_is_hot() {
let mut p = PGOProfile::empty();
p.record_function("hot", 100);
p.record_function("cold", 1);
assert!(p.is_hot("hot"));
assert!(!p.is_hot("cold"));
}
#[test]
fn test_pgo_summary() {
let pgo = GoldenPGO::new(PGOConfig {
enabled: true,
generate: true,
..Default::default()
});
assert!(pgo.summary().contains("generating"));
}
#[test]
fn test_edge_empty_switch() {
let r = compile_to_ir("int f(int x) { switch(x) {} return 0; }");
let _ = r;
}
#[test]
fn test_edge_max_includes() {
let mut config = GoldenConfig::x86_64_linux();
for i in 0..100 {
config
.includes
.push(PathBuf::from(format!("/inc/path_{i}")));
}
config.input_files = vec![PathBuf::from("test.c")];
assert_eq!(config.includes.len(), 100);
}
#[test]
fn test_self_host_double_run() {
let tmpdir = std::env::temp_dir();
let src = tmpdir.join("dr_src");
let build = tmpdir.join("dr_build");
let _ = fs::create_dir_all(&src);
let _ = fs::create_dir_all(&build);
let _ = fs::write(src.join("main.rs"), "fn main() {}");
let config = SelfHostConfig {
source_dir: src.clone(),
build_dir: build.clone(),
generate_report: false,
verify_stages: false,
run_test_suite: false,
..Default::default()
};
let mut sh = GoldenSelfHost::new(config);
let _ = sh.run();
let r2 = sh.run();
assert!(r2.is_ok());
let _ = fs::remove_dir_all(&src);
let _ = fs::remove_dir_all(&build);
}
#[test]
fn test_all_output_formats_valid() {
for fmt in &["object", "assembly", "llvm-ir", "preprocessed"] {
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![PathBuf::from("test.c")],
output_format: fmt.to_string(),
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let _ = path.compile();
}
}
#[test]
fn test_oracle_lexer_keyword_roundtrip() {
let keywords = [
"int", "void", "return", "if", "else", "while", "for", "struct", "enum", "union",
"typedef", "sizeof", "static", "extern", "const", "volatile", "register", "auto",
"unsigned", "signed", "char", "short", "long", "float", "double",
];
for kw in &keywords {
let source = format!("{kw} main(void) {{ return 0; }}\n");
let result = compile_to_ir(&source);
let _ = result;
}
}
#[test]
fn test_oracle_integer_literals() {
let types = ["int", "unsigned", "long", "unsigned long", "long long"];
for t in &types {
let source = format!("{t} x = 42; int main(void) {{ return (int)x; }}\n");
let result = compile_to_ir(&source);
let _ = result;
}
}
#[test]
fn test_oracle_control_flow() {
let programs = [
("if", "int f(int x) { if (x > 0) return 1; return 0; }"),
("while", "int f(int n) { int s = 0; while (n > 0) { s += n; n--; } return s; }"),
("for", "int f(int n) { int s = 0; for (int i = 0; i < n; i++) s += i; return s; }"),
("do_while", "int f(int n) { int s = 0; do { s += n; n--; } while (n > 0); return s; }"),
("switch", "int f(int x) { switch(x) { case 0: return 1; case 1: return 2; default: return 0; } }"),
];
for (name, prog) in &programs {
let source = format!("{prog}\nint main(void) {{ return f(5); }}\n");
let result = compile_to_ir(&source);
assert!(
result.is_some(),
"Oracle test '{name}' should compile: {prog}"
);
}
}
#[test]
fn test_oracle_struct_typedef() {
let source = r#"
struct Point { int x; int y; };
typedef struct Point Point;
int origin_x(void) {
Point p = {0, 0};
return p.x;
}
int main(void) { return origin_x(); }
"#;
let result = compile_to_ir(source);
let _ = result;
}
#[test]
fn test_oracle_nested_structs() {
let source = r#"
struct Inner { int a; int b; };
struct Outer { struct Inner in; int c; };
int sum(struct Outer o) { return o.in.a + o.in.b + o.c; }
int main(void) {
struct Outer o = {{1, 2}, 3};
return sum(o);
}
"#;
let result = compile_to_ir(source);
let _ = result;
}
#[test]
fn test_oracle_recursive_function() {
let source = r#"
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
int main(void) { return factorial(5); }
"#;
let result = compile_to_ir(source);
let _ = result;
}
#[test]
fn test_oracle_function_pointer() {
let source = r#"
typedef int (*op_t)(int, int);
int add(int a, int b) { return a + b; }
int mul(int a, int b) { return a * b; }
int apply(op_t op, int a, int b) { return op(a, b); }
int main(void) { return apply(add, 3, 4) + apply(mul, 2, 5); }
"#;
let result = compile_to_ir(source);
let _ = result;
}
#[test]
fn test_oracle_array_operations() {
let source = r#"
int sum_array(int arr[], int len) {
int s = 0;
for (int i = 0; i < len; i++) s += arr[i];
return s;
}
int main(void) {
int a[5] = {1, 2, 3, 4, 5};
return sum_array(a, 5);
}
"#;
let result = compile_to_ir(source);
let _ = result;
}
#[test]
fn test_oracle_bitwise_ops() {
let source = r#"
unsigned int and(unsigned int a, unsigned int b) { return a & b; }
unsigned int or(unsigned int a, unsigned int b) { return a | b; }
unsigned int xor(unsigned int a, unsigned int b) { return a ^ b; }
unsigned int shl(unsigned int a, unsigned int b) { return a << b; }
unsigned int shr(unsigned int a, unsigned int b) { return a >> b; }
unsigned int not(unsigned int a) { return ~a; }
int main(void) { return (int)(and(0xFF, 0x0F) + or(0xF0, 0x0F)); }
"#;
let result = compile_to_ir(source);
let _ = result;
}
#[test]
fn test_oracle_preprocessor_defines() {
let source = r#"
#define MAGIC 42
#define ADD(a,b) ((a)+(b))
#ifndef MAGIC
#error "MAGIC not defined"
#endif
int main(void) { return MAGIC + ADD(1, 2); }
"#;
let result = compile_with_config(
source,
GoldenConfig {
syntax_only: true,
..GoldenConfig::x86_64_linux()
},
);
let _ = result;
}
#[test]
fn test_oracle_static_var() {
let source = r#"
int counter(void) {
static int count = 0;
return ++count;
}
int main(void) {
int a = counter();
int b = counter();
return a + b;
}
"#;
let result = compile_to_ir(source);
let _ = result;
}
#[test]
fn test_oracle_goto_label() {
let source = r#"
int find(int x, int n, int arr[]) {
int i = 0;
loop:
if (i >= n) goto not_found;
if (arr[i] == x) goto found;
i++;
goto loop;
found:
return i;
not_found:
return -1;
}
int main(void) {
int a[3] = {10, 20, 30};
return find(20, 3, a);
}
"#;
let result = compile_to_ir(source);
let _ = result;
}
#[test]
fn test_oracle_varargs() {
let source = r#"
#include <stdarg.h>
int sum(int n, ...) {
va_list args;
va_start(args, n);
int s = 0;
for (int i = 0; i < n; i++) s += va_arg(args, int);
va_end(args);
return s;
}
"#;
let result = compile_to_ir(source);
let _ = result;
}
#[test]
fn test_stress_concurrent_compilations() {
use std::sync::Arc;
use std::sync::Barrier;
let configs: Vec<GoldenConfig> = (0..4)
.map(|i| GoldenConfig {
input_files: vec![PathBuf::from(format!("file_{i}.c"))],
syntax_only: true,
..GoldenConfig::x86_64_linux()
})
.collect();
let barrier = Arc::new(Barrier::new(4));
let results = Arc::new(Mutex::new(Vec::new()));
let mut handles = Vec::new();
for config in configs {
let barrier = Arc::clone(&barrier);
let results = Arc::clone(&results);
handles.push(std::thread::spawn(move || {
barrier.wait();
let mut path = GoldenPath::new(config);
let result = path.compile();
results.lock().unwrap().push(result.success);
}));
}
for h in handles {
let _ = h.join();
}
let _ = results.lock().unwrap();
}
#[test]
fn test_stress_compile_many_parallel() {
let manager_config = GoldenConfig {
syntax_only: true,
..GoldenConfig::x86_64_linux()
};
let jobs: Vec<ParallelCompilationJob> = (0..8)
.map(|i| ParallelCompilationJob {
source_file: PathBuf::from(format!("test_{i}.c")),
config: manager_config.clone(),
id: i,
is_cxx: false,
dependencies: vec![],
})
.collect();
let mut mgr = ParallelCompilationManager::new(jobs, 4);
let results = mgr.run();
assert_eq!(results.len(), 8);
assert!(mgr.complete.load(Ordering::SeqCst));
}
#[test]
fn test_verifier_empty_module() {
let mut verifier = GoldenVerifier::new(false);
assert!(verifier.all_passed());
let report = verifier.report();
assert!(report.contains("Passed: 0"));
}
#[test]
fn test_verifier_reset_clears_all() {
let mut verifier = GoldenVerifier::new(false);
verifier.total_checks = 10;
verifier.total_passed = 8;
verifier.total_failed = 2;
verifier.reset();
assert_eq!(verifier.total_checks, 0);
assert_eq!(verifier.total_failed, 0);
}
#[test]
fn test_verifier_abort_on_error() {
let mut verifier = GoldenVerifier::new(false);
verifier.abort_on_error = true;
assert!(verifier.abort_on_error);
}
#[test]
fn test_profiler_nested_spans() {
let mut profiler = GoldenProfiler::new(true);
profiler.begin_span("outer");
profiler.begin_span("inner");
std::thread::sleep(Duration::from_micros(100));
profiler.end_span("inner", ProfileCategory::Backend, 1);
profiler.end_span("outer", ProfileCategory::Frontend, 100);
assert_eq!(profiler.records.len(), 2);
}
#[test]
fn test_profiler_many_counters() {
let mut profiler = GoldenProfiler::new(true);
for i in 0..100 {
profiler.increment_counter(&format!("event_{i}"));
}
assert_eq!(profiler.event_counters.len(), 100);
}
#[test]
fn test_profiler_reset_preserves_enabled() {
let mut profiler = GoldenProfiler::new(true);
profiler.increment_counter("x");
profiler.reset();
assert!(profiler.enabled);
assert!(profiler.event_counters.is_empty());
}
#[test]
fn test_cross_all_known_triples() {
let triples = [
"x86_64-unknown-linux-gnu",
"i386-unknown-linux-gnu",
"aarch64-unknown-linux-gnu",
"arm-unknown-linux-gnueabi",
"riscv64-unknown-elf",
"wasm32-unknown-unknown",
];
for triple in &triples {
let cc = CrossCompiler::new("x86_64-unknown-linux-gnu", triple);
let _ = cc;
assert!(
CrossTargetArch::from_triple(triple).is_some(),
"Failed to parse arch from triple: {triple}"
);
}
}
#[test]
fn test_cross_pointer_widths() {
assert_eq!(CrossTargetArch::X86_64.pointer_width(), 64);
assert_eq!(CrossTargetArch::AArch64.pointer_width(), 64);
assert_eq!(CrossTargetArch::X86.pointer_width(), 32);
assert_eq!(CrossTargetArch::RiscV32.pointer_width(), 32);
assert_eq!(CrossTargetArch::RiscV64.pointer_width(), 64);
}
#[test]
fn test_cross_validate_with_sysroot() {
let cc = CrossCompiler::new("x86_64-linux", "aarch64-linux")
.with_sysroot(PathBuf::from("/opt/aarch64-sysroot"));
assert!(cc.validate().is_ok());
}
#[test]
fn test_smoke_compile_empty_to_all_fmts() {
let formats = ["object", "assembly", "llvm-ir"];
for fmt in &formats {
let mut path = GoldenPath::new(GoldenConfig {
input_files: vec![PathBuf::from("smoke.c")],
output_format: fmt.to_string(),
syntax_only: true,
..GoldenConfig::x86_64_linux()
});
let _ = path.compile();
}
}
#[test]
fn test_smoke_compile_minimal_to_asm() {
let result = compile_to_asm("int main(void) { return 0; }\n");
let _ = result;
}
#[test]
fn test_smoke_compile_cxx_to_obj() {
let result =
compile_cxx_to_obj("struct A { int x; }; int main() { A a; a.x = 1; return a.x; }");
let _ = result;
}
#[test]
fn test_smoke_full_pipeline() {
let result = full_pipeline_compile("int main(void) { return 42; }\n");
let _ = result;
}
#[test]
fn test_smoke_golden_orchestrator_compile() {
let config = GoldenConfig {
input_files: vec![PathBuf::from("test.c")],
syntax_only: true,
..GoldenConfig::x86_64_linux()
};
let mut orch = GoldenOrchestrator::new(config, OrchestrationMode::Compile);
let result = orch.execute();
assert!(orch.executed);
let _ = result;
}
#[test]
fn test_smoke_dependency_tracker_integration() {
let mut tracker = DependencyTracker::new();
tracker.start();
tracker.record_dependency(Path::new("src/lib.c"), Path::new("include/lib.h"));
tracker.record_dependency(Path::new("src/lib.c"), Path::new("include/common.h"));
tracker.record_dependency(Path::new("src/main.c"), Path::new("include/common.h"));
tracker.mark_modified(Path::new("include/common.h"));
let needs = tracker.files_needing_recompilation();
assert_eq!(needs.len(), 2);
assert!(needs.contains(Path::new("src/lib.c")));
assert!(needs.contains(Path::new("src/main.c")));
}
#[test]
fn test_smoke_pgo_integration() {
let mut pgo = GoldenPGO::from_golden_config(&GoldenConfig::x86_64_linux_release());
let mut profile = PGOProfile::empty();
profile.record_function("hot_func", 100000);
profile.record_function("cold_func", 10);
assert!(profile.is_hot("hot_func"));
assert!(!profile.is_hot("cold_func"));
pgo.profile_data = Some(profile);
pgo.apply();
assert!(pgo.applied);
}
#[test]
fn test_smoke_sanitizer_lto_together() {
let config = GoldenConfig::x86_64_linux_release()
.with_sanitizer("address")
.with_lto(true)
.with_thin_lto(true);
assert!(config.asan);
assert!(config.lto);
assert!(config.thin_lto);
}
#[test]
fn test_smoke_incremental_compile_workflow() {
let mut ic = IncrementalCompiler::new(GoldenConfig {
incremental: true,
incremental_cache_dir: Some(PathBuf::from("/tmp/incr_test")),
..GoldenConfig::x86_64_linux()
});
assert!(ic.enabled);
assert!(ic.needs_recompilation(Path::new("new_file.c")));
}
#[test]
fn test_smoke_cache_lifecycle() {
let dir = std::env::temp_dir().join("smoke_cache_test");
let mut cache = CompilationCache::new();
cache.set_enabled(true);
cache.set_cache_dir(dir.clone());
let key = "smoke_key";
cache.store(key, b"smoke_data");
let val = cache.lookup(key);
assert!(val.is_some());
cache.clear();
let val2 = cache.lookup(key);
assert!(val2.is_none());
let _ = fs::remove_dir_all(&dir);
}
#[test]
fn test_smoke_cross_compilation_workflow() {
let cc = CrossCompiler::new("x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu")
.with_sysroot(PathBuf::from("/sysroot/aarch64"))
.with_resource_dir(PathBuf::from("/usr/lib/llvm-18"));
let flags = cc.target_compiler_flags();
assert!(flags.iter().any(|f| f.contains("aarch64")));
assert!(flags.iter().any(|f| f.contains("sysroot")));
assert!(cc.is_cross_compiling());
}
#[test]
fn test_error_recovery_new() {
let recovery = ErrorRecovery::new(RecoveryStrategy::Collect);
assert!(!recovery.has_errors());
assert!(!recovery.fatal_error);
assert_eq!(recovery.skip_count, 0);
}
#[test]
fn test_error_recovery_record_error() {
let mut recovery = ErrorRecovery::new(RecoveryStrategy::Collect);
recovery.record_error("parse error".into());
assert!(recovery.has_errors());
assert_eq!(recovery.error_count(), 1);
}
#[test]
fn test_error_recovery_abort_strategy() {
let recovery = ErrorRecovery::new(RecoveryStrategy::Abort);
assert!(recovery.should_continue()); }
#[test]
fn test_error_recovery_collect_strategy() {
let mut recovery = ErrorRecovery::new(RecoveryStrategy::Collect);
recovery.record_error("err1".into());
recovery.record_error("err2".into());
assert!(recovery.should_continue()); assert_eq!(recovery.error_count(), 2);
}
#[test]
fn test_error_recovery_fatal() {
let mut recovery = ErrorRecovery::new(RecoveryStrategy::Collect);
recovery.mark_fatal();
assert!(!recovery.should_continue());
}
#[test]
fn test_error_recovery_skip_count() {
let mut recovery = ErrorRecovery::new(RecoveryStrategy::SkipToNextDecl);
recovery.increment_skip_count();
recovery.increment_skip_count();
assert_eq!(recovery.skip_count, 2);
}
#[test]
fn test_error_recovery_fix_count() {
let mut recovery = ErrorRecovery::new(RecoveryStrategy::AttemptFix);
recovery.increment_fix_count();
assert_eq!(recovery.fix_count, 1);
}
#[test]
fn test_error_recovery_recovery_points() {
let mut recovery = ErrorRecovery::new(RecoveryStrategy::Collect);
recovery.record_error("err1".into());
recovery.record_recovery_point();
recovery.record_error("err2".into());
assert_eq!(recovery.recovery_points.len(), 1);
assert_eq!(recovery.recovery_points[0], 1);
}
#[test]
fn test_error_recovery_reset() {
let mut recovery = ErrorRecovery::new(RecoveryStrategy::Collect);
recovery.record_error("err".into());
recovery.increment_skip_count();
recovery.mark_fatal();
recovery.reset();
assert!(!recovery.has_errors());
assert!(!recovery.fatal_error);
assert_eq!(recovery.skip_count, 0);
}
#[test]
fn test_recovery_strategy_all_variants() {
let strategies = [
RecoveryStrategy::Abort,
RecoveryStrategy::Collect,
RecoveryStrategy::SkipToNextDecl,
RecoveryStrategy::AttemptFix,
RecoveryStrategy::BestEffort,
];
for s in &strategies {
let recovery = ErrorRecovery::new(*s);
assert!(recovery.should_continue());
}
}
#[test]
fn test_recovery_strategy_default() {
let default = RecoveryStrategy::default();
assert_eq!(default, RecoveryStrategy::Collect);
}
#[test]
fn test_compiler_version_current() {
let version = CompilerVersion::current();
assert_eq!(version.name, "llvm-native");
assert!(!version.version.is_empty());
assert!(!version.target_triple.is_empty());
}
#[test]
fn test_compiler_version_to_string() {
let version = CompilerVersion::current();
let s = version.to_string();
assert!(s.contains("llvm-native"));
assert!(s.contains("version"));
}
#[test]
fn test_compiler_version_supports_feature() {
let version = CompilerVersion::current();
assert!(version.supports_feature("c11"));
assert!(version.supports_feature("cxx17"));
assert!(version.supports_feature("lto"));
assert!(version.supports_feature("x86_64"));
assert!(!version.supports_feature("nonexistent_feature"));
}
#[test]
fn test_compiler_version_supported_features() {
let version = CompilerVersion::current();
let features = version.supported_features();
assert!(!features.is_empty());
assert!(features.contains(&"c17"));
assert!(features.contains(&"x86_64"));
}
#[test]
fn test_compiler_version_default() {
let version = CompilerVersion::default();
assert_eq!(version.name, "llvm-native");
}
#[test]
fn test_integration_full_workflow_compile_verify_profile() {
let source =
"int add(int a, int b) { return a + b; }\nint main(void) { return add(1, 2); }\n";
let result = full_pipeline_compile(source);
let mut verifier = GoldenVerifier::new(false);
if let Some(ref module) = result.module {
verifier.verify_module(module);
}
let mut profiler = GoldenProfiler::new(true);
profiler.begin_span("total");
profiler.end_span("total", ProfileCategory::Other, 1);
let _ = profiler.report();
let _ = verifier.report();
}
#[test]
fn test_integration_orchestrator_all_modes() {
for mode in &[
OrchestrationMode::Compile,
OrchestrationMode::Analyze,
OrchestrationMode::Test,
] {
let config = GoldenConfig {
input_files: vec![PathBuf::from("test.c")],
syntax_only: true,
..GoldenConfig::x86_64_linux()
};
let mut orch = GoldenOrchestrator::new(config, *mode);
let _ = orch.execute();
}
}
#[test]
fn test_integration_compilation_database_from_commands() {
let mut db = CompilationDatabase::new(PathBuf::from("/workspace"));
for i in 0..10 {
db.add(CompilationCommand {
file: PathBuf::from(format!("src/file_{i}.c")),
directory: PathBuf::from("/workspace/src"),
arguments: vec!["cc".into(), "-c".into(), format!("file_{i}.c")],
output: Some(PathBuf::from(format!("file_{i}.o"))),
});
}
assert_eq!(db.len(), 10);
assert_eq!(db.source_files().len(), 10);
let json = db.to_json();
assert!(json.contains("file_0"));
assert!(json.contains("file_9"));
}
#[test]
fn test_edge_golden_config_clone() {
let config1 = GoldenConfig::x86_64_linux_release();
let config2 = config1.clone();
assert_eq!(config1.cache_key(), config2.cache_key());
}
#[test]
fn test_edge_golden_result_clone() {
let result = GoldenResult {
success: true,
completed_stage: None,
failed_stage: None,
text_output: Some("hello".into()),
binary_output: Some(vec![0xDE, 0xAD, 0xBE, 0xEF]),
output_file: Some(PathBuf::from("out.o")),
module: None,
metrics: GoldenMetrics::default(),
error_count: 0,
warning_count: 0,
stage_results: vec![],
};
let cloned = result.clone();
assert_eq!(cloned.success, result.success);
assert_eq!(cloned.text_output, result.text_output);
assert_eq!(cloned.binary_output, result.binary_output);
}
#[test]
fn test_edge_cache_many_operations() {
let dir = std::env::temp_dir().join("edge_cache_ops");
let mut cache = CompilationCache::new();
cache.set_enabled(true);
cache.set_cache_dir(dir.clone());
cache.set_max_size(1024 * 1024);
for i in 0..200 {
cache.store(&format!("key_{i}"), &vec![i as u8; 100]);
}
let stats = cache.stats();
assert!(stats.enabled);
assert!(cache.lookup("key_0").is_some());
assert!(cache.lookup("key_199").is_some());
assert!(cache.lookup("key_200").is_none());
cache.clear();
let _ = fs::remove_dir_all(&dir);
}
#[test]
fn test_edge_parallel_manager_empty_jobs() {
let mgr = ParallelCompilationManager::new(vec![], 1);
let results = mgr.clone().run();
assert!(results.is_empty());
assert!(mgr.all_succeeded());
}
#[test]
fn test_edge_self_host_empty_source_dir() {
let tmpdir = std::env::temp_dir();
let empty_src = tmpdir.join("empty_selfhost_src");
let build = tmpdir.join("empty_selfhost_build");
let _ = fs::create_dir_all(&empty_src);
let _ = fs::create_dir_all(&build);
let config = SelfHostConfig {
source_dir: empty_src.clone(),
build_dir: build.clone(),
generate_report: false,
verify_stages: false,
run_test_suite: false,
..Default::default()
};
let mut sh = GoldenSelfHost::new(config);
let result = sh.run();
assert!(result.is_ok());
let _ = fs::remove_dir_all(&empty_src);
let _ = fs::remove_dir_all(&build);
}
#[test]
fn test_edge_golden_verifier_verbose() {
let mut verifier = GoldenVerifier::new(true);
assert!(verifier.verbose);
let report = verifier.report();
assert!(report.contains("Passed: 0"));
}
#[test]
fn test_edge_recursion_in_functions() {
let source = r#"
int ack(int m, int n) {
if (m == 0) return n + 1;
if (n == 0) return ack(m - 1, 1);
return ack(m - 1, ack(m, n - 1));
}
int main(void) { return ack(2, 2); }
"#;
let result = compile_to_ir(source);
let _ = result;
}
}