From 7ade2afc619f1c0fb0f87bb6f4c48e051a97969a Mon Sep 17 00:00:00 2001 From: FuryBaM <51872689+FuryBaM@users.noreply.github.com> Date: Mon, 20 Jul 2026 16:14:50 +0500 Subject: [PATCH 1/3] Eliminate LLVM-proven array bounds checks --- Absolute-CodeGen/src/codegen.cpp | 180 ++++++++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 2 deletions(-) diff --git a/Absolute-CodeGen/src/codegen.cpp b/Absolute-CodeGen/src/codegen.cpp index 2cebfdb1..55fc000e 100644 --- a/Absolute-CodeGen/src/codegen.cpp +++ b/Absolute-CodeGen/src/codegen.cpp @@ -1,6 +1,123 @@ #include "codegen_internal.h" +#include +#include +#include +#include + namespace Absolute { + namespace { + bool IsArrayBoundsFailure(const llvm::BasicBlock* block) { + return block && block->getName().find("array.bounds.failure") == 0; + } + + bool IsKnownBoolean( + llvm::Value* value, + bool expected, + llvm::Instruction* context, + llvm::LazyValueInfo& lazyValues, + unsigned depth = 0) { + if (!value || depth > 12 || !value->getType()->isIntegerTy(1)) return false; + if (const auto* constant = llvm::dyn_cast(value)) + return constant->isOne() == expected; + + llvm::Constant* known = lazyValues.getPredicateAt( + llvm::CmpInst::ICMP_EQ, + value, + llvm::ConstantInt::get(value->getType(), expected), + context, + true); + if (const auto* result = llvm::dyn_cast_or_null(known)) + if (result->isOne()) return true; + + if (const auto* compare = llvm::dyn_cast(value)) { + llvm::CmpInst::Predicate predicate = expected + ? compare->getPredicate() + : compare->getInversePredicate(); + llvm::Value* left = compare->getOperand(0); + llvm::Value* right = compare->getOperand(1); + if (llvm::isa(left) || llvm::isa(right)) { + llvm::Constant* comparison = lazyValues.getPredicateAt( + predicate, left, right, context, true); + if (const auto* result = llvm::dyn_cast_or_null(comparison)) + return result->isOne(); + } + } + + const auto* binary = llvm::dyn_cast(value); + if (!binary) return false; + llvm::Value* left = binary->getOperand(0); + llvm::Value* right = binary->getOperand(1); + switch (binary->getOpcode()) { + case llvm::Instruction::And: + if (expected) + return IsKnownBoolean(left, true, context, lazyValues, depth + 1) && + IsKnownBoolean(right, true, context, lazyValues, depth + 1); + return IsKnownBoolean(left, false, context, lazyValues, depth + 1) || + IsKnownBoolean(right, false, context, lazyValues, depth + 1); + case llvm::Instruction::Or: + if (expected) + return IsKnownBoolean(left, true, context, lazyValues, depth + 1) || + IsKnownBoolean(right, true, context, lazyValues, depth + 1); + return IsKnownBoolean(left, false, context, lazyValues, depth + 1) && + IsKnownBoolean(right, false, context, lazyValues, depth + 1); + case llvm::Instruction::Xor: + if (const auto* constant = llvm::dyn_cast(right)) { + if (constant->isOne()) + return IsKnownBoolean(left, !expected, context, lazyValues, depth + 1); + if (constant->isZero()) + return IsKnownBoolean(left, expected, context, lazyValues, depth + 1); + } + return false; + default: + return false; + } + } + + class ProvenArrayBoundsPass final + : public llvm::PassInfoMixin { + public: + llvm::PreservedAnalyses run( + llvm::Function& function, + llvm::FunctionAnalysisManager& analyses) { + llvm::LazyValueInfo& lazyValues = + analyses.getResult(function); + llvm::SmallVector, 8> rewrites; + + for (llvm::BasicBlock& block : function) { + auto* branch = llvm::dyn_cast(block.getTerminator()); + if (!branch || !branch->isConditional()) continue; + llvm::BasicBlock* first = branch->getSuccessor(0); + llvm::BasicBlock* second = branch->getSuccessor(1); + const bool firstFailure = IsArrayBoundsFailure(first); + const bool secondFailure = IsArrayBoundsFailure(second); + if (firstFailure == secondFailure) continue; + + const bool requiredCondition = secondFailure; + if (!IsKnownBoolean( + branch->getCondition(), requiredCondition, branch, lazyValues)) continue; + rewrites.emplace_back(branch, firstFailure ? second : first); + } + + for (auto& [branch, success] : rewrites) { + llvm::BranchInst::Create(success, branch); + branch->eraseFromParent(); + } + return rewrites.empty() + ? llvm::PreservedAnalyses::all() + : llvm::PreservedAnalyses::none(); + } + }; + + void AddAbsoluteOptimizationPasses(llvm::ModulePassManager& passes) { + llvm::FunctionPassManager functions; + functions.addPass(ProvenArrayBoundsPass()); + functions.addPass(llvm::SimplifyCFGPass()); + functions.addPass(llvm::DCEPass()); + passes.addPass(llvm::createModuleToFunctionPassAdaptor(std::move(functions))); + } + } + CodeGenerator::CodeGenerator(const Analyzer* analyzer) : impl(std::make_unique(*this, analyzer)) { } @@ -13,7 +130,66 @@ namespace Absolute { void CodeGenerator::GenerateObject( Program& program, const std::string& moduleName, const std::string& outputPath) { - impl->GenerateObject(program, moduleName, outputPath); - } + static std::once_flag initializeTarget; + std::call_once(initializeTarget, [] { + if (llvm::InitializeNativeTarget()) + throw std::runtime_error("LLVM codegen: failed to initialize the native target"); + if (llvm::InitializeNativeTargetAsmPrinter()) + throw std::runtime_error("LLVM codegen: failed to initialize the native assembly printer"); + }); + + const std::string triple = llvm::sys::getDefaultTargetTriple(); + std::string targetError; + const llvm::Target* target = llvm::TargetRegistry::lookupTarget(triple, targetError); + if (!target) + throw std::runtime_error("cannot select target '" + triple + "': " + targetError); + + llvm::TargetOptions options; + const std::string cpu = llvm::sys::getHostCPUName().str(); + std::unique_ptr targetMachine(target->createTargetMachine( + triple, cpu.empty() ? "generic" : cpu, "", options, llvm::Reloc::PIC_, + std::nullopt, llvm::CodeGenOptLevel::Aggressive)); + if (!targetMachine) + throw std::runtime_error("cannot create target machine for '" + triple + "'"); + const std::string dataLayout = + targetMachine->createDataLayout().getStringRepresentation(); + llvm::Module& generatedModule = + impl->BuildModule(program, moduleName, triple, dataLayout); + + llvm::LoopAnalysisManager loopAnalyses; + llvm::FunctionAnalysisManager functionAnalyses; + llvm::CGSCCAnalysisManager cgsccAnalyses; + llvm::ModuleAnalysisManager moduleAnalyses; + llvm::PassBuilder passBuilder(targetMachine.get()); + passBuilder.registerModuleAnalyses(moduleAnalyses); + passBuilder.registerCGSCCAnalyses(cgsccAnalyses); + passBuilder.registerFunctionAnalyses(functionAnalyses); + passBuilder.registerLoopAnalyses(loopAnalyses); + passBuilder.crossRegisterProxies( + loopAnalyses, functionAnalyses, cgsccAnalyses, moduleAnalyses); + + llvm::ModulePassManager optimizationPasses = + passBuilder.buildPerModuleDefaultPipeline(llvm::OptimizationLevel::O3); + AddAbsoluteOptimizationPasses(optimizationPasses); + optimizationPasses.run(generatedModule, moduleAnalyses); + + std::error_code error; + llvm::raw_fd_ostream output(outputPath, error, llvm::sys::fs::OF_None); + if (error) + throw std::runtime_error( + "cannot create object file '" + outputPath + "': " + error.message()); + + llvm::legacy::PassManager emissionPasses; +#if LLVM_VERSION_MAJOR >= 18 + constexpr llvm::CodeGenFileType fileType = llvm::CodeGenFileType::ObjectFile; +#else + constexpr llvm::CodeGenFileType fileType = llvm::CGFT_ObjectFile; +#endif + if (targetMachine->addPassesToEmitFile( + emissionPasses, output, nullptr, fileType)) + throw std::runtime_error("target cannot emit an object file"); + emissionPasses.run(generatedModule); + output.flush(); + } } From f093de9670b4341c5daeca76862d34ebc1f6c420 Mon Sep 17 00:00:00 2001 From: FuryBaM <51872689+FuryBaM@users.noreply.github.com> Date: Mon, 20 Jul 2026 16:22:31 +0500 Subject: [PATCH 2/3] Use ScalarEvolution for bounds proofs --- Absolute-CodeGen/src/codegen.cpp | 81 ++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 24 deletions(-) diff --git a/Absolute-CodeGen/src/codegen.cpp b/Absolute-CodeGen/src/codegen.cpp index 55fc000e..ef894a7f 100644 --- a/Absolute-CodeGen/src/codegen.cpp +++ b/Absolute-CodeGen/src/codegen.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -11,11 +12,40 @@ namespace Absolute { return block && block->getName().find("array.bounds.failure") == 0; } + bool IsKnownIntegerComparison( + const llvm::ICmpInst& comparison, + bool expected, + llvm::Instruction* context, + llvm::LazyValueInfo& lazyValues, + llvm::ScalarEvolution& scalarEvolution) { + const llvm::ICmpInst::Predicate predicate = expected + ? comparison.getPredicate() + : comparison.getInversePredicate(); + llvm::Value* left = comparison.getOperand(0); + llvm::Value* right = comparison.getOperand(1); + + if (llvm::isa(left) || llvm::isa(right)) { + llvm::Constant* result = lazyValues.getPredicateAt( + predicate, left, right, context, true); + if (const auto* known = llvm::dyn_cast_or_null(result)) + if (known->isOne()) return true; + } + + if (!left->getType()->isIntegerTy() || left->getType() != right->getType()) + return false; + return scalarEvolution.isKnownPredicateAt( + predicate, + scalarEvolution.getSCEV(left), + scalarEvolution.getSCEV(right), + context); + } + bool IsKnownBoolean( llvm::Value* value, bool expected, llvm::Instruction* context, llvm::LazyValueInfo& lazyValues, + llvm::ScalarEvolution& scalarEvolution, unsigned depth = 0) { if (!value || depth > 12 || !value->getType()->isIntegerTy(1)) return false; if (const auto* constant = llvm::dyn_cast(value)) @@ -30,18 +60,9 @@ namespace Absolute { if (const auto* result = llvm::dyn_cast_or_null(known)) if (result->isOne()) return true; - if (const auto* compare = llvm::dyn_cast(value)) { - llvm::CmpInst::Predicate predicate = expected - ? compare->getPredicate() - : compare->getInversePredicate(); - llvm::Value* left = compare->getOperand(0); - llvm::Value* right = compare->getOperand(1); - if (llvm::isa(left) || llvm::isa(right)) { - llvm::Constant* comparison = lazyValues.getPredicateAt( - predicate, left, right, context, true); - if (const auto* result = llvm::dyn_cast_or_null(comparison)) - return result->isOne(); - } + if (const auto* comparison = llvm::dyn_cast(value)) { + if (IsKnownIntegerComparison( + *comparison, expected, context, lazyValues, scalarEvolution)) return true; } const auto* binary = llvm::dyn_cast(value); @@ -51,22 +72,32 @@ namespace Absolute { switch (binary->getOpcode()) { case llvm::Instruction::And: if (expected) - return IsKnownBoolean(left, true, context, lazyValues, depth + 1) && - IsKnownBoolean(right, true, context, lazyValues, depth + 1); - return IsKnownBoolean(left, false, context, lazyValues, depth + 1) || - IsKnownBoolean(right, false, context, lazyValues, depth + 1); + return IsKnownBoolean( + left, true, context, lazyValues, scalarEvolution, depth + 1) && + IsKnownBoolean( + right, true, context, lazyValues, scalarEvolution, depth + 1); + return IsKnownBoolean( + left, false, context, lazyValues, scalarEvolution, depth + 1) || + IsKnownBoolean( + right, false, context, lazyValues, scalarEvolution, depth + 1); case llvm::Instruction::Or: if (expected) - return IsKnownBoolean(left, true, context, lazyValues, depth + 1) || - IsKnownBoolean(right, true, context, lazyValues, depth + 1); - return IsKnownBoolean(left, false, context, lazyValues, depth + 1) && - IsKnownBoolean(right, false, context, lazyValues, depth + 1); + return IsKnownBoolean( + left, true, context, lazyValues, scalarEvolution, depth + 1) || + IsKnownBoolean( + right, true, context, lazyValues, scalarEvolution, depth + 1); + return IsKnownBoolean( + left, false, context, lazyValues, scalarEvolution, depth + 1) && + IsKnownBoolean( + right, false, context, lazyValues, scalarEvolution, depth + 1); case llvm::Instruction::Xor: if (const auto* constant = llvm::dyn_cast(right)) { if (constant->isOne()) - return IsKnownBoolean(left, !expected, context, lazyValues, depth + 1); + return IsKnownBoolean( + left, !expected, context, lazyValues, scalarEvolution, depth + 1); if (constant->isZero()) - return IsKnownBoolean(left, expected, context, lazyValues, depth + 1); + return IsKnownBoolean( + left, expected, context, lazyValues, scalarEvolution, depth + 1); } return false; default: @@ -82,6 +113,8 @@ namespace Absolute { llvm::FunctionAnalysisManager& analyses) { llvm::LazyValueInfo& lazyValues = analyses.getResult(function); + llvm::ScalarEvolution& scalarEvolution = + analyses.getResult(function); llvm::SmallVector, 8> rewrites; for (llvm::BasicBlock& block : function) { @@ -94,8 +127,8 @@ namespace Absolute { if (firstFailure == secondFailure) continue; const bool requiredCondition = secondFailure; - if (!IsKnownBoolean( - branch->getCondition(), requiredCondition, branch, lazyValues)) continue; + if (!IsKnownBoolean(branch->getCondition(), requiredCondition, branch, + lazyValues, scalarEvolution)) continue; rewrites.emplace_back(branch, firstFailure ? second : first); } From e9f4345fd291dcfe69099ee70ddc3d795c037480 Mon Sep 17 00:00:00 2001 From: FuryBaM <51872689+FuryBaM@users.noreply.github.com> Date: Mon, 20 Jul 2026 16:26:27 +0500 Subject: [PATCH 3/3] Verify optimized bounds-check IR --- Absolute-CodeGen/src/codegen.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Absolute-CodeGen/src/codegen.cpp b/Absolute-CodeGen/src/codegen.cpp index ef894a7f..9ef199f5 100644 --- a/Absolute-CodeGen/src/codegen.cpp +++ b/Absolute-CodeGen/src/codegen.cpp @@ -9,7 +9,8 @@ namespace Absolute { namespace { bool IsArrayBoundsFailure(const llvm::BasicBlock* block) { - return block && block->getName().find("array.bounds.failure") == 0; + return block && block->getName().find("array.bounds.failure") == 0 && + llvm::isa(block->getTerminator()); } bool IsKnownIntegerComparison( @@ -20,7 +21,7 @@ namespace Absolute { llvm::ScalarEvolution& scalarEvolution) { const llvm::ICmpInst::Predicate predicate = expected ? comparison.getPredicate() - : comparison.getInversePredicate(); + : llvm::CmpInst::getInversePredicate(comparison.getPredicate()); llvm::Value* left = comparison.getOperand(0); llvm::Value* right = comparison.getOperand(1); @@ -207,6 +208,14 @@ namespace Absolute { AddAbsoluteOptimizationPasses(optimizationPasses); optimizationPasses.run(generatedModule, moduleAnalyses); + std::string verifierMessage; + llvm::raw_string_ostream verifierStream(verifierMessage); + if (llvm::verifyModule(generatedModule, &verifierStream)) { + verifierStream.flush(); + throw std::runtime_error( + "optimized module verification failed: " + verifierMessage); + } + std::error_code error; llvm::raw_fd_ostream output(outputPath, error, llvm::sys::fs::OF_None); if (error)