Translate the small integer arguments to i32 or i64 with the appropriate extend and ireduce instructions.
96 lines
3.0 KiB
Rust
96 lines
3.0 KiB
Rust
//! RISC-V ABI implementation.
|
|
//!
|
|
//! This module implements the RISC-V calling convention through the primary `legalize_signature()`
|
|
//! entry point.
|
|
//!
|
|
//! This doesn't support the soft-float ABI at the moment.
|
|
|
|
use abi::{ArgAction, ValueConversion, ArgAssigner, legalize_args};
|
|
use ir::{Signature, Type, ArgumentType, ArgumentLoc, ArgumentExtension};
|
|
use isa::riscv::registers::{GPR, FPR};
|
|
use settings as shared_settings;
|
|
|
|
struct Args {
|
|
pointer_bits: u16,
|
|
pointer_bytes: u32,
|
|
pointer_type: Type,
|
|
regs: u32,
|
|
offset: u32,
|
|
}
|
|
|
|
impl Args {
|
|
fn new(bits: u16) -> Args {
|
|
Args {
|
|
pointer_bits: bits,
|
|
pointer_bytes: bits as u32 / 8,
|
|
pointer_type: Type::int(bits).unwrap(),
|
|
regs: 0,
|
|
offset: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ArgAssigner for Args {
|
|
fn assign(&mut self, arg: &ArgumentType) -> ArgAction {
|
|
fn align(value: u32, to: u32) -> u32 {
|
|
(value + to - 1) & !(to - 1)
|
|
}
|
|
|
|
let ty = arg.value_type;
|
|
|
|
// Check for a legal type.
|
|
// RISC-V doesn't have SIMD at all, so break all vectors down.
|
|
if !ty.is_scalar() {
|
|
return ArgAction::Convert(ValueConversion::VectorSplit);
|
|
}
|
|
|
|
// Large integers and booleans are broken down to fit in a register.
|
|
if !ty.is_float() && ty.bits() > self.pointer_bits {
|
|
// Align registers and stack to a multiple of two pointers.
|
|
self.regs = align(self.regs, 2);
|
|
self.offset = align(self.offset, 2 * self.pointer_bytes);
|
|
return ArgAction::Convert(ValueConversion::IntSplit);
|
|
}
|
|
|
|
// Small integers are extended to the size of a pointer register.
|
|
if ty.is_int() && ty.bits() < self.pointer_bits {
|
|
match arg.extension {
|
|
ArgumentExtension::None => {}
|
|
ArgumentExtension::Uext => {
|
|
return ArgAction::Convert(ValueConversion::Uext(self.pointer_type))
|
|
}
|
|
ArgumentExtension::Sext => {
|
|
return ArgAction::Convert(ValueConversion::Sext(self.pointer_type))
|
|
}
|
|
}
|
|
}
|
|
|
|
if self.regs < 8 {
|
|
// Assign to a register.
|
|
let reg = if ty.is_float() {
|
|
FPR.unit(10 + self.regs as usize)
|
|
} else {
|
|
GPR.unit(10 + self.regs as usize)
|
|
};
|
|
self.regs += 1;
|
|
ArgAction::Assign(ArgumentLoc::Reg(reg))
|
|
} else {
|
|
// Assign a stack location.
|
|
let loc = ArgumentLoc::Stack(self.offset);
|
|
self.offset += self.pointer_bytes;
|
|
ArgAction::Assign(loc)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Legalize `sig` for RISC-V.
|
|
pub fn legalize_signature(sig: &mut Signature, flags: &shared_settings::Flags) {
|
|
let bits = if flags.is_64bit() { 64 } else { 32 };
|
|
|
|
let mut args = Args::new(bits);
|
|
legalize_args(&mut sig.argument_types, &mut args);
|
|
|
|
let mut rets = Args::new(bits);
|
|
legalize_args(&mut sig.return_types, &mut rets);
|
|
}
|