Apply LLVM patches for deterministic operand order and correct peephole optimization for minsize (#500)

## Description

Applies LLVM patches that have not been backported to the major version
used in our submodule:

* [LLVM PR #163679](https://github.com/llvm/llvm-project/pull/163679)
  * *"[RISCV] Allow large div peephole optimization for minsize"*
* Fixes peephole optimization of large integers when `minsize` function
attribute is set.
* (Our revive codebase used a workaround that can be removed once this
500 PR is merged and we publish a new LLVM release.)
* [LLVM PR #190219](https://github.com/llvm/llvm-project/pull/190219)
* *"[TargetLowering] Speculative fix for a non-determinism issue between
different compilers"*
* Operand ordering of `mul i256` were different depending on the target
ABI when building LLVM, producing different RISC-V and PVM bytecode for
our Windows vs macOS/linux builds.
* The bytecode divergence (yet functionally equivalent) affected
Solidity contracts containing a value [multiplied by
itself](https://github.com/llvm/llvm-project/issues/190148) (e.g. via
explicit squaring or exponentiation), manifesting primarily when using
optimization level `-O0`.
This commit is contained in:
LJ authored and GitHub committed 2026-04-09 17:33:09 +02:00
1 parent 8c41f93ace
commit 3dc84349d9
9 files changed
+99 -11

No files matched your search

+2
View File
@@ -82,6 +82,8 @@ pub fn build(
)
}
utils::apply_patches()?;
std::fs::create_dir_all(llvm_path::DIRECTORY_LLVM_TARGET.get().unwrap())?;
if cfg!(target_arch = "x86_64") {
+3
View File
@@ -20,6 +20,9 @@ impl LLVMPath {
/// The Emscripten SDK source directory.
pub const DIRECTORY_EMSDK_SOURCE: &'static str = "./emsdk/";
/// The directory containing patches to apply to the LLVM source.
pub const DIRECTORY_PATCHES: &'static str = "./patches/llvm/";
/// Returns the path to the `llvm` stage 1 host LLVM source module directory.
pub fn llvm_host_module_llvm() -> anyhow::Result<PathBuf> {
let mut path = PathBuf::from(Self::DIRECTORY_LLVM_HOST_SOURCE);
+52 -7
View File
@@ -1,6 +1,6 @@
//! The LLVM builder utilities.
use std::fs::File;
use std::fs::{read_dir, File};
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
@@ -10,12 +10,6 @@ use std::time::Duration;
use anyhow::Context;
use path_slash::PathBufExt;
/// The LLVM host repository URL.
pub const LLVM_HOST_SOURCE_URL: &str = "https://github.com/llvm/llvm-project";
/// The LLVM host repository tag.
pub const LLVM_HOST_SOURCE_TAG: &str = "llvmorg-18.1.8";
/// The minimum required XCode version.
pub const XCODE_MIN_VERSION: u32 = 11;
@@ -220,6 +214,57 @@ pub fn install_emsdk() -> anyhow::Result<()> {
Ok(())
}
/// Applies all LLVM `.patch` files to the LLVM source.
///
/// Patches that have already been applied are skipped.
pub fn apply_patches() -> anyhow::Result<()> {
let patches_directory = PathBuf::from(crate::LLVMPath::DIRECTORY_PATCHES);
if !patches_directory.exists() {
log::debug!("no patches directory found, skipping");
return Ok(());
}
let llvm_source = PathBuf::from(crate::LLVMPath::DIRECTORY_LLVM_SOURCE);
let mut patches: Vec<_> = read_dir(&patches_directory)?
.filter_map(|entry| entry.ok())
.map(|entry| entry.path())
.filter(|path| {
path.extension()
.is_some_and(|extension| extension == "patch")
})
.collect();
patches.sort();
for patch in patches {
let patch = absolute_path(&patch)?;
let already_applied = Command::new("git")
.args(["apply", "--reverse", "--check"])
.arg(&patch)
.current_dir(&llvm_source)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.map(|status| status.success())
.unwrap_or(false);
if already_applied {
log::info!("patch already applied, skipping: {}", patch.display());
continue;
}
log::info!("applying patch: {}", patch.display());
command(
Command::new("git")
.args(["apply"])
.arg(&patch)
.current_dir(&llvm_source),
&format!("applying patch {}", patch.display()),
)?;
}
Ok(())
}
/// The LLVM target directory default path.
pub fn directory_target_llvm(target_env: crate::target_env::TargetEnv) -> PathBuf {
crate::llvm_path::DIRECTORY_LLVM_TARGET