python-cc 0.0.5__py3-none-any.whl → 0.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pcc/codegen/c_codegen.py +2940 -565
- pcc/evaluater/c_evaluator.py +1192 -47
- pcc/lex/c_lexer.py +24 -5
- pcc/parse/c_parser.py +124 -51
- pcc/pcc.py +198 -5
- pcc/ply/yacc.py +1 -1
- pcc/project.py +934 -9
- python_cc-0.0.7.dist-info/METADATA +429 -0
- {python_cc-0.0.5.dist-info → python_cc-0.0.7.dist-info}/RECORD +38 -33
- utils/fake_libc_include/TargetConditionals.h +16 -0
- utils/fake_libc_include/_fake_typedefs.h +46 -42
- utils/fake_libc_include/assert.h +4 -0
- utils/fake_libc_include/errno.h +82 -0
- utils/fake_libc_include/fcntl.h +132 -0
- utils/fake_libc_include/langinfo.h +13 -0
- utils/fake_libc_include/limits.h +13 -0
- utils/fake_libc_include/locale.h +43 -0
- utils/fake_libc_include/poll.h +23 -0
- utils/fake_libc_include/pwd.h +21 -0
- utils/fake_libc_include/setjmp.h +2 -0
- utils/fake_libc_include/signal.h +71 -0
- utils/fake_libc_include/strings.h +12 -0
- utils/fake_libc_include/sys/ioctl.h +2 -0
- utils/fake_libc_include/sys/mman.h +27 -0
- utils/fake_libc_include/sys/select.h +30 -0
- utils/fake_libc_include/sys/stat.h +77 -0
- utils/fake_libc_include/sys/time.h +10 -0
- utils/fake_libc_include/termios.h +56 -0
- utils/fake_libc_include/time.h +9 -0
- utils/fake_libc_include/unistd.h +37 -0
- utils/fake_libc_include/utime.h +7 -0
- utils/fake_libc_include/wchar.h +21 -0
- utils/fake_libc_include/wctype.h +18 -0
- utils/internal/refresh_clang_c_manifest.py +88 -0
- utils/internal/refresh_gcc_torture_manifest.py +145 -0
- python_cc-0.0.5.dist-info/METADATA +0 -185
- {python_cc-0.0.5.dist-info → python_cc-0.0.7.dist-info}/WHEEL +0 -0
- {python_cc-0.0.5.dist-info → python_cc-0.0.7.dist-info}/entry_points.txt +0 -0
- {python_cc-0.0.5.dist-info → python_cc-0.0.7.dist-info}/licenses/LICENSE +0 -0
pcc/codegen/c_codegen.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import llvmlite.ir as ir
|
|
2
|
+
import math
|
|
2
3
|
import re
|
|
3
4
|
import struct
|
|
4
5
|
from collections import ChainMap
|
|
5
|
-
from contextlib import contextmanager
|
|
6
|
+
from contextlib import contextmanager, nullcontext
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from itertools import count
|
|
6
9
|
from llvmlite.ir import IRBuilder
|
|
7
10
|
from ..ast import c_ast as c_ast
|
|
8
11
|
|
|
@@ -10,6 +13,7 @@ bool_t = ir.IntType(1)
|
|
|
10
13
|
int8_t = ir.IntType(8)
|
|
11
14
|
int32_t = ir.IntType(32)
|
|
12
15
|
int64_t = ir.IntType(64)
|
|
16
|
+
int128_t = ir.IntType(128)
|
|
13
17
|
voidptr_t = int8_t.as_pointer()
|
|
14
18
|
int64ptr_t = int64_t.as_pointer()
|
|
15
19
|
true_bit = bool_t(1)
|
|
@@ -18,6 +22,52 @@ true_byte = int8_t(1)
|
|
|
18
22
|
false_byte = int8_t(0)
|
|
19
23
|
cstring = voidptr_t
|
|
20
24
|
struct_types = {}
|
|
25
|
+
_aggregate_namespace_counter = count(1)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SemanticError(ValueError):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class FileScopeObjectState:
|
|
34
|
+
type_key: str
|
|
35
|
+
linkage: str
|
|
36
|
+
definition_kind: str
|
|
37
|
+
symbol_name: str
|
|
38
|
+
ir_type: object
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class FileScopeFunctionState:
|
|
43
|
+
type_key: str
|
|
44
|
+
linkage: str
|
|
45
|
+
defined: bool
|
|
46
|
+
symbol_name: str
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class StructFieldLayout:
|
|
51
|
+
name: object
|
|
52
|
+
byte_offset: int
|
|
53
|
+
semantic_ir_type: object
|
|
54
|
+
decl_type: object
|
|
55
|
+
is_bitfield: bool = False
|
|
56
|
+
storage_byte_offset: int = 0
|
|
57
|
+
storage_ir_type: object = None
|
|
58
|
+
bit_offset: int = 0
|
|
59
|
+
bit_width: int = 0
|
|
60
|
+
is_unsigned: bool = False
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class BitFieldRef:
|
|
65
|
+
container_ptr: object
|
|
66
|
+
storage_ir_type: object
|
|
67
|
+
bit_offset: int
|
|
68
|
+
bit_width: int
|
|
69
|
+
semantic_ir_type: object
|
|
70
|
+
is_unsigned: bool
|
|
21
71
|
|
|
22
72
|
# Libc function signature registry: name -> (return_type, [param_types], var_arg)
|
|
23
73
|
# Covers: stdio.h, stdlib.h, string.h, ctype.h, math.h, unistd.h, time.h
|
|
@@ -92,6 +142,15 @@ LIBC_FUNCTIONS = {
|
|
|
92
142
|
"qsort": (_VOID, [voidptr_t, _size_t, _size_t, voidptr_t], False),
|
|
93
143
|
"bsearch": (voidptr_t, [voidptr_t, voidptr_t, _size_t, _size_t, voidptr_t], False),
|
|
94
144
|
"getenv": (cstring, [cstring], False),
|
|
145
|
+
"getlogin": (cstring, [], False),
|
|
146
|
+
"getpwent": (voidptr_t, [], False),
|
|
147
|
+
"getpwnam": (voidptr_t, [cstring], False),
|
|
148
|
+
"getpwuid": (voidptr_t, [int32_t], False),
|
|
149
|
+
"setpwent": (_VOID, [], False),
|
|
150
|
+
"endpwent": (_VOID, [], False),
|
|
151
|
+
"setenv": (int32_t, [cstring, cstring, int32_t], False),
|
|
152
|
+
"putenv": (int32_t, [cstring], False),
|
|
153
|
+
"unsetenv": (int32_t, [cstring], False),
|
|
95
154
|
"system": (int32_t, [cstring], False),
|
|
96
155
|
# === string.h ===
|
|
97
156
|
"strlen": (_size_t, [cstring], False),
|
|
@@ -101,6 +160,8 @@ LIBC_FUNCTIONS = {
|
|
|
101
160
|
"strncpy": (cstring, [cstring, cstring, _size_t], False),
|
|
102
161
|
"strcat": (cstring, [cstring, cstring], False),
|
|
103
162
|
"strncat": (cstring, [cstring, cstring, _size_t], False),
|
|
163
|
+
"strlcpy": (_size_t, [cstring, cstring, _size_t], False),
|
|
164
|
+
"strlcat": (_size_t, [cstring, cstring, _size_t], False),
|
|
104
165
|
"strchr": (cstring, [cstring, int32_t], False),
|
|
105
166
|
"strrchr": (cstring, [cstring, int32_t], False),
|
|
106
167
|
"strstr": (cstring, [cstring, cstring], False),
|
|
@@ -128,6 +189,34 @@ LIBC_FUNCTIONS = {
|
|
|
128
189
|
"isgraph": (int32_t, [int32_t], False),
|
|
129
190
|
"toupper": (int32_t, [int32_t], False),
|
|
130
191
|
"tolower": (int32_t, [int32_t], False),
|
|
192
|
+
# === wchar.h / wctype.h ===
|
|
193
|
+
"mbtowc": (int32_t, [int32_t.as_pointer(), cstring, _size_t], False),
|
|
194
|
+
"wctomb": (int32_t, [cstring, int32_t], False),
|
|
195
|
+
"mbrlen": (_size_t, [cstring, _size_t, voidptr_t], False),
|
|
196
|
+
"mbrtowc": (_size_t, [int32_t.as_pointer(), cstring, _size_t, voidptr_t], False),
|
|
197
|
+
"mbsrtowcs": (_size_t, [int32_t.as_pointer(), voidptr_t, _size_t, voidptr_t], False),
|
|
198
|
+
"mbstowcs": (_size_t, [int32_t.as_pointer(), cstring, _size_t], False),
|
|
199
|
+
"wcrtomb": (_size_t, [cstring, int32_t, voidptr_t], False),
|
|
200
|
+
"wcsrtombs": (_size_t, [cstring, voidptr_t, _size_t, voidptr_t], False),
|
|
201
|
+
"wcstombs": (_size_t, [cstring, voidptr_t, _size_t], False),
|
|
202
|
+
"wcwidth": (int32_t, [int32_t], False),
|
|
203
|
+
"wcswidth": (int32_t, [voidptr_t, _size_t], False),
|
|
204
|
+
"wmemchr": (voidptr_t, [voidptr_t, int32_t, _size_t], False),
|
|
205
|
+
"wmemcpy": (voidptr_t, [voidptr_t, voidptr_t, _size_t], False),
|
|
206
|
+
"wmemmove": (voidptr_t, [voidptr_t, voidptr_t, _size_t], False),
|
|
207
|
+
"wmemcmp": (int32_t, [voidptr_t, voidptr_t, _size_t], False),
|
|
208
|
+
"iswalnum": (int32_t, [int32_t], False),
|
|
209
|
+
"iswalpha": (int32_t, [int32_t], False),
|
|
210
|
+
"iswcntrl": (int32_t, [int32_t], False),
|
|
211
|
+
"iswctype": (int32_t, [int32_t, int32_t], False),
|
|
212
|
+
"iswgraph": (int32_t, [int32_t], False),
|
|
213
|
+
"iswlower": (int32_t, [int32_t], False),
|
|
214
|
+
"iswprint": (int32_t, [int32_t], False),
|
|
215
|
+
"iswspace": (int32_t, [int32_t], False),
|
|
216
|
+
"iswupper": (int32_t, [int32_t], False),
|
|
217
|
+
"towlower": (int32_t, [int32_t], False),
|
|
218
|
+
"towupper": (int32_t, [int32_t], False),
|
|
219
|
+
"wctype": (int32_t, [cstring], False),
|
|
131
220
|
# === math.h ===
|
|
132
221
|
"sin": (_double, [_double], False),
|
|
133
222
|
"cos": (_double, [_double], False),
|
|
@@ -153,7 +242,9 @@ LIBC_FUNCTIONS = {
|
|
|
153
242
|
"round": (_double, [_double], False),
|
|
154
243
|
"trunc": (_double, [_double], False),
|
|
155
244
|
"fmod": (_double, [_double, _double], False),
|
|
245
|
+
"fabsf": (_float, [_float], False),
|
|
156
246
|
"fabs": (_double, [_double], False),
|
|
247
|
+
"fabsl": (_double, [_double], False),
|
|
157
248
|
"ldexp": (_double, [_double, int32_t], False),
|
|
158
249
|
# === time.h ===
|
|
159
250
|
"time": (_time_t, [voidptr_t], False),
|
|
@@ -161,36 +252,75 @@ LIBC_FUNCTIONS = {
|
|
|
161
252
|
"difftime": (_double, [_time_t, _time_t], False),
|
|
162
253
|
"gmtime_r": (voidptr_t, [voidptr_t, voidptr_t], False),
|
|
163
254
|
"localtime_r": (voidptr_t, [voidptr_t, voidptr_t], False),
|
|
255
|
+
"nanosleep": (int32_t, [voidptr_t, voidptr_t], False),
|
|
164
256
|
# === unistd.h (POSIX) ===
|
|
165
257
|
"sleep": (int32_t, [int32_t], False),
|
|
258
|
+
"alarm": (int32_t, [int32_t], False),
|
|
166
259
|
"usleep": (int32_t, [int32_t], False),
|
|
167
260
|
"read": (int64_t, [int32_t, voidptr_t, _size_t], False),
|
|
168
261
|
"write": (int64_t, [int32_t, voidptr_t, _size_t], False),
|
|
262
|
+
"getuid": (int32_t, [], False),
|
|
263
|
+
"geteuid": (int32_t, [], False),
|
|
169
264
|
"open": (int32_t, [cstring, int32_t], True),
|
|
170
265
|
"close": (int32_t, [int32_t], False),
|
|
266
|
+
"access": (int32_t, [cstring, int32_t], False),
|
|
267
|
+
"fcntl": (int32_t, [int32_t, int32_t], True),
|
|
268
|
+
"fsync": (int32_t, [int32_t], False),
|
|
269
|
+
"ftruncate": (int32_t, [int32_t, int64_t], False),
|
|
270
|
+
"pread": (int64_t, [int32_t, voidptr_t, _size_t, int64_t], False),
|
|
271
|
+
"pwrite": (int64_t, [int32_t, voidptr_t, _size_t, int64_t], False),
|
|
272
|
+
"unlink": (int32_t, [cstring], False),
|
|
273
|
+
"readlink": (int64_t, [cstring, cstring, _size_t], False),
|
|
171
274
|
"getpid": (int32_t, [], False),
|
|
172
275
|
"getppid": (int32_t, [], False),
|
|
276
|
+
"sysconf": (int64_t, [int32_t], False),
|
|
173
277
|
"isatty": (int32_t, [int32_t], False),
|
|
174
278
|
"mkstemp": (int32_t, [cstring], False),
|
|
279
|
+
"tcdrain": (int32_t, [int32_t], False),
|
|
280
|
+
"tcflow": (int32_t, [int32_t, int32_t], False),
|
|
281
|
+
"tcgetattr": (int32_t, [int32_t, voidptr_t], False),
|
|
282
|
+
"tcsetattr": (int32_t, [int32_t, int32_t, voidptr_t], False),
|
|
283
|
+
"select": (int32_t, [int32_t, voidptr_t, voidptr_t, voidptr_t, voidptr_t], False),
|
|
284
|
+
"pselect": (int32_t, [int32_t, voidptr_t, voidptr_t, voidptr_t, voidptr_t, voidptr_t], False),
|
|
175
285
|
# === setjmp.h ===
|
|
176
286
|
"setjmp": (int32_t, [voidptr_t], False),
|
|
177
287
|
"longjmp": (_VOID, [voidptr_t, int32_t], False),
|
|
178
288
|
"_setjmp": (int32_t, [voidptr_t], False),
|
|
179
289
|
"_longjmp": (_VOID, [voidptr_t, int32_t], False),
|
|
290
|
+
"sigsetjmp": (int32_t, [voidptr_t, int32_t], False),
|
|
291
|
+
"siglongjmp": (_VOID, [voidptr_t, int32_t], False),
|
|
180
292
|
# === signal.h ===
|
|
181
293
|
"signal": (voidptr_t, [int32_t, voidptr_t], False),
|
|
182
294
|
"sigaction": (int32_t, [int32_t, voidptr_t, voidptr_t], False),
|
|
295
|
+
"sigaddset": (int32_t, [voidptr_t, int32_t], False),
|
|
296
|
+
"sigdelset": (int32_t, [voidptr_t, int32_t], False),
|
|
183
297
|
"sigemptyset": (int32_t, [voidptr_t], False),
|
|
298
|
+
"sigismember": (int32_t, [voidptr_t, int32_t], False),
|
|
299
|
+
"sigprocmask": (int32_t, [int32_t, voidptr_t, voidptr_t], False),
|
|
300
|
+
"sigsuspend": (int32_t, [voidptr_t], False),
|
|
301
|
+
"kill": (int32_t, [int32_t, int32_t], False),
|
|
184
302
|
"raise": (int32_t, [int32_t], False),
|
|
185
303
|
# === errno ===
|
|
186
304
|
"__errno_location": (ir.IntType(32).as_pointer(), [], False),
|
|
187
305
|
# === locale.h ===
|
|
188
306
|
"setlocale": (cstring, [int32_t, cstring], False),
|
|
189
307
|
"localeconv": (voidptr_t, [], False),
|
|
308
|
+
"nl_langinfo": (cstring, [int32_t], False),
|
|
190
309
|
# === misc ===
|
|
191
310
|
"tmpnam": (cstring, [cstring], False),
|
|
192
311
|
"tmpfile": (voidptr_t, [], False),
|
|
193
312
|
"__errno_location": (int32_t.as_pointer(), [], False),
|
|
313
|
+
"stat": (int32_t, [cstring, voidptr_t], False),
|
|
314
|
+
"fstat": (int32_t, [int32_t, voidptr_t], False),
|
|
315
|
+
"lstat": (int32_t, [cstring, voidptr_t], False),
|
|
316
|
+
"chmod": (int32_t, [cstring, int32_t], False),
|
|
317
|
+
"fchmod": (int32_t, [int32_t, int32_t], False),
|
|
318
|
+
"mkdir": (int32_t, [cstring, int32_t], False),
|
|
319
|
+
"umask": (int32_t, [int32_t], False),
|
|
320
|
+
"utime": (int32_t, [cstring, voidptr_t], False),
|
|
321
|
+
"utimes": (int32_t, [cstring, voidptr_t], False),
|
|
322
|
+
"futimes": (int32_t, [int32_t, voidptr_t], False),
|
|
323
|
+
"gettimeofday": (int32_t, [voidptr_t, voidptr_t], False),
|
|
194
324
|
"gmtime": (voidptr_t, [voidptr_t], False),
|
|
195
325
|
"localtime": (voidptr_t, [voidptr_t], False),
|
|
196
326
|
"mktime": (_time_t, [voidptr_t], False),
|
|
@@ -202,10 +332,28 @@ LIBC_FUNCTIONS = {
|
|
|
202
332
|
"__builtin_va_start": (_VOID, [voidptr_t], False),
|
|
203
333
|
"__builtin_va_end": (_VOID, [voidptr_t], False),
|
|
204
334
|
"__builtin_va_copy": (_VOID, [voidptr_t, voidptr_t], False),
|
|
335
|
+
"__builtin_alloca": (voidptr_t, [int64_t], False),
|
|
205
336
|
"__builtin_expect": (int64_t, [int64_t, int64_t], False),
|
|
337
|
+
"__builtin_assume": (_VOID, [int64_t], False),
|
|
338
|
+
"__builtin_prefetch": (_VOID, [voidptr_t, int32_t, int32_t], False),
|
|
206
339
|
"__builtin_unreachable": (_VOID, [], False),
|
|
340
|
+
"__builtin_add_overflow": (int32_t, [int64_t, int64_t, voidptr_t], False),
|
|
341
|
+
"__builtin_sub_overflow": (int32_t, [int64_t, int64_t, voidptr_t], False),
|
|
342
|
+
"__builtin_mul_overflow": (int32_t, [int64_t, int64_t, voidptr_t], False),
|
|
343
|
+
"__builtin_bswap16": (int32_t, [int32_t], False),
|
|
344
|
+
"__builtin_bswap32": (int32_t, [int32_t], False),
|
|
345
|
+
"__builtin_bswap64": (int64_t, [int64_t], False),
|
|
207
346
|
"__builtin_clz": (int32_t, [int32_t], False),
|
|
347
|
+
"__builtin_clzll": (int32_t, [int64_t], False),
|
|
208
348
|
"__builtin_ctz": (int32_t, [int32_t], False),
|
|
349
|
+
"__builtin_ctzll": (int32_t, [int64_t], False),
|
|
350
|
+
"__builtin_rotateleft32": (int32_t, [int32_t, int32_t], False),
|
|
351
|
+
"__builtin_rotateleft64": (int64_t, [int64_t, int64_t], False),
|
|
352
|
+
"__builtin_rotateright32": (int32_t, [int32_t, int32_t], False),
|
|
353
|
+
"__builtin_rotateright64": (int64_t, [int64_t, int64_t], False),
|
|
354
|
+
"__sync_synchronize": (_VOID, [], False),
|
|
355
|
+
"__atomic_load_n": (int64_t, [voidptr_t, int32_t], False),
|
|
356
|
+
"__atomic_store_n": (_VOID, [voidptr_t, int64_t, int32_t], False),
|
|
209
357
|
"modf": (_double, [_double, ir.DoubleType().as_pointer()], False),
|
|
210
358
|
"ldexp": (_double, [_double, int32_t], False),
|
|
211
359
|
"__builtin_va_arg": (voidptr_t, [voidptr_t, int64_t], False),
|
|
@@ -228,6 +376,12 @@ class CodegenError(Exception):
|
|
|
228
376
|
pass
|
|
229
377
|
|
|
230
378
|
|
|
379
|
+
class ExternGlobalRef:
|
|
380
|
+
def __init__(self, symbol_name, ir_type):
|
|
381
|
+
self.symbol_name = symbol_name
|
|
382
|
+
self.ir_type = ir_type
|
|
383
|
+
|
|
384
|
+
|
|
231
385
|
int16_t = ir.IntType(16)
|
|
232
386
|
|
|
233
387
|
|
|
@@ -275,25 +429,10 @@ _PCC_VAARG_CALL_RE = re.compile(
|
|
|
275
429
|
)
|
|
276
430
|
|
|
277
431
|
|
|
278
|
-
_INVALID_VOID_INSTR_RE = re.compile(
|
|
279
|
-
r"^(?:%\S+\s*=\s*)?(?:alloca|load|bitcast) void(?! \()([,\s]|$)|^store void(?! \()([,\s]|$)"
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
_LABEL_RE = re.compile(r"^[A-Za-z$._][A-Za-z0-9$._-]*:$")
|
|
283
|
-
|
|
284
|
-
|
|
285
432
|
def postprocess_ir_text(text):
|
|
286
|
-
"""Apply textual
|
|
433
|
+
"""Apply the minimal textual lowering that llvmlite cannot express directly."""
|
|
287
434
|
|
|
288
|
-
# --- simple regex rewrites ---
|
|
289
435
|
text = _PCC_VAARG_DECL_RE.sub("", text)
|
|
290
|
-
text = re.sub(
|
|
291
|
-
r"bitcast i64 (%\S+) to (i8\*|[^,\n]+\*)", r"inttoptr i64 \1 to \2", text
|
|
292
|
-
)
|
|
293
|
-
text = re.sub(
|
|
294
|
-
r"bitcast i8 (%\S+) to (i8\*|[^,\n]+\*)", r"inttoptr i8 \1 to \2", text
|
|
295
|
-
)
|
|
296
|
-
text = re.sub(r"ptrtoint \[\d+ x i8\] [^\n]+ to i64", "add i64 0, 0", text)
|
|
297
436
|
|
|
298
437
|
def repl(match):
|
|
299
438
|
lhs = match.group("lhs")
|
|
@@ -303,74 +442,7 @@ def postprocess_ir_text(text):
|
|
|
303
442
|
return f"{lhs} = va_arg {argtype} {argval}, {rettype}"
|
|
304
443
|
|
|
305
444
|
text = _PCC_VAARG_CALL_RE.sub(repl, text)
|
|
306
|
-
|
|
307
|
-
# --- line-level fixups ---
|
|
308
|
-
lines = []
|
|
309
|
-
for line in text.splitlines():
|
|
310
|
-
# Fix Python repr leak in array initializers → zeroinitializer
|
|
311
|
-
if "<ir.Constant" in line:
|
|
312
|
-
m = re.match(r'(@"[^"]*"\s*=\s*(?:global|constant)\s*\[[^\]]*\]).*', line)
|
|
313
|
-
if m:
|
|
314
|
-
line = m.group(1) + " zeroinitializer"
|
|
315
|
-
else:
|
|
316
|
-
continue
|
|
317
|
-
s = line.strip()
|
|
318
|
-
# Drop invalid void instructions (alloca void, load void, store void)
|
|
319
|
-
if _INVALID_VOID_INSTR_RE.match(s):
|
|
320
|
-
continue
|
|
321
|
-
lines.append(line)
|
|
322
|
-
|
|
323
|
-
# Deduplicate switch case values
|
|
324
|
-
deduped = []
|
|
325
|
-
for line in lines:
|
|
326
|
-
s = line.strip()
|
|
327
|
-
if s.startswith("switch i64 ") and "[" in line and "]" in line:
|
|
328
|
-
prefix, rest = line.split("[", 1)
|
|
329
|
-
case_text, suffix = rest.rsplit("]", 1)
|
|
330
|
-
cases = re.findall(r'(i64 -?\d+, label %"[^"]*")', case_text)
|
|
331
|
-
if cases:
|
|
332
|
-
seen = set()
|
|
333
|
-
unique = []
|
|
334
|
-
for case in cases:
|
|
335
|
-
val = re.match(r"i64 (-?\d+)", case).group(1)
|
|
336
|
-
if val not in seen:
|
|
337
|
-
seen.add(val)
|
|
338
|
-
unique.append(case)
|
|
339
|
-
line = prefix + "[" + " ".join(unique) + "]" + suffix
|
|
340
|
-
deduped.append(line)
|
|
341
|
-
|
|
342
|
-
# Repair control flow: drop dead code after terminators, bridge empty labels
|
|
343
|
-
def _is_label(s):
|
|
344
|
-
return bool(_LABEL_RE.match(s))
|
|
345
|
-
|
|
346
|
-
def _is_terminator(s):
|
|
347
|
-
return s.startswith(("br ", "ret ", "switch ", "unreachable", "resume "))
|
|
348
|
-
|
|
349
|
-
repaired = []
|
|
350
|
-
skip_dead = False
|
|
351
|
-
for raw in deduped:
|
|
352
|
-
s = raw.strip()
|
|
353
|
-
if skip_dead:
|
|
354
|
-
if _is_label(s):
|
|
355
|
-
skip_dead = False
|
|
356
|
-
else:
|
|
357
|
-
continue
|
|
358
|
-
if (
|
|
359
|
-
repaired
|
|
360
|
-
and _is_terminator(repaired[-1].strip())
|
|
361
|
-
and s
|
|
362
|
-
and raw.startswith(" ")
|
|
363
|
-
and not _is_label(s)
|
|
364
|
-
):
|
|
365
|
-
skip_dead = True
|
|
366
|
-
continue
|
|
367
|
-
if repaired and _is_label(repaired[-1].strip()) and _is_label(s):
|
|
368
|
-
repaired.append(f' br label %"{s[:-1]}"')
|
|
369
|
-
if s == "}" and repaired and _is_label(repaired[-1].strip()):
|
|
370
|
-
repaired.append(" unreachable")
|
|
371
|
-
repaired.append(raw)
|
|
372
|
-
|
|
373
|
-
return "\n".join(repaired)
|
|
445
|
+
return text
|
|
374
446
|
|
|
375
447
|
|
|
376
448
|
def get_ir_type_from_names(names):
|
|
@@ -400,12 +472,14 @@ def get_ir_type_from_names(names):
|
|
|
400
472
|
"void": ir.VoidType(),
|
|
401
473
|
"double": _double,
|
|
402
474
|
"float": _float,
|
|
475
|
+
"_Float16": _float,
|
|
403
476
|
"short": int16_t,
|
|
404
477
|
"long": int64_t,
|
|
405
478
|
"int short": int16_t,
|
|
406
479
|
"int long": int64_t,
|
|
407
480
|
"long long": int64_t,
|
|
408
481
|
"int long long": int64_t,
|
|
482
|
+
"__int128": int128_t,
|
|
409
483
|
"char unsigned": int8_t,
|
|
410
484
|
"int unsigned": int32_t,
|
|
411
485
|
"unsigned": int32_t,
|
|
@@ -414,6 +488,7 @@ def get_ir_type_from_names(names):
|
|
|
414
488
|
"int long unsigned": int64_t,
|
|
415
489
|
"long unsigned": int64_t,
|
|
416
490
|
"long long unsigned": int64_t,
|
|
491
|
+
"__int128 unsigned": int128_t,
|
|
417
492
|
# size_t, etc.
|
|
418
493
|
"size_t": int64_t,
|
|
419
494
|
"ssize_t": int64_t,
|
|
@@ -435,6 +510,8 @@ def get_ir_type_from_names(names):
|
|
|
435
510
|
return _double
|
|
436
511
|
if "float" in names:
|
|
437
512
|
return _float
|
|
513
|
+
if "_Float16" in names:
|
|
514
|
+
return _float
|
|
438
515
|
# If it contains 'char', return i8
|
|
439
516
|
if "char" in names:
|
|
440
517
|
return int8_t
|
|
@@ -459,14 +536,20 @@ def _resolve_node_type(node_type):
|
|
|
459
536
|
if isinstance(inner, c_ast.FuncDecl):
|
|
460
537
|
ret_type = _resolve_node_type(inner.type)
|
|
461
538
|
param_types = []
|
|
539
|
+
is_var_arg = False
|
|
462
540
|
if inner.args:
|
|
463
541
|
for p in inner.args.params:
|
|
464
542
|
if isinstance(p, c_ast.EllipsisParam):
|
|
543
|
+
is_var_arg = True
|
|
465
544
|
continue
|
|
466
545
|
t = get_ir_type_from_node(p)
|
|
467
546
|
if not isinstance(t, ir.VoidType):
|
|
468
547
|
param_types.append(t)
|
|
469
|
-
return ir.FunctionType(
|
|
548
|
+
return ir.FunctionType(
|
|
549
|
+
ret_type,
|
|
550
|
+
param_types,
|
|
551
|
+
var_arg=is_var_arg,
|
|
552
|
+
).as_pointer()
|
|
470
553
|
pointee = _resolve_node_type(inner)
|
|
471
554
|
if isinstance(pointee, ir.VoidType):
|
|
472
555
|
return voidptr_t
|
|
@@ -476,7 +559,7 @@ def _resolve_node_type(node_type):
|
|
|
476
559
|
return get_ir_type(node_type.type.names)
|
|
477
560
|
elif isinstance(node_type.type, c_ast.Struct):
|
|
478
561
|
snode = node_type.type
|
|
479
|
-
if snode.decls:
|
|
562
|
+
if snode.decls is not None:
|
|
480
563
|
# Inline struct with declarations — build real type
|
|
481
564
|
member_types = []
|
|
482
565
|
for decl in snode.decls:
|
|
@@ -488,8 +571,15 @@ def _resolve_node_type(node_type):
|
|
|
488
571
|
return int8_t # opaque/forward-declared struct
|
|
489
572
|
elif isinstance(node_type.type, c_ast.Union):
|
|
490
573
|
unode = node_type.type
|
|
491
|
-
if unode.decls:
|
|
574
|
+
if unode.decls is not None:
|
|
492
575
|
# Inline union with declarations — compute max size
|
|
576
|
+
if len(unode.decls) == 0:
|
|
577
|
+
ut = ir.LiteralStructType([])
|
|
578
|
+
ut.members = []
|
|
579
|
+
ut.member_types = {}
|
|
580
|
+
ut.member_decl_types = {}
|
|
581
|
+
ut.is_union = True
|
|
582
|
+
return ut
|
|
493
583
|
max_size = 0
|
|
494
584
|
max_align = 1
|
|
495
585
|
member_types = {}
|
|
@@ -517,7 +607,7 @@ def _resolve_node_type(node_type):
|
|
|
517
607
|
ir_t = _resolve_union_member_type(decl.type)
|
|
518
608
|
member_types[decl.name] = ir_t
|
|
519
609
|
sz = ir_t.width // 8 if isinstance(ir_t, ir.IntType) else 8
|
|
520
|
-
if
|
|
610
|
+
if _is_struct_ir_type(ir_t):
|
|
521
611
|
sz = sum(
|
|
522
612
|
e.width // 8 if isinstance(e, ir.IntType) else 8
|
|
523
613
|
for e in ir_t.elements
|
|
@@ -545,15 +635,21 @@ def _resolve_node_type(node_type):
|
|
|
545
635
|
ut.is_union = True
|
|
546
636
|
return ut
|
|
547
637
|
return int8_t # opaque/forward-declared union
|
|
638
|
+
elif isinstance(node_type.type, c_ast.Enum):
|
|
639
|
+
return int32_t
|
|
548
640
|
return int64_t
|
|
549
641
|
elif isinstance(node_type, c_ast.ArrayDecl):
|
|
550
642
|
return voidptr_t # array params decay to pointer
|
|
551
643
|
return int64_t
|
|
552
644
|
|
|
553
645
|
|
|
646
|
+
def _is_struct_ir_type(ir_type):
|
|
647
|
+
return isinstance(ir_type, (ir.LiteralStructType, ir.IdentifiedStructType))
|
|
648
|
+
|
|
649
|
+
|
|
554
650
|
class LLVMCodeGenerator(object):
|
|
555
651
|
|
|
556
|
-
def __init__(self):
|
|
652
|
+
def __init__(self, translation_unit_name=None):
|
|
557
653
|
self.module = ir.Module()
|
|
558
654
|
# Set proper data layout for struct padding/alignment
|
|
559
655
|
import llvmlite.binding as _llvm
|
|
@@ -570,6 +666,8 @@ class LLVMCodeGenerator(object):
|
|
|
570
666
|
self.env = ChainMap()
|
|
571
667
|
self.nlabels = 0
|
|
572
668
|
self.function = None
|
|
669
|
+
self._function_display_name = None
|
|
670
|
+
self._frame_address_marker = None
|
|
573
671
|
self.in_global = True
|
|
574
672
|
self._declared_libc = set()
|
|
575
673
|
self._unsigned_bindings = set() # alloca/global ids with unsigned type
|
|
@@ -578,10 +676,379 @@ class LLVMCodeGenerator(object):
|
|
|
578
676
|
self._expr_ir_types = {}
|
|
579
677
|
self._labels = {}
|
|
580
678
|
self._vaarg_counter = 0
|
|
679
|
+
self._anon_type_counter = 0
|
|
680
|
+
self._file_scope_object_states = {}
|
|
681
|
+
self._file_scope_function_states = {}
|
|
682
|
+
self._future_file_scope_object_ir_types = {}
|
|
683
|
+
self._future_file_scope_function_ir_types = {}
|
|
684
|
+
self.translation_unit_name = self._sanitize_translation_unit_name(
|
|
685
|
+
translation_unit_name
|
|
686
|
+
)
|
|
687
|
+
base_namespace = self.translation_unit_name or "pcc"
|
|
688
|
+
self._aggregate_namespace = (
|
|
689
|
+
f"{base_namespace}_{next(_aggregate_namespace_counter)}"
|
|
690
|
+
)
|
|
581
691
|
|
|
582
692
|
def define(self, name, val):
|
|
583
693
|
self.env[name] = val
|
|
584
694
|
|
|
695
|
+
@staticmethod
|
|
696
|
+
def _sanitize_translation_unit_name(name):
|
|
697
|
+
if not name:
|
|
698
|
+
return None
|
|
699
|
+
return re.sub(r"\W+", "_", name)
|
|
700
|
+
|
|
701
|
+
@staticmethod
|
|
702
|
+
def _tag_type_key(name):
|
|
703
|
+
return f"__struct_{name}"
|
|
704
|
+
|
|
705
|
+
def _next_anon_struct_name(self, kind):
|
|
706
|
+
self._anon_type_counter += 1
|
|
707
|
+
return (
|
|
708
|
+
f"__pcc_{self._aggregate_namespace}_{kind}_{self._anon_type_counter}"
|
|
709
|
+
)
|
|
710
|
+
|
|
711
|
+
def _aggregate_type_name(self, kind, name=None):
|
|
712
|
+
if name:
|
|
713
|
+
return f"__pcc_{self._aggregate_namespace}_{kind}_{name}"
|
|
714
|
+
return self._next_anon_struct_name(kind)
|
|
715
|
+
|
|
716
|
+
def _identified_aggregate_type(self, kind, name, body):
|
|
717
|
+
aggregate_type = self.module.context.get_identified_type(
|
|
718
|
+
self._aggregate_type_name(kind, name)
|
|
719
|
+
)
|
|
720
|
+
if aggregate_type.is_opaque:
|
|
721
|
+
aggregate_type.set_body(*body)
|
|
722
|
+
return aggregate_type
|
|
723
|
+
|
|
724
|
+
def _is_file_scope_static(self, storage=None):
|
|
725
|
+
return (
|
|
726
|
+
self.translation_unit_name
|
|
727
|
+
and self.in_global
|
|
728
|
+
and storage
|
|
729
|
+
and "static" in storage
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
def _has_internal_inline_linkage(self, storage=None, funcspec=None):
|
|
733
|
+
return (
|
|
734
|
+
self.translation_unit_name
|
|
735
|
+
and self.in_global
|
|
736
|
+
and funcspec
|
|
737
|
+
and "inline" in funcspec
|
|
738
|
+
and not storage
|
|
739
|
+
)
|
|
740
|
+
|
|
741
|
+
def _file_scope_symbol_name(self, name, storage=None, funcspec=None, linkage=None):
|
|
742
|
+
if linkage == "internal" or self._is_file_scope_static(storage) or self._has_internal_inline_linkage(storage, funcspec):
|
|
743
|
+
return f"__pcc_internal_{self.translation_unit_name}_{name}"
|
|
744
|
+
return name
|
|
745
|
+
|
|
746
|
+
def _static_local_symbol_name(self, name):
|
|
747
|
+
if self.translation_unit_name:
|
|
748
|
+
return f"__static_{self.translation_unit_name}_{self.function.name}_{name}"
|
|
749
|
+
return f"__static_{self.function.name}_{name}"
|
|
750
|
+
|
|
751
|
+
def _create_bound_global(
|
|
752
|
+
self, bind_name, ir_type, symbol_name=None, external=False, storage=None
|
|
753
|
+
):
|
|
754
|
+
actual_name = symbol_name or bind_name
|
|
755
|
+
gv = self.module.globals.get(actual_name)
|
|
756
|
+
if gv is None:
|
|
757
|
+
gv = ir.GlobalVariable(self.module, ir_type, actual_name)
|
|
758
|
+
if self._is_file_scope_static(storage):
|
|
759
|
+
gv.linkage = "internal"
|
|
760
|
+
elif not external and getattr(gv, "initializer", None) is None:
|
|
761
|
+
gv.initializer = ir.Constant(ir_type, None)
|
|
762
|
+
self.define(bind_name, (ir_type, gv))
|
|
763
|
+
return gv
|
|
764
|
+
|
|
765
|
+
def _decl_linkage(self, storage=None, funcspec=None, existing_state=None):
|
|
766
|
+
if storage and "static" in storage:
|
|
767
|
+
return "internal"
|
|
768
|
+
if self._has_internal_inline_linkage(storage, funcspec):
|
|
769
|
+
return "internal"
|
|
770
|
+
if existing_state is not None:
|
|
771
|
+
return existing_state.linkage
|
|
772
|
+
return "external"
|
|
773
|
+
|
|
774
|
+
def _effective_file_scope_symbol_name(
|
|
775
|
+
self, name, storage=None, funcspec=None, existing_state=None, linkage=None
|
|
776
|
+
):
|
|
777
|
+
if linkage is None:
|
|
778
|
+
linkage = self._decl_linkage(
|
|
779
|
+
storage, funcspec=funcspec, existing_state=existing_state
|
|
780
|
+
)
|
|
781
|
+
if linkage == "internal":
|
|
782
|
+
if existing_state is not None and existing_state.linkage == "internal":
|
|
783
|
+
return existing_state.symbol_name
|
|
784
|
+
return self._file_scope_symbol_name(
|
|
785
|
+
name, storage=storage, funcspec=funcspec, linkage=linkage
|
|
786
|
+
)
|
|
787
|
+
if existing_state is not None and existing_state.linkage == "internal":
|
|
788
|
+
return existing_state.symbol_name
|
|
789
|
+
return name
|
|
790
|
+
|
|
791
|
+
def _file_scope_object_definition_kind(self, storage=None, has_initializer=False):
|
|
792
|
+
if storage and "extern" in storage and not has_initializer:
|
|
793
|
+
return "extern"
|
|
794
|
+
if has_initializer:
|
|
795
|
+
return "definition"
|
|
796
|
+
return "tentative"
|
|
797
|
+
|
|
798
|
+
def _is_incomplete_array_ir_type(self, ir_type):
|
|
799
|
+
return isinstance(ir_type, ir.ArrayType) and ir_type.count == 0
|
|
800
|
+
|
|
801
|
+
def _are_compatible_object_ir_types(self, existing_ir_type, new_ir_type):
|
|
802
|
+
if str(existing_ir_type) == str(new_ir_type):
|
|
803
|
+
return True
|
|
804
|
+
if not (
|
|
805
|
+
isinstance(existing_ir_type, ir.ArrayType)
|
|
806
|
+
and isinstance(new_ir_type, ir.ArrayType)
|
|
807
|
+
):
|
|
808
|
+
return False
|
|
809
|
+
if str(existing_ir_type.element) != str(new_ir_type.element):
|
|
810
|
+
return False
|
|
811
|
+
return (
|
|
812
|
+
existing_ir_type.count == 0
|
|
813
|
+
or new_ir_type.count == 0
|
|
814
|
+
or existing_ir_type.count == new_ir_type.count
|
|
815
|
+
)
|
|
816
|
+
|
|
817
|
+
def _merge_object_ir_types(self, existing_ir_type, new_ir_type):
|
|
818
|
+
if self._is_incomplete_array_ir_type(existing_ir_type) and not self._is_incomplete_array_ir_type(new_ir_type):
|
|
819
|
+
return new_ir_type
|
|
820
|
+
return existing_ir_type
|
|
821
|
+
|
|
822
|
+
def _preferred_file_scope_object_ir_type(self, name, ir_type):
|
|
823
|
+
future_ir_type = self._future_file_scope_object_ir_types.get(name)
|
|
824
|
+
if future_ir_type is None:
|
|
825
|
+
return ir_type
|
|
826
|
+
if not self._are_compatible_object_ir_types(ir_type, future_ir_type):
|
|
827
|
+
return ir_type
|
|
828
|
+
return self._merge_object_ir_types(ir_type, future_ir_type)
|
|
829
|
+
|
|
830
|
+
def _preferred_file_scope_function_ir_type(self, name, function_type, has_prototype):
|
|
831
|
+
if has_prototype:
|
|
832
|
+
return function_type
|
|
833
|
+
future_type = self._future_file_scope_function_ir_types.get(name)
|
|
834
|
+
if future_type is None:
|
|
835
|
+
return function_type
|
|
836
|
+
if str(function_type.return_type) != str(future_type.return_type):
|
|
837
|
+
return function_type
|
|
838
|
+
return future_type
|
|
839
|
+
|
|
840
|
+
def _prepare_file_scope_object(self, name, ir_type, storage=None, has_initializer=False):
|
|
841
|
+
if not self.in_global or name is None:
|
|
842
|
+
return None, True
|
|
843
|
+
if name in self._file_scope_function_states:
|
|
844
|
+
raise SemanticError(f"'{name}' redeclared as object after function declaration")
|
|
845
|
+
ir_type = self._preferred_file_scope_object_ir_type(name, ir_type)
|
|
846
|
+
|
|
847
|
+
type_key = str(ir_type)
|
|
848
|
+
definition_kind = self._file_scope_object_definition_kind(
|
|
849
|
+
storage, has_initializer
|
|
850
|
+
)
|
|
851
|
+
state = self._file_scope_object_states.get(name)
|
|
852
|
+
linkage = self._decl_linkage(storage, existing_state=state)
|
|
853
|
+
symbol_name = self._effective_file_scope_symbol_name(
|
|
854
|
+
name, storage=storage, existing_state=state
|
|
855
|
+
)
|
|
856
|
+
|
|
857
|
+
if state is None:
|
|
858
|
+
state = FileScopeObjectState(
|
|
859
|
+
type_key=type_key,
|
|
860
|
+
linkage=linkage,
|
|
861
|
+
definition_kind=definition_kind,
|
|
862
|
+
symbol_name=symbol_name,
|
|
863
|
+
ir_type=ir_type,
|
|
864
|
+
)
|
|
865
|
+
self._file_scope_object_states[name] = state
|
|
866
|
+
if definition_kind == "extern":
|
|
867
|
+
self._record_extern_global(name, ir_type, storage=storage)
|
|
868
|
+
return None, False
|
|
869
|
+
gv = self._create_bound_global(
|
|
870
|
+
name, ir_type, symbol_name=symbol_name, storage=storage
|
|
871
|
+
)
|
|
872
|
+
return gv, True
|
|
873
|
+
|
|
874
|
+
if not self._are_compatible_object_ir_types(state.ir_type, ir_type):
|
|
875
|
+
raise SemanticError(f"conflicting types for global '{name}'")
|
|
876
|
+
merged_ir_type = self._merge_object_ir_types(state.ir_type, ir_type)
|
|
877
|
+
state.ir_type = merged_ir_type
|
|
878
|
+
state.type_key = str(merged_ir_type)
|
|
879
|
+
if state.linkage != linkage:
|
|
880
|
+
raise SemanticError(f"conflicting linkage for global '{name}'")
|
|
881
|
+
if state.symbol_name != symbol_name:
|
|
882
|
+
raise SemanticError(f"conflicting symbol binding for global '{name}'")
|
|
883
|
+
|
|
884
|
+
existing = self.module.globals.get(symbol_name)
|
|
885
|
+
if definition_kind == "extern":
|
|
886
|
+
if existing is not None:
|
|
887
|
+
self.define(name, (merged_ir_type, existing))
|
|
888
|
+
else:
|
|
889
|
+
self._record_extern_global(name, merged_ir_type, storage=storage)
|
|
890
|
+
return None, False
|
|
891
|
+
|
|
892
|
+
if existing is None:
|
|
893
|
+
gv = self._create_bound_global(
|
|
894
|
+
name, ir_type, symbol_name=symbol_name, storage=storage
|
|
895
|
+
)
|
|
896
|
+
else:
|
|
897
|
+
gv = existing
|
|
898
|
+
self.define(name, (ir_type, gv))
|
|
899
|
+
|
|
900
|
+
if state.definition_kind == "definition":
|
|
901
|
+
if definition_kind == "definition":
|
|
902
|
+
raise SemanticError(f"redefinition of global '{name}'")
|
|
903
|
+
return gv, False
|
|
904
|
+
|
|
905
|
+
if state.definition_kind == "tentative":
|
|
906
|
+
if definition_kind == "definition":
|
|
907
|
+
state.definition_kind = "definition"
|
|
908
|
+
return gv, True
|
|
909
|
+
return gv, False
|
|
910
|
+
|
|
911
|
+
state.definition_kind = definition_kind
|
|
912
|
+
return gv, True
|
|
913
|
+
|
|
914
|
+
def _register_file_scope_function(
|
|
915
|
+
self, name, function_type, storage=None, funcspec=None, is_definition=False
|
|
916
|
+
):
|
|
917
|
+
if not self.in_global or name is None:
|
|
918
|
+
return
|
|
919
|
+
if name in self._file_scope_object_states:
|
|
920
|
+
raise SemanticError(f"'{name}' redeclared as function after object declaration")
|
|
921
|
+
|
|
922
|
+
type_key = str(function_type)
|
|
923
|
+
state = self._file_scope_function_states.get(name)
|
|
924
|
+
linkage = self._decl_linkage(storage, funcspec=funcspec, existing_state=state)
|
|
925
|
+
symbol_name = self._effective_file_scope_symbol_name(
|
|
926
|
+
name,
|
|
927
|
+
storage=storage,
|
|
928
|
+
funcspec=funcspec,
|
|
929
|
+
existing_state=state,
|
|
930
|
+
linkage=linkage,
|
|
931
|
+
)
|
|
932
|
+
|
|
933
|
+
if state is None:
|
|
934
|
+
self._file_scope_function_states[name] = FileScopeFunctionState(
|
|
935
|
+
type_key=type_key,
|
|
936
|
+
linkage=linkage,
|
|
937
|
+
defined=is_definition,
|
|
938
|
+
symbol_name=symbol_name,
|
|
939
|
+
)
|
|
940
|
+
return symbol_name
|
|
941
|
+
|
|
942
|
+
if state.type_key != type_key:
|
|
943
|
+
raise SemanticError(f"conflicting types for function '{name}'")
|
|
944
|
+
if state.linkage != linkage:
|
|
945
|
+
raise SemanticError(f"conflicting linkage for function '{name}'")
|
|
946
|
+
if state.symbol_name != symbol_name:
|
|
947
|
+
raise SemanticError(f"conflicting symbol binding for function '{name}'")
|
|
948
|
+
if is_definition:
|
|
949
|
+
if state.defined:
|
|
950
|
+
raise SemanticError(f"redefinition of function '{name}'")
|
|
951
|
+
state.defined = True
|
|
952
|
+
return state.symbol_name
|
|
953
|
+
|
|
954
|
+
@staticmethod
|
|
955
|
+
def _function_arg_types_match(lhs_args, rhs_args):
|
|
956
|
+
if len(lhs_args) != len(rhs_args):
|
|
957
|
+
return False
|
|
958
|
+
return all(str(lhs) == str(rhs) for lhs, rhs in zip(lhs_args, rhs_args))
|
|
959
|
+
|
|
960
|
+
def external_definitions(self):
|
|
961
|
+
defs = []
|
|
962
|
+
for name, state in self._file_scope_function_states.items():
|
|
963
|
+
if state.linkage == "external" and state.defined:
|
|
964
|
+
defs.append(("function", state.symbol_name, name))
|
|
965
|
+
for name, state in self._file_scope_object_states.items():
|
|
966
|
+
if (
|
|
967
|
+
state.linkage == "external"
|
|
968
|
+
and state.definition_kind in ("tentative", "definition")
|
|
969
|
+
):
|
|
970
|
+
defs.append(("object", state.symbol_name, name))
|
|
971
|
+
return defs
|
|
972
|
+
|
|
973
|
+
def _is_global_extern_decl(self, node):
|
|
974
|
+
return (
|
|
975
|
+
self.in_global
|
|
976
|
+
and node.init is None
|
|
977
|
+
and node.storage
|
|
978
|
+
and "extern" in node.storage
|
|
979
|
+
and not isinstance(node.type, c_ast.FuncDecl)
|
|
980
|
+
and node.name is not None
|
|
981
|
+
)
|
|
982
|
+
|
|
983
|
+
def _extern_decl_ir_type(self, name, node_type):
|
|
984
|
+
if isinstance(node_type, c_ast.ArrayDecl):
|
|
985
|
+
ir_type = self._build_array_ir_type(node_type)
|
|
986
|
+
else:
|
|
987
|
+
ir_type = self._resolve_ast_type(node_type)
|
|
988
|
+
return self._preferred_file_scope_object_ir_type(name, ir_type)
|
|
989
|
+
|
|
990
|
+
def _static_local_ir_type(self, node_type, init_node=None):
|
|
991
|
+
if isinstance(node_type, c_ast.ArrayDecl):
|
|
992
|
+
return self._build_array_ir_type(node_type, init_node=init_node)
|
|
993
|
+
return self._resolve_ast_type(node_type)
|
|
994
|
+
|
|
995
|
+
def _collect_file_scope_object_ir_types(self, ext_nodes):
|
|
996
|
+
merged_types = {}
|
|
997
|
+
for ext in ext_nodes:
|
|
998
|
+
if not (
|
|
999
|
+
isinstance(ext, c_ast.Decl)
|
|
1000
|
+
and ext.name is not None
|
|
1001
|
+
and not isinstance(ext.type, c_ast.FuncDecl)
|
|
1002
|
+
):
|
|
1003
|
+
continue
|
|
1004
|
+
try:
|
|
1005
|
+
if isinstance(ext.type, c_ast.ArrayDecl):
|
|
1006
|
+
ir_type = self._build_array_ir_type(ext.type, init_node=ext.init)
|
|
1007
|
+
else:
|
|
1008
|
+
ir_type = self._resolve_ast_type(ext.type)
|
|
1009
|
+
except Exception:
|
|
1010
|
+
continue
|
|
1011
|
+
existing_ir_type = merged_types.get(ext.name)
|
|
1012
|
+
if existing_ir_type is None:
|
|
1013
|
+
merged_types[ext.name] = ir_type
|
|
1014
|
+
continue
|
|
1015
|
+
if self._are_compatible_object_ir_types(existing_ir_type, ir_type):
|
|
1016
|
+
merged_types[ext.name] = self._merge_object_ir_types(
|
|
1017
|
+
existing_ir_type, ir_type
|
|
1018
|
+
)
|
|
1019
|
+
self._future_file_scope_object_ir_types = merged_types
|
|
1020
|
+
|
|
1021
|
+
def _collect_file_scope_function_ir_types(self, ext_nodes):
|
|
1022
|
+
future_types = {}
|
|
1023
|
+
for ext in ext_nodes:
|
|
1024
|
+
decl = None
|
|
1025
|
+
if isinstance(ext, c_ast.FuncDef):
|
|
1026
|
+
decl = ext.decl
|
|
1027
|
+
elif isinstance(ext, c_ast.Decl) and isinstance(ext.type, c_ast.FuncDecl):
|
|
1028
|
+
decl = ext
|
|
1029
|
+
if decl is None or decl.name is None:
|
|
1030
|
+
continue
|
|
1031
|
+
if getattr(decl.type, "args", None) is None:
|
|
1032
|
+
continue
|
|
1033
|
+
try:
|
|
1034
|
+
function_type, _ = self._build_function_ir_type(decl.type)
|
|
1035
|
+
except Exception:
|
|
1036
|
+
continue
|
|
1037
|
+
future_types[decl.name] = function_type
|
|
1038
|
+
self._future_file_scope_function_ir_types = future_types
|
|
1039
|
+
|
|
1040
|
+
def _record_extern_global(self, name, ir_type, storage=None):
|
|
1041
|
+
ir_type = self._preferred_file_scope_object_ir_type(name, ir_type)
|
|
1042
|
+
self.define(
|
|
1043
|
+
name,
|
|
1044
|
+
(
|
|
1045
|
+
ir_type,
|
|
1046
|
+
ExternGlobalRef(
|
|
1047
|
+
self._file_scope_symbol_name(name, storage), ir_type
|
|
1048
|
+
),
|
|
1049
|
+
),
|
|
1050
|
+
)
|
|
1051
|
+
|
|
585
1052
|
def _mark_unsigned(self, binding):
|
|
586
1053
|
"""Mark a concrete IR binding as having unsigned type."""
|
|
587
1054
|
if binding is not None:
|
|
@@ -698,6 +1165,34 @@ class LLVMCodeGenerator(object):
|
|
|
698
1165
|
return self._convert_int_value(val, int32_t, result_unsigned=False)
|
|
699
1166
|
return val
|
|
700
1167
|
|
|
1168
|
+
def _integer_promotion_ir_type(self, ir_type):
|
|
1169
|
+
if not isinstance(ir_type, ir.IntType):
|
|
1170
|
+
return ir_type
|
|
1171
|
+
if ir_type.width < int32_t.width:
|
|
1172
|
+
return int32_t
|
|
1173
|
+
return ir_type
|
|
1174
|
+
|
|
1175
|
+
def _usual_arithmetic_conversion_ir_type(self, lhs_type, rhs_type):
|
|
1176
|
+
lhs_type = self._integer_promotion_ir_type(lhs_type)
|
|
1177
|
+
rhs_type = self._integer_promotion_ir_type(rhs_type)
|
|
1178
|
+
|
|
1179
|
+
if self._is_floating_ir_type(lhs_type) or self._is_floating_ir_type(rhs_type):
|
|
1180
|
+
if self._is_floating_ir_type(lhs_type) and self._is_floating_ir_type(
|
|
1181
|
+
rhs_type
|
|
1182
|
+
):
|
|
1183
|
+
return self._common_float_type(lhs_type, rhs_type)
|
|
1184
|
+
return lhs_type if self._is_floating_ir_type(lhs_type) else rhs_type
|
|
1185
|
+
|
|
1186
|
+
if isinstance(lhs_type, ir.IntType) and isinstance(rhs_type, ir.IntType):
|
|
1187
|
+
return lhs_type if lhs_type.width >= rhs_type.width else rhs_type
|
|
1188
|
+
|
|
1189
|
+
return lhs_type
|
|
1190
|
+
|
|
1191
|
+
def _decay_ir_type(self, ir_type):
|
|
1192
|
+
if isinstance(ir_type, ir.ArrayType):
|
|
1193
|
+
return ir.PointerType(ir_type.element)
|
|
1194
|
+
return ir_type
|
|
1195
|
+
|
|
701
1196
|
def _usual_arithmetic_conversion(self, lhs, rhs):
|
|
702
1197
|
lhs = self._integer_promotion(lhs)
|
|
703
1198
|
rhs = self._integer_promotion(rhs)
|
|
@@ -747,10 +1242,18 @@ class LLVMCodeGenerator(object):
|
|
|
747
1242
|
return _float
|
|
748
1243
|
|
|
749
1244
|
def _parse_float_constant(self, raw):
|
|
1245
|
+
is_float32 = raw.endswith(("f", "F"))
|
|
750
1246
|
value = raw.rstrip("fFlL")
|
|
751
1247
|
if value.lower().startswith("0x") and "p" in value.lower():
|
|
752
|
-
|
|
753
|
-
|
|
1248
|
+
parsed = float.fromhex(value)
|
|
1249
|
+
else:
|
|
1250
|
+
parsed = float(value)
|
|
1251
|
+
if is_float32:
|
|
1252
|
+
try:
|
|
1253
|
+
return struct.unpack("!f", struct.pack("!f", parsed))[0]
|
|
1254
|
+
except OverflowError:
|
|
1255
|
+
return math.copysign(float("inf"), parsed)
|
|
1256
|
+
return parsed
|
|
754
1257
|
|
|
755
1258
|
def _float_literal_ir_type(self, raw):
|
|
756
1259
|
if raw.endswith(("f", "F")):
|
|
@@ -769,18 +1272,14 @@ class LLVMCodeGenerator(object):
|
|
|
769
1272
|
return existing
|
|
770
1273
|
try:
|
|
771
1274
|
gv = ir.GlobalVariable(self.module, ir_type, name)
|
|
772
|
-
if external:
|
|
773
|
-
gv.linkage = "external"
|
|
774
|
-
else:
|
|
1275
|
+
if not external:
|
|
775
1276
|
gv.initializer = ir.Constant(ir_type, None)
|
|
776
1277
|
return gv
|
|
777
1278
|
except Exception:
|
|
778
1279
|
gv = self.module.globals.get(name) or ir.GlobalVariable(
|
|
779
1280
|
self.module, ir_type, self.module.get_unique_name(name)
|
|
780
1281
|
)
|
|
781
|
-
if external:
|
|
782
|
-
gv.linkage = "external"
|
|
783
|
-
elif getattr(gv, "initializer", None) is None:
|
|
1282
|
+
if not external and getattr(gv, "initializer", None) is None:
|
|
784
1283
|
gv.initializer = ir.Constant(ir_type, None)
|
|
785
1284
|
return gv
|
|
786
1285
|
|
|
@@ -805,7 +1304,17 @@ class LLVMCodeGenerator(object):
|
|
|
805
1304
|
gv_type = self._EXTERN_GLOBAL_VARS[name]
|
|
806
1305
|
gv = self._safe_global_var(gv_type, name, external=True)
|
|
807
1306
|
self.define(name, (gv_type, gv))
|
|
808
|
-
|
|
1307
|
+
stored = self.env[name]
|
|
1308
|
+
if not (isinstance(stored, tuple) and len(stored) == 2):
|
|
1309
|
+
return stored
|
|
1310
|
+
valtype, binding = stored
|
|
1311
|
+
if isinstance(binding, ExternGlobalRef):
|
|
1312
|
+
gv = self._safe_global_var(
|
|
1313
|
+
binding.ir_type, binding.symbol_name, external=True
|
|
1314
|
+
)
|
|
1315
|
+
self.define(name, (binding.ir_type, gv))
|
|
1316
|
+
return self.env[name]
|
|
1317
|
+
return valtype, binding
|
|
809
1318
|
|
|
810
1319
|
def _declare_libc(self, name):
|
|
811
1320
|
"""Lazily declare a libc function on first use."""
|
|
@@ -844,16 +1353,21 @@ class LLVMCodeGenerator(object):
|
|
|
844
1353
|
@contextmanager
|
|
845
1354
|
def new_function(self):
|
|
846
1355
|
oldfunc = self.function
|
|
1356
|
+
old_display_name = self._function_display_name
|
|
1357
|
+
old_frame_address_marker = self._frame_address_marker
|
|
847
1358
|
oldbuilder = self.builder
|
|
848
1359
|
oldenv = self.env
|
|
849
1360
|
oldlabels = self._labels
|
|
850
1361
|
self.in_global = False
|
|
851
1362
|
self.env = self.env.new_child()
|
|
852
1363
|
self._labels = {}
|
|
1364
|
+
self._frame_address_marker = None
|
|
853
1365
|
try:
|
|
854
1366
|
yield
|
|
855
1367
|
finally:
|
|
856
1368
|
self.function = oldfunc
|
|
1369
|
+
self._function_display_name = old_display_name
|
|
1370
|
+
self._frame_address_marker = old_frame_address_marker
|
|
857
1371
|
self.builder = oldbuilder
|
|
858
1372
|
self.env = oldenv
|
|
859
1373
|
self._labels = oldlabels
|
|
@@ -872,7 +1386,14 @@ class LLVMCodeGenerator(object):
|
|
|
872
1386
|
return normal
|
|
873
1387
|
|
|
874
1388
|
def create_entry_block_alloca(
|
|
875
|
-
self,
|
|
1389
|
+
self,
|
|
1390
|
+
name,
|
|
1391
|
+
type_str,
|
|
1392
|
+
size,
|
|
1393
|
+
array_list=None,
|
|
1394
|
+
point_level=0,
|
|
1395
|
+
storage=None,
|
|
1396
|
+
symbol_name=None,
|
|
876
1397
|
):
|
|
877
1398
|
|
|
878
1399
|
ir_type = get_ir_type(type_str)
|
|
@@ -893,20 +1414,12 @@ class LLVMCodeGenerator(object):
|
|
|
893
1414
|
ret = self._alloca_in_entry(ir_type, name)
|
|
894
1415
|
self.define(name, (ir_type, ret))
|
|
895
1416
|
else:
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
ret.initializer = ir.Constant(ir_type, None)
|
|
903
|
-
except Exception:
|
|
904
|
-
ret = self.module.globals.get(name) or ir.GlobalVariable(
|
|
905
|
-
self.module, ir_type, self.module.get_unique_name(name)
|
|
906
|
-
)
|
|
907
|
-
if hasattr(ret, "initializer") and ret.initializer is None:
|
|
908
|
-
ret.initializer = ir.Constant(ir_type, None)
|
|
909
|
-
self.define(name, (ir_type, ret))
|
|
1417
|
+
ret = self._create_bound_global(
|
|
1418
|
+
name,
|
|
1419
|
+
ir_type,
|
|
1420
|
+
symbol_name=symbol_name or self._file_scope_symbol_name(name, storage),
|
|
1421
|
+
storage=storage,
|
|
1422
|
+
)
|
|
910
1423
|
|
|
911
1424
|
return ret, ir_type
|
|
912
1425
|
|
|
@@ -956,9 +1469,11 @@ class LLVMCodeGenerator(object):
|
|
|
956
1469
|
for i, ext in enumerate(node.ext):
|
|
957
1470
|
is_type_def = False
|
|
958
1471
|
if isinstance(ext, c_ast.Decl):
|
|
959
|
-
if
|
|
1472
|
+
if ext.name is None and isinstance(
|
|
1473
|
+
ext.type, (c_ast.Struct, c_ast.Union, c_ast.Enum)
|
|
1474
|
+
):
|
|
960
1475
|
is_type_def = True
|
|
961
|
-
elif isinstance(ext.type, c_ast.TypeDecl) and isinstance(
|
|
1476
|
+
elif ext.name is None and isinstance(ext.type, c_ast.TypeDecl) and isinstance(
|
|
962
1477
|
ext.type.type, (c_ast.Struct, c_ast.Union)
|
|
963
1478
|
):
|
|
964
1479
|
is_type_def = True
|
|
@@ -970,6 +1485,9 @@ class LLVMCodeGenerator(object):
|
|
|
970
1485
|
except Exception:
|
|
971
1486
|
pass
|
|
972
1487
|
pass1.add(i)
|
|
1488
|
+
remaining_exts = [ext for i, ext in enumerate(node.ext) if i not in pass1]
|
|
1489
|
+
self._collect_file_scope_function_ir_types(remaining_exts)
|
|
1490
|
+
self._collect_file_scope_object_ir_types(remaining_exts)
|
|
973
1491
|
for i, ext in enumerate(node.ext):
|
|
974
1492
|
if i not in pass1:
|
|
975
1493
|
try:
|
|
@@ -1053,15 +1571,37 @@ class LLVMCodeGenerator(object):
|
|
|
1053
1571
|
if node.type == "int":
|
|
1054
1572
|
# Support hex (0xFF), octal (077), and decimal literals
|
|
1055
1573
|
raw = node.value
|
|
1056
|
-
|
|
1574
|
+
raw_lower = raw.lower()
|
|
1575
|
+
has_unsigned_suffix = "u" in raw_lower
|
|
1576
|
+
has_long_suffix = "l" in raw_lower
|
|
1057
1577
|
val_str = raw.rstrip("uUlL")
|
|
1058
1578
|
if val_str.startswith("0x") or val_str.startswith("0X"):
|
|
1059
1579
|
int_val = int(val_str, 16)
|
|
1580
|
+
is_non_decimal = True
|
|
1060
1581
|
elif val_str.startswith("0") and len(val_str) > 1 and val_str[1:].isdigit():
|
|
1061
1582
|
int_val = int(val_str, 8)
|
|
1583
|
+
is_non_decimal = True
|
|
1062
1584
|
else:
|
|
1063
1585
|
int_val = int(val_str)
|
|
1064
|
-
|
|
1586
|
+
is_non_decimal = False
|
|
1587
|
+
|
|
1588
|
+
if has_long_suffix or int_val > 0xFFFFFFFF:
|
|
1589
|
+
ir_type = int64_t
|
|
1590
|
+
is_unsigned = has_unsigned_suffix
|
|
1591
|
+
elif has_unsigned_suffix:
|
|
1592
|
+
ir_type = int32_t
|
|
1593
|
+
is_unsigned = True
|
|
1594
|
+
elif is_non_decimal and int_val > 0x7FFFFFFF:
|
|
1595
|
+
ir_type = int32_t
|
|
1596
|
+
is_unsigned = True
|
|
1597
|
+
elif int_val > 0x7FFFFFFF:
|
|
1598
|
+
ir_type = int64_t
|
|
1599
|
+
is_unsigned = False
|
|
1600
|
+
else:
|
|
1601
|
+
ir_type = int32_t
|
|
1602
|
+
is_unsigned = False
|
|
1603
|
+
|
|
1604
|
+
result = ir.values.Constant(ir_type, int_val)
|
|
1065
1605
|
if is_unsigned:
|
|
1066
1606
|
self._tag_unsigned(result)
|
|
1067
1607
|
return result, None
|
|
@@ -1095,6 +1635,7 @@ class LLVMCodeGenerator(object):
|
|
|
1095
1635
|
if lv is None or rv is None:
|
|
1096
1636
|
return ir.Constant(int64_t, 0), None
|
|
1097
1637
|
result = None
|
|
1638
|
+
is_bitfield = isinstance(lv_addr, BitFieldRef)
|
|
1098
1639
|
|
|
1099
1640
|
dispatch_type_double = 1
|
|
1100
1641
|
dispatch_type_int = 0
|
|
@@ -1150,13 +1691,19 @@ class LLVMCodeGenerator(object):
|
|
|
1150
1691
|
|
|
1151
1692
|
if node.op == "=":
|
|
1152
1693
|
# Type coercion: match rv to the target's pointee type
|
|
1153
|
-
if
|
|
1694
|
+
if is_bitfield:
|
|
1695
|
+
target_type = lv_addr.semantic_ir_type
|
|
1696
|
+
elif lv_addr and hasattr(lv_addr.type, "pointee"):
|
|
1154
1697
|
target_type = lv_addr.type.pointee
|
|
1155
1698
|
else:
|
|
1156
1699
|
target_type = lv.type
|
|
1157
1700
|
if rv.type != target_type:
|
|
1158
1701
|
rv = self._implicit_convert(rv, target_type)
|
|
1159
|
-
|
|
1702
|
+
if is_bitfield:
|
|
1703
|
+
self._store_bitfield(rv, lv_addr)
|
|
1704
|
+
rv = self._load_bitfield(lv_addr)
|
|
1705
|
+
else:
|
|
1706
|
+
self._safe_store(rv, lv_addr)
|
|
1160
1707
|
return rv, lv_addr # return value for chained assignment
|
|
1161
1708
|
else:
|
|
1162
1709
|
# Pointer compound assignment: p += n, p -= n
|
|
@@ -1172,6 +1719,11 @@ class LLVMCodeGenerator(object):
|
|
|
1172
1719
|
addresult = handle(lv, rv, "addtmp")
|
|
1173
1720
|
else:
|
|
1174
1721
|
addresult = handle(lv, rv, "addtmp")
|
|
1722
|
+
if dispatch_type == dispatch_type_int and is_unsigned:
|
|
1723
|
+
self._tag_unsigned(addresult)
|
|
1724
|
+
if is_bitfield:
|
|
1725
|
+
self._store_bitfield(addresult, lv_addr)
|
|
1726
|
+
return self._load_bitfield(lv_addr), lv_addr
|
|
1175
1727
|
self._safe_store(addresult, lv_addr)
|
|
1176
1728
|
return addresult, lv_addr
|
|
1177
1729
|
|
|
@@ -1196,8 +1748,14 @@ class LLVMCodeGenerator(object):
|
|
|
1196
1748
|
if is_inc
|
|
1197
1749
|
else self.builder.sub(lv, one, "dec")
|
|
1198
1750
|
)
|
|
1199
|
-
|
|
1200
|
-
|
|
1751
|
+
if self._is_unsigned_val(lv):
|
|
1752
|
+
self._tag_unsigned(new_val)
|
|
1753
|
+
if isinstance(lv_addr, BitFieldRef):
|
|
1754
|
+
self._store_bitfield(new_val, lv_addr)
|
|
1755
|
+
result = lv if is_post else self._load_bitfield(lv_addr)
|
|
1756
|
+
else:
|
|
1757
|
+
self._safe_store(new_val, lv_addr)
|
|
1758
|
+
result = lv if is_post else new_val
|
|
1201
1759
|
|
|
1202
1760
|
elif node.op == "*":
|
|
1203
1761
|
if (
|
|
@@ -1211,8 +1769,8 @@ class LLVMCodeGenerator(object):
|
|
|
1211
1769
|
node.expr.expr.args.exprs if node.expr.expr.args is not None else []
|
|
1212
1770
|
)
|
|
1213
1771
|
if isinstance(target_ptr_type, ir.PointerType) and va_args:
|
|
1214
|
-
ap_addr
|
|
1215
|
-
if
|
|
1772
|
+
ap_addr = self._builtin_va_list_storage(va_args[0])
|
|
1773
|
+
if ap_addr is not None:
|
|
1216
1774
|
self._vaarg_counter += 1
|
|
1217
1775
|
name = f"__pcc_va_arg_{self._vaarg_counter}"
|
|
1218
1776
|
placeholder = self.module.globals.get(name)
|
|
@@ -1235,6 +1793,11 @@ class LLVMCodeGenerator(object):
|
|
|
1235
1793
|
result_ptr = self._decay_array_value_to_pointer(name_ir, "derefarray")
|
|
1236
1794
|
else:
|
|
1237
1795
|
result_ptr = name_ir
|
|
1796
|
+
if isinstance(getattr(result_ptr, "type", None), ir.PointerType) and isinstance(
|
|
1797
|
+
result_ptr.type.pointee, ir.ArrayType
|
|
1798
|
+
):
|
|
1799
|
+
self._set_expr_ir_type(node, result_ptr.type.pointee)
|
|
1800
|
+
return result_ptr, result_ptr
|
|
1238
1801
|
result = self._safe_load(result_ptr)
|
|
1239
1802
|
if self._is_unsigned_pointee(name_ir) or self._is_unsigned_pointee(
|
|
1240
1803
|
result_ptr
|
|
@@ -1308,12 +1871,15 @@ class LLVMCodeGenerator(object):
|
|
|
1308
1871
|
if isinstance(expr, c_ast.Typename):
|
|
1309
1872
|
ir_t = self._resolve_ast_type(expr.type)
|
|
1310
1873
|
size = self._ir_type_size(ir_t)
|
|
1874
|
+
elif isinstance(expr, c_ast.Constant) and expr.type == "string":
|
|
1875
|
+
raw = expr.value[1:-1]
|
|
1876
|
+
processed = self._process_escapes(raw)
|
|
1877
|
+
size = len(self._string_bytes(processed + "\00"))
|
|
1311
1878
|
elif isinstance(expr, c_ast.ID):
|
|
1312
1879
|
ir_type, _ = self.lookup(expr.name)
|
|
1313
1880
|
size = self._ir_type_size(ir_type)
|
|
1314
1881
|
else:
|
|
1315
|
-
|
|
1316
|
-
semantic_type = self._get_expr_ir_type(expr, getattr(val, "type", None))
|
|
1882
|
+
semantic_type = self._infer_sizeof_operand_ir_type(expr)
|
|
1317
1883
|
size = self._ir_type_size(semantic_type)
|
|
1318
1884
|
result = ir.Constant(int64_t, size)
|
|
1319
1885
|
return self._tag_unsigned(result)
|
|
@@ -1332,9 +1898,8 @@ class LLVMCodeGenerator(object):
|
|
|
1332
1898
|
if isinstance(resolved, str):
|
|
1333
1899
|
# Could be a __struct_ reference or a base type name
|
|
1334
1900
|
if resolved.startswith("__struct_"):
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
return self.env[struct_name][0]
|
|
1901
|
+
if resolved in self.env:
|
|
1902
|
+
return self.env[resolved][0]
|
|
1338
1903
|
return int8_t # opaque
|
|
1339
1904
|
# Recursively resolve further typedefs
|
|
1340
1905
|
return self._resolve_type_str(resolved, depth + 1)
|
|
@@ -1477,11 +2042,162 @@ class LLVMCodeGenerator(object):
|
|
|
1477
2042
|
return None
|
|
1478
2043
|
return self._scalar_init_node(init_node.exprs[0])
|
|
1479
2044
|
|
|
2045
|
+
def _struct_field_names(self, ir_type):
|
|
2046
|
+
member_names = list(getattr(ir_type, "members", ()) or [])
|
|
2047
|
+
if member_names:
|
|
2048
|
+
return member_names
|
|
2049
|
+
member_types = getattr(ir_type, "member_types", None)
|
|
2050
|
+
if isinstance(member_types, dict):
|
|
2051
|
+
return list(member_types.keys())
|
|
2052
|
+
return []
|
|
2053
|
+
|
|
2054
|
+
def _ordered_struct_init_exprs(self, init_node, ir_type):
|
|
2055
|
+
exprs = list(getattr(init_node, "exprs", None) or [])
|
|
2056
|
+
field_names = self._struct_field_names(ir_type)
|
|
2057
|
+
if not exprs or not field_names:
|
|
2058
|
+
return exprs
|
|
2059
|
+
if not any(isinstance(expr, c_ast.NamedInitializer) for expr in exprs):
|
|
2060
|
+
return exprs
|
|
2061
|
+
|
|
2062
|
+
ordered = [None] * len(field_names)
|
|
2063
|
+
cursor = 0
|
|
2064
|
+
index_by_name = {name: i for i, name in enumerate(field_names)}
|
|
2065
|
+
|
|
2066
|
+
for expr in exprs:
|
|
2067
|
+
if isinstance(expr, c_ast.NamedInitializer):
|
|
2068
|
+
designators = getattr(expr, "name", None) or []
|
|
2069
|
+
if len(designators) == 1 and isinstance(designators[0], c_ast.ID):
|
|
2070
|
+
target = index_by_name.get(designators[0].name)
|
|
2071
|
+
if target is not None:
|
|
2072
|
+
ordered[target] = expr.expr
|
|
2073
|
+
cursor = target + 1
|
|
2074
|
+
continue
|
|
2075
|
+
|
|
2076
|
+
while cursor < len(ordered) and ordered[cursor] is not None:
|
|
2077
|
+
cursor += 1
|
|
2078
|
+
if cursor >= len(ordered):
|
|
2079
|
+
break
|
|
2080
|
+
ordered[cursor] = expr
|
|
2081
|
+
cursor += 1
|
|
2082
|
+
|
|
2083
|
+
return ordered
|
|
2084
|
+
|
|
2085
|
+
def _build_const_address(self, init_node):
|
|
2086
|
+
if isinstance(init_node, c_ast.ID):
|
|
2087
|
+
try:
|
|
2088
|
+
_, sym = self.lookup(init_node.name)
|
|
2089
|
+
except Exception:
|
|
2090
|
+
return None
|
|
2091
|
+
if isinstance(sym, (ir.Function, ir.GlobalVariable)):
|
|
2092
|
+
return sym
|
|
2093
|
+
return None
|
|
2094
|
+
|
|
2095
|
+
if isinstance(init_node, c_ast.Cast):
|
|
2096
|
+
return self._build_const_address(init_node.expr)
|
|
2097
|
+
|
|
2098
|
+
if isinstance(init_node, c_ast.ArrayRef):
|
|
2099
|
+
base_addr = self._build_const_address(init_node.name)
|
|
2100
|
+
if base_addr is None or not isinstance(
|
|
2101
|
+
getattr(base_addr, "type", None), ir.PointerType
|
|
2102
|
+
):
|
|
2103
|
+
return None
|
|
2104
|
+
try:
|
|
2105
|
+
idx_val = int(self._eval_const_expr(init_node.subscript))
|
|
2106
|
+
except Exception:
|
|
2107
|
+
return None
|
|
2108
|
+
idx0 = ir.Constant(ir.IntType(32), 0)
|
|
2109
|
+
idx = ir.Constant(ir.IntType(32), idx_val)
|
|
2110
|
+
pointee = base_addr.type.pointee
|
|
2111
|
+
try:
|
|
2112
|
+
if isinstance(pointee, ir.ArrayType):
|
|
2113
|
+
return base_addr.gep([idx0, idx])
|
|
2114
|
+
return base_addr.gep([idx])
|
|
2115
|
+
except Exception:
|
|
2116
|
+
return None
|
|
2117
|
+
|
|
2118
|
+
if isinstance(init_node, c_ast.BinaryOp) and init_node.op in ("+", "-"):
|
|
2119
|
+
base_addr = self._build_const_address(init_node.left)
|
|
2120
|
+
offset_node = init_node.right
|
|
2121
|
+
offset_sign = 1
|
|
2122
|
+
if base_addr is None and init_node.op == "+":
|
|
2123
|
+
base_addr = self._build_const_address(init_node.right)
|
|
2124
|
+
offset_node = init_node.left
|
|
2125
|
+
elif base_addr is None:
|
|
2126
|
+
return None
|
|
2127
|
+
if base_addr is None or not isinstance(
|
|
2128
|
+
getattr(base_addr, "type", None), ir.PointerType
|
|
2129
|
+
):
|
|
2130
|
+
return None
|
|
2131
|
+
try:
|
|
2132
|
+
idx_val = int(self._eval_const_expr(offset_node))
|
|
2133
|
+
except Exception:
|
|
2134
|
+
return None
|
|
2135
|
+
if init_node.op == "-":
|
|
2136
|
+
idx_val = -idx_val
|
|
2137
|
+
idx0 = ir.Constant(ir.IntType(32), 0)
|
|
2138
|
+
idx = ir.Constant(ir.IntType(32), idx_val)
|
|
2139
|
+
pointee = base_addr.type.pointee
|
|
2140
|
+
try:
|
|
2141
|
+
if isinstance(pointee, ir.ArrayType):
|
|
2142
|
+
return base_addr.gep([idx0, idx])
|
|
2143
|
+
return base_addr.gep([idx])
|
|
2144
|
+
except Exception:
|
|
2145
|
+
return None
|
|
2146
|
+
|
|
2147
|
+
if isinstance(init_node, c_ast.StructRef):
|
|
2148
|
+
base_addr = self._build_const_address(init_node.name)
|
|
2149
|
+
if base_addr is None or not isinstance(
|
|
2150
|
+
getattr(base_addr, "type", None), ir.PointerType
|
|
2151
|
+
):
|
|
2152
|
+
return None
|
|
2153
|
+
if (
|
|
2154
|
+
init_node.type == "->"
|
|
2155
|
+
and isinstance(base_addr.type.pointee, ir.ArrayType)
|
|
2156
|
+
):
|
|
2157
|
+
idx0 = ir.Constant(ir.IntType(32), 0)
|
|
2158
|
+
try:
|
|
2159
|
+
base_addr = base_addr.gep([idx0, idx0])
|
|
2160
|
+
except Exception:
|
|
2161
|
+
return None
|
|
2162
|
+
aggregate_type = base_addr.type.pointee
|
|
2163
|
+
try:
|
|
2164
|
+
offset, field_type = self._get_aggregate_field_info(
|
|
2165
|
+
aggregate_type, init_node.field.name
|
|
2166
|
+
)
|
|
2167
|
+
except Exception:
|
|
2168
|
+
return None
|
|
2169
|
+
|
|
2170
|
+
if (
|
|
2171
|
+
hasattr(aggregate_type, "members")
|
|
2172
|
+
and init_node.field.name in aggregate_type.members
|
|
2173
|
+
and not getattr(aggregate_type, "has_custom_layout", False)
|
|
2174
|
+
and not getattr(aggregate_type, "is_union", False)
|
|
2175
|
+
):
|
|
2176
|
+
idx0 = ir.Constant(ir.IntType(32), 0)
|
|
2177
|
+
field_index = aggregate_type.members.index(init_node.field.name)
|
|
2178
|
+
try:
|
|
2179
|
+
return base_addr.gep(
|
|
2180
|
+
[idx0, ir.Constant(ir.IntType(32), field_index)]
|
|
2181
|
+
)
|
|
2182
|
+
except Exception:
|
|
2183
|
+
return None
|
|
2184
|
+
|
|
2185
|
+
try:
|
|
2186
|
+
byte_base = base_addr.bitcast(ir.PointerType(int8_t))
|
|
2187
|
+
byte_addr = byte_base.gep([ir.Constant(ir.IntType(32), offset)])
|
|
2188
|
+
return byte_addr.bitcast(ir.PointerType(field_type))
|
|
2189
|
+
except Exception:
|
|
2190
|
+
return None
|
|
2191
|
+
|
|
2192
|
+
return None
|
|
2193
|
+
|
|
1480
2194
|
def _build_pointer_const(self, init_node, ir_type):
|
|
1481
2195
|
if isinstance(init_node, c_ast.InitList):
|
|
1482
2196
|
if init_node.exprs:
|
|
1483
2197
|
return self._build_pointer_const(init_node.exprs[0], ir_type)
|
|
1484
2198
|
return ir.Constant(ir_type, None)
|
|
2199
|
+
if isinstance(init_node, c_ast.Cast):
|
|
2200
|
+
return self._build_pointer_const(init_node.expr, ir_type)
|
|
1485
2201
|
if (
|
|
1486
2202
|
isinstance(init_node, c_ast.Constant)
|
|
1487
2203
|
and getattr(init_node, "type", None) == "string"
|
|
@@ -1502,22 +2218,23 @@ class LLVMCodeGenerator(object):
|
|
|
1502
2218
|
return sym
|
|
1503
2219
|
if isinstance(sym.type, ir.PointerType):
|
|
1504
2220
|
return sym.bitcast(ir_type)
|
|
2221
|
+
if isinstance(init_node, c_ast.ArrayRef):
|
|
2222
|
+
addr = self._build_const_address(init_node)
|
|
2223
|
+
if addr is not None:
|
|
2224
|
+
if addr.type == ir_type:
|
|
2225
|
+
return addr
|
|
2226
|
+
if isinstance(addr.type, ir.PointerType):
|
|
2227
|
+
return addr.bitcast(ir_type)
|
|
1505
2228
|
if (
|
|
1506
2229
|
isinstance(init_node, c_ast.UnaryOp)
|
|
1507
2230
|
and init_node.op == "&"
|
|
1508
|
-
and isinstance(init_node.expr, c_ast.ID)
|
|
1509
2231
|
):
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
if isinstance(sym, ir.GlobalVariable):
|
|
1517
|
-
if sym.type == ir_type:
|
|
1518
|
-
return sym
|
|
1519
|
-
if isinstance(sym.type, ir.PointerType):
|
|
1520
|
-
return sym.bitcast(ir_type)
|
|
2232
|
+
addr = self._build_const_address(init_node.expr)
|
|
2233
|
+
if addr is not None:
|
|
2234
|
+
if addr.type == ir_type:
|
|
2235
|
+
return addr
|
|
2236
|
+
if isinstance(addr.type, ir.PointerType):
|
|
2237
|
+
return addr.bitcast(ir_type)
|
|
1521
2238
|
try:
|
|
1522
2239
|
val = self._eval_const_expr(init_node)
|
|
1523
2240
|
if val == 0:
|
|
@@ -1598,6 +2315,17 @@ class LLVMCodeGenerator(object):
|
|
|
1598
2315
|
result -= 1 << bits
|
|
1599
2316
|
return ir.Constant(int_type, result)
|
|
1600
2317
|
|
|
2318
|
+
def _raw_bytes_to_unsigned_int(self, byte_values):
|
|
2319
|
+
result = 0
|
|
2320
|
+
width = len(byte_values)
|
|
2321
|
+
for i, byte_val in enumerate(byte_values):
|
|
2322
|
+
shift_bits = 8 * (i if self._is_little_endian() else (width - 1 - i))
|
|
2323
|
+
raw = getattr(byte_val, "constant", 0)
|
|
2324
|
+
if not isinstance(raw, int):
|
|
2325
|
+
raw = 0
|
|
2326
|
+
result |= (raw & 0xFF) << shift_bits
|
|
2327
|
+
return result
|
|
2328
|
+
|
|
1601
2329
|
def _const_init_bytes(self, init_node, ir_type):
|
|
1602
2330
|
size = self._ir_type_size(ir_type)
|
|
1603
2331
|
if init_node is None:
|
|
@@ -1605,28 +2333,12 @@ class LLVMCodeGenerator(object):
|
|
|
1605
2333
|
|
|
1606
2334
|
if getattr(ir_type, "is_union", False):
|
|
1607
2335
|
raw = self._zero_bytes(size)
|
|
1608
|
-
|
|
1609
|
-
ir_type
|
|
2336
|
+
field_name, member_type, member_init = self._select_union_initializer(
|
|
2337
|
+
init_node, ir_type
|
|
1610
2338
|
)
|
|
1611
|
-
if
|
|
2339
|
+
if field_name is None:
|
|
1612
2340
|
return raw
|
|
1613
2341
|
|
|
1614
|
-
first_name = member_names[0]
|
|
1615
|
-
member_type = ir_type.member_types[first_name]
|
|
1616
|
-
member_init = init_node
|
|
1617
|
-
if isinstance(init_node, c_ast.InitList):
|
|
1618
|
-
exprs = init_node.exprs or []
|
|
1619
|
-
if not exprs:
|
|
1620
|
-
member_init = None
|
|
1621
|
-
elif isinstance(member_type, (ir.ArrayType, ir.LiteralStructType)):
|
|
1622
|
-
member_init = (
|
|
1623
|
-
exprs[0]
|
|
1624
|
-
if len(exprs) == 1 and isinstance(exprs[0], c_ast.InitList)
|
|
1625
|
-
else init_node
|
|
1626
|
-
)
|
|
1627
|
-
else:
|
|
1628
|
-
member_init = exprs[0]
|
|
1629
|
-
|
|
1630
2342
|
member_bytes = self._const_init_bytes(member_init, member_type)
|
|
1631
2343
|
raw[: min(size, len(member_bytes))] = member_bytes[:size]
|
|
1632
2344
|
return raw
|
|
@@ -1686,16 +2398,62 @@ class LLVMCodeGenerator(object):
|
|
|
1686
2398
|
|
|
1687
2399
|
return self._zero_bytes(size)
|
|
1688
2400
|
|
|
1689
|
-
if
|
|
2401
|
+
if _is_struct_ir_type(ir_type):
|
|
2402
|
+
if getattr(ir_type, "has_custom_layout", False):
|
|
2403
|
+
raw = self._zero_bytes(size)
|
|
2404
|
+
if not isinstance(init_node, c_ast.InitList):
|
|
2405
|
+
return raw
|
|
2406
|
+
|
|
2407
|
+
exprs = self._ordered_struct_init_exprs(init_node, ir_type)
|
|
2408
|
+
for i, field_name in enumerate(getattr(ir_type, "members", ())):
|
|
2409
|
+
if i >= len(exprs):
|
|
2410
|
+
break
|
|
2411
|
+
expr = exprs[i]
|
|
2412
|
+
layout = ir_type.field_layouts.get(field_name)
|
|
2413
|
+
if layout is None:
|
|
2414
|
+
continue
|
|
2415
|
+
|
|
2416
|
+
if layout.is_bitfield:
|
|
2417
|
+
scalar_node = self._scalar_init_node(expr)
|
|
2418
|
+
if scalar_node is None:
|
|
2419
|
+
continue
|
|
2420
|
+
try:
|
|
2421
|
+
field_value = int(self._eval_const_expr(scalar_node))
|
|
2422
|
+
except Exception:
|
|
2423
|
+
continue
|
|
2424
|
+
storage_size = self._ir_type_size(layout.storage_ir_type)
|
|
2425
|
+
start = layout.storage_byte_offset
|
|
2426
|
+
current = self._raw_bytes_to_unsigned_int(
|
|
2427
|
+
raw[start : start + storage_size]
|
|
2428
|
+
)
|
|
2429
|
+
field_mask = self._bitfield_mask(layout.bit_width)
|
|
2430
|
+
clear_mask = ((1 << (storage_size * 8)) - 1) ^ (
|
|
2431
|
+
field_mask << layout.bit_offset
|
|
2432
|
+
)
|
|
2433
|
+
current = (current & clear_mask) | (
|
|
2434
|
+
(field_value & field_mask) << layout.bit_offset
|
|
2435
|
+
)
|
|
2436
|
+
raw[start : start + storage_size] = self._const_int_to_bytes(
|
|
2437
|
+
current, storage_size
|
|
2438
|
+
)
|
|
2439
|
+
continue
|
|
2440
|
+
|
|
2441
|
+
field_size = self._ir_type_size(layout.semantic_ir_type)
|
|
2442
|
+
field_bytes = self._const_init_bytes(expr, layout.semantic_ir_type)
|
|
2443
|
+
start = layout.byte_offset
|
|
2444
|
+
raw[start : start + field_size] = field_bytes[:field_size]
|
|
2445
|
+
return raw
|
|
2446
|
+
|
|
1690
2447
|
raw = self._zero_bytes(size)
|
|
1691
2448
|
if not isinstance(init_node, c_ast.InitList):
|
|
1692
2449
|
return raw
|
|
1693
2450
|
|
|
2451
|
+
exprs = self._ordered_struct_init_exprs(init_node, ir_type)
|
|
1694
2452
|
offset = 0
|
|
1695
2453
|
for i, member_type in enumerate(ir_type.elements):
|
|
1696
2454
|
align = self._ir_type_align(member_type)
|
|
1697
2455
|
offset = (offset + align - 1) & ~(align - 1)
|
|
1698
|
-
expr =
|
|
2456
|
+
expr = exprs[i] if i < len(exprs) else None
|
|
1699
2457
|
field_bytes = self._const_init_bytes(expr, member_type)
|
|
1700
2458
|
field_size = self._ir_type_size(member_type)
|
|
1701
2459
|
raw[offset : offset + field_size] = field_bytes[:field_size]
|
|
@@ -1767,11 +2525,36 @@ class LLVMCodeGenerator(object):
|
|
|
1767
2525
|
|
|
1768
2526
|
return self._zero_initializer(ir_type)
|
|
1769
2527
|
|
|
1770
|
-
if
|
|
2528
|
+
if _is_struct_ir_type(ir_type):
|
|
2529
|
+
if getattr(ir_type, "has_custom_layout", False):
|
|
2530
|
+
try:
|
|
2531
|
+
raw = self._const_init_bytes(init_node, ir_type)
|
|
2532
|
+
values = []
|
|
2533
|
+
offset = 0
|
|
2534
|
+
for member_type in ir_type.elements:
|
|
2535
|
+
field_size = self._ir_type_size(member_type)
|
|
2536
|
+
field_bytes = raw[offset : offset + field_size]
|
|
2537
|
+
if isinstance(member_type, ir.IntType):
|
|
2538
|
+
values.append(
|
|
2539
|
+
self._bytes_to_int_constant(field_bytes, member_type)
|
|
2540
|
+
)
|
|
2541
|
+
elif (
|
|
2542
|
+
isinstance(member_type, ir.ArrayType)
|
|
2543
|
+
and isinstance(member_type.element, ir.IntType)
|
|
2544
|
+
and member_type.element.width == 8
|
|
2545
|
+
):
|
|
2546
|
+
values.append(ir.Constant(member_type, field_bytes))
|
|
2547
|
+
else:
|
|
2548
|
+
values.append(self._zero_initializer(member_type))
|
|
2549
|
+
offset += field_size
|
|
2550
|
+
return ir.Constant(ir_type, values)
|
|
2551
|
+
except Exception:
|
|
2552
|
+
return self._zero_initializer(ir_type)
|
|
1771
2553
|
if isinstance(init_node, c_ast.InitList):
|
|
2554
|
+
exprs = self._ordered_struct_init_exprs(init_node, ir_type)
|
|
1772
2555
|
values = []
|
|
1773
2556
|
for i, member_type in enumerate(ir_type.elements):
|
|
1774
|
-
expr =
|
|
2557
|
+
expr = exprs[i] if i < len(exprs) else None
|
|
1775
2558
|
values.append(self._build_const_init(expr, member_type))
|
|
1776
2559
|
try:
|
|
1777
2560
|
return ir.Constant(ir_type, values)
|
|
@@ -1796,49 +2579,249 @@ class LLVMCodeGenerator(object):
|
|
|
1796
2579
|
"""Recursively initialize array elements from an InitList."""
|
|
1797
2580
|
for i, expr in enumerate(init_list.exprs):
|
|
1798
2581
|
idx = prefix_idx + [ir.Constant(ir.IntType(32), i)]
|
|
1799
|
-
if isinstance(expr, c_ast.InitList):
|
|
1800
|
-
self._init_array(base_addr, expr, elem_ir_type, idx)
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
elem_ptr = self.builder.gep(base_addr, idx, inbounds=True)
|
|
1805
|
-
self._safe_store(val, elem_ptr)
|
|
2582
|
+
if isinstance(expr, c_ast.InitList) and isinstance(elem_ir_type, ir.ArrayType):
|
|
2583
|
+
self._init_array(base_addr, expr, elem_ir_type.element, idx)
|
|
2584
|
+
continue
|
|
2585
|
+
elem_ptr = self.builder.gep(base_addr, idx, inbounds=True)
|
|
2586
|
+
self._init_runtime_value(elem_ptr, elem_ir_type, expr)
|
|
1806
2587
|
|
|
1807
|
-
def
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
while isinstance(node, c_ast.ArrayDecl):
|
|
1811
|
-
dims.append(self._eval_dim(node.dim) if node.dim else 0)
|
|
1812
|
-
node = node.type
|
|
1813
|
-
elem_ir_type = self._resolve_ast_type(node)
|
|
1814
|
-
if isinstance(elem_ir_type, ir.VoidType):
|
|
1815
|
-
elem_ir_type = int8_t
|
|
1816
|
-
arr_ir_type = elem_ir_type
|
|
1817
|
-
for dim in reversed(dims):
|
|
1818
|
-
arr_ir_type = ir.ArrayType(arr_ir_type, dim)
|
|
1819
|
-
arr_ir_type.dim_array = dims
|
|
1820
|
-
return arr_ir_type
|
|
2588
|
+
def _init_runtime_value(self, dest_ptr, target_type, init_node):
|
|
2589
|
+
if dest_ptr is None or init_node is None:
|
|
2590
|
+
return
|
|
1821
2591
|
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
2592
|
+
if isinstance(target_type, ir.ArrayType):
|
|
2593
|
+
if (
|
|
2594
|
+
isinstance(init_node, c_ast.Constant)
|
|
2595
|
+
and getattr(init_node, "type", None) == "string"
|
|
2596
|
+
and isinstance(target_type.element, ir.IntType)
|
|
2597
|
+
and target_type.element.width == 8
|
|
2598
|
+
):
|
|
2599
|
+
raw = self._process_escapes(init_node.value[1:-1]) + "\00"
|
|
2600
|
+
idx0 = ir.Constant(ir.IntType(32), 0)
|
|
2601
|
+
for i, ch in enumerate(raw[: target_type.count]):
|
|
2602
|
+
elem_ptr = self.builder.gep(
|
|
2603
|
+
dest_ptr,
|
|
2604
|
+
[idx0, ir.Constant(ir.IntType(32), i)],
|
|
2605
|
+
inbounds=True,
|
|
2606
|
+
)
|
|
2607
|
+
self.builder.store(int8_t(ord(ch)), elem_ptr)
|
|
2608
|
+
return
|
|
2609
|
+
if isinstance(init_node, c_ast.InitList):
|
|
2610
|
+
self._init_array(
|
|
2611
|
+
dest_ptr,
|
|
2612
|
+
init_node,
|
|
2613
|
+
target_type.element,
|
|
2614
|
+
[ir.Constant(ir.IntType(32), 0)],
|
|
2615
|
+
)
|
|
2616
|
+
return
|
|
1833
2617
|
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
2618
|
+
if getattr(target_type, "is_union", False) or _is_struct_ir_type(target_type):
|
|
2619
|
+
if isinstance(init_node, c_ast.InitList):
|
|
2620
|
+
self._init_runtime_aggregate(dest_ptr, init_node, target_type)
|
|
2621
|
+
return
|
|
2622
|
+
init_val, _ = self.codegen(init_node)
|
|
2623
|
+
if init_val is not None:
|
|
2624
|
+
if init_val.type != target_type:
|
|
2625
|
+
init_val = self._implicit_convert(init_val, target_type)
|
|
2626
|
+
self._safe_store(init_val, dest_ptr)
|
|
2627
|
+
return
|
|
2628
|
+
|
|
2629
|
+
scalar_node = self._scalar_init_node(init_node)
|
|
2630
|
+
if scalar_node is None:
|
|
2631
|
+
return
|
|
2632
|
+
init_val, _ = self.codegen(scalar_node)
|
|
2633
|
+
if init_val is None:
|
|
2634
|
+
return
|
|
2635
|
+
if init_val.type != target_type:
|
|
2636
|
+
init_val = self._implicit_convert(init_val, target_type)
|
|
2637
|
+
self._safe_store(init_val, dest_ptr)
|
|
2638
|
+
|
|
2639
|
+
def _init_runtime_aggregate(self, base_addr, init_node, ir_type):
|
|
2640
|
+
exprs = list(getattr(init_node, "exprs", None) or [])
|
|
2641
|
+
if getattr(ir_type, "is_union", False):
|
|
2642
|
+
field_name, field_type, member_init = self._select_union_initializer(
|
|
2643
|
+
init_node, ir_type
|
|
2644
|
+
)
|
|
2645
|
+
if field_name is None or member_init is None:
|
|
2646
|
+
return
|
|
2647
|
+
field_ptr = self.builder.bitcast(
|
|
2648
|
+
base_addr,
|
|
2649
|
+
ir.PointerType(field_type),
|
|
2650
|
+
name="unioninit",
|
|
2651
|
+
)
|
|
2652
|
+
self._init_runtime_value(field_ptr, field_type, member_init)
|
|
2653
|
+
return
|
|
2654
|
+
|
|
2655
|
+
if getattr(ir_type, "has_custom_layout", False):
|
|
2656
|
+
exprs = self._ordered_struct_init_exprs(init_node, ir_type)
|
|
2657
|
+
for i, field_name in enumerate(getattr(ir_type, "members", ())):
|
|
2658
|
+
if i >= len(exprs):
|
|
2659
|
+
break
|
|
2660
|
+
expr = exprs[i]
|
|
2661
|
+
layout = ir_type.field_layouts.get(field_name)
|
|
2662
|
+
if layout is None:
|
|
2663
|
+
continue
|
|
2664
|
+
if layout.is_bitfield:
|
|
2665
|
+
scalar_node = self._scalar_init_node(expr)
|
|
2666
|
+
if scalar_node is None:
|
|
2667
|
+
continue
|
|
2668
|
+
field_val, _ = self.codegen(scalar_node)
|
|
2669
|
+
if field_val is None:
|
|
2670
|
+
continue
|
|
2671
|
+
if field_val.type != layout.semantic_ir_type:
|
|
2672
|
+
field_val = self._implicit_convert(
|
|
2673
|
+
field_val,
|
|
2674
|
+
layout.semantic_ir_type,
|
|
2675
|
+
)
|
|
2676
|
+
ref = BitFieldRef(
|
|
2677
|
+
container_ptr=self._byte_offset_ptr(
|
|
2678
|
+
base_addr,
|
|
2679
|
+
layout.storage_byte_offset,
|
|
2680
|
+
ir.PointerType(layout.storage_ir_type),
|
|
2681
|
+
name="bitfieldptr",
|
|
2682
|
+
),
|
|
2683
|
+
storage_ir_type=layout.storage_ir_type,
|
|
2684
|
+
bit_offset=layout.bit_offset,
|
|
2685
|
+
bit_width=layout.bit_width,
|
|
2686
|
+
semantic_ir_type=layout.semantic_ir_type,
|
|
2687
|
+
is_unsigned=layout.is_unsigned,
|
|
2688
|
+
)
|
|
2689
|
+
self._store_bitfield(field_val, ref)
|
|
2690
|
+
continue
|
|
2691
|
+
|
|
2692
|
+
field_ptr = self._byte_offset_ptr(
|
|
2693
|
+
base_addr,
|
|
2694
|
+
layout.byte_offset,
|
|
2695
|
+
ir.PointerType(layout.semantic_ir_type),
|
|
2696
|
+
name="fieldptr",
|
|
2697
|
+
)
|
|
2698
|
+
self._init_runtime_value(field_ptr, layout.semantic_ir_type, expr)
|
|
2699
|
+
return
|
|
2700
|
+
|
|
2701
|
+
exprs = self._ordered_struct_init_exprs(init_node, ir_type)
|
|
2702
|
+
for i, field_type in enumerate(ir_type.elements):
|
|
2703
|
+
if i >= len(exprs):
|
|
2704
|
+
break
|
|
2705
|
+
expr = exprs[i]
|
|
2706
|
+
field_addr = self.builder.gep(
|
|
2707
|
+
base_addr,
|
|
2708
|
+
[ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)],
|
|
2709
|
+
inbounds=True,
|
|
2710
|
+
)
|
|
2711
|
+
semantic_field_type = self._refine_member_ir_type(ir_type, i, field_type)
|
|
2712
|
+
typed_field_addr = field_addr
|
|
2713
|
+
target_ptr_type = ir.PointerType(semantic_field_type)
|
|
2714
|
+
if field_addr.type != target_ptr_type:
|
|
2715
|
+
try:
|
|
2716
|
+
typed_field_addr = self.builder.bitcast(
|
|
2717
|
+
field_addr,
|
|
2718
|
+
target_ptr_type,
|
|
2719
|
+
)
|
|
2720
|
+
except Exception:
|
|
2721
|
+
typed_field_addr = field_addr
|
|
2722
|
+
self._init_runtime_value(typed_field_addr, semantic_field_type, expr)
|
|
2723
|
+
|
|
2724
|
+
def _select_union_initializer(self, init_node, ir_type):
|
|
2725
|
+
member_names = getattr(ir_type, "members", None) or list(
|
|
2726
|
+
getattr(ir_type, "member_types", {}).keys()
|
|
2727
|
+
)
|
|
2728
|
+
if not member_names:
|
|
2729
|
+
return None, None, None
|
|
2730
|
+
|
|
2731
|
+
field_name = member_names[0]
|
|
2732
|
+
field_type = self._refine_member_ir_type(
|
|
2733
|
+
ir_type,
|
|
2734
|
+
field_name,
|
|
2735
|
+
ir_type.member_types[field_name],
|
|
2736
|
+
)
|
|
2737
|
+
member_init = init_node
|
|
2738
|
+
|
|
2739
|
+
if isinstance(init_node, c_ast.InitList):
|
|
2740
|
+
exprs = init_node.exprs or []
|
|
2741
|
+
if not exprs:
|
|
2742
|
+
return field_name, field_type, None
|
|
2743
|
+
|
|
2744
|
+
first_expr = exprs[0]
|
|
2745
|
+
if isinstance(first_expr, c_ast.NamedInitializer):
|
|
2746
|
+
designators = getattr(first_expr, "name", None) or []
|
|
2747
|
+
if len(designators) == 1 and isinstance(designators[0], c_ast.ID):
|
|
2748
|
+
candidate = designators[0].name
|
|
2749
|
+
if candidate in ir_type.member_types:
|
|
2750
|
+
field_name = candidate
|
|
2751
|
+
field_type = self._refine_member_ir_type(
|
|
2752
|
+
ir_type,
|
|
2753
|
+
field_name,
|
|
2754
|
+
ir_type.member_types[field_name],
|
|
2755
|
+
)
|
|
2756
|
+
return field_name, field_type, first_expr.expr
|
|
2757
|
+
first_expr = first_expr.expr
|
|
2758
|
+
|
|
2759
|
+
if isinstance(field_type, (ir.ArrayType, ir.IdentifiedStructType, ir.LiteralStructType)):
|
|
2760
|
+
member_init = (
|
|
2761
|
+
first_expr
|
|
2762
|
+
if len(exprs) == 1 and isinstance(first_expr, c_ast.InitList)
|
|
2763
|
+
else init_node
|
|
2764
|
+
)
|
|
2765
|
+
else:
|
|
2766
|
+
member_init = first_expr
|
|
2767
|
+
|
|
2768
|
+
return field_name, field_type, member_init
|
|
2769
|
+
|
|
2770
|
+
def _build_array_ir_type(self, array_decl, init_node=None):
|
|
2771
|
+
dims = []
|
|
2772
|
+
node = array_decl
|
|
2773
|
+
inferred_top_dim = self._infer_array_count_from_initializer(init_node)
|
|
2774
|
+
is_top_level = True
|
|
2775
|
+
while isinstance(node, c_ast.ArrayDecl):
|
|
2776
|
+
dim = self._eval_dim(node.dim) if node.dim else 0
|
|
2777
|
+
if dim == 0 and is_top_level and inferred_top_dim is not None:
|
|
2778
|
+
dim = inferred_top_dim
|
|
2779
|
+
dims.append(dim)
|
|
2780
|
+
node = node.type
|
|
2781
|
+
is_top_level = False
|
|
2782
|
+
elem_ir_type = self._resolve_ast_type(node)
|
|
2783
|
+
if isinstance(elem_ir_type, ir.VoidType):
|
|
2784
|
+
elem_ir_type = int8_t
|
|
2785
|
+
arr_ir_type = elem_ir_type
|
|
2786
|
+
for dim in reversed(dims):
|
|
2787
|
+
arr_ir_type = ir.ArrayType(arr_ir_type, dim)
|
|
2788
|
+
arr_ir_type.dim_array = dims
|
|
2789
|
+
return arr_ir_type
|
|
2790
|
+
|
|
2791
|
+
def _resolve_param_type(self, param):
|
|
2792
|
+
"""Resolve a function parameter type, handling typedefs and pointers."""
|
|
2793
|
+
node_type = param.type if hasattr(param, "type") else param
|
|
2794
|
+
if isinstance(node_type, c_ast.ArrayDecl):
|
|
2795
|
+
inner = node_type.type
|
|
2796
|
+
if isinstance(inner, c_ast.ArrayDecl):
|
|
2797
|
+
return ir.PointerType(self._build_array_ir_type(inner))
|
|
2798
|
+
elem_ir_type = self._resolve_ast_type(inner)
|
|
2799
|
+
if isinstance(elem_ir_type, ir.VoidType):
|
|
2800
|
+
elem_ir_type = int8_t
|
|
2801
|
+
return ir.PointerType(elem_ir_type)
|
|
2802
|
+
t = self._resolve_ast_type(node_type)
|
|
2803
|
+
if isinstance(t, ir.ArrayType):
|
|
2804
|
+
return ir.PointerType(t.element)
|
|
2805
|
+
if isinstance(t, ir.VoidType):
|
|
2806
|
+
return None # void params mean "no params" in C
|
|
2807
|
+
return t
|
|
2808
|
+
|
|
2809
|
+
def _emit_vla_param_bound_side_effects(self, node_type):
|
|
2810
|
+
current = node_type
|
|
2811
|
+
while isinstance(current, c_ast.ArrayDecl):
|
|
2812
|
+
dim = current.dim
|
|
2813
|
+
if dim is not None and not isinstance(dim, c_ast.Constant):
|
|
2814
|
+
self.codegen(dim)
|
|
2815
|
+
current = current.type
|
|
2816
|
+
|
|
2817
|
+
def _resolve_ast_type(self, node_type):
|
|
2818
|
+
"""Recursively resolve an AST type to IR type, with typedef support."""
|
|
2819
|
+
if isinstance(node_type, c_ast.PtrDecl):
|
|
2820
|
+
inner = node_type.type
|
|
2821
|
+
if isinstance(inner, c_ast.FuncDecl):
|
|
2822
|
+
return self._build_func_ptr_type(inner)
|
|
2823
|
+
pointee = self._resolve_ast_type(inner)
|
|
2824
|
+
if isinstance(pointee, ir.VoidType):
|
|
1842
2825
|
return voidptr_t
|
|
1843
2826
|
return ir.PointerType(pointee)
|
|
1844
2827
|
elif isinstance(node_type, c_ast.TypeDecl):
|
|
@@ -1848,6 +2831,9 @@ class LLVMCodeGenerator(object):
|
|
|
1848
2831
|
return self.codegen_Struct(node_type.type)
|
|
1849
2832
|
elif isinstance(node_type.type, c_ast.Union):
|
|
1850
2833
|
return self.codegen_Union(node_type.type)
|
|
2834
|
+
elif isinstance(node_type.type, c_ast.Enum):
|
|
2835
|
+
self.codegen_Enum(node_type.type)
|
|
2836
|
+
return int32_t
|
|
1851
2837
|
return int64_t
|
|
1852
2838
|
elif isinstance(node_type, c_ast.ArrayDecl):
|
|
1853
2839
|
return voidptr_t
|
|
@@ -1862,26 +2848,74 @@ class LLVMCodeGenerator(object):
|
|
|
1862
2848
|
return int(v, 0) # handles hex/octal/decimal
|
|
1863
2849
|
return self._eval_const_expr(dim_node)
|
|
1864
2850
|
|
|
2851
|
+
def _infer_array_count_from_initializer(self, init_node):
|
|
2852
|
+
if init_node is None:
|
|
2853
|
+
return None
|
|
2854
|
+
if isinstance(init_node, c_ast.InitList):
|
|
2855
|
+
return len(init_node.exprs)
|
|
2856
|
+
if (
|
|
2857
|
+
isinstance(init_node, c_ast.Constant)
|
|
2858
|
+
and getattr(init_node, "type", None) == "string"
|
|
2859
|
+
):
|
|
2860
|
+
raw = init_node.value[1:-1]
|
|
2861
|
+
return len(self._process_escapes(raw)) + 1
|
|
2862
|
+
return None
|
|
2863
|
+
|
|
1865
2864
|
def _build_func_ptr_type(self, func_decl_node):
|
|
1866
2865
|
"""Build an IR function pointer type from a FuncDecl AST node."""
|
|
2866
|
+
func_type, _ = self._build_function_ir_type(func_decl_node)
|
|
2867
|
+
return func_type.as_pointer()
|
|
2868
|
+
|
|
2869
|
+
def _build_function_ir_type(self, func_decl_node):
|
|
2870
|
+
"""Build an IR function type from a FuncDecl AST node."""
|
|
1867
2871
|
ret_ir, _ = self.codegen(func_decl_node)
|
|
1868
2872
|
param_types = []
|
|
2873
|
+
is_var_arg = False
|
|
1869
2874
|
if func_decl_node.args:
|
|
1870
2875
|
for param in func_decl_node.args.params:
|
|
1871
2876
|
if isinstance(param, c_ast.EllipsisParam):
|
|
2877
|
+
is_var_arg = True
|
|
1872
2878
|
continue
|
|
1873
|
-
if isinstance(param, c_ast.Typename):
|
|
1874
|
-
t = self._resolve_ast_type(param.type)
|
|
1875
|
-
if not isinstance(t, ir.VoidType):
|
|
1876
|
-
param_types.append(t)
|
|
1877
|
-
elif isinstance(param, c_ast.Decl):
|
|
2879
|
+
if isinstance(param, (c_ast.Typename, c_ast.Decl)):
|
|
1878
2880
|
t = self._resolve_param_type(param)
|
|
1879
2881
|
if t is not None:
|
|
1880
2882
|
param_types.append(t)
|
|
1881
2883
|
if isinstance(ret_ir, ir.VoidType):
|
|
1882
2884
|
ret_ir = ir.VoidType()
|
|
1883
|
-
|
|
1884
|
-
|
|
2885
|
+
return ir.FunctionType(ret_ir, param_types, var_arg=is_var_arg), ret_ir
|
|
2886
|
+
|
|
2887
|
+
def _funcdef_param_infos(self, node):
|
|
2888
|
+
infos = []
|
|
2889
|
+
is_var_arg = False
|
|
2890
|
+
if not node.decl.type.args:
|
|
2891
|
+
return infos, is_var_arg
|
|
2892
|
+
|
|
2893
|
+
knr_param_decls = {
|
|
2894
|
+
decl.name: decl for decl in (getattr(node, "param_decls", None) or [])
|
|
2895
|
+
}
|
|
2896
|
+
|
|
2897
|
+
for index, param in enumerate(node.decl.type.args.params):
|
|
2898
|
+
if isinstance(param, c_ast.EllipsisParam):
|
|
2899
|
+
is_var_arg = True
|
|
2900
|
+
continue
|
|
2901
|
+
|
|
2902
|
+
decl = param
|
|
2903
|
+
if isinstance(param, c_ast.ID):
|
|
2904
|
+
decl = knr_param_decls.get(param.name)
|
|
2905
|
+
if decl is None:
|
|
2906
|
+
infos.append((param.name, int32_t, None))
|
|
2907
|
+
continue
|
|
2908
|
+
|
|
2909
|
+
t = self._resolve_param_type(decl)
|
|
2910
|
+
if t is None:
|
|
2911
|
+
continue
|
|
2912
|
+
|
|
2913
|
+
pname = getattr(decl, "name", None)
|
|
2914
|
+
if not isinstance(pname, str):
|
|
2915
|
+
pname = f"arg{index}"
|
|
2916
|
+
infos.append((pname, t, decl))
|
|
2917
|
+
|
|
2918
|
+
return infos, is_var_arg
|
|
1885
2919
|
|
|
1886
2920
|
def _safe_load(self, ptr, name=""):
|
|
1887
2921
|
"""Load from ptr, guard against non-pointer types."""
|
|
@@ -1907,9 +2941,26 @@ class LLVMCodeGenerator(object):
|
|
|
1907
2941
|
gv.global_constant = True
|
|
1908
2942
|
gv.linkage = "internal"
|
|
1909
2943
|
base = gv
|
|
2944
|
+
elif not isinstance(getattr(value, "type", None), ir.PointerType):
|
|
2945
|
+
base = self._alloca_in_entry(value.type, f"{name}.tmp")
|
|
2946
|
+
self._safe_store(value, base)
|
|
1910
2947
|
idx0 = ir.Constant(ir.IntType(32), 0)
|
|
1911
2948
|
return self.builder.gep(base, [idx0, idx0], name=name)
|
|
1912
2949
|
|
|
2950
|
+
def _decay_array_expr_to_pointer(self, expr_node, value, name="arrayexprdecay"):
|
|
2951
|
+
"""Apply array-to-pointer decay using the expression's semantic type."""
|
|
2952
|
+
semantic_type = self._get_expr_ir_type(expr_node)
|
|
2953
|
+
if isinstance(semantic_type, ir.ArrayType):
|
|
2954
|
+
if isinstance(getattr(value, "type", None), ir.ArrayType):
|
|
2955
|
+
return self._decay_array_value_to_pointer(value, name)
|
|
2956
|
+
if (
|
|
2957
|
+
isinstance(getattr(value, "type", None), ir.PointerType)
|
|
2958
|
+
and value.type.pointee == semantic_type
|
|
2959
|
+
):
|
|
2960
|
+
idx0 = ir.Constant(ir.IntType(32), 0)
|
|
2961
|
+
return self.builder.gep(value, [idx0, idx0], name=name)
|
|
2962
|
+
return self._decay_array_value_to_pointer(value, name)
|
|
2963
|
+
|
|
1913
2964
|
def _safe_store(self, value, ptr):
|
|
1914
2965
|
"""Store value to ptr, auto-converting types if needed."""
|
|
1915
2966
|
if value is None or ptr is None:
|
|
@@ -1929,11 +2980,9 @@ class LLVMCodeGenerator(object):
|
|
|
1929
2980
|
"""Convert val to target_type if needed (implicit C promotion/truncation)."""
|
|
1930
2981
|
if val is None or isinstance(val.type, ir.VoidType):
|
|
1931
2982
|
# Can't convert void — return a zero of target type
|
|
1932
|
-
if isinstance(target_type, ir.
|
|
1933
|
-
return ir.Constant(target_type, None)
|
|
1934
|
-
elif isinstance(target_type, ir.VoidType):
|
|
2983
|
+
if isinstance(target_type, ir.VoidType):
|
|
1935
2984
|
return val
|
|
1936
|
-
return
|
|
2985
|
+
return self._zero_initializer(target_type)
|
|
1937
2986
|
if val.type == target_type:
|
|
1938
2987
|
return val
|
|
1939
2988
|
if isinstance(val.type, ir.IntType) and self._is_floating_ir_type(target_type):
|
|
@@ -1994,6 +3043,49 @@ class LLVMCodeGenerator(object):
|
|
|
1994
3043
|
return self.builder.bitcast(ptr, target_type)
|
|
1995
3044
|
return val
|
|
1996
3045
|
|
|
3046
|
+
def _is_scalar_ir_type(self, ir_type):
|
|
3047
|
+
return (
|
|
3048
|
+
isinstance(ir_type, (ir.IntType, ir.PointerType))
|
|
3049
|
+
or self._is_floating_ir_type(ir_type)
|
|
3050
|
+
)
|
|
3051
|
+
|
|
3052
|
+
def _is_aggregate_ir_type(self, ir_type):
|
|
3053
|
+
return _is_struct_ir_type(ir_type) or getattr(ir_type, "is_union", False)
|
|
3054
|
+
|
|
3055
|
+
def _validate_explicit_cast(self, source_type, target_type):
|
|
3056
|
+
if isinstance(target_type, ir.VoidType):
|
|
3057
|
+
return
|
|
3058
|
+
|
|
3059
|
+
if self._is_aggregate_ir_type(target_type) or isinstance(
|
|
3060
|
+
target_type, ir.ArrayType
|
|
3061
|
+
):
|
|
3062
|
+
raise SemanticError("invalid cast to non-scalar type")
|
|
3063
|
+
|
|
3064
|
+
if self._is_aggregate_ir_type(source_type):
|
|
3065
|
+
raise SemanticError("invalid cast from non-scalar type")
|
|
3066
|
+
|
|
3067
|
+
if isinstance(source_type, ir.ArrayType):
|
|
3068
|
+
if not isinstance(target_type, ir.PointerType):
|
|
3069
|
+
raise SemanticError("invalid cast from array type")
|
|
3070
|
+
return
|
|
3071
|
+
|
|
3072
|
+
if self._is_floating_ir_type(source_type) and isinstance(
|
|
3073
|
+
target_type, ir.PointerType
|
|
3074
|
+
):
|
|
3075
|
+
raise SemanticError("invalid cast from floating type to pointer type")
|
|
3076
|
+
|
|
3077
|
+
if isinstance(source_type, ir.PointerType) and self._is_floating_ir_type(
|
|
3078
|
+
target_type
|
|
3079
|
+
):
|
|
3080
|
+
raise SemanticError("invalid cast from pointer type to floating type")
|
|
3081
|
+
|
|
3082
|
+
if self._is_scalar_ir_type(source_type) and self._is_scalar_ir_type(
|
|
3083
|
+
target_type
|
|
3084
|
+
):
|
|
3085
|
+
return
|
|
3086
|
+
|
|
3087
|
+
raise SemanticError("invalid cast expression")
|
|
3088
|
+
|
|
1997
3089
|
def _extend_call_result(self, result, returns_unsigned=False):
|
|
1998
3090
|
if not isinstance(result.type, ir.IntType):
|
|
1999
3091
|
return result
|
|
@@ -2019,6 +3111,9 @@ class LLVMCodeGenerator(object):
|
|
|
2019
3111
|
|
|
2020
3112
|
def _ir_type_align(self, ir_type):
|
|
2021
3113
|
"""Return natural alignment of an IR type in bytes."""
|
|
3114
|
+
custom_align = getattr(ir_type, "custom_align", None)
|
|
3115
|
+
if custom_align is not None:
|
|
3116
|
+
return custom_align
|
|
2022
3117
|
if isinstance(ir_type, ir.IntType):
|
|
2023
3118
|
return min(ir_type.width // 8, 8)
|
|
2024
3119
|
elif isinstance(ir_type, ir.FloatType):
|
|
@@ -2029,7 +3124,7 @@ class LLVMCodeGenerator(object):
|
|
|
2029
3124
|
return 8
|
|
2030
3125
|
elif isinstance(ir_type, ir.ArrayType):
|
|
2031
3126
|
return self._ir_type_align(ir_type.element)
|
|
2032
|
-
elif
|
|
3127
|
+
elif _is_struct_ir_type(ir_type):
|
|
2033
3128
|
if not ir_type.elements:
|
|
2034
3129
|
return 1
|
|
2035
3130
|
return max(self._ir_type_align(e) for e in ir_type.elements)
|
|
@@ -2037,6 +3132,9 @@ class LLVMCodeGenerator(object):
|
|
|
2037
3132
|
|
|
2038
3133
|
def _ir_type_size(self, ir_type):
|
|
2039
3134
|
"""Compute byte size of an IR type with proper alignment/padding."""
|
|
3135
|
+
custom_size = getattr(ir_type, "custom_size", None)
|
|
3136
|
+
if custom_size is not None:
|
|
3137
|
+
return custom_size
|
|
2040
3138
|
if isinstance(ir_type, ir.IntType):
|
|
2041
3139
|
return ir_type.width // 8
|
|
2042
3140
|
elif isinstance(ir_type, ir.FloatType):
|
|
@@ -2047,7 +3145,7 @@ class LLVMCodeGenerator(object):
|
|
|
2047
3145
|
return 8
|
|
2048
3146
|
elif isinstance(ir_type, ir.ArrayType):
|
|
2049
3147
|
return int(ir_type.count) * self._ir_type_size(ir_type.element)
|
|
2050
|
-
elif
|
|
3148
|
+
elif _is_struct_ir_type(ir_type):
|
|
2051
3149
|
offset = 0
|
|
2052
3150
|
for elem in ir_type.elements:
|
|
2053
3151
|
align = self._ir_type_align(elem)
|
|
@@ -2059,6 +3157,232 @@ class LLVMCodeGenerator(object):
|
|
|
2059
3157
|
return offset
|
|
2060
3158
|
return 8
|
|
2061
3159
|
|
|
3160
|
+
@staticmethod
|
|
3161
|
+
def _align_up(value, align):
|
|
3162
|
+
if align <= 1:
|
|
3163
|
+
return value
|
|
3164
|
+
return (value + align - 1) & ~(align - 1)
|
|
3165
|
+
|
|
3166
|
+
def _resolve_struct_member_ir_type(self, decl):
|
|
3167
|
+
if isinstance(decl.type, c_ast.TypeDecl) and isinstance(
|
|
3168
|
+
decl.type.type, c_ast.Struct
|
|
3169
|
+
):
|
|
3170
|
+
return self.codegen_Struct(decl.type.type)
|
|
3171
|
+
if isinstance(decl.type, c_ast.TypeDecl) and isinstance(
|
|
3172
|
+
decl.type.type, c_ast.Union
|
|
3173
|
+
):
|
|
3174
|
+
return self.codegen_Union(decl.type.type)
|
|
3175
|
+
if isinstance(decl.type, c_ast.ArrayDecl):
|
|
3176
|
+
def _build_array_type(arr_node):
|
|
3177
|
+
dim = self._eval_dim(arr_node.dim) if arr_node.dim else 0
|
|
3178
|
+
if isinstance(arr_node.type, c_ast.ArrayDecl):
|
|
3179
|
+
inner = _build_array_type(arr_node.type)
|
|
3180
|
+
else:
|
|
3181
|
+
inner = self._resolve_ast_type(arr_node.type)
|
|
3182
|
+
return ir.ArrayType(inner, dim)
|
|
3183
|
+
|
|
3184
|
+
return _build_array_type(decl.type)
|
|
3185
|
+
if isinstance(decl.type, c_ast.PtrDecl):
|
|
3186
|
+
return self._resolve_ast_type(decl.type)
|
|
3187
|
+
if isinstance(decl.type, c_ast.TypeDecl):
|
|
3188
|
+
return self._resolve_ast_type(decl.type)
|
|
3189
|
+
return int64_t
|
|
3190
|
+
|
|
3191
|
+
def _bitfield_storage_ir_type(self, decl):
|
|
3192
|
+
storage_ir_type = self._resolve_ast_type(decl.type)
|
|
3193
|
+
if not isinstance(storage_ir_type, ir.IntType):
|
|
3194
|
+
return int32_t
|
|
3195
|
+
return storage_ir_type
|
|
3196
|
+
|
|
3197
|
+
def _raw_layout_struct_type(
|
|
3198
|
+
self, size_bytes, align_bytes, type_name=None, existing_type=None
|
|
3199
|
+
):
|
|
3200
|
+
align_map = {8: int64_t, 4: int32_t, 2: int16_t, 1: int8_t}
|
|
3201
|
+
identified_name = type_name or self._aggregate_type_name("layout")
|
|
3202
|
+
if size_bytes <= 0:
|
|
3203
|
+
body = []
|
|
3204
|
+
elif align_bytes <= 1:
|
|
3205
|
+
body = [ir.ArrayType(int8_t, size_bytes)]
|
|
3206
|
+
else:
|
|
3207
|
+
align_type = align_map.get(align_bytes)
|
|
3208
|
+
if align_type is None or size_bytes < align_bytes:
|
|
3209
|
+
body = [ir.ArrayType(int8_t, size_bytes)]
|
|
3210
|
+
else:
|
|
3211
|
+
pad_size = size_bytes - align_bytes
|
|
3212
|
+
if pad_size > 0:
|
|
3213
|
+
body = [align_type, ir.ArrayType(int8_t, pad_size)]
|
|
3214
|
+
else:
|
|
3215
|
+
body = [align_type]
|
|
3216
|
+
if existing_type is not None:
|
|
3217
|
+
storage_type = existing_type
|
|
3218
|
+
else:
|
|
3219
|
+
storage_type = self.module.context.get_identified_type(identified_name)
|
|
3220
|
+
if storage_type.is_opaque:
|
|
3221
|
+
storage_type.set_body(*body)
|
|
3222
|
+
storage_type.custom_size = size_bytes
|
|
3223
|
+
storage_type.custom_align = align_bytes
|
|
3224
|
+
storage_type.has_custom_layout = True
|
|
3225
|
+
return storage_type
|
|
3226
|
+
|
|
3227
|
+
def _build_layout_backed_struct(self, node):
|
|
3228
|
+
current_bit = 0
|
|
3229
|
+
max_align = 1
|
|
3230
|
+
member_names = []
|
|
3231
|
+
member_decl_types = []
|
|
3232
|
+
field_layouts = {}
|
|
3233
|
+
|
|
3234
|
+
for decl in node.decls:
|
|
3235
|
+
if decl.bitsize is not None:
|
|
3236
|
+
storage_ir_type = self._bitfield_storage_ir_type(decl)
|
|
3237
|
+
storage_bits = storage_ir_type.width
|
|
3238
|
+
bit_width = self._eval_const_expr(decl.bitsize)
|
|
3239
|
+
max_align = max(max_align, self._ir_type_align(storage_ir_type))
|
|
3240
|
+
if bit_width == 0:
|
|
3241
|
+
current_bit = self._align_up(current_bit, storage_bits)
|
|
3242
|
+
continue
|
|
3243
|
+
unit_start = (current_bit // storage_bits) * storage_bits
|
|
3244
|
+
if current_bit + bit_width > unit_start + storage_bits:
|
|
3245
|
+
current_bit = self._align_up(current_bit, storage_bits)
|
|
3246
|
+
unit_start = current_bit
|
|
3247
|
+
layout = StructFieldLayout(
|
|
3248
|
+
name=decl.name,
|
|
3249
|
+
byte_offset=current_bit // 8,
|
|
3250
|
+
semantic_ir_type=storage_ir_type,
|
|
3251
|
+
decl_type=decl.type,
|
|
3252
|
+
is_bitfield=True,
|
|
3253
|
+
storage_byte_offset=unit_start // 8,
|
|
3254
|
+
storage_ir_type=storage_ir_type,
|
|
3255
|
+
bit_offset=current_bit - unit_start,
|
|
3256
|
+
bit_width=bit_width,
|
|
3257
|
+
is_unsigned=self._is_unsigned_scalar_decl_type(decl.type),
|
|
3258
|
+
)
|
|
3259
|
+
if decl.name is not None:
|
|
3260
|
+
field_layouts[decl.name] = layout
|
|
3261
|
+
member_names.append(decl.name)
|
|
3262
|
+
member_decl_types.append(decl.type)
|
|
3263
|
+
current_bit += bit_width
|
|
3264
|
+
continue
|
|
3265
|
+
|
|
3266
|
+
semantic_ir_type = self._resolve_struct_member_ir_type(decl)
|
|
3267
|
+
align_bits = self._ir_type_align(semantic_ir_type) * 8
|
|
3268
|
+
current_bit = self._align_up(current_bit, align_bits)
|
|
3269
|
+
max_align = max(max_align, self._ir_type_align(semantic_ir_type))
|
|
3270
|
+
layout = StructFieldLayout(
|
|
3271
|
+
name=decl.name,
|
|
3272
|
+
byte_offset=current_bit // 8,
|
|
3273
|
+
semantic_ir_type=semantic_ir_type,
|
|
3274
|
+
decl_type=decl.type,
|
|
3275
|
+
)
|
|
3276
|
+
if decl.name is not None:
|
|
3277
|
+
field_layouts[decl.name] = layout
|
|
3278
|
+
member_names.append(decl.name)
|
|
3279
|
+
member_decl_types.append(decl.type)
|
|
3280
|
+
current_bit += self._ir_type_size(semantic_ir_type) * 8
|
|
3281
|
+
|
|
3282
|
+
size_bits = self._align_up(current_bit, max_align * 8)
|
|
3283
|
+
size_bytes = max(1, size_bits // 8)
|
|
3284
|
+
type_name = None
|
|
3285
|
+
existing_type = None
|
|
3286
|
+
if node.name:
|
|
3287
|
+
tag_key = self._tag_type_key(node.name)
|
|
3288
|
+
if tag_key in self.env:
|
|
3289
|
+
existing_type = self.env[tag_key][0]
|
|
3290
|
+
type_name = self._aggregate_type_name("struct", node.name)
|
|
3291
|
+
struct_type = self._raw_layout_struct_type(
|
|
3292
|
+
size_bytes,
|
|
3293
|
+
max_align,
|
|
3294
|
+
type_name,
|
|
3295
|
+
existing_type=existing_type,
|
|
3296
|
+
)
|
|
3297
|
+
struct_type.members = member_names
|
|
3298
|
+
struct_type.member_decl_types = member_decl_types
|
|
3299
|
+
struct_type.field_layouts = field_layouts
|
|
3300
|
+
if node.name:
|
|
3301
|
+
self.define(self._tag_type_key(node.name), (struct_type, None))
|
|
3302
|
+
return struct_type
|
|
3303
|
+
|
|
3304
|
+
def _byte_offset_ptr(self, base_ptr, byte_offset, target_ptr_type, name="fieldptr"):
|
|
3305
|
+
byte_ptr = self.builder.bitcast(base_ptr, voidptr_t, name=f"{name}.base")
|
|
3306
|
+
if byte_offset:
|
|
3307
|
+
byte_ptr = self.builder.gep(
|
|
3308
|
+
byte_ptr,
|
|
3309
|
+
[ir.Constant(ir.IntType(32), byte_offset)],
|
|
3310
|
+
name=f"{name}.offs",
|
|
3311
|
+
)
|
|
3312
|
+
if byte_ptr.type != target_ptr_type:
|
|
3313
|
+
return self.builder.bitcast(byte_ptr, target_ptr_type, name=name)
|
|
3314
|
+
return byte_ptr
|
|
3315
|
+
|
|
3316
|
+
@staticmethod
|
|
3317
|
+
def _bitfield_mask(bit_width):
|
|
3318
|
+
if bit_width <= 0:
|
|
3319
|
+
return 0
|
|
3320
|
+
return (1 << bit_width) - 1
|
|
3321
|
+
|
|
3322
|
+
def _load_bitfield(self, ref):
|
|
3323
|
+
align = max(1, self._ir_type_align(ref.storage_ir_type))
|
|
3324
|
+
raw = self.builder.load(ref.container_ptr, align=align)
|
|
3325
|
+
if ref.bit_offset:
|
|
3326
|
+
raw = self.builder.lshr(
|
|
3327
|
+
raw, ir.Constant(ref.storage_ir_type, ref.bit_offset), "bitshift"
|
|
3328
|
+
)
|
|
3329
|
+
|
|
3330
|
+
semantic_width = ref.semantic_ir_type.width
|
|
3331
|
+
if ref.is_unsigned:
|
|
3332
|
+
if ref.bit_width < ref.storage_ir_type.width:
|
|
3333
|
+
raw = self.builder.and_(
|
|
3334
|
+
raw,
|
|
3335
|
+
ir.Constant(ref.storage_ir_type, self._bitfield_mask(ref.bit_width)),
|
|
3336
|
+
"bitmask",
|
|
3337
|
+
)
|
|
3338
|
+
if raw.type.width > semantic_width:
|
|
3339
|
+
raw = self.builder.trunc(raw, ref.semantic_ir_type, "bittrunc")
|
|
3340
|
+
elif raw.type.width < semantic_width:
|
|
3341
|
+
raw = self.builder.zext(raw, ref.semantic_ir_type, "bitzext")
|
|
3342
|
+
self._tag_unsigned(raw)
|
|
3343
|
+
return raw
|
|
3344
|
+
|
|
3345
|
+
if ref.bit_width < ref.storage_ir_type.width:
|
|
3346
|
+
narrow_type = ir.IntType(ref.bit_width)
|
|
3347
|
+
raw = self.builder.trunc(raw, narrow_type, "bitsigned.trunc")
|
|
3348
|
+
return self.builder.sext(raw, ref.semantic_ir_type, "bitsigned.sext")
|
|
3349
|
+
if raw.type.width > semantic_width:
|
|
3350
|
+
return self.builder.trunc(raw, ref.semantic_ir_type, "bittrunc")
|
|
3351
|
+
if raw.type.width < semantic_width:
|
|
3352
|
+
return self.builder.sext(raw, ref.semantic_ir_type, "bitsext")
|
|
3353
|
+
return raw
|
|
3354
|
+
|
|
3355
|
+
def _store_bitfield(self, value, ref):
|
|
3356
|
+
if value is None:
|
|
3357
|
+
return
|
|
3358
|
+
align = max(1, self._ir_type_align(ref.storage_ir_type))
|
|
3359
|
+
storage_value = self.builder.load(ref.container_ptr, align=align)
|
|
3360
|
+
if value.type != ref.semantic_ir_type:
|
|
3361
|
+
value = self._implicit_convert(value, ref.semantic_ir_type)
|
|
3362
|
+
value = self._convert_int_value(
|
|
3363
|
+
value, ref.storage_ir_type, result_unsigned=ref.is_unsigned
|
|
3364
|
+
)
|
|
3365
|
+
field_mask = self._bitfield_mask(ref.bit_width)
|
|
3366
|
+
field_mask_const = ir.Constant(ref.storage_ir_type, field_mask)
|
|
3367
|
+
if ref.bit_width < ref.storage_ir_type.width:
|
|
3368
|
+
value = self.builder.and_(value, field_mask_const, "bitstore.mask")
|
|
3369
|
+
if ref.bit_offset:
|
|
3370
|
+
value = self.builder.shl(
|
|
3371
|
+
value,
|
|
3372
|
+
ir.Constant(ref.storage_ir_type, ref.bit_offset),
|
|
3373
|
+
"bitstore.shift",
|
|
3374
|
+
)
|
|
3375
|
+
clear_mask = ((1 << ref.storage_ir_type.width) - 1) ^ (
|
|
3376
|
+
field_mask << ref.bit_offset
|
|
3377
|
+
)
|
|
3378
|
+
storage_value = self.builder.and_(
|
|
3379
|
+
storage_value,
|
|
3380
|
+
ir.Constant(ref.storage_ir_type, clear_mask),
|
|
3381
|
+
"bitstore.clear",
|
|
3382
|
+
)
|
|
3383
|
+
value = self.builder.or_(storage_value, value, "bitstore.merge")
|
|
3384
|
+
self.builder.store(value, ref.container_ptr, align=align)
|
|
3385
|
+
|
|
2062
3386
|
def _refine_member_ir_type(self, aggregate_type, member_key, field_type):
|
|
2063
3387
|
"""Prefer semantic member types over storage types when available."""
|
|
2064
3388
|
semantic_field_type = field_type
|
|
@@ -2083,8 +3407,8 @@ class LLVMCodeGenerator(object):
|
|
|
2083
3407
|
resolved, ir.PointerType
|
|
2084
3408
|
):
|
|
2085
3409
|
return semantic_field_type
|
|
2086
|
-
if isinstance(
|
|
2087
|
-
resolved
|
|
3410
|
+
if isinstance(resolved, (ir.ArrayType, ir.PointerType)) or _is_struct_ir_type(
|
|
3411
|
+
resolved
|
|
2088
3412
|
):
|
|
2089
3413
|
return resolved
|
|
2090
3414
|
except Exception:
|
|
@@ -2101,6 +3425,14 @@ class LLVMCodeGenerator(object):
|
|
|
2101
3425
|
)
|
|
2102
3426
|
return 0, semantic_field_type
|
|
2103
3427
|
|
|
3428
|
+
if getattr(aggregate_type, "has_custom_layout", False):
|
|
3429
|
+
layout = aggregate_type.field_layouts.get(field_name)
|
|
3430
|
+
if layout is None:
|
|
3431
|
+
raise CodegenError(f"Field '{field_name}' not found in aggregate")
|
|
3432
|
+
if layout.is_bitfield:
|
|
3433
|
+
raise CodegenError("offsetof on bit-field is not supported")
|
|
3434
|
+
return layout.byte_offset, layout.semantic_ir_type
|
|
3435
|
+
|
|
2104
3436
|
if not hasattr(aggregate_type, "members"):
|
|
2105
3437
|
raise CodegenError(f"Aggregate has no named fields: {aggregate_type}")
|
|
2106
3438
|
|
|
@@ -2145,6 +3477,153 @@ class LLVMCodeGenerator(object):
|
|
|
2145
3477
|
|
|
2146
3478
|
raise CodegenError(f"Not an offsetof base: {type(node).__name__}")
|
|
2147
3479
|
|
|
3480
|
+
def _infer_sizeof_operand_ir_type(self, node):
|
|
3481
|
+
"""Infer the operand type for sizeof without emitting runtime IR."""
|
|
3482
|
+
cached = self._get_expr_ir_type(node)
|
|
3483
|
+
if cached is not None:
|
|
3484
|
+
return cached
|
|
3485
|
+
|
|
3486
|
+
if isinstance(node, c_ast.Constant):
|
|
3487
|
+
if node.type == "int":
|
|
3488
|
+
raw = node.value
|
|
3489
|
+
lower = raw.lower()
|
|
3490
|
+
val_str = raw.rstrip("uUlL")
|
|
3491
|
+
if val_str.startswith("0x") or val_str.startswith("0X"):
|
|
3492
|
+
value = int(val_str, 16)
|
|
3493
|
+
elif val_str.startswith("0") and len(val_str) > 1 and val_str[1:].isdigit():
|
|
3494
|
+
value = int(val_str, 8)
|
|
3495
|
+
else:
|
|
3496
|
+
value = int(val_str)
|
|
3497
|
+
if "l" in lower or value > 0x7FFFFFFF:
|
|
3498
|
+
return int64_t
|
|
3499
|
+
return int32_t
|
|
3500
|
+
if node.type == "char":
|
|
3501
|
+
return int32_t
|
|
3502
|
+
if node.type == "string":
|
|
3503
|
+
raw = node.value[1:-1]
|
|
3504
|
+
processed = self._process_escapes(raw)
|
|
3505
|
+
return ir.ArrayType(int8_t, len(self._string_bytes(processed + "\00")))
|
|
3506
|
+
return self._float_literal_ir_type(node.value)
|
|
3507
|
+
|
|
3508
|
+
if isinstance(node, c_ast.ID):
|
|
3509
|
+
ir_type, _ = self.lookup(node.name)
|
|
3510
|
+
return ir_type
|
|
3511
|
+
|
|
3512
|
+
if isinstance(node, c_ast.StructRef):
|
|
3513
|
+
base_type = self._infer_sizeof_operand_ir_type(node.name)
|
|
3514
|
+
aggregate_type = base_type
|
|
3515
|
+
if node.type == "->":
|
|
3516
|
+
if not isinstance(base_type, ir.PointerType):
|
|
3517
|
+
raise CodegenError(
|
|
3518
|
+
f"sizeof operand is not a pointer for '->': {base_type}"
|
|
3519
|
+
)
|
|
3520
|
+
aggregate_type = base_type.pointee
|
|
3521
|
+
_, field_type = self._get_aggregate_field_info(
|
|
3522
|
+
aggregate_type, node.field.name
|
|
3523
|
+
)
|
|
3524
|
+
return field_type
|
|
3525
|
+
|
|
3526
|
+
if isinstance(node, c_ast.ArrayRef):
|
|
3527
|
+
base_type = self._infer_sizeof_operand_ir_type(node.name)
|
|
3528
|
+
if isinstance(base_type, ir.ArrayType):
|
|
3529
|
+
return base_type.element
|
|
3530
|
+
if isinstance(base_type, ir.PointerType):
|
|
3531
|
+
return base_type.pointee
|
|
3532
|
+
raise CodegenError(
|
|
3533
|
+
f"sizeof operand is not indexable: {type(base_type).__name__}"
|
|
3534
|
+
)
|
|
3535
|
+
|
|
3536
|
+
if isinstance(node, c_ast.Cast):
|
|
3537
|
+
return self._resolve_ast_type(node.to_type.type)
|
|
3538
|
+
|
|
3539
|
+
if isinstance(node, c_ast.UnaryOp):
|
|
3540
|
+
if node.op == "&":
|
|
3541
|
+
return ir.PointerType(self._infer_sizeof_operand_ir_type(node.expr))
|
|
3542
|
+
if node.op == "*":
|
|
3543
|
+
base_type = self._infer_sizeof_operand_ir_type(node.expr)
|
|
3544
|
+
if isinstance(base_type, ir.ArrayType):
|
|
3545
|
+
return base_type.element
|
|
3546
|
+
if not isinstance(base_type, ir.PointerType):
|
|
3547
|
+
raise CodegenError(
|
|
3548
|
+
f"sizeof operand is not a pointer for '*': {base_type}"
|
|
3549
|
+
)
|
|
3550
|
+
return base_type.pointee
|
|
3551
|
+
if node.op in ("+", "-", "~"):
|
|
3552
|
+
base_type = self._infer_sizeof_operand_ir_type(node.expr)
|
|
3553
|
+
if isinstance(base_type, ir.IntType):
|
|
3554
|
+
return self._integer_promotion_ir_type(base_type)
|
|
3555
|
+
return base_type
|
|
3556
|
+
if node.op == "!":
|
|
3557
|
+
return int32_t
|
|
3558
|
+
if node.op in ("p++", "p--", "++", "--"):
|
|
3559
|
+
return self._infer_sizeof_operand_ir_type(node.expr)
|
|
3560
|
+
if node.op == "sizeof":
|
|
3561
|
+
return int64_t
|
|
3562
|
+
|
|
3563
|
+
if isinstance(node, c_ast.BinaryOp):
|
|
3564
|
+
lhs_type = self._decay_ir_type(
|
|
3565
|
+
self._infer_sizeof_operand_ir_type(node.left)
|
|
3566
|
+
)
|
|
3567
|
+
rhs_type = self._decay_ir_type(
|
|
3568
|
+
self._infer_sizeof_operand_ir_type(node.right)
|
|
3569
|
+
)
|
|
3570
|
+
|
|
3571
|
+
if node.op in ("&&", "||", "==", "!=", "<", "<=", ">", ">="):
|
|
3572
|
+
return int32_t
|
|
3573
|
+
|
|
3574
|
+
if (
|
|
3575
|
+
node.op in ("+", "-")
|
|
3576
|
+
and isinstance(lhs_type, ir.PointerType)
|
|
3577
|
+
and isinstance(rhs_type, ir.IntType)
|
|
3578
|
+
):
|
|
3579
|
+
return lhs_type
|
|
3580
|
+
if (
|
|
3581
|
+
node.op == "+"
|
|
3582
|
+
and isinstance(rhs_type, ir.PointerType)
|
|
3583
|
+
and isinstance(lhs_type, ir.IntType)
|
|
3584
|
+
):
|
|
3585
|
+
return rhs_type
|
|
3586
|
+
if (
|
|
3587
|
+
node.op == "-"
|
|
3588
|
+
and isinstance(lhs_type, ir.PointerType)
|
|
3589
|
+
and isinstance(rhs_type, ir.PointerType)
|
|
3590
|
+
):
|
|
3591
|
+
return int64_t
|
|
3592
|
+
|
|
3593
|
+
if node.op in ("<<", ">>") and isinstance(lhs_type, ir.IntType):
|
|
3594
|
+
return self._integer_promotion_ir_type(lhs_type)
|
|
3595
|
+
|
|
3596
|
+
return self._usual_arithmetic_conversion_ir_type(lhs_type, rhs_type)
|
|
3597
|
+
|
|
3598
|
+
if isinstance(node, c_ast.TernaryOp):
|
|
3599
|
+
true_type = self._infer_sizeof_operand_ir_type(node.iftrue)
|
|
3600
|
+
false_type = self._infer_sizeof_operand_ir_type(node.iffalse)
|
|
3601
|
+
if true_type == false_type:
|
|
3602
|
+
return true_type
|
|
3603
|
+
if (
|
|
3604
|
+
isinstance(true_type, (ir.IntType, ir.FloatType, ir.DoubleType))
|
|
3605
|
+
and isinstance(false_type, (ir.IntType, ir.FloatType, ir.DoubleType))
|
|
3606
|
+
):
|
|
3607
|
+
return self._usual_arithmetic_conversion_ir_type(
|
|
3608
|
+
true_type, false_type
|
|
3609
|
+
)
|
|
3610
|
+
if isinstance(true_type, ir.PointerType) and isinstance(
|
|
3611
|
+
false_type, ir.PointerType
|
|
3612
|
+
):
|
|
3613
|
+
return true_type
|
|
3614
|
+
return true_type
|
|
3615
|
+
|
|
3616
|
+
if isinstance(node, c_ast.ExprList) and node.exprs:
|
|
3617
|
+
return self._infer_sizeof_operand_ir_type(node.exprs[-1])
|
|
3618
|
+
|
|
3619
|
+
if isinstance(node, c_ast.FuncCall):
|
|
3620
|
+
if isinstance(node.name, c_ast.ID):
|
|
3621
|
+
ret_type = getattr(self, "func_return_types", {}).get(node.name.name)
|
|
3622
|
+
if ret_type is not None:
|
|
3623
|
+
return ret_type
|
|
3624
|
+
|
|
3625
|
+
raise CodegenError(f"Cannot infer sizeof operand type: {type(node).__name__}")
|
|
3626
|
+
|
|
2148
3627
|
def codegen_Typename(self, node):
|
|
2149
3628
|
# Used inside sizeof(type) — not directly code-generated
|
|
2150
3629
|
return None, None
|
|
@@ -2160,6 +3639,8 @@ class LLVMCodeGenerator(object):
|
|
|
2160
3639
|
rhs, _ = self.codegen(node.right)
|
|
2161
3640
|
if lhs is None or rhs is None:
|
|
2162
3641
|
return ir.Constant(int64_t, 0), None
|
|
3642
|
+
lhs = self._decay_array_expr_to_pointer(node.left, lhs, "lhsarraydecay")
|
|
3643
|
+
rhs = self._decay_array_expr_to_pointer(node.right, rhs, "rhsarraydecay")
|
|
2163
3644
|
|
|
2164
3645
|
# Pointer arithmetic: ptr + int or ptr - int
|
|
2165
3646
|
if (
|
|
@@ -2299,7 +3780,10 @@ class LLVMCodeGenerator(object):
|
|
|
2299
3780
|
self._tag_unsigned(result)
|
|
2300
3781
|
return result, None
|
|
2301
3782
|
elif node.op == "^":
|
|
2302
|
-
|
|
3783
|
+
result = self.builder.xor(lhs, rhs, "xortmp")
|
|
3784
|
+
if is_unsigned:
|
|
3785
|
+
self._tag_unsigned(result)
|
|
3786
|
+
return result, None
|
|
2303
3787
|
elif node.op == "<<":
|
|
2304
3788
|
result = self.builder.shl(lhs, rhs, "shltmp")
|
|
2305
3789
|
if is_unsigned:
|
|
@@ -2307,7 +3791,9 @@ class LLVMCodeGenerator(object):
|
|
|
2307
3791
|
return result, None
|
|
2308
3792
|
elif node.op == ">>":
|
|
2309
3793
|
if is_unsigned:
|
|
2310
|
-
|
|
3794
|
+
result = self.builder.lshr(lhs, rhs, "shrtmp")
|
|
3795
|
+
self._tag_unsigned(result)
|
|
3796
|
+
return result, None
|
|
2311
3797
|
return self.builder.ashr(lhs, rhs, "shrtmp"), None
|
|
2312
3798
|
else:
|
|
2313
3799
|
func = self.module.globals.get("binary{0}".format(node.op))
|
|
@@ -2407,8 +3893,7 @@ class LLVMCodeGenerator(object):
|
|
|
2407
3893
|
|
|
2408
3894
|
# append by name nor just add it
|
|
2409
3895
|
after_loop_label = self.new_label("afterloop")
|
|
2410
|
-
after_bb =
|
|
2411
|
-
# self.builder.function.append_basic_block('afterloop')
|
|
3896
|
+
after_bb = self.builder.function.append_basic_block(after_loop_label)
|
|
2412
3897
|
|
|
2413
3898
|
self.builder.branch(test_bb)
|
|
2414
3899
|
self.builder.position_at_end(test_bb)
|
|
@@ -2432,9 +3917,6 @@ class LLVMCodeGenerator(object):
|
|
|
2432
3917
|
if node.next is not None:
|
|
2433
3918
|
self.codegen(node.next)
|
|
2434
3919
|
self.builder.branch(test_bb)
|
|
2435
|
-
# this append_basic_blook change the label
|
|
2436
|
-
# after_bb = self.builder.function.append_basic_block(after_loop_label)
|
|
2437
|
-
self.builder.function.basic_blocks.append(after_bb)
|
|
2438
3920
|
self.builder.position_at_end(after_bb)
|
|
2439
3921
|
|
|
2440
3922
|
return ir.values.Constant(ir.DoubleType(), 0.0), None
|
|
@@ -2472,11 +3954,17 @@ class LLVMCodeGenerator(object):
|
|
|
2472
3954
|
return ir.values.Constant(ir.DoubleType(), 0.0)
|
|
2473
3955
|
|
|
2474
3956
|
def codegen_Break(self, node):
|
|
2475
|
-
self.
|
|
3957
|
+
target = self.lookup("break")
|
|
3958
|
+
if isinstance(target, tuple):
|
|
3959
|
+
target = target[1]
|
|
3960
|
+
self.builder.branch(target)
|
|
2476
3961
|
return None, None
|
|
2477
3962
|
|
|
2478
3963
|
def codegen_Continue(self, node):
|
|
2479
|
-
self.
|
|
3964
|
+
target = self.lookup("continue")
|
|
3965
|
+
if isinstance(target, tuple):
|
|
3966
|
+
target = target[1]
|
|
3967
|
+
self.builder.branch(target)
|
|
2480
3968
|
return None, None
|
|
2481
3969
|
|
|
2482
3970
|
def codegen_DoWhile(self, node):
|
|
@@ -2514,8 +4002,8 @@ class LLVMCodeGenerator(object):
|
|
|
2514
4002
|
cond_val = self.builder.ptrtoint(cond_val, int64_t)
|
|
2515
4003
|
elif self._is_floating_ir_type(cond_val.type):
|
|
2516
4004
|
cond_val = self.builder.fptosi(cond_val, int64_t)
|
|
2517
|
-
elif isinstance(cond_val.type, ir.IntType) and cond_val.type.width
|
|
2518
|
-
cond_val = self.
|
|
4005
|
+
elif isinstance(cond_val.type, ir.IntType) and cond_val.type.width < int32_t.width:
|
|
4006
|
+
cond_val = self._integer_promotion(cond_val)
|
|
2519
4007
|
|
|
2520
4008
|
after_bb = self.builder.function.append_basic_block("switch_end")
|
|
2521
4009
|
|
|
@@ -2528,11 +4016,57 @@ class LLVMCodeGenerator(object):
|
|
|
2528
4016
|
switch_items = [node.stmt]
|
|
2529
4017
|
else:
|
|
2530
4018
|
switch_items = []
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
4019
|
+
prelabel_items = []
|
|
4020
|
+
hoisted_items = []
|
|
4021
|
+
labels = []
|
|
4022
|
+
label_bodies = {}
|
|
4023
|
+
|
|
4024
|
+
def contains_switch_label(item):
|
|
4025
|
+
if isinstance(item, (c_ast.Case, c_ast.Default)):
|
|
4026
|
+
return True
|
|
4027
|
+
if isinstance(item, c_ast.Compound):
|
|
4028
|
+
return any(
|
|
4029
|
+
contains_switch_label(child) for child in (item.block_items or [])
|
|
4030
|
+
)
|
|
4031
|
+
return False
|
|
4032
|
+
|
|
4033
|
+
def add_label(item):
|
|
4034
|
+
labels.append(item)
|
|
4035
|
+
label_bodies.setdefault(id(item), [])
|
|
4036
|
+
|
|
4037
|
+
def process_items(items, active_label):
|
|
4038
|
+
active = active_label
|
|
4039
|
+
items = list(items or [])
|
|
4040
|
+
for idx, item in enumerate(items):
|
|
4041
|
+
later_has_label = any(
|
|
4042
|
+
contains_switch_label(later) for later in items[idx + 1 :]
|
|
4043
|
+
)
|
|
4044
|
+
if isinstance(item, (c_ast.Case, c_ast.Default)):
|
|
4045
|
+
add_label(item)
|
|
4046
|
+
active = process_items(item.stmts or [], item)
|
|
4047
|
+
continue
|
|
4048
|
+
if isinstance(item, c_ast.Compound) and contains_switch_label(item):
|
|
4049
|
+
active = process_items(item.block_items or [], active)
|
|
4050
|
+
continue
|
|
4051
|
+
if active is None:
|
|
4052
|
+
prelabel_items.append(item)
|
|
4053
|
+
continue
|
|
4054
|
+
if isinstance(item, c_ast.Decl) and later_has_label:
|
|
4055
|
+
if item.init is not None:
|
|
4056
|
+
raise CodegenError(
|
|
4057
|
+
"switch-scope declaration before later case with initializer is not supported"
|
|
4058
|
+
)
|
|
4059
|
+
hoisted_items.append(item)
|
|
4060
|
+
continue
|
|
4061
|
+
if later_has_label and isinstance(
|
|
4062
|
+
item, (c_ast.Typedef, c_ast.EmptyStatement)
|
|
4063
|
+
):
|
|
4064
|
+
hoisted_items.append(item)
|
|
4065
|
+
continue
|
|
4066
|
+
label_bodies[id(active)].append(item)
|
|
4067
|
+
return active
|
|
4068
|
+
|
|
4069
|
+
process_items(switch_items, None)
|
|
2536
4070
|
|
|
2537
4071
|
label_blocks = {}
|
|
2538
4072
|
default_bb = after_bb
|
|
@@ -2545,11 +4079,21 @@ class LLVMCodeGenerator(object):
|
|
|
2545
4079
|
if isinstance(item, c_ast.Default):
|
|
2546
4080
|
default_bb = bb
|
|
2547
4081
|
|
|
2548
|
-
switch_inst = self.builder.switch(cond_val, default_bb)
|
|
2549
|
-
|
|
2550
4082
|
with self.new_scope():
|
|
2551
4083
|
self.define("break", after_bb)
|
|
2552
4084
|
|
|
4085
|
+
for item in prelabel_items + hoisted_items:
|
|
4086
|
+
if isinstance(item, c_ast.Decl):
|
|
4087
|
+
if item.init is not None:
|
|
4088
|
+
raise CodegenError(
|
|
4089
|
+
"switch-scope declaration before first case with initializer is not supported"
|
|
4090
|
+
)
|
|
4091
|
+
self.codegen(item)
|
|
4092
|
+
elif isinstance(item, (c_ast.Typedef, c_ast.EmptyStatement)):
|
|
4093
|
+
self.codegen(item)
|
|
4094
|
+
|
|
4095
|
+
switch_inst = self.builder.switch(cond_val, default_bb)
|
|
4096
|
+
|
|
2553
4097
|
for item in labels:
|
|
2554
4098
|
if not isinstance(item, c_ast.Case):
|
|
2555
4099
|
continue
|
|
@@ -2570,10 +4114,12 @@ class LLVMCodeGenerator(object):
|
|
|
2570
4114
|
|
|
2571
4115
|
for idx, item in enumerate(labels):
|
|
2572
4116
|
self.builder.position_at_end(label_blocks[id(item)])
|
|
2573
|
-
for stmt in item
|
|
2574
|
-
self.codegen(stmt)
|
|
4117
|
+
for stmt in label_bodies.get(id(item), []):
|
|
2575
4118
|
if self.builder.block.is_terminated:
|
|
2576
|
-
|
|
4119
|
+
if isinstance(stmt, c_ast.Label):
|
|
4120
|
+
self.codegen(stmt)
|
|
4121
|
+
continue
|
|
4122
|
+
self.codegen(stmt)
|
|
2577
4123
|
if not self.builder.block.is_terminated:
|
|
2578
4124
|
next_bb = after_bb
|
|
2579
4125
|
if idx + 1 < len(labels):
|
|
@@ -2595,7 +4141,10 @@ class LLVMCodeGenerator(object):
|
|
|
2595
4141
|
self.builder.cbranch(cmp, then_bb, else_bb)
|
|
2596
4142
|
|
|
2597
4143
|
self.builder.position_at_end(then_bb)
|
|
2598
|
-
|
|
4144
|
+
if node.iftrue is None:
|
|
4145
|
+
true_val = cond_val
|
|
4146
|
+
else:
|
|
4147
|
+
true_val, _ = self.codegen(node.iftrue)
|
|
2599
4148
|
true_bb_end = self.builder.block
|
|
2600
4149
|
|
|
2601
4150
|
self.builder.position_at_end(else_bb)
|
|
@@ -2603,11 +4152,7 @@ class LLVMCodeGenerator(object):
|
|
|
2603
4152
|
false_bb_end = self.builder.block
|
|
2604
4153
|
|
|
2605
4154
|
def zero_value(target_type):
|
|
2606
|
-
|
|
2607
|
-
return ir.Constant(target_type, None)
|
|
2608
|
-
if self._is_floating_ir_type(target_type):
|
|
2609
|
-
return ir.Constant(target_type, 0.0)
|
|
2610
|
-
return ir.Constant(target_type, 0)
|
|
4155
|
+
return self._zero_initializer(target_type)
|
|
2611
4156
|
|
|
2612
4157
|
def pick_target_type(lhs, rhs):
|
|
2613
4158
|
if lhs is None and rhs is None:
|
|
@@ -2666,19 +4211,48 @@ class LLVMCodeGenerator(object):
|
|
|
2666
4211
|
self.builder.position_at_end(merge_bb)
|
|
2667
4212
|
if not incoming:
|
|
2668
4213
|
return zero_value(target), None
|
|
4214
|
+
result_is_unsigned = isinstance(target, ir.IntType) and any(
|
|
4215
|
+
self._is_unsigned_val(value) for _pred, value in incoming
|
|
4216
|
+
)
|
|
4217
|
+
result_has_unsigned_pointee = isinstance(target, ir.PointerType) and any(
|
|
4218
|
+
self._is_unsigned_pointee(value) for _pred, value in incoming
|
|
4219
|
+
)
|
|
4220
|
+
result_has_unsigned_return = isinstance(target, ir.PointerType) and any(
|
|
4221
|
+
self._is_unsigned_return(value) for _pred, value in incoming
|
|
4222
|
+
)
|
|
2669
4223
|
if len(incoming) == 1:
|
|
2670
|
-
|
|
4224
|
+
result = incoming[0][1]
|
|
4225
|
+
if result_is_unsigned:
|
|
4226
|
+
self._tag_unsigned(result)
|
|
4227
|
+
if result_has_unsigned_pointee:
|
|
4228
|
+
self._tag_unsigned_pointee(result)
|
|
4229
|
+
if result_has_unsigned_return:
|
|
4230
|
+
self._tag_unsigned_return(result)
|
|
4231
|
+
return result, None
|
|
2671
4232
|
|
|
2672
4233
|
phi = self.builder.phi(target, "ternary")
|
|
2673
4234
|
for pred, value in incoming:
|
|
2674
4235
|
phi.add_incoming(value, pred)
|
|
4236
|
+
if result_is_unsigned:
|
|
4237
|
+
self._tag_unsigned(phi)
|
|
4238
|
+
if result_has_unsigned_pointee:
|
|
4239
|
+
self._tag_unsigned_pointee(phi)
|
|
4240
|
+
if result_has_unsigned_return:
|
|
4241
|
+
self._tag_unsigned_return(phi)
|
|
2675
4242
|
return phi, None
|
|
2676
4243
|
|
|
2677
4244
|
def codegen_Cast(self, node):
|
|
4245
|
+
dest_ir_type = self._resolve_ast_type(node.to_type.type)
|
|
4246
|
+
if isinstance(node.expr, c_ast.InitList) and (
|
|
4247
|
+
isinstance(dest_ir_type, ir.ArrayType)
|
|
4248
|
+
or _is_struct_ir_type(dest_ir_type)
|
|
4249
|
+
or getattr(dest_ir_type, "is_union", False)
|
|
4250
|
+
):
|
|
4251
|
+
return self._materialize_compound_literal(node.to_type.type, node.expr)
|
|
2678
4252
|
|
|
2679
4253
|
expr, ptr = self.codegen(node.expr)
|
|
2680
4254
|
|
|
2681
|
-
|
|
4255
|
+
self._validate_explicit_cast(expr.type, dest_ir_type)
|
|
2682
4256
|
# Check if casting to unsigned type
|
|
2683
4257
|
is_unsigned = False
|
|
2684
4258
|
if isinstance(node.to_type.type, c_ast.TypeDecl) and isinstance(
|
|
@@ -2727,6 +4301,9 @@ class LLVMCodeGenerator(object):
|
|
|
2727
4301
|
self._tag_value_from_decl_type(result, node.to_type.type)
|
|
2728
4302
|
return result, None
|
|
2729
4303
|
|
|
4304
|
+
def codegen_CompoundLiteral(self, node):
|
|
4305
|
+
return self._materialize_compound_literal(node.type.type, node.init)
|
|
4306
|
+
|
|
2730
4307
|
def codegen_FuncCall(self, node):
|
|
2731
4308
|
|
|
2732
4309
|
callee = None
|
|
@@ -2738,13 +4315,111 @@ class LLVMCodeGenerator(object):
|
|
|
2738
4315
|
return self._codegen_builtin_va_end(node)
|
|
2739
4316
|
if callee == "__builtin_va_copy":
|
|
2740
4317
|
return self._codegen_builtin_va_copy(node)
|
|
4318
|
+
if callee == "__builtin_alloca":
|
|
4319
|
+
return self._codegen_builtin_alloca(node)
|
|
2741
4320
|
if callee == "__builtin_va_arg":
|
|
2742
4321
|
return ir.Constant(voidptr_t, None), None
|
|
4322
|
+
if callee == "__builtin_expect":
|
|
4323
|
+
return self._codegen_builtin_expect(node)
|
|
4324
|
+
if callee == "__builtin_assume":
|
|
4325
|
+
return ir.Constant(int64_t, 0), None
|
|
4326
|
+
if callee == "__builtin_prefetch":
|
|
4327
|
+
return ir.Constant(int64_t, 0), None
|
|
4328
|
+
if callee == "__builtin_unreachable":
|
|
4329
|
+
return self._codegen_builtin_unreachable(node)
|
|
4330
|
+
if callee == "__builtin_add_overflow":
|
|
4331
|
+
return self._codegen_builtin_overflow(node, "add")
|
|
4332
|
+
if callee == "__builtin_sub_overflow":
|
|
4333
|
+
return self._codegen_builtin_overflow(node, "sub")
|
|
4334
|
+
if callee == "__builtin_mul_overflow":
|
|
4335
|
+
return self._codegen_builtin_overflow(node, "mul")
|
|
4336
|
+
if callee == "__builtin_bswap16":
|
|
4337
|
+
return self._codegen_builtin_bswap(node, 16)
|
|
4338
|
+
if callee == "__builtin_bswap32":
|
|
4339
|
+
return self._codegen_builtin_bswap(node, 32)
|
|
4340
|
+
if callee == "__builtin_bswap64":
|
|
4341
|
+
return self._codegen_builtin_bswap(node, 64)
|
|
4342
|
+
if callee == "__builtin_rotateleft32":
|
|
4343
|
+
return self._codegen_builtin_rotate(node, 32, "left")
|
|
4344
|
+
if callee == "__builtin_rotateleft64":
|
|
4345
|
+
return self._codegen_builtin_rotate(node, 64, "left")
|
|
4346
|
+
if callee == "__builtin_rotateright32":
|
|
4347
|
+
return self._codegen_builtin_rotate(node, 32, "right")
|
|
4348
|
+
if callee == "__builtin_rotateright64":
|
|
4349
|
+
return self._codegen_builtin_rotate(node, 64, "right")
|
|
4350
|
+
if callee == "__builtin_clz":
|
|
4351
|
+
return self._codegen_builtin_bitcount(node, 32, "ctlz")
|
|
4352
|
+
if callee == "__builtin_clzll":
|
|
4353
|
+
return self._codegen_builtin_bitcount(node, 64, "ctlz")
|
|
4354
|
+
if callee == "__builtin_ctz":
|
|
4355
|
+
return self._codegen_builtin_bitcount(node, 32, "cttz")
|
|
4356
|
+
if callee == "__builtin_ctzll":
|
|
4357
|
+
return self._codegen_builtin_bitcount(node, 64, "cttz")
|
|
4358
|
+
if callee == "__builtin_ffs":
|
|
4359
|
+
return self._codegen_builtin_ffs(node, 32)
|
|
4360
|
+
if callee == "__builtin_ffsll":
|
|
4361
|
+
return self._codegen_builtin_ffs(node, 64)
|
|
4362
|
+
if callee == "__builtin_frame_address":
|
|
4363
|
+
return self._codegen_builtin_frame_address(node)
|
|
4364
|
+
if callee == "__builtin_memcmp":
|
|
4365
|
+
callee = "memcmp"
|
|
4366
|
+
if callee == "__builtin_memchr":
|
|
4367
|
+
callee = "memchr"
|
|
4368
|
+
if callee == "__builtin_inf":
|
|
4369
|
+
return ir.Constant(_double, float("inf")), None
|
|
4370
|
+
if callee == "__builtin_inff":
|
|
4371
|
+
return ir.Constant(_float, float("inf")), None
|
|
4372
|
+
if callee == "__builtin_infl":
|
|
4373
|
+
return ir.Constant(_double, float("inf")), None
|
|
4374
|
+
if callee == "__builtin_nan":
|
|
4375
|
+
return ir.Constant(_double, float("nan")), None
|
|
4376
|
+
if callee == "__builtin_nanf":
|
|
4377
|
+
return ir.Constant(_float, float("nan")), None
|
|
4378
|
+
if callee == "__builtin_nanl":
|
|
4379
|
+
return ir.Constant(_double, float("nan")), None
|
|
4380
|
+
if callee in ("__builtin_isnan", "__builtin_isnanf", "__builtin_isnanl"):
|
|
4381
|
+
return self._codegen_builtin_isnan(node)
|
|
4382
|
+
if callee in ("__builtin_isfinite", "__builtin_finite"):
|
|
4383
|
+
return self._codegen_builtin_isfinite(node)
|
|
4384
|
+
if callee in ("__builtin_isinf", "__builtin_isinff", "__builtin_isinfl"):
|
|
4385
|
+
return self._codegen_builtin_isinf(node)
|
|
4386
|
+
if callee == "__builtin_signbit":
|
|
4387
|
+
return self._codegen_builtin_signbit(node)
|
|
4388
|
+
if callee == "__builtin_isunordered":
|
|
4389
|
+
return self._codegen_builtin_isunordered(node)
|
|
4390
|
+
if callee == "__builtin_isless":
|
|
4391
|
+
return self._codegen_builtin_ordered_compare(node, "<", "isless")
|
|
4392
|
+
if callee == "__builtin_islessequal":
|
|
4393
|
+
return self._codegen_builtin_ordered_compare(
|
|
4394
|
+
node, "<=", "islessequal"
|
|
4395
|
+
)
|
|
4396
|
+
if callee == "__builtin_isgreater":
|
|
4397
|
+
return self._codegen_builtin_ordered_compare(node, ">", "isgreater")
|
|
4398
|
+
if callee == "__builtin_isgreaterequal":
|
|
4399
|
+
return self._codegen_builtin_ordered_compare(
|
|
4400
|
+
node, ">=", "isgreaterequal"
|
|
4401
|
+
)
|
|
4402
|
+
if callee == "__builtin_islessgreater":
|
|
4403
|
+
return self._codegen_builtin_islessgreater(node)
|
|
4404
|
+
if callee == "__builtin_copysign":
|
|
4405
|
+
return self._codegen_builtin_copysign(node, _double)
|
|
4406
|
+
if callee == "__builtin_copysignf":
|
|
4407
|
+
return self._codegen_builtin_copysign(node, _float)
|
|
4408
|
+
if callee == "__builtin_copysignl":
|
|
4409
|
+
return self._codegen_builtin_copysign(node, _double)
|
|
4410
|
+
if callee == "__sync_synchronize":
|
|
4411
|
+
return self._codegen_builtin_sync_synchronize(node)
|
|
4412
|
+
if callee == "__atomic_load_n":
|
|
4413
|
+
return self._codegen_builtin_atomic_load(node)
|
|
4414
|
+
if callee == "__atomic_store_n":
|
|
4415
|
+
return self._codegen_builtin_atomic_store(node)
|
|
2743
4416
|
else:
|
|
2744
4417
|
# Calling function pointer in struct: s.fn(args)
|
|
2745
4418
|
call_args = []
|
|
4419
|
+
arg_nodes = []
|
|
2746
4420
|
if node.args:
|
|
2747
|
-
|
|
4421
|
+
arg_nodes = list(node.args.exprs)
|
|
4422
|
+
call_args = [self.codegen(arg)[0] for arg in arg_nodes]
|
|
2748
4423
|
fp_val, _ = self.codegen(node.name)
|
|
2749
4424
|
if isinstance(fp_val.type, ir.PointerType) and isinstance(
|
|
2750
4425
|
fp_val.type.pointee, ir.FunctionType
|
|
@@ -2753,10 +4428,15 @@ class LLVMCodeGenerator(object):
|
|
|
2753
4428
|
ftype = fp_val.type.pointee
|
|
2754
4429
|
coerced = []
|
|
2755
4430
|
for j, a in enumerate(call_args):
|
|
4431
|
+
arg_node = arg_nodes[j] if j < len(arg_nodes) else None
|
|
2756
4432
|
if j < len(ftype.args):
|
|
2757
|
-
coerced.append(
|
|
4433
|
+
coerced.append(
|
|
4434
|
+
self._coerce_arg(a, ftype.args[j], arg_node=arg_node)
|
|
4435
|
+
)
|
|
2758
4436
|
else:
|
|
2759
|
-
coerced.append(
|
|
4437
|
+
coerced.append(
|
|
4438
|
+
self._default_arg_promotion(a, arg_node=arg_node)
|
|
4439
|
+
)
|
|
2760
4440
|
call_args = coerced
|
|
2761
4441
|
ret_type = ftype.return_type
|
|
2762
4442
|
if isinstance(ret_type, ir.VoidType):
|
|
@@ -2775,8 +4455,10 @@ class LLVMCodeGenerator(object):
|
|
|
2775
4455
|
_, callee_func = self.lookup(callee)
|
|
2776
4456
|
|
|
2777
4457
|
call_args = []
|
|
4458
|
+
arg_nodes = []
|
|
2778
4459
|
if node.args:
|
|
2779
|
-
|
|
4460
|
+
arg_nodes = list(node.args.exprs)
|
|
4461
|
+
call_args = [self.codegen(arg)[0] for arg in arg_nodes]
|
|
2780
4462
|
|
|
2781
4463
|
# Function pointer: load the pointer and call through it
|
|
2782
4464
|
if not isinstance(callee_func, ir.Function):
|
|
@@ -2794,7 +4476,16 @@ class LLVMCodeGenerator(object):
|
|
|
2794
4476
|
):
|
|
2795
4477
|
ftype = func_val.type.pointee
|
|
2796
4478
|
coerced = [
|
|
2797
|
-
self._coerce_arg(
|
|
4479
|
+
self._coerce_arg(
|
|
4480
|
+
a,
|
|
4481
|
+
ftype.args[j],
|
|
4482
|
+
arg_node=arg_nodes[j] if j < len(arg_nodes) else None,
|
|
4483
|
+
)
|
|
4484
|
+
if j < len(ftype.args)
|
|
4485
|
+
else self._default_arg_promotion(
|
|
4486
|
+
a,
|
|
4487
|
+
arg_node=arg_nodes[j] if j < len(arg_nodes) else None,
|
|
4488
|
+
)
|
|
2798
4489
|
for j, a in enumerate(call_args)
|
|
2799
4490
|
]
|
|
2800
4491
|
ret_type = ftype.return_type
|
|
@@ -2815,7 +4506,9 @@ class LLVMCodeGenerator(object):
|
|
|
2815
4506
|
return ir.Constant(int64_t, 0), None
|
|
2816
4507
|
|
|
2817
4508
|
# Convert arguments to match function parameter types
|
|
2818
|
-
converted = self._convert_call_args(
|
|
4509
|
+
converted = self._convert_call_args(
|
|
4510
|
+
call_args, callee_func, arg_nodes=arg_nodes
|
|
4511
|
+
)
|
|
2819
4512
|
|
|
2820
4513
|
# Call and handle return type
|
|
2821
4514
|
try:
|
|
@@ -2845,11 +4538,18 @@ class LLVMCodeGenerator(object):
|
|
|
2845
4538
|
return existing
|
|
2846
4539
|
return ir.Function(self.module, ir.FunctionType(ret_type, arg_types), name=name)
|
|
2847
4540
|
|
|
4541
|
+
def _builtin_va_list_storage(self, expr):
|
|
4542
|
+
value, addr = self.codegen(expr)
|
|
4543
|
+
storage = addr if addr is not None else value
|
|
4544
|
+
if not isinstance(getattr(storage, "type", None), ir.PointerType):
|
|
4545
|
+
return None
|
|
4546
|
+
return storage
|
|
4547
|
+
|
|
2848
4548
|
def _codegen_builtin_va_start(self, node):
|
|
2849
4549
|
if not node.args or not node.args.exprs:
|
|
2850
4550
|
return ir.Constant(int64_t, 0), None
|
|
2851
|
-
ap_addr
|
|
2852
|
-
if
|
|
4551
|
+
ap_addr = self._builtin_va_list_storage(node.args.exprs[0])
|
|
4552
|
+
if ap_addr is None:
|
|
2853
4553
|
return ir.Constant(int64_t, 0), None
|
|
2854
4554
|
intrinsic = self._get_or_declare_intrinsic(
|
|
2855
4555
|
"llvm.va_start", ir.VoidType(), [voidptr_t]
|
|
@@ -2863,8 +4563,8 @@ class LLVMCodeGenerator(object):
|
|
|
2863
4563
|
def _codegen_builtin_va_end(self, node):
|
|
2864
4564
|
if not node.args or not node.args.exprs:
|
|
2865
4565
|
return ir.Constant(int64_t, 0), None
|
|
2866
|
-
ap_addr
|
|
2867
|
-
if
|
|
4566
|
+
ap_addr = self._builtin_va_list_storage(node.args.exprs[0])
|
|
4567
|
+
if ap_addr is None:
|
|
2868
4568
|
return ir.Constant(int64_t, 0), None
|
|
2869
4569
|
intrinsic = self._get_or_declare_intrinsic(
|
|
2870
4570
|
"llvm.va_end", ir.VoidType(), [voidptr_t]
|
|
@@ -2878,11 +4578,11 @@ class LLVMCodeGenerator(object):
|
|
|
2878
4578
|
def _codegen_builtin_va_copy(self, node):
|
|
2879
4579
|
if not node.args or len(node.args.exprs) < 2:
|
|
2880
4580
|
return ir.Constant(int64_t, 0), None
|
|
2881
|
-
dst_addr
|
|
2882
|
-
src_addr
|
|
2883
|
-
if
|
|
4581
|
+
dst_addr = self._builtin_va_list_storage(node.args.exprs[0])
|
|
4582
|
+
src_addr = self._builtin_va_list_storage(node.args.exprs[1])
|
|
4583
|
+
if dst_addr is None:
|
|
2884
4584
|
return ir.Constant(int64_t, 0), None
|
|
2885
|
-
if
|
|
4585
|
+
if src_addr is None:
|
|
2886
4586
|
return ir.Constant(int64_t, 0), None
|
|
2887
4587
|
src_val = self._safe_load(src_addr)
|
|
2888
4588
|
dst_pointee = dst_addr.type.pointee
|
|
@@ -2891,24 +4591,429 @@ class LLVMCodeGenerator(object):
|
|
|
2891
4591
|
self._safe_store(src_val, dst_addr)
|
|
2892
4592
|
return ir.Constant(int64_t, 0), None
|
|
2893
4593
|
|
|
2894
|
-
def
|
|
4594
|
+
def _codegen_builtin_expect(self, node):
|
|
4595
|
+
if not node.args or not node.args.exprs:
|
|
4596
|
+
return ir.Constant(int64_t, 0), None
|
|
4597
|
+
value, _ = self.codegen(node.args.exprs[0])
|
|
4598
|
+
return value, None
|
|
4599
|
+
|
|
4600
|
+
def _codegen_builtin_unreachable(self, node):
|
|
4601
|
+
if self.builder is not None and not self.builder.block.is_terminated:
|
|
4602
|
+
self.builder.unreachable()
|
|
4603
|
+
dead_bb = self.function.append_basic_block(name="after_unreachable")
|
|
4604
|
+
self.builder.position_at_end(dead_bb)
|
|
4605
|
+
return ir.Constant(int64_t, 0), None
|
|
4606
|
+
|
|
4607
|
+
def _codegen_builtin_alloca(self, node):
|
|
4608
|
+
if not node.args or not node.args.exprs:
|
|
4609
|
+
return ir.Constant(voidptr_t, None), None
|
|
4610
|
+
|
|
4611
|
+
size_val, _ = self.codegen(node.args.exprs[0])
|
|
4612
|
+
if not isinstance(getattr(size_val, "type", None), ir.IntType):
|
|
4613
|
+
size_val = self._implicit_convert(size_val, int64_t)
|
|
4614
|
+
|
|
4615
|
+
return self.builder.alloca(int8_t, size=size_val, name="builtinalloca"), None
|
|
4616
|
+
|
|
4617
|
+
def _codegen_builtin_frame_address(self, node):
|
|
4618
|
+
if not node.args or not node.args.exprs:
|
|
4619
|
+
return ir.Constant(voidptr_t, None), None
|
|
4620
|
+
try:
|
|
4621
|
+
level = int(self._eval_const_expr(node.args.exprs[0]))
|
|
4622
|
+
except Exception:
|
|
4623
|
+
level = 0
|
|
4624
|
+
if level != 0 or self.builder is None:
|
|
4625
|
+
return ir.Constant(voidptr_t, None), None
|
|
4626
|
+
if self._frame_address_marker is None:
|
|
4627
|
+
self._frame_address_marker = self._alloca_in_entry(
|
|
4628
|
+
int8_t, "__builtin_frame_address"
|
|
4629
|
+
)
|
|
4630
|
+
if self._frame_address_marker.type == voidptr_t:
|
|
4631
|
+
return self._frame_address_marker, None
|
|
4632
|
+
return self.builder.bitcast(
|
|
4633
|
+
self._frame_address_marker, voidptr_t, name="frameaddrcast"
|
|
4634
|
+
), None
|
|
4635
|
+
|
|
4636
|
+
def _codegen_builtin_ffs(self, node, width):
|
|
4637
|
+
if not node.args or not node.args.exprs:
|
|
4638
|
+
return ir.Constant(int32_t, 0), None
|
|
4639
|
+
|
|
4640
|
+
arg, _ = self.codegen(node.args.exprs[0])
|
|
4641
|
+
arg_type = ir.IntType(width)
|
|
4642
|
+
if not isinstance(getattr(arg, "type", None), ir.IntType) or arg.type != arg_type:
|
|
4643
|
+
arg = self._implicit_convert(arg, arg_type)
|
|
4644
|
+
|
|
4645
|
+
zero = ir.Constant(arg_type, 0)
|
|
4646
|
+
is_zero = self.builder.icmp_unsigned("==", arg, zero, name="ffsiszero")
|
|
4647
|
+
intrinsic = self._get_or_declare_intrinsic(
|
|
4648
|
+
f"llvm.cttz.i{width}",
|
|
4649
|
+
arg_type,
|
|
4650
|
+
[arg_type, ir.IntType(1)],
|
|
4651
|
+
)
|
|
4652
|
+
cttz = self.builder.call(
|
|
4653
|
+
intrinsic,
|
|
4654
|
+
[arg, ir.Constant(ir.IntType(1), 0)],
|
|
4655
|
+
name="ffstmp",
|
|
4656
|
+
)
|
|
4657
|
+
if cttz.type != int32_t:
|
|
4658
|
+
cttz = self.builder.trunc(cttz, int32_t, name="ffsi32")
|
|
4659
|
+
plus_one = self.builder.add(cttz, ir.Constant(int32_t, 1), name="ffsplusone")
|
|
4660
|
+
result = self.builder.select(is_zero, ir.Constant(int32_t, 0), plus_one)
|
|
4661
|
+
self._clear_unsigned(result)
|
|
4662
|
+
return result, None
|
|
4663
|
+
|
|
4664
|
+
def _coerce_builtin_float_arg(self, expr, target_type=None):
|
|
4665
|
+
value, _ = self.codegen(expr)
|
|
4666
|
+
if target_type is None:
|
|
4667
|
+
if isinstance(getattr(value, "type", None), ir.FloatType):
|
|
4668
|
+
target_type = _float
|
|
4669
|
+
else:
|
|
4670
|
+
target_type = _double
|
|
4671
|
+
if not self._is_floating_ir_type(getattr(value, "type", None)):
|
|
4672
|
+
value = self._implicit_convert(value, target_type)
|
|
4673
|
+
elif value.type != target_type:
|
|
4674
|
+
value = self._implicit_convert(value, target_type)
|
|
4675
|
+
return value
|
|
4676
|
+
|
|
4677
|
+
def _materialize_compound_literal(self, ast_type, init_node):
|
|
4678
|
+
dest_ir_type = self._resolve_ast_type(ast_type)
|
|
4679
|
+
if self.builder is None:
|
|
4680
|
+
return self._build_const_init(init_node, dest_ir_type), None
|
|
4681
|
+
tmp_ptr = self._alloca_in_entry(dest_ir_type, "compoundlit")
|
|
4682
|
+
self._safe_store(self._zero_initializer(dest_ir_type), tmp_ptr)
|
|
4683
|
+
self._init_runtime_value(tmp_ptr, dest_ir_type, init_node)
|
|
4684
|
+
value = self._safe_load(tmp_ptr, name="compoundlitval")
|
|
4685
|
+
self._tag_value_from_decl_type(value, ast_type)
|
|
4686
|
+
return value, tmp_ptr
|
|
4687
|
+
|
|
4688
|
+
def _builtin_bool_to_i32(self, value, name):
|
|
4689
|
+
return self.builder.zext(value, int32_t, name=name), None
|
|
4690
|
+
|
|
4691
|
+
def _codegen_builtin_isnan(self, node):
|
|
4692
|
+
if not node.args or not node.args.exprs:
|
|
4693
|
+
return ir.Constant(int32_t, 0), None
|
|
4694
|
+
value = self._coerce_builtin_float_arg(node.args.exprs[0])
|
|
4695
|
+
result = self.builder.fcmp_unordered("!=", value, value, name="isnan")
|
|
4696
|
+
return self._builtin_bool_to_i32(result, "isnani32")
|
|
4697
|
+
|
|
4698
|
+
def _codegen_builtin_isinf(self, node):
|
|
4699
|
+
if not node.args or not node.args.exprs:
|
|
4700
|
+
return ir.Constant(int32_t, 0), None
|
|
4701
|
+
value = self._coerce_builtin_float_arg(node.args.exprs[0])
|
|
4702
|
+
pos_inf = ir.Constant(value.type, float("inf"))
|
|
4703
|
+
neg_inf = ir.Constant(value.type, float("-inf"))
|
|
4704
|
+
is_pos = self.builder.fcmp_ordered("==", value, pos_inf, name="isinfpos")
|
|
4705
|
+
is_neg = self.builder.fcmp_ordered("==", value, neg_inf, name="isinfneg")
|
|
4706
|
+
return self._builtin_bool_to_i32(
|
|
4707
|
+
self.builder.or_(is_pos, is_neg, name="isinf"),
|
|
4708
|
+
"isinfi32",
|
|
4709
|
+
)
|
|
4710
|
+
|
|
4711
|
+
def _codegen_builtin_isfinite(self, node):
|
|
4712
|
+
if not node.args or not node.args.exprs:
|
|
4713
|
+
return ir.Constant(int32_t, 0), None
|
|
4714
|
+
value = self._coerce_builtin_float_arg(node.args.exprs[0])
|
|
4715
|
+
not_nan = self.builder.fcmp_ordered("==", value, value, name="isfinitenotnan")
|
|
4716
|
+
pos_inf = self.builder.fcmp_ordered(
|
|
4717
|
+
"==", value, ir.Constant(value.type, float("inf")), name="isfiniteposinf"
|
|
4718
|
+
)
|
|
4719
|
+
neg_inf = self.builder.fcmp_ordered(
|
|
4720
|
+
"==", value, ir.Constant(value.type, float("-inf")), name="isfiniteneginf"
|
|
4721
|
+
)
|
|
4722
|
+
is_inf = self.builder.or_(pos_inf, neg_inf, name="isfiniteisinf")
|
|
4723
|
+
result = self.builder.and_(
|
|
4724
|
+
not_nan,
|
|
4725
|
+
self.builder.not_(is_inf, name="isfinite_not_inf"),
|
|
4726
|
+
name="isfinite",
|
|
4727
|
+
)
|
|
4728
|
+
return self._builtin_bool_to_i32(result, "isfinitei32")
|
|
4729
|
+
|
|
4730
|
+
def _codegen_builtin_signbit(self, node):
|
|
4731
|
+
if not node.args or not node.args.exprs:
|
|
4732
|
+
return ir.Constant(int32_t, 0), None
|
|
4733
|
+
value = self._coerce_builtin_float_arg(node.args.exprs[0])
|
|
4734
|
+
if isinstance(value.type, ir.FloatType):
|
|
4735
|
+
int_type = ir.IntType(32)
|
|
4736
|
+
sign_mask = ir.Constant(int_type, 0x80000000)
|
|
4737
|
+
else:
|
|
4738
|
+
int_type = ir.IntType(64)
|
|
4739
|
+
sign_mask = ir.Constant(int_type, 0x8000000000000000)
|
|
4740
|
+
bits = self.builder.bitcast(value, int_type, name="signbitbits")
|
|
4741
|
+
masked = self.builder.and_(bits, sign_mask, name="signbitmask")
|
|
4742
|
+
result = self.builder.icmp_unsigned(
|
|
4743
|
+
"!=", masked, ir.Constant(int_type, 0), name="signbit"
|
|
4744
|
+
)
|
|
4745
|
+
return self._builtin_bool_to_i32(result, "signbiti32")
|
|
4746
|
+
|
|
4747
|
+
def _codegen_builtin_isunordered(self, node):
|
|
4748
|
+
if not node.args or len(node.args.exprs) < 2:
|
|
4749
|
+
return ir.Constant(int32_t, 0), None
|
|
4750
|
+
lhs = self._coerce_builtin_float_arg(node.args.exprs[0])
|
|
4751
|
+
rhs = self._coerce_builtin_float_arg(node.args.exprs[1], lhs.type)
|
|
4752
|
+
lhs_nan = self.builder.fcmp_unordered("!=", lhs, lhs, name="lhsnan")
|
|
4753
|
+
rhs_nan = self.builder.fcmp_unordered("!=", rhs, rhs, name="rhsnan")
|
|
4754
|
+
result = self.builder.or_(lhs_nan, rhs_nan, name="isunord")
|
|
4755
|
+
return self._builtin_bool_to_i32(result, "isunordi32")
|
|
4756
|
+
|
|
4757
|
+
def _codegen_builtin_ordered_compare(self, node, op, name):
|
|
4758
|
+
if not node.args or len(node.args.exprs) < 2:
|
|
4759
|
+
return ir.Constant(int32_t, 0), None
|
|
4760
|
+
lhs = self._coerce_builtin_float_arg(node.args.exprs[0])
|
|
4761
|
+
rhs = self._coerce_builtin_float_arg(node.args.exprs[1], lhs.type)
|
|
4762
|
+
result = self.builder.fcmp_ordered(op, lhs, rhs, name=name)
|
|
4763
|
+
return self._builtin_bool_to_i32(result, f"{name}i32")
|
|
4764
|
+
|
|
4765
|
+
def _codegen_builtin_islessgreater(self, node):
|
|
4766
|
+
if not node.args or len(node.args.exprs) < 2:
|
|
4767
|
+
return ir.Constant(int32_t, 0), None
|
|
4768
|
+
lhs = self._coerce_builtin_float_arg(node.args.exprs[0])
|
|
4769
|
+
rhs = self._coerce_builtin_float_arg(node.args.exprs[1], lhs.type)
|
|
4770
|
+
result = self.builder.fcmp_ordered("!=", lhs, rhs, name="islessgreater")
|
|
4771
|
+
return self._builtin_bool_to_i32(result, "islessgreateri32")
|
|
4772
|
+
|
|
4773
|
+
def _codegen_builtin_copysign(self, node, target_type):
|
|
4774
|
+
if not node.args or len(node.args.exprs) < 2:
|
|
4775
|
+
return ir.Constant(target_type, 0.0), None
|
|
4776
|
+
magnitude = self._coerce_builtin_float_arg(node.args.exprs[0], target_type)
|
|
4777
|
+
sign = self._coerce_builtin_float_arg(node.args.exprs[1], target_type)
|
|
4778
|
+
|
|
4779
|
+
if isinstance(target_type, ir.FloatType):
|
|
4780
|
+
int_type = ir.IntType(32)
|
|
4781
|
+
sign_mask = ir.Constant(int_type, 0x80000000)
|
|
4782
|
+
value_mask = ir.Constant(int_type, 0x7FFFFFFF)
|
|
4783
|
+
else:
|
|
4784
|
+
int_type = ir.IntType(64)
|
|
4785
|
+
sign_mask = ir.Constant(int_type, 0x8000000000000000)
|
|
4786
|
+
value_mask = ir.Constant(int_type, 0x7FFFFFFFFFFFFFFF)
|
|
4787
|
+
|
|
4788
|
+
magnitude_bits = self.builder.bitcast(
|
|
4789
|
+
magnitude, int_type, name="copysignmagbits"
|
|
4790
|
+
)
|
|
4791
|
+
sign_bits = self.builder.bitcast(sign, int_type, name="copysignsignbits")
|
|
4792
|
+
magnitude_bits = self.builder.and_(
|
|
4793
|
+
magnitude_bits, value_mask, name="copysignmag"
|
|
4794
|
+
)
|
|
4795
|
+
sign_bits = self.builder.and_(sign_bits, sign_mask, name="copysignsign")
|
|
4796
|
+
result_bits = self.builder.or_(
|
|
4797
|
+
magnitude_bits, sign_bits, name="copysignbits"
|
|
4798
|
+
)
|
|
4799
|
+
return self.builder.bitcast(result_bits, target_type, name="copysigntmp"), None
|
|
4800
|
+
|
|
4801
|
+
def _codegen_builtin_overflow(self, node, operation):
|
|
4802
|
+
if not node.args or len(node.args.exprs) < 3:
|
|
4803
|
+
return ir.Constant(int32_t, 0), None
|
|
4804
|
+
|
|
4805
|
+
lhs, _ = self.codegen(node.args.exprs[0])
|
|
4806
|
+
rhs, _ = self.codegen(node.args.exprs[1])
|
|
4807
|
+
out_ptr, _ = self.codegen(node.args.exprs[2])
|
|
4808
|
+
|
|
4809
|
+
if not isinstance(getattr(out_ptr, "type", None), ir.PointerType):
|
|
4810
|
+
return ir.Constant(int32_t, 0), None
|
|
4811
|
+
|
|
4812
|
+
result_type = out_ptr.type.pointee
|
|
4813
|
+
if not isinstance(result_type, ir.IntType):
|
|
4814
|
+
return ir.Constant(int32_t, 0), None
|
|
4815
|
+
|
|
4816
|
+
lhs = self._implicit_convert(lhs, result_type)
|
|
4817
|
+
rhs = self._implicit_convert(rhs, result_type)
|
|
4818
|
+
|
|
4819
|
+
is_unsigned = self._is_unsigned_val(lhs) or self._is_unsigned_val(rhs)
|
|
4820
|
+
if is_unsigned:
|
|
4821
|
+
self._tag_unsigned(lhs)
|
|
4822
|
+
self._tag_unsigned(rhs)
|
|
4823
|
+
|
|
4824
|
+
intrinsic_prefix = {
|
|
4825
|
+
("add", False): "sadd",
|
|
4826
|
+
("add", True): "uadd",
|
|
4827
|
+
("sub", False): "ssub",
|
|
4828
|
+
("sub", True): "usub",
|
|
4829
|
+
("mul", False): "smul",
|
|
4830
|
+
("mul", True): "umul",
|
|
4831
|
+
}[(operation, is_unsigned)]
|
|
4832
|
+
pair_type = ir.LiteralStructType([result_type, ir.IntType(1)])
|
|
4833
|
+
intrinsic = self._get_or_declare_intrinsic(
|
|
4834
|
+
f"llvm.{intrinsic_prefix}.with.overflow.i{result_type.width}",
|
|
4835
|
+
pair_type,
|
|
4836
|
+
[result_type, result_type],
|
|
4837
|
+
)
|
|
4838
|
+
pair = self.builder.call(intrinsic, [lhs, rhs], name=f"{operation}ovtmp")
|
|
4839
|
+
result = self.builder.extract_value(pair, 0, name=f"{operation}ovval")
|
|
4840
|
+
overflow = self.builder.extract_value(pair, 1, name=f"{operation}ovflag")
|
|
4841
|
+
if is_unsigned:
|
|
4842
|
+
self._tag_unsigned(result)
|
|
4843
|
+
self._safe_store(result, out_ptr)
|
|
4844
|
+
|
|
4845
|
+
overflow_i32 = self.builder.zext(overflow, int32_t, name=f"{operation}ovi32")
|
|
4846
|
+
self._clear_unsigned(overflow_i32)
|
|
4847
|
+
return overflow_i32, None
|
|
4848
|
+
|
|
4849
|
+
def _codegen_builtin_sync_synchronize(self, node):
|
|
4850
|
+
self.builder.fence("seq_cst")
|
|
4851
|
+
return ir.Constant(int64_t, 0), None
|
|
4852
|
+
|
|
4853
|
+
def _codegen_builtin_bswap(self, node, width):
|
|
4854
|
+
if not node.args or not node.args.exprs:
|
|
4855
|
+
return ir.Constant(ir.IntType(width), 0), None
|
|
4856
|
+
|
|
4857
|
+
arg, _ = self.codegen(node.args.exprs[0])
|
|
4858
|
+
arg_type = ir.IntType(width)
|
|
4859
|
+
returns_unsigned = self._is_unsigned_val(arg)
|
|
4860
|
+
|
|
4861
|
+
if not isinstance(getattr(arg, "type", None), ir.IntType) or arg.type != arg_type:
|
|
4862
|
+
arg = self._implicit_convert(arg, arg_type)
|
|
4863
|
+
|
|
4864
|
+
mask = ir.Constant(arg_type, 0xFF)
|
|
4865
|
+
result = ir.Constant(arg_type, 0)
|
|
4866
|
+
byte_count = width // 8
|
|
4867
|
+
|
|
4868
|
+
for index in range(byte_count):
|
|
4869
|
+
piece = arg
|
|
4870
|
+
if index:
|
|
4871
|
+
piece = self.builder.lshr(
|
|
4872
|
+
piece,
|
|
4873
|
+
ir.Constant(arg_type, index * 8),
|
|
4874
|
+
name=f"bswapshr{index}",
|
|
4875
|
+
)
|
|
4876
|
+
piece = self.builder.and_(piece, mask, name=f"bswapmask{index}")
|
|
4877
|
+
shift = (byte_count - 1 - index) * 8
|
|
4878
|
+
if shift:
|
|
4879
|
+
piece = self.builder.shl(
|
|
4880
|
+
piece,
|
|
4881
|
+
ir.Constant(arg_type, shift),
|
|
4882
|
+
name=f"bswapshl{index}",
|
|
4883
|
+
)
|
|
4884
|
+
result = self.builder.or_(result, piece, name=f"bswapor{index}")
|
|
4885
|
+
|
|
4886
|
+
return self._extend_call_result(result, returns_unsigned=returns_unsigned), None
|
|
4887
|
+
|
|
4888
|
+
def _codegen_builtin_rotate(self, node, width, direction):
|
|
4889
|
+
if not node.args or len(node.args.exprs) < 2:
|
|
4890
|
+
return ir.Constant(ir.IntType(width), 0), None
|
|
4891
|
+
|
|
4892
|
+
value, _ = self.codegen(node.args.exprs[0])
|
|
4893
|
+
amount, _ = self.codegen(node.args.exprs[1])
|
|
4894
|
+
value_type = ir.IntType(width)
|
|
4895
|
+
returns_unsigned = self._is_unsigned_val(value)
|
|
4896
|
+
|
|
4897
|
+
if (
|
|
4898
|
+
not isinstance(getattr(value, "type", None), ir.IntType)
|
|
4899
|
+
or value.type != value_type
|
|
4900
|
+
):
|
|
4901
|
+
value = self._implicit_convert(value, value_type)
|
|
4902
|
+
if (
|
|
4903
|
+
not isinstance(getattr(amount, "type", None), ir.IntType)
|
|
4904
|
+
or amount.type != value_type
|
|
4905
|
+
):
|
|
4906
|
+
amount = self._implicit_convert(amount, value_type)
|
|
4907
|
+
|
|
4908
|
+
mask = ir.Constant(value_type, width - 1)
|
|
4909
|
+
amount = self.builder.and_(amount, mask, name=f"rot{direction}amt")
|
|
4910
|
+
inverse = self.builder.sub(
|
|
4911
|
+
ir.Constant(value_type, 0), amount, name=f"rot{direction}invtmp"
|
|
4912
|
+
)
|
|
4913
|
+
inverse = self.builder.and_(inverse, mask, name=f"rot{direction}inv")
|
|
4914
|
+
|
|
4915
|
+
if direction == "left":
|
|
4916
|
+
lhs = self.builder.shl(value, amount, name=f"rot{direction}lhs")
|
|
4917
|
+
rhs = self.builder.lshr(value, inverse, name=f"rot{direction}rhs")
|
|
4918
|
+
else:
|
|
4919
|
+
lhs = self.builder.lshr(value, amount, name=f"rot{direction}lhs")
|
|
4920
|
+
rhs = self.builder.shl(value, inverse, name=f"rot{direction}rhs")
|
|
4921
|
+
|
|
4922
|
+
result = self.builder.or_(lhs, rhs, name=f"rot{direction}")
|
|
4923
|
+
return self._extend_call_result(result, returns_unsigned=returns_unsigned), None
|
|
4924
|
+
|
|
4925
|
+
def _codegen_builtin_bitcount(self, node, width, intrinsic_base):
|
|
4926
|
+
if not node.args or not node.args.exprs:
|
|
4927
|
+
return ir.Constant(int32_t, 0), None
|
|
4928
|
+
|
|
4929
|
+
arg, _ = self.codegen(node.args.exprs[0])
|
|
4930
|
+
arg_type = ir.IntType(width)
|
|
4931
|
+
if not isinstance(getattr(arg, "type", None), ir.IntType) or arg.type != arg_type:
|
|
4932
|
+
arg = self._implicit_convert(arg, arg_type)
|
|
4933
|
+
|
|
4934
|
+
intrinsic = self._get_or_declare_intrinsic(
|
|
4935
|
+
f"llvm.{intrinsic_base}.i{width}",
|
|
4936
|
+
arg_type,
|
|
4937
|
+
[arg_type, ir.IntType(1)],
|
|
4938
|
+
)
|
|
4939
|
+
result = self.builder.call(
|
|
4940
|
+
intrinsic,
|
|
4941
|
+
[arg, ir.Constant(ir.IntType(1), 0)],
|
|
4942
|
+
name=f"{intrinsic_base}tmp",
|
|
4943
|
+
)
|
|
4944
|
+
if result.type != int32_t:
|
|
4945
|
+
result = self.builder.trunc(result, int32_t, name=f"{intrinsic_base}i32")
|
|
4946
|
+
self._clear_unsigned(result)
|
|
4947
|
+
return result, None
|
|
4948
|
+
|
|
4949
|
+
def _atomic_ordering(self, node, is_store):
|
|
4950
|
+
try:
|
|
4951
|
+
value = self._eval_const_expr(node)
|
|
4952
|
+
except Exception:
|
|
4953
|
+
return "monotonic"
|
|
4954
|
+
if is_store:
|
|
4955
|
+
return {
|
|
4956
|
+
0: "monotonic", # __ATOMIC_RELAXED
|
|
4957
|
+
3: "release", # __ATOMIC_RELEASE
|
|
4958
|
+
4: "release", # __ATOMIC_ACQ_REL
|
|
4959
|
+
5: "seq_cst", # __ATOMIC_SEQ_CST
|
|
4960
|
+
}.get(value, "monotonic")
|
|
4961
|
+
return {
|
|
4962
|
+
0: "monotonic", # __ATOMIC_RELAXED
|
|
4963
|
+
1: "acquire", # __ATOMIC_CONSUME
|
|
4964
|
+
2: "acquire", # __ATOMIC_ACQUIRE
|
|
4965
|
+
5: "seq_cst", # __ATOMIC_SEQ_CST
|
|
4966
|
+
}.get(value, "monotonic")
|
|
4967
|
+
|
|
4968
|
+
def _codegen_builtin_atomic_load(self, node):
|
|
4969
|
+
if not node.args or len(node.args.exprs) < 2:
|
|
4970
|
+
return ir.Constant(int64_t, 0), None
|
|
4971
|
+
ptr, _ = self.codegen(node.args.exprs[0])
|
|
4972
|
+
if not isinstance(getattr(ptr, "type", None), ir.PointerType):
|
|
4973
|
+
return ir.Constant(int64_t, 0), None
|
|
4974
|
+
pointee_type = ptr.type.pointee
|
|
4975
|
+
align = max(1, self._ir_type_align(pointee_type))
|
|
4976
|
+
ordering = self._atomic_ordering(node.args.exprs[1], is_store=False)
|
|
4977
|
+
result = self.builder.load_atomic(ptr, ordering, align)
|
|
4978
|
+
if self._is_unsigned_pointee(ptr):
|
|
4979
|
+
self._tag_unsigned(result)
|
|
4980
|
+
return result, ptr
|
|
4981
|
+
|
|
4982
|
+
def _codegen_builtin_atomic_store(self, node):
|
|
4983
|
+
if not node.args or len(node.args.exprs) < 3:
|
|
4984
|
+
return ir.Constant(int64_t, 0), None
|
|
4985
|
+
ptr, _ = self.codegen(node.args.exprs[0])
|
|
4986
|
+
value, _ = self.codegen(node.args.exprs[1])
|
|
4987
|
+
if not isinstance(getattr(ptr, "type", None), ir.PointerType):
|
|
4988
|
+
return ir.Constant(int64_t, 0), None
|
|
4989
|
+
pointee_type = ptr.type.pointee
|
|
4990
|
+
if value.type != pointee_type:
|
|
4991
|
+
value = self._implicit_convert(value, pointee_type)
|
|
4992
|
+
align = max(1, self._ir_type_align(pointee_type))
|
|
4993
|
+
ordering = self._atomic_ordering(node.args.exprs[2], is_store=True)
|
|
4994
|
+
self.builder.store_atomic(value, ptr, ordering, align)
|
|
4995
|
+
return ir.Constant(int64_t, 0), None
|
|
4996
|
+
|
|
4997
|
+
def _convert_call_args(self, call_args, callee_func, arg_nodes=None):
|
|
2895
4998
|
"""Convert call arguments to match function parameter types."""
|
|
2896
4999
|
converted = []
|
|
2897
5000
|
param_types = [p.type for p in callee_func.args]
|
|
2898
5001
|
|
|
2899
5002
|
for i, arg in enumerate(call_args):
|
|
5003
|
+
arg_node = arg_nodes[i] if arg_nodes and i < len(arg_nodes) else None
|
|
2900
5004
|
if i < len(param_types):
|
|
2901
5005
|
expected = param_types[i]
|
|
2902
|
-
arg = self._coerce_arg(arg, expected)
|
|
5006
|
+
arg = self._coerce_arg(arg, expected, arg_node=arg_node)
|
|
2903
5007
|
else:
|
|
2904
|
-
arg = self._default_arg_promotion(arg)
|
|
5008
|
+
arg = self._default_arg_promotion(arg, arg_node=arg_node)
|
|
2905
5009
|
converted.append(arg)
|
|
2906
5010
|
return converted
|
|
2907
5011
|
|
|
2908
|
-
def _default_arg_promotion(self, arg):
|
|
5012
|
+
def _default_arg_promotion(self, arg, arg_node=None):
|
|
2909
5013
|
"""Apply C default argument promotions for variadic calls."""
|
|
2910
5014
|
if arg is None or isinstance(getattr(arg, "type", None), ir.VoidType):
|
|
2911
5015
|
return ir.Constant(int64_t, 0)
|
|
5016
|
+
arg = self._decay_array_expr_to_pointer(arg_node, arg, "varargarraydecay")
|
|
2912
5017
|
if isinstance(arg.type, ir.ArrayType):
|
|
2913
5018
|
return self._implicit_convert(arg, ir.PointerType(arg.type.element))
|
|
2914
5019
|
if isinstance(arg.type, ir.FloatType):
|
|
@@ -2917,7 +5022,7 @@ class LLVMCodeGenerator(object):
|
|
|
2917
5022
|
return self._integer_promotion(arg)
|
|
2918
5023
|
return arg
|
|
2919
5024
|
|
|
2920
|
-
def _coerce_arg(self, arg, expected):
|
|
5025
|
+
def _coerce_arg(self, arg, expected, arg_node=None):
|
|
2921
5026
|
"""Coerce a single argument to the expected type."""
|
|
2922
5027
|
if arg is None or isinstance(getattr(arg, "type", None), ir.VoidType):
|
|
2923
5028
|
return (
|
|
@@ -2925,16 +5030,13 @@ class LLVMCodeGenerator(object):
|
|
|
2925
5030
|
if isinstance(expected, ir.PointerType)
|
|
2926
5031
|
else ir.Constant(int64_t, 0)
|
|
2927
5032
|
)
|
|
5033
|
+
arg = self._decay_array_expr_to_pointer(arg_node, arg, "argarraydecay")
|
|
2928
5034
|
if arg.type == expected:
|
|
2929
5035
|
return arg
|
|
2930
|
-
#
|
|
5036
|
+
# Array values decay to pointers at the call site; do not try to
|
|
5037
|
+
# synthesize globals from function-local SSA array values here.
|
|
2931
5038
|
if isinstance(arg.type, ir.ArrayType) and isinstance(expected, ir.PointerType):
|
|
2932
|
-
|
|
2933
|
-
self.module, arg.type, self.module.get_unique_name("str")
|
|
2934
|
-
)
|
|
2935
|
-
gv.initializer = arg
|
|
2936
|
-
gv.global_constant = True
|
|
2937
|
-
return self.builder.bitcast(gv, expected)
|
|
5039
|
+
return self._implicit_convert(arg, expected)
|
|
2938
5040
|
# Pointer -> different pointer: bitcast
|
|
2939
5041
|
if isinstance(arg.type, ir.PointerType) and isinstance(
|
|
2940
5042
|
expected, ir.PointerType
|
|
@@ -2957,19 +5059,45 @@ class LLVMCodeGenerator(object):
|
|
|
2957
5059
|
):
|
|
2958
5060
|
return None, None
|
|
2959
5061
|
|
|
2960
|
-
#
|
|
5062
|
+
# Standalone tag definitions such as:
|
|
5063
|
+
# struct S { ... };
|
|
5064
|
+
# union U { ... };
|
|
5065
|
+
# enum E { ... };
|
|
5066
|
+
# do not declare objects. Register the aggregate/enum type and stop.
|
|
5067
|
+
if node.name is None and isinstance(node.type, c_ast.TypeDecl):
|
|
5068
|
+
inner = node.type.type
|
|
5069
|
+
if isinstance(inner, c_ast.Struct):
|
|
5070
|
+
self.codegen_Struct(inner)
|
|
5071
|
+
return None, None
|
|
5072
|
+
if isinstance(inner, c_ast.Union):
|
|
5073
|
+
self.codegen_Union(inner)
|
|
5074
|
+
return None, None
|
|
5075
|
+
if isinstance(inner, c_ast.Enum):
|
|
5076
|
+
self.codegen_Enum(inner)
|
|
5077
|
+
return None, None
|
|
5078
|
+
|
|
5079
|
+
# Static local objects: stored as internal globals with function-scoped names
|
|
2961
5080
|
is_static = node.storage and "static" in node.storage
|
|
2962
|
-
if is_static and not self.in_global and isinstance(node.type, c_ast.
|
|
2963
|
-
|
|
2964
|
-
ir_type = self._get_ir_type(type_str)
|
|
5081
|
+
if is_static and not self.in_global and not isinstance(node.type, c_ast.FuncDecl):
|
|
5082
|
+
ir_type = self._static_local_ir_type(node.type, init_node=node.init)
|
|
2965
5083
|
# Create unique global name
|
|
2966
|
-
global_name =
|
|
2967
|
-
gv =
|
|
5084
|
+
global_name = self._static_local_symbol_name(node.name)
|
|
5085
|
+
gv = self._create_bound_global(node.name, ir_type, symbol_name=global_name)
|
|
5086
|
+
gv.linkage = "internal"
|
|
2968
5087
|
if node.init:
|
|
2969
5088
|
gv.initializer = self._build_const_init(node.init, ir_type)
|
|
2970
5089
|
else:
|
|
2971
5090
|
gv.initializer = self._zero_initializer(ir_type)
|
|
2972
|
-
|
|
5091
|
+
return None, None
|
|
5092
|
+
|
|
5093
|
+
if self._is_global_extern_decl(node):
|
|
5094
|
+
ir_type = self._extern_decl_ir_type(node.name, node.type)
|
|
5095
|
+
self._prepare_file_scope_object(
|
|
5096
|
+
node.name,
|
|
5097
|
+
ir_type,
|
|
5098
|
+
storage=node.storage,
|
|
5099
|
+
has_initializer=False,
|
|
5100
|
+
)
|
|
2973
5101
|
return None, None
|
|
2974
5102
|
|
|
2975
5103
|
if isinstance(node.type, c_ast.Enum):
|
|
@@ -2978,39 +5106,38 @@ class LLVMCodeGenerator(object):
|
|
|
2978
5106
|
# Forward function declaration: int foo(int x);
|
|
2979
5107
|
if isinstance(node.type, c_ast.FuncDecl):
|
|
2980
5108
|
funcname = node.name
|
|
5109
|
+
function_type, ir_type = self._build_function_ir_type(node.type)
|
|
5110
|
+
function_type = self._preferred_file_scope_function_ir_type(
|
|
5111
|
+
funcname,
|
|
5112
|
+
function_type,
|
|
5113
|
+
getattr(node.type, "args", None) is not None,
|
|
5114
|
+
)
|
|
5115
|
+
symbol_name = self._register_file_scope_function(
|
|
5116
|
+
funcname,
|
|
5117
|
+
function_type,
|
|
5118
|
+
storage=node.storage,
|
|
5119
|
+
funcspec=node.funcspec,
|
|
5120
|
+
is_definition=False,
|
|
5121
|
+
)
|
|
2981
5122
|
# Skip if already exists (module globals, libc, or env)
|
|
2982
|
-
existing = self.module.globals.get(
|
|
5123
|
+
existing = self.module.globals.get(symbol_name)
|
|
2983
5124
|
if existing:
|
|
2984
5125
|
if self._func_decl_returns_unsigned(node.type):
|
|
2985
5126
|
self._mark_unsigned_return(existing)
|
|
2986
5127
|
self.define(funcname, (None, existing))
|
|
2987
5128
|
return None, None
|
|
2988
|
-
if funcname in LIBC_FUNCTIONS:
|
|
2989
|
-
self._declare_libc(funcname)
|
|
2990
|
-
return None, None
|
|
2991
|
-
ir_type, _ = self.codegen(node.type)
|
|
2992
|
-
arg_types = []
|
|
2993
|
-
is_va = False
|
|
2994
|
-
if node.type.args:
|
|
2995
|
-
for arg in node.type.args.params:
|
|
2996
|
-
if isinstance(arg, c_ast.EllipsisParam):
|
|
2997
|
-
is_va = True
|
|
2998
|
-
continue
|
|
2999
|
-
t = self._resolve_param_type(arg)
|
|
3000
|
-
if t is not None:
|
|
3001
|
-
arg_types.append(t)
|
|
3002
5129
|
try:
|
|
3003
5130
|
func = ir.Function(
|
|
3004
5131
|
self.module,
|
|
3005
|
-
|
|
3006
|
-
name=
|
|
5132
|
+
function_type,
|
|
5133
|
+
name=symbol_name,
|
|
3007
5134
|
)
|
|
3008
5135
|
if self._func_decl_returns_unsigned(node.type):
|
|
3009
5136
|
self._mark_unsigned_return(func)
|
|
3010
5137
|
self.define(funcname, (ir_type, func))
|
|
3011
5138
|
except Exception:
|
|
3012
5139
|
# Already exists (libc or previous decl)
|
|
3013
|
-
existing = self.module.globals.get(
|
|
5140
|
+
existing = self.module.globals.get(symbol_name)
|
|
3014
5141
|
if existing:
|
|
3015
5142
|
if self._func_decl_returns_unsigned(node.type):
|
|
3016
5143
|
self._mark_unsigned_return(existing)
|
|
@@ -3031,8 +5158,29 @@ class LLVMCodeGenerator(object):
|
|
|
3031
5158
|
if isinstance(node.type.type, c_ast.IdentifierType):
|
|
3032
5159
|
# Check if the type resolves to a struct or pointer via typedef
|
|
3033
5160
|
resolved = self._resolve_type_str(node.type.type.names)
|
|
3034
|
-
if isinstance(
|
|
3035
|
-
|
|
5161
|
+
if isinstance(resolved, ir.FunctionType):
|
|
5162
|
+
funcname = node.type.declname
|
|
5163
|
+
symbol_name = self._register_file_scope_function(
|
|
5164
|
+
funcname,
|
|
5165
|
+
resolved,
|
|
5166
|
+
storage=node.storage,
|
|
5167
|
+
funcspec=node.funcspec,
|
|
5168
|
+
is_definition=False,
|
|
5169
|
+
)
|
|
5170
|
+
existing = self.module.globals.get(symbol_name)
|
|
5171
|
+
if existing:
|
|
5172
|
+
self.define(funcname, (resolved.return_type, existing))
|
|
5173
|
+
return None, None
|
|
5174
|
+
try:
|
|
5175
|
+
func = ir.Function(self.module, resolved, name=symbol_name)
|
|
5176
|
+
self.define(funcname, (resolved.return_type, func))
|
|
5177
|
+
except Exception:
|
|
5178
|
+
existing = self.module.globals.get(symbol_name)
|
|
5179
|
+
if existing:
|
|
5180
|
+
self.define(funcname, (resolved.return_type, existing))
|
|
5181
|
+
return None, None
|
|
5182
|
+
if isinstance(resolved, (ir.PointerType, ir.ArrayType)) or _is_struct_ir_type(
|
|
5183
|
+
resolved
|
|
3036
5184
|
):
|
|
3037
5185
|
name = node.type.declname
|
|
3038
5186
|
ir_type = resolved
|
|
@@ -3040,18 +5188,36 @@ class LLVMCodeGenerator(object):
|
|
|
3040
5188
|
ret = self._alloca_in_entry(ir_type, name)
|
|
3041
5189
|
self.define(name, (ir_type, ret))
|
|
3042
5190
|
else:
|
|
3043
|
-
ret =
|
|
3044
|
-
|
|
5191
|
+
ret, write_initializer = self._prepare_file_scope_object(
|
|
5192
|
+
name,
|
|
5193
|
+
ir_type,
|
|
5194
|
+
storage=node.storage,
|
|
5195
|
+
has_initializer=node.init is not None,
|
|
5196
|
+
)
|
|
5197
|
+
if ret is None:
|
|
5198
|
+
return None, None
|
|
3045
5199
|
if node.init is not None:
|
|
3046
5200
|
if self.in_global:
|
|
3047
|
-
|
|
5201
|
+
if write_initializer:
|
|
5202
|
+
ret.initializer = self._build_const_init(
|
|
5203
|
+
node.init, ir_type
|
|
5204
|
+
)
|
|
3048
5205
|
else:
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
self._safe_store(
|
|
3054
|
-
|
|
5206
|
+
if isinstance(node.init, c_ast.InitList) and (
|
|
5207
|
+
getattr(ir_type, "is_union", False)
|
|
5208
|
+
or _is_struct_ir_type(ir_type)
|
|
5209
|
+
):
|
|
5210
|
+
self._safe_store(self._zero_initializer(ir_type), ret)
|
|
5211
|
+
self._init_runtime_aggregate(ret, node.init, ir_type)
|
|
5212
|
+
else:
|
|
5213
|
+
init_val, _ = self.codegen(node.init)
|
|
5214
|
+
if init_val is not None:
|
|
5215
|
+
if init_val.type != ir_type:
|
|
5216
|
+
init_val = self._implicit_convert(
|
|
5217
|
+
init_val, ir_type
|
|
5218
|
+
)
|
|
5219
|
+
self._safe_store(init_val, ret)
|
|
5220
|
+
elif self.in_global and write_initializer:
|
|
3055
5221
|
ret.initializer = self._zero_initializer(ir_type)
|
|
3056
5222
|
return None, None
|
|
3057
5223
|
|
|
@@ -3062,61 +5228,107 @@ class LLVMCodeGenerator(object):
|
|
|
3062
5228
|
if isinstance(node.type.type, c_ast.Union)
|
|
3063
5229
|
else self.codegen_Struct
|
|
3064
5230
|
)
|
|
3065
|
-
if node.type.type.name is None:
|
|
5231
|
+
if node.type.type.name is None or getattr(node.type.type, "decls", None) is not None:
|
|
3066
5232
|
struct_type = codegen_fn(node.type.type)
|
|
5233
|
+
if self.in_global and node.name and node.type.type.name is None:
|
|
5234
|
+
# Preserve the repository's legacy behavior for
|
|
5235
|
+
# file-scope anonymous aggregates declared as:
|
|
5236
|
+
# struct { ... } Name;
|
|
5237
|
+
# Existing tests rely on a later `struct Name`
|
|
5238
|
+
# resolving to the same aggregate type.
|
|
5239
|
+
self.define(self._tag_type_key(node.name), (struct_type, None))
|
|
3067
5240
|
if not self.in_global:
|
|
3068
5241
|
ret = self._alloca_in_entry(struct_type, name)
|
|
3069
5242
|
self.define(name, (struct_type, ret))
|
|
3070
5243
|
else:
|
|
3071
|
-
ret =
|
|
3072
|
-
|
|
5244
|
+
ret, write_initializer = self._prepare_file_scope_object(
|
|
5245
|
+
name,
|
|
5246
|
+
struct_type,
|
|
5247
|
+
storage=node.storage,
|
|
5248
|
+
has_initializer=node.init is not None,
|
|
5249
|
+
)
|
|
5250
|
+
if ret is None:
|
|
5251
|
+
return None, None
|
|
3073
5252
|
if node.init is not None:
|
|
3074
5253
|
if self.in_global:
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
5254
|
+
if write_initializer:
|
|
5255
|
+
ret.initializer = self._build_const_init(
|
|
5256
|
+
node.init, struct_type
|
|
5257
|
+
)
|
|
3078
5258
|
else:
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
5259
|
+
if isinstance(node.init, c_ast.InitList):
|
|
5260
|
+
self._safe_store(
|
|
5261
|
+
self._zero_initializer(struct_type), ret
|
|
5262
|
+
)
|
|
5263
|
+
self._init_runtime_aggregate(
|
|
5264
|
+
ret, node.init, struct_type
|
|
5265
|
+
)
|
|
5266
|
+
else:
|
|
5267
|
+
init_val, _ = self.codegen(node.init)
|
|
5268
|
+
if init_val is not None:
|
|
5269
|
+
if init_val.type != struct_type:
|
|
5270
|
+
init_val = self._implicit_convert(
|
|
5271
|
+
init_val, struct_type
|
|
5272
|
+
)
|
|
5273
|
+
self._safe_store(init_val, ret)
|
|
5274
|
+
elif self.in_global and write_initializer:
|
|
3087
5275
|
ret.initializer = self._zero_initializer(struct_type)
|
|
3088
5276
|
return None, None
|
|
3089
5277
|
else:
|
|
3090
|
-
struct_type = self.env[
|
|
5278
|
+
struct_type = self.env[
|
|
5279
|
+
self._tag_type_key(node.type.type.name)
|
|
5280
|
+
][0]
|
|
3091
5281
|
if not self.in_global:
|
|
3092
5282
|
ret = self._alloca_in_entry(struct_type, name)
|
|
3093
5283
|
self.define(name, (struct_type, ret))
|
|
3094
5284
|
else:
|
|
3095
|
-
ret =
|
|
3096
|
-
|
|
5285
|
+
ret, write_initializer = self._prepare_file_scope_object(
|
|
5286
|
+
name,
|
|
5287
|
+
struct_type,
|
|
5288
|
+
storage=node.storage,
|
|
5289
|
+
has_initializer=node.init is not None,
|
|
5290
|
+
)
|
|
5291
|
+
if ret is None:
|
|
5292
|
+
return None, None
|
|
3097
5293
|
if node.init is not None:
|
|
3098
5294
|
if self.in_global:
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
5295
|
+
if write_initializer:
|
|
5296
|
+
ret.initializer = self._build_const_init(
|
|
5297
|
+
node.init, struct_type
|
|
5298
|
+
)
|
|
3102
5299
|
else:
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
5300
|
+
if isinstance(node.init, c_ast.InitList):
|
|
5301
|
+
self._safe_store(
|
|
5302
|
+
self._zero_initializer(struct_type), ret
|
|
5303
|
+
)
|
|
5304
|
+
self._init_runtime_aggregate(
|
|
5305
|
+
ret, node.init, struct_type
|
|
5306
|
+
)
|
|
5307
|
+
else:
|
|
5308
|
+
init_val, _ = self.codegen(node.init)
|
|
5309
|
+
if init_val is not None:
|
|
5310
|
+
if init_val.type != struct_type:
|
|
5311
|
+
init_val = self._implicit_convert(
|
|
5312
|
+
init_val, struct_type
|
|
5313
|
+
)
|
|
5314
|
+
self._safe_store(init_val, ret)
|
|
5315
|
+
elif self.in_global and write_initializer:
|
|
3111
5316
|
ret.initializer = self._zero_initializer(struct_type)
|
|
3112
5317
|
return None, None
|
|
3113
5318
|
else:
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
type_str
|
|
5319
|
+
if isinstance(node.type.type, c_ast.IdentifierType):
|
|
5320
|
+
type_str = node.type.type.names
|
|
5321
|
+
is_unsigned = self._is_unsigned_type_names(type_str)
|
|
5322
|
+
ir_type = self._get_ir_type(type_str)
|
|
5323
|
+
type_str = self._resolve_type_str(type_str)
|
|
5324
|
+
if isinstance(type_str, ir.Type):
|
|
5325
|
+
type_str = "int" # fallback for alloca name
|
|
5326
|
+
else:
|
|
5327
|
+
if isinstance(node.type.type, c_ast.Enum):
|
|
5328
|
+
self.codegen_Enum(node.type.type)
|
|
5329
|
+
type_str = "int"
|
|
5330
|
+
is_unsigned = False
|
|
5331
|
+
ir_type = self._resolve_ast_type(node.type)
|
|
3120
5332
|
if self._is_floating_ir_type(ir_type):
|
|
3121
5333
|
init = 0.0
|
|
3122
5334
|
else:
|
|
@@ -3126,21 +5338,37 @@ class LLVMCodeGenerator(object):
|
|
|
3126
5338
|
if self.in_global:
|
|
3127
5339
|
init_val = self._build_const_init(node.init, ir_type)
|
|
3128
5340
|
else:
|
|
5341
|
+
var_addr, var_ir_type = self.create_entry_block_alloca(
|
|
5342
|
+
node.name, type_str, 1, storage=node.storage
|
|
5343
|
+
)
|
|
5344
|
+
if is_unsigned:
|
|
5345
|
+
self._mark_unsigned(var_addr)
|
|
3129
5346
|
init_val, _ = self.codegen(node.init)
|
|
3130
5347
|
else:
|
|
3131
5348
|
init_val = self._zero_initializer(ir_type)
|
|
3132
|
-
|
|
3133
|
-
var_addr, var_ir_type = self.create_entry_block_alloca(
|
|
3134
|
-
node.name, type_str, 1
|
|
3135
|
-
)
|
|
3136
|
-
if is_unsigned:
|
|
3137
|
-
self._mark_unsigned(var_addr)
|
|
3138
|
-
|
|
3139
5349
|
if self.in_global:
|
|
3140
|
-
var_addr
|
|
5350
|
+
var_addr, write_initializer = self._prepare_file_scope_object(
|
|
5351
|
+
node.name,
|
|
5352
|
+
ir_type,
|
|
5353
|
+
storage=node.storage,
|
|
5354
|
+
has_initializer=node.init is not None,
|
|
5355
|
+
)
|
|
5356
|
+
if var_addr is None:
|
|
5357
|
+
return None, None
|
|
5358
|
+
var_ir_type = ir_type
|
|
5359
|
+
if write_initializer:
|
|
5360
|
+
var_addr.initializer = init_val
|
|
3141
5361
|
else:
|
|
5362
|
+
if node.init is None:
|
|
5363
|
+
var_addr, var_ir_type = self.create_entry_block_alloca(
|
|
5364
|
+
node.name, type_str, 1, storage=node.storage
|
|
5365
|
+
)
|
|
5366
|
+
if is_unsigned:
|
|
5367
|
+
self._mark_unsigned(var_addr)
|
|
3142
5368
|
init_val = self._implicit_convert(init_val, ir_type)
|
|
3143
5369
|
self._safe_store(init_val, var_addr)
|
|
5370
|
+
if self.in_global and is_unsigned:
|
|
5371
|
+
self._mark_unsigned(var_addr)
|
|
3144
5372
|
|
|
3145
5373
|
elif isinstance(node.type, c_ast.ArrayDecl):
|
|
3146
5374
|
array_list = []
|
|
@@ -3148,27 +5376,43 @@ class LLVMCodeGenerator(object):
|
|
|
3148
5376
|
var_addr = None
|
|
3149
5377
|
var_ir_type = None
|
|
3150
5378
|
elem_ir_type = None
|
|
5379
|
+
write_initializer = True
|
|
5380
|
+
inferred_top_dim = self._infer_array_count_from_initializer(node.init)
|
|
3151
5381
|
while True:
|
|
3152
5382
|
array_next_type = array_node.type
|
|
3153
5383
|
if isinstance(array_next_type, c_ast.TypeDecl):
|
|
3154
5384
|
dim_val = self._eval_dim(array_node.dim) if array_node.dim else 0
|
|
5385
|
+
if (
|
|
5386
|
+
dim_val == 0
|
|
5387
|
+
and array_node is node.type
|
|
5388
|
+
and inferred_top_dim is not None
|
|
5389
|
+
):
|
|
5390
|
+
dim_val = inferred_top_dim
|
|
3155
5391
|
array_list.append(dim_val)
|
|
3156
5392
|
elem_ir_type = self._resolve_ast_type(array_next_type)
|
|
3157
5393
|
break
|
|
3158
5394
|
|
|
3159
5395
|
elif isinstance(array_next_type, c_ast.ArrayDecl):
|
|
3160
|
-
|
|
5396
|
+
dim_val = self._eval_dim(array_node.dim)
|
|
5397
|
+
if (
|
|
5398
|
+
dim_val == 0
|
|
5399
|
+
and array_node is node.type
|
|
5400
|
+
and inferred_top_dim is not None
|
|
5401
|
+
):
|
|
5402
|
+
dim_val = inferred_top_dim
|
|
5403
|
+
array_list.append(dim_val)
|
|
3161
5404
|
array_node = array_next_type
|
|
3162
5405
|
continue
|
|
3163
5406
|
elif isinstance(array_next_type, c_ast.PtrDecl):
|
|
3164
5407
|
# Array of pointers: int *arr[3]
|
|
3165
5408
|
dim = self._eval_dim(array_node.dim)
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
5409
|
+
if (
|
|
5410
|
+
dim == 0
|
|
5411
|
+
and array_node is node.type
|
|
5412
|
+
and inferred_top_dim is not None
|
|
5413
|
+
):
|
|
5414
|
+
dim = inferred_top_dim
|
|
5415
|
+
elem_ir = self._resolve_ast_type(array_next_type)
|
|
3172
5416
|
elem_ir_type = elem_ir
|
|
3173
5417
|
arr_ir = ir.ArrayType(elem_ir, dim)
|
|
3174
5418
|
arr_ir.dim_array = [dim]
|
|
@@ -3176,12 +5420,14 @@ class LLVMCodeGenerator(object):
|
|
|
3176
5420
|
var_addr = self._alloca_in_entry(arr_ir, node.name)
|
|
3177
5421
|
self.define(node.name, (arr_ir, var_addr))
|
|
3178
5422
|
else:
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
5423
|
+
var_addr, write_initializer = self._prepare_file_scope_object(
|
|
5424
|
+
node.name,
|
|
5425
|
+
arr_ir,
|
|
5426
|
+
storage=node.storage,
|
|
5427
|
+
has_initializer=node.init is not None,
|
|
5428
|
+
)
|
|
5429
|
+
if var_addr is None:
|
|
5430
|
+
return None, None
|
|
3185
5431
|
var_ir_type = arr_ir
|
|
3186
5432
|
break
|
|
3187
5433
|
else:
|
|
@@ -3195,47 +5441,19 @@ class LLVMCodeGenerator(object):
|
|
|
3195
5441
|
if not self.in_global:
|
|
3196
5442
|
var_addr = self._alloca_in_entry(var_ir_type, node.name)
|
|
3197
5443
|
else:
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
5444
|
+
var_addr, write_initializer = self._prepare_file_scope_object(
|
|
5445
|
+
node.name,
|
|
5446
|
+
var_ir_type,
|
|
5447
|
+
storage=node.storage,
|
|
5448
|
+
has_initializer=node.init is not None,
|
|
5449
|
+
)
|
|
5450
|
+
if var_addr is None:
|
|
5451
|
+
return None, None
|
|
3205
5452
|
self.define(node.name, (var_ir_type, var_addr))
|
|
3206
5453
|
|
|
3207
5454
|
if self._has_unsigned_scalar_pointee(node.type):
|
|
3208
5455
|
self._mark_unsigned_pointee(var_addr)
|
|
3209
5456
|
|
|
3210
|
-
# Infer the size of zero-length arrays from the initializer.
|
|
3211
|
-
if (
|
|
3212
|
-
isinstance(var_ir_type, ir.ArrayType)
|
|
3213
|
-
and var_ir_type.count == 0
|
|
3214
|
-
and node.init is not None
|
|
3215
|
-
):
|
|
3216
|
-
actual_count = None
|
|
3217
|
-
if isinstance(node.init, c_ast.InitList):
|
|
3218
|
-
actual_count = len(node.init.exprs)
|
|
3219
|
-
elif (
|
|
3220
|
-
isinstance(node.init, c_ast.Constant)
|
|
3221
|
-
and getattr(node.init, "type", None) == "string"
|
|
3222
|
-
):
|
|
3223
|
-
raw = node.init.value[1:-1]
|
|
3224
|
-
actual_count = len(self._process_escapes(raw)) + 1
|
|
3225
|
-
if actual_count is not None and elem_ir_type is not None:
|
|
3226
|
-
var_ir_type = ir.ArrayType(elem_ir_type, actual_count)
|
|
3227
|
-
var_ir_type.dim_array = [actual_count]
|
|
3228
|
-
if self.in_global:
|
|
3229
|
-
new_name = self.module.get_unique_name(node.name)
|
|
3230
|
-
var_addr = ir.GlobalVariable(self.module, var_ir_type, new_name)
|
|
3231
|
-
self.define(node.name, (var_ir_type, var_addr))
|
|
3232
|
-
if not hasattr(self, "_array_renames"):
|
|
3233
|
-
self._array_renames = {}
|
|
3234
|
-
self._array_renames[f'@"{node.name}"'] = f'@"{new_name}"'
|
|
3235
|
-
else:
|
|
3236
|
-
var_addr = self._alloca_in_entry(var_ir_type, node.name)
|
|
3237
|
-
self.define(node.name, (var_ir_type, var_addr))
|
|
3238
|
-
|
|
3239
5457
|
if self._has_unsigned_scalar_pointee(node.type):
|
|
3240
5458
|
self._mark_unsigned_pointee(var_addr)
|
|
3241
5459
|
|
|
@@ -3243,17 +5461,19 @@ class LLVMCodeGenerator(object):
|
|
|
3243
5461
|
# char s[] = "hi"; or const char *names[] = {"a", helper};
|
|
3244
5462
|
if node.init is not None:
|
|
3245
5463
|
if self.in_global:
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
5464
|
+
if write_initializer:
|
|
5465
|
+
try:
|
|
5466
|
+
const_init = self._build_const_init(node.init, var_ir_type)
|
|
5467
|
+
str(const_init)
|
|
5468
|
+
var_addr.initializer = const_init
|
|
5469
|
+
except Exception:
|
|
5470
|
+
var_addr.initializer = self._zero_initializer(var_ir_type)
|
|
3252
5471
|
elif isinstance(node.init, c_ast.InitList):
|
|
5472
|
+
self._safe_store(self._zero_initializer(var_ir_type), var_addr)
|
|
3253
5473
|
self._init_array(
|
|
3254
5474
|
var_addr,
|
|
3255
5475
|
node.init,
|
|
3256
|
-
|
|
5476
|
+
var_ir_type.element,
|
|
3257
5477
|
[ir.Constant(ir.IntType(32), 0)],
|
|
3258
5478
|
)
|
|
3259
5479
|
elif (
|
|
@@ -3262,6 +5482,7 @@ class LLVMCodeGenerator(object):
|
|
|
3262
5482
|
and isinstance(elem_ir_type, ir.IntType)
|
|
3263
5483
|
and elem_ir_type.width == 8
|
|
3264
5484
|
):
|
|
5485
|
+
self._safe_store(self._zero_initializer(var_ir_type), var_addr)
|
|
3265
5486
|
raw = self._process_escapes(node.init.value[1:-1]) + "\00"
|
|
3266
5487
|
idx0 = ir.Constant(ir.IntType(32), 0)
|
|
3267
5488
|
for i, ch in enumerate(raw[: var_ir_type.count]):
|
|
@@ -3271,7 +5492,7 @@ class LLVMCodeGenerator(object):
|
|
|
3271
5492
|
inbounds=True,
|
|
3272
5493
|
)
|
|
3273
5494
|
self.builder.store(int8_t(ord(ch)), elem_ptr)
|
|
3274
|
-
elif self.in_global:
|
|
5495
|
+
elif self.in_global and write_initializer:
|
|
3275
5496
|
var_addr.initializer = self._zero_initializer(var_ir_type)
|
|
3276
5497
|
|
|
3277
5498
|
elif isinstance(node.type, c_ast.PtrDecl):
|
|
@@ -3279,6 +5500,7 @@ class LLVMCodeGenerator(object):
|
|
|
3279
5500
|
point_level = 1
|
|
3280
5501
|
sub_node = node.type
|
|
3281
5502
|
resolved_pointee_type = None
|
|
5503
|
+
write_initializer = True
|
|
3282
5504
|
|
|
3283
5505
|
while True:
|
|
3284
5506
|
sub_next_type = sub_node.type
|
|
@@ -3290,12 +5512,16 @@ class LLVMCodeGenerator(object):
|
|
|
3290
5512
|
elif isinstance(sub_next_type.type, c_ast.Union):
|
|
3291
5513
|
resolved_pointee_type = self.codegen_Union(sub_next_type.type)
|
|
3292
5514
|
type_str = "union"
|
|
5515
|
+
elif isinstance(sub_next_type.type, c_ast.Enum):
|
|
5516
|
+
self.codegen_Enum(sub_next_type.type)
|
|
5517
|
+
resolved_pointee_type = int32_t
|
|
5518
|
+
type_str = "int"
|
|
3293
5519
|
else:
|
|
3294
5520
|
type_str = sub_next_type.type.names
|
|
3295
5521
|
resolved = self._get_ir_type(type_str)
|
|
3296
5522
|
if isinstance(resolved, ir.Type):
|
|
3297
5523
|
resolved_pointee_type = resolved
|
|
3298
|
-
if
|
|
5524
|
+
if _is_struct_ir_type(resolved):
|
|
3299
5525
|
type_str = "struct"
|
|
3300
5526
|
break
|
|
3301
5527
|
elif isinstance(sub_next_type, c_ast.PtrDecl):
|
|
@@ -3309,19 +5535,40 @@ class LLVMCodeGenerator(object):
|
|
|
3309
5535
|
var_addr = self._alloca_in_entry(func_ir_type, node.name)
|
|
3310
5536
|
self.define(node.name, (func_ir_type, var_addr))
|
|
3311
5537
|
else:
|
|
3312
|
-
var_addr =
|
|
3313
|
-
|
|
5538
|
+
var_addr, write_initializer = self._prepare_file_scope_object(
|
|
5539
|
+
node.name,
|
|
5540
|
+
func_ir_type,
|
|
5541
|
+
storage=node.storage,
|
|
5542
|
+
has_initializer=node.init is not None,
|
|
3314
5543
|
)
|
|
3315
|
-
var_addr
|
|
3316
|
-
|
|
5544
|
+
if var_addr is None:
|
|
5545
|
+
return None, None
|
|
3317
5546
|
if self._func_decl_returns_unsigned(sub_next_type):
|
|
3318
5547
|
self._mark_unsigned_return(var_addr)
|
|
3319
5548
|
if node.init is not None:
|
|
3320
5549
|
init_val, _ = self.codegen(node.init)
|
|
3321
|
-
#
|
|
3322
|
-
if
|
|
3323
|
-
|
|
3324
|
-
|
|
5550
|
+
# For global scope, set as initializer directly
|
|
5551
|
+
if self.in_global and isinstance(var_addr, ir.GlobalVariable):
|
|
5552
|
+
# NULL (i64 0) → null pointer of correct type
|
|
5553
|
+
if (isinstance(init_val.type, ir.IntType)
|
|
5554
|
+
and isinstance(init_val, ir.Constant)
|
|
5555
|
+
and init_val.constant == 0):
|
|
5556
|
+
init_val = ir.Constant(
|
|
5557
|
+
var_addr.value_type, None
|
|
5558
|
+
)
|
|
5559
|
+
var_addr.initializer = init_val
|
|
5560
|
+
else:
|
|
5561
|
+
if (
|
|
5562
|
+
isinstance(init_val, ir.Constant)
|
|
5563
|
+
and isinstance(init_val.type, ir.IntType)
|
|
5564
|
+
and init_val.constant == 0
|
|
5565
|
+
):
|
|
5566
|
+
init_val = ir.Constant(func_ir_type, None)
|
|
5567
|
+
elif init_val.type != func_ir_type:
|
|
5568
|
+
init_val = self._implicit_convert(
|
|
5569
|
+
init_val, func_ir_type
|
|
5570
|
+
)
|
|
5571
|
+
self._safe_store(init_val, var_addr)
|
|
3325
5572
|
return None, var_addr
|
|
3326
5573
|
pass
|
|
3327
5574
|
|
|
@@ -3335,38 +5582,61 @@ class LLVMCodeGenerator(object):
|
|
|
3335
5582
|
var_addr = self._alloca_in_entry(ir_type, node.name)
|
|
3336
5583
|
self.define(node.name, (ir_type, var_addr))
|
|
3337
5584
|
else:
|
|
3338
|
-
var_addr =
|
|
3339
|
-
|
|
5585
|
+
var_addr, write_initializer = self._prepare_file_scope_object(
|
|
5586
|
+
node.name,
|
|
5587
|
+
ir_type,
|
|
5588
|
+
storage=node.storage,
|
|
5589
|
+
has_initializer=node.init is not None,
|
|
5590
|
+
)
|
|
5591
|
+
if var_addr is None:
|
|
5592
|
+
return None, None
|
|
3340
5593
|
var_ir_type = ir_type
|
|
3341
5594
|
else:
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
5595
|
+
if self.in_global:
|
|
5596
|
+
pointee_ir_type = get_ir_type(type_str)
|
|
5597
|
+
if isinstance(pointee_ir_type, ir.VoidType):
|
|
5598
|
+
pointee_ir_type = int8_t
|
|
5599
|
+
for _ in range(point_level):
|
|
5600
|
+
pointee_ir_type = ir.PointerType(pointee_ir_type)
|
|
5601
|
+
var_ir_type = pointee_ir_type
|
|
5602
|
+
var_addr, write_initializer = self._prepare_file_scope_object(
|
|
5603
|
+
node.name,
|
|
5604
|
+
var_ir_type,
|
|
5605
|
+
storage=node.storage,
|
|
5606
|
+
has_initializer=node.init is not None,
|
|
5607
|
+
)
|
|
5608
|
+
if var_addr is None:
|
|
5609
|
+
return None, None
|
|
5610
|
+
else:
|
|
5611
|
+
var_addr, var_ir_type = self.create_entry_block_alloca(
|
|
5612
|
+
node.name,
|
|
5613
|
+
type_str,
|
|
5614
|
+
1,
|
|
5615
|
+
point_level=point_level,
|
|
5616
|
+
storage=node.storage,
|
|
5617
|
+
)
|
|
3345
5618
|
|
|
3346
5619
|
if self._has_unsigned_scalar_pointee(node.type):
|
|
3347
5620
|
self._mark_unsigned_pointee(var_addr)
|
|
3348
5621
|
|
|
3349
5622
|
if node.init is not None:
|
|
3350
5623
|
if self.in_global:
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
5624
|
+
if write_initializer:
|
|
5625
|
+
try:
|
|
5626
|
+
const_init = self._build_const_init(node.init, var_ir_type)
|
|
5627
|
+
str(const_init)
|
|
5628
|
+
var_addr.initializer = const_init
|
|
5629
|
+
except Exception:
|
|
5630
|
+
var_addr.initializer = ir.Constant(var_ir_type, None)
|
|
3357
5631
|
else:
|
|
3358
5632
|
init_val, _ = self.codegen(node.init)
|
|
5633
|
+
init_val = self._decay_array_expr_to_pointer(
|
|
5634
|
+
node.init, init_val, f"{node.name}.initdecay"
|
|
5635
|
+
)
|
|
3359
5636
|
if isinstance(init_val.type, ir.ArrayType) and isinstance(
|
|
3360
5637
|
var_ir_type, ir.PointerType
|
|
3361
5638
|
):
|
|
3362
|
-
|
|
3363
|
-
self.module,
|
|
3364
|
-
init_val.type,
|
|
3365
|
-
self.module.get_unique_name("str"),
|
|
3366
|
-
)
|
|
3367
|
-
gv.initializer = init_val
|
|
3368
|
-
gv.global_constant = True
|
|
3369
|
-
init_val = self.builder.bitcast(gv, var_ir_type)
|
|
5639
|
+
init_val = self._implicit_convert(init_val, var_ir_type)
|
|
3370
5640
|
elif init_val.type != var_ir_type:
|
|
3371
5641
|
init_val = self._implicit_convert(init_val, var_ir_type)
|
|
3372
5642
|
self._safe_store(init_val, var_addr)
|
|
@@ -3376,6 +5646,14 @@ class LLVMCodeGenerator(object):
|
|
|
3376
5646
|
return None, var_addr
|
|
3377
5647
|
|
|
3378
5648
|
def codegen_ID(self, node):
|
|
5649
|
+
if node.name in {"__func__", "__FUNCTION__", "__PRETTY_FUNCTION__"}:
|
|
5650
|
+
func_name = self._function_display_name or (
|
|
5651
|
+
self.function.name if self.function is not None else node.name
|
|
5652
|
+
)
|
|
5653
|
+
gv = self._make_global_string_constant(func_name, name_hint="funcname")
|
|
5654
|
+
ptr = self._const_pointer_to_first_elem(gv, cstring)
|
|
5655
|
+
node.ir_type = cstring
|
|
5656
|
+
return ptr, gv
|
|
3379
5657
|
|
|
3380
5658
|
valtype, var = self.lookup(node.name)
|
|
3381
5659
|
node.ir_type = valtype
|
|
@@ -3462,7 +5740,7 @@ class LLVMCodeGenerator(object):
|
|
|
3462
5740
|
# Non-array type (opaque struct etc): treat as pointer subscript
|
|
3463
5741
|
if not isinstance(name_type, ir.ArrayType):
|
|
3464
5742
|
ptr = (
|
|
3465
|
-
self.
|
|
5743
|
+
self._implicit_convert(name_ir, ir.PointerType(int8_t))
|
|
3466
5744
|
if not isinstance(name_ir.type, ir.PointerType)
|
|
3467
5745
|
else name_ir
|
|
3468
5746
|
)
|
|
@@ -3545,22 +5823,30 @@ class LLVMCodeGenerator(object):
|
|
|
3545
5823
|
retval, _ = self.codegen(node.expr)
|
|
3546
5824
|
# Implicit convert to function return type
|
|
3547
5825
|
func_ret_type = self.function.return_value.type
|
|
5826
|
+
if isinstance(func_ret_type, ir.VoidType):
|
|
5827
|
+
self.builder.ret_void()
|
|
5828
|
+
return None, None
|
|
3548
5829
|
if retval.type != func_ret_type:
|
|
3549
5830
|
retval = self._implicit_convert(retval, func_ret_type)
|
|
3550
5831
|
self.builder.ret(retval)
|
|
3551
5832
|
return None, None
|
|
3552
5833
|
|
|
3553
5834
|
def codegen_Compound(self, node):
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
5835
|
+
return self._codegen_compound_items(node, use_new_scope=True)
|
|
5836
|
+
|
|
5837
|
+
def _codegen_compound_items(self, node, use_new_scope):
|
|
5838
|
+
scope = self.new_scope() if use_new_scope else nullcontext()
|
|
5839
|
+
|
|
5840
|
+
with scope:
|
|
5841
|
+
if node.block_items:
|
|
5842
|
+
for stmt in node.block_items:
|
|
5843
|
+
if self.builder and self.builder.block.is_terminated:
|
|
5844
|
+
# After a terminator (goto/break/continue/return),
|
|
5845
|
+
# only process labels — skip unreachable code
|
|
5846
|
+
if isinstance(stmt, c_ast.Label):
|
|
5847
|
+
self.codegen(stmt)
|
|
5848
|
+
continue
|
|
5849
|
+
self.codegen(stmt)
|
|
3564
5850
|
return None, None
|
|
3565
5851
|
|
|
3566
5852
|
def codegen_FuncDecl(self, node):
|
|
@@ -3574,38 +5860,56 @@ class LLVMCodeGenerator(object):
|
|
|
3574
5860
|
ir_type, _ = self.codegen(node.decl.type)
|
|
3575
5861
|
funcname = node.decl.name
|
|
3576
5862
|
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
5863
|
+
self.return_type = ir_type # for call in C
|
|
5864
|
+
if not hasattr(self, "func_return_types"):
|
|
5865
|
+
self.func_return_types = {}
|
|
5866
|
+
self.func_return_types[funcname] = ir_type
|
|
5867
|
+
|
|
5868
|
+
param_infos, is_var_arg = self._funcdef_param_infos(node)
|
|
5869
|
+
arg_types = [param_type for _name, param_type, _decl in param_infos]
|
|
5870
|
+
|
|
5871
|
+
function_type = ir.FunctionType(ir_type, arg_types, var_arg=is_var_arg)
|
|
5872
|
+
prior_state = self._file_scope_function_states.get(funcname)
|
|
5873
|
+
if node.param_decls and prior_state is not None:
|
|
5874
|
+
prior_decl = self.module.globals.get(prior_state.symbol_name)
|
|
5875
|
+
if isinstance(prior_decl, ir.Function):
|
|
5876
|
+
prior_type = prior_decl.function_type
|
|
5877
|
+
if self._function_arg_types_match(prior_type.args, arg_types):
|
|
5878
|
+
function_type = prior_type
|
|
5879
|
+
symbol_name = self._register_file_scope_function(
|
|
5880
|
+
funcname,
|
|
5881
|
+
function_type,
|
|
5882
|
+
storage=node.decl.storage,
|
|
5883
|
+
funcspec=node.decl.funcspec,
|
|
5884
|
+
is_definition=True,
|
|
5885
|
+
)
|
|
5886
|
+
function_state = self._file_scope_function_states.get(funcname)
|
|
5887
|
+
needs_internal_linkage = (
|
|
5888
|
+
function_state is not None and function_state.linkage == "internal"
|
|
5889
|
+
)
|
|
3590
5890
|
|
|
3591
5891
|
with self.new_function():
|
|
5892
|
+
self._function_display_name = funcname
|
|
3592
5893
|
|
|
3593
|
-
existing = self.module.globals.get(
|
|
5894
|
+
existing = self.module.globals.get(symbol_name)
|
|
3594
5895
|
if existing and isinstance(existing, ir.Function):
|
|
3595
5896
|
if existing.is_declaration:
|
|
3596
5897
|
self.function = existing
|
|
5898
|
+
if needs_internal_linkage:
|
|
5899
|
+
self.function.linkage = "internal"
|
|
3597
5900
|
else:
|
|
3598
|
-
|
|
3599
|
-
return None, None
|
|
5901
|
+
raise SemanticError(f"redefinition of function '{funcname}'")
|
|
3600
5902
|
else:
|
|
3601
5903
|
try:
|
|
3602
5904
|
self.function = ir.Function(
|
|
3603
5905
|
self.module,
|
|
3604
|
-
|
|
3605
|
-
name=
|
|
5906
|
+
function_type,
|
|
5907
|
+
name=symbol_name,
|
|
3606
5908
|
)
|
|
5909
|
+
if needs_internal_linkage:
|
|
5910
|
+
self.function.linkage = "internal"
|
|
3607
5911
|
except Exception:
|
|
3608
|
-
|
|
5912
|
+
raise SemanticError(f"failed to define function '{funcname}'")
|
|
3609
5913
|
if self._func_decl_returns_unsigned(node.decl.type):
|
|
3610
5914
|
self._mark_unsigned_return(self.function)
|
|
3611
5915
|
self.block = self.function.append_basic_block()
|
|
@@ -3613,53 +5917,38 @@ class LLVMCodeGenerator(object):
|
|
|
3613
5917
|
if len(self.env.maps) > 1:
|
|
3614
5918
|
self.env.maps[1][funcname] = (ir_type, self.function)
|
|
3615
5919
|
self.define(funcname, (ir_type, self.function))
|
|
3616
|
-
|
|
3617
|
-
param_idx
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
)
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
self.define(pname, (arg_type, var))
|
|
3635
|
-
self._safe_store(self.function.args[param_idx], var)
|
|
3636
|
-
# Track unsigned params
|
|
3637
|
-
if isinstance(p, c_ast.Decl) and isinstance(
|
|
3638
|
-
getattr(p, "type", None), c_ast.TypeDecl
|
|
5920
|
+
for param_idx, (pname, arg_type, p) in enumerate(param_infos):
|
|
5921
|
+
if param_idx >= len(arg_types):
|
|
5922
|
+
break
|
|
5923
|
+
var = self._alloca_in_entry(arg_type, pname)
|
|
5924
|
+
self.define(pname, (arg_type, var))
|
|
5925
|
+
self._safe_store(self.function.args[param_idx], var)
|
|
5926
|
+
# Track unsigned params
|
|
5927
|
+
if isinstance(p, c_ast.Decl) and isinstance(
|
|
5928
|
+
getattr(p, "type", None), c_ast.TypeDecl
|
|
5929
|
+
):
|
|
5930
|
+
if isinstance(p.type.type, c_ast.IdentifierType):
|
|
5931
|
+
if self._is_unsigned_type_names(p.type.type.names):
|
|
5932
|
+
self._mark_unsigned(var)
|
|
5933
|
+
if isinstance(p, c_ast.Decl):
|
|
5934
|
+
if self._has_unsigned_scalar_pointee(p.type):
|
|
5935
|
+
self._mark_unsigned_pointee(var)
|
|
5936
|
+
if isinstance(p.type, c_ast.PtrDecl) and self._func_decl_returns_unsigned(
|
|
5937
|
+
p.type.type
|
|
3639
5938
|
):
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
p.type, c_ast.PtrDecl
|
|
3648
|
-
) and self._func_decl_returns_unsigned(p.type.type):
|
|
3649
|
-
self._mark_unsigned_return(var)
|
|
3650
|
-
param_idx += 1
|
|
3651
|
-
|
|
3652
|
-
self.codegen(node.body)
|
|
5939
|
+
self._mark_unsigned_return(var)
|
|
5940
|
+
|
|
5941
|
+
for _pname, _arg_type, p in param_infos:
|
|
5942
|
+
if isinstance(p, c_ast.Decl):
|
|
5943
|
+
self._emit_vla_param_bound_side_effects(p.type)
|
|
5944
|
+
|
|
5945
|
+
self._codegen_compound_items(node.body, use_new_scope=False)
|
|
3653
5946
|
|
|
3654
5947
|
if not self.builder.block.is_terminated:
|
|
3655
5948
|
if isinstance(ir_type, ir.VoidType):
|
|
3656
5949
|
self.builder.ret_void()
|
|
3657
|
-
elif isinstance(ir_type, ir.PointerType):
|
|
3658
|
-
self.builder.ret(ir.Constant(ir_type, None))
|
|
3659
|
-
elif self._is_floating_ir_type(ir_type):
|
|
3660
|
-
self.builder.ret(ir.Constant(ir_type, 0.0))
|
|
3661
5950
|
else:
|
|
3662
|
-
self.builder.ret(
|
|
5951
|
+
self.builder.ret(self._zero_initializer(ir_type))
|
|
3663
5952
|
|
|
3664
5953
|
return None, None
|
|
3665
5954
|
|
|
@@ -3667,63 +5956,58 @@ class LLVMCodeGenerator(object):
|
|
|
3667
5956
|
# Generate LLVM types for struct members
|
|
3668
5957
|
|
|
3669
5958
|
# If this is a reference to a named struct without decls, look it up
|
|
3670
|
-
if node.name and
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
opaque =
|
|
3675
|
-
|
|
5959
|
+
if node.name and node.decls is None:
|
|
5960
|
+
tag_key = self._tag_type_key(node.name)
|
|
5961
|
+
if tag_key in self.env:
|
|
5962
|
+
return self.env[tag_key][0]
|
|
5963
|
+
opaque = self.module.context.get_identified_type(
|
|
5964
|
+
self._aggregate_type_name("struct", node.name)
|
|
5965
|
+
)
|
|
5966
|
+
self.define(tag_key, (opaque, None))
|
|
3676
5967
|
return opaque
|
|
3677
5968
|
|
|
5969
|
+
if any(decl.bitsize is not None for decl in node.decls):
|
|
5970
|
+
return self._build_layout_backed_struct(node)
|
|
5971
|
+
|
|
3678
5972
|
member_types = []
|
|
3679
5973
|
member_names = []
|
|
3680
5974
|
member_decl_types = []
|
|
3681
5975
|
for decl in node.decls:
|
|
3682
|
-
|
|
3683
|
-
decl.type.type, c_ast.Struct
|
|
3684
|
-
):
|
|
3685
|
-
nested_type = self.codegen_Struct(decl.type.type)
|
|
3686
|
-
member_types.append(nested_type)
|
|
3687
|
-
elif isinstance(decl.type, c_ast.TypeDecl) and isinstance(
|
|
3688
|
-
decl.type.type, c_ast.Union
|
|
3689
|
-
):
|
|
3690
|
-
nested_type = self.codegen_Union(decl.type.type)
|
|
3691
|
-
member_types.append(nested_type)
|
|
3692
|
-
elif isinstance(decl.type, c_ast.ArrayDecl):
|
|
3693
|
-
# Handle multi-dimensional arrays: a[N][M] -> [N x [M x T]]
|
|
3694
|
-
def _build_array_type(arr_node):
|
|
3695
|
-
dim = self._eval_dim(arr_node.dim) if arr_node.dim else 0
|
|
3696
|
-
if isinstance(arr_node.type, c_ast.ArrayDecl):
|
|
3697
|
-
inner = _build_array_type(arr_node.type)
|
|
3698
|
-
else:
|
|
3699
|
-
inner = self._resolve_ast_type(arr_node.type)
|
|
3700
|
-
return ir.ArrayType(inner, dim)
|
|
3701
|
-
|
|
3702
|
-
member_types.append(_build_array_type(decl.type))
|
|
3703
|
-
elif isinstance(decl.type, c_ast.PtrDecl):
|
|
3704
|
-
member_types.append(self._resolve_ast_type(decl.type))
|
|
3705
|
-
elif isinstance(decl.type, c_ast.TypeDecl):
|
|
3706
|
-
type_str = decl.type.type.names
|
|
3707
|
-
member_types.append(self._get_ir_type(type_str))
|
|
3708
|
-
else:
|
|
3709
|
-
member_types.append(int64_t) # fallback
|
|
5976
|
+
member_types.append(self._resolve_struct_member_ir_type(decl))
|
|
3710
5977
|
member_names.append(decl.name)
|
|
3711
5978
|
member_decl_types.append(decl.type)
|
|
3712
5979
|
# Create the struct type
|
|
3713
|
-
struct_type =
|
|
5980
|
+
struct_type = self._identified_aggregate_type("struct", node.name, member_types)
|
|
3714
5981
|
struct_type.members = member_names
|
|
3715
5982
|
struct_type.member_decl_types = member_decl_types
|
|
3716
5983
|
|
|
3717
5984
|
# Register named structs for later reuse
|
|
3718
5985
|
if node.name:
|
|
3719
|
-
self.define(node.name, (struct_type, None))
|
|
5986
|
+
self.define(self._tag_type_key(node.name), (struct_type, None))
|
|
3720
5987
|
|
|
3721
5988
|
return struct_type
|
|
3722
5989
|
|
|
3723
5990
|
def codegen_Union(self, node):
|
|
3724
5991
|
"""Model union as a struct with alignment-preserving storage."""
|
|
3725
|
-
if node.name and
|
|
3726
|
-
|
|
5992
|
+
if node.name and node.decls is None:
|
|
5993
|
+
tag_key = self._tag_type_key(node.name)
|
|
5994
|
+
if tag_key in self.env:
|
|
5995
|
+
return self.env[tag_key][0]
|
|
5996
|
+
opaque = self.module.context.get_identified_type(
|
|
5997
|
+
self._aggregate_type_name("union", node.name)
|
|
5998
|
+
)
|
|
5999
|
+
self.define(tag_key, (opaque, None))
|
|
6000
|
+
return opaque
|
|
6001
|
+
|
|
6002
|
+
if node.decls is not None and len(node.decls) == 0:
|
|
6003
|
+
union_type = self._identified_aggregate_type("union", node.name, [])
|
|
6004
|
+
union_type.members = []
|
|
6005
|
+
union_type.member_types = {}
|
|
6006
|
+
union_type.member_decl_types = {}
|
|
6007
|
+
union_type.is_union = True
|
|
6008
|
+
if node.name:
|
|
6009
|
+
self.define(self._tag_type_key(node.name), (union_type, None))
|
|
6010
|
+
return union_type
|
|
3727
6011
|
|
|
3728
6012
|
member_types = {}
|
|
3729
6013
|
member_decl_types = {}
|
|
@@ -3750,18 +6034,17 @@ class LLVMCodeGenerator(object):
|
|
|
3750
6034
|
align_size = max_align
|
|
3751
6035
|
pad_size = max_size - align_size
|
|
3752
6036
|
if pad_size > 0:
|
|
3753
|
-
|
|
3754
|
-
[align_type, ir.ArrayType(int8_t, pad_size)]
|
|
3755
|
-
)
|
|
6037
|
+
union_body = [align_type, ir.ArrayType(int8_t, pad_size)]
|
|
3756
6038
|
else:
|
|
3757
|
-
|
|
6039
|
+
union_body = [align_type]
|
|
6040
|
+
union_type = self._identified_aggregate_type("union", node.name, union_body)
|
|
3758
6041
|
union_type.members = list(member_types.keys())
|
|
3759
6042
|
union_type.member_types = member_types
|
|
3760
6043
|
union_type.member_decl_types = member_decl_types
|
|
3761
6044
|
union_type.is_union = True
|
|
3762
6045
|
|
|
3763
6046
|
if node.name:
|
|
3764
|
-
self.define(node.name, (union_type, None))
|
|
6047
|
+
self.define(self._tag_type_key(node.name), (union_type, None))
|
|
3765
6048
|
|
|
3766
6049
|
return union_type
|
|
3767
6050
|
|
|
@@ -3805,7 +6088,7 @@ class LLVMCodeGenerator(object):
|
|
|
3805
6088
|
)
|
|
3806
6089
|
struct_addr = inner_addr
|
|
3807
6090
|
elif isinstance(node.name, c_ast.ID):
|
|
3808
|
-
struct_instance_addr = self.
|
|
6091
|
+
_, struct_instance_addr = self.lookup(node.name.name)
|
|
3809
6092
|
if not isinstance(struct_instance_addr.type, ir.PointerType):
|
|
3810
6093
|
raise Exception("Invalid struct reference")
|
|
3811
6094
|
|
|
@@ -3865,6 +6148,66 @@ class LLVMCodeGenerator(object):
|
|
|
3865
6148
|
if semantic_base_type is not None
|
|
3866
6149
|
else (val.type if hasattr(val.type, "members") else int8_t)
|
|
3867
6150
|
)
|
|
6151
|
+
if (
|
|
6152
|
+
addr is None
|
|
6153
|
+
and not isinstance(getattr(struct_addr, "type", None), ir.PointerType)
|
|
6154
|
+
and (
|
|
6155
|
+
getattr(struct_type, "has_custom_layout", False)
|
|
6156
|
+
or _is_struct_ir_type(struct_type)
|
|
6157
|
+
)
|
|
6158
|
+
):
|
|
6159
|
+
materialized = self._alloca_in_entry(val.type, "structrval")
|
|
6160
|
+
self._safe_store(val, materialized)
|
|
6161
|
+
struct_addr = materialized
|
|
6162
|
+
|
|
6163
|
+
if getattr(struct_type, "has_custom_layout", False):
|
|
6164
|
+
layout = struct_type.field_layouts.get(node.field.name)
|
|
6165
|
+
if layout is None:
|
|
6166
|
+
raise RuntimeError(f"Field '{node.field.name}' not found in struct")
|
|
6167
|
+
|
|
6168
|
+
if layout.is_bitfield:
|
|
6169
|
+
container_ptr = self._byte_offset_ptr(
|
|
6170
|
+
struct_addr,
|
|
6171
|
+
layout.storage_byte_offset,
|
|
6172
|
+
ir.PointerType(layout.storage_ir_type),
|
|
6173
|
+
name="bitfieldptr",
|
|
6174
|
+
)
|
|
6175
|
+
ref = BitFieldRef(
|
|
6176
|
+
container_ptr=container_ptr,
|
|
6177
|
+
storage_ir_type=layout.storage_ir_type,
|
|
6178
|
+
bit_offset=layout.bit_offset,
|
|
6179
|
+
bit_width=layout.bit_width,
|
|
6180
|
+
semantic_ir_type=layout.semantic_ir_type,
|
|
6181
|
+
is_unsigned=layout.is_unsigned,
|
|
6182
|
+
)
|
|
6183
|
+
val = self._load_bitfield(ref)
|
|
6184
|
+
if layout.decl_type is not None:
|
|
6185
|
+
self._tag_value_from_decl_type(val, layout.decl_type)
|
|
6186
|
+
self._set_expr_ir_type(node, layout.semantic_ir_type)
|
|
6187
|
+
return val, ref
|
|
6188
|
+
|
|
6189
|
+
typed_field_addr = self._byte_offset_ptr(
|
|
6190
|
+
struct_addr,
|
|
6191
|
+
layout.byte_offset,
|
|
6192
|
+
ir.PointerType(layout.semantic_ir_type),
|
|
6193
|
+
name="fieldptr",
|
|
6194
|
+
)
|
|
6195
|
+
if isinstance(layout.semantic_ir_type, ir.ArrayType):
|
|
6196
|
+
elem_ptr = self.builder.gep(
|
|
6197
|
+
typed_field_addr,
|
|
6198
|
+
[ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)],
|
|
6199
|
+
name="arraydecay",
|
|
6200
|
+
)
|
|
6201
|
+
if layout.decl_type is not None:
|
|
6202
|
+
self._tag_value_from_decl_type(elem_ptr, layout.decl_type)
|
|
6203
|
+
self._set_expr_ir_type(node, layout.semantic_ir_type)
|
|
6204
|
+
return elem_ptr, typed_field_addr
|
|
6205
|
+
|
|
6206
|
+
field_value = self._safe_load(typed_field_addr)
|
|
6207
|
+
if layout.decl_type is not None:
|
|
6208
|
+
self._tag_value_from_decl_type(field_value, layout.decl_type)
|
|
6209
|
+
self._set_expr_ir_type(node, layout.semantic_ir_type)
|
|
6210
|
+
return field_value, typed_field_addr
|
|
3868
6211
|
|
|
3869
6212
|
# Union access: all fields share offset 0, use bitcast
|
|
3870
6213
|
if getattr(struct_type, "is_union", False):
|
|
@@ -3880,8 +6223,8 @@ class LLVMCodeGenerator(object):
|
|
|
3880
6223
|
resolved, ir.PointerType
|
|
3881
6224
|
):
|
|
3882
6225
|
pass
|
|
3883
|
-
elif isinstance(
|
|
3884
|
-
resolved
|
|
6226
|
+
elif isinstance(resolved, (ir.ArrayType, ir.PointerType)) or _is_struct_ir_type(
|
|
6227
|
+
resolved
|
|
3885
6228
|
):
|
|
3886
6229
|
semantic_field_type = resolved
|
|
3887
6230
|
except Exception:
|
|
@@ -3905,10 +6248,9 @@ class LLVMCodeGenerator(object):
|
|
|
3905
6248
|
|
|
3906
6249
|
# Opaque struct (no members) — treat as byte-offset access
|
|
3907
6250
|
if not hasattr(struct_type, "members"):
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
return val, ptr
|
|
6251
|
+
raise SemanticError(
|
|
6252
|
+
f"field '{node.field.name}' accessed on incomplete struct"
|
|
6253
|
+
)
|
|
3912
6254
|
|
|
3913
6255
|
field_index = None
|
|
3914
6256
|
for i, field in enumerate(struct_type.members):
|
|
@@ -3939,7 +6281,9 @@ class LLVMCodeGenerator(object):
|
|
|
3939
6281
|
resolved, ir.PointerType
|
|
3940
6282
|
):
|
|
3941
6283
|
pass # keep original array type
|
|
3942
|
-
elif isinstance(resolved,
|
|
6284
|
+
elif isinstance(resolved, ir.PointerType) or _is_struct_ir_type(
|
|
6285
|
+
resolved
|
|
6286
|
+
):
|
|
3943
6287
|
semantic_field_type = resolved
|
|
3944
6288
|
except Exception:
|
|
3945
6289
|
pass
|
|
@@ -4023,16 +6367,35 @@ class LLVMCodeGenerator(object):
|
|
|
4023
6367
|
if enumerator.value:
|
|
4024
6368
|
current_val = self._eval_const_expr(enumerator.value)
|
|
4025
6369
|
self.define(
|
|
4026
|
-
enumerator.name, (
|
|
6370
|
+
enumerator.name, (int32_t, ir.Constant(int32_t, current_val))
|
|
4027
6371
|
)
|
|
4028
6372
|
current_val += 1
|
|
4029
6373
|
return None, None
|
|
4030
6374
|
|
|
4031
6375
|
def _eval_const_expr(self, node):
|
|
4032
6376
|
"""Evaluate a constant expression at compile time (for enum values)."""
|
|
6377
|
+
def is_float_value(value):
|
|
6378
|
+
return isinstance(value, float)
|
|
6379
|
+
|
|
6380
|
+
def c_int_div(lhs, rhs):
|
|
6381
|
+
return int(lhs / rhs)
|
|
6382
|
+
|
|
6383
|
+
def c_int_mod(lhs, rhs):
|
|
6384
|
+
return lhs - c_int_div(lhs, rhs) * rhs
|
|
6385
|
+
|
|
6386
|
+
def c_float_div(lhs, rhs):
|
|
6387
|
+
if rhs == 0.0:
|
|
6388
|
+
if lhs == 0.0:
|
|
6389
|
+
return float("nan")
|
|
6390
|
+
sign = math.copysign(1.0, lhs) * math.copysign(1.0, rhs)
|
|
6391
|
+
return math.copysign(float("inf"), sign)
|
|
6392
|
+
return lhs / rhs
|
|
6393
|
+
|
|
4033
6394
|
if isinstance(node, c_ast.Constant):
|
|
4034
6395
|
if node.type == "string":
|
|
4035
6396
|
return 0 # string constants can't be int-evaluated
|
|
6397
|
+
if node.type in ("float", "double"):
|
|
6398
|
+
return self._parse_float_constant(node.value)
|
|
4036
6399
|
v = node.value.rstrip("uUlL")
|
|
4037
6400
|
if v.startswith("'"):
|
|
4038
6401
|
return self._char_constant_value(v)
|
|
@@ -4053,8 +6416,8 @@ class LLVMCodeGenerator(object):
|
|
|
4053
6416
|
raw = node.expr.value[1:-1]
|
|
4054
6417
|
processed = self._process_escapes(raw)
|
|
4055
6418
|
return len(self._string_bytes(processed + "\00"))
|
|
4056
|
-
|
|
4057
|
-
return
|
|
6419
|
+
ir_t = self._infer_sizeof_operand_ir_type(node.expr)
|
|
6420
|
+
return self._ir_type_size(ir_t)
|
|
4058
6421
|
if node.op == "&" and isinstance(node.expr, c_ast.StructRef):
|
|
4059
6422
|
offset, _ = self._eval_offsetof_structref(node.expr)
|
|
4060
6423
|
return offset
|
|
@@ -4070,12 +6433,13 @@ class LLVMCodeGenerator(object):
|
|
|
4070
6433
|
elif isinstance(node, c_ast.BinaryOp):
|
|
4071
6434
|
l = self._eval_const_expr(node.left)
|
|
4072
6435
|
r = self._eval_const_expr(node.right)
|
|
6436
|
+
use_float = is_float_value(l) or is_float_value(r)
|
|
4073
6437
|
ops = {
|
|
4074
6438
|
"+": lambda a, b: a + b,
|
|
4075
6439
|
"-": lambda a, b: a - b,
|
|
4076
6440
|
"*": lambda a, b: a * b,
|
|
4077
|
-
"/": lambda a, b: a
|
|
4078
|
-
"%": lambda a, b: a % b,
|
|
6441
|
+
"/": lambda a, b: c_float_div(a, b) if use_float else c_int_div(a, b),
|
|
6442
|
+
"%": lambda a, b: a % b if use_float else c_int_mod(a, b),
|
|
4079
6443
|
"<<": lambda a, b: a << b,
|
|
4080
6444
|
">>": lambda a, b: a >> b,
|
|
4081
6445
|
"&": lambda a, b: a & b,
|
|
@@ -4107,6 +6471,14 @@ class LLVMCodeGenerator(object):
|
|
|
4107
6471
|
return 0 # unknown identifier defaults to 0
|
|
4108
6472
|
elif isinstance(node, c_ast.Cast):
|
|
4109
6473
|
return self._eval_const_expr(node.expr)
|
|
6474
|
+
elif isinstance(node, c_ast.FuncCall):
|
|
6475
|
+
if isinstance(node.name, c_ast.ID):
|
|
6476
|
+
callee = node.name.name
|
|
6477
|
+
if callee in ("__builtin_inf", "__builtin_inff", "__builtin_infl"):
|
|
6478
|
+
return float("inf")
|
|
6479
|
+
if callee in ("__builtin_nan", "__builtin_nanf", "__builtin_nanl"):
|
|
6480
|
+
return float("nan")
|
|
6481
|
+
raise CodegenError(f"Not a constant expression: {type(node).__name__}")
|
|
4110
6482
|
elif isinstance(node, c_ast.Typename):
|
|
4111
6483
|
return 0
|
|
4112
6484
|
raise CodegenError(f"Not a constant expression: {type(node).__name__}")
|
|
@@ -4150,7 +6522,7 @@ class LLVMCodeGenerator(object):
|
|
|
4150
6522
|
elif isinstance(node.type.type, c_ast.Enum):
|
|
4151
6523
|
# typedef enum { A, B, C } MyEnum;
|
|
4152
6524
|
self.codegen_Enum(node.type.type)
|
|
4153
|
-
self.define(f"__typedef_{node.name}",
|
|
6525
|
+
self.define(f"__typedef_{node.name}", int32_t)
|
|
4154
6526
|
elif isinstance(node.type, c_ast.ArrayDecl):
|
|
4155
6527
|
self.define(f"__typedef_{node.name}", self._build_array_ir_type(node.type))
|
|
4156
6528
|
elif isinstance(node.type, c_ast.PtrDecl):
|
|
@@ -4174,4 +6546,7 @@ class LLVMCodeGenerator(object):
|
|
|
4174
6546
|
else:
|
|
4175
6547
|
ptr_type = ir.PointerType(base_ir)
|
|
4176
6548
|
self.define(f"__typedef_{node.name}", ptr_type)
|
|
6549
|
+
elif isinstance(node.type, c_ast.FuncDecl):
|
|
6550
|
+
func_type, _ = self._build_function_ir_type(node.type)
|
|
6551
|
+
self.define(f"__typedef_{node.name}", func_type)
|
|
4177
6552
|
return None, None
|