-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtypes.c
197 lines (171 loc) · 4.89 KB
/
types.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
* types.c -- type handling functions
* Copyright 2010 Kalle A. Sandström <ksandstr@iki.fi>
*
* This file is part of µiX.
*
* µiX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* µiX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with µiX. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <llvm-c/Core.h>
#include <libIDL/IDL.h>
#include "defs.h"
#include "llvmutil.h"
#include "l4x2.h"
bool is_integral_type(IDL_tree typ)
{
switch(IDL_NODE_TYPE(typ)) {
case IDLN_TYPE_INTEGER:
case IDLN_TYPE_OCTET:
case IDLN_TYPE_CHAR:
case IDLN_TYPE_WIDE_CHAR:
case IDLN_TYPE_BOOLEAN:
return true;
default:
return IS_WORD_TYPE(typ);
}
}
#if 0
bool is_signed(IDL_tree typ)
{
assert(is_integral_type(typ));
return IDL_NODE_TYPE(typ) == IDLN_TYPE_CHAR
|| IDL_NODE_TYPE(typ) == IDLN_TYPE_WIDE_CHAR
|| (IDL_NODE_TYPE(typ) == IDLN_TYPE_INTEGER
&& IDL_TYPE_INTEGER(typ).f_signed);
}
#endif
/* returns a LLVM representation corresponding to the C translation of the
* given IDL type.
*/
LLVMTypeRef llvm_value_type(struct llvm_ctx *ctx, IDL_tree type)
{
if(type == NULL) return LLVMVoidTypeInContext(ctx->ctx);
switch(IDL_NODE_TYPE(type)) {
case IDLN_TYPE_INTEGER: {
static short bitlens[] = {
[IDL_INTEGER_TYPE_SHORT] = 16,
[IDL_INTEGER_TYPE_LONG] = 32,
[IDL_INTEGER_TYPE_LONGLONG] = 64,
};
int t = IDL_TYPE_INTEGER(type).f_type;
assert(t < G_N_ELEMENTS(bitlens));
return LLVMIntTypeInContext(ctx->ctx, bitlens[t]);
}
case IDLN_NATIVE: {
/* each of these is the size of a single word, which is all LLVM
* wants to know.
*/
if(IS_WORD_TYPE(type) || IS_FPAGE_TYPE(type)
|| IS_TIME_TYPE(type))
{
return ctx->wordt;
} else {
fprintf(stderr, "%s: native type `%s' not supported\n",
__FUNCTION__, NATIVE_NAME(type));
abort();
}
break;
}
case IDLN_TYPE_FLOAT:
switch(IDL_TYPE_FLOAT(type).f_type) {
case IDL_FLOAT_TYPE_FLOAT:
return LLVMFloatTypeInContext(ctx->ctx);
case IDL_FLOAT_TYPE_DOUBLE:
return LLVMDoubleTypeInContext(ctx->ctx);
case IDL_FLOAT_TYPE_LONGDOUBLE:
return LLVMFP128TypeInContext(ctx->ctx);
}
g_assert_not_reached();
case IDLN_TYPE_BOOLEAN:
case IDLN_TYPE_OCTET:
case IDLN_TYPE_CHAR:
return LLVMInt8TypeInContext(ctx->ctx);
case IDLN_TYPE_WIDE_CHAR:
return ctx->i32t;
case IDLN_TYPE_ENUM: return LLVMInt16TypeInContext(ctx->ctx);
default:
NOTDEFINED(type);
}
}
/* TODO: cache outputs by the struct type's repo id, like in
* packed_format_of()
*/
LLVMTypeRef llvm_struct_type(
struct llvm_ctx *ctx,
char ***names_p,
IDL_tree type)
{
assert(IDL_NODE_TYPE(type) == IDLN_TYPE_STRUCT);
GArray *types = g_array_new(FALSE, FALSE, sizeof(T));
GPtrArray *names = names_p != NULL ? g_ptr_array_new() : NULL;
struct member_item *members = expand_member_list(
IDL_TYPE_STRUCT(type).member_list);
for(int i=0; members[i].type != NULL; i++) {
IDL_tree mtype = members[i].type;
T mt = llvm_rigid_type(ctx, mtype);
if(members[i].dim == 0) {
g_array_append_val(types, mt);
} else {
T ary = LLVMArrayType(mt, members[i].dim);
g_array_append_val(types, ary);
}
if(names_p != NULL) {
g_ptr_array_add(names, g_strdup(members[i].name));
}
}
g_free(members);
if(names_p != NULL) {
char **namev = g_new(char *, names->len + 1);
for(int i=0; i<names->len; i++) namev[i] = names->pdata[i];
namev[names->len] = NULL;
g_ptr_array_free(names, TRUE);
(*names_p) = namev;
}
T ret = LLVMStructTypeInContext(ctx->ctx, &g_array_index(types, T, 0),
types->len, is_packed(type) ? 1 : 0);
g_array_free(types, TRUE);
return ret;
}
/* arrays, while rigid according to is_rigid_type(), don't have a distinct LLVM
* representation.
*/
LLVMTypeRef llvm_rigid_type(struct llvm_ctx *ctx, IDL_tree type)
{
if(type == NULL) return LLVMVoidTypeInContext(ctx->ctx);
switch(IDL_NODE_TYPE(type)) {
case IDLN_TYPE_STRUCT:
return llvm_struct_type(ctx, NULL, type);
case IDLN_TYPE_UNION:
/* TODO */
case IDLN_NATIVE:
if(IS_MAPGRANT_TYPE(type)) return ctx->mapgrant;
/* FALL THRU */
case IDLN_TYPE_ARRAY:
default:
if(is_value_type(type)) return llvm_value_type(ctx, type);
else {
NOTDEFINED(type);
}
}
}
bool is_byval_param(IDL_tree pdecl)
{
return pdecl != NULL
&& IDL_NODE_TYPE(pdecl) == IDLN_PARAM_DCL
&& IDL_PARAM_DCL(pdecl).attr == IDL_PARAM_IN
&& is_value_type(get_type_spec(IDL_PARAM_DCL(pdecl).param_type_spec));
}