Skip to content

Commit

Permalink
Implement SystemV struct argument passing
Browse files Browse the repository at this point in the history
  • Loading branch information
bjorn3 committed Jun 29, 2020
1 parent cca558c commit 8fbde92
Show file tree
Hide file tree
Showing 15 changed files with 298 additions and 50 deletions.
18 changes: 17 additions & 1 deletion cranelift/codegen/meta/src/cdsl/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,8 @@ impl fmt::Debug for VectorType {
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum SpecialType {
Flag(shared_types::Flag),
// FIXME remove once the old style backends are removed.
StructArgument,
}

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

/// Return the number of bits in a lane.
pub fn lane_bits(self) -> u64 {
match self {
SpecialType::Flag(_) => 0,
SpecialType::StructArgument => 0,
}
}

Expand All @@ -436,6 +442,7 @@ impl SpecialType {
match self {
SpecialType::Flag(shared_types::Flag::IFlags) => 1,
SpecialType::Flag(shared_types::Flag::FFlags) => 2,
SpecialType::StructArgument => 3,
}
}
}
Expand All @@ -445,6 +452,7 @@ impl fmt::Display for SpecialType {
match *self {
SpecialType::Flag(shared_types::Flag::IFlags) => write!(f, "iflags"),
SpecialType::Flag(shared_types::Flag::FFlags) => write!(f, "fflags"),
SpecialType::StructArgument => write!(f, "sarg__"),
}
}
}
Expand All @@ -456,6 +464,7 @@ impl fmt::Debug for SpecialType {
"{}",
match *self {
SpecialType::Flag(_) => format!("FlagsType({})", self),
SpecialType::StructArgument => format!("StructArgument"),
}
)
}
Expand All @@ -469,12 +478,14 @@ impl From<shared_types::Flag> for SpecialType {

pub(crate) struct SpecialTypeIterator {
flag_iter: shared_types::FlagIterator,
done: bool,
}

impl SpecialTypeIterator {
fn new() -> Self {
Self {
flag_iter: shared_types::FlagIterator::new(),
done: false,
}
}
}
Expand All @@ -485,7 +496,12 @@ impl Iterator for SpecialTypeIterator {
if let Some(f) = self.flag_iter.next() {
Some(SpecialType::from(f))
} else {
None
if !self.done {
self.done = true;
Some(SpecialType::StructArgument)
} else {
None
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions cranelift/codegen/meta/src/isa/x86/encodings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ fn define_moves(e: &mut PerCpuModeEncodings, shared_defs: &SharedDefinitions, r:
let sextend = shared.by_name("sextend");
let set_pinned_reg = shared.by_name("set_pinned_reg");
let uextend = shared.by_name("uextend");
let dummy_sarg__ = shared.by_name("dummy_sarg__");

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

// The pinned reg is fixed to a certain value entirely user-controlled, so it generates nothing!
e.enc64_rec(get_pinned_reg.bind(I64), rec_get_pinned_reg, 0);
Expand Down Expand Up @@ -721,6 +723,8 @@ fn define_moves(e: &mut PerCpuModeEncodings, shared_defs: &SharedDefinitions, r:
copy_to_ssa.bind(F32),
rec_furm_reg_to_ssa.opcodes(&MOVSS_LOAD),
);

e.enc_32_64_rec(dummy_sarg__, rec_dummy_sarg__, 0);
}

#[inline(never)]
Expand Down
6 changes: 6 additions & 0 deletions cranelift/codegen/meta/src/isa/x86/recipes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,12 @@ pub(crate) fn define<'shared>(
);
}

recipes.add_recipe(
EncodingRecipeBuilder::new("dummy_sarg__", &formats.nullary, 0)
.operands_out(vec![Stack::new(gpr)])
.emit(""),
);

// XX+rd id with Abs4 function relocation.
recipes.add_template_recipe(
EncodingRecipeBuilder::new("fnaddr4", &formats.func_addr, 4)
Expand Down
25 changes: 25 additions & 0 deletions cranelift/codegen/meta/src/shared/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1835,6 +1835,31 @@ pub(crate) fn define(
.can_load(true),
);

let Sarg = &TypeVar::new(
"Sarg",
"Any scalar or vector type with as most 128 lanes",
TypeSetBuilder::new()
.specials(vec![crate::cdsl::types::SpecialType::StructArgument])
.build(),
);
let sarg__ = &Operand::new("sarg__", Sarg);

// FIXME remove once the old style codegen backends are removed.
ig.push(
Inst::new(
"dummy_sarg__",
r#"
This creates a sarg__
This instruction is internal and should not be created by
Cranelift users.
"#,
&formats.nullary,
)
.operands_in(vec![])
.operands_out(vec![sarg__]),
);

let src = &Operand::new("src", &imm.regunit);
let dst = &Operand::new("dst", &imm.regunit);

Expand Down
11 changes: 11 additions & 0 deletions cranelift/codegen/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ pub enum ArgAction {
/// Assign the argument to the given location.
Assign(ArgumentLoc),

/// Assign the argument to the given location and change the type to the specified type.
/// This is used by [`ArgumentPurpose::StructArgument`].
AssignAndChangeType(ArgumentLoc, Type),

/// Convert the argument, then call again.
///
/// This action can split an integer type into two smaller integer arguments, or it can split a
Expand Down Expand Up @@ -119,6 +123,13 @@ pub fn legalize_args<AA: ArgAssigner>(args: &[AbiParam], aa: &mut AA) -> Option<
args.to_mut()[argno].location = loc;
argno += 1;
}
// Assign argument to a location, change type to `INVALID` and move on to the next one.
ArgAction::AssignAndChangeType(loc, ty) => {
let arg = &mut args.to_mut()[argno];
arg.location = loc;
arg.value_type = ty;
argno += 1;
}
// Split this argument into two smaller ones. Then revisit both.
ArgAction::Convert(conv) => {
debug_assert!(
Expand Down
53 changes: 31 additions & 22 deletions cranelift/codegen/src/ir/extfunc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ pub enum ArgumentPurpose {
/// A normal user program value passed to or from a function.
Normal,

/// A C struct passed as argument.
StructArgument(u32),

/// Struct return pointer.
///
/// When a function needs to return more data than will fit in registers, the caller passes a
Expand Down Expand Up @@ -328,21 +331,19 @@ pub enum ArgumentPurpose {
StackLimit,
}

/// Text format names of the `ArgumentPurpose` variants.
static PURPOSE_NAMES: [&str; 8] = [
"normal",
"sret",
"link",
"fp",
"csr",
"vmctx",
"sigid",
"stack_limit",
];

impl fmt::Display for ArgumentPurpose {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(PURPOSE_NAMES[*self as usize])
f.write_str(match self {
Self::Normal => "normal",
Self::StructArgument(size) => return write!(f, "sarg({})", size),
Self::StructReturn => "sret",
Self::Link => "link",
Self::FramePointer => "fp",
Self::CalleeSaved => "csr",
Self::VMContext => "vmctx",
Self::SignatureId => "sigid",
Self::StackLimit => "stack_limit",
})
}
}

Expand All @@ -358,6 +359,13 @@ impl FromStr for ArgumentPurpose {
"vmctx" => Ok(Self::VMContext),
"sigid" => Ok(Self::SignatureId),
"stack_limit" => Ok(Self::StackLimit),
_ if s.starts_with("sarg(") => {
if !s.ends_with(")") {
return Err(());
}
let size: u32 = s["sarg(".len()..s.len() - 1].parse().map_err(|_| ())?;
Ok(Self::StructArgument(size))
}
_ => Err(()),
}
}
Expand Down Expand Up @@ -430,16 +438,17 @@ mod tests {
#[test]
fn argument_purpose() {
let all_purpose = [
ArgumentPurpose::Normal,
ArgumentPurpose::StructReturn,
ArgumentPurpose::Link,
ArgumentPurpose::FramePointer,
ArgumentPurpose::CalleeSaved,
ArgumentPurpose::VMContext,
ArgumentPurpose::SignatureId,
ArgumentPurpose::StackLimit,
(ArgumentPurpose::Normal, "normal"),
(ArgumentPurpose::StructReturn, "sret"),
(ArgumentPurpose::Link, "link"),
(ArgumentPurpose::FramePointer, "fp"),
(ArgumentPurpose::CalleeSaved, "csr"),
(ArgumentPurpose::VMContext, "vmctx"),
(ArgumentPurpose::SignatureId, "sigid"),
(ArgumentPurpose::StackLimit, "stack_limit"),
(ArgumentPurpose::StructArgument(42), "sarg(42)"),
];
for (&e, &n) in all_purpose.iter().zip(PURPOSE_NAMES.iter()) {
for &(e, n) in &all_purpose {
assert_eq!(e.to_string(), n);
assert_eq!(Ok(e), n.parse());
}
Expand Down
12 changes: 10 additions & 2 deletions cranelift/codegen/src/ir/stackslot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,12 @@ impl StackSlots {

/// Create a stack slot representing an incoming function argument.
pub fn make_incoming_arg(&mut self, ty: Type, offset: StackOffset) -> StackSlot {
let mut data = StackSlotData::new(StackSlotKind::IncomingArg, ty.bytes());
self.make_incoming_struct_arg(ty.bytes(), offset)
}

/// Create a stack slot representing an incoming struct function argument.
pub fn make_incoming_struct_arg(&mut self, size: u32, offset: StackOffset) -> StackSlot {
let mut data = StackSlotData::new(StackSlotKind::IncomingArg, size);
debug_assert!(offset <= StackOffset::max_value() - data.size as StackOffset);
data.offset = Some(offset);
self.push(data)
Expand All @@ -301,8 +306,11 @@ impl StackSlots {
/// The requested offset is relative to this function's stack pointer immediately before making
/// the call.
pub fn get_outgoing_arg(&mut self, ty: Type, offset: StackOffset) -> StackSlot {
let size = ty.bytes();
self.get_outgoing_struct_arg(ty.bytes(), offset)
}

/// FIXME
pub fn get_outgoing_struct_arg(&mut self, size: u32, offset: StackOffset) -> StackSlot {
// Look for an existing outgoing stack slot with the same offset and size.
let inspos = match self.outgoing.binary_search_by_key(&(offset, size), |&ss| {
(self[ss].offset.unwrap(), self[ss].size)
Expand Down
1 change: 1 addition & 0 deletions cranelift/codegen/src/ir/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ impl Display for Type {
f.write_str(match *self {
IFLAGS => "iflags",
FFLAGS => "fflags",
SARG__ => "sarg__",
INVALID => panic!("INVALID encountered"),
_ => panic!("Unknown Type(0x{:x})", self.0),
})
Expand Down
2 changes: 2 additions & 0 deletions cranelift/codegen/src/isa/aarch64/lower_inst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2069,6 +2069,8 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
panic!("x86-specific opcode in supposedly arch-neutral IR!");
}

Opcode::DummySarg => unreachable!(),

Opcode::AvgRound => unimplemented!(),
Opcode::TlsValue => unimplemented!(),
}
Expand Down
13 changes: 13 additions & 0 deletions cranelift/codegen/src/isa/x86/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,19 @@ impl Args {

impl ArgAssigner for Args {
fn assign(&mut self, arg: &AbiParam) -> ArgAction {
if let ArgumentPurpose::StructArgument(size) = arg.purpose {
if self.call_conv != CallConv::SystemV {
panic!(
"The sarg argument purpose is not yet implemented for non-systemv call conv {:?}",
self.call_conv,
);
}
let loc = ArgumentLoc::Stack(self.offset as i32);
self.offset += size;
debug_assert!(self.offset <= i32::MAX as u32);
return ArgAction::AssignAndChangeType(loc, types::SARG__);
}

let ty = arg.value_type;

if ty.bits() > u16::from(self.pointer_bits) {
Expand Down
Loading

0 comments on commit 8fbde92

Please sign in to comment.