/
pointer.d
281 lines (260 loc) · 8.25 KB
/
pointer.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
module ast.pointer;
import ast.types, ast.base, parseBase, tools.base: This, This_fn, rmSpace, Ret, Params;
import dwarf2;
class Pointer_ : Type, Dwarf2Encodable {
IType target;
this(IType t) { target = forcedConvert(t); if (!target) asm { int 3; } }
IType proxycache;
string targettypecmp, lltypecache;
IType _proxyType() { if (auto tp = target.proxyType()) return fastalloc!(Pointer)(tp); return null; }
override {
mixin memoize!(_proxyType, proxycache, "proxyType");
int opEquals(IType ty) {
ty = resolveType(ty);
if (!super.opEquals(ty)) return false;
auto p = fastcast!(Pointer)~ ty;
return target == p.target;
}
string llvmSize() { if (nativePtrSize == 4) return "4"; if (nativePtrSize == 8) return "8"; assert(false); }
// string llvmType() { return typeToLLVM(target) ~ "*"; }
string llvmType() {
auto tt = typeToLLVM(target);
if (targettypecmp != tt) {
targettypecmp = tt;
lltypecache = qformat(tt, "*");
}
return lltypecache;
}
string mangle() { return qformat("ptrto_", target.mangle()); }
string toString() { return Format(target, "*"[]); }
bool canEncode() {
auto d2e = fastcast!(Dwarf2Encodable)(resolveType(target));
return d2e && d2e.canEncode();
}
Dwarf2Section encode(Dwarf2Controller dwarf2) {
auto targetref = registerType(dwarf2, fastcast!(Dwarf2Encodable) (resolveType(target)));
auto targetpsec = fastalloc!(Dwarf2Section)(dwarf2.cache.getKeyFor("pointer type"[]));
with (targetpsec) {
data ~= targetref;
data ~= ".int\t4\t/* pointer size */";
}
return targetpsec;
}
}
}
final class Pointer : Pointer_ {
static const isFinal = true;
this(IType t) { super(t); }
}
alias Single!(Pointer, Single!(Void)) voidp;
// &foo
class RefExpr_ : Expr {
CValue src;
int counter;
static int pointer_counter;
this(CValue cv) { if (!cv) fail; this.src = cv; this(); }
private this() {
counter = pointer_counter ++;
// if (counter == 5101) fail;
}
mixin DefaultDup!();
mixin defaultIterate!(src);
IType type_cache;
override {
IType valueType() {
if (!type_cache) type_cache = fastalloc!(Pointer)(src.valueType());
return type_cache;
}
void emitLLVM(LLVMFile lf) {
src.emitLocation(lf);
}
string toString() {
return Format("&"[], src);
}
}
}
final class RefExpr : RefExpr_ {
static const isFinal = true;
this(CValue cv) { super(cv); }
}
// *foo
class DerefExpr_ : LValue, HasInfo {
Expr src;
int count;
static int de_count;
this(Expr ex) {
this();
src = ex;
if (!fastcast!(Pointer) (resolveType(src.valueType())))
throw new Exception(Format("Can't dereference non-pointer: "[], src));
}
private this() { count = de_count ++; }
mixin DefaultDup!();
mixin defaultIterate!(src);
override {
string getInfo() { return Format("count: "[], count); }
IType valueType() { return fastcast!(Pointer) (resolveType(src.valueType())).target; }
void emitLLVM(LLVMFile lf) {
auto ptrtype = typeToLLVM(src.valueType);
// use addrspace(1) to preserve null accesses so they can crash properly
auto fixedtype = qformat(ptrtype[0..$-1], " addrspace(1)*");
auto c = save(lf, src);
c = save(lf, "bitcast ", ptrtype, " ", c, " to ", fixedtype);
load(lf, "load ", fixedtype, " ", c);
// load(lf, "load ", typeToLLVM(src.valueType), " ", save(lf, src));
}
void emitLocation(LLVMFile lf) {
src.emitLLVM(lf);
}
}
string toString() { return Format("*"[], src); }
}
final class DerefExpr : DerefExpr_ {
static const isFinal = true;
this(Expr ex) { super(ex); }
}
bool isVoidP(IType it) {
if (!it) return false;
auto p = fastcast!(Pointer)~ it;
if (!p) return false;
return !!fastcast!(Void) (resolveType(p.target));
}
static this() {
typeModlist ~= delegate IType(ref string text, IType cur, ParseCb, ParseCb) {
if (text.accept("*"[])) { return fastalloc!(Pointer)(cur); }
else return null;
};
foldopt ~= delegate Itr(Itr it) {
if (auto re = fastcast!(RefExpr) (it)) {
if (auto de = fastcast!(DerefExpr) (re.src)) {
return fastcast!(Itr) (de.src);
}
}
return null;
};
// LOL, good luck working out when this is useful (and yes it is)
foldopt ~= delegate Itr(Itr it) {
if (auto de = fastcast!(DerefExpr) (it)) {
if (auto re = fastcast!(RefExpr) (de.src)) {
return fastcast!(Itr) (re.src);
}
}
return null;
};
// Pointers must NOT autocast to void* unless expected!
implicits ~= delegate void(Expr ex, IType target, void delegate(Expr, int) consider) {
if (!target) return;
if (auto p = fastcast!(Pointer) (resolveType(ex.valueType()))) {
if (!isVoidP(p) && isVoidP(target)) {
/* This is something of a fallback.
As such, give it a lower score. */
consider(dcm(reinterpret_cast(voidp, ex)), 1);
}
}
return;
};
implicits ~= delegate Expr(Expr ex, IType expect) {
if (isVoidP(ex.valueType()) && fastcast!(Pointer) (resolveType(expect))) {
return reinterpret_cast(expect, ex);
}
return null;
};
}
import ast.fold, ast.casting;
Object gotRefExpr(ref string text, ParseCb cont, ParseCb rest) {
auto t2 = text;
Expr ex;
if (!rest(t2, "tree.expr _tree.expr.arith"[], &ex)) {
text.setError("Address operator found but nothing to take address matched"[]);
return null;
}
if (!gotImplicitCast(ex, (Expr ex) {
auto f = forcedConvert(ex);
opt(f);
unrollSAE(f);
return test(fastcast!(CValue)~ f);
})) {
text.setError("Can't take reference: expression does not seem to have an address"[]);
return null;
}
text = t2;
auto thing = forcedConvert(ex);
opt(thing);
Statement st;
if (auto _st = unrollSAE(thing)) st = _st;
auto cv = fastcast!(CValue) (thing);
assert(!!cv);
Expr res = fastalloc!(RefExpr)(cv);
if (st) res = mkStatementAndExpr(st, res);
return fastcast!(Object) (res);
}
mixin DefaultParser!(gotRefExpr, "tree.expr.ref"[], "21"[], "&"[]);
Object gotDerefExpr(ref string text, ParseCb cont, ParseCb rest) {
auto t2 = text;
Expr ex;
if (!rest(t2, "tree.expr _tree.expr.arith"[], &ex))
t2.failparse("Dereference operator found but no expression matched"[]);
if (!gotImplicitCast(ex, (IType it) { return !!fastcast!(Pointer) (it); })) {
return null;
}
text = t2;
return fastalloc!(DerefExpr)(ex);
}
mixin DefaultParser!(gotDerefExpr, "tree.expr.deref"[], "22"[], "*"[]);
/*
// emit declaration
if (!tree && extern_c && name) {
auto ret = typeToLLVM(type.ret);
string pars;
foreach (arg; type.params) {
if (pars) pars ~= ", ";
pars ~= typeToLLVM(arg.type);
}
putSection(lf, "module", "declare ", ret, " @", fmn, "(", pars, ")");
return;
}
*/
class Symbol : Expr {
string _name;
string getName() { return _name; }
IType type;
bool defineme;
this(string name, IType type) {
this._name = name;
this.type = type; if (!this.type) fail;
}
Symbol dup() { return new Symbol(getName(), type); }
mixin defaultIterate!();
IType typecache;
override IType valueType() { if (!typecache) typecache = fastalloc!(Pointer)(type); return typecache; }
override void emitLLVM(LLVMFile lf) {
auto ts = typeToLLVM(type);
if (ts == "void") { ts = "i8"; }
if (once(lf, "symbol ", getName())) {
lf.decls[getName()] = qformat("@", getName(), " = external global ", ts);
}
push(lf, "@", getName());
}
}
// fill string at emit-time via dg
class LateSymbol : Expr {
void delegate(LLVMFile) dg;
string* name;
IType type;
Expr referent; // expr that we reference, so that iteration can see it
this(Expr referent, IType type, void delegate(LLVMFile) dg, string* name) { this.referent = referent; this.type = type; this.dg = dg; this.name = name; }
private this() { }
LateSymbol dup() { return fastalloc!(LateSymbol)(referent, type, dg, name); }
mixin defaultIterate!(referent);
override IType valueType() { return type; }
override string toString() { return qformat("(", type, ") ", *name); }
override void emitLLVM(LLVMFile lf) {
// if (!*name) dg(lf);
dg(lf);
if (!*name) {
logln("wat");
fail;
}
push(lf, "@", *name);
}
}