Skip to content
← Back

src/ir/innate_operation_generator.ghul

1
namespace IR is
2
use System.Exception;
3
4
use Values.Call;
5
use Values.Value;
6
7
use Values.BLOCK;
8
9
class INNATE_OPERATION_GENERATOR(
10
_logger: Logging.Logger,
11
_boxer: VALUE_BOXER,
12
_brancher: IR.BRANCHER
13
) is
14
_type_and_operation_handlers: Collections.MAP[string,(INNATE,BLOCK) -> void];
15
_operation_handlers: Collections.MAP[string,(INNATE,BLOCK) -> void];
16
_type_handlers: Collections.MAP[string,(INNATE,BLOCK) -> void];
17
18
init(..) is
19
_type_and_operation_handlers = Collections.MAP[string,(INNATE,BLOCK) -> void]();
20
_operation_handlers = Collections.MAP[string,(INNATE,BLOCK) -> void]();
21
_type_handlers = Collections.MAP[string,(INNATE,BLOCK) -> void]();
22
23
_type_and_operation_handlers["compare.order"] = (value: INNATE, context: BLOCK) -> void is gen_compare_order(value, false, context); si;
24
_type_and_operation_handlers["compare.uorder"] = (value: INNATE, context: BLOCK) -> void is gen_compare_order(value, true, context); si;
25
_type_and_operation_handlers["compare.value"] = (value: INNATE, context: BLOCK) -> void is gen_compare_value(value, context); si;
26
_type_and_operation_handlers["compare.reference"] = (value: INNATE, context: BLOCK) -> void is gen_compare_reference(value, context); si;
27
28
_type_and_operation_handlers["bool.not"] = (value: INNATE, context: BLOCK) -> void is gen_bool_not(value, context); si;
29
_type_and_operation_handlers["reference.read"] = (value: INNATE, context: BLOCK) -> void is gen_reference_read(value, context); si;
30
_type_and_operation_handlers["reference.assign"] = (value: INNATE, context: BLOCK) -> void is gen_reference_assign(value, context); si;
31
32
_type_handlers["bool"] = (value: INNATE, context: BLOCK) -> void is gen_short_circuit_bool(value, context); si;
33
_type_handlers["arithmetic"] = (value: INNATE, context: BLOCK) -> void is gen_arithmetic(value, context); si;
34
_type_handlers["arithmetic_decimal"] = (value: INNATE, context: BLOCK) -> void is gen_arithmetic_decimal(value, context); si;
35
_type_handlers["compare_decimal"] = (value: INNATE, context: BLOCK) -> void is gen_compare_decimal(value, context); si;
36
_type_handlers["string"] = (value: INNATE, context: BLOCK) -> void is gen_string(value, context); si;
37
_type_handlers["range"] = (value: INNATE, context: BLOCK) -> void is gen_range(value, context); si;
38
39
// _type_handlers["object"] = (value: INNATE, context: CONTEXT) -> void is gen_object(value, context); si;
40
si
41
42
lower(value: INNATE, block: BLOCK) is
43
if !IoC.CONTAINER.instance.build_flags.want_assembler then
44
return;
45
fi
46
47
let innate_name = value.innate_name;
48
49
if try_handle(innate_name, _type_and_operation_handlers, value, block) then
50
return;
51
fi
52
53
let operation_name = value.op_name;
54
55
if try_handle(operation_name, _operation_handlers, value, block) then
56
return;
57
fi
58
59
let type_name = value.type_name;
60
61
if try_handle(type_name, _type_handlers, value, block) then
62
return;
63
fi
64
65
throw System.Exception("unknown innate operation: {value.function.innate_name}");
66
si
67
68
try_handle(
69
key: string,
70
handlers: Collections.Map[string,(INNATE,BLOCK) -> void],
71
value: INNATE,
72
block: BLOCK) -> bool is
73
74
if handlers.contains_key(key) then
75
let handler = handlers[key];
76
77
handler(value, block);
78
return true;
79
fi
80
return false;
81
si
82
83
gen_arithmetic(value: INNATE, block: BLOCK) is
84
gen_arguments(value, block);
85
86
let operation = value.op_name;
87
88
// FIXME: do we need to convert the inputs or outputs?
89
block.add(operation);
90
si
91
92
gen_bool_not(value: INNATE, block: BLOCK) is
93
assert value.arguments.count == 1 else "not bool missing arguments";
94
95
gen_arguments(value, block);
96
97
block.add("ldc.i4 0");
98
block.add("ceq");
99
si
100
101
gen_short_circuit_bool(value: INNATE, block: BLOCK) is
102
assert value.arguments.count == 2 else "short circuit bool missing arguments";
103
104
let brancher = _brancher.get_for(block);
105
106
let exit = IR.LABEL();
107
let operation = value.op_name;
108
109
// push speculative result:
110
if operation =~ "and_then" then
111
block.add("ldc.i4 0");
112
else
113
block.add("ldc.i4 1");
114
fi
115
116
// branch to exit if speculative result is correct based on evaluating left argument:
117
if operation =~ "and_then" then
118
brancher.branch(IR.BRANCH.Z, value.arguments[0], exit);
119
else
120
brancher.branch(IR.BRANCH.NZ, value.arguments[0], exit);
121
fi
122
123
// speculative result may not be correct, discard it:
124
block.add("pop");
125
126
// result is value of right side:
127
gen_argument(value, 1, block);
128
129
brancher.label(exit);
130
si
131
132
gen_compare_order(value: INNATE, is_unsigned: bool, block: BLOCK) is
133
assert value.arguments.count == 2 else "compare order missing arguments";
134
135
gen_arguments(value, block);
136
137
let actual_operation = value.actual_operation;
138
139
let needs_not mut = false;
140
let instruction: string mut;
141
142
if actual_operation =~ ">" then
143
instruction = "cgt";
144
elif actual_operation =~ ">=" then
145
instruction = "clt";
146
needs_not = true;
147
elif actual_operation =~ "<" then
148
instruction = "clt";
149
elif actual_operation =~ "<=" then
150
instruction = "cgt";
151
needs_not = true;
152
else
153
throw System.Exception("unexpected compare order operation: {actual_operation}");
154
fi
155
156
if is_unsigned then
157
instruction = "{instruction}.un";
158
fi
159
160
block.add(instruction);
161
162
if needs_not then
163
block.add("ldc.i4 0");
164
block.add("ceq");
165
fi
166
si
167
168
gen_string(value: INNATE, block: BLOCK) is
169
let innate_name = value.function.innate_name;
170
171
if innate_name =~ "string.equals" then
172
gen_arguments(value, block);
173
174
block.add("call bool string::op_Equality(string, string)");
175
176
if value.actual_operation =~ "!~" then
177
block.add("ldc.i4 0");
178
block.add("ceq");
179
fi
180
else
181
throw System.Exception("unexpected string innate operation: {innate_name}");
182
fi
183
si
184
185
gen_compare_reference(value: INNATE, block: BLOCK) is
186
assert value.arguments.count == 2 else "compare reference missing arguments";
187
188
let left mut = value.arguments[0];
189
let right mut = value.arguments[1];
190
191
if left.is_value_type != right.is_value_type then
192
left = _boxer.box_if_value(left);
193
right = _boxer.box_if_value(right);
194
fi
195
196
block.add(left);
197
block.add(right);
198
199
block.add("ceq");
200
201
if value.actual_operation =~ "!=" then
202
block.add("ldc.i4 0");
203
block.add("ceq");
204
fi
205
si
206
207
gen_compare_value(value: INNATE, block: BLOCK) is
208
assert value.arguments.count == 2 else "compare value missing arguments";
209
210
gen_arguments(value, block);
211
212
block.add("ceq");
213
214
if value.actual_operation =~ "!=" then
215
block.add("ldc.i4 0");
216
block.add("ceq");
217
fi
218
si
219
220
gen_range(value: INNATE, block: BLOCK) is
221
assert value.arguments.count == 2 else "create range incorrect arguments";
222
223
gen_arguments(value, block);
224
225
let prefix = "['ghul-runtime']";
226
227
if value.op_name =~ "inclusive" then
228
block.add("newobj instance void valuetype {prefix}'Ghul'.'INT_RANGE_INCLUSIVE'::'.ctor'(int32,int32)");
229
elif value.op_name =~ "exclusive" then
230
block.add("newobj instance void valuetype {prefix}'Ghul'.'INT_RANGE'::'.ctor'(int32,int32)");
231
else
232
throw Exception("unexpected range innate operation: {value.innate_name}");
233
fi
234
si
235
236
gen_reference_read(value: INNATE, context: BLOCK) is
237
// TODO
238
si
239
240
gen_reference_assign(value: INNATE, context: BLOCK) is
241
// TODO
242
si
243
244
gen_arithmetic_decimal(value: INNATE, block: BLOCK) is
245
gen_arguments(value, block);
246
247
let decimal_il = "valuetype ['System.Runtime']'System'.'Decimal'";
248
let op = value.op_name;
249
250
let method_name: string mut;
251
let is_unary mut = false;
252
253
if op =~ "neg" then
254
method_name = "op_UnaryNegation";
255
is_unary = true;
256
elif op =~ "add" then
257
method_name = "op_Addition";
258
elif op =~ "sub" then
259
method_name = "op_Subtraction";
260
elif op =~ "mul" then
261
method_name = "op_Multiply";
262
elif op =~ "div" then
263
method_name = "op_Division";
264
else
265
throw System.Exception("unexpected arithmetic_decimal operation: {op}");
266
fi
267
268
if is_unary then
269
block.add("call {decimal_il} {decimal_il}::{method_name}({decimal_il})");
270
else
271
block.add("call {decimal_il} {decimal_il}::{method_name}({decimal_il}, {decimal_il})");
272
fi
273
si
274
275
gen_compare_decimal(value: INNATE, block: BLOCK) is
276
gen_arguments(value, block);
277
278
let decimal_il = "valuetype ['System.Runtime']'System'.'Decimal'";
279
let op = value.op_name;
280
281
if op =~ "equality" then
282
block.add("call bool {decimal_il}::op_Equality({decimal_il}, {decimal_il})");
283
284
if value.actual_operation =~ "!=" then
285
block.add("ldc.i4 0");
286
block.add("ceq");
287
fi
288
289
return;
290
fi
291
292
if op =~ "order" then
293
let actual = value.actual_operation;
294
let method_name: string mut;
295
296
if actual =~ ">" then
297
method_name = "op_GreaterThan";
298
elif actual =~ ">=" then
299
method_name = "op_GreaterThanOrEqual";
300
elif actual =~ "<" then
301
method_name = "op_LessThan";
302
elif actual =~ "<=" then
303
method_name = "op_LessThanOrEqual";
304
else
305
throw System.Exception("unexpected compare_decimal.order operation: {actual}");
306
fi
307
308
block.add("call bool {decimal_il}::{method_name}({decimal_il}, {decimal_il})");
309
310
return;
311
fi
312
313
throw System.Exception("unexpected compare_decimal operation: {op}");
314
si
315
316
gen_argument(value: INNATE, index: int, block: BLOCK) is
317
block.add(value.arguments[index]);
318
si
319
320
gen_arguments(value: INNATE, block: BLOCK) is
321
for a in value.arguments do
322
block.add(a);
323
od
324
si
325
si
326
si