powerpc64.rs 4.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2014-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
// FIXME:
12 13 14
// Alignment of 128 bit types is not currently handled, this will
// need to be fixed when PowerPC vector support is added.

15 16
use abi::call::{FnType, ArgType, Reg, RegKind, Uniform};
use abi::{Align, Endian, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
17

18 19 20 21 22 23 24
#[derive(Debug, Clone, Copy, PartialEq)]
enum ABI {
    ELFv1, // original ABI used for powerpc64 (big-endian)
    ELFv2, // newer ABI used for powerpc64le
}
use self::ABI::*;

25 26 27 28 29
fn is_homogeneous_aggregate<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>, abi: ABI) 
                                       -> Option<Uniform>
    where Ty: TyLayoutMethods<'a, C> + Copy,
          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
{                                   
30
    arg.layout.homogeneous_aggregate(cx).and_then(|unit| {
31 32
        // ELFv1 only passes one-member aggregates transparently.
        // ELFv2 passes up to eight uniquely addressable members.
33
        if (abi == ELFv1 && arg.layout.size > unit.size)
34
                || arg.layout.size > unit.size.checked_mul(8, cx).unwrap() {
35
            return None;
36 37
        }

38 39 40
        let valid_unit = match unit.kind {
            RegKind::Integer => false,
            RegKind::Float => true,
41
            RegKind::Vector => arg.layout.size.bits() == 128
42
        };
43

44 45 46
        if valid_unit {
            Some(Uniform {
                unit,
47
                total: arg.layout.size
48
            })
49 50 51 52 53 54
        } else {
            None
        }
    })
}

55 56 57 58
fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<'a, Ty>, abi: ABI)
    where Ty: TyLayoutMethods<'a, C> + Copy,
          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
{
59
    if !ret.layout.is_aggregate() {
60
        ret.extend_integer_width_to(64);
61
        return;
62 63
    }

64 65
    // The ELFv1 ABI doesn't return aggregates in registers
    if abi == ELFv1 {
66
        ret.make_indirect();
67
        return;
68 69
    }

70
    if let Some(uniform) = is_homogeneous_aggregate(cx, ret, abi) {
71
        ret.cast_to(uniform);
72
        return;
73
    }
74

75
    let size = ret.layout.size;
76 77 78 79 80 81 82 83
    let bits = size.bits();
    if bits <= 128 {
        let unit = if bits <= 8 {
            Reg::i8()
        } else if bits <= 16 {
            Reg::i16()
        } else if bits <= 32 {
            Reg::i32()
84
        } else {
85
            Reg::i64()
86
        };
87

88
        ret.cast_to(Uniform {
89 90 91
            unit,
            total: size
        });
92
        return;
93 94
    }

95
    ret.make_indirect();
96 97
}

98 99 100 101
fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>, abi: ABI)
    where Ty: TyLayoutMethods<'a, C> + Copy,
          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
{
102
    if !arg.layout.is_aggregate() {
103
        arg.extend_integer_width_to(64);
104
        return;
105
    }
106

107
    if let Some(uniform) = is_homogeneous_aggregate(cx, arg, abi) {
108
        arg.cast_to(uniform);
109
        return;
110 111
    }

112
    let size = arg.layout.size;
113 114 115 116 117 118 119 120
    let (unit, total) = match abi {
        ELFv1 => {
            // In ELFv1, aggregates smaller than a doubleword should appear in
            // the least-significant bits of the parameter doubleword.  The rest
            // should be padded at their tail to fill out multiple doublewords.
            if size.bits() <= 64 {
                (Reg { kind: RegKind::Integer, size }, size)
            } else {
121
                let align = Align::from_bits(64, 64).unwrap();
122 123 124 125 126 127 128 129 130
                (Reg::i64(), size.abi_align(align))
            }
        },
        ELFv2 => {
            // In ELFv2, we can just cast directly.
            (Reg::i64(), size)
        },
    };

131
    arg.cast_to(Uniform {
132
        unit,
133 134
        total
    });
135 136
}

137 138 139 140 141 142 143
pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>)
    where Ty: TyLayoutMethods<'a, C> + Copy,
          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
{
    let abi = match cx.data_layout().endian {
        Endian::Big => ELFv1,
        Endian::Little => ELFv2,
144 145
    };

146
    if !fty.ret.is_ignore() {
147
        classify_ret_ty(cx, &mut fty.ret, abi);
148
    }
149

150
    for arg in &mut fty.args {
151
        if arg.is_ignore() { continue; }
152
        classify_arg_ty(cx, arg, abi);
153
    }
154
}