1#!/usr/bin/env python3
2# © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
3#
4# SPDX-License-Identifier: BSD-3-Clause
5
6import abc
7
8
9class CType:
10    def __init__(self, name, is_signed, size, align=None, bitsize=None):
11        self.name = name
12        self.is_signed = is_signed
13        self.size = size
14        self.align = size if align is None else align
15        self.bitsize = bitsize
16
17
18class ABI(metaclass=abc.ABCMeta):
19    """
20    Abstract base class for ABI definitions.
21    """
22
23    def __init__(self):
24        basic_ctypes = (
25            CType('bool', False, 1, bitsize=1),
26            CType('uint8_t', False, 1),
27            CType('uint16_t', False, 2),
28            CType('uint32_t', False, 4),
29            CType('uint64_t', False, 8),
30            CType('uintptr_t', False, self.pointer_size,
31                  align=self.pointer_align),
32            CType('int8_t', True, 1),
33            CType('int16_t', True, 2),
34            CType('int32_t', True, 4),
35            CType('int64_t', True, 8),
36            CType('intptr_t', True, self.pointer_size,
37                  align=self.pointer_align),
38            CType('char', self.signed_char, 1),
39            CType('size_t', False, self.pointer_size,
40                  align=self.pointer_align),
41            CType('uregister_t', False, self.register_size,
42                  align=self.register_align),
43        )
44        self.c_types = {t.name: t for t in basic_ctypes}
45
46    @staticmethod
47    def is_power2(val):
48        """Returns true if number is a power of two"""
49        return ((val & (val - 1)) == 0) and (val > 0)
50
51    @abc.abstractproperty
52    def pointer_size(self):
53        """The size of a pointer, in bytes."""
54        raise NotImplementedError
55
56    @property
57    def pointer_align(self):
58        """The alignment of a pointer, in bytes."""
59        return self.pointer_size
60
61    @abc.abstractproperty
62    def register_size(self):
63        """The size of a register, in bytes."""
64        raise NotImplementedError
65
66    @property
67    def register_align(self):
68        """The alignment of a register, in bytes."""
69        return self.pointer_size
70
71    @abc.abstractproperty
72    def signed_char(self):
73        """True if the char type is signed."""
74        raise NotImplementedError
75
76    def get_c_type(self, type_name):
77        return self.c_types[type_name]
78
79    @abc.abstractmethod
80    def get_c_type_name(self, abi_type_name):
81        """Return the c name for the abi type name."""
82        raise NotImplementedError
83
84    def layout_struct_member(self, current_offset, current_alignment,
85                             next_size, next_alignment):
86        """
87        Return the offset at which a new struct member should be placed.
88
89        In principle this is entirely implementation-defined, but nearly all
90        implementations use the same algorithm: add enough padding bytes to
91        align the next member, and no more. Any ABI that does something
92        different can override this.
93
94        The current_offset argument is the size of the structure in bytes up
95        to the end of the last member. This is always nonzero, because
96        structures are not allowed to be padded at the start, so this function
97        is only called for the second member onwards.
98
99        The current_align argument is the largest alignment that has been seen
100        in the members added to the struct so far.
101
102        If next_size is not None, the next_size and next_alignment arguments
103        are the size and alignment of the member that is being added to the
104        struct. The return value in this case is the offset of the new member.
105
106        If next_size is None, all members have been added and this function
107        should determine the amount of padding at the end of the structure.
108        The return value in this case is the final size of the structure.
109
110        The return value in any case should be an integer that is not less
111        than current_offset.
112        """
113        if next_size is not None:
114            alignment = next_alignment
115        else:
116            alignment = current_alignment
117        assert (self.is_power2(alignment))
118
119        align_mask = alignment - 1
120        return (current_offset + align_mask) & ~align_mask
121
122    @abc.abstractmethod
123    def get_enum_properties(self, e_min, e_max):
124        """
125        Returns the size, alignment and signedness of the enum.
126
127        Calculates the underlying type properties that the ABI will use for
128        an enum with the given enumerator value range.
129        """
130        raise NotImplementedError
131
132
133class AArch64ABI(ABI):
134    abi_type_map = {
135        'uregister_t': 'uint64_t',
136        'sregister_t': 'int64_t',
137    }
138
139    @property
140    def pointer_size(self):
141        """The size of a pointer, in bytes."""
142        return 8
143
144    @property
145    def register_size(self):
146        """The size of a register, in bytes."""
147        return 8
148
149    @property
150    def signed_char(self):
151        """True if the char type is signed."""
152        return True
153
154    def get_c_type_name(self, abi_type_name):
155        """Return the c name for the abi type name."""
156        assert (abi_type_name in self.abi_type_map)
157        return self.abi_type_map[abi_type_name]
158
159    def get_enum_properties(self, e_min, e_max):
160        """
161        Returns the size, alignment and signedness of the enum.
162
163        Calculates the underlying type properties that the ABI will use for
164        an enum with the given enumerator value range.
165        """
166
167        min_bits = e_min.bit_length()
168        max_bits = e_max.bit_length()
169
170        signed = e_min < 0
171
172        if not signed and max_bits <= 32:
173            return (4, 4, False)
174        elif signed and max_bits <= 31 and min_bits <= 32:
175            return (4, 4, True)
176        elif not signed and max_bits <= 64:
177            return (8, 8, False)
178        elif signed and max_bits <= 63 and min_bits <= 64:
179            return (8, 8, True)
180        else:
181            raise NotImplementedError
182