Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9824c0e
Split IncrCompSession out of Session
bjorn3 Jul 8, 2026
ba41df4
Rollup merge of #159225 - bjorn3:split_incr_comp_session, r=oli-obk
JonathanBrouwer Aug 5, 2026
e9d0e58
refactor handling of target features in Session
RalfJung Aug 4, 2026
972d229
Rollup merge of #160530 - RalfJung:internal-target-features, r=nnethe…
JonathanBrouwer Aug 7, 2026
bcd8937
Upgrade and deduplicate dependencies
cuviper Aug 4, 2026
ca241a4
atomic volatile: add intrinsics
RalfJung Jul 28, 2026
0ac1585
Rollup merge of #160058 - RalfJung:atomic-volatile, r=JohnTitor
JonathanBrouwer Aug 17, 2026
4256f1d
reformat
cuviper Aug 18, 2026
bbf8c0c
Merge branch 'master' into sync_from_rust_2026_08_21
antoyo Aug 21, 2026
e08aa54
Update to nightly-2026-08-21
antoyo Aug 21, 2026
b658899
Refactor to avoid having to use set_type for global variables
antoyo Aug 20, 2026
07ea5eb
Fix abort implementation
antoyo Aug 21, 2026
9ad588c
Add regression test for #827
antoyo Aug 23, 2026
351d4b4
Mark default EII function aliases as weak
AsakuraMizu Aug 20, 2026
d3af584
Fix EII static alias declarations
AsakuraMizu Aug 20, 2026
9f48c46
Handle alignment and volatile flag for mem operations
antoyo Aug 24, 2026
5137886
Fix and support more linkages
antoyo Aug 23, 2026
9eb0d26
Implement linkage in predefine_static and fix internal linkage on ext…
antoyo Aug 23, 2026
5d5d945
Use internal linkage for check_and_apply_linkage
antoyo Aug 23, 2026
5b8a80d
Fix ICE that happened on a weak function marked inline
antoyo Aug 24, 2026
cb5c02a
Cleanup
antoyo Aug 25, 2026
0ae82b3
Update .gitignore
antoyo Aug 25, 2026
37039fa
Improve tests
antoyo Aug 26, 2026
c0bd587
Add support for the common attribute
antoyo Aug 26, 2026
19bde30
Update comments
antoyo Aug 26, 2026
29b7475
Update libgccjit version
antoyo Aug 26, 2026
62cf303
Use the correct sign for the division
antoyo Aug 29, 2026
4ec7c75
[DO NOT MERGE] Debug sysroot
jieyouxu Aug 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ llvm
build_system/target
config.toml
build
rustlantis
rustlantis
stuff/
12 changes: 6 additions & 6 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,18 @@ dependencies = [

[[package]]
name = "gccjit"
version = "6.0.0"
version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bb358d2563af5e32af92620915e6b05839ae60645343473735619441f45eb04"
checksum = "6d85b5754389edaad832ba320709a25086b3081a8c6c0fab2322965e5fb512b3"
dependencies = [
"gccjit_sys",
]

[[package]]
name = "gccjit_sys"
version = "3.1.0"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2389fb01673e9cc63684d996a58079edccc5de89008274f3be59f1b16ac1f017"
checksum = "e081669728b490723537f9def7eb674b7c9acd8de0b92ad4f4abf5f5cc75ea4b"
dependencies = [
"libc",
]
Expand Down Expand Up @@ -145,9 +145,9 @@ dependencies = [

[[package]]
name = "object"
version = "0.37.1"
version = "0.39.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a"
checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b"
dependencies = [
"memchr",
]
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ master = ["gccjit/master"]
default = ["master"]

[dependencies]
object = { version = "0.37.0", default-features = false, features = ["std", "read"] }
object = { version = "0.39.0", default-features = false, features = ["std", "read"] }
tempfile = "3.20"
gccjit = { version = "6.0.0", features = ["dlopen"] }
gccjit = { version = "6.1.0", features = ["dlopen"] }
#gccjit = { git = "https://github.com/rust-lang/gccjit.rs", branch = "error-dlopen", features = ["dlopen"] }

# Local copy.
Expand Down
7 changes: 4 additions & 3 deletions build_system/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1263,13 +1263,12 @@ fn run_ui_tests(env: &Env, args: &TestArg) -> Result<(), String> {
let rust_path = setup_rustc(&mut env, args)?;

let extra =
if args.is_using_gcc_master_branch() { "" } else { " -Csymbol-mangling-version=v0" };
if args.is_using_gcc_master_branch() { "" } else { "-Csymbol-mangling-version=v0" };

let rustc_args = format!(
"{test_flags} -Zcodegen-backend={backend} --sysroot {sysroot}{extra}",
"{test_flags} -Zcodegen-backend={backend} {extra}",
test_flags = env.get("TEST_FLAGS").unwrap_or(&String::new()),
backend = args.config_info.cg_backend_path,
sysroot = args.config_info.sysroot_path,
extra = extra,
);

Expand All @@ -1286,6 +1285,8 @@ fn run_ui_tests(env: &Env, args: &TestArg) -> Result<(), String> {
&"build.compiletest-allow-stage0=true",
&"--compiletest-rustc-args",
&rustc_args,
&"--sysroot",
&args.config_info.sysroot_path,
&"--bypass-ignore-backends",
&"--force-rerun",
];
Expand Down
2 changes: 1 addition & 1 deletion libgccjit.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
201ca90ac810d1c6509c252cc9c87d3ace0661d7
badf78d09d16e66f4ca07971c51aa6a227558d4f
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2026-08-04"
channel = "nightly-2026-08-21"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
12 changes: 12 additions & 0 deletions src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use rustc_target::callconv::FnAbi;
#[cfg(feature = "master")]
use rustc_target::spec::Arch;

#[cfg(feature = "master")]
use crate::base;
use crate::context::CodegenCx;
use crate::gcc_util::to_gcc_features;

Expand Down Expand Up @@ -116,6 +118,16 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
} else {
codegen_fn_attrs.inline
};
// GCC drops `weak` from a function that is also `inline`, leaving the symbol strong, and
// the linkage is what has to survive. `inline(never)` does not conflict.
let inline = match inline {
InlineAttr::Always | InlineAttr::Hint | InlineAttr::Force { .. }
if codegen_fn_attrs.linkage.is_some_and(base::linkage_needs_weak_attribute) =>
{
InlineAttr::None
}
inline => inline,
};
if let Some(attr) = inline_attr(cx, inline, instance) {
if let FnAttribute::AlwaysInline = attr {
func.add_attribute(FnAttribute::Inline);
Expand Down
78 changes: 60 additions & 18 deletions src/base.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::sync::Arc;
use std::time::Instant;

#[cfg(feature = "master")]
use gccjit::VarAttribute;
use gccjit::{CType, FunctionType, GlobalKind};
use rustc_codegen_ssa::ModuleCodegen;
use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
Expand Down Expand Up @@ -39,32 +41,72 @@ pub fn symbol_visibility_to_gcc(visibility: SymbolVisibility) -> gccjit::Visibil
}
}

/// The kind of a global *definition* with an explicit `#[linkage]`.
///
/// The flavours that another object file is allowed to override also need
/// `global_linkage_attribute` from the caller: `GlobalKind` alone cannot express weakness.
pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind {
match linkage {
Linkage::External => GlobalKind::Imported,
Linkage::AvailableExternally => GlobalKind::Imported,
Linkage::LinkOnceAny => unimplemented!(),
Linkage::LinkOnceODR => unimplemented!(),
Linkage::WeakAny => unimplemented!(),
Linkage::WeakODR => unimplemented!(),
Linkage::Internal => GlobalKind::Internal,
Linkage::ExternalWeak => GlobalKind::Imported, // FIXME(antoyo): should be weak linkage.
Linkage::Common => unimplemented!(),
Linkage::External => GlobalKind::Exported,
// libgccjit cannot emit a definition that the linker discards in favour of the one in
// another object file, so emit a private copy of it instead.
Linkage::AvailableExternally | Linkage::Internal => GlobalKind::Internal,
// libgccjit exposes no comdat, so `weak` stands in for the linkonce flavours.
Linkage::LinkOnceAny
| Linkage::LinkOnceODR
| Linkage::WeakAny
| Linkage::WeakODR
| Linkage::ExternalWeak
| Linkage::Common => GlobalKind::Exported,
}
}

/// The attribute a global *definition* needs on top of its [`GlobalKind`] to get this linkage.
#[cfg(feature = "master")]
pub fn global_linkage_attribute<'gcc>(linkage: Linkage) -> Option<VarAttribute<'gcc>> {
match linkage {
Linkage::Common => Some(VarAttribute::Common),
_ if linkage_needs_weak_attribute(linkage) => Some(VarAttribute::Weak),
_ => None,
}
}

/// The type of a function *definition* with an explicit `#[linkage]`.
///
/// The flavours that another object file is allowed to override also need
/// `linkage_needs_weak_attribute` from the caller: `FunctionType` alone cannot express weakness.
pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType {
match linkage {
Linkage::External => FunctionType::Exported,
// FIXME(antoyo): set the attribute externally_visible.
Linkage::AvailableExternally => FunctionType::Extern,
Linkage::LinkOnceAny => unimplemented!(),
Linkage::LinkOnceODR => unimplemented!(),
Linkage::WeakAny => FunctionType::Exported, // FIXME(antoyo): should be similar to linkonce.
Linkage::WeakODR => unimplemented!(),
Linkage::Internal => FunctionType::Internal,
Linkage::ExternalWeak => unimplemented!(),
Linkage::Common => unimplemented!(),
// libgccjit cannot emit a definition that the linker discards in favour of the one in
// another object file, so emit a private copy of it instead.
Linkage::AvailableExternally | Linkage::Internal => FunctionType::Internal,
// libgccjit exposes no comdat, so `weak` stands in for every overridable flavour.
Linkage::LinkOnceAny
| Linkage::LinkOnceODR
| Linkage::WeakAny
| Linkage::WeakODR
| Linkage::ExternalWeak
| Linkage::Common => FunctionType::Exported,
}
}

/// Whether a definition with this linkage must carry the `weak` attribute, so that a strong
/// definition in another object file wins over it instead of clashing with it.
///
/// `common` is in here for functions only: GCC honours that attribute on a variable, but drops it
/// on a function, so a common function falls back to weak. Globals go through
/// `global_linkage_attribute` instead.
#[cfg(feature = "master")]
pub fn linkage_needs_weak_attribute(linkage: Linkage) -> bool {
match linkage {
Linkage::LinkOnceAny
| Linkage::LinkOnceODR
| Linkage::WeakAny
| Linkage::WeakODR
| Linkage::ExternalWeak
| Linkage::Common => true,
Linkage::External | Linkage::AvailableExternally | Linkage::Internal => false,
}
}

Expand Down
72 changes: 57 additions & 15 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,33 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
self.value_counter.get()
}

/// Tell GCC that `pointer` is `align`-aligned, so that the bulk memory builtins can widen their
/// accesses: a pointer cast to an aligned type would be dropped as a useless conversion.
fn assume_aligned(&mut self, pointer: RValue<'gcc>, align: Align) -> RValue<'gcc> {
if align.bytes() <= 1 {
return pointer;
}
let assume_aligned = self.context.get_builtin_function("__builtin_assume_aligned");
let alignment = self.context.new_rvalue_from_long(self.type_size_t(), align.bytes() as i64);
let pointer_type = pointer.get_type();
let const_void_ptr_type = self.context.new_type::<()>().make_const().make_pointer();
let pointer = self.context.new_cast(self.location, pointer, const_void_ptr_type);
let aligned = self.context.new_call(self.location, assume_aligned, &[pointer, alignment]);
self.context.new_cast(self.location, aligned, pointer_type)
}

/// GCC ignores a volatile qualifier on the pointers given to `memcpy`/`memmove`/`memset` and
/// happily deletes the call, so a barrier is what keeps the operation observable. The pointers
/// are fed to it because a clobber alone does not reach memory GCC believes never escapes.
fn volatile_barrier(&mut self, pointers: &[RValue<'gcc>]) {
let barrier = self.block.add_extended_asm(self.location, "");
for pointer in pointers {
barrier.add_input_operand(None, "r", *pointer);
}
barrier.add_clobber("memory");
barrier.set_volatile_flag(true);
}

fn atomic_extremum(
&mut self,
operation: ExtremumOperation,
Expand All @@ -82,8 +109,13 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
AtomicOrdering::AcqRel | AtomicOrdering::Release => AtomicOrdering::Acquire,
_ => order,
};
let previous_value =
self.atomic_load(dst.get_type(), dst, load_ordering, Size::from_bytes(size));
let previous_value = self.atomic_load(
dst.get_type(),
dst,
load_ordering,
/* volatile */ false,
Size::from_bytes(size),
);
let previous_var =
func.new_local(self.location, previous_value.get_type(), "previous_value");
let return_value = self.new_temp(func, self.location, previous_value.get_type());
Expand Down Expand Up @@ -719,8 +751,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
if return_type == void_type {
self.block.end_with_void_return(self.location)
} else {
let abort = self.context.get_builtin_function("abort");
self.block.add_eval(self.location, self.context.new_call(self.location, abort, &[]));
let trap = self.context.get_builtin_function("__builtin_trap");
self.block.add_eval(self.location, self.context.new_call(self.location, trap, &[]));
let return_value = self.new_temp(self.current_func(), self.location, return_type);
self.block.end_with_return(self.location, return_value)
}
Expand Down Expand Up @@ -1060,6 +1092,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
_ty: Type<'gcc>,
ptr: RValue<'gcc>,
order: AtomicOrdering,
_volatile: bool, // FIXME we are always making the load volatile
size: Size,
) -> RValue<'gcc> {
// FIXME(antoyo): use ty.
Expand Down Expand Up @@ -1229,6 +1262,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
value: RValue<'gcc>,
ptr: RValue<'gcc>,
order: AtomicOrdering,
_volatile: bool, // FIXME we are always making the store volatile
size: Size,
) {
// FIXME(antoyo): handle alignment.
Expand Down Expand Up @@ -1448,68 +1482,76 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
fn memcpy(
&mut self,
dst: RValue<'gcc>,
_dst_align: Align,
dst_align: Align,
src: RValue<'gcc>,
_src_align: Align,
src_align: Align,
size: RValue<'gcc>,
flags: MemFlags,
_tt: Option<rustc_ast::expand::typetree::FncTree>, // Autodiff TypeTrees are LLVM-only, ignored in GCC backend
) {
assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memcpy not supported");
let size = self.intcast(size, self.type_size_t(), false);
let _is_volatile = flags.contains(MemFlags::VOLATILE);
let dst = self.pointercast(dst, self.type_i8p());
let dst = self.assume_aligned(dst, dst_align);
let src = self.pointercast(src, self.type_ptr_to(self.type_void()));
let src = self.assume_aligned(src, src_align);
let memcpy = self.context.get_builtin_function("memcpy");
// FIXME(antoyo): handle aligns and is_volatile.
self.block.add_eval(
self.location,
self.context.new_call(self.location, memcpy, &[dst, src, size]),
);
if flags.contains(MemFlags::VOLATILE) {
self.volatile_barrier(&[dst, src]);
}
}

fn memmove(
&mut self,
dst: RValue<'gcc>,
_dst_align: Align,
dst_align: Align,
src: RValue<'gcc>,
_src_align: Align,
src_align: Align,
size: RValue<'gcc>,
flags: MemFlags,
) {
assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memmove not supported");
let size = self.intcast(size, self.type_size_t(), false);
let _is_volatile = flags.contains(MemFlags::VOLATILE);
let dst = self.pointercast(dst, self.type_i8p());
let dst = self.assume_aligned(dst, dst_align);
let src = self.pointercast(src, self.type_ptr_to(self.type_void()));
let src = self.assume_aligned(src, src_align);

let memmove = self.context.get_builtin_function("memmove");
// FIXME(antoyo): handle is_volatile.
self.block.add_eval(
self.location,
self.context.new_call(self.location, memmove, &[dst, src, size]),
);
if flags.contains(MemFlags::VOLATILE) {
self.volatile_barrier(&[dst, src]);
}
}

fn memset(
&mut self,
ptr: RValue<'gcc>,
fill_byte: RValue<'gcc>,
size: RValue<'gcc>,
_align: Align,
align: Align,
flags: MemFlags,
) {
assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memset not supported");
let _is_volatile = flags.contains(MemFlags::VOLATILE);
let ptr = self.pointercast(ptr, self.type_i8p());
let ptr = self.assume_aligned(ptr, align);
let memset = self.context.get_builtin_function("memset");
// FIXME(antoyo): handle align and is_volatile.
let fill_byte = self.context.new_cast(self.location, fill_byte, self.i32_type);
let size = self.intcast(size, self.type_size_t(), false);
self.block.add_eval(
self.location,
self.context.new_call(self.location, memset, &[ptr, fill_byte, size]),
);
if flags.contains(MemFlags::VOLATILE) {
self.volatile_barrier(&[ptr]);
}
}

fn vscale(&mut self, _: Self::Type) -> Self::Value {
Expand Down
Loading
Loading