Skip to content

Commit 8fbde92

Browse files
committed
Implement SystemV struct argument passing
1 parent cca558c commit 8fbde92

File tree

15 files changed

+298
-50
lines changed

15 files changed

+298
-50
lines changed

cranelift/codegen/meta/src/cdsl/types.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,8 @@ impl fmt::Debug for VectorType {
407407
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
408408
pub(crate) enum SpecialType {
409409
Flag(shared_types::Flag),
410+
// FIXME remove once the old style backends are removed.
411+
StructArgument,
410412
}
411413

412414
impl SpecialType {
@@ -421,13 +423,17 @@ impl SpecialType {
421423
"CPU flags representing the result of a floating point comparison. These
422424
flags can be tested with a :type:`floatcc` condition code.",
423425
),
426+
SpecialType::StructArgument => {
427+
String::from("After legalization sarg__ arguments will get this type.")
428+
}
424429
}
425430
}
426431

427432
/// Return the number of bits in a lane.
428433
pub fn lane_bits(self) -> u64 {
429434
match self {
430435
SpecialType::Flag(_) => 0,
436+
SpecialType::StructArgument => 0,
431437
}
432438
}
433439

@@ -436,6 +442,7 @@ impl SpecialType {
436442
match self {
437443
SpecialType::Flag(shared_types::Flag::IFlags) => 1,
438444
SpecialType::Flag(shared_types::Flag::FFlags) => 2,
445+
SpecialType::StructArgument => 3,
439446
}
440447
}
441448
}
@@ -445,6 +452,7 @@ impl fmt::Display for SpecialType {
445452
match *self {
446453
SpecialType::Flag(shared_types::Flag::IFlags) => write!(f, "iflags"),
447454
SpecialType::Flag(shared_types::Flag::FFlags) => write!(f, "fflags"),
455+
SpecialType::StructArgument => write!(f, "sarg__"),
448456
}
449457
}
450458
}
@@ -456,6 +464,7 @@ impl fmt::Debug for SpecialType {
456464
"{}",
457465
match *self {
458466
SpecialType::Flag(_) => format!("FlagsType({})", self),
467+
SpecialType::StructArgument => format!("StructArgument"),
459468
}
460469
)
461470
}
@@ -469,12 +478,14 @@ impl From<shared_types::Flag> for SpecialType {
469478

470479
pub(crate) struct SpecialTypeIterator {
471480
flag_iter: shared_types::FlagIterator,
481+
done: bool,
472482
}
473483

474484
impl SpecialTypeIterator {
475485
fn new() -> Self {
476486
Self {
477487
flag_iter: shared_types::FlagIterator::new(),
488+
done: false,
478489
}
479490
}
480491
}
@@ -485,7 +496,12 @@ impl Iterator for SpecialTypeIterator {
485496
if let Some(f) = self.flag_iter.next() {
486497
Some(SpecialType::from(f))
487498
} else {
488-
None
499+
if !self.done {
500+
self.done = true;
501+
Some(SpecialType::StructArgument)
502+
} else {
503+
None
504+
}
489505
}
490506
}
491507
}

cranelift/codegen/meta/src/isa/x86/encodings.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ fn define_moves(e: &mut PerCpuModeEncodings, shared_defs: &SharedDefinitions, r:
439439
let sextend = shared.by_name("sextend");
440440
let set_pinned_reg = shared.by_name("set_pinned_reg");
441441
let uextend = shared.by_name("uextend");
442+
let dummy_sarg__ = shared.by_name("dummy_sarg__");
442443

443444
// Shorthands for recipes.
444445
let rec_copysp = r.template("copysp");
@@ -456,6 +457,7 @@ fn define_moves(e: &mut PerCpuModeEncodings, shared_defs: &SharedDefinitions, r:
456457
let rec_umr_reg_to_ssa = r.template("umr_reg_to_ssa");
457458
let rec_urm_noflags = r.template("urm_noflags");
458459
let rec_urm_noflags_abcd = r.template("urm_noflags_abcd");
460+
let rec_dummy_sarg__ = r.recipe("dummy_sarg__");
459461

460462
// The pinned reg is fixed to a certain value entirely user-controlled, so it generates nothing!
461463
e.enc64_rec(get_pinned_reg.bind(I64), rec_get_pinned_reg, 0);
@@ -721,6 +723,8 @@ fn define_moves(e: &mut PerCpuModeEncodings, shared_defs: &SharedDefinitions, r:
721723
copy_to_ssa.bind(F32),
722724
rec_furm_reg_to_ssa.opcodes(&MOVSS_LOAD),
723725
);
726+
727+
e.enc_32_64_rec(dummy_sarg__, rec_dummy_sarg__, 0);
724728
}
725729

726730
#[inline(never)]

cranelift/codegen/meta/src/isa/x86/recipes.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,12 @@ pub(crate) fn define<'shared>(
12701270
);
12711271
}
12721272

