Use the term "Function parameter" instead of "argument".
Rename the ArgumentType type to AbiParam since it describes the ABI characteristics of a parameter or return value, not just the value type. In Signature, rename members argument_types and return_types to "params" and "returns". Again, they are not just types. Fix a couple lingering references to "EBB arguments".
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
//! This module provides functions and data structures that are useful for implementing the
|
//! This module provides functions and data structures that are useful for implementing the
|
||||||
//! `TargetIsa::legalize_signature()` method.
|
//! `TargetIsa::legalize_signature()` method.
|
||||||
|
|
||||||
use ir::{ArgumentLoc, ArgumentType, ArgumentExtension, Type};
|
use ir::{ArgumentLoc, AbiParam, ArgumentExtension, Type};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
/// Legalization action to perform on a single argument or return value when converting a
|
/// Legalization action to perform on a single argument or return value when converting a
|
||||||
@@ -81,13 +81,13 @@ impl ValueConversion {
|
|||||||
/// This will be implemented by individual ISAs.
|
/// This will be implemented by individual ISAs.
|
||||||
pub trait ArgAssigner {
|
pub trait ArgAssigner {
|
||||||
/// Pick an assignment action for function argument (or return value) `arg`.
|
/// Pick an assignment action for function argument (or return value) `arg`.
|
||||||
fn assign(&mut self, arg: &ArgumentType) -> ArgAction;
|
fn assign(&mut self, arg: &AbiParam) -> ArgAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Legalize the arguments in `args` using the given argument assigner.
|
/// Legalize the arguments in `args` using the given argument assigner.
|
||||||
///
|
///
|
||||||
/// This function can be used for both arguments and return values.
|
/// This function can be used for both arguments and return values.
|
||||||
pub fn legalize_args<AA: ArgAssigner>(args: &mut Vec<ArgumentType>, aa: &mut AA) {
|
pub fn legalize_args<AA: ArgAssigner>(args: &mut Vec<AbiParam>, aa: &mut AA) {
|
||||||
// Iterate over the arguments.
|
// Iterate over the arguments.
|
||||||
// We may need to mutate the vector in place, so don't use a normal iterator, and clone the
|
// We may need to mutate the vector in place, so don't use a normal iterator, and clone the
|
||||||
// argument to avoid holding a reference.
|
// argument to avoid holding a reference.
|
||||||
@@ -108,7 +108,7 @@ pub fn legalize_args<AA: ArgAssigner>(args: &mut Vec<ArgumentType>, aa: &mut AA)
|
|||||||
}
|
}
|
||||||
// Split this argument into two smaller ones. Then revisit both.
|
// Split this argument into two smaller ones. Then revisit both.
|
||||||
ArgAction::Convert(conv) => {
|
ArgAction::Convert(conv) => {
|
||||||
let new_arg = ArgumentType {
|
let new_arg = AbiParam {
|
||||||
value_type: conv.apply(arg.value_type),
|
value_type: conv.apply(arg.value_type),
|
||||||
..arg
|
..arg
|
||||||
};
|
};
|
||||||
@@ -143,7 +143,7 @@ pub fn legalize_args<AA: ArgAssigner>(args: &mut Vec<ArgumentType>, aa: &mut AA)
|
|||||||
/// It may be necessary to call `legalize_abi_value` more than once for a given argument before the
|
/// It may be necessary to call `legalize_abi_value` more than once for a given argument before the
|
||||||
/// desired argument type appears. This will happen when a vector or integer type needs to be split
|
/// desired argument type appears. This will happen when a vector or integer type needs to be split
|
||||||
/// more than once, for example.
|
/// more than once, for example.
|
||||||
pub fn legalize_abi_value(have: Type, arg: &ArgumentType) -> ValueConversion {
|
pub fn legalize_abi_value(have: Type, arg: &AbiParam) -> ValueConversion {
|
||||||
let have_bits = have.bits();
|
let have_bits = have.bits();
|
||||||
let arg_bits = arg.value_type.bits();
|
let arg_bits = arg.value_type.bits();
|
||||||
|
|
||||||
@@ -186,11 +186,11 @@ pub fn legalize_abi_value(have: Type, arg: &ArgumentType) -> ValueConversion {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use ir::types;
|
use ir::types;
|
||||||
use ir::ArgumentType;
|
use ir::AbiParam;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn legalize() {
|
fn legalize() {
|
||||||
let mut arg = ArgumentType::new(types::I32);
|
let mut arg = AbiParam::new(types::I32);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
legalize_abi_value(types::I64X2, &arg),
|
legalize_abi_value(types::I64X2, &arg),
|
||||||
|
|||||||
@@ -463,10 +463,10 @@ impl DataFlowGraph {
|
|||||||
// Get the call signature if this is a function call.
|
// Get the call signature if this is a function call.
|
||||||
if let Some(sig) = self.call_signature(inst) {
|
if let Some(sig) = self.call_signature(inst) {
|
||||||
// Create result values corresponding to the call return types.
|
// Create result values corresponding to the call return types.
|
||||||
let var_results = self.signatures[sig].return_types.len();
|
let var_results = self.signatures[sig].returns.len();
|
||||||
total_results += var_results;
|
total_results += var_results;
|
||||||
for res_idx in 0..var_results {
|
for res_idx in 0..var_results {
|
||||||
let ty = self.signatures[sig].return_types[res_idx].value_type;
|
let ty = self.signatures[sig].returns[res_idx].value_type;
|
||||||
if let Some(Some(v)) = reuse.next() {
|
if let Some(Some(v)) = reuse.next() {
|
||||||
debug_assert_eq!(self.value_type(v), ty, "Reused {} is wrong type", ty);
|
debug_assert_eq!(self.value_type(v), ty, "Reused {} is wrong type", ty);
|
||||||
self.attach_result(inst, v);
|
self.attach_result(inst, v);
|
||||||
@@ -632,7 +632,7 @@ impl DataFlowGraph {
|
|||||||
// Not a fixed result, try to extract a return type from the call signature.
|
// Not a fixed result, try to extract a return type from the call signature.
|
||||||
self.call_signature(inst).and_then(|sigref| {
|
self.call_signature(inst).and_then(|sigref| {
|
||||||
self.signatures[sigref]
|
self.signatures[sigref]
|
||||||
.return_types
|
.returns
|
||||||
.get(result_idx - fixed_results)
|
.get(result_idx - fixed_results)
|
||||||
.map(|&arg| arg.value_type)
|
.map(|&arg| arg.value_type)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,17 +13,17 @@ use std::str::FromStr;
|
|||||||
|
|
||||||
/// Function signature.
|
/// Function signature.
|
||||||
///
|
///
|
||||||
/// The function signature describes the types of arguments and return values along with other
|
/// The function signature describes the types of formal parameters and return values along with
|
||||||
/// details that are needed to call a function correctly.
|
/// other details that are needed to call a function correctly.
|
||||||
///
|
///
|
||||||
/// A signature can optionally include ISA-specific ABI information which specifies exactly how
|
/// A signature can optionally include ISA-specific ABI information which specifies exactly how
|
||||||
/// arguments and return values are passed.
|
/// arguments and return values are passed.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Signature {
|
pub struct Signature {
|
||||||
/// Types of the arguments passed to the function.
|
/// The arguments passed to the function.
|
||||||
pub argument_types: Vec<ArgumentType>,
|
pub params: Vec<AbiParam>,
|
||||||
/// Types returned from the function.
|
/// Values returned from the function.
|
||||||
pub return_types: Vec<ArgumentType>,
|
pub returns: Vec<AbiParam>,
|
||||||
|
|
||||||
/// Calling convention.
|
/// Calling convention.
|
||||||
pub call_conv: CallConv,
|
pub call_conv: CallConv,
|
||||||
@@ -31,7 +31,7 @@ pub struct Signature {
|
|||||||
/// When the signature has been legalized to a specific ISA, this holds the size of the
|
/// When the signature has been legalized to a specific ISA, this holds the size of the
|
||||||
/// argument array on the stack. Before legalization, this is `None`.
|
/// argument array on the stack. Before legalization, this is `None`.
|
||||||
///
|
///
|
||||||
/// This can be computed from the legalized `argument_types` array as the maximum (offset plus
|
/// This can be computed from the legalized `params` array as the maximum (offset plus
|
||||||
/// byte size) of the `ArgumentLoc::Stack(offset)` argument.
|
/// byte size) of the `ArgumentLoc::Stack(offset)` argument.
|
||||||
pub argument_bytes: Option<u32>,
|
pub argument_bytes: Option<u32>,
|
||||||
}
|
}
|
||||||
@@ -40,8 +40,8 @@ impl Signature {
|
|||||||
/// Create a new blank signature.
|
/// Create a new blank signature.
|
||||||
pub fn new(call_conv: CallConv) -> Signature {
|
pub fn new(call_conv: CallConv) -> Signature {
|
||||||
Signature {
|
Signature {
|
||||||
argument_types: Vec::new(),
|
params: Vec::new(),
|
||||||
return_types: Vec::new(),
|
returns: Vec::new(),
|
||||||
call_conv,
|
call_conv,
|
||||||
argument_bytes: None,
|
argument_bytes: None,
|
||||||
}
|
}
|
||||||
@@ -49,18 +49,18 @@ impl Signature {
|
|||||||
|
|
||||||
/// Clear the signature so it is identical to a fresh one returned by `new()`.
|
/// Clear the signature so it is identical to a fresh one returned by `new()`.
|
||||||
pub fn clear(&mut self, call_conv: CallConv) {
|
pub fn clear(&mut self, call_conv: CallConv) {
|
||||||
self.argument_types.clear();
|
self.params.clear();
|
||||||
self.return_types.clear();
|
self.returns.clear();
|
||||||
self.call_conv = call_conv;
|
self.call_conv = call_conv;
|
||||||
self.argument_bytes = None;
|
self.argument_bytes = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the size of the stack arguments and mark signature as legalized.
|
/// Compute the size of the stack arguments and mark signature as legalized.
|
||||||
///
|
///
|
||||||
/// Even if there are no stack arguments, this will set `argument_types` to `Some(0)` instead
|
/// Even if there are no stack arguments, this will set `params` to `Some(0)` instead
|
||||||
/// of `None`. This indicates that the signature has been legalized.
|
/// of `None`. This indicates that the signature has been legalized.
|
||||||
pub fn compute_argument_bytes(&mut self) {
|
pub fn compute_argument_bytes(&mut self) {
|
||||||
let bytes = self.argument_types
|
let bytes = self.params
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|arg| match arg.location {
|
.filter_map(|arg| match arg.location {
|
||||||
ArgumentLoc::Stack(offset) if offset >= 0 => {
|
ArgumentLoc::Stack(offset) if offset >= 0 => {
|
||||||
@@ -77,22 +77,16 @@ impl Signature {
|
|||||||
DisplaySignature(self, regs.into())
|
DisplaySignature(self, regs.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find the index of a presumed unique special-purpose argument.
|
/// Find the index of a presumed unique special-purpose parameter.
|
||||||
pub fn special_arg_index(&self, purpose: ArgumentPurpose) -> Option<usize> {
|
pub fn special_param_index(&self, purpose: ArgumentPurpose) -> Option<usize> {
|
||||||
self.argument_types.iter().rposition(
|
self.params.iter().rposition(|arg| arg.purpose == purpose)
|
||||||
|arg| arg.purpose == purpose,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper type capable of displaying a `Signature` with correct register names.
|
/// Wrapper type capable of displaying a `Signature` with correct register names.
|
||||||
pub struct DisplaySignature<'a>(&'a Signature, Option<&'a RegInfo>);
|
pub struct DisplaySignature<'a>(&'a Signature, Option<&'a RegInfo>);
|
||||||
|
|
||||||
fn write_list(
|
fn write_list(f: &mut fmt::Formatter, args: &[AbiParam], regs: Option<&RegInfo>) -> fmt::Result {
|
||||||
f: &mut fmt::Formatter,
|
|
||||||
args: &[ArgumentType],
|
|
||||||
regs: Option<&RegInfo>,
|
|
||||||
) -> fmt::Result {
|
|
||||||
match args.split_first() {
|
match args.split_first() {
|
||||||
None => {}
|
None => {}
|
||||||
Some((first, rest)) => {
|
Some((first, rest)) => {
|
||||||
@@ -108,11 +102,11 @@ fn write_list(
|
|||||||
impl<'a> fmt::Display for DisplaySignature<'a> {
|
impl<'a> fmt::Display for DisplaySignature<'a> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
write_list(f, &self.0.argument_types, self.1)?;
|
write_list(f, &self.0.params, self.1)?;
|
||||||
write!(f, ")")?;
|
write!(f, ")")?;
|
||||||
if !self.0.return_types.is_empty() {
|
if !self.0.returns.is_empty() {
|
||||||
write!(f, " -> ")?;
|
write!(f, " -> ")?;
|
||||||
write_list(f, &self.0.return_types, self.1)?;
|
write_list(f, &self.0.returns, self.1)?;
|
||||||
}
|
}
|
||||||
write!(f, " {}", self.0.call_conv)
|
write!(f, " {}", self.0.call_conv)
|
||||||
}
|
}
|
||||||
@@ -124,12 +118,12 @@ impl fmt::Display for Signature {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function argument or return value type.
|
/// Function parameter or return value descriptor.
|
||||||
///
|
///
|
||||||
/// This describes the value type being passed to or from a function along with flags that affect
|
/// This describes the value type being passed to or from a function along with flags that affect
|
||||||
/// how the argument is passed.
|
/// how the argument is passed.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct ArgumentType {
|
pub struct AbiParam {
|
||||||
/// Type of the argument value.
|
/// Type of the argument value.
|
||||||
pub value_type: Type,
|
pub value_type: Type,
|
||||||
/// Special purpose of argument, or `Normal`.
|
/// Special purpose of argument, or `Normal`.
|
||||||
@@ -142,10 +136,10 @@ pub struct ArgumentType {
|
|||||||
pub location: ArgumentLoc,
|
pub location: ArgumentLoc,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArgumentType {
|
impl AbiParam {
|
||||||
/// Create an argument type with default flags.
|
/// Create a parameter with default flags.
|
||||||
pub fn new(vt: Type) -> ArgumentType {
|
pub fn new(vt: Type) -> AbiParam {
|
||||||
ArgumentType {
|
AbiParam {
|
||||||
value_type: vt,
|
value_type: vt,
|
||||||
extension: ArgumentExtension::None,
|
extension: ArgumentExtension::None,
|
||||||
purpose: ArgumentPurpose::Normal,
|
purpose: ArgumentPurpose::Normal,
|
||||||
@@ -153,9 +147,9 @@ impl ArgumentType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a special-purpose argument type that is not (yet) bound to a specific register.
|
/// Create a special-purpose parameter that is not (yet) bound to a specific register.
|
||||||
pub fn special(vt: Type, purpose: ArgumentPurpose) -> ArgumentType {
|
pub fn special(vt: Type, purpose: ArgumentPurpose) -> AbiParam {
|
||||||
ArgumentType {
|
AbiParam {
|
||||||
value_type: vt,
|
value_type: vt,
|
||||||
extension: ArgumentExtension::None,
|
extension: ArgumentExtension::None,
|
||||||
purpose,
|
purpose,
|
||||||
@@ -163,9 +157,9 @@ impl ArgumentType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an argument type for a special-purpose register.
|
/// Create a parameter for a special-purpose register.
|
||||||
pub fn special_reg(vt: Type, purpose: ArgumentPurpose, regunit: RegUnit) -> ArgumentType {
|
pub fn special_reg(vt: Type, purpose: ArgumentPurpose, regunit: RegUnit) -> AbiParam {
|
||||||
ArgumentType {
|
AbiParam {
|
||||||
value_type: vt,
|
value_type: vt,
|
||||||
extension: ArgumentExtension::None,
|
extension: ArgumentExtension::None,
|
||||||
purpose,
|
purpose,
|
||||||
@@ -173,34 +167,34 @@ impl ArgumentType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert `self` to an argument type with the `uext` flag set.
|
/// Convert `self` to a parameter with the `uext` flag set.
|
||||||
pub fn uext(self) -> ArgumentType {
|
pub fn uext(self) -> AbiParam {
|
||||||
debug_assert!(self.value_type.is_int(), "uext on {} arg", self.value_type);
|
debug_assert!(self.value_type.is_int(), "uext on {} arg", self.value_type);
|
||||||
ArgumentType {
|
AbiParam {
|
||||||
extension: ArgumentExtension::Uext,
|
extension: ArgumentExtension::Uext,
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert `self` to an argument type with the `sext` flag set.
|
/// Convert `self` to a parameter type with the `sext` flag set.
|
||||||
pub fn sext(self) -> ArgumentType {
|
pub fn sext(self) -> AbiParam {
|
||||||
debug_assert!(self.value_type.is_int(), "sext on {} arg", self.value_type);
|
debug_assert!(self.value_type.is_int(), "sext on {} arg", self.value_type);
|
||||||
ArgumentType {
|
AbiParam {
|
||||||
extension: ArgumentExtension::Sext,
|
extension: ArgumentExtension::Sext,
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an object that can display `self` with correct register names.
|
/// Return an object that can display `self` with correct register names.
|
||||||
pub fn display<'a, R: Into<Option<&'a RegInfo>>>(&'a self, regs: R) -> DisplayArgumentType<'a> {
|
pub fn display<'a, R: Into<Option<&'a RegInfo>>>(&'a self, regs: R) -> DisplayAbiParam<'a> {
|
||||||
DisplayArgumentType(self, regs.into())
|
DisplayAbiParam(self, regs.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper type capable of displaying an `ArgumentType` with correct register names.
|
/// Wrapper type capable of displaying a `AbiParam` with correct register names.
|
||||||
pub struct DisplayArgumentType<'a>(&'a ArgumentType, Option<&'a RegInfo>);
|
pub struct DisplayAbiParam<'a>(&'a AbiParam, Option<&'a RegInfo>);
|
||||||
|
|
||||||
impl<'a> fmt::Display for DisplayArgumentType<'a> {
|
impl<'a> fmt::Display for DisplayAbiParam<'a> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", self.0.value_type)?;
|
write!(f, "{}", self.0.value_type)?;
|
||||||
match self.0.extension {
|
match self.0.extension {
|
||||||
@@ -220,7 +214,7 @@ impl<'a> fmt::Display for DisplayArgumentType<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ArgumentType {
|
impl fmt::Display for AbiParam {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.display(None).fmt(f)
|
self.display(None).fmt(f)
|
||||||
}
|
}
|
||||||
@@ -387,7 +381,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn argument_type() {
|
fn argument_type() {
|
||||||
let t = ArgumentType::new(I32);
|
let t = AbiParam::new(I32);
|
||||||
assert_eq!(t.to_string(), "i32");
|
assert_eq!(t.to_string(), "i32");
|
||||||
let mut t = t.uext();
|
let mut t = t.uext();
|
||||||
assert_eq!(t.to_string(), "i32 uext");
|
assert_eq!(t.to_string(), "i32 uext");
|
||||||
@@ -423,25 +417,23 @@ mod tests {
|
|||||||
fn signatures() {
|
fn signatures() {
|
||||||
let mut sig = Signature::new(CallConv::SpiderWASM);
|
let mut sig = Signature::new(CallConv::SpiderWASM);
|
||||||
assert_eq!(sig.to_string(), "() spiderwasm");
|
assert_eq!(sig.to_string(), "() spiderwasm");
|
||||||
sig.argument_types.push(ArgumentType::new(I32));
|
sig.params.push(AbiParam::new(I32));
|
||||||
assert_eq!(sig.to_string(), "(i32) spiderwasm");
|
assert_eq!(sig.to_string(), "(i32) spiderwasm");
|
||||||
sig.return_types.push(ArgumentType::new(F32));
|
sig.returns.push(AbiParam::new(F32));
|
||||||
assert_eq!(sig.to_string(), "(i32) -> f32 spiderwasm");
|
assert_eq!(sig.to_string(), "(i32) -> f32 spiderwasm");
|
||||||
sig.argument_types.push(
|
sig.params.push(AbiParam::new(I32.by(4).unwrap()));
|
||||||
ArgumentType::new(I32.by(4).unwrap()),
|
|
||||||
);
|
|
||||||
assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 spiderwasm");
|
assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 spiderwasm");
|
||||||
sig.return_types.push(ArgumentType::new(B8));
|
sig.returns.push(AbiParam::new(B8));
|
||||||
assert_eq!(sig.to_string(), "(i32, i32x4) -> f32, b8 spiderwasm");
|
assert_eq!(sig.to_string(), "(i32, i32x4) -> f32, b8 spiderwasm");
|
||||||
|
|
||||||
// Test the offset computation algorithm.
|
// Test the offset computation algorithm.
|
||||||
assert_eq!(sig.argument_bytes, None);
|
assert_eq!(sig.argument_bytes, None);
|
||||||
sig.argument_types[1].location = ArgumentLoc::Stack(8);
|
sig.params[1].location = ArgumentLoc::Stack(8);
|
||||||
sig.compute_argument_bytes();
|
sig.compute_argument_bytes();
|
||||||
// An `i32x4` at offset 8 requires a 24-byte argument array.
|
// An `i32x4` at offset 8 requires a 24-byte argument array.
|
||||||
assert_eq!(sig.argument_bytes, Some(24));
|
assert_eq!(sig.argument_bytes, Some(24));
|
||||||
// Order does not matter.
|
// Order does not matter.
|
||||||
sig.argument_types[0].location = ArgumentLoc::Stack(24);
|
sig.params[0].location = ArgumentLoc::Stack(24);
|
||||||
sig.compute_argument_bytes();
|
sig.compute_argument_bytes();
|
||||||
assert_eq!(sig.argument_bytes, Some(28));
|
assert_eq!(sig.argument_bytes, Some(28));
|
||||||
|
|
||||||
|
|||||||
@@ -144,12 +144,12 @@ impl Function {
|
|||||||
DisplayFunction(self, isa.into())
|
DisplayFunction(self, isa.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find a presumed unique special-purpose function argument value.
|
/// Find a presumed unique special-purpose function parameter value.
|
||||||
///
|
///
|
||||||
/// Returns the value of the last `purpose` argument, or `None` if no such argument exists.
|
/// Returns the value of the last `purpose` parameter, or `None` if no such parameter exists.
|
||||||
pub fn special_arg(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> {
|
pub fn special_param(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> {
|
||||||
let entry = self.layout.entry_block().expect("Function is empty");
|
let entry = self.layout.entry_block().expect("Function is empty");
|
||||||
self.signature.special_arg_index(purpose).map(|i| {
|
self.signature.special_param_index(purpose).map(|i| {
|
||||||
self.dfg.ebb_params(entry)[i]
|
self.dfg.ebb_params(entry)[i]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ mod valueloc;
|
|||||||
pub use ir::builder::{InstBuilder, InstBuilderBase, InstInserterBase, InsertBuilder};
|
pub use ir::builder::{InstBuilder, InstBuilderBase, InstInserterBase, InsertBuilder};
|
||||||
pub use ir::dfg::{DataFlowGraph, ValueDef};
|
pub use ir::dfg::{DataFlowGraph, ValueDef};
|
||||||
pub use ir::entities::{Ebb, Inst, Value, StackSlot, GlobalVar, JumpTable, FuncRef, SigRef, Heap};
|
pub use ir::entities::{Ebb, Inst, Value, StackSlot, GlobalVar, JumpTable, FuncRef, SigRef, Heap};
|
||||||
pub use ir::extfunc::{Signature, CallConv, ArgumentType, ArgumentExtension, ArgumentPurpose,
|
pub use ir::extfunc::{Signature, CallConv, AbiParam, ArgumentExtension, ArgumentPurpose,
|
||||||
ExtFuncData};
|
ExtFuncData};
|
||||||
pub use ir::funcname::FunctionName;
|
pub use ir::funcname::FunctionName;
|
||||||
pub use ir::function::Function;
|
pub use ir::function::Function;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use regalloc::AllocatableSet;
|
|||||||
use settings as shared_settings;
|
use settings as shared_settings;
|
||||||
use super::registers::{GPR, FPR, RU};
|
use super::registers::{GPR, FPR, RU};
|
||||||
use abi::{ArgAction, ValueConversion, ArgAssigner, legalize_args};
|
use abi::{ArgAction, ValueConversion, ArgAssigner, legalize_args};
|
||||||
use ir::{ArgumentType, ArgumentPurpose, ArgumentLoc, ArgumentExtension};
|
use ir::{AbiParam, ArgumentPurpose, ArgumentLoc, ArgumentExtension};
|
||||||
|
|
||||||
/// Argument registers for x86-64
|
/// Argument registers for x86-64
|
||||||
static ARG_GPRS: [RU; 6] = [RU::rdi, RU::rsi, RU::rdx, RU::rcx, RU::r8, RU::r9];
|
static ARG_GPRS: [RU; 6] = [RU::rdi, RU::rsi, RU::rdx, RU::rcx, RU::r8, RU::r9];
|
||||||
@@ -41,7 +41,7 @@ impl Args {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ArgAssigner for Args {
|
impl ArgAssigner for Args {
|
||||||
fn assign(&mut self, arg: &ArgumentType) -> ArgAction {
|
fn assign(&mut self, arg: &AbiParam) -> ArgAction {
|
||||||
let ty = arg.value_type;
|
let ty = arg.value_type;
|
||||||
|
|
||||||
// Check for a legal type.
|
// Check for a legal type.
|
||||||
@@ -117,10 +117,10 @@ pub fn legalize_signature(sig: &mut ir::Signature, flags: &shared_settings::Flag
|
|||||||
args = Args::new(bits, &[], 0);
|
args = Args::new(bits, &[], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
legalize_args(&mut sig.argument_types, &mut args);
|
legalize_args(&mut sig.params, &mut args);
|
||||||
|
|
||||||
let mut rets = Args::new(bits, &RET_GPRS, 2);
|
let mut rets = Args::new(bits, &RET_GPRS, 2);
|
||||||
legalize_args(&mut sig.return_types, &mut rets);
|
legalize_args(&mut sig.returns, &mut rets);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get register class for a type appearing in a legalized signature.
|
/// Get register class for a type appearing in a legalized signature.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
//! This doesn't support the soft-float ABI at the moment.
|
//! This doesn't support the soft-float ABI at the moment.
|
||||||
|
|
||||||
use abi::{ArgAction, ValueConversion, ArgAssigner, legalize_args};
|
use abi::{ArgAction, ValueConversion, ArgAssigner, legalize_args};
|
||||||
use ir::{self, Type, ArgumentType, ArgumentLoc, ArgumentExtension, ArgumentPurpose};
|
use ir::{self, Type, AbiParam, ArgumentLoc, ArgumentExtension, ArgumentPurpose};
|
||||||
use isa::RegClass;
|
use isa::RegClass;
|
||||||
use regalloc::AllocatableSet;
|
use regalloc::AllocatableSet;
|
||||||
use settings as shared_settings;
|
use settings as shared_settings;
|
||||||
@@ -36,7 +36,7 @@ impl Args {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ArgAssigner for Args {
|
impl ArgAssigner for Args {
|
||||||
fn assign(&mut self, arg: &ArgumentType) -> ArgAction {
|
fn assign(&mut self, arg: &AbiParam) -> ArgAction {
|
||||||
fn align(value: u32, to: u32) -> u32 {
|
fn align(value: u32, to: u32) -> u32 {
|
||||||
(value + to - 1) & !(to - 1)
|
(value + to - 1) & !(to - 1)
|
||||||
}
|
}
|
||||||
@@ -95,10 +95,10 @@ pub fn legalize_signature(
|
|||||||
let bits = if flags.is_64bit() { 64 } else { 32 };
|
let bits = if flags.is_64bit() { 64 } else { 32 };
|
||||||
|
|
||||||
let mut args = Args::new(bits, isa_flags.enable_e());
|
let mut args = Args::new(bits, isa_flags.enable_e());
|
||||||
legalize_args(&mut sig.argument_types, &mut args);
|
legalize_args(&mut sig.params, &mut args);
|
||||||
|
|
||||||
let mut rets = Args::new(bits, isa_flags.enable_e());
|
let mut rets = Args::new(bits, isa_flags.enable_e());
|
||||||
legalize_args(&mut sig.return_types, &mut rets);
|
legalize_args(&mut sig.returns, &mut rets);
|
||||||
|
|
||||||
if current {
|
if current {
|
||||||
let ptr = Type::int(bits).unwrap();
|
let ptr = Type::int(bits).unwrap();
|
||||||
@@ -108,9 +108,9 @@ pub fn legalize_signature(
|
|||||||
// The `jalr` instruction implementing a return can technically accept the return address
|
// The `jalr` instruction implementing a return can technically accept the return address
|
||||||
// in any register, but a micro-architecture with a return address predictor will only
|
// in any register, but a micro-architecture with a return address predictor will only
|
||||||
// recognize it as a return if the address is in `x1`.
|
// recognize it as a return if the address is in `x1`.
|
||||||
let link = ArgumentType::special_reg(ptr, ArgumentPurpose::Link, GPR.unit(1));
|
let link = AbiParam::special_reg(ptr, ArgumentPurpose::Link, GPR.unit(1));
|
||||||
sig.argument_types.push(link);
|
sig.params.push(link);
|
||||||
sig.return_types.push(link);
|
sig.returns.push(link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use abi::{legalize_abi_value, ValueConversion};
|
|||||||
use cursor::{Cursor, FuncCursor};
|
use cursor::{Cursor, FuncCursor};
|
||||||
use flowgraph::ControlFlowGraph;
|
use flowgraph::ControlFlowGraph;
|
||||||
use ir::{Function, DataFlowGraph, Inst, InstBuilder, Ebb, Type, Value, Signature, SigRef,
|
use ir::{Function, DataFlowGraph, Inst, InstBuilder, Ebb, Type, Value, Signature, SigRef,
|
||||||
ArgumentType, ArgumentPurpose, ArgumentLoc, ValueLoc};
|
AbiParam, ArgumentPurpose, ArgumentLoc, ValueLoc};
|
||||||
use ir::instructions::CallInfo;
|
use ir::instructions::CallInfo;
|
||||||
use isa::TargetIsa;
|
use isa::TargetIsa;
|
||||||
use legalizer::split::{isplit, vsplit};
|
use legalizer::split::{isplit, vsplit};
|
||||||
@@ -40,20 +40,20 @@ pub fn legalize_signatures(func: &mut Function, isa: &TargetIsa) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(entry) = func.layout.entry_block() {
|
if let Some(entry) = func.layout.entry_block() {
|
||||||
legalize_entry_arguments(func, entry);
|
legalize_entry_params(func, entry);
|
||||||
spill_entry_arguments(func, entry);
|
spill_entry_params(func, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Legalize the entry block arguments after `func`'s signature has been legalized.
|
/// Legalize the entry block parameters after `func`'s signature has been legalized.
|
||||||
///
|
///
|
||||||
/// The legalized signature may contain more arguments than the original signature, and the
|
/// The legalized signature may contain more parameters than the original signature, and the
|
||||||
/// argument types have been changed. This function goes through the arguments to the entry EBB and
|
/// parameter types have been changed. This function goes through the parameters of the entry EBB
|
||||||
/// replaces them with arguments of the right type for the ABI.
|
/// and replaces them with parameters of the right type for the ABI.
|
||||||
///
|
///
|
||||||
/// The original entry EBB arguments are computed from the new ABI arguments by code inserted at
|
/// The original entry EBB parameters are computed from the new ABI parameters by code inserted at
|
||||||
/// the top of the entry block.
|
/// the top of the entry block.
|
||||||
fn legalize_entry_arguments(func: &mut Function, entry: Ebb) {
|
fn legalize_entry_params(func: &mut Function, entry: Ebb) {
|
||||||
let mut has_sret = false;
|
let mut has_sret = false;
|
||||||
let mut has_link = false;
|
let mut has_link = false;
|
||||||
let mut has_vmctx = false;
|
let mut has_vmctx = false;
|
||||||
@@ -74,7 +74,7 @@ fn legalize_entry_arguments(func: &mut Function, entry: Ebb) {
|
|||||||
while let Some(arg) = ebb_params.get(old_arg, &pos.func.dfg.value_lists) {
|
while let Some(arg) = ebb_params.get(old_arg, &pos.func.dfg.value_lists) {
|
||||||
old_arg += 1;
|
old_arg += 1;
|
||||||
|
|
||||||
let abi_type = pos.func.signature.argument_types[abi_arg];
|
let abi_type = pos.func.signature.params[abi_arg];
|
||||||
let arg_type = pos.func.dfg.value_type(arg);
|
let arg_type = pos.func.dfg.value_type(arg);
|
||||||
if arg_type == abi_type.value_type {
|
if arg_type == abi_type.value_type {
|
||||||
// No value translation is necessary, this argument matches the ABI type.
|
// No value translation is necessary, this argument matches the ABI type.
|
||||||
@@ -98,9 +98,9 @@ fn legalize_entry_arguments(func: &mut Function, entry: Ebb) {
|
|||||||
}
|
}
|
||||||
abi_arg += 1;
|
abi_arg += 1;
|
||||||
} else {
|
} else {
|
||||||
// Compute the value we want for `arg` from the legalized ABI arguments.
|
// Compute the value we want for `arg` from the legalized ABI parameters.
|
||||||
let mut get_arg = |func: &mut Function, ty| {
|
let mut get_arg = |func: &mut Function, ty| {
|
||||||
let abi_type = func.signature.argument_types[abi_arg];
|
let abi_type = func.signature.params[abi_arg];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
abi_type.purpose,
|
abi_type.purpose,
|
||||||
ArgumentPurpose::Normal,
|
ArgumentPurpose::Normal,
|
||||||
@@ -120,15 +120,15 @@ fn legalize_entry_arguments(func: &mut Function, entry: Ebb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The legalized signature may contain additional arguments representing special-purpose
|
// The legalized signature may contain additional parameters representing special-purpose
|
||||||
// registers.
|
// registers.
|
||||||
for &arg in &pos.func.signature.argument_types[abi_arg..] {
|
for &arg in &pos.func.signature.params[abi_arg..] {
|
||||||
match arg.purpose {
|
match arg.purpose {
|
||||||
// Any normal arguments should have been processed above.
|
// Any normal parameters should have been processed above.
|
||||||
ArgumentPurpose::Normal => {
|
ArgumentPurpose::Normal => {
|
||||||
panic!("Leftover arg: {}", arg);
|
panic!("Leftover arg: {}", arg);
|
||||||
}
|
}
|
||||||
// The callee-save arguments should not appear until after register allocation is
|
// The callee-save parameters should not appear until after register allocation is
|
||||||
// done.
|
// done.
|
||||||
ArgumentPurpose::FramePointer |
|
ArgumentPurpose::FramePointer |
|
||||||
ArgumentPurpose::CalleeSaved => {
|
ArgumentPurpose::CalleeSaved => {
|
||||||
@@ -136,19 +136,19 @@ fn legalize_entry_arguments(func: &mut Function, entry: Ebb) {
|
|||||||
}
|
}
|
||||||
// These can be meaningfully added by `legalize_signature()`.
|
// These can be meaningfully added by `legalize_signature()`.
|
||||||
ArgumentPurpose::Link => {
|
ArgumentPurpose::Link => {
|
||||||
assert!(!has_link, "Multiple link arguments found");
|
assert!(!has_link, "Multiple link parameters found");
|
||||||
has_link = true;
|
has_link = true;
|
||||||
}
|
}
|
||||||
ArgumentPurpose::StructReturn => {
|
ArgumentPurpose::StructReturn => {
|
||||||
assert!(!has_sret, "Multiple sret arguments found");
|
assert!(!has_sret, "Multiple sret parameters found");
|
||||||
has_sret = true;
|
has_sret = true;
|
||||||
}
|
}
|
||||||
ArgumentPurpose::VMContext => {
|
ArgumentPurpose::VMContext => {
|
||||||
assert!(!has_vmctx, "Multiple vmctx arguments found");
|
assert!(!has_vmctx, "Multiple vmctx parameters found");
|
||||||
has_vmctx = true;
|
has_vmctx = true;
|
||||||
}
|
}
|
||||||
ArgumentPurpose::SignatureId => {
|
ArgumentPurpose::SignatureId => {
|
||||||
assert!(!has_sigid, "Multiple sigid arguments found");
|
assert!(!has_sigid, "Multiple sigid parameters found");
|
||||||
has_sigid = true;
|
has_sigid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,12 +164,12 @@ fn legalize_entry_arguments(func: &mut Function, entry: Ebb) {
|
|||||||
/// The cursor `pos` points to a call instruction with at least one return value. The cursor will
|
/// The cursor `pos` points to a call instruction with at least one return value. The cursor will
|
||||||
/// be left pointing after the instructions inserted to convert the return values.
|
/// be left pointing after the instructions inserted to convert the return values.
|
||||||
///
|
///
|
||||||
/// This function is very similar to the `legalize_entry_arguments` function above.
|
/// This function is very similar to the `legalize_entry_params` function above.
|
||||||
///
|
///
|
||||||
/// Returns the possibly new instruction representing the call.
|
/// Returns the possibly new instruction representing the call.
|
||||||
fn legalize_inst_results<ResType>(pos: &mut FuncCursor, mut get_abi_type: ResType) -> Inst
|
fn legalize_inst_results<ResType>(pos: &mut FuncCursor, mut get_abi_type: ResType) -> Inst
|
||||||
where
|
where
|
||||||
ResType: FnMut(&Function, usize) -> ArgumentType,
|
ResType: FnMut(&Function, usize) -> AbiParam,
|
||||||
{
|
{
|
||||||
let call = pos.current_inst().expect(
|
let call = pos.current_inst().expect(
|
||||||
"Cursor must point to a call instruction",
|
"Cursor must point to a call instruction",
|
||||||
@@ -230,7 +230,7 @@ fn convert_from_abi<GetArg>(
|
|||||||
get_arg: &mut GetArg,
|
get_arg: &mut GetArg,
|
||||||
) -> Value
|
) -> Value
|
||||||
where
|
where
|
||||||
GetArg: FnMut(&mut Function, Type) -> Result<Value, ArgumentType>,
|
GetArg: FnMut(&mut Function, Type) -> Result<Value, AbiParam>,
|
||||||
{
|
{
|
||||||
// Terminate the recursion when we get the desired type.
|
// Terminate the recursion when we get the desired type.
|
||||||
let arg_type = match get_arg(pos.func, ty) {
|
let arg_type = match get_arg(pos.func, ty) {
|
||||||
@@ -304,7 +304,7 @@ where
|
|||||||
/// 1. If the suggested argument has an acceptable value type, consume it by adding it to the list
|
/// 1. If the suggested argument has an acceptable value type, consume it by adding it to the list
|
||||||
/// of arguments and return `Ok(())`.
|
/// of arguments and return `Ok(())`.
|
||||||
/// 2. If the suggested argument doesn't have the right value type, don't change anything, but
|
/// 2. If the suggested argument doesn't have the right value type, don't change anything, but
|
||||||
/// return the `Err(ArgumentType)` that is needed.
|
/// return the `Err(AbiParam)` that is needed.
|
||||||
///
|
///
|
||||||
fn convert_to_abi<PutArg>(
|
fn convert_to_abi<PutArg>(
|
||||||
pos: &mut FuncCursor,
|
pos: &mut FuncCursor,
|
||||||
@@ -312,7 +312,7 @@ fn convert_to_abi<PutArg>(
|
|||||||
value: Value,
|
value: Value,
|
||||||
put_arg: &mut PutArg,
|
put_arg: &mut PutArg,
|
||||||
) where
|
) where
|
||||||
PutArg: FnMut(&mut Function, Value) -> Result<(), ArgumentType>,
|
PutArg: FnMut(&mut Function, Value) -> Result<(), AbiParam>,
|
||||||
{
|
{
|
||||||
// Start by invoking the closure to either terminate the recursion or get the argument type
|
// Start by invoking the closure to either terminate the recursion or get the argument type
|
||||||
// we're trying to match.
|
// we're trying to match.
|
||||||
@@ -355,7 +355,7 @@ fn convert_to_abi<PutArg>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a sequence of arguments match a desired sequence of argument types.
|
/// Check if a sequence of arguments match a desired sequence of argument types.
|
||||||
fn check_arg_types(dfg: &DataFlowGraph, args: &[Value], types: &[ArgumentType]) -> bool {
|
fn check_arg_types(dfg: &DataFlowGraph, args: &[Value], types: &[AbiParam]) -> bool {
|
||||||
let arg_types = args.iter().map(|&v| dfg.value_type(v));
|
let arg_types = args.iter().map(|&v| dfg.value_type(v));
|
||||||
let sig_types = types.iter().map(|&at| at.value_type);
|
let sig_types = types.iter().map(|&at| at.value_type);
|
||||||
arg_types.eq(sig_types)
|
arg_types.eq(sig_types)
|
||||||
@@ -374,8 +374,8 @@ fn check_call_signature(dfg: &DataFlowGraph, inst: Inst) -> Result<(), SigRef> {
|
|||||||
};
|
};
|
||||||
let sig = &dfg.signatures[sig_ref];
|
let sig = &dfg.signatures[sig_ref];
|
||||||
|
|
||||||
if check_arg_types(dfg, args, &sig.argument_types[..]) &&
|
if check_arg_types(dfg, args, &sig.params[..]) &&
|
||||||
check_arg_types(dfg, dfg.inst_results(inst), &sig.return_types[..])
|
check_arg_types(dfg, dfg.inst_results(inst), &sig.returns[..])
|
||||||
{
|
{
|
||||||
// All types check out.
|
// All types check out.
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -387,13 +387,13 @@ fn check_call_signature(dfg: &DataFlowGraph, inst: Inst) -> Result<(), SigRef> {
|
|||||||
|
|
||||||
/// Check if the arguments of the return `inst` match the signature.
|
/// Check if the arguments of the return `inst` match the signature.
|
||||||
fn check_return_signature(dfg: &DataFlowGraph, inst: Inst, sig: &Signature) -> bool {
|
fn check_return_signature(dfg: &DataFlowGraph, inst: Inst, sig: &Signature) -> bool {
|
||||||
check_arg_types(dfg, dfg.inst_variable_args(inst), &sig.return_types)
|
check_arg_types(dfg, dfg.inst_variable_args(inst), &sig.returns)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert ABI conversion code for the arguments to the call or return instruction at `pos`.
|
/// Insert ABI conversion code for the arguments to the call or return instruction at `pos`.
|
||||||
///
|
///
|
||||||
/// - `abi_args` is the number of arguments that the ABI signature requires.
|
/// - `abi_args` is the number of arguments that the ABI signature requires.
|
||||||
/// - `get_abi_type` is a closure that can provide the desired `ArgumentType` for a given ABI
|
/// - `get_abi_type` is a closure that can provide the desired `AbiParam` for a given ABI
|
||||||
/// argument number in `0..abi_args`.
|
/// argument number in `0..abi_args`.
|
||||||
///
|
///
|
||||||
fn legalize_inst_arguments<ArgType>(
|
fn legalize_inst_arguments<ArgType>(
|
||||||
@@ -402,7 +402,7 @@ fn legalize_inst_arguments<ArgType>(
|
|||||||
abi_args: usize,
|
abi_args: usize,
|
||||||
mut get_abi_type: ArgType,
|
mut get_abi_type: ArgType,
|
||||||
) where
|
) where
|
||||||
ArgType: FnMut(&Function, usize) -> ArgumentType,
|
ArgType: FnMut(&Function, usize) -> AbiParam,
|
||||||
{
|
{
|
||||||
let inst = pos.current_inst().expect(
|
let inst = pos.current_inst().expect(
|
||||||
"Cursor must point to a call instruction",
|
"Cursor must point to a call instruction",
|
||||||
@@ -498,14 +498,14 @@ pub fn handle_call_abi(mut inst: Inst, func: &mut Function, cfg: &ControlFlowGra
|
|||||||
};
|
};
|
||||||
|
|
||||||
// OK, we need to fix the call arguments to match the ABI signature.
|
// OK, we need to fix the call arguments to match the ABI signature.
|
||||||
let abi_args = pos.func.dfg.signatures[sig_ref].argument_types.len();
|
let abi_args = pos.func.dfg.signatures[sig_ref].params.len();
|
||||||
legalize_inst_arguments(pos, cfg, abi_args, |func, abi_arg| {
|
legalize_inst_arguments(pos, cfg, abi_args, |func, abi_arg| {
|
||||||
func.dfg.signatures[sig_ref].argument_types[abi_arg]
|
func.dfg.signatures[sig_ref].params[abi_arg]
|
||||||
});
|
});
|
||||||
|
|
||||||
if !pos.func.dfg.signatures[sig_ref].return_types.is_empty() {
|
if !pos.func.dfg.signatures[sig_ref].returns.is_empty() {
|
||||||
inst = legalize_inst_results(pos, |func, abi_res| {
|
inst = legalize_inst_results(pos, |func, abi_res| {
|
||||||
func.dfg.signatures[sig_ref].return_types[abi_res]
|
func.dfg.signatures[sig_ref].returns[abi_res]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,7 +537,7 @@ pub fn handle_return_abi(inst: Inst, func: &mut Function, cfg: &ControlFlowGraph
|
|||||||
// Count the special-purpose return values (`link`, `sret`, and `vmctx`) that were appended to
|
// Count the special-purpose return values (`link`, `sret`, and `vmctx`) that were appended to
|
||||||
// the legalized signature.
|
// the legalized signature.
|
||||||
let special_args = func.signature
|
let special_args = func.signature
|
||||||
.return_types
|
.returns
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.take_while(|&rt| {
|
.take_while(|&rt| {
|
||||||
@@ -545,13 +545,13 @@ pub fn handle_return_abi(inst: Inst, func: &mut Function, cfg: &ControlFlowGraph
|
|||||||
rt.purpose == ArgumentPurpose::VMContext
|
rt.purpose == ArgumentPurpose::VMContext
|
||||||
})
|
})
|
||||||
.count();
|
.count();
|
||||||
let abi_args = func.signature.return_types.len() - special_args;
|
let abi_args = func.signature.returns.len() - special_args;
|
||||||
|
|
||||||
let pos = &mut FuncCursor::new(func).at_inst(inst);
|
let pos = &mut FuncCursor::new(func).at_inst(inst);
|
||||||
pos.use_srcloc(inst);
|
pos.use_srcloc(inst);
|
||||||
|
|
||||||
legalize_inst_arguments(pos, cfg, abi_args, |func, abi_arg| {
|
legalize_inst_arguments(pos, cfg, abi_args, |func, abi_arg| {
|
||||||
func.signature.return_types[abi_arg]
|
func.signature.returns[abi_arg]
|
||||||
});
|
});
|
||||||
assert_eq!(pos.func.dfg.inst_variable_args(inst).len(), abi_args);
|
assert_eq!(pos.func.dfg.inst_variable_args(inst).len(), abi_args);
|
||||||
|
|
||||||
@@ -565,7 +565,7 @@ pub fn handle_return_abi(inst: Inst, func: &mut Function, cfg: &ControlFlowGraph
|
|||||||
pos.func.dfg.display_inst(inst, None)
|
pos.func.dfg.display_inst(inst, None)
|
||||||
);
|
);
|
||||||
let mut vlist = pos.func.dfg[inst].take_value_list().unwrap();
|
let mut vlist = pos.func.dfg[inst].take_value_list().unwrap();
|
||||||
for arg in &pos.func.signature.return_types[abi_args..] {
|
for arg in &pos.func.signature.returns[abi_args..] {
|
||||||
match arg.purpose {
|
match arg.purpose {
|
||||||
ArgumentPurpose::Link |
|
ArgumentPurpose::Link |
|
||||||
ArgumentPurpose::StructReturn |
|
ArgumentPurpose::StructReturn |
|
||||||
@@ -578,7 +578,7 @@ pub fn handle_return_abi(inst: Inst, func: &mut Function, cfg: &ControlFlowGraph
|
|||||||
// the end.
|
// the end.
|
||||||
let idx = pos.func
|
let idx = pos.func
|
||||||
.signature
|
.signature
|
||||||
.argument_types
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.rposition(|t| t.purpose == arg.purpose)
|
.rposition(|t| t.purpose == arg.purpose)
|
||||||
.expect("No matching special purpose argument.");
|
.expect("No matching special purpose argument.");
|
||||||
@@ -605,17 +605,12 @@ pub fn handle_return_abi(inst: Inst, func: &mut Function, cfg: &ControlFlowGraph
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assign stack slots to incoming function arguments on the stack.
|
/// Assign stack slots to incoming function parameters on the stack.
|
||||||
///
|
///
|
||||||
/// Values that are passed into the function on the stack must be assigned to an `IncomingArg`
|
/// Values that are passed into the function on the stack must be assigned to an `IncomingArg`
|
||||||
/// stack slot already during legalization.
|
/// stack slot already during legalization.
|
||||||
fn spill_entry_arguments(func: &mut Function, entry: Ebb) {
|
fn spill_entry_params(func: &mut Function, entry: Ebb) {
|
||||||
for (abi, &arg) in func.signature.argument_types.iter().zip(
|
for (abi, &arg) in func.signature.params.iter().zip(func.dfg.ebb_params(entry)) {
|
||||||
func.dfg.ebb_params(
|
|
||||||
entry,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if let ArgumentLoc::Stack(offset) = abi.location {
|
if let ArgumentLoc::Stack(offset) = abi.location {
|
||||||
let ss = func.stack_slots.make_incoming_arg(abi.value_type, offset);
|
let ss = func.stack_slots.make_incoming_arg(abi.value_type, offset);
|
||||||
func.locations[arg] = ValueLoc::Stack(ss);
|
func.locations[arg] = ValueLoc::Stack(ss);
|
||||||
@@ -648,7 +643,7 @@ fn spill_call_arguments(pos: &mut FuncCursor) -> bool {
|
|||||||
.dfg
|
.dfg
|
||||||
.inst_variable_args(inst)
|
.inst_variable_args(inst)
|
||||||
.iter()
|
.iter()
|
||||||
.zip(&pos.func.dfg.signatures[sig_ref].argument_types)
|
.zip(&pos.func.dfg.signatures[sig_ref].params)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(idx, (&arg, abi))| {
|
.filter_map(|(idx, (&arg, abi))| {
|
||||||
match abi.location {
|
match abi.location {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ pub fn expand_global_addr(inst: ir::Inst, func: &mut ir::Function, _cfg: &mut Co
|
|||||||
/// Expand a `global_addr` instruction for a vmctx global.
|
/// Expand a `global_addr` instruction for a vmctx global.
|
||||||
fn vmctx_addr(inst: ir::Inst, func: &mut ir::Function, offset: i64) {
|
fn vmctx_addr(inst: ir::Inst, func: &mut ir::Function, offset: i64) {
|
||||||
// Get the value representing the `vmctx` argument.
|
// Get the value representing the `vmctx` argument.
|
||||||
let vmctx = func.special_arg(ir::ArgumentPurpose::VMContext).expect(
|
let vmctx = func.special_param(ir::ArgumentPurpose::VMContext).expect(
|
||||||
"Missing vmctx parameter",
|
"Missing vmctx parameter",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
//! larger register class instead.
|
//! larger register class instead.
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use ir::{ArgumentType, ArgumentLoc};
|
use ir::{AbiParam, ArgumentLoc};
|
||||||
use isa::{TargetIsa, RegInfo, RegClassIndex, OperandConstraint, ConstraintKind};
|
use isa::{TargetIsa, RegInfo, RegClassIndex, OperandConstraint, ConstraintKind};
|
||||||
|
|
||||||
/// Preferred register allocation for an SSA value.
|
/// Preferred register allocation for an SSA value.
|
||||||
@@ -48,7 +48,7 @@ impl Affinity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create an affinity that matches an ABI argument for `isa`.
|
/// Create an affinity that matches an ABI argument for `isa`.
|
||||||
pub fn abi(arg: &ArgumentType, isa: &TargetIsa) -> Affinity {
|
pub fn abi(arg: &AbiParam, isa: &TargetIsa) -> Affinity {
|
||||||
match arg.location {
|
match arg.location {
|
||||||
ArgumentLoc::Unassigned => Affinity::None,
|
ArgumentLoc::Unassigned => Affinity::None,
|
||||||
ArgumentLoc::Reg(_) => Affinity::Reg(isa.regclass_for_abi_type(arg.value_type).into()),
|
ArgumentLoc::Reg(_) => Affinity::Reg(isa.regclass_for_abi_type(arg.value_type).into()),
|
||||||
|
|||||||
@@ -418,14 +418,12 @@ impl<'a> Context<'a> {
|
|||||||
self.func.dfg.display_inst(pred_inst, self.isa)
|
self.func.dfg.display_inst(pred_inst, self.isa)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Never coalesce incoming function arguments on the stack. These arguments are
|
// Never coalesce incoming function parameters on the stack. These parameters are
|
||||||
// pre-spilled, and the rest of the virtual register would be forced to spill to the
|
// pre-spilled, and the rest of the virtual register would be forced to spill to the
|
||||||
// `incoming_arg` stack slot too.
|
// `incoming_arg` stack slot too.
|
||||||
if let ValueDef::Param(def_ebb, def_num) = self.func.dfg.value_def(pred_val) {
|
if let ValueDef::Param(def_ebb, def_num) = self.func.dfg.value_def(pred_val) {
|
||||||
if Some(def_ebb) == self.func.layout.entry_block() &&
|
if Some(def_ebb) == self.func.layout.entry_block() &&
|
||||||
self.func.signature.argument_types[def_num]
|
self.func.signature.params[def_num].location.is_stack()
|
||||||
.location
|
|
||||||
.is_stack()
|
|
||||||
{
|
{
|
||||||
dbg!("Isolating incoming stack parameter {}", pred_val);
|
dbg!("Isolating incoming stack parameter {}", pred_val);
|
||||||
let new_val = self.split_pred(pred_inst, pred_ebb, argnum, pred_val);
|
let new_val = self.split_pred(pred_inst, pred_ebb, argnum, pred_val);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
use cursor::{Cursor, EncCursor};
|
use cursor::{Cursor, EncCursor};
|
||||||
use dominator_tree::DominatorTree;
|
use dominator_tree::DominatorTree;
|
||||||
use ir::{Ebb, Inst, Value, Function, ValueLoc, SigRef};
|
use ir::{Ebb, Inst, Value, Function, ValueLoc, SigRef};
|
||||||
use ir::{InstBuilder, ArgumentType, ArgumentLoc, ValueDef};
|
use ir::{InstBuilder, AbiParam, ArgumentLoc, ValueDef};
|
||||||
use isa::{RegUnit, RegClass, RegInfo, regs_overlap};
|
use isa::{RegUnit, RegClass, RegInfo, regs_overlap};
|
||||||
use isa::{TargetIsa, EncInfo, RecipeConstraints, OperandConstraint, ConstraintKind};
|
use isa::{TargetIsa, EncInfo, RecipeConstraints, OperandConstraint, ConstraintKind};
|
||||||
use packed_option::PackedOption;
|
use packed_option::PackedOption;
|
||||||
@@ -188,10 +188,10 @@ impl<'a> Context<'a> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if self.cur.func.layout.entry_block() == Some(ebb) {
|
if self.cur.func.layout.entry_block() == Some(ebb) {
|
||||||
// Arguments to the entry block have ABI constraints.
|
// Parameters on the entry block have ABI constraints.
|
||||||
self.color_entry_args(tracker.live())
|
self.color_entry_params(tracker.live())
|
||||||
} else {
|
} else {
|
||||||
// The live-ins and arguments to a non-entry EBB have already been assigned a register.
|
// The live-ins and parameters of a non-entry EBB have already been assigned a register.
|
||||||
// Reconstruct the allocatable set.
|
// Reconstruct the allocatable set.
|
||||||
self.livein_regs(tracker.live())
|
self.livein_regs(tracker.live())
|
||||||
}
|
}
|
||||||
@@ -230,19 +230,19 @@ impl<'a> Context<'a> {
|
|||||||
regs
|
regs
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Color the arguments to the entry block.
|
/// Color the parameters on the entry block.
|
||||||
///
|
///
|
||||||
/// These are function arguments that should already have assigned register units in the
|
/// These are function parameters that should already have assigned register units in the
|
||||||
/// function signature.
|
/// function signature.
|
||||||
///
|
///
|
||||||
/// Return the set of remaining allocatable registers after filtering out the dead arguments.
|
/// Return the set of remaining allocatable registers after filtering out the dead arguments.
|
||||||
fn color_entry_args(&mut self, args: &[LiveValue]) -> AvailableRegs {
|
fn color_entry_params(&mut self, args: &[LiveValue]) -> AvailableRegs {
|
||||||
let sig = &self.cur.func.signature;
|
let sig = &self.cur.func.signature;
|
||||||
assert_eq!(sig.argument_types.len(), args.len());
|
assert_eq!(sig.params.len(), args.len());
|
||||||
|
|
||||||
let mut regs = AvailableRegs::new(&self.usable_regs);
|
let mut regs = AvailableRegs::new(&self.usable_regs);
|
||||||
|
|
||||||
for (lv, abi) in args.iter().zip(&sig.argument_types) {
|
for (lv, abi) in args.iter().zip(&sig.params) {
|
||||||
match lv.affinity {
|
match lv.affinity {
|
||||||
Affinity::Reg(rci) => {
|
Affinity::Reg(rci) => {
|
||||||
let rc = self.reginfo.rc(rci);
|
let rc = self.reginfo.rc(rci);
|
||||||
@@ -305,7 +305,7 @@ impl<'a> Context<'a> {
|
|||||||
program_input_abi(
|
program_input_abi(
|
||||||
&mut self.solver,
|
&mut self.solver,
|
||||||
inst,
|
inst,
|
||||||
&self.cur.func.dfg.signatures[sig].argument_types,
|
&self.cur.func.dfg.signatures[sig].params,
|
||||||
&self.cur.func,
|
&self.cur.func,
|
||||||
&self.liveness,
|
&self.liveness,
|
||||||
&self.reginfo,
|
&self.reginfo,
|
||||||
@@ -315,7 +315,7 @@ impl<'a> Context<'a> {
|
|||||||
program_input_abi(
|
program_input_abi(
|
||||||
&mut self.solver,
|
&mut self.solver,
|
||||||
inst,
|
inst,
|
||||||
&self.cur.func.signature.return_types,
|
&self.cur.func.signature.returns,
|
||||||
&self.cur.func,
|
&self.cur.func,
|
||||||
&self.liveness,
|
&self.liveness,
|
||||||
&self.reginfo,
|
&self.reginfo,
|
||||||
@@ -687,12 +687,9 @@ impl<'a> Context<'a> {
|
|||||||
// It's technically possible for a call instruction to have fixed results before the
|
// It's technically possible for a call instruction to have fixed results before the
|
||||||
// variable list of results, but we have no known instances of that.
|
// variable list of results, but we have no known instances of that.
|
||||||
// Just assume all results are variable return values.
|
// Just assume all results are variable return values.
|
||||||
assert_eq!(
|
assert_eq!(defs.len(), self.cur.func.dfg.signatures[sig].returns.len());
|
||||||
defs.len(),
|
|
||||||
self.cur.func.dfg.signatures[sig].return_types.len()
|
|
||||||
);
|
|
||||||
for (i, lv) in defs.iter().enumerate() {
|
for (i, lv) in defs.iter().enumerate() {
|
||||||
let abi = self.cur.func.dfg.signatures[sig].return_types[i];
|
let abi = self.cur.func.dfg.signatures[sig].returns[i];
|
||||||
if let ArgumentLoc::Reg(reg) = abi.location {
|
if let ArgumentLoc::Reg(reg) = abi.location {
|
||||||
if let Affinity::Reg(rci) = lv.affinity {
|
if let Affinity::Reg(rci) = lv.affinity {
|
||||||
let rc = self.reginfo.rc(rci);
|
let rc = self.reginfo.rc(rci);
|
||||||
@@ -1015,7 +1012,7 @@ impl<'a> Context<'a> {
|
|||||||
fn program_input_abi(
|
fn program_input_abi(
|
||||||
solver: &mut Solver,
|
solver: &mut Solver,
|
||||||
inst: Inst,
|
inst: Inst,
|
||||||
abi_types: &[ArgumentType],
|
abi_types: &[AbiParam],
|
||||||
func: &Function,
|
func: &Function,
|
||||||
liveness: &Liveness,
|
liveness: &Liveness,
|
||||||
reginfo: &RegInfo,
|
reginfo: &RegInfo,
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ fn get_or_create<'a>(
|
|||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
// If this is a call, get the return value affinity.
|
// If this is a call, get the return value affinity.
|
||||||
func.dfg.call_signature(inst).map(|sig| {
|
func.dfg.call_signature(inst).map(|sig| {
|
||||||
Affinity::abi(&func.dfg.signatures[sig].return_types[rnum], isa)
|
Affinity::abi(&func.dfg.signatures[sig].returns[rnum], isa)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
@@ -226,7 +226,7 @@ fn get_or_create<'a>(
|
|||||||
if func.layout.entry_block() == Some(ebb) {
|
if func.layout.entry_block() == Some(ebb) {
|
||||||
// The affinity for entry block parameters can be inferred from the function
|
// The affinity for entry block parameters can be inferred from the function
|
||||||
// signature.
|
// signature.
|
||||||
affinity = Affinity::abi(&func.signature.argument_types[num], isa);
|
affinity = Affinity::abi(&func.signature.params[num], isa);
|
||||||
} else {
|
} else {
|
||||||
// Don't apply any affinity to normal EBB parameters.
|
// Don't apply any affinity to normal EBB parameters.
|
||||||
// They could be in a register or on the stack.
|
// They could be in a register or on the stack.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use cursor::{Cursor, EncCursor};
|
|||||||
use dominator_tree::DominatorTree;
|
use dominator_tree::DominatorTree;
|
||||||
use entity::{SparseMap, SparseMapValue};
|
use entity::{SparseMap, SparseMapValue};
|
||||||
use ir::{Ebb, Inst, Value, Function};
|
use ir::{Ebb, Inst, Value, Function};
|
||||||
use ir::{InstBuilder, ArgumentType, ArgumentLoc};
|
use ir::{InstBuilder, AbiParam, ArgumentLoc};
|
||||||
use isa::RegClass;
|
use isa::RegClass;
|
||||||
use isa::{TargetIsa, Encoding, EncInfo, RecipeConstraints, ConstraintKind};
|
use isa::{TargetIsa, Encoding, EncInfo, RecipeConstraints, ConstraintKind};
|
||||||
use regalloc::affinity::Affinity;
|
use regalloc::affinity::Affinity;
|
||||||
@@ -137,20 +137,20 @@ impl<'a> Context<'a> {
|
|||||||
|
|
||||||
if self.cur.func.layout.entry_block() == Some(ebb) {
|
if self.cur.func.layout.entry_block() == Some(ebb) {
|
||||||
assert_eq!(liveins.len(), 0);
|
assert_eq!(liveins.len(), 0);
|
||||||
self.visit_entry_args(ebb, args);
|
self.visit_entry_params(ebb, args);
|
||||||
} else {
|
} else {
|
||||||
self.visit_ebb_params(ebb, args);
|
self.visit_ebb_params(ebb, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Visit the arguments to the entry block.
|
/// Visit the parameters on the entry block.
|
||||||
/// These values have ABI constraints from the function signature.
|
/// These values have ABI constraints from the function signature.
|
||||||
fn visit_entry_args(&mut self, ebb: Ebb, args: &[LiveValue]) {
|
fn visit_entry_params(&mut self, ebb: Ebb, args: &[LiveValue]) {
|
||||||
assert_eq!(self.cur.func.signature.argument_types.len(), args.len());
|
assert_eq!(self.cur.func.signature.params.len(), args.len());
|
||||||
self.cur.goto_first_inst(ebb);
|
self.cur.goto_first_inst(ebb);
|
||||||
|
|
||||||
for (arg_idx, arg) in args.iter().enumerate() {
|
for (arg_idx, arg) in args.iter().enumerate() {
|
||||||
let abi = self.cur.func.signature.argument_types[arg_idx];
|
let abi = self.cur.func.signature.params[arg_idx];
|
||||||
match abi.location {
|
match abi.location {
|
||||||
ArgumentLoc::Reg(_) => {
|
ArgumentLoc::Reg(_) => {
|
||||||
if arg.affinity.is_stack() {
|
if arg.affinity.is_stack() {
|
||||||
@@ -266,7 +266,7 @@ impl<'a> Context<'a> {
|
|||||||
"Extra results on non-call instruction",
|
"Extra results on non-call instruction",
|
||||||
);
|
);
|
||||||
for (i, lv) in retvals.iter().enumerate() {
|
for (i, lv) in retvals.iter().enumerate() {
|
||||||
let abi = self.cur.func.dfg.signatures[sig].return_types[i];
|
let abi = self.cur.func.dfg.signatures[sig].returns[i];
|
||||||
debug_assert!(abi.location.is_reg());
|
debug_assert!(abi.location.is_reg());
|
||||||
if lv.affinity.is_stack() {
|
if lv.affinity.is_stack() {
|
||||||
let reg = self.cur.func.dfg.replace_result(lv.value, abi.value_type);
|
let reg = self.cur.func.dfg.replace_result(lv.value, abi.value_type);
|
||||||
@@ -308,7 +308,7 @@ impl<'a> Context<'a> {
|
|||||||
if let Some(sig) = self.cur.func.dfg.call_signature(inst) {
|
if let Some(sig) = self.cur.func.dfg.call_signature(inst) {
|
||||||
handle_abi_args(
|
handle_abi_args(
|
||||||
self.candidates,
|
self.candidates,
|
||||||
&self.cur.func.dfg.signatures[sig].argument_types,
|
&self.cur.func.dfg.signatures[sig].params,
|
||||||
var_args,
|
var_args,
|
||||||
self.cur.isa,
|
self.cur.isa,
|
||||||
self.liveness,
|
self.liveness,
|
||||||
@@ -316,7 +316,7 @@ impl<'a> Context<'a> {
|
|||||||
} else if self.cur.func.dfg[inst].opcode().is_return() {
|
} else if self.cur.func.dfg[inst].opcode().is_return() {
|
||||||
handle_abi_args(
|
handle_abi_args(
|
||||||
self.candidates,
|
self.candidates,
|
||||||
&self.cur.func.signature.return_types,
|
&self.cur.func.signature.returns,
|
||||||
var_args,
|
var_args,
|
||||||
self.cur.isa,
|
self.cur.isa,
|
||||||
self.liveness,
|
self.liveness,
|
||||||
@@ -348,7 +348,7 @@ impl<'a> Context<'a> {
|
|||||||
/// return values and call arguments.
|
/// return values and call arguments.
|
||||||
fn handle_abi_args(
|
fn handle_abi_args(
|
||||||
candidates: &mut Vec<ReloadCandidate>,
|
candidates: &mut Vec<ReloadCandidate>,
|
||||||
abi_types: &[ArgumentType],
|
abi_types: &[AbiParam],
|
||||||
var_args: &[Value],
|
var_args: &[Value],
|
||||||
isa: &TargetIsa,
|
isa: &TargetIsa,
|
||||||
liveness: &Liveness,
|
liveness: &Liveness,
|
||||||
|
|||||||
@@ -324,7 +324,7 @@ impl<'a> Context<'a> {
|
|||||||
let args = self.cur.func.dfg.inst_variable_args(inst);
|
let args = self.cur.func.dfg.inst_variable_args(inst);
|
||||||
for (idx, (abi, &arg)) in
|
for (idx, (abi, &arg)) in
|
||||||
self.cur.func.dfg.signatures[sig]
|
self.cur.func.dfg.signatures[sig]
|
||||||
.argument_types
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.zip(args)
|
.zip(args)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ impl<'a> LocationVerifier<'a> {
|
|||||||
let varargs = self.func.dfg.inst_variable_args(inst);
|
let varargs = self.func.dfg.inst_variable_args(inst);
|
||||||
let results = self.func.dfg.inst_results(inst);
|
let results = self.func.dfg.inst_results(inst);
|
||||||
|
|
||||||
for (abi, &value) in sig.argument_types.iter().zip(varargs) {
|
for (abi, &value) in sig.params.iter().zip(varargs) {
|
||||||
self.check_abi_location(
|
self.check_abi_location(
|
||||||
inst,
|
inst,
|
||||||
value,
|
value,
|
||||||
@@ -139,7 +139,7 @@ impl<'a> LocationVerifier<'a> {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (abi, &value) in sig.return_types.iter().zip(results) {
|
for (abi, &value) in sig.returns.iter().zip(results) {
|
||||||
self.check_abi_location(
|
self.check_abi_location(
|
||||||
inst,
|
inst,
|
||||||
value,
|
value,
|
||||||
@@ -157,7 +157,7 @@ impl<'a> LocationVerifier<'a> {
|
|||||||
let sig = &self.func.signature;
|
let sig = &self.func.signature;
|
||||||
let varargs = self.func.dfg.inst_variable_args(inst);
|
let varargs = self.func.dfg.inst_variable_args(inst);
|
||||||
|
|
||||||
for (abi, &value) in sig.return_types.iter().zip(varargs) {
|
for (abi, &value) in sig.returns.iter().zip(varargs) {
|
||||||
self.check_abi_location(
|
self.check_abi_location(
|
||||||
inst,
|
inst,
|
||||||
value,
|
value,
|
||||||
@@ -175,7 +175,7 @@ impl<'a> LocationVerifier<'a> {
|
|||||||
&self,
|
&self,
|
||||||
inst: ir::Inst,
|
inst: ir::Inst,
|
||||||
value: ir::Value,
|
value: ir::Value,
|
||||||
abi: &ir::ArgumentType,
|
abi: &ir::AbiParam,
|
||||||
loc: ir::ValueLoc,
|
loc: ir::ValueLoc,
|
||||||
want_kind: ir::StackSlotKind,
|
want_kind: ir::StackSlotKind,
|
||||||
) -> Result {
|
) -> Result {
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ impl<'a> Verifier<'a> {
|
|||||||
let fixed_results = inst_data.opcode().constraints().fixed_results();
|
let fixed_results = inst_data.opcode().constraints().fixed_results();
|
||||||
// var_results is 0 if we aren't a call instruction
|
// var_results is 0 if we aren't a call instruction
|
||||||
let var_results = dfg.call_signature(inst)
|
let var_results = dfg.call_signature(inst)
|
||||||
.map(|sig| dfg.signatures[sig].return_types.len())
|
.map(|sig| dfg.signatures[sig].returns.len())
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
let total_results = fixed_results + var_results;
|
let total_results = fixed_results + var_results;
|
||||||
|
|
||||||
@@ -551,9 +551,9 @@ impl<'a> Verifier<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typecheck_entry_block_arguments(&self) -> Result {
|
fn typecheck_entry_block_params(&self) -> Result {
|
||||||
if let Some(ebb) = self.func.layout.entry_block() {
|
if let Some(ebb) = self.func.layout.entry_block() {
|
||||||
let expected_types = &self.func.signature.argument_types;
|
let expected_types = &self.func.signature.params;
|
||||||
let ebb_param_count = self.func.dfg.num_ebb_params(ebb);
|
let ebb_param_count = self.func.dfg.num_ebb_params(ebb);
|
||||||
|
|
||||||
if ebb_param_count != expected_types.len() {
|
if ebb_param_count != expected_types.len() {
|
||||||
@@ -700,18 +700,16 @@ impl<'a> Verifier<'a> {
|
|||||||
match self.func.dfg[inst].analyze_call(&self.func.dfg.value_lists) {
|
match self.func.dfg[inst].analyze_call(&self.func.dfg.value_lists) {
|
||||||
CallInfo::Direct(func_ref, _) => {
|
CallInfo::Direct(func_ref, _) => {
|
||||||
let sig_ref = self.func.dfg.ext_funcs[func_ref].signature;
|
let sig_ref = self.func.dfg.ext_funcs[func_ref].signature;
|
||||||
let arg_types = self.func.dfg.signatures[sig_ref]
|
let arg_types = self.func.dfg.signatures[sig_ref].params.iter().map(|a| {
|
||||||
.argument_types
|
a.value_type
|
||||||
.iter()
|
});
|
||||||
.map(|a| a.value_type);
|
|
||||||
self.typecheck_variable_args_iterator(inst, arg_types)?;
|
self.typecheck_variable_args_iterator(inst, arg_types)?;
|
||||||
self.check_outgoing_args(inst, sig_ref)?;
|
self.check_outgoing_args(inst, sig_ref)?;
|
||||||
}
|
}
|
||||||
CallInfo::Indirect(sig_ref, _) => {
|
CallInfo::Indirect(sig_ref, _) => {
|
||||||
let arg_types = self.func.dfg.signatures[sig_ref]
|
let arg_types = self.func.dfg.signatures[sig_ref].params.iter().map(|a| {
|
||||||
.argument_types
|
a.value_type
|
||||||
.iter()
|
});
|
||||||
.map(|a| a.value_type);
|
|
||||||
self.typecheck_variable_args_iterator(inst, arg_types)?;
|
self.typecheck_variable_args_iterator(inst, arg_types)?;
|
||||||
self.check_outgoing_args(inst, sig_ref)?;
|
self.check_outgoing_args(inst, sig_ref)?;
|
||||||
}
|
}
|
||||||
@@ -772,7 +770,7 @@ impl<'a> Verifier<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let args = self.func.dfg.inst_variable_args(inst);
|
let args = self.func.dfg.inst_variable_args(inst);
|
||||||
let expected_args = &sig.argument_types[..];
|
let expected_args = &sig.params[..];
|
||||||
|
|
||||||
for (&arg, &abi) in args.iter().zip(expected_args) {
|
for (&arg, &abi) in args.iter().zip(expected_args) {
|
||||||
// Value types have already been checked by `typecheck_variable_args_iterator()`.
|
// Value types have already been checked by `typecheck_variable_args_iterator()`.
|
||||||
@@ -828,7 +826,7 @@ impl<'a> Verifier<'a> {
|
|||||||
fn typecheck_return(&self, inst: Inst) -> Result {
|
fn typecheck_return(&self, inst: Inst) -> Result {
|
||||||
if self.func.dfg[inst].opcode().is_return() {
|
if self.func.dfg[inst].opcode().is_return() {
|
||||||
let args = self.func.dfg.inst_variable_args(inst);
|
let args = self.func.dfg.inst_variable_args(inst);
|
||||||
let expected_types = &self.func.signature.return_types;
|
let expected_types = &self.func.signature.returns;
|
||||||
if args.len() != expected_types.len() {
|
if args.len() != expected_types.len() {
|
||||||
return err!(inst, "arguments of return must match function signature");
|
return err!(inst, "arguments of return must match function signature");
|
||||||
}
|
}
|
||||||
@@ -1081,7 +1079,7 @@ impl<'a> Verifier<'a> {
|
|||||||
|
|
||||||
pub fn run(&self) -> Result {
|
pub fn run(&self) -> Result {
|
||||||
self.verify_global_vars()?;
|
self.verify_global_vars()?;
|
||||||
self.typecheck_entry_block_arguments()?;
|
self.typecheck_entry_block_params()?;
|
||||||
for ebb in self.func.layout.ebbs() {
|
for ebb in self.func.layout.ebbs() {
|
||||||
for inst in self.func.layout.ebb_insts(ebb) {
|
for inst in self.func.layout.ebb_insts(ebb) {
|
||||||
self.ebb_integrity(ebb, inst)?;
|
self.ebb_integrity(ebb, inst)?;
|
||||||
|
|||||||
@@ -529,14 +529,14 @@ where
|
|||||||
fn check_return_args(&self, args: &[Value]) {
|
fn check_return_args(&self, args: &[Value]) {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
args.len(),
|
args.len(),
|
||||||
self.func.signature.return_types.len(),
|
self.func.signature.returns.len(),
|
||||||
"the number of returned values doesn't match the function signature "
|
"the number of returned values doesn't match the function signature "
|
||||||
);
|
);
|
||||||
for (i, arg) in args.iter().enumerate() {
|
for (i, arg) in args.iter().enumerate() {
|
||||||
let valty = self.func.dfg.value_type(*arg);
|
let valty = self.func.dfg.value_type(*arg);
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
valty,
|
valty,
|
||||||
self.func.signature.return_types[i].value_type,
|
self.func.signature.returns[i].value_type,
|
||||||
"the types of the values returned don't match the \
|
"the types of the values returned don't match the \
|
||||||
function signature"
|
function signature"
|
||||||
);
|
);
|
||||||
@@ -545,7 +545,7 @@ where
|
|||||||
|
|
||||||
fn fill_function_args_values(&mut self, ebb: Ebb) {
|
fn fill_function_args_values(&mut self, ebb: Ebb) {
|
||||||
debug_assert!(self.pristine);
|
debug_assert!(self.pristine);
|
||||||
for argtyp in &self.func.signature.argument_types {
|
for argtyp in &self.func.signature.params {
|
||||||
self.builder.function_args_values.push(
|
self.builder.function_args_values.push(
|
||||||
self.func.dfg.append_ebb_param(ebb, argtyp.value_type),
|
self.func.dfg.append_ebb_param(ebb, argtyp.value_type),
|
||||||
);
|
);
|
||||||
@@ -621,7 +621,7 @@ where
|
|||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use cretonne::entity::EntityRef;
|
use cretonne::entity::EntityRef;
|
||||||
use cretonne::ir::{FunctionName, Function, CallConv, Signature, ArgumentType, InstBuilder};
|
use cretonne::ir::{FunctionName, Function, CallConv, Signature, AbiParam, InstBuilder};
|
||||||
use cretonne::ir::types::*;
|
use cretonne::ir::types::*;
|
||||||
use frontend::{ILBuilder, FunctionBuilder};
|
use frontend::{ILBuilder, FunctionBuilder};
|
||||||
use cretonne::verifier::verify_function;
|
use cretonne::verifier::verify_function;
|
||||||
@@ -651,8 +651,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn sample_function() {
|
fn sample_function() {
|
||||||
let mut sig = Signature::new(CallConv::Native);
|
let mut sig = Signature::new(CallConv::Native);
|
||||||
sig.return_types.push(ArgumentType::new(I32));
|
sig.returns.push(AbiParam::new(I32));
|
||||||
sig.argument_types.push(ArgumentType::new(I32));
|
sig.params.push(AbiParam::new(I32));
|
||||||
|
|
||||||
let mut il_builder = ILBuilder::<Variable>::new();
|
let mut il_builder = ILBuilder::<Variable>::new();
|
||||||
let mut func = Function::with_name_signature(FunctionName::new("sample_function"), sig);
|
let mut func = Function::with_name_signature(FunctionName::new("sample_function"), sig);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
//! extern crate cton_frontend;
|
//! extern crate cton_frontend;
|
||||||
//!
|
//!
|
||||||
//! use cretonne::entity::EntityRef;
|
//! use cretonne::entity::EntityRef;
|
||||||
//! use cretonne::ir::{FunctionName, CallConv, Function, Signature, ArgumentType, InstBuilder};
|
//! use cretonne::ir::{FunctionName, CallConv, Function, Signature, AbiParam, InstBuilder};
|
||||||
//! use cretonne::ir::types::*;
|
//! use cretonne::ir::types::*;
|
||||||
//! use cretonne::settings;
|
//! use cretonne::settings;
|
||||||
//! use cton_frontend::{ILBuilder, FunctionBuilder};
|
//! use cton_frontend::{ILBuilder, FunctionBuilder};
|
||||||
@@ -64,8 +64,8 @@
|
|||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! let mut sig = Signature::new(CallConv::Native);
|
//! let mut sig = Signature::new(CallConv::Native);
|
||||||
//! sig.return_types.push(ArgumentType::new(I32));
|
//! sig.returns.push(AbiParam::new(I32));
|
||||||
//! sig.argument_types.push(ArgumentType::new(I32));
|
//! sig.params.push(AbiParam::new(I32));
|
||||||
//! let mut il_builder = ILBuilder::<Variable>::new();
|
//! let mut il_builder = ILBuilder::<Variable>::new();
|
||||||
//! let mut func = Function::with_name_signature(FunctionName::new("sample_function"), sig);
|
//! let mut func = Function::with_name_signature(FunctionName::new("sample_function"), sig);
|
||||||
//! {
|
//! {
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ use std::str::FromStr;
|
|||||||
use std::{u16, u32};
|
use std::{u16, u32};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use cretonne::ir::{Function, Ebb, Opcode, Value, Type, FunctionName, CallConv, StackSlotData,
|
use cretonne::ir::{Function, Ebb, Opcode, Value, Type, FunctionName, CallConv, StackSlotData,
|
||||||
JumpTable, JumpTableData, Signature, ArgumentType, ArgumentExtension,
|
JumpTable, JumpTableData, Signature, AbiParam, ArgumentExtension, ExtFuncData,
|
||||||
ExtFuncData, SigRef, FuncRef, StackSlot, ValueLoc, ArgumentLoc, MemFlags,
|
SigRef, FuncRef, StackSlot, ValueLoc, ArgumentLoc, MemFlags, GlobalVar,
|
||||||
GlobalVar, GlobalVarData, Heap, HeapData, HeapStyle, HeapBase};
|
GlobalVarData, Heap, HeapData, HeapStyle, HeapBase};
|
||||||
use cretonne::ir;
|
use cretonne::ir;
|
||||||
use cretonne::ir::types::VOID;
|
use cretonne::ir::types::VOID;
|
||||||
use cretonne::ir::immediates::{Imm64, Uimm32, Offset32, Ieee32, Ieee64};
|
use cretonne::ir::immediates::{Imm64, Uimm32, Offset32, Ieee32, Ieee64};
|
||||||
@@ -918,7 +918,7 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
// Parse a function signature.
|
// Parse a function signature.
|
||||||
//
|
//
|
||||||
// signature ::= * "(" [arglist] ")" ["->" retlist] [callconv]
|
// signature ::= * "(" [paramlist] ")" ["->" retlist] [callconv]
|
||||||
//
|
//
|
||||||
fn parse_signature(&mut self, unique_isa: Option<&TargetIsa>) -> Result<Signature> {
|
fn parse_signature(&mut self, unique_isa: Option<&TargetIsa>) -> Result<Signature> {
|
||||||
// Calling convention defaults to `native`, but can be changed.
|
// Calling convention defaults to `native`, but can be changed.
|
||||||
@@ -928,16 +928,16 @@ impl<'a> Parser<'a> {
|
|||||||
Token::LPar,
|
Token::LPar,
|
||||||
"expected function signature: ( args... )",
|
"expected function signature: ( args... )",
|
||||||
)?;
|
)?;
|
||||||
// signature ::= "(" * [arglist] ")" ["->" retlist] [callconv]
|
// signature ::= "(" * [abi-param-list] ")" ["->" retlist] [callconv]
|
||||||
if self.token() != Some(Token::RPar) {
|
if self.token() != Some(Token::RPar) {
|
||||||
sig.argument_types = self.parse_argument_list(unique_isa)?;
|
sig.params = self.parse_abi_param_list(unique_isa)?;
|
||||||
}
|
}
|
||||||
self.match_token(
|
self.match_token(
|
||||||
Token::RPar,
|
Token::RPar,
|
||||||
"expected ')' after function arguments",
|
"expected ')' after function arguments",
|
||||||
)?;
|
)?;
|
||||||
if self.optional(Token::Arrow) {
|
if self.optional(Token::Arrow) {
|
||||||
sig.return_types = self.parse_argument_list(unique_isa)?;
|
sig.returns = self.parse_abi_param_list(unique_isa)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The calling convention is optional.
|
// The calling convention is optional.
|
||||||
@@ -951,38 +951,38 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sig.argument_types.iter().all(|a| a.location.is_assigned()) {
|
if sig.params.iter().all(|a| a.location.is_assigned()) {
|
||||||
sig.compute_argument_bytes();
|
sig.compute_argument_bytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(sig)
|
Ok(sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse list of function argument / return value types.
|
// Parse list of function parameter / return value types.
|
||||||
//
|
//
|
||||||
// arglist ::= * arg { "," arg }
|
// paramlist ::= * param { "," param }
|
||||||
//
|
//
|
||||||
fn parse_argument_list(&mut self, unique_isa: Option<&TargetIsa>) -> Result<Vec<ArgumentType>> {
|
fn parse_abi_param_list(&mut self, unique_isa: Option<&TargetIsa>) -> Result<Vec<AbiParam>> {
|
||||||
let mut list = Vec::new();
|
let mut list = Vec::new();
|
||||||
|
|
||||||
// arglist ::= * arg { "," arg }
|
// abi-param-list ::= * abi-param { "," abi-param }
|
||||||
list.push(self.parse_argument_type(unique_isa)?);
|
list.push(self.parse_abi_param(unique_isa)?);
|
||||||
|
|
||||||
// arglist ::= arg * { "," arg }
|
// abi-param-list ::= abi-param * { "," abi-param }
|
||||||
while self.optional(Token::Comma) {
|
while self.optional(Token::Comma) {
|
||||||
// arglist ::= arg { "," * arg }
|
// abi-param-list ::= abi-param { "," * abi-param }
|
||||||
list.push(self.parse_argument_type(unique_isa)?);
|
list.push(self.parse_abi_param(unique_isa)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(list)
|
Ok(list)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse a single argument type with flags.
|
// Parse a single argument type with flags.
|
||||||
fn parse_argument_type(&mut self, unique_isa: Option<&TargetIsa>) -> Result<ArgumentType> {
|
fn parse_abi_param(&mut self, unique_isa: Option<&TargetIsa>) -> Result<AbiParam> {
|
||||||
// arg ::= * type { flag } [ argumentloc ]
|
// abi-param ::= * type { flag } [ argumentloc ]
|
||||||
let mut arg = ArgumentType::new(self.match_type("expected argument type")?);
|
let mut arg = AbiParam::new(self.match_type("expected parameter type")?);
|
||||||
|
|
||||||
// arg ::= type * { flag } [ argumentloc ]
|
// abi-param ::= type * { flag } [ argumentloc ]
|
||||||
while let Some(Token::Identifier(s)) = self.token() {
|
while let Some(Token::Identifier(s)) = self.token() {
|
||||||
match s {
|
match s {
|
||||||
"uext" => arg.extension = ArgumentExtension::Uext,
|
"uext" => arg.extension = ArgumentExtension::Uext,
|
||||||
@@ -998,7 +998,7 @@ impl<'a> Parser<'a> {
|
|||||||
self.consume();
|
self.consume();
|
||||||
}
|
}
|
||||||
|
|
||||||
// arg ::= type { flag } * [ argumentloc ]
|
// abi-param ::= type { flag } * [ argumentloc ]
|
||||||
arg.location = self.parse_argument_location(unique_isa)?;
|
arg.location = self.parse_argument_location(unique_isa)?;
|
||||||
|
|
||||||
Ok(arg)
|
Ok(arg)
|
||||||
@@ -1374,7 +1374,7 @@ impl<'a> Parser<'a> {
|
|||||||
self.parse_ebb_params(ctx, ebb)?;
|
self.parse_ebb_params(ctx, ebb)?;
|
||||||
self.match_token(
|
self.match_token(
|
||||||
Token::Colon,
|
Token::Colon,
|
||||||
"expected ':' after EBB arguments",
|
"expected ':' after EBB parameters",
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1437,7 +1437,7 @@ impl<'a> Parser<'a> {
|
|||||||
// ebb-params ::= * "(" ebb-param { "," ebb-param } ")"
|
// ebb-params ::= * "(" ebb-param { "," ebb-param } ")"
|
||||||
self.match_token(
|
self.match_token(
|
||||||
Token::LPar,
|
Token::LPar,
|
||||||
"expected '(' before EBB arguments",
|
"expected '(' before EBB parameters",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// ebb-params ::= "(" * ebb-param { "," ebb-param } ")"
|
// ebb-params ::= "(" * ebb-param { "," ebb-param } ")"
|
||||||
@@ -1452,7 +1452,7 @@ impl<'a> Parser<'a> {
|
|||||||
// ebb-params ::= "(" ebb-param { "," ebb-param } * ")"
|
// ebb-params ::= "(" ebb-param { "," ebb-param } * ")"
|
||||||
self.match_token(
|
self.match_token(
|
||||||
Token::RPar,
|
Token::RPar,
|
||||||
"expected ')' after EBB arguments",
|
"expected ')' after EBB parameters",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -2337,13 +2337,13 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn argument_type() {
|
fn argument_type() {
|
||||||
let mut p = Parser::new("i32 sext");
|
let mut p = Parser::new("i32 sext");
|
||||||
let arg = p.parse_argument_type(None).unwrap();
|
let arg = p.parse_abi_param(None).unwrap();
|
||||||
assert_eq!(arg.value_type, types::I32);
|
assert_eq!(arg.value_type, types::I32);
|
||||||
assert_eq!(arg.extension, ArgumentExtension::Sext);
|
assert_eq!(arg.extension, ArgumentExtension::Sext);
|
||||||
assert_eq!(arg.purpose, ArgumentPurpose::Normal);
|
assert_eq!(arg.purpose, ArgumentPurpose::Normal);
|
||||||
let Error { location, message } = p.parse_argument_type(None).unwrap_err();
|
let Error { location, message } = p.parse_abi_param(None).unwrap_err();
|
||||||
assert_eq!(location.line_number, 1);
|
assert_eq!(location.line_number, 1);
|
||||||
assert_eq!(message, "expected argument type");
|
assert_eq!(message, "expected parameter type");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -2374,8 +2374,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn signature() {
|
fn signature() {
|
||||||
let sig = Parser::new("()native").parse_signature(None).unwrap();
|
let sig = Parser::new("()native").parse_signature(None).unwrap();
|
||||||
assert_eq!(sig.argument_types.len(), 0);
|
assert_eq!(sig.params.len(), 0);
|
||||||
assert_eq!(sig.return_types.len(), 0);
|
assert_eq!(sig.returns.len(), 0);
|
||||||
assert_eq!(sig.call_conv, CallConv::Native);
|
assert_eq!(sig.call_conv, CallConv::Native);
|
||||||
|
|
||||||
let sig2 = Parser::new("(i8 uext, f32, f64, i32 sret) -> i32 sext, f64 spiderwasm")
|
let sig2 = Parser::new("(i8 uext, f32, f64, i32 sret) -> i32 sext, f64 spiderwasm")
|
||||||
@@ -2406,7 +2406,7 @@ mod tests {
|
|||||||
.parse_signature(None)
|
.parse_signature(None)
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
"1: expected argument type"
|
"1: expected parameter type"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Parser::new("i8 -> i8")
|
Parser::new("i8 -> i8")
|
||||||
|
|||||||
@@ -100,14 +100,14 @@ impl FuncTranslator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Declare local variables for the signature arguments that correspond to WebAssembly locals.
|
/// Declare local variables for the signature parameters that correspond to WebAssembly locals.
|
||||||
///
|
///
|
||||||
/// Return the number of local variables declared.
|
/// Return the number of local variables declared.
|
||||||
fn declare_wasm_arguments(builder: &mut FunctionBuilder<Local>) -> usize {
|
fn declare_wasm_arguments(builder: &mut FunctionBuilder<Local>) -> usize {
|
||||||
let sig_len = builder.func.signature.argument_types.len();
|
let sig_len = builder.func.signature.params.len();
|
||||||
let mut next_local = 0;
|
let mut next_local = 0;
|
||||||
for i in 0..sig_len {
|
for i in 0..sig_len {
|
||||||
let arg_type = builder.func.signature.argument_types[i];
|
let arg_type = builder.func.signature.params[i];
|
||||||
// There may be additional special-purpose arguments following the normal WebAssembly
|
// There may be additional special-purpose arguments following the normal WebAssembly
|
||||||
// signature arguments. For example, a `vmctx` pointer.
|
// signature arguments. For example, a `vmctx` pointer.
|
||||||
if arg_type.purpose == ir::ArgumentPurpose::Normal {
|
if arg_type.purpose == ir::ArgumentPurpose::Normal {
|
||||||
@@ -256,12 +256,8 @@ mod tests {
|
|||||||
let mut ctx = Context::new();
|
let mut ctx = Context::new();
|
||||||
|
|
||||||
ctx.func.name = ir::FunctionName::new("small1");
|
ctx.func.name = ir::FunctionName::new("small1");
|
||||||
ctx.func.signature.argument_types.push(
|
ctx.func.signature.params.push(ir::AbiParam::new(I32));
|
||||||
ir::ArgumentType::new(I32),
|
ctx.func.signature.returns.push(ir::AbiParam::new(I32));
|
||||||
);
|
|
||||||
ctx.func.signature.return_types.push(
|
|
||||||
ir::ArgumentType::new(I32),
|
|
||||||
);
|
|
||||||
|
|
||||||
trans
|
trans
|
||||||
.translate(&BODY, &mut ctx.func, &mut runtime.func_env())
|
.translate(&BODY, &mut ctx.func, &mut runtime.func_env())
|
||||||
@@ -291,12 +287,8 @@ mod tests {
|
|||||||
let mut ctx = Context::new();
|
let mut ctx = Context::new();
|
||||||
|
|
||||||
ctx.func.name = ir::FunctionName::new("small2");
|
ctx.func.name = ir::FunctionName::new("small2");
|
||||||
ctx.func.signature.argument_types.push(
|
ctx.func.signature.params.push(ir::AbiParam::new(I32));
|
||||||
ir::ArgumentType::new(I32),
|
ctx.func.signature.returns.push(ir::AbiParam::new(I32));
|
||||||
);
|
|
||||||
ctx.func.signature.return_types.push(
|
|
||||||
ir::ArgumentType::new(I32),
|
|
||||||
);
|
|
||||||
|
|
||||||
trans
|
trans
|
||||||
.translate(&BODY, &mut ctx.func, &mut runtime.func_env())
|
.translate(&BODY, &mut ctx.func, &mut runtime.func_env())
|
||||||
@@ -335,9 +327,7 @@ mod tests {
|
|||||||
let mut ctx = Context::new();
|
let mut ctx = Context::new();
|
||||||
|
|
||||||
ctx.func.name = ir::FunctionName::new("infloop");
|
ctx.func.name = ir::FunctionName::new("infloop");
|
||||||
ctx.func.signature.return_types.push(
|
ctx.func.signature.returns.push(ir::AbiParam::new(I32));
|
||||||
ir::ArgumentType::new(I32),
|
|
||||||
);
|
|
||||||
|
|
||||||
trans
|
trans
|
||||||
.translate(&BODY, &mut ctx.func, &mut runtime.func_env())
|
.translate(&BODY, &mut ctx.func, &mut runtime.func_env())
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
//! interpreted on the fly.
|
//! interpreted on the fly.
|
||||||
use translation_utils::{type_to_type, TableIndex, FunctionIndex, GlobalIndex, SignatureIndex,
|
use translation_utils::{type_to_type, TableIndex, FunctionIndex, GlobalIndex, SignatureIndex,
|
||||||
MemoryIndex, Global, GlobalInit, Table, TableElementType, Memory};
|
MemoryIndex, Global, GlobalInit, Table, TableElementType, Memory};
|
||||||
use cretonne::ir::{Signature, ArgumentType, CallConv};
|
use cretonne::ir::{Signature, AbiParam, CallConv};
|
||||||
use cretonne;
|
use cretonne;
|
||||||
use wasmparser::{Parser, ParserState, FuncType, ImportSectionEntryType, ExternalKind, WasmDecoder,
|
use wasmparser::{Parser, ParserState, FuncType, ImportSectionEntryType, ExternalKind, WasmDecoder,
|
||||||
MemoryType, Operator};
|
MemoryType, Operator};
|
||||||
@@ -35,17 +35,17 @@ pub fn parse_function_signatures(
|
|||||||
ref returns,
|
ref returns,
|
||||||
}) => {
|
}) => {
|
||||||
let mut sig = Signature::new(CallConv::Native);
|
let mut sig = Signature::new(CallConv::Native);
|
||||||
sig.argument_types.extend(params.iter().map(|ty| {
|
sig.params.extend(params.iter().map(|ty| {
|
||||||
let cret_arg: cretonne::ir::Type = type_to_type(ty).expect(
|
let cret_arg: cretonne::ir::Type = type_to_type(ty).expect(
|
||||||
"only numeric types are supported in function signatures",
|
"only numeric types are supported in function signatures",
|
||||||
);
|
);
|
||||||
ArgumentType::new(cret_arg)
|
AbiParam::new(cret_arg)
|
||||||
}));
|
}));
|
||||||
sig.return_types.extend(returns.iter().map(|ty| {
|
sig.returns.extend(returns.iter().map(|ty| {
|
||||||
let cret_arg: cretonne::ir::Type = type_to_type(ty).expect(
|
let cret_arg: cretonne::ir::Type = type_to_type(ty).expect(
|
||||||
"only numeric types are supported in function signatures",
|
"only numeric types are supported in function signatures",
|
||||||
);
|
);
|
||||||
ArgumentType::new(cret_arg)
|
AbiParam::new(cret_arg)
|
||||||
}));
|
}));
|
||||||
environ.declare_signature(&sig);
|
environ.declare_signature(&sig);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ impl TranslationState {
|
|||||||
self.clear();
|
self.clear();
|
||||||
self.push_block(
|
self.push_block(
|
||||||
exit_block,
|
exit_block,
|
||||||
sig.return_types
|
sig.returns
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|arg| arg.purpose == ir::ArgumentPurpose::Normal)
|
.filter(|arg| arg.purpose == ir::ArgumentPurpose::Normal)
|
||||||
.count(),
|
.count(),
|
||||||
@@ -323,10 +323,10 @@ impl TranslationState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Count the number of normal arguments in a signature.
|
/// Count the number of normal parameters in a signature.
|
||||||
/// Exclude special-purpose arguments that represent runtime stuff and not WebAssembly arguments.
|
/// Exclude special-purpose parameters that represent runtime stuff and not WebAssembly arguments.
|
||||||
fn normal_args(sig: &ir::Signature) -> usize {
|
fn normal_args(sig: &ir::Signature) -> usize {
|
||||||
sig.argument_types
|
sig.params
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|arg| arg.purpose == ir::ArgumentPurpose::Normal)
|
.filter(|arg| arg.purpose == ir::ArgumentPurpose::Normal)
|
||||||
.count()
|
.count()
|
||||||
|
|||||||
Reference in New Issue
Block a user