fn compute_argument_locations(
    arg_types: &Vec<P<MuType>>,
    stack: &P<Value>,
    offset: i64,
    is_callee_saved: bool,
    vm: &VM
) -> (Vec<bool>, Vec<P<Value>>, usize) {
    if arg_types.len() == 0 {
        // nothing to do
        return (vec![], vec![], 0);
    }

    let fpr_regs = if is_callee_saved {
        CALLEE_SAVED_FPRS.as_ref()
    } else {
        ARGUMENT_FPRS.as_ref()
    };

    let gpr_regs = if is_callee_saved {
        CALLEE_SAVED_GPRS.as_ref()
    } else {
        ARGUMENT_GPRS.as_ref()
    };

    let mut ngrn = 0 as usize; // The Next General-purpose Register Number
    let mut nsrn = 0 as usize; // The Next SIMD and Floating-point Register Number
    let mut nsaa = 0 as usize; // The next stacked argument address (an offset from the SP)
    use ast::types::MuType_::*;

    // reference[i] = true indicates the argument is passed an IRef to a location on the stack
    let mut reference: Vec<bool> = vec![];
    for t in arg_types {
        reference.push(
            hfa_length(t) == 0 && // HFA's aren't converted to IRef's
                match t.v {
                    // size can't be statically determined
                    Hybrid(_) => panic!("Hybrid argument not supported"),
                    //  type is too large
                    Struct(_) | Array(_, _) if vm.get_backend_type_size(t.id()) > 16 => true,
                    Vector(_, _)  => unimplemented!(),
                    _ => false
                }
        );
    }
    // TODO: How does passing arguments by reference effect the stack size??
    let mut locations: Vec<P<Value>> = vec![];
    for i in 0..arg_types.len() {
        let i = i as usize;
        let t = if reference[i] {
            P(MuType::new(
                new_internal_id(),
                MuType_::IRef(arg_types[i].clone())
            ))
        } else {
            arg_types[i].clone()
        };
        let size = align_up(vm.get_backend_type_size(t.id()), 8);
        let align = get_type_alignment(&t, vm);
        match t.v {
            Hybrid(_) => panic!("hybrid argument not supported"),

            Vector(_, _) => unimplemented!(),
            Float | Double => {
                if nsrn < 8 {
                    locations.push(get_alias_for_length(
                        fpr_regs[nsrn].id(),
                        get_bit_size(&t, vm)
                    ));
                    nsrn += 1;
                } else {
                    nsrn = 8;
                    locations.push(make_value_base_offset(
                        &stack,
                        offset + (nsaa as i64),
                        &t,
                        vm
                    ));
                    nsaa += size;
                }
            }
            Struct(_) | Array(_, _) => {
                let hfa_n = hfa_length(&t);
                if hfa_n > 0 {
                    if nsrn + hfa_n <= 8 {
                        // Note: the argument will occupy succesiv registers
                        // (one for each element)
                        locations.push(get_alias_for_length(
                            fpr_regs[nsrn].id(),
                            get_bit_size(&t, vm) / hfa_n
                        ));
                        nsrn += hfa_n;
                    } else {
                        nsrn = 8;
                        locations.push(make_value_base_offset(
                            &stack,
                            offset + (nsaa as i64),
                            &t,
                            vm
                        ));
                        nsaa += size;
                    }
                } else {
                    if align == 16 {
                        ngrn = align_up(ngrn, 2); // align NGRN to the next even number
                    }

                    if size <= 8 * (8 - ngrn) {
                        // The struct should be packed, starting here
                        // (note: this may result in multiple struct fields in the same regsiter
                        // or even floating points in a GPR)
                        locations.push(gpr_regs[ngrn].clone());
                        // How many GPRS are taken up by t
                        ngrn += if size % 8 != 0 {
                            size / 8 + 1
                        } else {
                            size / 8
                        };
                    } else {
                        ngrn = 8;
                        nsaa = align_up(nsaa, align_up(align, 8));
                        locations.push(make_value_base_offset(
                            &stack,
                            offset + (nsaa as i64) as i64,
                            &t,
                            vm
                        ));
                        nsaa += size;
                    }
                }
            }

            Void => panic!("void argument not supported"),

            // Integral or pointer type
            _ => {
                if size <= 8 {
                    if ngrn < 8 {
                        locations.push(get_alias_for_length(
                            gpr_regs[ngrn].id(),
                            get_bit_size(&t, vm)
                        ));
                        ngrn += 1;
                    } else {
                        nsaa = align_up(nsaa, align_up(align, 8));
                        locations.push(make_value_base_offset(
                            &stack,
                            offset + (nsaa as i64) as i64,
                            &t,
                            vm
                        ));
                        nsaa += size;
                    }

                } else if size == 16 {
                    ngrn = align_up(ngrn, 2); // align NGRN to the next even number

                    if ngrn < 7 {
                        locations.push(gpr_regs[ngrn].clone());
                        ngrn += 2;
                    } else {
                        ngrn = 8;
                        nsaa = align_up(nsaa, 16);
                        locations.push(make_value_base_offset(
                            &stack,
                            offset + (nsaa as i64) as i64,
                            &t,
                            vm
                        ));
                        nsaa += 16;
                    }
                } else {
                    unimplemented!(); // Integer type is too large
                }
            }
        }
    }

    (reference, locations, align_up(nsaa, 16) as usize)
}
// TODO: Thoroughly test this
// (compare with code generated by GCC with variouse different types???)
// The algorithm presented here is derived from the ARM AAPCS64 reference
// Returns a vector indicating whether each should be passed as an IRef (and not directly),
// a vector referencing to the location of each argument (in memory or a register) and
// the amount of stack space used
// NOTE: It currently does not support vectors/SIMD types (or aggregates of such types)
Thoroughly test this
(compare with code generated by GCC with variouse different types???)
The algorithm presented here is derived from the ARM AAPCS64 reference
Returns a vector indicating whether each should be passed as an IRef (and not directly),
a vector referencing to the location of each argument (in memory or a register) and
the amount of stack space used
NOTE: It currently does not support vectors/SIMD types (or aggregates of such types)
Thoroughly test this ( compare with code generated by GCC with variouse different types??? ) The algorithm presented here is derived from the ARM AAPCS64 reference Returns a vector indicating whether each should be passed as an IRef ( and not directly ) a vector referencing to the location of each argument ( in memory or a register ) and the amount of stack space used NOTE : It currently does not support vectors / SIMD types ( or aggregates of such types )
fn compute_argument_locations(
    arg_types: &Vec<P<MuType>>,
    stack: &P<Value>,
    offset: i64,
    is_callee_saved: bool,
    vm: &VM
) -> (Vec<bool>, Vec<P<Value>>, usize) {
    if arg_types.len() == 0 {
        // nothing to do
        return (vec![], vec![], 0);
    }
    let fpr_regs = if is_callee_saved {
        CALLEE_SAVED_FPRS.as_ref()
    } else {
        ARGUMENT_FPRS.as_ref()
    };
    let gpr_regs = if is_callee_saved {
        CALLEE_SAVED_GPRS.as_ref()
    } else {
        ARGUMENT_GPRS.as_ref()
    };
    let mut ngrn = 0 as usize; // The Next General-purpose Register Number
    let mut nsrn = 0 as usize; // The Next SIMD and Floating-point Register Number
    let mut nsaa = 0 as usize; // The next stacked argument address (an offset from the SP)
    use ast::types::MuType_::*;
    // reference[i] = true indicates the argument is passed an IRef to a location on the stack
    let mut reference: Vec<bool> = vec![];
    for t in arg_types {
        reference.push(
            hfa_length(t) == 0 && // HFA's aren't converted to IRef's
                match t.v {
                    // size can't be statically determined
                    Hybrid(_) => panic!("Hybrid argument not supported"),
                    //  type is too large
                    Struct(_) | Array(_, _) if vm.get_backend_type_size(t.id()) > 16 => true,
                    Vector(_, _)  => unimplemented!(),
                    _ => false
                }
        );
    }
    // TODO: How does passing arguments by reference effect the stack size??
    let mut locations: Vec<P<Value>> = vec![];
    for i in 0..arg_types.len() {
        let i = i as usize;
        let t = if reference[i] {
            P(MuType::new(
                new_internal_id(),
                MuType_::IRef(arg_types[i].clone())
            ))
        } else {
            arg_types[i].clone()
        };
        let size = align_up(vm.get_backend_type_size(t.id()), 8);
        let align = get_type_alignment(&t, vm);
        match t.v {
            Hybrid(_) => panic!("hybrid argument not supported"),
            Vector(_, _) => unimplemented!(),
            Float | Double => {
                if nsrn < 8 {
                    locations.push(get_alias_for_length(
                        fpr_regs[nsrn].id(),
                        get_bit_size(&t, vm)
                    ));
                    nsrn += 1;
                } else {
                    nsrn = 8;
                    locations.push(make_value_base_offset(
                        &stack,
                        offset + (nsaa as i64),
                        &t,
                        vm
                    ));
                    nsaa += size;
                }
            }
            Struct(_) | Array(_, _) => {
                let hfa_n = hfa_length(&t);
                if hfa_n > 0 {
                    if nsrn + hfa_n <= 8 {
                        // Note: the argument will occupy succesiv registers
                        // (one for each element)
                        locations.push(get_alias_for_length(
                            fpr_regs[nsrn].id(),
                            get_bit_size(&t, vm) / hfa_n
                        ));
                        nsrn += hfa_n;
                    } else {
                        nsrn = 8;
                        locations.push(make_value_base_offset(
                            &stack,
                            offset + (nsaa as i64),
                            &t,
                            vm
                        ));
                        nsaa += size;
                    }
                } else {
                    if align == 16 {
                        ngrn = align_up(ngrn, 2); // align NGRN to the next even number
                    }
                    if size <= 8 * (8 - ngrn) {
                        // The struct should be packed, starting here
                        // (note: this may result in multiple struct fields in the same regsiter
                        // or even floating points in a GPR)
                        locations.push(gpr_regs[ngrn].clone());
                        // How many GPRS are taken up by t
                        ngrn += if size % 8 != 0 {
                            size / 8 + 1
                        } else {
                            size / 8
                        };
                    } else {
                        ngrn = 8;
                        nsaa = align_up(nsaa, align_up(align, 8));
                        locations.push(make_value_base_offset(
                            &stack,
                            offset + (nsaa as i64) as i64,
                            &t,
                            vm
                        ));
                        nsaa += size;
                    }
                }
            }
            Void => panic!("void argument not supported"),
            // Integral or pointer type
            _ => {
                if size <= 8 {
                    if ngrn < 8 {
                        locations.push(get_alias_for_length(
                            gpr_regs[ngrn].id(),
                            get_bit_size(&t, vm)
                        ));
                        ngrn += 1;
                    } else {
                        nsaa = align_up(nsaa, align_up(align, 8));
                        locations.push(make_value_base_offset(
                            &stack,
                            offset + (nsaa as i64) as i64,
                            &t,
                            vm
                        ));
                        nsaa += size;
                    }
                } else if size == 16 {
                    ngrn = align_up(ngrn, 2); // align NGRN to the next even number
                    if ngrn < 7 {
                        locations.push(gpr_regs[ngrn].clone());
                        ngrn += 2;
                    } else {
                        ngrn = 8;
                        nsaa = align_up(nsaa, 16);
                        locations.push(make_value_base_offset(
                            &stack,
                            offset + (nsaa as i64) as i64,
                            &t,
                            vm
                        ));
                        nsaa += 16;
                    }
                } else {
                    unimplemented!(); // Integer type is too large
                }
            }
        }
    }
    (reference, locations, align_up(nsaa, 16) as usize)
}
fn compute_argument_locations ( arg_types : & Vec < P < MuType > > , stack : & P < Value > , offset : i64 , is_callee_saved : bool , vm : & VM ) -> ( Vec < bool > , Vec < P < Value > > , usize ) { if arg_types . len ( ) == 0 { // nothing to do return ( vec ! [ ] , vec ! [ ] , 0 ) ; } let fpr_regs = if is_callee_saved { CALLEE_SAVED_FPRS . as_ref ( ) } else { ARGUMENT_FPRS . as_ref ( ) } ; let gpr_regs = if is_callee_saved { CALLEE_SAVED_GPRS . as_ref ( ) } else { ARGUMENT_GPRS . as_ref ( ) } ; let mut ngrn = 0 as usize ; // The Next General-purpose Register Number let mut nsrn = 0 as usize ; // The Next SIMD and Floating-point Register Number let mut nsaa = 0 as usize ; // The next stacked argument address (an offset from the SP) use ast :: types :: MuType_ :: * ; // reference[i] = true indicates the argument is passed an IRef to a location on the stack let mut reference : Vec < bool > = vec ! [ ] ; for t in arg_types { reference . push ( hfa_length ( t ) == 0 && // HFA's aren't converted to IRef's match t . v { // size can't be statically determined Hybrid ( _ ) => panic ! ( " " ) , //  type is too large Struct ( _ ) | Array ( _ , _ ) if vm . get_backend_type_size ( t . id ( ) ) > 16 => true , Vector ( _ , _ ) => unimplemented ! ( ) , _ => false } ) ; } // TODO: How does passing arguments by reference effect the stack size?? let mut locations : Vec < P < Value > > = vec ! [ ] ; for i in 0 .. arg_types . len ( ) { let i = i as usize ; let t = if reference [ i ] { P ( MuType :: new ( new_internal_id ( ) , MuType_ :: IRef ( arg_types [ i ] . clone ( ) ) ) ) } else { arg_types [ i ] . clone ( ) } ; let size = align_up ( vm . get_backend_type_size ( t . id ( ) ) , 8 ) ; let align = get_type_alignment ( & t , vm ) ; match t . v { Hybrid ( _ ) => panic ! ( " " ) , Vector ( _ , _ ) => unimplemented ! ( ) , Float | Double => { if nsrn < 8 { locations . push ( get_alias_for_length ( fpr_regs [ nsrn ] . id ( ) , get_bit_size ( & t , vm ) ) ) ; nsrn += 1 ; } else { nsrn = 8 ; locations . push ( make_value_base_offset ( & stack , offset + ( nsaa as i64 ) , & t , vm ) ) ; nsaa += size ; } } Struct ( _ ) | Array ( _ , _ ) => { let hfa_n = hfa_length ( & t ) ; if hfa_n > 0 { if nsrn + hfa_n <= 8 { // Note: the argument will occupy succesiv registers // (one for each element) locations . push ( get_alias_for_length ( fpr_regs [ nsrn ] . id ( ) , get_bit_size ( & t , vm ) / hfa_n ) ) ; nsrn += hfa_n ; } else { nsrn = 8 ; locations . push ( make_value_base_offset ( & stack , offset + ( nsaa as i64 ) , & t , vm ) ) ; nsaa += size ; } } else { if align == 16 { ngrn = align_up ( ngrn , 2 ) ; // align NGRN to the next even number } if size <= 8 * ( 8 - ngrn ) { // The struct should be packed, starting here // (note: this may result in multiple struct fields in the same regsiter // or even floating points in a GPR) locations . push ( gpr_regs [ ngrn ] . clone ( ) ) ; // How many GPRS are taken up by t ngrn += if size % 8 != 0 { size / 8 + 1 } else { size / 8 } ; } else { ngrn = 8 ; nsaa = align_up ( nsaa , align_up ( align , 8 ) ) ; locations . push ( make_value_base_offset ( & stack , offset + ( nsaa as i64 ) as i64 , & t , vm ) ) ; nsaa += size ; } } } Void => panic ! ( " " ) , // Integral or pointer type _ => { if size <= 8 { if ngrn < 8 { locations . push ( get_alias_for_length ( gpr_regs [ ngrn ] . id ( ) , get_bit_size ( & t , vm ) ) ) ; ngrn += 1 ; } else { nsaa = align_up ( nsaa , align_up ( align , 8 ) ) ; locations . push ( make_value_base_offset ( & stack , offset + ( nsaa as i64 ) as i64 , & t , vm ) ) ; nsaa += size ; } } else if size == 16 { ngrn = align_up ( ngrn , 2 ) ; // align NGRN to the next even number if ngrn < 7 { locations . push ( gpr_regs [ ngrn ] . clone ( ) ) ; ngrn += 2 ; } else { ngrn = 8 ; nsaa = align_up ( nsaa , 16 ) ; locations . push ( make_value_base_offset ( & stack , offset + ( nsaa as i64 ) as i64 , & t , vm ) ) ; nsaa += 16 ; } } else { unimplemented ! ( ) ; // Integer type is too large } } } } ( reference , locations , align_up ( nsaa , 16 ) as usize ) }
TODO: Thoroughly test this
(compare with code generated by GCC with variouse different types???)
TODO : Thoroughly test this ( compare with code generated by GCC with variouse different types??? )
arg_types
&Vec<P<MuType>>
stack
&P<Value>
offset
i64
is_callee_saved
bool
vm
&VM
arg_types
&Vec<P<MuType>>
stack
&P<Value>
offset
i64
is_callee_saved
bool
vm
&VM