1273+
recipes.add_recipe(
1274+
EncodingRecipeBuilder::new("dummy_sarg__", &formats.nullary, 0)
1275+
.operands_out(vec![Stack::new(gpr)])
1276+
.emit(""),
1277+
);
1278+
12731279
// XX+rd id with Abs4 function relocation.
12741280
recipes.add_template_recipe(
12751281
EncodingRecipeBuilder::new("fnaddr4", &formats.func_addr, 4)

cranelift/codegen/meta/src/shared/instructions.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,6 +1835,31 @@ pub(crate) fn define(
18351835
.can_load(true),
18361836
);
18371837

1838+
let Sarg = &TypeVar::new(
1839+
"Sarg",
1840+
"Any scalar or vector type with as most 128 lanes",
1841+
TypeSetBuilder::new()
1842+
.specials(vec![crate::cdsl::types::SpecialType::StructArgument])
1843+
.build(),
1844+
);
1845+
let sarg__ = &Operand::new("sarg__", Sarg);
1846+
1847+
// FIXME remove once the old style codegen backends are removed.
1848+
ig.push(
1849+
Inst::new(
1850+
"dummy_sarg__",
1851+
r#"
1852+
This creates a sarg__
1853+
1854+
This instruction is internal and should not be created by
1855+
Cranelift users.
1856+
"#,
1857+
&formats.nullary,
1858+
)
1859+
.operands_in(vec![])
1860+
.operands_out(vec![sarg__]),
1861+
);
1862+
18381863
let src = &Operand::new("src", &imm.regunit);
18391864
let dst = &Operand::new("dst", &imm.regunit);
18401865

cranelift/codegen/src/abi.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ pub enum ArgAction {
1818
/// Assign the argument to the given location.
1919
Assign(ArgumentLoc),
2020

21+
/// Assign the argument to the given location and change the type to the specified type.
22+
/// This is used by [`ArgumentPurpose::StructArgument`].
23+
AssignAndChangeType(ArgumentLoc, Type),
24+
2125
/// Convert the argument, then call again.
2226
///
2327
/// This action can split an integer type into two smaller integer arguments, or it can split a
@@ -119,6 +123,13 @@ pub fn legalize_args<AA: ArgAssigner>(args: &[AbiParam], aa: &mut AA) -> Option<
119123
args.to_mut()[argno].location = loc;
120124
argno += 1;
121125
}
126+
// Assign argument to a location, change type to `INVALID` and move on to the next one.
127+
ArgAction::AssignAndChangeType(loc, ty) => {
128+
let arg = &mut args.to_mut()[argno];
129+
arg.location = loc;
130+
arg.value_type = ty;
131+
argno += 1;
132+
}
122133
// Split this argument into two smaller ones. Then revisit both.
123134
ArgAction::Convert(conv) => {
124135
debug_assert!(

cranelift/codegen/src/ir/extfunc.rs

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@ pub enum ArgumentPurpose {
276276
/// A normal user program value passed to or from a function.
277277
Normal,
278278

279+
/// A C struct passed as argument.
280+
StructArgument(u32),
281+
279282
/// Struct return pointer.
280283
///
281284
/// When a function needs to return more data than will fit in registers, the caller passes a
@@ -328,21 +331,19 @@ pub enum ArgumentPurpose {
328331
StackLimit,
329332
}
330333

331-
/// Text format names of the `ArgumentPurpose` variants.
332-
static PURPOSE_NAMES: [&str; 8] = [
333-
"normal",
334-
"sret",
335-
"link",
336-
"fp",
337-
"csr",
338-
"vmctx",
339-
"sigid",
340-
"stack_limit",
341-
];
342-
343334
impl fmt::Display for ArgumentPurpose {
344335
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
345-
f.write_str(PURPOSE_NAMES[*self as usize])
336+
f.write_str(match self {
337+
Self::Normal => "normal",
338+
Self::StructArgument(size) => return write!(f, "sarg({})", size),
339+
Self::StructReturn => "sret",
340+
Self::Link => "link",
341+
Self::FramePointer => "fp",
342+
Self::CalleeSaved => "csr",
343+
Self::VMContext => "vmctx",
344+
Self::SignatureId => "sigid",
345+
Self::StackLimit => "stack_limit",
346+
})
346347
}
347348
}
348349

@@ -358,6 +359,13 @@ impl FromStr for ArgumentPurpose {
358359
"vmctx" => Ok(Self::VMContext),
359360
"sigid" => Ok(Self::SignatureId),
360361
"stack_limit" => Ok(Self::StackLimit),
362+
_ if s.starts_with("sarg(") => {
363+
if !s.ends_with(")") {
364+
return Err(());
365+
}
366+
let size: u32 = s["sarg(".len()..s.len() - 1].parse().map_err(|_| ())?;
367+
Ok(Self::StructArgument(size))
368+
}
361369
_ => Err(()),
362370
}
363371
}
@@ -430,16 +438,17 @@ mod tests {
430438
#[test]
431439
fn argument_purpose() {
432440
let all_purpose = [
433-
ArgumentPurpose::Normal,
434-
ArgumentPurpose::StructReturn,
435-
ArgumentPurpose::Link,
436-
ArgumentPurpose::FramePointer,
437-
ArgumentPurpose::CalleeSaved,
438-
ArgumentPurpose::VMContext,
439-
ArgumentPurpose::SignatureId,
440-
ArgumentPurpose::StackLimit,
441+
(ArgumentPurpose::Normal, "normal"),
442+
(ArgumentPurpose::StructReturn, "sret"),
443+
(ArgumentPurpose::Link, "link"),
444+
(ArgumentPurpose::FramePointer, "fp"),
445+
(ArgumentPurpose::CalleeSaved, "csr"),
446+
(ArgumentPurpose::VMContext, "vmctx"),
447+
(ArgumentPurpose::SignatureId, "sigid"),
448+
(ArgumentPurpose::StackLimit, "stack_limit"),
449+
(ArgumentPurpose::StructArgument(42), "sarg(42)"),
441450
];
442-
for (&e, &n) in all_purpose.iter().zip(PURPOSE_NAMES.iter()) {
451+
for &(e, n) in &all_purpose {
443452
assert_eq!(e.to_string(), n);
444453
assert_eq!(Ok(e), n.parse());
445454
}

cranelift/codegen/src/ir/stackslot.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,12 @@ impl StackSlots {
287287

288288
/// Create a stack slot representing an incoming function argument.
289289
pub fn make_incoming_arg(&mut self, ty: Type, offset: StackOffset) -> StackSlot {
290-
let mut data = StackSlotData::new(StackSlotKind::IncomingArg, ty.bytes());
290+
self.make_incoming_struct_arg(ty.bytes(), offset)
291+
}
292+
293+
/// Create a stack slot representing an incoming struct function argument.
294+
pub fn make_incoming_struct_arg(&mut self, size: u32, offset: StackOffset) -> StackSlot {
295+
let mut data = StackSlotData::new(StackSlotKind::IncomingArg, size);
291296
debug_assert!(offset <= StackOffset::max_value() - data.size as StackOffset);
292297
data.offset = Some(offset);
293298
self.push(data)
@@ -301,8 +306,11 @@ impl StackSlots {
301306
/// The requested offset is relative to this function's stack pointer immediately before making
302307
/// the call.
303308
pub fn get_outgoing_arg(&mut self, ty: Type, offset: StackOffset) -> StackSlot {
304-
let size = ty.bytes();
309+
self.get_outgoing_struct_arg(ty.bytes(), offset)
310+
}
305311

312+
/// FIXME
313+
pub fn get_outgoing_struct_arg(&mut self, size: u32, offset: StackOffset) -> StackSlot {
306314
// Look for an existing outgoing stack slot with the same offset and size.
307315
let inspos = match self.outgoing.binary_search_by_key(&(offset, size), |&ss| {
308316
(self[ss].offset.unwrap(), self[ss].size)

cranelift/codegen/src/ir/types.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ impl Display for Type {
329329
f.write_str(match *self {
330330
IFLAGS => "iflags",
331331
FFLAGS => "fflags",
332+
SARG__ => "sarg__",
332333
INVALID => panic!("INVALID encountered"),
333334
_ => panic!("Unknown Type(0x{:x})", self.0),
334335
})

cranelift/codegen/src/isa/aarch64/lower_inst.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2069,6 +2069,8 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
20692069
panic!("x86-specific opcode in supposedly arch-neutral IR!");
20702070
}
20712071

2072+
Opcode::DummySarg => unreachable!(),
2073+
20722074
Opcode::AvgRound => unimplemented!(),
20732075
Opcode::TlsValue => unimplemented!(),
20742076
}

cranelift/codegen/src/isa/x86/abi.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,19 @@ impl Args {
108108

109109
impl ArgAssigner for Args {
110110
fn assign(&mut self, arg: &AbiParam) -> ArgAction {
111+
if let ArgumentPurpose::StructArgument(size) = arg.purpose {
112+
if self.call_conv != CallConv::SystemV {
113+
panic!(
114+
"The sarg argument purpose is not yet implemented for non-systemv call conv {:?}",
115+
self.call_conv,
116+
);
117+
}
118+
let loc = ArgumentLoc::Stack(self.offset as i32);
119+
self.offset += size;
120+
debug_assert!(self.offset <= i32::MAX as u32);
121+
return ArgAction::AssignAndChangeType(loc, types::SARG__);
122+
}
123+
111124
let ty = arg.value_type;
112125

113126
if ty.bits() > u16::from(self.pointer_bits) {

0 commit comments

Comments
 (0)