Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,18 @@ fn backchain_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attrib
if found_positive { Some(llvm::CreateAttrString(cx.llcx, "backchain")) } else { None }
}

fn packed_stack_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
if sess.target.arch != Arch::S390x {
return None;
}

if sess.opts.cg.packed_stack {
Some(llvm::CreateAttrString(cx.llcx, "packed-stack"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are the ABI considerations for this flag? Is it possible to freely mix code built with and without this flag? If not, it needs to be made a "target modifier" to avoid unsoundness.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes packed-stack and non packed stack code can be mixed. It just affects the calling code and not the called code.

} else {
None
}
}

pub(crate) fn target_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> &'ll Attribute {
let target_cpu = llvm_util::target_cpu(sess);
llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu)
Expand Down Expand Up @@ -525,6 +537,10 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
if let Some(backchain) = backchain_attr(cx, sess) {
to_add.push(backchain);
}
if let Some(packed_stack) = packed_stack_attr(cx, sess) {
to_add.push(packed_stack);
}

to_add.extend(patchable_function_entry_attrs(
cx,
sess,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2551,6 +2551,8 @@ options! {
"pass `-install_name @rpath/...` to the macOS linker (default: no)"),
packed_bundled_libs: bool = (false, parse_bool, [TRACKED],
"change rlib format to store native libraries as archives"),
packed_stack: bool = (false, parse_bool, [TRACKED],
"use packed stack frames (s390x only) (default: no)"),
panic_abort_tests: bool = (false, parse_bool, [TRACKED],
"support compiling tests with panic=abort (default: no)"),
panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED],
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3242,6 +3242,17 @@ impl Target {
));
}
}

// If both `packed-stack` and `backchain` are set we need to use soft-float ABI.
if self.arch == Arch::S390x
&& features_enabled.contains("packed-stack")
&& features_enabled.contains("backchain")
&& !matches!(self.abi, Abi::SoftFloat)
{
return Err(format!(
"Enabling both `packed-stack` and `backchain` attributes is incompatible with the hard-float ABI. Enable soft-float ABI to use these attributes."
));
}
}

Ok(())
Expand Down
12 changes: 7 additions & 5 deletions compiler/rustc_target/src/target_features.rs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that further up this file it still says

("soft-float", Forbidden { reason: "currently unsupported ABI-configuration feature" }, &[]),

So using the soft-float target feature still doesn't work even with this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On that note, it would be great to have codegen tests for these kind of flags.

Original file line number Diff line number Diff line change
Expand Up @@ -1211,11 +1211,13 @@ impl Target {
}
}
Arch::S390x => {
// We don't currently support a softfloat target on this architecture.
// As usual, we have to reject swapping the `soft-float` target feature.
// The "vector" target feature does not affect the ABI for floats
// because the vector and float registers overlap.
FeatureConstraints { required: &[], incompatible: &["soft-float"] }
// On s390x only the hard-float ABI is valid. However for kernel compilation we need to
// allow soft-float if and only if the ABI is explicitly set to soft-float.
Comment on lines +1214 to +1215
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this refer to the linux kernel? Also I feel like this mixes up the SoftFloat ABI and the soft-float feature, maybe you can clarify which way the implication goes?

if matches!(self.abi, Abi::SoftFloat) {
Copy link
Member

@RalfJung RalfJung Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.abi is just used for cfg(target_abi), it doesn't actually control the ABI.

It looks like s390x is just as bad as x86 when it comes to ABI handling so the logic should probably be similar?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is only one valid abi on s390x. This ABI uses hard-float.

The idea is that soft-floatremains incompatible unless the user explicitly requests to use the soft-float abi(e.g.1). This will not change the abi, as there is no other ABI specified. And to my knowledge there wont be a soft-float abi specified that really could be used by llvm.

It is used as a gate, so if you want to use soft-float you also have to explicitly change the ABI. And make it clear that this code is incompatible with the normal code.

Footnotes

  1. https://github.com/torvalds/linux/compare/master...fneddy:linux:add_rustc_s390x#diff-8b2b79dc9fe8130845984440e8df685c928623dfe1ebd12fe937efe4ab352aa9R267

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not change the abi, as there is no other ABI specified.

What exactly do you mean by this - floats still get passed in vregs even with soft-float? What does the flag do then?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There might only be one official ABI, but the soft-float ABI is real and we're not going to pretend that it isn't. The soft-float ABI is whatever LLVM does to pass float args across function barriers when the soft-float target feature is on. So there might be no specification for such an ABI, but that doesn't stop LLVM from using it.

That's what happened on x86, anyway. I suspect it is similar on s390x.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so if you want to use soft-float you also have to explicitly change the ABI.

Exactly. But self.abi does not change the ABI, it just tells cfg what the ABI is. llvm_abiname, llvm_floatabi, and rustc_abi change the ABI.

(Well, that's not entirely true. self.abi actually is used in some places in the ABI adjustment logic. It's all a bit messy unfortunately...)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fneddy I assume that by saying there is only "one" "valid" ABI, you may be trying to say something like "the soft-float ABI is not required to be stable, as it is an implementation detail of the (Linux?) kernel, which is allowed to have an unstable ABI that changes from version to version"? If so, that is not something very important to us here. That describes the situation for Rust too.

For the Rust compiler's purposes, all that matters is that an ABI can be used by anything for an external call. Sometimes Linux code calls across kernel object boundaries, and sometimes Rust code calls across object boundaries, too. They both manage, despite the need to recompile everything per-version. Stability between compiler or kernel versions is not a required component for us to care about an ABI.

Copy link
Member

@workingjubilee workingjubilee Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...it does technically mean that any Rust target tuple supported since around 2015 has at least 3652... eh, 3660? Rust ABIs. "Legally" speaking, of course, we aren't changing every target's code literally every night.

FeatureConstraints { required: &["soft-float"], incompatible: &[] }
} else {
FeatureConstraints { required: &[], incompatible: &["soft-float"] }
}
}
_ => NOTHING,
}
Expand Down
6 changes: 6 additions & 0 deletions src/doc/rustc/src/codegen-options/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,12 @@ one of the following values:
If not specified, overflow checks are enabled if
[debug-assertions](#debug-assertions) are enabled, disabled otherwise.

## packed-stack

This flag enables packed StackFrames on s390x. Enabling both `packed-stack` and
`backchain` attributes is incompatible with the default hard-float ABI.
Enable soft-float ABI to use these attributes.

## panic

This option lets you control what happens when the code panics.
Expand Down
Loading