python-cc 0.0.6__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 +2483 -470
- pcc/evaluater/c_evaluator.py +1059 -96
- pcc/lex/c_lexer.py +24 -5
- pcc/parse/c_parser.py +124 -51
- pcc/pcc.py +161 -18
- pcc/ply/yacc.py +1 -1
- pcc/project.py +842 -58
- python_cc-0.0.7.dist-info/METADATA +429 -0
- {python_cc-0.0.6.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.6.dist-info/METADATA +0 -200
- {python_cc-0.0.6.dist-info → python_cc-0.0.7.dist-info}/WHEEL +0 -0
- {python_cc-0.0.6.dist-info → python_cc-0.0.7.dist-info}/entry_points.txt +0 -0
- {python_cc-0.0.6.dist-info → python_cc-0.0.7.dist-info}/licenses/LICENSE +0 -0
pcc/codegen/c_codegen.py
CHANGED
|
@@ -1,9 +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
|
|
6
7
|
from dataclasses import dataclass
|
|
8
|
+
from itertools import count
|
|
7
9
|
from llvmlite.ir import IRBuilder
|
|
8
10
|
from ..ast import c_ast as c_ast
|
|
9
11
|
|
|
@@ -11,6 +13,7 @@ bool_t = ir.IntType(1)
|
|
|
11
13
|
int8_t = ir.IntType(8)
|
|
12
14
|
int32_t = ir.IntType(32)
|
|
13
15
|
int64_t = ir.IntType(64)
|
|
16
|
+
int128_t = ir.IntType(128)
|
|
14
17
|
voidptr_t = int8_t.as_pointer()
|
|
15
18
|
int64ptr_t = int64_t.as_pointer()
|
|
16
19
|
true_bit = bool_t(1)
|
|
@@ -19,6 +22,7 @@ true_byte = int8_t(1)
|
|
|
19
22
|
false_byte = int8_t(0)
|
|
20
23
|
cstring = voidptr_t
|
|
21
24
|
struct_types = {}
|
|
25
|
+
_aggregate_namespace_counter = count(1)
|
|
22
26
|
|
|
23
27
|
|
|
24
28
|
class SemanticError(ValueError):
|
|
@@ -31,6 +35,7 @@ class FileScopeObjectState:
|
|
|
31
35
|
linkage: str
|
|
32
36
|
definition_kind: str
|
|
33
37
|
symbol_name: str
|
|
38
|
+
ir_type: object
|
|
34
39
|
|
|
35
40
|
|
|
36
41
|
@dataclass
|
|
@@ -40,6 +45,30 @@ class FileScopeFunctionState:
|
|
|
40
45
|
defined: bool
|
|
41
46
|
symbol_name: str
|
|
42
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
|
|
71
|
+
|
|
43
72
|
# Libc function signature registry: name -> (return_type, [param_types], var_arg)
|
|
44
73
|
# Covers: stdio.h, stdlib.h, string.h, ctype.h, math.h, unistd.h, time.h
|
|
45
74
|
_VOID = ir.VoidType()
|
|
@@ -113,6 +142,15 @@ LIBC_FUNCTIONS = {
|
|
|
113
142
|
"qsort": (_VOID, [voidptr_t, _size_t, _size_t, voidptr_t], False),
|
|
114
143
|
"bsearch": (voidptr_t, [voidptr_t, voidptr_t, _size_t, _size_t, voidptr_t], False),
|
|
115
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),
|
|
116
154
|
"system": (int32_t, [cstring], False),
|
|
117
155
|
# === string.h ===
|
|
118
156
|
"strlen": (_size_t, [cstring], False),
|
|
@@ -122,6 +160,8 @@ LIBC_FUNCTIONS = {
|
|
|
122
160
|
"strncpy": (cstring, [cstring, cstring, _size_t], False),
|
|
123
161
|
"strcat": (cstring, [cstring, cstring], False),
|
|
124
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),
|
|
125
165
|
"strchr": (cstring, [cstring, int32_t], False),
|
|
126
166
|
"strrchr": (cstring, [cstring, int32_t], False),
|
|
127
167
|
"strstr": (cstring, [cstring, cstring], False),
|
|
@@ -149,6 +189,34 @@ LIBC_FUNCTIONS = {
|
|
|
149
189
|
"isgraph": (int32_t, [int32_t], False),
|
|
150
190
|
"toupper": (int32_t, [int32_t], False),
|
|
151
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),
|
|
152
220
|
# === math.h ===
|
|
153
221
|
"sin": (_double, [_double], False),
|
|
154
222
|
"cos": (_double, [_double], False),
|
|
@@ -174,7 +242,9 @@ LIBC_FUNCTIONS = {
|
|
|
174
242
|
"round": (_double, [_double], False),
|
|
175
243
|
"trunc": (_double, [_double], False),
|
|
176
244
|
"fmod": (_double, [_double, _double], False),
|
|
245
|
+
"fabsf": (_float, [_float], False),
|
|
177
246
|
"fabs": (_double, [_double], False),
|
|
247
|
+
"fabsl": (_double, [_double], False),
|
|
178
248
|
"ldexp": (_double, [_double, int32_t], False),
|
|
179
249
|
# === time.h ===
|
|
180
250
|
"time": (_time_t, [voidptr_t], False),
|
|
@@ -182,36 +252,75 @@ LIBC_FUNCTIONS = {
|
|
|
182
252
|
"difftime": (_double, [_time_t, _time_t], False),
|
|
183
253
|
"gmtime_r": (voidptr_t, [voidptr_t, voidptr_t], False),
|
|
184
254
|
"localtime_r": (voidptr_t, [voidptr_t, voidptr_t], False),
|
|
255
|
+
"nanosleep": (int32_t, [voidptr_t, voidptr_t], False),
|
|
185
256
|
# === unistd.h (POSIX) ===
|
|
186
257
|
"sleep": (int32_t, [int32_t], False),
|
|
258
|
+
"alarm": (int32_t, [int32_t], False),
|
|
187
259
|
"usleep": (int32_t, [int32_t], False),
|
|
188
260
|
"read": (int64_t, [int32_t, voidptr_t, _size_t], False),
|
|
189
261
|
"write": (int64_t, [int32_t, voidptr_t, _size_t], False),
|
|
262
|
+
"getuid": (int32_t, [], False),
|
|
263
|
+
"geteuid": (int32_t, [], False),
|
|
190
264
|
"open": (int32_t, [cstring, int32_t], True),
|
|
191
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),
|
|
192
274
|
"getpid": (int32_t, [], False),
|
|
193
275
|
"getppid": (int32_t, [], False),
|
|
276
|
+
"sysconf": (int64_t, [int32_t], False),
|
|
194
277
|
"isatty": (int32_t, [int32_t], False),
|
|
195
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),
|
|
196
285
|
# === setjmp.h ===
|
|
197
286
|
"setjmp": (int32_t, [voidptr_t], False),
|
|
198
287
|
"longjmp": (_VOID, [voidptr_t, int32_t], False),
|
|
199
288
|
"_setjmp": (int32_t, [voidptr_t], False),
|
|
200
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),
|
|
201
292
|
# === signal.h ===
|
|
202
293
|
"signal": (voidptr_t, [int32_t, voidptr_t], False),
|
|
203
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),
|
|
204
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),
|
|
205
302
|
"raise": (int32_t, [int32_t], False),
|
|
206
303
|
# === errno ===
|
|
207
304
|
"__errno_location": (ir.IntType(32).as_pointer(), [], False),
|
|
208
305
|
# === locale.h ===
|
|
209
306
|
"setlocale": (cstring, [int32_t, cstring], False),
|
|
210
307
|
"localeconv": (voidptr_t, [], False),
|
|
308
|
+
"nl_langinfo": (cstring, [int32_t], False),
|
|
211
309
|
# === misc ===
|
|
212
310
|
"tmpnam": (cstring, [cstring], False),
|
|
213
311
|
"tmpfile": (voidptr_t, [], False),
|
|
214
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),
|
|
215
324
|
"gmtime": (voidptr_t, [voidptr_t], False),
|
|
216
325
|
"localtime": (voidptr_t, [voidptr_t], False),
|
|
217
326
|
"mktime": (_time_t, [voidptr_t], False),
|
|
@@ -223,10 +332,28 @@ LIBC_FUNCTIONS = {
|
|
|
223
332
|
"__builtin_va_start": (_VOID, [voidptr_t], False),
|
|
224
333
|
"__builtin_va_end": (_VOID, [voidptr_t], False),
|
|
225
334
|
"__builtin_va_copy": (_VOID, [voidptr_t, voidptr_t], False),
|
|
335
|
+
"__builtin_alloca": (voidptr_t, [int64_t], False),
|
|
226
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),
|
|
227
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),
|
|
228
346
|
"__builtin_clz": (int32_t, [int32_t], False),
|
|
347
|
+
"__builtin_clzll": (int32_t, [int64_t], False),
|
|
229
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),
|
|
230
357
|
"modf": (_double, [_double, ir.DoubleType().as_pointer()], False),
|
|
231
358
|
"ldexp": (_double, [_double, int32_t], False),
|
|
232
359
|
"__builtin_va_arg": (voidptr_t, [voidptr_t, int64_t], False),
|
|
@@ -302,25 +429,10 @@ _PCC_VAARG_CALL_RE = re.compile(
|
|
|
302
429
|
)
|
|
303
430
|
|
|
304
431
|
|
|
305
|
-
_INVALID_VOID_INSTR_RE = re.compile(
|
|
306
|
-
r"^(?:%\S+\s*=\s*)?(?:alloca|load|bitcast) void(?! \()([,\s]|$)|^store void(?! \()([,\s]|$)"
|
|
307
|
-
)
|
|
308
|
-
|
|
309
|
-
_LABEL_RE = re.compile(r"^[A-Za-z$._][A-Za-z0-9$._-]*:$")
|
|
310
|
-
|
|
311
|
-
|
|
312
432
|
def postprocess_ir_text(text):
|
|
313
|
-
"""Apply textual
|
|
433
|
+
"""Apply the minimal textual lowering that llvmlite cannot express directly."""
|
|
314
434
|
|
|
315
|
-
# --- simple regex rewrites ---
|
|
316
435
|
text = _PCC_VAARG_DECL_RE.sub("", text)
|
|
317
|
-
text = re.sub(
|
|
318
|
-
r"bitcast i64 (%\S+) to (i8\*|[^,\n]+\*)", r"inttoptr i64 \1 to \2", text
|
|
319
|
-
)
|
|
320
|
-
text = re.sub(
|
|
321
|
-
r"bitcast i8 (%\S+) to (i8\*|[^,\n]+\*)", r"inttoptr i8 \1 to \2", text
|
|
322
|
-
)
|
|
323
|
-
text = re.sub(r"ptrtoint \[\d+ x i8\] [^\n]+ to i64", "add i64 0, 0", text)
|
|
324
436
|
|
|
325
437
|
def repl(match):
|
|
326
438
|
lhs = match.group("lhs")
|
|
@@ -330,78 +442,7 @@ def postprocess_ir_text(text):
|
|
|
330
442
|
return f"{lhs} = va_arg {argtype} {argval}, {rettype}"
|
|
331
443
|
|
|
332
444
|
text = _PCC_VAARG_CALL_RE.sub(repl, text)
|
|
333
|
-
|
|
334
|
-
# --- line-level fixups ---
|
|
335
|
-
lines = []
|
|
336
|
-
for line in text.splitlines():
|
|
337
|
-
# Fix Python repr leak in array initializers → zeroinitializer
|
|
338
|
-
if "<ir.Constant" in line:
|
|
339
|
-
m = re.match(r'(@"[^"]*"\s*=\s*(?:global|constant)\s*\[[^\]]*\]).*', line)
|
|
340
|
-
if m:
|
|
341
|
-
line = m.group(1) + " zeroinitializer"
|
|
342
|
-
else:
|
|
343
|
-
continue
|
|
344
|
-
s = line.strip()
|
|
345
|
-
# Drop invalid void instructions (alloca void, load void, store void)
|
|
346
|
-
if _INVALID_VOID_INSTR_RE.match(s):
|
|
347
|
-
continue
|
|
348
|
-
lines.append(line)
|
|
349
|
-
|
|
350
|
-
# Deduplicate switch case values
|
|
351
|
-
deduped = []
|
|
352
|
-
for line in lines:
|
|
353
|
-
s = line.strip()
|
|
354
|
-
if s.startswith("switch i64 ") and "[" in line and "]" in line:
|
|
355
|
-
prefix, rest = line.split("[", 1)
|
|
356
|
-
case_text, suffix = rest.rsplit("]", 1)
|
|
357
|
-
cases = re.findall(r'(i64 -?\d+, label %"[^"]*")', case_text)
|
|
358
|
-
if cases:
|
|
359
|
-
seen = set()
|
|
360
|
-
unique = []
|
|
361
|
-
for case in cases:
|
|
362
|
-
val = re.match(r"i64 (-?\d+)", case).group(1)
|
|
363
|
-
if val not in seen:
|
|
364
|
-
seen.add(val)
|
|
365
|
-
unique.append(case)
|
|
366
|
-
line = prefix + "[" + " ".join(unique) + "]" + suffix
|
|
367
|
-
deduped.append(line)
|
|
368
|
-
|
|
369
|
-
# Repair control flow: drop dead code after terminators, bridge empty labels
|
|
370
|
-
def _is_label(s):
|
|
371
|
-
return bool(_LABEL_RE.match(s))
|
|
372
|
-
|
|
373
|
-
def _is_terminator(s):
|
|
374
|
-
return s.startswith(("br ", "ret ", "switch ", "unreachable", "resume "))
|
|
375
|
-
|
|
376
|
-
repaired = []
|
|
377
|
-
skip_dead = False
|
|
378
|
-
for raw in deduped:
|
|
379
|
-
s = raw.strip()
|
|
380
|
-
if skip_dead:
|
|
381
|
-
if _is_label(s):
|
|
382
|
-
skip_dead = False
|
|
383
|
-
else:
|
|
384
|
-
continue
|
|
385
|
-
if (
|
|
386
|
-
repaired
|
|
387
|
-
and _is_terminator(repaired[-1].strip())
|
|
388
|
-
and s
|
|
389
|
-
and raw.startswith(" ")
|
|
390
|
-
and not _is_label(s)
|
|
391
|
-
):
|
|
392
|
-
skip_dead = True
|
|
393
|
-
continue
|
|
394
|
-
if repaired and _is_label(s):
|
|
395
|
-
prev = repaired[-1].strip()
|
|
396
|
-
if _is_label(prev):
|
|
397
|
-
repaired.append(f' br label %"{s[:-1]}"')
|
|
398
|
-
elif prev not in {"", "{"} and not _is_terminator(prev):
|
|
399
|
-
repaired.append(f' br label %"{s[:-1]}"')
|
|
400
|
-
if s == "}" and repaired and _is_label(repaired[-1].strip()):
|
|
401
|
-
repaired.append(" unreachable")
|
|
402
|
-
repaired.append(raw)
|
|
403
|
-
|
|
404
|
-
return "\n".join(repaired)
|
|
445
|
+
return text
|
|
405
446
|
|
|
406
447
|
|
|
407
448
|
def get_ir_type_from_names(names):
|
|
@@ -431,12 +472,14 @@ def get_ir_type_from_names(names):
|
|
|
431
472
|
"void": ir.VoidType(),
|
|
432
473
|
"double": _double,
|
|
433
474
|
"float": _float,
|
|
475
|
+
"_Float16": _float,
|
|
434
476
|
"short": int16_t,
|
|
435
477
|
"long": int64_t,
|
|
436
478
|
"int short": int16_t,
|
|
437
479
|
"int long": int64_t,
|
|
438
480
|
"long long": int64_t,
|
|
439
481
|
"int long long": int64_t,
|
|
482
|
+
"__int128": int128_t,
|
|
440
483
|
"char unsigned": int8_t,
|
|
441
484
|
"int unsigned": int32_t,
|
|
442
485
|
"unsigned": int32_t,
|
|
@@ -445,6 +488,7 @@ def get_ir_type_from_names(names):
|
|
|
445
488
|
"int long unsigned": int64_t,
|
|
446
489
|
"long unsigned": int64_t,
|
|
447
490
|
"long long unsigned": int64_t,
|
|
491
|
+
"__int128 unsigned": int128_t,
|
|
448
492
|
# size_t, etc.
|
|
449
493
|
"size_t": int64_t,
|
|
450
494
|
"ssize_t": int64_t,
|
|
@@ -466,6 +510,8 @@ def get_ir_type_from_names(names):
|
|
|
466
510
|
return _double
|
|
467
511
|
if "float" in names:
|
|
468
512
|
return _float
|
|
513
|
+
if "_Float16" in names:
|
|
514
|
+
return _float
|
|
469
515
|
# If it contains 'char', return i8
|
|
470
516
|
if "char" in names:
|
|
471
517
|
return int8_t
|
|
@@ -490,14 +536,20 @@ def _resolve_node_type(node_type):
|
|
|
490
536
|
if isinstance(inner, c_ast.FuncDecl):
|
|
491
537
|
ret_type = _resolve_node_type(inner.type)
|
|
492
538
|
param_types = []
|
|
539
|
+
is_var_arg = False
|
|
493
540
|
if inner.args:
|
|
494
541
|
for p in inner.args.params:
|
|
495
542
|
if isinstance(p, c_ast.EllipsisParam):
|
|
543
|
+
is_var_arg = True
|
|
496
544
|
continue
|
|
497
545
|
t = get_ir_type_from_node(p)
|
|
498
546
|
if not isinstance(t, ir.VoidType):
|
|
499
547
|
param_types.append(t)
|
|
500
|
-
return ir.FunctionType(
|
|
548
|
+
return ir.FunctionType(
|
|
549
|
+
ret_type,
|
|
550
|
+
param_types,
|
|
551
|
+
var_arg=is_var_arg,
|
|
552
|
+
).as_pointer()
|
|
501
553
|
pointee = _resolve_node_type(inner)
|
|
502
554
|
if isinstance(pointee, ir.VoidType):
|
|
503
555
|
return voidptr_t
|
|
@@ -507,7 +559,7 @@ def _resolve_node_type(node_type):
|
|
|
507
559
|
return get_ir_type(node_type.type.names)
|
|
508
560
|
elif isinstance(node_type.type, c_ast.Struct):
|
|
509
561
|
snode = node_type.type
|
|
510
|
-
if snode.decls:
|
|
562
|
+
if snode.decls is not None:
|
|
511
563
|
# Inline struct with declarations — build real type
|
|
512
564
|
member_types = []
|
|
513
565
|
for decl in snode.decls:
|
|
@@ -519,8 +571,15 @@ def _resolve_node_type(node_type):
|
|
|
519
571
|
return int8_t # opaque/forward-declared struct
|
|
520
572
|
elif isinstance(node_type.type, c_ast.Union):
|
|
521
573
|
unode = node_type.type
|
|
522
|
-
if unode.decls:
|
|
574
|
+
if unode.decls is not None:
|
|
523
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
|
|
524
583
|
max_size = 0
|
|
525
584
|
max_align = 1
|
|
526
585
|
member_types = {}
|
|
@@ -548,7 +607,7 @@ def _resolve_node_type(node_type):
|
|
|
548
607
|
ir_t = _resolve_union_member_type(decl.type)
|
|
549
608
|
member_types[decl.name] = ir_t
|
|
550
609
|
sz = ir_t.width // 8 if isinstance(ir_t, ir.IntType) else 8
|
|
551
|
-
if
|
|
610
|
+
if _is_struct_ir_type(ir_t):
|
|
552
611
|
sz = sum(
|
|
553
612
|
e.width // 8 if isinstance(e, ir.IntType) else 8
|
|
554
613
|
for e in ir_t.elements
|
|
@@ -576,12 +635,18 @@ def _resolve_node_type(node_type):
|
|
|
576
635
|
ut.is_union = True
|
|
577
636
|
return ut
|
|
578
637
|
return int8_t # opaque/forward-declared union
|
|
638
|
+
elif isinstance(node_type.type, c_ast.Enum):
|
|
639
|
+
return int32_t
|
|
579
640
|
return int64_t
|
|
580
641
|
elif isinstance(node_type, c_ast.ArrayDecl):
|
|
581
642
|
return voidptr_t # array params decay to pointer
|
|
582
643
|
return int64_t
|
|
583
644
|
|
|
584
645
|
|
|
646
|
+
def _is_struct_ir_type(ir_type):
|
|
647
|
+
return isinstance(ir_type, (ir.LiteralStructType, ir.IdentifiedStructType))
|
|
648
|
+
|
|
649
|
+
|
|
585
650
|
class LLVMCodeGenerator(object):
|
|
586
651
|
|
|
587
652
|
def __init__(self, translation_unit_name=None):
|
|
@@ -601,6 +666,8 @@ class LLVMCodeGenerator(object):
|
|
|
601
666
|
self.env = ChainMap()
|
|
602
667
|
self.nlabels = 0
|
|
603
668
|
self.function = None
|
|
669
|
+
self._function_display_name = None
|
|
670
|
+
self._frame_address_marker = None
|
|
604
671
|
self.in_global = True
|
|
605
672
|
self._declared_libc = set()
|
|
606
673
|
self._unsigned_bindings = set() # alloca/global ids with unsigned type
|
|
@@ -609,11 +676,18 @@ class LLVMCodeGenerator(object):
|
|
|
609
676
|
self._expr_ir_types = {}
|
|
610
677
|
self._labels = {}
|
|
611
678
|
self._vaarg_counter = 0
|
|
679
|
+
self._anon_type_counter = 0
|
|
612
680
|
self._file_scope_object_states = {}
|
|
613
681
|
self._file_scope_function_states = {}
|
|
682
|
+
self._future_file_scope_object_ir_types = {}
|
|
683
|
+
self._future_file_scope_function_ir_types = {}
|
|
614
684
|
self.translation_unit_name = self._sanitize_translation_unit_name(
|
|
615
685
|
translation_unit_name
|
|
616
686
|
)
|
|
687
|
+
base_namespace = self.translation_unit_name or "pcc"
|
|
688
|
+
self._aggregate_namespace = (
|
|
689
|
+
f"{base_namespace}_{next(_aggregate_namespace_counter)}"
|
|
690
|
+
)
|
|
617
691
|
|
|
618
692
|
def define(self, name, val):
|
|
619
693
|
self.env[name] = val
|
|
@@ -624,6 +698,29 @@ class LLVMCodeGenerator(object):
|
|
|
624
698
|
return None
|
|
625
699
|
return re.sub(r"\W+", "_", name)
|
|
626
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
|
+
|
|
627
724
|
def _is_file_scope_static(self, storage=None):
|
|
628
725
|
return (
|
|
629
726
|
self.translation_unit_name
|
|
@@ -632,8 +729,17 @@ class LLVMCodeGenerator(object):
|
|
|
632
729
|
and "static" in storage
|
|
633
730
|
)
|
|
634
731
|
|
|
635
|
-
def
|
|
636
|
-
|
|
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):
|
|
637
743
|
return f"__pcc_internal_{self.translation_unit_name}_{name}"
|
|
638
744
|
return name
|
|
639
745
|
|
|
@@ -656,16 +762,28 @@ class LLVMCodeGenerator(object):
|
|
|
656
762
|
self.define(bind_name, (ir_type, gv))
|
|
657
763
|
return gv
|
|
658
764
|
|
|
659
|
-
def _decl_linkage(self, storage=None, existing_state=None):
|
|
765
|
+
def _decl_linkage(self, storage=None, funcspec=None, existing_state=None):
|
|
660
766
|
if storage and "static" in storage:
|
|
661
767
|
return "internal"
|
|
768
|
+
if self._has_internal_inline_linkage(storage, funcspec):
|
|
769
|
+
return "internal"
|
|
662
770
|
if existing_state is not None:
|
|
663
771
|
return existing_state.linkage
|
|
664
772
|
return "external"
|
|
665
773
|
|
|
666
|
-
def _effective_file_scope_symbol_name(
|
|
667
|
-
|
|
668
|
-
|
|
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
|
+
)
|
|
669
787
|
if existing_state is not None and existing_state.linkage == "internal":
|
|
670
788
|
return existing_state.symbol_name
|
|
671
789
|
return name
|
|
@@ -677,11 +795,54 @@ class LLVMCodeGenerator(object):
|
|
|
677
795
|
return "definition"
|
|
678
796
|
return "tentative"
|
|
679
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
|
+
|
|
680
840
|
def _prepare_file_scope_object(self, name, ir_type, storage=None, has_initializer=False):
|
|
681
841
|
if not self.in_global or name is None:
|
|
682
842
|
return None, True
|
|
683
843
|
if name in self._file_scope_function_states:
|
|
684
844
|
raise SemanticError(f"'{name}' redeclared as object after function declaration")
|
|
845
|
+
ir_type = self._preferred_file_scope_object_ir_type(name, ir_type)
|
|
685
846
|
|
|
686
847
|
type_key = str(ir_type)
|
|
687
848
|
definition_kind = self._file_scope_object_definition_kind(
|
|
@@ -699,6 +860,7 @@ class LLVMCodeGenerator(object):
|
|
|
699
860
|
linkage=linkage,
|
|
700
861
|
definition_kind=definition_kind,
|
|
701
862
|
symbol_name=symbol_name,
|
|
863
|
+
ir_type=ir_type,
|
|
702
864
|
)
|
|
703
865
|
self._file_scope_object_states[name] = state
|
|
704
866
|
if definition_kind == "extern":
|
|
@@ -709,8 +871,11 @@ class LLVMCodeGenerator(object):
|
|
|
709
871
|
)
|
|
710
872
|
return gv, True
|
|
711
873
|
|
|
712
|
-
if state.
|
|
874
|
+
if not self._are_compatible_object_ir_types(state.ir_type, ir_type):
|
|
713
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)
|
|
714
879
|
if state.linkage != linkage:
|
|
715
880
|
raise SemanticError(f"conflicting linkage for global '{name}'")
|
|
716
881
|
if state.symbol_name != symbol_name:
|
|
@@ -719,9 +884,9 @@ class LLVMCodeGenerator(object):
|
|
|
719
884
|
existing = self.module.globals.get(symbol_name)
|
|
720
885
|
if definition_kind == "extern":
|
|
721
886
|
if existing is not None:
|
|
722
|
-
self.define(name, (
|
|
887
|
+
self.define(name, (merged_ir_type, existing))
|
|
723
888
|
else:
|
|
724
|
-
self._record_extern_global(name,
|
|
889
|
+
self._record_extern_global(name, merged_ir_type, storage=storage)
|
|
725
890
|
return None, False
|
|
726
891
|
|
|
727
892
|
if existing is None:
|
|
@@ -747,7 +912,7 @@ class LLVMCodeGenerator(object):
|
|
|
747
912
|
return gv, True
|
|
748
913
|
|
|
749
914
|
def _register_file_scope_function(
|
|
750
|
-
self, name, function_type, storage=None, is_definition=False
|
|
915
|
+
self, name, function_type, storage=None, funcspec=None, is_definition=False
|
|
751
916
|
):
|
|
752
917
|
if not self.in_global or name is None:
|
|
753
918
|
return
|
|
@@ -756,9 +921,13 @@ class LLVMCodeGenerator(object):
|
|
|
756
921
|
|
|
757
922
|
type_key = str(function_type)
|
|
758
923
|
state = self._file_scope_function_states.get(name)
|
|
759
|
-
linkage = self._decl_linkage(storage, existing_state=state)
|
|
924
|
+
linkage = self._decl_linkage(storage, funcspec=funcspec, existing_state=state)
|
|
760
925
|
symbol_name = self._effective_file_scope_symbol_name(
|
|
761
|
-
name,
|
|
926
|
+
name,
|
|
927
|
+
storage=storage,
|
|
928
|
+
funcspec=funcspec,
|
|
929
|
+
existing_state=state,
|
|
930
|
+
linkage=linkage,
|
|
762
931
|
)
|
|
763
932
|
|
|
764
933
|
if state is None:
|
|
@@ -782,6 +951,12 @@ class LLVMCodeGenerator(object):
|
|
|
782
951
|
state.defined = True
|
|
783
952
|
return state.symbol_name
|
|
784
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
|
+
|
|
785
960
|
def external_definitions(self):
|
|
786
961
|
defs = []
|
|
787
962
|
for name, state in self._file_scope_function_states.items():
|
|
@@ -805,12 +980,65 @@ class LLVMCodeGenerator(object):
|
|
|
805
980
|
and node.name is not None
|
|
806
981
|
)
|
|
807
982
|
|
|
808
|
-
def _extern_decl_ir_type(self, node_type):
|
|
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):
|
|
809
991
|
if isinstance(node_type, c_ast.ArrayDecl):
|
|
810
|
-
return self._build_array_ir_type(node_type)
|
|
992
|
+
return self._build_array_ir_type(node_type, init_node=init_node)
|
|
811
993
|
return self._resolve_ast_type(node_type)
|
|
812
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
|
+
|
|
813
1040
|
def _record_extern_global(self, name, ir_type, storage=None):
|
|
1041
|
+
ir_type = self._preferred_file_scope_object_ir_type(name, ir_type)
|
|
814
1042
|
self.define(
|
|
815
1043
|
name,
|
|
816
1044
|
(
|
|
@@ -937,6 +1165,34 @@ class LLVMCodeGenerator(object):
|
|
|
937
1165
|
return self._convert_int_value(val, int32_t, result_unsigned=False)
|
|
938
1166
|
return val
|
|
939
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
|
+
|
|
940
1196
|
def _usual_arithmetic_conversion(self, lhs, rhs):
|
|
941
1197
|
lhs = self._integer_promotion(lhs)
|
|
942
1198
|
rhs = self._integer_promotion(rhs)
|
|
@@ -986,10 +1242,18 @@ class LLVMCodeGenerator(object):
|
|
|
986
1242
|
return _float
|
|
987
1243
|
|
|
988
1244
|
def _parse_float_constant(self, raw):
|
|
1245
|
+
is_float32 = raw.endswith(("f", "F"))
|
|
989
1246
|
value = raw.rstrip("fFlL")
|
|
990
1247
|
if value.lower().startswith("0x") and "p" in value.lower():
|
|
991
|
-
|
|
992
|
-
|
|
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
|
|
993
1257
|
|
|
994
1258
|
def _float_literal_ir_type(self, raw):
|
|
995
1259
|
if raw.endswith(("f", "F")):
|
|
@@ -1089,16 +1353,21 @@ class LLVMCodeGenerator(object):
|
|
|
1089
1353
|
@contextmanager
|
|
1090
1354
|
def new_function(self):
|
|
1091
1355
|
oldfunc = self.function
|
|
1356
|
+
old_display_name = self._function_display_name
|
|
1357
|
+
old_frame_address_marker = self._frame_address_marker
|
|
1092
1358
|
oldbuilder = self.builder
|
|
1093
1359
|
oldenv = self.env
|
|
1094
1360
|
oldlabels = self._labels
|
|
1095
1361
|
self.in_global = False
|
|
1096
1362
|
self.env = self.env.new_child()
|
|
1097
1363
|
self._labels = {}
|
|
1364
|
+
self._frame_address_marker = None
|
|
1098
1365
|
try:
|
|
1099
1366
|
yield
|
|
1100
1367
|
finally:
|
|
1101
1368
|
self.function = oldfunc
|
|
1369
|
+
self._function_display_name = old_display_name
|
|
1370
|
+
self._frame_address_marker = old_frame_address_marker
|
|
1102
1371
|
self.builder = oldbuilder
|
|
1103
1372
|
self.env = oldenv
|
|
1104
1373
|
self._labels = oldlabels
|
|
@@ -1200,9 +1469,11 @@ class LLVMCodeGenerator(object):
|
|
|
1200
1469
|
for i, ext in enumerate(node.ext):
|
|
1201
1470
|
is_type_def = False
|
|
1202
1471
|
if isinstance(ext, c_ast.Decl):
|
|
1203
|
-
if
|
|
1472
|
+
if ext.name is None and isinstance(
|
|
1473
|
+
ext.type, (c_ast.Struct, c_ast.Union, c_ast.Enum)
|
|
1474
|
+
):
|
|
1204
1475
|
is_type_def = True
|
|
1205
|
-
elif isinstance(ext.type, c_ast.TypeDecl) and isinstance(
|
|
1476
|
+
elif ext.name is None and isinstance(ext.type, c_ast.TypeDecl) and isinstance(
|
|
1206
1477
|
ext.type.type, (c_ast.Struct, c_ast.Union)
|
|
1207
1478
|
):
|
|
1208
1479
|
is_type_def = True
|
|
@@ -1214,6 +1485,9 @@ class LLVMCodeGenerator(object):
|
|
|
1214
1485
|
except Exception:
|
|
1215
1486
|
pass
|
|
1216
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)
|
|
1217
1491
|
for i, ext in enumerate(node.ext):
|
|
1218
1492
|
if i not in pass1:
|
|
1219
1493
|
try:
|
|
@@ -1297,15 +1571,37 @@ class LLVMCodeGenerator(object):
|
|
|
1297
1571
|
if node.type == "int":
|
|
1298
1572
|
# Support hex (0xFF), octal (077), and decimal literals
|
|
1299
1573
|
raw = node.value
|
|
1300
|
-
|
|
1574
|
+
raw_lower = raw.lower()
|
|
1575
|
+
has_unsigned_suffix = "u" in raw_lower
|
|
1576
|
+
has_long_suffix = "l" in raw_lower
|
|
1301
1577
|
val_str = raw.rstrip("uUlL")
|
|
1302
1578
|
if val_str.startswith("0x") or val_str.startswith("0X"):
|
|
1303
1579
|
int_val = int(val_str, 16)
|
|
1580
|
+
is_non_decimal = True
|
|
1304
1581
|
elif val_str.startswith("0") and len(val_str) > 1 and val_str[1:].isdigit():
|
|
1305
1582
|
int_val = int(val_str, 8)
|
|
1583
|
+
is_non_decimal = True
|
|
1306
1584
|
else:
|
|
1307
1585
|
int_val = int(val_str)
|
|
1308
|
-
|
|
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)
|
|
1309
1605
|
if is_unsigned:
|
|
1310
1606
|
self._tag_unsigned(result)
|
|
1311
1607
|
return result, None
|
|
@@ -1339,6 +1635,7 @@ class LLVMCodeGenerator(object):
|
|
|
1339
1635
|
if lv is None or rv is None:
|
|
1340
1636
|
return ir.Constant(int64_t, 0), None
|
|
1341
1637
|
result = None
|
|
1638
|
+
is_bitfield = isinstance(lv_addr, BitFieldRef)
|
|
1342
1639
|
|
|
1343
1640
|
dispatch_type_double = 1
|
|
1344
1641
|
dispatch_type_int = 0
|
|
@@ -1394,13 +1691,19 @@ class LLVMCodeGenerator(object):
|
|
|
1394
1691
|
|
|
1395
1692
|
if node.op == "=":
|
|
1396
1693
|
# Type coercion: match rv to the target's pointee type
|
|
1397
|
-
if
|
|
1694
|
+
if is_bitfield:
|
|
1695
|
+
target_type = lv_addr.semantic_ir_type
|
|
1696
|
+
elif lv_addr and hasattr(lv_addr.type, "pointee"):
|
|
1398
1697
|
target_type = lv_addr.type.pointee
|
|
1399
1698
|
else:
|
|
1400
1699
|
target_type = lv.type
|
|
1401
1700
|
if rv.type != target_type:
|
|
1402
1701
|
rv = self._implicit_convert(rv, target_type)
|
|
1403
|
-
|
|
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)
|
|
1404
1707
|
return rv, lv_addr # return value for chained assignment
|
|
1405
1708
|
else:
|
|
1406
1709
|
# Pointer compound assignment: p += n, p -= n
|
|
@@ -1418,6 +1721,9 @@ class LLVMCodeGenerator(object):
|
|
|
1418
1721
|
addresult = handle(lv, rv, "addtmp")
|
|
1419
1722
|
if dispatch_type == dispatch_type_int and is_unsigned:
|
|
1420
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
|
|
1421
1727
|
self._safe_store(addresult, lv_addr)
|
|
1422
1728
|
return addresult, lv_addr
|
|
1423
1729
|
|
|
@@ -1444,8 +1750,12 @@ class LLVMCodeGenerator(object):
|
|
|
1444
1750
|
)
|
|
1445
1751
|
if self._is_unsigned_val(lv):
|
|
1446
1752
|
self._tag_unsigned(new_val)
|
|
1447
|
-
|
|
1448
|
-
|
|
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
|
|
1449
1759
|
|
|
1450
1760
|
elif node.op == "*":
|
|
1451
1761
|
if (
|
|
@@ -1459,8 +1769,8 @@ class LLVMCodeGenerator(object):
|
|
|
1459
1769
|
node.expr.expr.args.exprs if node.expr.expr.args is not None else []
|
|
1460
1770
|
)
|
|
1461
1771
|
if isinstance(target_ptr_type, ir.PointerType) and va_args:
|
|
1462
|
-
ap_addr
|
|
1463
|
-
if
|
|
1772
|
+
ap_addr = self._builtin_va_list_storage(va_args[0])
|
|
1773
|
+
if ap_addr is not None:
|
|
1464
1774
|
self._vaarg_counter += 1
|
|
1465
1775
|
name = f"__pcc_va_arg_{self._vaarg_counter}"
|
|
1466
1776
|
placeholder = self.module.globals.get(name)
|
|
@@ -1483,6 +1793,11 @@ class LLVMCodeGenerator(object):
|
|
|
1483
1793
|
result_ptr = self._decay_array_value_to_pointer(name_ir, "derefarray")
|
|
1484
1794
|
else:
|
|
1485
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
|
|
1486
1801
|
result = self._safe_load(result_ptr)
|
|
1487
1802
|
if self._is_unsigned_pointee(name_ir) or self._is_unsigned_pointee(
|
|
1488
1803
|
result_ptr
|
|
@@ -1556,12 +1871,15 @@ class LLVMCodeGenerator(object):
|
|
|
1556
1871
|
if isinstance(expr, c_ast.Typename):
|
|
1557
1872
|
ir_t = self._resolve_ast_type(expr.type)
|
|
1558
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"))
|
|
1559
1878
|
elif isinstance(expr, c_ast.ID):
|
|
1560
1879
|
ir_type, _ = self.lookup(expr.name)
|
|
1561
1880
|
size = self._ir_type_size(ir_type)
|
|
1562
1881
|
else:
|
|
1563
|
-
|
|
1564
|
-
semantic_type = self._get_expr_ir_type(expr, getattr(val, "type", None))
|
|
1882
|
+
semantic_type = self._infer_sizeof_operand_ir_type(expr)
|
|
1565
1883
|
size = self._ir_type_size(semantic_type)
|
|
1566
1884
|
result = ir.Constant(int64_t, size)
|
|
1567
1885
|
return self._tag_unsigned(result)
|
|
@@ -1580,9 +1898,8 @@ class LLVMCodeGenerator(object):
|
|
|
1580
1898
|
if isinstance(resolved, str):
|
|
1581
1899
|
# Could be a __struct_ reference or a base type name
|
|
1582
1900
|
if resolved.startswith("__struct_"):
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
return self.env[struct_name][0]
|
|
1901
|
+
if resolved in self.env:
|
|
1902
|
+
return self.env[resolved][0]
|
|
1586
1903
|
return int8_t # opaque
|
|
1587
1904
|
# Recursively resolve further typedefs
|
|
1588
1905
|
return self._resolve_type_str(resolved, depth + 1)
|
|
@@ -1725,11 +2042,162 @@ class LLVMCodeGenerator(object):
|
|
|
1725
2042
|
return None
|
|
1726
2043
|
return self._scalar_init_node(init_node.exprs[0])
|
|
1727
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
|
+
|
|
1728
2194
|
def _build_pointer_const(self, init_node, ir_type):
|
|
1729
2195
|
if isinstance(init_node, c_ast.InitList):
|
|
1730
2196
|
if init_node.exprs:
|
|
1731
2197
|
return self._build_pointer_const(init_node.exprs[0], ir_type)
|
|
1732
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)
|
|
1733
2201
|
if (
|
|
1734
2202
|
isinstance(init_node, c_ast.Constant)
|
|
1735
2203
|
and getattr(init_node, "type", None) == "string"
|
|
@@ -1750,22 +2218,23 @@ class LLVMCodeGenerator(object):
|
|
|
1750
2218
|
return sym
|
|
1751
2219
|
if isinstance(sym.type, ir.PointerType):
|
|
1752
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)
|
|
1753
2228
|
if (
|
|
1754
2229
|
isinstance(init_node, c_ast.UnaryOp)
|
|
1755
2230
|
and init_node.op == "&"
|
|
1756
|
-
and isinstance(init_node.expr, c_ast.ID)
|
|
1757
2231
|
):
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
if isinstance(sym, ir.GlobalVariable):
|
|
1765
|
-
if sym.type == ir_type:
|
|
1766
|
-
return sym
|
|
1767
|
-
if isinstance(sym.type, ir.PointerType):
|
|
1768
|
-
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)
|
|
1769
2238
|
try:
|
|
1770
2239
|
val = self._eval_const_expr(init_node)
|
|
1771
2240
|
if val == 0:
|
|
@@ -1846,6 +2315,17 @@ class LLVMCodeGenerator(object):
|
|
|
1846
2315
|
result -= 1 << bits
|
|
1847
2316
|
return ir.Constant(int_type, result)
|
|
1848
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
|
+
|
|
1849
2329
|
def _const_init_bytes(self, init_node, ir_type):
|
|
1850
2330
|
size = self._ir_type_size(ir_type)
|
|
1851
2331
|
if init_node is None:
|
|
@@ -1853,28 +2333,12 @@ class LLVMCodeGenerator(object):
|
|
|
1853
2333
|
|
|
1854
2334
|
if getattr(ir_type, "is_union", False):
|
|
1855
2335
|
raw = self._zero_bytes(size)
|
|
1856
|
-
|
|
1857
|
-
ir_type
|
|
2336
|
+
field_name, member_type, member_init = self._select_union_initializer(
|
|
2337
|
+
init_node, ir_type
|
|
1858
2338
|
)
|
|
1859
|
-
if
|
|
2339
|
+
if field_name is None:
|
|
1860
2340
|
return raw
|
|
1861
2341
|
|
|
1862
|
-
first_name = member_names[0]
|
|
1863
|
-
member_type = ir_type.member_types[first_name]
|
|
1864
|
-
member_init = init_node
|
|
1865
|
-
if isinstance(init_node, c_ast.InitList):
|
|
1866
|
-
exprs = init_node.exprs or []
|
|
1867
|
-
if not exprs:
|
|
1868
|
-
member_init = None
|
|
1869
|
-
elif isinstance(member_type, (ir.ArrayType, ir.LiteralStructType)):
|
|
1870
|
-
member_init = (
|
|
1871
|
-
exprs[0]
|
|
1872
|
-
if len(exprs) == 1 and isinstance(exprs[0], c_ast.InitList)
|
|
1873
|
-
else init_node
|
|
1874
|
-
)
|
|
1875
|
-
else:
|
|
1876
|
-
member_init = exprs[0]
|
|
1877
|
-
|
|
1878
2342
|
member_bytes = self._const_init_bytes(member_init, member_type)
|
|
1879
2343
|
raw[: min(size, len(member_bytes))] = member_bytes[:size]
|
|
1880
2344
|
return raw
|
|
@@ -1934,16 +2398,62 @@ class LLVMCodeGenerator(object):
|
|
|
1934
2398
|
|
|
1935
2399
|
return self._zero_bytes(size)
|
|
1936
2400
|
|
|
1937
|
-
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
|
+
|
|
1938
2447
|
raw = self._zero_bytes(size)
|
|
1939
2448
|
if not isinstance(init_node, c_ast.InitList):
|
|
1940
2449
|
return raw
|
|
1941
2450
|
|
|
2451
|
+
exprs = self._ordered_struct_init_exprs(init_node, ir_type)
|
|
1942
2452
|
offset = 0
|
|
1943
2453
|
for i, member_type in enumerate(ir_type.elements):
|
|
1944
2454
|
align = self._ir_type_align(member_type)
|
|
1945
2455
|
offset = (offset + align - 1) & ~(align - 1)
|
|
1946
|
-
expr =
|
|
2456
|
+
expr = exprs[i] if i < len(exprs) else None
|
|
1947
2457
|
field_bytes = self._const_init_bytes(expr, member_type)
|
|
1948
2458
|
field_size = self._ir_type_size(member_type)
|
|
1949
2459
|
raw[offset : offset + field_size] = field_bytes[:field_size]
|
|
@@ -2015,11 +2525,36 @@ class LLVMCodeGenerator(object):
|
|
|
2015
2525
|
|
|
2016
2526
|
return self._zero_initializer(ir_type)
|
|
2017
2527
|
|
|
2018
|
-
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)
|
|
2019
2553
|
if isinstance(init_node, c_ast.InitList):
|
|
2554
|
+
exprs = self._ordered_struct_init_exprs(init_node, ir_type)
|
|
2020
2555
|
values = []
|
|
2021
2556
|
for i, member_type in enumerate(ir_type.elements):
|
|
2022
|
-
expr =
|
|
2557
|
+
expr = exprs[i] if i < len(exprs) else None
|
|
2023
2558
|
values.append(self._build_const_init(expr, member_type))
|
|
2024
2559
|
try:
|
|
2025
2560
|
return ir.Constant(ir_type, values)
|
|
@@ -2044,20 +2579,206 @@ class LLVMCodeGenerator(object):
|
|
|
2044
2579
|
"""Recursively initialize array elements from an InitList."""
|
|
2045
2580
|
for i, expr in enumerate(init_list.exprs):
|
|
2046
2581
|
idx = prefix_idx + [ir.Constant(ir.IntType(32), i)]
|
|
2047
|
-
if isinstance(expr, c_ast.InitList):
|
|
2048
|
-
self._init_array(base_addr, expr, elem_ir_type, idx)
|
|
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)
|
|
2587
|
+
|
|
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
|
|
2591
|
+
|
|
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
|
|
2617
|
+
|
|
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
|
+
)
|
|
2049
2765
|
else:
|
|
2050
|
-
|
|
2051
|
-
val = self._implicit_convert(val, elem_ir_type)
|
|
2052
|
-
elem_ptr = self.builder.gep(base_addr, idx, inbounds=True)
|
|
2053
|
-
self._safe_store(val, elem_ptr)
|
|
2766
|
+
member_init = first_expr
|
|
2054
2767
|
|
|
2055
|
-
|
|
2768
|
+
return field_name, field_type, member_init
|
|
2769
|
+
|
|
2770
|
+
def _build_array_ir_type(self, array_decl, init_node=None):
|
|
2056
2771
|
dims = []
|
|
2057
2772
|
node = array_decl
|
|
2773
|
+
inferred_top_dim = self._infer_array_count_from_initializer(init_node)
|
|
2774
|
+
is_top_level = True
|
|
2058
2775
|
while isinstance(node, c_ast.ArrayDecl):
|
|
2059
|
-
|
|
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)
|
|
2060
2780
|
node = node.type
|
|
2781
|
+
is_top_level = False
|
|
2061
2782
|
elem_ir_type = self._resolve_ast_type(node)
|
|
2062
2783
|
if isinstance(elem_ir_type, ir.VoidType):
|
|
2063
2784
|
elem_ir_type = int8_t
|
|
@@ -2069,16 +2790,30 @@ class LLVMCodeGenerator(object):
|
|
|
2069
2790
|
|
|
2070
2791
|
def _resolve_param_type(self, param):
|
|
2071
2792
|
"""Resolve a function parameter type, handling typedefs and pointers."""
|
|
2072
|
-
if
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
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)
|
|
2076
2803
|
if isinstance(t, ir.ArrayType):
|
|
2077
2804
|
return ir.PointerType(t.element)
|
|
2078
2805
|
if isinstance(t, ir.VoidType):
|
|
2079
2806
|
return None # void params mean "no params" in C
|
|
2080
2807
|
return t
|
|
2081
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
|
+
|
|
2082
2817
|
def _resolve_ast_type(self, node_type):
|
|
2083
2818
|
"""Recursively resolve an AST type to IR type, with typedef support."""
|
|
2084
2819
|
if isinstance(node_type, c_ast.PtrDecl):
|
|
@@ -2096,6 +2831,9 @@ class LLVMCodeGenerator(object):
|
|
|
2096
2831
|
return self.codegen_Struct(node_type.type)
|
|
2097
2832
|
elif isinstance(node_type.type, c_ast.Union):
|
|
2098
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
|
|
2099
2837
|
return int64_t
|
|
2100
2838
|
elif isinstance(node_type, c_ast.ArrayDecl):
|
|
2101
2839
|
return voidptr_t
|
|
@@ -2110,31 +2848,79 @@ class LLVMCodeGenerator(object):
|
|
|
2110
2848
|
return int(v, 0) # handles hex/octal/decimal
|
|
2111
2849
|
return self._eval_const_expr(dim_node)
|
|
2112
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
|
+
|
|
2113
2864
|
def _build_func_ptr_type(self, func_decl_node):
|
|
2114
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."""
|
|
2115
2871
|
ret_ir, _ = self.codegen(func_decl_node)
|
|
2116
2872
|
param_types = []
|
|
2873
|
+
is_var_arg = False
|
|
2117
2874
|
if func_decl_node.args:
|
|
2118
2875
|
for param in func_decl_node.args.params:
|
|
2119
2876
|
if isinstance(param, c_ast.EllipsisParam):
|
|
2877
|
+
is_var_arg = True
|
|
2120
2878
|
continue
|
|
2121
|
-
if isinstance(param, c_ast.Typename):
|
|
2122
|
-
t = self._resolve_ast_type(param.type)
|
|
2123
|
-
if not isinstance(t, ir.VoidType):
|
|
2124
|
-
param_types.append(t)
|
|
2125
|
-
elif isinstance(param, c_ast.Decl):
|
|
2879
|
+
if isinstance(param, (c_ast.Typename, c_ast.Decl)):
|
|
2126
2880
|
t = self._resolve_param_type(param)
|
|
2127
2881
|
if t is not None:
|
|
2128
2882
|
param_types.append(t)
|
|
2129
2883
|
if isinstance(ret_ir, ir.VoidType):
|
|
2130
2884
|
ret_ir = ir.VoidType()
|
|
2131
|
-
|
|
2132
|
-
return func_type.as_pointer()
|
|
2885
|
+
return ir.FunctionType(ret_ir, param_types, var_arg=is_var_arg), ret_ir
|
|
2133
2886
|
|
|
2134
|
-
def
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
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
|
|
2919
|
+
|
|
2920
|
+
def _safe_load(self, ptr, name=""):
|
|
2921
|
+
"""Load from ptr, guard against non-pointer types."""
|
|
2922
|
+
if not isinstance(ptr.type, ir.PointerType):
|
|
2923
|
+
return ptr
|
|
2138
2924
|
if isinstance(ptr.type.pointee, ir.FunctionType):
|
|
2139
2925
|
return ptr # function pointers are first-class as pointers
|
|
2140
2926
|
try:
|
|
@@ -2155,9 +2941,26 @@ class LLVMCodeGenerator(object):
|
|
|
2155
2941
|
gv.global_constant = True
|
|
2156
2942
|
gv.linkage = "internal"
|
|
2157
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)
|
|
2158
2947
|
idx0 = ir.Constant(ir.IntType(32), 0)
|
|
2159
2948
|
return self.builder.gep(base, [idx0, idx0], name=name)
|
|
2160
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
|
+
|
|
2161
2964
|
def _safe_store(self, value, ptr):
|
|
2162
2965
|
"""Store value to ptr, auto-converting types if needed."""
|
|
2163
2966
|
if value is None or ptr is None:
|
|
@@ -2177,11 +2980,9 @@ class LLVMCodeGenerator(object):
|
|
|
2177
2980
|
"""Convert val to target_type if needed (implicit C promotion/truncation)."""
|
|
2178
2981
|
if val is None or isinstance(val.type, ir.VoidType):
|
|
2179
2982
|
# Can't convert void — return a zero of target type
|
|
2180
|
-
if isinstance(target_type, ir.
|
|
2181
|
-
return ir.Constant(target_type, None)
|
|
2182
|
-
elif isinstance(target_type, ir.VoidType):
|
|
2983
|
+
if isinstance(target_type, ir.VoidType):
|
|
2183
2984
|
return val
|
|
2184
|
-
return
|
|
2985
|
+
return self._zero_initializer(target_type)
|
|
2185
2986
|
if val.type == target_type:
|
|
2186
2987
|
return val
|
|
2187
2988
|
if isinstance(val.type, ir.IntType) and self._is_floating_ir_type(target_type):
|
|
@@ -2242,6 +3043,49 @@ class LLVMCodeGenerator(object):
|
|
|
2242
3043
|
return self.builder.bitcast(ptr, target_type)
|
|
2243
3044
|
return val
|
|
2244
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
|
+
|
|
2245
3089
|
def _extend_call_result(self, result, returns_unsigned=False):
|
|
2246
3090
|
if not isinstance(result.type, ir.IntType):
|
|
2247
3091
|
return result
|
|
@@ -2267,6 +3111,9 @@ class LLVMCodeGenerator(object):
|
|
|
2267
3111
|
|
|
2268
3112
|
def _ir_type_align(self, ir_type):
|
|
2269
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
|
|
2270
3117
|
if isinstance(ir_type, ir.IntType):
|
|
2271
3118
|
return min(ir_type.width // 8, 8)
|
|
2272
3119
|
elif isinstance(ir_type, ir.FloatType):
|
|
@@ -2277,7 +3124,7 @@ class LLVMCodeGenerator(object):
|
|
|
2277
3124
|
return 8
|
|
2278
3125
|
elif isinstance(ir_type, ir.ArrayType):
|
|
2279
3126
|
return self._ir_type_align(ir_type.element)
|
|
2280
|
-
elif
|
|
3127
|
+
elif _is_struct_ir_type(ir_type):
|
|
2281
3128
|
if not ir_type.elements:
|
|
2282
3129
|
return 1
|
|
2283
3130
|
return max(self._ir_type_align(e) for e in ir_type.elements)
|
|
@@ -2285,6 +3132,9 @@ class LLVMCodeGenerator(object):
|
|
|
2285
3132
|
|
|
2286
3133
|
def _ir_type_size(self, ir_type):
|
|
2287
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
|
|
2288
3138
|
if isinstance(ir_type, ir.IntType):
|
|
2289
3139
|
return ir_type.width // 8
|
|
2290
3140
|
elif isinstance(ir_type, ir.FloatType):
|
|
@@ -2295,7 +3145,7 @@ class LLVMCodeGenerator(object):
|
|
|
2295
3145
|
return 8
|
|
2296
3146
|
elif isinstance(ir_type, ir.ArrayType):
|
|
2297
3147
|
return int(ir_type.count) * self._ir_type_size(ir_type.element)
|
|
2298
|
-
elif
|
|
3148
|
+
elif _is_struct_ir_type(ir_type):
|
|
2299
3149
|
offset = 0
|
|
2300
3150
|
for elem in ir_type.elements:
|
|
2301
3151
|
align = self._ir_type_align(elem)
|
|
@@ -2307,6 +3157,232 @@ class LLVMCodeGenerator(object):
|
|
|
2307
3157
|
return offset
|
|
2308
3158
|
return 8
|
|
2309
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
|
+
|
|
2310
3386
|
def _refine_member_ir_type(self, aggregate_type, member_key, field_type):
|
|
2311
3387
|
"""Prefer semantic member types over storage types when available."""
|
|
2312
3388
|
semantic_field_type = field_type
|
|
@@ -2331,8 +3407,8 @@ class LLVMCodeGenerator(object):
|
|
|
2331
3407
|
resolved, ir.PointerType
|
|
2332
3408
|
):
|
|
2333
3409
|
return semantic_field_type
|
|
2334
|
-
if isinstance(
|
|
2335
|
-
resolved
|
|
3410
|
+
if isinstance(resolved, (ir.ArrayType, ir.PointerType)) or _is_struct_ir_type(
|
|
3411
|
+
resolved
|
|
2336
3412
|
):
|
|
2337
3413
|
return resolved
|
|
2338
3414
|
except Exception:
|
|
@@ -2349,6 +3425,14 @@ class LLVMCodeGenerator(object):
|
|
|
2349
3425
|
)
|
|
2350
3426
|
return 0, semantic_field_type
|
|
2351
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
|
+
|
|
2352
3436
|
if not hasattr(aggregate_type, "members"):
|
|
2353
3437
|
raise CodegenError(f"Aggregate has no named fields: {aggregate_type}")
|
|
2354
3438
|
|
|
@@ -2393,6 +3477,153 @@ class LLVMCodeGenerator(object):
|
|
|
2393
3477
|
|
|
2394
3478
|
raise CodegenError(f"Not an offsetof base: {type(node).__name__}")
|
|
2395
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
|
+
|
|
2396
3627
|
def codegen_Typename(self, node):
|
|
2397
3628
|
# Used inside sizeof(type) — not directly code-generated
|
|
2398
3629
|
return None, None
|
|
@@ -2408,6 +3639,8 @@ class LLVMCodeGenerator(object):
|
|
|
2408
3639
|
rhs, _ = self.codegen(node.right)
|
|
2409
3640
|
if lhs is None or rhs is None:
|
|
2410
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")
|
|
2411
3644
|
|
|
2412
3645
|
# Pointer arithmetic: ptr + int or ptr - int
|
|
2413
3646
|
if (
|
|
@@ -2769,8 +4002,8 @@ class LLVMCodeGenerator(object):
|
|
|
2769
4002
|
cond_val = self.builder.ptrtoint(cond_val, int64_t)
|
|
2770
4003
|
elif self._is_floating_ir_type(cond_val.type):
|
|
2771
4004
|
cond_val = self.builder.fptosi(cond_val, int64_t)
|
|
2772
|
-
elif isinstance(cond_val.type, ir.IntType) and cond_val.type.width
|
|
2773
|
-
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)
|
|
2774
4007
|
|
|
2775
4008
|
after_bb = self.builder.function.append_basic_block("switch_end")
|
|
2776
4009
|
|
|
@@ -2783,11 +4016,57 @@ class LLVMCodeGenerator(object):
|
|
|
2783
4016
|
switch_items = [node.stmt]
|
|
2784
4017
|
else:
|
|
2785
4018
|
switch_items = []
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
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)
|
|
2791
4070
|
|
|
2792
4071
|
label_blocks = {}
|
|
2793
4072
|
default_bb = after_bb
|
|
@@ -2800,11 +4079,21 @@ class LLVMCodeGenerator(object):
|
|
|
2800
4079
|
if isinstance(item, c_ast.Default):
|
|
2801
4080
|
default_bb = bb
|
|
2802
4081
|
|
|
2803
|
-
switch_inst = self.builder.switch(cond_val, default_bb)
|
|
2804
|
-
|
|
2805
4082
|
with self.new_scope():
|
|
2806
4083
|
self.define("break", after_bb)
|
|
2807
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
|
+
|
|
2808
4097
|
for item in labels:
|
|
2809
4098
|
if not isinstance(item, c_ast.Case):
|
|
2810
4099
|
continue
|
|
@@ -2825,10 +4114,12 @@ class LLVMCodeGenerator(object):
|
|
|
2825
4114
|
|
|
2826
4115
|
for idx, item in enumerate(labels):
|
|
2827
4116
|
self.builder.position_at_end(label_blocks[id(item)])
|
|
2828
|
-
for stmt in item
|
|
2829
|
-
self.codegen(stmt)
|
|
4117
|
+
for stmt in label_bodies.get(id(item), []):
|
|
2830
4118
|
if self.builder.block.is_terminated:
|
|
2831
|
-
|
|
4119
|
+
if isinstance(stmt, c_ast.Label):
|
|
4120
|
+
self.codegen(stmt)
|
|
4121
|
+
continue
|
|
4122
|
+
self.codegen(stmt)
|
|
2832
4123
|
if not self.builder.block.is_terminated:
|
|
2833
4124
|
next_bb = after_bb
|
|
2834
4125
|
if idx + 1 < len(labels):
|
|
@@ -2850,7 +4141,10 @@ class LLVMCodeGenerator(object):
|
|
|
2850
4141
|
self.builder.cbranch(cmp, then_bb, else_bb)
|
|
2851
4142
|
|
|
2852
4143
|
self.builder.position_at_end(then_bb)
|
|
2853
|
-
|
|
4144
|
+
if node.iftrue is None:
|
|
4145
|
+
true_val = cond_val
|
|
4146
|
+
else:
|
|
4147
|
+
true_val, _ = self.codegen(node.iftrue)
|
|
2854
4148
|
true_bb_end = self.builder.block
|
|
2855
4149
|
|
|
2856
4150
|
self.builder.position_at_end(else_bb)
|
|
@@ -2858,11 +4152,7 @@ class LLVMCodeGenerator(object):
|
|
|
2858
4152
|
false_bb_end = self.builder.block
|
|
2859
4153
|
|
|
2860
4154
|
def zero_value(target_type):
|
|
2861
|
-
|
|
2862
|
-
return ir.Constant(target_type, None)
|
|
2863
|
-
if self._is_floating_ir_type(target_type):
|
|
2864
|
-
return ir.Constant(target_type, 0.0)
|
|
2865
|
-
return ir.Constant(target_type, 0)
|
|
4155
|
+
return self._zero_initializer(target_type)
|
|
2866
4156
|
|
|
2867
4157
|
def pick_target_type(lhs, rhs):
|
|
2868
4158
|
if lhs is None and rhs is None:
|
|
@@ -2921,19 +4211,48 @@ class LLVMCodeGenerator(object):
|
|
|
2921
4211
|
self.builder.position_at_end(merge_bb)
|
|
2922
4212
|
if not incoming:
|
|
2923
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
|
+
)
|
|
2924
4223
|
if len(incoming) == 1:
|
|
2925
|
-
|
|
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
|
|
2926
4232
|
|
|
2927
4233
|
phi = self.builder.phi(target, "ternary")
|
|
2928
4234
|
for pred, value in incoming:
|
|
2929
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)
|
|
2930
4242
|
return phi, None
|
|
2931
4243
|
|
|
2932
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)
|
|
2933
4252
|
|
|
2934
4253
|
expr, ptr = self.codegen(node.expr)
|
|
2935
4254
|
|
|
2936
|
-
|
|
4255
|
+
self._validate_explicit_cast(expr.type, dest_ir_type)
|
|
2937
4256
|
# Check if casting to unsigned type
|
|
2938
4257
|
is_unsigned = False
|
|
2939
4258
|
if isinstance(node.to_type.type, c_ast.TypeDecl) and isinstance(
|
|
@@ -2982,6 +4301,9 @@ class LLVMCodeGenerator(object):
|
|
|
2982
4301
|
self._tag_value_from_decl_type(result, node.to_type.type)
|
|
2983
4302
|
return result, None
|
|
2984
4303
|
|
|
4304
|
+
def codegen_CompoundLiteral(self, node):
|
|
4305
|
+
return self._materialize_compound_literal(node.type.type, node.init)
|
|
4306
|
+
|
|
2985
4307
|
def codegen_FuncCall(self, node):
|
|
2986
4308
|
|
|
2987
4309
|
callee = None
|
|
@@ -2993,13 +4315,111 @@ class LLVMCodeGenerator(object):
|
|
|
2993
4315
|
return self._codegen_builtin_va_end(node)
|
|
2994
4316
|
if callee == "__builtin_va_copy":
|
|
2995
4317
|
return self._codegen_builtin_va_copy(node)
|
|
4318
|
+
if callee == "__builtin_alloca":
|
|
4319
|
+
return self._codegen_builtin_alloca(node)
|
|
2996
4320
|
if callee == "__builtin_va_arg":
|
|
2997
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)
|
|
2998
4416
|
else:
|
|
2999
4417
|
# Calling function pointer in struct: s.fn(args)
|
|
3000
4418
|
call_args = []
|
|
4419
|
+
arg_nodes = []
|
|
3001
4420
|
if node.args:
|
|
3002
|
-
|
|
4421
|
+
arg_nodes = list(node.args.exprs)
|
|
4422
|
+
call_args = [self.codegen(arg)[0] for arg in arg_nodes]
|
|
3003
4423
|
fp_val, _ = self.codegen(node.name)
|
|
3004
4424
|
if isinstance(fp_val.type, ir.PointerType) and isinstance(
|
|
3005
4425
|
fp_val.type.pointee, ir.FunctionType
|
|
@@ -3008,10 +4428,15 @@ class LLVMCodeGenerator(object):
|
|
|
3008
4428
|
ftype = fp_val.type.pointee
|
|
3009
4429
|
coerced = []
|
|
3010
4430
|
for j, a in enumerate(call_args):
|
|
4431
|
+
arg_node = arg_nodes[j] if j < len(arg_nodes) else None
|
|
3011
4432
|
if j < len(ftype.args):
|
|
3012
|
-
coerced.append(
|
|
4433
|
+
coerced.append(
|
|
4434
|
+
self._coerce_arg(a, ftype.args[j], arg_node=arg_node)
|
|
4435
|
+
)
|
|
3013
4436
|
else:
|
|
3014
|
-
coerced.append(
|
|
4437
|
+
coerced.append(
|
|
4438
|
+
self._default_arg_promotion(a, arg_node=arg_node)
|
|
4439
|
+
)
|
|
3015
4440
|
call_args = coerced
|
|
3016
4441
|
ret_type = ftype.return_type
|
|
3017
4442
|
if isinstance(ret_type, ir.VoidType):
|
|
@@ -3030,8 +4455,10 @@ class LLVMCodeGenerator(object):
|
|
|
3030
4455
|
_, callee_func = self.lookup(callee)
|
|
3031
4456
|
|
|
3032
4457
|
call_args = []
|
|
4458
|
+
arg_nodes = []
|
|
3033
4459
|
if node.args:
|
|
3034
|
-
|
|
4460
|
+
arg_nodes = list(node.args.exprs)
|
|
4461
|
+
call_args = [self.codegen(arg)[0] for arg in arg_nodes]
|
|
3035
4462
|
|
|
3036
4463
|
# Function pointer: load the pointer and call through it
|
|
3037
4464
|
if not isinstance(callee_func, ir.Function):
|
|
@@ -3049,7 +4476,16 @@ class LLVMCodeGenerator(object):
|
|
|
3049
4476
|
):
|
|
3050
4477
|
ftype = func_val.type.pointee
|
|
3051
4478
|
coerced = [
|
|
3052
|
-
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
|
+
)
|
|
3053
4489
|
for j, a in enumerate(call_args)
|
|
3054
4490
|
]
|
|
3055
4491
|
ret_type = ftype.return_type
|
|
@@ -3070,7 +4506,9 @@ class LLVMCodeGenerator(object):
|
|
|
3070
4506
|
return ir.Constant(int64_t, 0), None
|
|
3071
4507
|
|
|
3072
4508
|
# Convert arguments to match function parameter types
|
|
3073
|
-
converted = self._convert_call_args(
|
|
4509
|
+
converted = self._convert_call_args(
|
|
4510
|
+
call_args, callee_func, arg_nodes=arg_nodes
|
|
4511
|
+
)
|
|
3074
4512
|
|
|
3075
4513
|
# Call and handle return type
|
|
3076
4514
|
try:
|
|
@@ -3100,11 +4538,18 @@ class LLVMCodeGenerator(object):
|
|
|
3100
4538
|
return existing
|
|
3101
4539
|
return ir.Function(self.module, ir.FunctionType(ret_type, arg_types), name=name)
|
|
3102
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
|
+
|
|
3103
4548
|
def _codegen_builtin_va_start(self, node):
|
|
3104
4549
|
if not node.args or not node.args.exprs:
|
|
3105
4550
|
return ir.Constant(int64_t, 0), None
|
|
3106
|
-
ap_addr
|
|
3107
|
-
if
|
|
4551
|
+
ap_addr = self._builtin_va_list_storage(node.args.exprs[0])
|
|
4552
|
+
if ap_addr is None:
|
|
3108
4553
|
return ir.Constant(int64_t, 0), None
|
|
3109
4554
|
intrinsic = self._get_or_declare_intrinsic(
|
|
3110
4555
|
"llvm.va_start", ir.VoidType(), [voidptr_t]
|
|
@@ -3118,8 +4563,8 @@ class LLVMCodeGenerator(object):
|
|
|
3118
4563
|
def _codegen_builtin_va_end(self, node):
|
|
3119
4564
|
if not node.args or not node.args.exprs:
|
|
3120
4565
|
return ir.Constant(int64_t, 0), None
|
|
3121
|
-
ap_addr
|
|
3122
|
-
if
|
|
4566
|
+
ap_addr = self._builtin_va_list_storage(node.args.exprs[0])
|
|
4567
|
+
if ap_addr is None:
|
|
3123
4568
|
return ir.Constant(int64_t, 0), None
|
|
3124
4569
|
intrinsic = self._get_or_declare_intrinsic(
|
|
3125
4570
|
"llvm.va_end", ir.VoidType(), [voidptr_t]
|
|
@@ -3133,11 +4578,11 @@ class LLVMCodeGenerator(object):
|
|
|
3133
4578
|
def _codegen_builtin_va_copy(self, node):
|
|
3134
4579
|
if not node.args or len(node.args.exprs) < 2:
|
|
3135
4580
|
return ir.Constant(int64_t, 0), None
|
|
3136
|
-
dst_addr
|
|
3137
|
-
src_addr
|
|
3138
|
-
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:
|
|
3139
4584
|
return ir.Constant(int64_t, 0), None
|
|
3140
|
-
if
|
|
4585
|
+
if src_addr is None:
|
|
3141
4586
|
return ir.Constant(int64_t, 0), None
|
|
3142
4587
|
src_val = self._safe_load(src_addr)
|
|
3143
4588
|
dst_pointee = dst_addr.type.pointee
|
|
@@ -3146,24 +4591,429 @@ class LLVMCodeGenerator(object):
|
|
|
3146
4591
|
self._safe_store(src_val, dst_addr)
|
|
3147
4592
|
return ir.Constant(int64_t, 0), None
|
|
3148
4593
|
|
|
3149
|
-
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):
|
|
3150
4998
|
"""Convert call arguments to match function parameter types."""
|
|
3151
4999
|
converted = []
|
|
3152
5000
|
param_types = [p.type for p in callee_func.args]
|
|
3153
5001
|
|
|
3154
5002
|
for i, arg in enumerate(call_args):
|
|
5003
|
+
arg_node = arg_nodes[i] if arg_nodes and i < len(arg_nodes) else None
|
|
3155
5004
|
if i < len(param_types):
|
|
3156
5005
|
expected = param_types[i]
|
|
3157
|
-
arg = self._coerce_arg(arg, expected)
|
|
5006
|
+
arg = self._coerce_arg(arg, expected, arg_node=arg_node)
|
|
3158
5007
|
else:
|
|
3159
|
-
arg = self._default_arg_promotion(arg)
|
|
5008
|
+
arg = self._default_arg_promotion(arg, arg_node=arg_node)
|
|
3160
5009
|
converted.append(arg)
|
|
3161
5010
|
return converted
|
|
3162
5011
|
|
|
3163
|
-
def _default_arg_promotion(self, arg):
|
|
5012
|
+
def _default_arg_promotion(self, arg, arg_node=None):
|
|
3164
5013
|
"""Apply C default argument promotions for variadic calls."""
|
|
3165
5014
|
if arg is None or isinstance(getattr(arg, "type", None), ir.VoidType):
|
|
3166
5015
|
return ir.Constant(int64_t, 0)
|
|
5016
|
+
arg = self._decay_array_expr_to_pointer(arg_node, arg, "varargarraydecay")
|
|
3167
5017
|
if isinstance(arg.type, ir.ArrayType):
|
|
3168
5018
|
return self._implicit_convert(arg, ir.PointerType(arg.type.element))
|
|
3169
5019
|
if isinstance(arg.type, ir.FloatType):
|
|
@@ -3172,7 +5022,7 @@ class LLVMCodeGenerator(object):
|
|
|
3172
5022
|
return self._integer_promotion(arg)
|
|
3173
5023
|
return arg
|
|
3174
5024
|
|
|
3175
|
-
def _coerce_arg(self, arg, expected):
|
|
5025
|
+
def _coerce_arg(self, arg, expected, arg_node=None):
|
|
3176
5026
|
"""Coerce a single argument to the expected type."""
|
|
3177
5027
|
if arg is None or isinstance(getattr(arg, "type", None), ir.VoidType):
|
|
3178
5028
|
return (
|
|
@@ -3180,16 +5030,13 @@ class LLVMCodeGenerator(object):
|
|
|
3180
5030
|
if isinstance(expected, ir.PointerType)
|
|
3181
5031
|
else ir.Constant(int64_t, 0)
|
|
3182
5032
|
)
|
|
5033
|
+
arg = self._decay_array_expr_to_pointer(arg_node, arg, "argarraydecay")
|
|
3183
5034
|
if arg.type == expected:
|
|
3184
5035
|
return arg
|
|
3185
|
-
#
|
|
5036
|
+
# Array values decay to pointers at the call site; do not try to
|
|
5037
|
+
# synthesize globals from function-local SSA array values here.
|
|
3186
5038
|
if isinstance(arg.type, ir.ArrayType) and isinstance(expected, ir.PointerType):
|
|
3187
|
-
|
|
3188
|
-
self.module, arg.type, self.module.get_unique_name("str")
|
|
3189
|
-
)
|
|
3190
|
-
gv.initializer = arg
|
|
3191
|
-
gv.global_constant = True
|
|
3192
|
-
return self.builder.bitcast(gv, expected)
|
|
5039
|
+
return self._implicit_convert(arg, expected)
|
|
3193
5040
|
# Pointer -> different pointer: bitcast
|
|
3194
5041
|
if isinstance(arg.type, ir.PointerType) and isinstance(
|
|
3195
5042
|
expected, ir.PointerType
|
|
@@ -3212,11 +5059,27 @@ class LLVMCodeGenerator(object):
|
|
|
3212
5059
|
):
|
|
3213
5060
|
return None, None
|
|
3214
5061
|
|
|
3215
|
-
#
|
|
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
|
|
3216
5080
|
is_static = node.storage and "static" in node.storage
|
|
3217
|
-
if is_static and not self.in_global and isinstance(node.type, c_ast.
|
|
3218
|
-
|
|
3219
|
-
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)
|
|
3220
5083
|
# Create unique global name
|
|
3221
5084
|
global_name = self._static_local_symbol_name(node.name)
|
|
3222
5085
|
gv = self._create_bound_global(node.name, ir_type, symbol_name=global_name)
|
|
@@ -3228,7 +5091,7 @@ class LLVMCodeGenerator(object):
|
|
|
3228
5091
|
return None, None
|
|
3229
5092
|
|
|
3230
5093
|
if self._is_global_extern_decl(node):
|
|
3231
|
-
ir_type = self._extern_decl_ir_type(node.type)
|
|
5094
|
+
ir_type = self._extern_decl_ir_type(node.name, node.type)
|
|
3232
5095
|
self._prepare_file_scope_object(
|
|
3233
5096
|
node.name,
|
|
3234
5097
|
ir_type,
|
|
@@ -3243,22 +5106,17 @@ class LLVMCodeGenerator(object):
|
|
|
3243
5106
|
# Forward function declaration: int foo(int x);
|
|
3244
5107
|
if isinstance(node.type, c_ast.FuncDecl):
|
|
3245
5108
|
funcname = node.name
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
is_va = True
|
|
3253
|
-
continue
|
|
3254
|
-
t = self._resolve_param_type(arg)
|
|
3255
|
-
if t is not None:
|
|
3256
|
-
arg_types.append(t)
|
|
3257
|
-
function_type = ir.FunctionType(ir_type, arg_types, var_arg=is_va)
|
|
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
|
+
)
|
|
3258
5115
|
symbol_name = self._register_file_scope_function(
|
|
3259
5116
|
funcname,
|
|
3260
5117
|
function_type,
|
|
3261
5118
|
storage=node.storage,
|
|
5119
|
+
funcspec=node.funcspec,
|
|
3262
5120
|
is_definition=False,
|
|
3263
5121
|
)
|
|
3264
5122
|
# Skip if already exists (module globals, libc, or env)
|
|
@@ -3268,17 +5126,12 @@ class LLVMCodeGenerator(object):
|
|
|
3268
5126
|
self._mark_unsigned_return(existing)
|
|
3269
5127
|
self.define(funcname, (None, existing))
|
|
3270
5128
|
return None, None
|
|
3271
|
-
if funcname in LIBC_FUNCTIONS:
|
|
3272
|
-
self._declare_libc(funcname)
|
|
3273
|
-
return None, None
|
|
3274
5129
|
try:
|
|
3275
5130
|
func = ir.Function(
|
|
3276
5131
|
self.module,
|
|
3277
5132
|
function_type,
|
|
3278
5133
|
name=symbol_name,
|
|
3279
5134
|
)
|
|
3280
|
-
if self._is_file_scope_static(node.storage):
|
|
3281
|
-
func.linkage = "internal"
|
|
3282
5135
|
if self._func_decl_returns_unsigned(node.type):
|
|
3283
5136
|
self._mark_unsigned_return(func)
|
|
3284
5137
|
self.define(funcname, (ir_type, func))
|
|
@@ -3305,8 +5158,29 @@ class LLVMCodeGenerator(object):
|
|
|
3305
5158
|
if isinstance(node.type.type, c_ast.IdentifierType):
|
|
3306
5159
|
# Check if the type resolves to a struct or pointer via typedef
|
|
3307
5160
|
resolved = self._resolve_type_str(node.type.type.names)
|
|
3308
|
-
if isinstance(
|
|
3309
|
-
|
|
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
|
|
3310
5184
|
):
|
|
3311
5185
|
name = node.type.declname
|
|
3312
5186
|
ir_type = resolved
|
|
@@ -3329,11 +5203,20 @@ class LLVMCodeGenerator(object):
|
|
|
3329
5203
|
node.init, ir_type
|
|
3330
5204
|
)
|
|
3331
5205
|
else:
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
self._safe_store(
|
|
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)
|
|
3337
5220
|
elif self.in_global and write_initializer:
|
|
3338
5221
|
ret.initializer = self._zero_initializer(ir_type)
|
|
3339
5222
|
return None, None
|
|
@@ -3345,8 +5228,15 @@ class LLVMCodeGenerator(object):
|
|
|
3345
5228
|
if isinstance(node.type.type, c_ast.Union)
|
|
3346
5229
|
else self.codegen_Struct
|
|
3347
5230
|
)
|
|
3348
|
-
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:
|
|
3349
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))
|
|
3350
5240
|
if not self.in_global:
|
|
3351
5241
|
ret = self._alloca_in_entry(struct_type, name)
|
|
3352
5242
|
self.define(name, (struct_type, ret))
|
|
@@ -3366,18 +5256,28 @@ class LLVMCodeGenerator(object):
|
|
|
3366
5256
|
node.init, struct_type
|
|
3367
5257
|
)
|
|
3368
5258
|
else:
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
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)
|
|
3376
5274
|
elif self.in_global and write_initializer:
|
|
3377
5275
|
ret.initializer = self._zero_initializer(struct_type)
|
|
3378
5276
|
return None, None
|
|
3379
5277
|
else:
|
|
3380
|
-
struct_type = self.env[
|
|
5278
|
+
struct_type = self.env[
|
|
5279
|
+
self._tag_type_key(node.type.type.name)
|
|
5280
|
+
][0]
|
|
3381
5281
|
if not self.in_global:
|
|
3382
5282
|
ret = self._alloca_in_entry(struct_type, name)
|
|
3383
5283
|
self.define(name, (struct_type, ret))
|
|
@@ -3397,23 +5297,38 @@ class LLVMCodeGenerator(object):
|
|
|
3397
5297
|
node.init, struct_type
|
|
3398
5298
|
)
|
|
3399
5299
|
else:
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
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)
|
|
3407
5315
|
elif self.in_global and write_initializer:
|
|
3408
5316
|
ret.initializer = self._zero_initializer(struct_type)
|
|
3409
5317
|
return None, None
|
|
3410
5318
|
else:
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
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)
|
|
3417
5332
|
if self._is_floating_ir_type(ir_type):
|
|
3418
5333
|
init = 0.0
|
|
3419
5334
|
else:
|
|
@@ -3423,6 +5338,11 @@ class LLVMCodeGenerator(object):
|
|
|
3423
5338
|
if self.in_global:
|
|
3424
5339
|
init_val = self._build_const_init(node.init, ir_type)
|
|
3425
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)
|
|
3426
5346
|
init_val, _ = self.codegen(node.init)
|
|
3427
5347
|
else:
|
|
3428
5348
|
init_val = self._zero_initializer(ir_type)
|
|
@@ -3439,45 +5359,60 @@ class LLVMCodeGenerator(object):
|
|
|
3439
5359
|
if write_initializer:
|
|
3440
5360
|
var_addr.initializer = init_val
|
|
3441
5361
|
else:
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
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)
|
|
3447
5368
|
init_val = self._implicit_convert(init_val, ir_type)
|
|
3448
5369
|
self._safe_store(init_val, var_addr)
|
|
3449
5370
|
if self.in_global and is_unsigned:
|
|
3450
5371
|
self._mark_unsigned(var_addr)
|
|
3451
5372
|
|
|
3452
5373
|
elif isinstance(node.type, c_ast.ArrayDecl):
|
|
3453
|
-
global_symbol_name = self._file_scope_symbol_name(node.name, node.storage)
|
|
3454
5374
|
array_list = []
|
|
3455
5375
|
array_node = node.type
|
|
3456
5376
|
var_addr = None
|
|
3457
5377
|
var_ir_type = None
|
|
3458
5378
|
elem_ir_type = None
|
|
3459
5379
|
write_initializer = True
|
|
5380
|
+
inferred_top_dim = self._infer_array_count_from_initializer(node.init)
|
|
3460
5381
|
while True:
|
|
3461
5382
|
array_next_type = array_node.type
|
|
3462
5383
|
if isinstance(array_next_type, c_ast.TypeDecl):
|
|
3463
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
|
|
3464
5391
|
array_list.append(dim_val)
|
|
3465
5392
|
elem_ir_type = self._resolve_ast_type(array_next_type)
|
|
3466
5393
|
break
|
|
3467
5394
|
|
|
3468
5395
|
elif isinstance(array_next_type, c_ast.ArrayDecl):
|
|
3469
|
-
|
|
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)
|
|
3470
5404
|
array_node = array_next_type
|
|
3471
5405
|
continue
|
|
3472
5406
|
elif isinstance(array_next_type, c_ast.PtrDecl):
|
|
3473
5407
|
# Array of pointers: int *arr[3]
|
|
3474
5408
|
dim = self._eval_dim(array_node.dim)
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
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)
|
|
3481
5416
|
elem_ir_type = elem_ir
|
|
3482
5417
|
arr_ir = ir.ArrayType(elem_ir, dim)
|
|
3483
5418
|
arr_ir.dim_array = [dim]
|
|
@@ -3519,42 +5454,6 @@ class LLVMCodeGenerator(object):
|
|
|
3519
5454
|
if self._has_unsigned_scalar_pointee(node.type):
|
|
3520
5455
|
self._mark_unsigned_pointee(var_addr)
|
|
3521
5456
|
|
|
3522
|
-
# Infer the size of zero-length arrays from the initializer.
|
|
3523
|
-
if (
|
|
3524
|
-
isinstance(var_ir_type, ir.ArrayType)
|
|
3525
|
-
and var_ir_type.count == 0
|
|
3526
|
-
and node.init is not None
|
|
3527
|
-
):
|
|
3528
|
-
actual_count = None
|
|
3529
|
-
if isinstance(node.init, c_ast.InitList):
|
|
3530
|
-
actual_count = len(node.init.exprs)
|
|
3531
|
-
elif (
|
|
3532
|
-
isinstance(node.init, c_ast.Constant)
|
|
3533
|
-
and getattr(node.init, "type", None) == "string"
|
|
3534
|
-
):
|
|
3535
|
-
raw = node.init.value[1:-1]
|
|
3536
|
-
actual_count = len(self._process_escapes(raw)) + 1
|
|
3537
|
-
if actual_count is not None and elem_ir_type is not None:
|
|
3538
|
-
var_ir_type = ir.ArrayType(elem_ir_type, actual_count)
|
|
3539
|
-
var_ir_type.dim_array = [actual_count]
|
|
3540
|
-
if self.in_global:
|
|
3541
|
-
new_name = self.module.get_unique_name(global_symbol_name)
|
|
3542
|
-
var_addr = self._create_bound_global(
|
|
3543
|
-
node.name,
|
|
3544
|
-
var_ir_type,
|
|
3545
|
-
symbol_name=new_name,
|
|
3546
|
-
storage=node.storage,
|
|
3547
|
-
)
|
|
3548
|
-
self.define(node.name, (var_ir_type, var_addr))
|
|
3549
|
-
if not hasattr(self, "_array_renames"):
|
|
3550
|
-
self._array_renames = {}
|
|
3551
|
-
self._array_renames[
|
|
3552
|
-
f'@"{global_symbol_name}"'
|
|
3553
|
-
] = f'@"{new_name}"'
|
|
3554
|
-
else:
|
|
3555
|
-
var_addr = self._alloca_in_entry(var_ir_type, node.name)
|
|
3556
|
-
self.define(node.name, (var_ir_type, var_addr))
|
|
3557
|
-
|
|
3558
5457
|
if self._has_unsigned_scalar_pointee(node.type):
|
|
3559
5458
|
self._mark_unsigned_pointee(var_addr)
|
|
3560
5459
|
|
|
@@ -3570,10 +5469,11 @@ class LLVMCodeGenerator(object):
|
|
|
3570
5469
|
except Exception:
|
|
3571
5470
|
var_addr.initializer = self._zero_initializer(var_ir_type)
|
|
3572
5471
|
elif isinstance(node.init, c_ast.InitList):
|
|
5472
|
+
self._safe_store(self._zero_initializer(var_ir_type), var_addr)
|
|
3573
5473
|
self._init_array(
|
|
3574
5474
|
var_addr,
|
|
3575
5475
|
node.init,
|
|
3576
|
-
|
|
5476
|
+
var_ir_type.element,
|
|
3577
5477
|
[ir.Constant(ir.IntType(32), 0)],
|
|
3578
5478
|
)
|
|
3579
5479
|
elif (
|
|
@@ -3582,6 +5482,7 @@ class LLVMCodeGenerator(object):
|
|
|
3582
5482
|
and isinstance(elem_ir_type, ir.IntType)
|
|
3583
5483
|
and elem_ir_type.width == 8
|
|
3584
5484
|
):
|
|
5485
|
+
self._safe_store(self._zero_initializer(var_ir_type), var_addr)
|
|
3585
5486
|
raw = self._process_escapes(node.init.value[1:-1]) + "\00"
|
|
3586
5487
|
idx0 = ir.Constant(ir.IntType(32), 0)
|
|
3587
5488
|
for i, ch in enumerate(raw[: var_ir_type.count]):
|
|
@@ -3611,12 +5512,16 @@ class LLVMCodeGenerator(object):
|
|
|
3611
5512
|
elif isinstance(sub_next_type.type, c_ast.Union):
|
|
3612
5513
|
resolved_pointee_type = self.codegen_Union(sub_next_type.type)
|
|
3613
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"
|
|
3614
5519
|
else:
|
|
3615
5520
|
type_str = sub_next_type.type.names
|
|
3616
5521
|
resolved = self._get_ir_type(type_str)
|
|
3617
5522
|
if isinstance(resolved, ir.Type):
|
|
3618
5523
|
resolved_pointee_type = resolved
|
|
3619
|
-
if
|
|
5524
|
+
if _is_struct_ir_type(resolved):
|
|
3620
5525
|
type_str = "struct"
|
|
3621
5526
|
break
|
|
3622
5527
|
elif isinstance(sub_next_type, c_ast.PtrDecl):
|
|
@@ -3642,10 +5547,28 @@ class LLVMCodeGenerator(object):
|
|
|
3642
5547
|
self._mark_unsigned_return(var_addr)
|
|
3643
5548
|
if node.init is not None:
|
|
3644
5549
|
init_val, _ = self.codegen(node.init)
|
|
3645
|
-
#
|
|
3646
|
-
if
|
|
3647
|
-
|
|
3648
|
-
|
|
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)
|
|
3649
5572
|
return None, var_addr
|
|
3650
5573
|
pass
|
|
3651
5574
|
|
|
@@ -3707,17 +5630,13 @@ class LLVMCodeGenerator(object):
|
|
|
3707
5630
|
var_addr.initializer = ir.Constant(var_ir_type, None)
|
|
3708
5631
|
else:
|
|
3709
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
|
+
)
|
|
3710
5636
|
if isinstance(init_val.type, ir.ArrayType) and isinstance(
|
|
3711
5637
|
var_ir_type, ir.PointerType
|
|
3712
5638
|
):
|
|
3713
|
-
|
|
3714
|
-
self.module,
|
|
3715
|
-
init_val.type,
|
|
3716
|
-
self.module.get_unique_name("str"),
|
|
3717
|
-
)
|
|
3718
|
-
gv.initializer = init_val
|
|
3719
|
-
gv.global_constant = True
|
|
3720
|
-
init_val = self.builder.bitcast(gv, var_ir_type)
|
|
5639
|
+
init_val = self._implicit_convert(init_val, var_ir_type)
|
|
3721
5640
|
elif init_val.type != var_ir_type:
|
|
3722
5641
|
init_val = self._implicit_convert(init_val, var_ir_type)
|
|
3723
5642
|
self._safe_store(init_val, var_addr)
|
|
@@ -3727,6 +5646,14 @@ class LLVMCodeGenerator(object):
|
|
|
3727
5646
|
return None, var_addr
|
|
3728
5647
|
|
|
3729
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
|
|
3730
5657
|
|
|
3731
5658
|
valtype, var = self.lookup(node.name)
|
|
3732
5659
|
node.ir_type = valtype
|
|
@@ -3813,7 +5740,7 @@ class LLVMCodeGenerator(object):
|
|
|
3813
5740
|
# Non-array type (opaque struct etc): treat as pointer subscript
|
|
3814
5741
|
if not isinstance(name_type, ir.ArrayType):
|
|
3815
5742
|
ptr = (
|
|
3816
|
-
self.
|
|
5743
|
+
self._implicit_convert(name_ir, ir.PointerType(int8_t))
|
|
3817
5744
|
if not isinstance(name_ir.type, ir.PointerType)
|
|
3818
5745
|
else name_ir
|
|
3819
5746
|
)
|
|
@@ -3896,22 +5823,30 @@ class LLVMCodeGenerator(object):
|
|
|
3896
5823
|
retval, _ = self.codegen(node.expr)
|
|
3897
5824
|
# Implicit convert to function return type
|
|
3898
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
|
|
3899
5829
|
if retval.type != func_ret_type:
|
|
3900
5830
|
retval = self._implicit_convert(retval, func_ret_type)
|
|
3901
5831
|
self.builder.ret(retval)
|
|
3902
5832
|
return None, None
|
|
3903
5833
|
|
|
3904
5834
|
def codegen_Compound(self, node):
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
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)
|
|
3915
5850
|
return None, None
|
|
3916
5851
|
|
|
3917
5852
|
def codegen_FuncDecl(self, node):
|
|
@@ -3930,31 +5865,38 @@ class LLVMCodeGenerator(object):
|
|
|
3930
5865
|
self.func_return_types = {}
|
|
3931
5866
|
self.func_return_types[funcname] = ir_type
|
|
3932
5867
|
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
if node.decl.type.args:
|
|
3936
|
-
for arg_type in node.decl.type.args.params:
|
|
3937
|
-
if isinstance(arg_type, c_ast.EllipsisParam):
|
|
3938
|
-
is_var_arg = True
|
|
3939
|
-
continue
|
|
3940
|
-
t = self._resolve_param_type(arg_type)
|
|
3941
|
-
if t is not None:
|
|
3942
|
-
arg_types.append(t)
|
|
5868
|
+
param_infos, is_var_arg = self._funcdef_param_infos(node)
|
|
5869
|
+
arg_types = [param_type for _name, param_type, _decl in param_infos]
|
|
3943
5870
|
|
|
3944
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
|
|
3945
5879
|
symbol_name = self._register_file_scope_function(
|
|
3946
5880
|
funcname,
|
|
3947
5881
|
function_type,
|
|
3948
5882
|
storage=node.decl.storage,
|
|
5883
|
+
funcspec=node.decl.funcspec,
|
|
3949
5884
|
is_definition=True,
|
|
3950
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
|
+
)
|
|
3951
5890
|
|
|
3952
5891
|
with self.new_function():
|
|
5892
|
+
self._function_display_name = funcname
|
|
3953
5893
|
|
|
3954
5894
|
existing = self.module.globals.get(symbol_name)
|
|
3955
5895
|
if existing and isinstance(existing, ir.Function):
|
|
3956
5896
|
if existing.is_declaration:
|
|
3957
5897
|
self.function = existing
|
|
5898
|
+
if needs_internal_linkage:
|
|
5899
|
+
self.function.linkage = "internal"
|
|
3958
5900
|
else:
|
|
3959
5901
|
raise SemanticError(f"redefinition of function '{funcname}'")
|
|
3960
5902
|
else:
|
|
@@ -3964,7 +5906,7 @@ class LLVMCodeGenerator(object):
|
|
|
3964
5906
|
function_type,
|
|
3965
5907
|
name=symbol_name,
|
|
3966
5908
|
)
|
|
3967
|
-
if
|
|
5909
|
+
if needs_internal_linkage:
|
|
3968
5910
|
self.function.linkage = "internal"
|
|
3969
5911
|
except Exception:
|
|
3970
5912
|
raise SemanticError(f"failed to define function '{funcname}'")
|
|
@@ -3975,53 +5917,38 @@ class LLVMCodeGenerator(object):
|
|
|
3975
5917
|
if len(self.env.maps) > 1:
|
|
3976
5918
|
self.env.maps[1][funcname] = (ir_type, self.function)
|
|
3977
5919
|
self.define(funcname, (ir_type, self.function))
|
|
3978
|
-
|
|
3979
|
-
param_idx
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
)
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
self.define(pname, (arg_type, var))
|
|
3997
|
-
self._safe_store(self.function.args[param_idx], var)
|
|
3998
|
-
# Track unsigned params
|
|
3999
|
-
if isinstance(p, c_ast.Decl) and isinstance(
|
|
4000
|
-
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
|
|
4001
5938
|
):
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
p.type, c_ast.PtrDecl
|
|
4010
|
-
) and self._func_decl_returns_unsigned(p.type.type):
|
|
4011
|
-
self._mark_unsigned_return(var)
|
|
4012
|
-
param_idx += 1
|
|
4013
|
-
|
|
4014
|
-
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)
|
|
4015
5946
|
|
|
4016
5947
|
if not self.builder.block.is_terminated:
|
|
4017
5948
|
if isinstance(ir_type, ir.VoidType):
|
|
4018
5949
|
self.builder.ret_void()
|
|
4019
|
-
elif isinstance(ir_type, ir.PointerType):
|
|
4020
|
-
self.builder.ret(ir.Constant(ir_type, None))
|
|
4021
|
-
elif self._is_floating_ir_type(ir_type):
|
|
4022
|
-
self.builder.ret(ir.Constant(ir_type, 0.0))
|
|
4023
5950
|
else:
|
|
4024
|
-
self.builder.ret(
|
|
5951
|
+
self.builder.ret(self._zero_initializer(ir_type))
|
|
4025
5952
|
|
|
4026
5953
|
return None, None
|
|
4027
5954
|
|
|
@@ -4029,63 +5956,58 @@ class LLVMCodeGenerator(object):
|
|
|
4029
5956
|
# Generate LLVM types for struct members
|
|
4030
5957
|
|
|
4031
5958
|
# If this is a reference to a named struct without decls, look it up
|
|
4032
|
-
if node.name and
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
opaque =
|
|
4037
|
-
|
|
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))
|
|
4038
5967
|
return opaque
|
|
4039
5968
|
|
|
5969
|
+
if any(decl.bitsize is not None for decl in node.decls):
|
|
5970
|
+
return self._build_layout_backed_struct(node)
|
|
5971
|
+
|
|
4040
5972
|
member_types = []
|
|
4041
5973
|
member_names = []
|
|
4042
5974
|
member_decl_types = []
|
|
4043
5975
|
for decl in node.decls:
|
|
4044
|
-
|
|
4045
|
-
decl.type.type, c_ast.Struct
|
|
4046
|
-
):
|
|
4047
|
-
nested_type = self.codegen_Struct(decl.type.type)
|
|
4048
|
-
member_types.append(nested_type)
|
|
4049
|
-
elif isinstance(decl.type, c_ast.TypeDecl) and isinstance(
|
|
4050
|
-
decl.type.type, c_ast.Union
|
|
4051
|
-
):
|
|
4052
|
-
nested_type = self.codegen_Union(decl.type.type)
|
|
4053
|
-
member_types.append(nested_type)
|
|
4054
|
-
elif isinstance(decl.type, c_ast.ArrayDecl):
|
|
4055
|
-
# Handle multi-dimensional arrays: a[N][M] -> [N x [M x T]]
|
|
4056
|
-
def _build_array_type(arr_node):
|
|
4057
|
-
dim = self._eval_dim(arr_node.dim) if arr_node.dim else 0
|
|
4058
|
-
if isinstance(arr_node.type, c_ast.ArrayDecl):
|
|
4059
|
-
inner = _build_array_type(arr_node.type)
|
|
4060
|
-
else:
|
|
4061
|
-
inner = self._resolve_ast_type(arr_node.type)
|
|
4062
|
-
return ir.ArrayType(inner, dim)
|
|
4063
|
-
|
|
4064
|
-
member_types.append(_build_array_type(decl.type))
|
|
4065
|
-
elif isinstance(decl.type, c_ast.PtrDecl):
|
|
4066
|
-
member_types.append(self._resolve_ast_type(decl.type))
|
|
4067
|
-
elif isinstance(decl.type, c_ast.TypeDecl):
|
|
4068
|
-
type_str = decl.type.type.names
|
|
4069
|
-
member_types.append(self._get_ir_type(type_str))
|
|
4070
|
-
else:
|
|
4071
|
-
member_types.append(int64_t) # fallback
|
|
5976
|
+
member_types.append(self._resolve_struct_member_ir_type(decl))
|
|
4072
5977
|
member_names.append(decl.name)
|
|
4073
5978
|
member_decl_types.append(decl.type)
|
|
4074
5979
|
# Create the struct type
|
|
4075
|
-
struct_type =
|
|
5980
|
+
struct_type = self._identified_aggregate_type("struct", node.name, member_types)
|
|
4076
5981
|
struct_type.members = member_names
|
|
4077
5982
|
struct_type.member_decl_types = member_decl_types
|
|
4078
5983
|
|
|
4079
5984
|
# Register named structs for later reuse
|
|
4080
5985
|
if node.name:
|
|
4081
|
-
self.define(node.name, (struct_type, None))
|
|
5986
|
+
self.define(self._tag_type_key(node.name), (struct_type, None))
|
|
4082
5987
|
|
|
4083
5988
|
return struct_type
|
|
4084
5989
|
|
|
4085
5990
|
def codegen_Union(self, node):
|
|
4086
5991
|
"""Model union as a struct with alignment-preserving storage."""
|
|
4087
|
-
if node.name and
|
|
4088
|
-
|
|
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
|
|
4089
6011
|
|
|
4090
6012
|
member_types = {}
|
|
4091
6013
|
member_decl_types = {}
|
|
@@ -4112,18 +6034,17 @@ class LLVMCodeGenerator(object):
|
|
|
4112
6034
|
align_size = max_align
|
|
4113
6035
|
pad_size = max_size - align_size
|
|
4114
6036
|
if pad_size > 0:
|
|
4115
|
-
|
|
4116
|
-
[align_type, ir.ArrayType(int8_t, pad_size)]
|
|
4117
|
-
)
|
|
6037
|
+
union_body = [align_type, ir.ArrayType(int8_t, pad_size)]
|
|
4118
6038
|
else:
|
|
4119
|
-
|
|
6039
|
+
union_body = [align_type]
|
|
6040
|
+
union_type = self._identified_aggregate_type("union", node.name, union_body)
|
|
4120
6041
|
union_type.members = list(member_types.keys())
|
|
4121
6042
|
union_type.member_types = member_types
|
|
4122
6043
|
union_type.member_decl_types = member_decl_types
|
|
4123
6044
|
union_type.is_union = True
|
|
4124
6045
|
|
|
4125
6046
|
if node.name:
|
|
4126
|
-
self.define(node.name, (union_type, None))
|
|
6047
|
+
self.define(self._tag_type_key(node.name), (union_type, None))
|
|
4127
6048
|
|
|
4128
6049
|
return union_type
|
|
4129
6050
|
|
|
@@ -4167,7 +6088,7 @@ class LLVMCodeGenerator(object):
|
|
|
4167
6088
|
)
|
|
4168
6089
|
struct_addr = inner_addr
|
|
4169
6090
|
elif isinstance(node.name, c_ast.ID):
|
|
4170
|
-
struct_instance_addr = self.
|
|
6091
|
+
_, struct_instance_addr = self.lookup(node.name.name)
|
|
4171
6092
|
if not isinstance(struct_instance_addr.type, ir.PointerType):
|
|
4172
6093
|
raise Exception("Invalid struct reference")
|
|
4173
6094
|
|
|
@@ -4227,6 +6148,66 @@ class LLVMCodeGenerator(object):
|
|
|
4227
6148
|
if semantic_base_type is not None
|
|
4228
6149
|
else (val.type if hasattr(val.type, "members") else int8_t)
|
|
4229
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
|
|
4230
6211
|
|
|
4231
6212
|
# Union access: all fields share offset 0, use bitcast
|
|
4232
6213
|
if getattr(struct_type, "is_union", False):
|
|
@@ -4242,8 +6223,8 @@ class LLVMCodeGenerator(object):
|
|
|
4242
6223
|
resolved, ir.PointerType
|
|
4243
6224
|
):
|
|
4244
6225
|
pass
|
|
4245
|
-
elif isinstance(
|
|
4246
|
-
resolved
|
|
6226
|
+
elif isinstance(resolved, (ir.ArrayType, ir.PointerType)) or _is_struct_ir_type(
|
|
6227
|
+
resolved
|
|
4247
6228
|
):
|
|
4248
6229
|
semantic_field_type = resolved
|
|
4249
6230
|
except Exception:
|
|
@@ -4267,10 +6248,9 @@ class LLVMCodeGenerator(object):
|
|
|
4267
6248
|
|
|
4268
6249
|
# Opaque struct (no members) — treat as byte-offset access
|
|
4269
6250
|
if not hasattr(struct_type, "members"):
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
return val, ptr
|
|
6251
|
+
raise SemanticError(
|
|
6252
|
+
f"field '{node.field.name}' accessed on incomplete struct"
|
|
6253
|
+
)
|
|
4274
6254
|
|
|
4275
6255
|
field_index = None
|
|
4276
6256
|
for i, field in enumerate(struct_type.members):
|
|
@@ -4301,7 +6281,9 @@ class LLVMCodeGenerator(object):
|
|
|
4301
6281
|
resolved, ir.PointerType
|
|
4302
6282
|
):
|
|
4303
6283
|
pass # keep original array type
|
|
4304
|
-
elif isinstance(resolved,
|
|
6284
|
+
elif isinstance(resolved, ir.PointerType) or _is_struct_ir_type(
|
|
6285
|
+
resolved
|
|
6286
|
+
):
|
|
4305
6287
|
semantic_field_type = resolved
|
|
4306
6288
|
except Exception:
|
|
4307
6289
|
pass
|
|
@@ -4385,16 +6367,35 @@ class LLVMCodeGenerator(object):
|
|
|
4385
6367
|
if enumerator.value:
|
|
4386
6368
|
current_val = self._eval_const_expr(enumerator.value)
|
|
4387
6369
|
self.define(
|
|
4388
|
-
enumerator.name, (
|
|
6370
|
+
enumerator.name, (int32_t, ir.Constant(int32_t, current_val))
|
|
4389
6371
|
)
|
|
4390
6372
|
current_val += 1
|
|
4391
6373
|
return None, None
|
|
4392
6374
|
|
|
4393
6375
|
def _eval_const_expr(self, node):
|
|
4394
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
|
+
|
|
4395
6394
|
if isinstance(node, c_ast.Constant):
|
|
4396
6395
|
if node.type == "string":
|
|
4397
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)
|
|
4398
6399
|
v = node.value.rstrip("uUlL")
|
|
4399
6400
|
if v.startswith("'"):
|
|
4400
6401
|
return self._char_constant_value(v)
|
|
@@ -4415,8 +6416,8 @@ class LLVMCodeGenerator(object):
|
|
|
4415
6416
|
raw = node.expr.value[1:-1]
|
|
4416
6417
|
processed = self._process_escapes(raw)
|
|
4417
6418
|
return len(self._string_bytes(processed + "\00"))
|
|
4418
|
-
|
|
4419
|
-
return
|
|
6419
|
+
ir_t = self._infer_sizeof_operand_ir_type(node.expr)
|
|
6420
|
+
return self._ir_type_size(ir_t)
|
|
4420
6421
|
if node.op == "&" and isinstance(node.expr, c_ast.StructRef):
|
|
4421
6422
|
offset, _ = self._eval_offsetof_structref(node.expr)
|
|
4422
6423
|
return offset
|
|
@@ -4432,12 +6433,13 @@ class LLVMCodeGenerator(object):
|
|
|
4432
6433
|
elif isinstance(node, c_ast.BinaryOp):
|
|
4433
6434
|
l = self._eval_const_expr(node.left)
|
|
4434
6435
|
r = self._eval_const_expr(node.right)
|
|
6436
|
+
use_float = is_float_value(l) or is_float_value(r)
|
|
4435
6437
|
ops = {
|
|
4436
6438
|
"+": lambda a, b: a + b,
|
|
4437
6439
|
"-": lambda a, b: a - b,
|
|
4438
6440
|
"*": lambda a, b: a * b,
|
|
4439
|
-
"/": lambda a, b: a
|
|
4440
|
-
"%": 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),
|
|
4441
6443
|
"<<": lambda a, b: a << b,
|
|
4442
6444
|
">>": lambda a, b: a >> b,
|
|
4443
6445
|
"&": lambda a, b: a & b,
|
|
@@ -4469,6 +6471,14 @@ class LLVMCodeGenerator(object):
|
|
|
4469
6471
|
return 0 # unknown identifier defaults to 0
|
|
4470
6472
|
elif isinstance(node, c_ast.Cast):
|
|
4471
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__}")
|
|
4472
6482
|
elif isinstance(node, c_ast.Typename):
|
|
4473
6483
|
return 0
|
|
4474
6484
|
raise CodegenError(f"Not a constant expression: {type(node).__name__}")
|
|
@@ -4512,7 +6522,7 @@ class LLVMCodeGenerator(object):
|
|
|
4512
6522
|
elif isinstance(node.type.type, c_ast.Enum):
|
|
4513
6523
|
# typedef enum { A, B, C } MyEnum;
|
|
4514
6524
|
self.codegen_Enum(node.type.type)
|
|
4515
|
-
self.define(f"__typedef_{node.name}",
|
|
6525
|
+
self.define(f"__typedef_{node.name}", int32_t)
|
|
4516
6526
|
elif isinstance(node.type, c_ast.ArrayDecl):
|
|
4517
6527
|
self.define(f"__typedef_{node.name}", self._build_array_ir_type(node.type))
|
|
4518
6528
|
elif isinstance(node.type, c_ast.PtrDecl):
|
|
@@ -4536,4 +6546,7 @@ class LLVMCodeGenerator(object):
|
|
|
4536
6546
|
else:
|
|
4537
6547
|
ptr_type = ir.PointerType(base_ir)
|
|
4538
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)
|
|
4539
6552
|
return None, None
|