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
|
namespace explain;
include rt;
// writes the records of zy --explain-checks (format version 1, docs/SPEC.md
// 4.15.4). the compiler embeds this file and compiles it only in that mode;
// its analysis calls note once for every bounds check it keeps. no top-level
// unbounded here: it would carry over into the unit being explained.
const int NOT_LOOP = 1, NOT_INVARIANT = 2, NOT_LEN = 3, SIZE = 4, PACKED = 5, HOISTED = 6, MAYFREE = 7;
word src;
// one character of the unit's source
int byte(int k) { return (src[k >> 2] >> ((k & 3) * 8)) & 255; }
// the column (from 1) of the source offset o
int col(int o) {
int k = o;
while (k > 0 && byte(k - 1) != 10) k--;
return o - k + 1;
}
// a json string
int str(char* s) {
int i = 0, ch;
rt.put_c(34);
while (s[i]) {
ch = s[i] & 255;
if (ch == 34 || ch == 92) rt.put_c(92);
if (ch < 32) rt.put_c(32); else rt.put_c(ch);
i++;
}
rt.put_c(34);
return 0;
}
int field(char* name) { rt.put_c(44); str(name); rt.put_c(58); return 0; }
// the first line
int version() { rt.put_s("{\"version\":1}"); rt.put_c(10); return 0; }
// one kept check: kind 0 index, 1 pointer; o1 and o2 the source offsets of its [ and ]
int note(word unit, int kind, int why, int line, int o1, int end_line, int o2, int depth, char* fn, char* file) {
src = unit;
rt.put_s("{\"file\":"); str(file);
field("line"); rt.put_n(line);
field("col"); rt.put_n(col(o1));
field("end_line"); rt.put_n(end_line);
field("end_col"); rt.put_n(col(o2));
field("fn"); str(fn);
field("kind"); if (kind) str("pointer"); else str("index");
field("loop_depth"); rt.put_n(depth);
field("reason");
if (why == NOT_LOOP) str("index-not-loop-variable");
else if (why == NOT_INVARIANT) str("bound-not-invariant");
else if (why == NOT_LEN) str("index-not-len-derived");
else if (why == SIZE) str("size-unknown");
else if (why == PACKED) str("packed-elements");
else if (why == MAYFREE) str("pointer-may-be-freed");
else str("hoisted-to-loop-entry");
field("fix");
if (why == NOT_LOOP) str("index with the variable of a loop for (i = 0; i < bound; i++), or mark the code unbounded if the index is known to be in range");
else if (why == NOT_INVARIANT) str("the loop body changes the index, the bound or the array, takes an address or makes a closure; keep them fixed inside the loop");
else if (why == NOT_LEN) str("bound the loop with len() of the array, or with a constant no larger than its length");
else if (why == SIZE) str("the compiler does not know the size of the block; allocate it here with a constant size, or index a fixed array");
else if (why == PACKED) str("packed elements are checked by the runtime on every access");
else if (why == MAYFREE) str("the loop body calls something that might free or resize the block; move the call out of the loop");
else str("checked once when the loop starts, and on every access only if that check fails; nothing to do");
rt.put_c(125); rt.put_c(10);
return 0;
}
|