-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathsym.c
More file actions
137 lines (111 loc) · 3.5 KB
/
Copy pathsym.c
File metadata and controls
137 lines (111 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#pragma once
#include "./sym.h"
#include "../clib/set.c"
// clang-format off
// Sanity check used in debugging.
static bool sym_valid(const Sym *sym) {
return (
sym &&
is_aligned(sym) &&
is_aligned(&sym->name) &&
is_aligned(&sym->callees) &&
is_aligned(&sym->callers) &&
sym->name.len &&
set_valid((const Set *)&sym->callees) &&
set_valid((const Set *)&sym->callers)
);
}
// clang-format on
static void sym_deinit(Sym *sym) {
set_deinit(&sym->callees);
set_deinit(&sym->callers);
}
static void sym_init_intrin(Sym *sym) {
sym->type = SYM_INTRIN;
sym->name.len = (Ind)strlen(sym->name.buf);
sym->clobber = ASM_REGS_VOLATILE;
sym->interp_only = true;
}
static bool is_sym_leaf(const Sym *sym) { return !sym->callees.len; }
static void sym_auto_comp_only(Sym *caller, const Sym *callee) {
if (caller->comp_only) return;
if (!callee->comp_only) return;
caller->comp_only = true;
IF_DEBUG(eprintf(
"[system] word " FMT_QUOTED " uses compile-only word " FMT_QUOTED
", marking as compile-only\n",
caller->name.buf,
callee->name.buf
));
}
// Redundant with the caller-callee graph. TODO consider deduping.
static void sym_auto_interp_only(Sym *caller, const Sym *callee) {
if (caller->interp_only) return;
if (!callee->interp_only) return;
caller->interp_only = true;
IF_DEBUG(eprintf(
"[system] word " FMT_QUOTED " uses interpreter-only word " FMT_QUOTED
", marking as interpreter-only\n",
caller->name.buf,
callee->name.buf
));
}
static Err err_inline_not_norm(const Sym *sym) {
return errf(
"unable to inline " FMT_QUOTED ": not a regular Forth word", sym->name.buf
);
}
static Err err_inline_pc_rel(const Sym *sym) {
return errf(
"unable to inline word " FMT_QUOTED
": contains operations relative to the program counter (instruction address)",
sym->name.buf
);
}
static Err err_inline_not_leaf(const Sym *sym) {
return errf(
"unable to inline word " FMT_QUOTED ": not a leaf function", sym->name.buf
);
}
static Err err_inline_has_data(const Sym *sym) {
return errf(
"unable to inline word " FMT_QUOTED ": loads local immediate values",
sym->name.buf
);
}
// SYNC[sym_inlinable].
static Err validate_sym_inlinable(const Sym *sym) {
if (sym->type != SYM_NORM) return err_inline_not_norm(sym);
if (sym->norm.has_loads) return err_inline_pc_rel(sym);
if (!is_sym_leaf(sym)) return err_inline_not_leaf(sym);
// Same as `err_inline_pc_rel`. Redundant check for safety.
const auto spans = &sym->norm.spans;
IF_DEBUG(try_assert(sym->norm.has_loads == (spans->data < spans->ceil)));
if (spans->data < spans->ceil) return err_inline_has_data(sym);
return nullptr;
}
static void sym_auto_inlinable(Sym *sym) {
// SYNC[sym_inlinable].
if (sym->type != SYM_NORM) return;
if (sym->norm.has_loads) return;
if (!is_sym_leaf(sym)) return;
const auto spans = &sym->norm.spans;
if (spans->data < spans->ceil) return;
const auto len = spans->epi_err - spans->inner;
if (len > ASM_INLINABLE_INSTR_LEN) return;
sym->norm.inlinable = true;
IF_DEBUG(
eprintf("[system] symbol " FMT_QUOTED " is auto-inlinable\n", sym->name.buf)
);
}
static const char *wordlist_name(Wordlist val) {
switch (val) {
case WORDLIST_EXEC: return "WORDLIST_EXEC";
case WORDLIST_COMP: return "WORDLIST_COMP";
default: return "unknown wordlist";
}
}
static void sym_register_call(Sym *caller, Sym *callee) {
set_add(&caller->callees, callee);
set_add(&callee->callers, caller);
}