-
Notifications
You must be signed in to change notification settings - Fork 13.4k
implement va_arg
for x86_64 systemv
#141538
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
This PR modifies cc @jieyouxu |
5d64c38
to
52601bf
Compare
This comment has been minimized.
This comment has been minimized.
52601bf
to
ac051ae
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some nits and general questions
ac051ae
to
584035c
Compare
This now supports structs like struct B(i32, i32);
struct C(i64, i64, i64);
struct D(f64, i64);
struct E(i64, f64);
struct F(f64, f64); It however does not support #[repr(C)]
struct Empty;
impl Copy for Empty {}
#[repr(C)]
struct Cursed([Empty; 8], i32); Because rust passes this as |
@rustbot ready |
the cause is this rust/compiler/rustc_abi/src/layout.rs Lines 1373 to 1396 in 95a2212
when I disable that |
dcdc645
to
6424fbe
Compare
This comment has been minimized.
This comment has been minimized.
It's fine if it's buggy for non-scalars, it just felt slightly silly to write it in the way that can support at least some structs and then not support any structs. |
I added this bit of logic and now it actually does work correctly for that struct // Peel off any newtype wrappers.
let layout = {
let mut layout = bx.cx.layout_of(target_ty);
while let Some((_, inner)) = layout.non_1zst_field(bx.cx) {
layout = inner;
}
layout
}; |
Does it support tulple that mix 8bit 32bit 64bit or different length type |
Currently, arguments to So, the testing with structs is just to verify the implementation, because the standard library currently does not allow The exact size of the fields does not matter, because they all get 8 bytes of space: // l->gp_offset = l->gp_offset + num_gp * 8
if num_gp_registers > 0 {
let offset = bx.const_u32(num_gp_registers * 8);
let sum = bx.add(gp_offset_v, offset);
bx.store(sum, gp_offset_ptr, Align::from_bytes(8).unwrap());
} |
Yeah, I'm not blocking this on being correct for all structs, I just kinda wanted to see us bother to land something that could be bugfixed, essentially. |
6424fbe
to
7daa926
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rebased and turned some inbounds_gep
into inbounds_ptradd
. I think this is good to go?
✌️ @folkertdev, you can now approve this pull request! If @tgross35 told you to " |
implement `va_arg` for x86_64 systemv tracking issue: #44930 Turns out LLVM's `va_arg` is also unreliable for this target. llvm/llvm-project#141361 So, like clang, we implement our own. I used - the spec at https://gitlab.com/x86-psABIs/x86-64-ABI - the clang implementation at https://github.com/llvm/llvm-project/blob/9a440f84773c56d3803f330774acb2b4f471d5b4/clang/lib/CodeGen/Targets/X86.cpp#L3041 We can take a bunch of shortcuts because the return type of `va_list` must implement `VaArgSafe`. I also extended some of the tests, because up to 11 floats can be stored in the `reg_safe_area` for this calling convention. r? `@workingjubilee` `@rustbot` label +F-c_variadic try-job: x86_64-apple-1
☀️ Try build successful - checks-actions |
Seems like we're good. |
Yes, I think so. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
while scrutinizing this more closely before the final approval I came up with some questions that may need me to re-reference the layout code to answer...
47f694a
to
11d1c33
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
r=me after review addressed
// Copy into a temporary if the type is more aligned than the register save area. | ||
copy_to_temporary_if_more_aligned(bx, reg_addr, layout) | ||
} | ||
Primitive::Float(_) => bx.inbounds_ptradd(reg_save_area_v, fp_offset_v), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm. should already be aligned to 16 bytes so we should handle f128 fine when that becomes relevant? right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly. Similarly SIMD types are stored in the same area, and always with an alignment of 16.
} | ||
Primitive::Float(_) => bx.inbounds_ptradd(reg_save_area_v, fp_offset_v), | ||
}, | ||
BackendRepr::ScalarPair(scalar1, scalar2) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems fine
Turns out LLVM's `va_arg` is also unreliable for this target, so we need our own implementation.
11d1c33
to
94cc726
Compare
cool @bors r+ |
tracking issue: #44930
Turns out LLVM's
va_arg
is also unreliable for this target.llvm/llvm-project#141361
So, like clang, we implement our own. I used
We can take a bunch of shortcuts because the return type of
va_list
must implementVaArgSafe
. I also extended some of the tests, because up to 11 floats can be stored in thereg_safe_area
for this calling convention.r? @workingjubilee
@rustbot label +F-c_variadic
try-job: x86_64-apple-1