LlvmGenerator.py 32.2 KB
Newer Older
Maxime Perrotin's avatar
Maxime Perrotin committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
    OpenGEODE - A tiny SDL Editor for TASTE

    This module generates LLVM IR code from SDL process models, allowing
    generation of a binary application without an intermediate language.
    LLVM also allows for various code verification, analysis, and optimization.

    The design is based on the Ada code generator. Check it for details.

    Copyright (c) 2012-2013 European Space Agency

    Designed and implemented by Maxime Perrotin

    Contact: maxime.perrotin@esa.int
"""

import logging
21

Maxime Perrotin's avatar
Maxime Perrotin committed
22
from singledispatch import singledispatch
23
from llvm import core
Maxime Perrotin's avatar
Maxime Perrotin committed
24
25

import ogAST
Maxime Perrotin's avatar
Maxime Perrotin committed
26
import Helper
Maxime Perrotin's avatar
Maxime Perrotin committed
27
28
29

LOG = logging.getLogger(__name__)

Maxime Perrotin's avatar
Maxime Perrotin committed
30
31
__all__ = ['generate']

Maxime Perrotin's avatar
Maxime Perrotin committed
32

33
34
35
36
37
38
# Global state
g = None


class GlobalState():
    def __init__(self, process):
dbarbera's avatar
dbarbera committed
39
40
        self.name = str(process.processName)
        self.module = core.Module.new(self.name)
41
42
        self.dataview = process.dataview

43
44
        self.scope = Scope()
        self.global_scope = self.scope
45
        self.states = {}
dbarbera's avatar
dbarbera committed
46
        self.structs = {}
47
        self.strings = {}
dbarbera's avatar
dbarbera committed
48
        self.funcs = {}
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

        # Initialize built-in types
        self.i1 = core.Type.int(1)
        self.i8 = core.Type.int(8)
        self.i32 = core.Type.int(32)
        self.i64 = core.Type.int(64)
        self.void = core.Type.void()
        self.double = core.Type.double()
        self.i1_ptr = core.Type.pointer(self.i1)
        self.i8_ptr = core.Type.pointer(self.i8)
        self.i32_ptr = core.Type.pointer(self.i32)
        self.i64_ptr = core.Type.pointer(self.i64)
        self.double_ptr = core.Type.pointer(self.double)

        # Intialize built-in functions
        ty = core.Type.function(self.void, [core.Type.pointer(self.i8)], True)
dbarbera's avatar
dbarbera committed
65
        self.funcs['printf'] = self.module.add_function(ty, 'printf')
66

dbarbera's avatar
dbarbera committed
67
        self.funcs['memcpy'] = core.Function.intrinsic(
68
69
            self.module,
            core.INTR_MEMCPY,
70
71
            [self.i8_ptr, self.i8_ptr, self.i64]
        )
Maxime Perrotin's avatar
Maxime Perrotin committed
72

73
74
75
76
77
78
        self.funcs['powi'] = core.Function.intrinsic(
            self.module,
            core.INTR_POWI,
            [self.double]
        )

dbarbera's avatar
dbarbera committed
79
80
81
82
83
84
        self.funcs['fabs'] = core.Function.intrinsic(
            self.module,
            core.INTR_FABS,
            [self.double]
        )

dbarbera's avatar
dbarbera committed
85

86
87
class StructType():
    def __init__(self, name, field_names, field_types):
dbarbera's avatar
dbarbera committed
88
        self.name = name
89
90
91
92
93
        self.field_names = field_names
        self.ty = core.Type.struct(field_types, self.name)

    def idx(self, field_name):
        return self.field_names.index(field_name)
dbarbera's avatar
dbarbera committed
94
95


96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
class Scope:
    def __init__(self, parent=None):
        self.vars = {}
        self.parent = parent

    def define(self, name, var):
        self.vars[name.lower()] = var

    def resolve(self, name):
        var = self.vars.get(name.lower())
        if var:
            return var
        if self.parent:
            return self.parent.resolve(name)
        else:
dbarbera's avatar
dbarbera committed
111
            print name
112
113
            raise NameError

dbarbera's avatar
dbarbera committed
114

Maxime Perrotin's avatar
Maxime Perrotin committed
115
116
117
118
@singledispatch
def generate(ast):
    ''' Generate the code for an item of the AST '''
    raise TypeError('[Backend] Unsupported AST construct')
Maxime Perrotin's avatar
Maxime Perrotin committed
119

dbarbera's avatar
dbarbera committed
120

Maxime Perrotin's avatar
Maxime Perrotin committed
121
122
123
# Processing of the AST
@generate.register(ogAST.Process)
def _process(process):
dbarbera's avatar
dbarbera committed
124
    ''' Generate LLVM IR code '''
dbarbera's avatar
dbarbera committed
125
126
    process_name = str(process.processName)
    LOG.info('Generating LLVM IR code for process ' + process_name)
127

128
129
    global g
    g = GlobalState(process)
130

dbarbera's avatar
dbarbera committed
131
132
133
134
135
136
    # In case model has nested states, flatten everything
    Helper.flatten(process)

    # Make an maping {input: {state: transition...}} in order to easily
    # generate the lookup tables for the state machine runtime
    mapping = Helper.map_input_state(process)
Maxime Perrotin's avatar
Maxime Perrotin committed
137

138
139
140
    # Initialize states enum
    for name in process.mapping.iterkeys():
        if not name.endswith('START'):
141
142
            cons = core.Constant.int(g.i32, len(g.states))
            g.states[name] = cons
143

144
    # Generate state var
145
146
    state_cons = g.module.add_global_variable(g.i32, 'state')
    state_cons.initializer = core.Constant.int(g.i32, -1)
147
    g.scope.define('state', state_cons)
148

149
150
151
    # Generare process-level vars
    for name, (ty, expr) in process.variables.viewitems():
        var_ty = _generate_type(ty)
152
        global_var = g.module.add_global_variable(var_ty, str(name))
153
        global_var.initializer = core.Constant.null(var_ty)
154
        g.scope.define(str(name).lower(), global_var)
155

dbarbera's avatar
dbarbera committed
156
157
158
    # Declare timer set/reset functions
    for timer in process.timers:
        # TODO: Should be uint?
159
160
        decl_func("set_%s" % str(timer), g.void, [g.i32_ptr], True)
        decl_func("reset_%s" % str(timer), g.void, [], True)
dbarbera's avatar
dbarbera committed
161

162
    # Declare output signal functions
dbarbera's avatar
dbarbera committed
163
    for signal in process.output_signals:
164
165
166
167
        if 'type' in signal:
            param_tys = [core.Type.pointer(_generate_type(signal['type']))]
        else:
            param_tys = []
168
        decl_func(str(signal['name']), g.void, param_tys, True)
dbarbera's avatar
dbarbera committed
169

170
    # Declare external procedures functions
dbarbera's avatar
dbarbera committed
171
172
    for proc in [proc for proc in process.procedures if proc.external]:
        param_tys = [core.Type.pointer(_generate_type(p['type'])) for p in proc.fpar]
173
        decl_func(str(proc.inputString), g.void, param_tys, True)
dbarbera's avatar
dbarbera committed
174

175
176
    # Generate internal procedures
    for proc in process.content.inner_procedures:
177
        generate(proc)
178

179
    # Generate process functions
180
    _generate_runtr_func(process)
181
    _generate_startup_func(process)
182

183
184
185
186
    # Generate input signals
    for signal in process.input_signals:
        _generate_input_signal(signal, mapping[signal['name']])

dbarbera's avatar
dbarbera committed
187
188
    g.module.verify()

dbarbera's avatar
dbarbera committed
189
    with open(g.name + '.ll', 'w') as ll_file:
dbarbera's avatar
dbarbera committed
190
        ll_file.write(str(g.module))
191
192
193


def _generate_runtr_func(process):
dbarbera's avatar
dbarbera committed
194
    ''' Generate code for the run_transition function '''
195
    func = decl_func('run_transition', g.void, [g.i32])
196

197
198
    _push_scope()

199
200
201
202
203
    entry_block = func.append_basic_block('entry')
    cond_block = func.append_basic_block('cond')
    body_block = func.append_basic_block('body')
    exit_block = func.append_basic_block('exit')

dbarbera's avatar
dbarbera committed
204
    g.builder = core.Builder.new(entry_block)
205
206

    # entry
dbarbera's avatar
dbarbera committed
207
    id_ptr = g.builder.alloca(g.i32, None, 'id')
208
    g.scope.define('id', id_ptr)
dbarbera's avatar
dbarbera committed
209
210
    g.builder.store(func.args[0], id_ptr)
    g.builder.branch(cond_block)
211
212

    # cond
dbarbera's avatar
dbarbera committed
213
    g.builder.position_at_end(cond_block)
214
    no_tr_cons = core.Constant.int(g.i32, -1)
215
216
    id_val = g.builder.load(id_ptr)
    cond_val = g.builder.icmp(core.ICMP_NE, id_val, no_tr_cons, 'cond')
dbarbera's avatar
dbarbera committed
217
    g.builder.cbranch(cond_val, body_block, exit_block)
218
219

    # body
dbarbera's avatar
dbarbera committed
220
221
    g.builder.position_at_end(body_block)
    switch = g.builder.switch(func.args[0], exit_block)
222
223
224
225

    # transitions
    for idx, tr in enumerate(process.transitions):
        tr_block = func.append_basic_block('tr%d' % idx)
226
        const = core.Constant.int(g.i32, idx)
227
        switch.add_case(const, tr_block)
dbarbera's avatar
dbarbera committed
228
        g.builder.position_at_end(tr_block)
229
        generate(tr)
dbarbera's avatar
dbarbera committed
230
        g.builder.branch(cond_block)
231
232

    # exit
dbarbera's avatar
dbarbera committed
233
234
    g.builder.position_at_end(exit_block)
    g.builder.ret_void()
235

236
237
    _pop_scope()

238
239
240
241
    func.verify()
    return func


242
def _generate_startup_func(process):
dbarbera's avatar
dbarbera committed
243
    ''' Generate code for the startup function '''
244
    func = decl_func(g.name + '_startup', g.void, [])
245

246
247
    _push_scope()

248
    entry_block = func.append_basic_block('entry')
249
    g.builder = core.Builder.new(entry_block)
250

251
252
253
    # Initialize process level variables
    for name, (ty, expr) in process.variables.viewitems():
        if expr:
dbarbera's avatar
dbarbera committed
254
            global_var = g.scope.resolve(str(name))
dbarbera's avatar
dbarbera committed
255
            generate_assign(global_var, expression(expr))
256

257
258
    g.builder.call(g.funcs['run_transition'], [core.Constant.int(g.i32, 0)])
    g.builder.ret_void()
Maxime Perrotin's avatar
Maxime Perrotin committed
259

260
261
    _pop_scope()

262
263
    func.verify()
    return func
Maxime Perrotin's avatar
Maxime Perrotin committed
264
265


266
def _generate_input_signal(signal, inputs):
dbarbera's avatar
dbarbera committed
267
    ''' Generate code for an input signal '''
dbarbera's avatar
dbarbera committed
268
    func_name = g.name + "_" + str(signal['name'])
269
270
271
    param_tys = []
    if 'type' in signal:
        param_tys.append(core.Type.pointer(_generate_type(signal['type'])))
272
273

    func = decl_func(func_name, g.void, param_tys)
274

275
276
    _push_scope()

277
278
    entry_block = func.append_basic_block('entry')
    exit_block = func.append_basic_block('exit')
279
    g.builder = core.Builder.new(entry_block)
280

281
    g_state_val = g.builder.load(g.global_scope.resolve('state'))
282
    switch = g.builder.switch(g_state_val, exit_block)
283

284
    for state_name, state_id in g.states.iteritems():
285
286
        state_block = func.append_basic_block('state_%s' % str(state_name))
        switch.add_case(state_id, state_block)
287
        g.builder.position_at_end(state_block)
288
289
290

        # TODO: Nested states

291
292
293
        input = inputs.get(state_name)
        if input:
            for var_name in input.parameters:
dbarbera's avatar
dbarbera committed
294
295
                var_ptr = g.scope.resolve(str(var_name))
                generate_assign(var_ptr, func.args[0])
296
            if input.transition:
297
                id_val = core.Constant.int(g.i32, input.transition_id)
298
                g.builder.call(g.funcs['run_transition'], [id_val])
299

300
        g.builder.ret_void()
301

302
303
    g.builder.position_at_end(exit_block)
    g.builder.ret_void()
304

305
306
    _pop_scope()

307
308
309
    func.verify()


Maxime Perrotin's avatar
Maxime Perrotin committed
310
311
312
313
@generate.register(ogAST.Output)
@generate.register(ogAST.ProcedureCall)
def _call_external_function(output):
    ''' Generate the code of a set of output or procedure call statement '''
dbarbera's avatar
dbarbera committed
314
315
316
    for out in output.output:
        name = out['outputName'].lower()

317
        if name == 'write':
dbarbera's avatar
dbarbera committed
318
319
            _generate_write(out['params'])
            continue
320
321
322
        elif name == 'writeln':
            _generate_writeln(out['params'])
            continue
dbarbera's avatar
dbarbera committed
323
324
325
326
327
328
329
        elif name == 'reset_timer':
            _generate_reset_timer(out['params'])
            continue
        elif name == 'set_timer':
            _generate_set_timer(out['params'])
            continue

dbarbera's avatar
dbarbera committed
330
        func = g.funcs[str(name).lower()]
331
332
333
334
335
336
337
338
339
340
341
342
343

        params = []
        for p in out.get('params', []):
            p_val = expression(p)
            # Pass by reference
            if p_val.type.kind != core.TYPE_POINTER:
                p_var = g.builder.alloca(p_val.type, None)
                g.builder.store(p_val, p_var)
                params.append(p_var)
            else:
                params.append(p_val)

        g.builder.call(func, params)
dbarbera's avatar
dbarbera committed
344
345
346
347


def _generate_write(params):
    ''' Generate the code for the write operator '''
348
    zero = core.Constant.int(g.i32, 0)
349
350
351
    for param in params:
        basic_ty = find_basic_type(param.exprType)
        expr_val = expression(param)
352

353
        if basic_ty.kind == 'IntegerType':
354
            fmt_val = _get_string_cons('% d')
355
            fmt_ptr = g.builder.gep(fmt_val, [zero, zero])
dbarbera's avatar
dbarbera committed
356
            g.builder.call(g.funcs['printf'], [fmt_ptr, expr_val])
357
        elif basic_ty.kind == 'RealType':
358
            fmt_val = _get_string_cons('% .14E')
359
            fmt_ptr = g.builder.gep(fmt_val, [zero, zero])
dbarbera's avatar
dbarbera committed
360
            g.builder.call(g.funcs['printf'], [fmt_ptr, expr_val])
361
        elif basic_ty.kind == 'BooleanType':
362
            true_str_val = _get_string_cons('TRUE')
363
            true_str_ptr = g.builder.gep(true_str_val, [zero, zero])
364
            false_str_val = _get_string_cons('FALSE')
365
366
            false_str_ptr = g.builder.gep(false_str_val, [zero, zero])
            str_ptr = g.builder.select(expr_val, true_str_ptr, false_str_ptr)
dbarbera's avatar
dbarbera committed
367
            g.builder.call(g.funcs['printf'], [str_ptr])
dbarbera's avatar
dbarbera committed
368
369
        elif basic_ty.kind == 'StringType':
            expr_ptr = g.builder.gep(expr_val, [zero, zero])
dbarbera's avatar
dbarbera committed
370
            g.builder.call(g.funcs['printf'], [expr_ptr])
371
372
373
374
375
376
377
        else:
            raise NotImplementedError


def _generate_writeln(params):
    ''' Generate the code for the writeln operator '''
    _generate_write(params)
378
379

    zero = core.Constant.int(g.i32, 0)
380
    str_cons = _get_string_cons('\n')
381
    str_ptr = g.builder.gep(str_cons, [zero, zero])
dbarbera's avatar
dbarbera committed
382
    g.builder.call(g.funcs['printf'], [str_ptr])
dbarbera's avatar
dbarbera committed
383
384
385
386


def _generate_reset_timer(params):
    ''' Generate the code for the reset timer operator '''
dbarbera's avatar
dbarbera committed
387
    timer_id = params[0]
388
    reset_func_name = 'reset_%s' % timer_id.value[0]
dbarbera's avatar
dbarbera committed
389
390
391
    reset_func = g.funcs[reset_func_name.lower()]

    g.builder.call(reset_func, [])
dbarbera's avatar
dbarbera committed
392
393
394
395


def _generate_set_timer(params):
    ''' Generate the code for the set timer operator '''
dbarbera's avatar
dbarbera committed
396
    timer_expr, timer_id = params
397
    set_func_name = 'set_%s' % timer_id.value[0]
dbarbera's avatar
dbarbera committed
398
399
400
401
402
403
404
405
    set_func = g.funcs[set_func_name.lower()]

    expr_val = expression(timer_expr)

    tmp_ptr = g.builder.alloca(expr_val.type)
    g.builder.store(expr_val, tmp_ptr)

    g.builder.call(set_func, [tmp_ptr])
Maxime Perrotin's avatar
Maxime Perrotin committed
406
407
408
409


@generate.register(ogAST.TaskAssign)
def _task_assign(task):
dbarbera's avatar
dbarbera committed
410
    ''' Generate the code of a list of assignments '''
411
412
    for expr in task.elems:
        expression(expr)
Maxime Perrotin's avatar
Maxime Perrotin committed
413
414
415
416
417


@generate.register(ogAST.TaskInformalText)
def _task_informal_text(task):
    ''' Generate comments for informal text '''
418
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
419
420
421
422


@generate.register(ogAST.TaskForLoop)
def _task_forloop(task):
dbarbera's avatar
dbarbera committed
423
    ''' Generate the code for a for loop '''
dbarbera's avatar
dbarbera committed
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
    for loop in task.elems:
        if loop['range']:
            _generate_for_range(loop)
        else:
            _generate_for_iterable(loop)


def _generate_for_range(loop):
    ''' Generate the code for a for x in range loop '''
    func = g.builder.basic_block.function
    cond_block = func.append_basic_block('for:cond')
    body_block = func.append_basic_block('for:body')
    inc_block = func.append_basic_block('for:inc')
    end_block = func.append_basic_block('')

    _push_scope()

    loop_var = g.builder.alloca(g.i32, None, str(loop['var']))
    g.scope.define(str(loop['var']), loop_var)

    if loop['range']['start']:
        start_val = expression(loop['range']['start'])
        g.builder.store(start_val, loop_var)
    else:
        g.builder.store(core.Constant.int(g.i32, 0), loop_var)

    stop_val = expression(loop['range']['stop'])
    g.builder.branch(cond_block)

    g.builder.position_at_end(cond_block)
    loop_val = g.builder.load(loop_var)
    cond_val = g.builder.icmp(core.ICMP_SLT, loop_val, stop_val)
    g.builder.cbranch(cond_val, body_block, end_block)

    g.builder.position_at_end(body_block)
    generate(loop['transition'])
    g.builder.branch(inc_block)

    g.builder.position_at_end(inc_block)
    step_val = core.Constant.int(g.i32, loop['range']['step'])
    loop_val = g.builder.load(loop_var)
    temp_val = g.builder.add(loop_val, step_val)
    g.builder.store(temp_val, loop_var)
    g.builder.branch(cond_block)

    g.builder.position_at_end(end_block)

    _pop_scope()


def _generate_for_iterable(loop):
    ''' Generate the code for a for x in iterable loop'''
476
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
477

dbarbera's avatar
dbarbera committed
478

dbarbera's avatar
dbarbera committed
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
@singledispatch
def reference(prim):
    ''' Generate a variable reference '''
    raise TypeError('Unsupported reference: ' + str(expr))


@reference.register(ogAST.PrimVariable)
def _prim_var_reference(prim):
    ''' Generate a primary variable reference '''
    return g.scope.resolve(str(prim.value[0]))


@reference.register(ogAST.PrimPath)
def _prim_path_reference(prim):
    ''' Generate a primary path reference '''
    var_name = prim.value.pop(0).lower()
    var_ptr = g.scope.resolve(str(var_name))

    if not prim.value:
        return var_ptr

    zero_cons = core.Constant.int(g.i32, 0)

    for field_name in prim.value:
        var_ty = var_ptr.type
        struct = g.structs[var_ty.pointee.name]
        field_idx_cons = core.Constant.int(g.i32, struct.idx(field_name.lower()))
        field_ptr = g.builder.gep(var_ptr, [zero_cons, field_idx_cons])
        var_ptr = field_ptr

    return var_ptr

Maxime Perrotin's avatar
Maxime Perrotin committed
511
512
513

@singledispatch
def expression(expr):
dbarbera's avatar
dbarbera committed
514
    ''' Generate the code for Expression-classes '''
Maxime Perrotin's avatar
Maxime Perrotin committed
515
516
517
518
    raise TypeError('Unsupported expression: ' + str(expr))


@expression.register(ogAST.PrimVariable)
Maxime Perrotin's avatar
Maxime Perrotin committed
519
def _primary_variable(prim):
dbarbera's avatar
dbarbera committed
520
521
522
    ''' Generate the code for a variable expression '''
    var_ptr = reference(prim)
    return var_ptr if is_struct_ptr(var_ptr) else g.builder.load(var_ptr)
Maxime Perrotin's avatar
Maxime Perrotin committed
523
524


Maxime Perrotin's avatar
Maxime Perrotin committed
525
@expression.register(ogAST.PrimPath)
dbarbera's avatar
dbarbera committed
526
def _prim_path(prim):
dbarbera's avatar
dbarbera committed
527
    ''' Generate the code for an of path expression '''
528
529
530
531
532
533
534
535
536
537
538
539
540
    specops_generators = {
        'length': generate_length,
        'present': generate_present,
        'abs': generate_abs,
        'fix': generate_fix,
        'float': generate_float,
        'power': generate_power
    }

    specop_generator = specops_generators.get(prim.value[0].lower())
    if specop_generator:
        return specop_generator(prim.value[1]['procParams'])

dbarbera's avatar
dbarbera committed
541
542
    var_ptr = reference(prim)
    return var_ptr if is_struct_ptr(var_ptr) else g.builder.load(var_ptr)
Maxime Perrotin's avatar
Maxime Perrotin committed
543
544


545
def generate_length(params):
dbarbera's avatar
dbarbera committed
546
    ''' Generate the code for the built-in length operation'''
547
548
549
550
    raise NotImplementedError


def generate_present(params):
dbarbera's avatar
dbarbera committed
551
    ''' Generate the code for the built-in present operation'''
552
553
554
555
    raise NotImplementedError


def generate_abs(params):
dbarbera's avatar
dbarbera committed
556
    ''' Generate the code for the built-in abs operation'''
dbarbera's avatar
dbarbera committed
557
558
559
560
561
562
563
564
    left_val = expression(params[0])

    if left_val.type.kind == core.TYPE_INTEGER:
        left_conv = g.builder.sitofp(left_val, g.double)
        res_val = g.builder.call(g.funcs['fabs'], [left_conv])
        return g.builder.fptosi(res_val, g.i32)
    else:
        return g.builder.call(g.funcs['fabs'], [left_val])
565
566
567


def generate_fix(params):
dbarbera's avatar
dbarbera committed
568
    ''' Generate the code for the built-in fix operation'''
569
570
571
572
    raise NotImplementedError


def generate_float(params):
dbarbera's avatar
dbarbera committed
573
    ''' Generate the code for the built-in float operation'''
dbarbera's avatar
dbarbera committed
574
575
    expr_val = expression(params[0])
    return g.builder.sitofp(expr_val, g.double)
576
577
578


def generate_power(params):
dbarbera's avatar
dbarbera committed
579
    ''' Generate the code for the built-in power operation'''
580
581
582
583
584
585
586
587
588
589
590
    left_val = expression(params[0])
    right_val = expression(params[1])

    if left_val.type.kind == core.TYPE_INTEGER:
        left_conv = g.builder.sitofp(left_val, g.double)
        res_val = g.builder.call(g.funcs['powi'], [left_conv, right_val])
        return g.builder.fptosi(res_val, g.i32)
    else:
        return g.builder.call(g.funcs['powi'], [left_val, right_val])


Maxime Perrotin's avatar
Maxime Perrotin committed
591
592
593
594
595
596
597
598
599
600
601
602
@expression.register(ogAST.ExprPlus)
@expression.register(ogAST.ExprMul)
@expression.register(ogAST.ExprMinus)
@expression.register(ogAST.ExprEq)
@expression.register(ogAST.ExprNeq)
@expression.register(ogAST.ExprGt)
@expression.register(ogAST.ExprGe)
@expression.register(ogAST.ExprLt)
@expression.register(ogAST.ExprLe)
@expression.register(ogAST.ExprDiv)
@expression.register(ogAST.ExprMod)
@expression.register(ogAST.ExprRem)
dbarbera's avatar
dbarbera committed
603
604
def _basic(expr):
    ''' Generate the code for an arithmetic of relational expression '''
605
606
    lefttmp = expression(expr.left)
    righttmp = expression(expr.right)
607

608
609
    if lefttmp.type.kind == core.TYPE_INTEGER:
        if expr.operand == '+':
610
            return g.builder.add(lefttmp, righttmp, 'addtmp')
611
        elif expr.operand == '-':
612
            return g.builder.sub(lefttmp, righttmp, 'subtmp')
613
        elif expr.operand == '*':
614
            return g.builder.mul(lefttmp, righttmp, 'multmp')
615
        elif expr.operand == '/':
616
            return g.builder.sdiv(lefttmp, righttmp, 'divtmp')
617
        elif expr.operand == 'mod':
618
            # l mod r == (((l rem r) + r) rem r)
619
620
621
            remtmp = g.builder.srem(lefttmp, righttmp)
            addtmp = g.builder.add(remtmp, righttmp)
            return g.builder.srem(addtmp, righttmp, 'modtmp')
622
        elif expr.operand == 'rem':
623
            return g.builder.srem(lefttmp, righttmp, 'remtmp')
624
        elif expr.operand == '<':
625
            return g.builder.icmp(core.ICMP_SLT, lefttmp, righttmp, 'lttmp')
626
        elif expr.operand == '<=':
627
            return g.builder.icmp(core.ICMP_SLE, lefttmp, righttmp, 'letmp')
628
        elif expr.operand == '=':
629
            return g.builder.icmp(core.ICMP_EQ, lefttmp, righttmp, 'eqtmp')
630
        elif expr.operand == '/=':
631
            return g.builder.icmp(core.ICMP_NE, lefttmp, righttmp, 'netmp')
632
        elif expr.operand == '>=':
633
            return g.builder.icmp(core.ICMP_SGE, lefttmp, righttmp, 'getmp')
634
        elif expr.operand == '>':
635
            return g.builder.icmp(core.ICMP_SGT, lefttmp, righttmp, 'gttmp')
636
637
638
639
        else:
            raise NotImplementedError
    elif lefttmp.type.kind == core.TYPE_DOUBLE:
        if expr.operand == '+':
640
            return g.builder.fadd(lefttmp, righttmp, 'addtmp')
641
        elif expr.operand == '-':
642
            return g.builder.fsub(lefttmp, righttmp, 'subtmp')
643
        elif expr.operand == '*':
644
            return g.builder.fmul(lefttmp, righttmp, 'multmp')
645
        elif expr.operand == '/':
646
            return g.builder.fdiv(lefttmp, righttmp, 'divtmp')
647
        elif expr.operand == '<':
648
            return g.builder.fcmp(core.FCMP_OLT, lefttmp, righttmp, 'lttmp')
649
        elif expr.operand == '<=':
650
            return g.builder.fcmp(core.FCMP_OLE, lefttmp, righttmp, 'letmp')
651
        elif expr.operand == '=':
652
            return g.builder.fcmp(core.FCMP_OEQ, lefttmp, righttmp, 'eqtmp')
653
        elif expr.operand == '/=':
654
            return g.builder.fcmp(core.FCMP_ONE, lefttmp, righttmp, 'netmp')
655
        elif expr.operand == '>=':
656
            return g.builder.fcmp(core.FCMP_OGE, lefttmp, righttmp, 'getmp')
657
        elif expr.operand == '>':
658
            return g.builder.fcmp(core.FCMP_OGT, lefttmp, righttmp, 'gttmp')
659
660
        else:
            raise NotImplementedError
661
    else:
662
        raise NotImplementedError
663

Maxime Perrotin's avatar
Maxime Perrotin committed
664

665
666
@expression.register(ogAST.ExprAssign)
def _assign(expr):
dbarbera's avatar
dbarbera committed
667
    ''' Generate the code for an assign expression '''
dbarbera's avatar
dbarbera committed
668
    generate_assign(reference(expr.left), expression(expr.right))
669

670

dbarbera's avatar
dbarbera committed
671
def generate_assign(left, right):
672
673
674
    ''' Generate code for an assign from two LLVM values'''
    # This is extracted as an standalone function because is used by
    # multiple generation rules
dbarbera's avatar
dbarbera committed
675
    if is_struct_ptr(left):
676
677
        size = core.Constant.sizeof(left.type.pointee)
        align = core.Constant.int(g.i32, 0)
678
        volatile = core.Constant.int(g.i1, 0)
679

680
681
        right_ptr = g.builder.bitcast(right, g.i8_ptr)
        left_ptr = g.builder.bitcast(left, g.i8_ptr)
682

dbarbera's avatar
dbarbera committed
683
        g.builder.call(g.funcs['memcpy'], [left_ptr, right_ptr, size, align, volatile])
684
    else:
685
        g.builder.store(right, left)
dbarbera's avatar
dbarbera committed
686

Maxime Perrotin's avatar
Maxime Perrotin committed
687

Maxime Perrotin's avatar
Maxime Perrotin committed
688
689
690
@expression.register(ogAST.ExprOr)
@expression.register(ogAST.ExprAnd)
@expression.register(ogAST.ExprXor)
dbarbera's avatar
dbarbera committed
691
692
def _logical(expr):
    ''' Generate the code for a logical expression '''
dbarbera's avatar
dbarbera committed
693
694
695
696
697
698
699
    lefttmp = expression(expr.left)
    righttmp = expression(expr.right)

    ty = find_basic_type(expr.exprType)
    if ty.kind != 'BooleanType':
        raise NotImplementedError

dbarbera's avatar
dbarbera committed
700
701
702
    if expr.operand == 'and':
        return g.builder.and_(lefttmp, righttmp, 'andtmp')
    elif expr.operand == 'or':
703
        return g.builder.or_(lefttmp, righttmp, 'ortmp')
dbarbera's avatar
dbarbera committed
704
    else:
705
        return g.builder.xor(lefttmp, righttmp, 'xortmp')
dbarbera's avatar
dbarbera committed
706

Maxime Perrotin's avatar
Maxime Perrotin committed
707

Maxime Perrotin's avatar
Maxime Perrotin committed
708
@expression.register(ogAST.ExprAppend)
Maxime Perrotin's avatar
Maxime Perrotin committed
709
710
def _append(expr):
    ''' Generate code for the APPEND construct: a // b '''
711
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
712
713


Maxime Perrotin's avatar
Maxime Perrotin committed
714
@expression.register(ogAST.ExprIn)
Maxime Perrotin's avatar
Maxime Perrotin committed
715
def _expr_in(expr):
dbarbera's avatar
dbarbera committed
716
    ''' Generate the code for an in expression '''
717
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
718
719


Maxime Perrotin's avatar
Maxime Perrotin committed
720
@expression.register(ogAST.PrimEnumeratedValue)
Maxime Perrotin's avatar
Maxime Perrotin committed
721
722
def _enumerated_value(primary):
    ''' Generate code for an enumerated value '''
dbarbera's avatar
dbarbera committed
723
724
725
    enumerant = primary.value[0].replace('_', '-')
    basic_ty = find_basic_type(primary.exprType)
    return core.Constant.int(g.i32, basic_ty.EnumValues[enumerant].IntValue)
Maxime Perrotin's avatar
Maxime Perrotin committed
726
727


Maxime Perrotin's avatar
Maxime Perrotin committed
728
@expression.register(ogAST.PrimChoiceDeterminant)
Maxime Perrotin's avatar
Maxime Perrotin committed
729
730
def _choice_determinant(primary):
    ''' Generate code for a choice determinant (enumerated) '''
731
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
732
733


Maxime Perrotin's avatar
Maxime Perrotin committed
734
@expression.register(ogAST.PrimInteger)
735
736
def _integer(primary):
    ''' Generate code for a raw integer value  '''
737
    return core.Constant.int(g.i32, primary.value[0])
738
739


Maxime Perrotin's avatar
Maxime Perrotin committed
740
@expression.register(ogAST.PrimReal)
741
742
def _real(primary):
    ''' Generate code for a raw real value  '''
743
    return core.Constant.real(g.double, primary.value[0])
744
745


Maxime Perrotin's avatar
Maxime Perrotin committed
746
@expression.register(ogAST.PrimBoolean)
747
748
def _boolean(primary):
    ''' Generate code for a raw boolean value  '''
dbarbera's avatar
dbarbera committed
749
    if primary.value[0].lower() == 'true':
750
        return core.Constant.int(g.i1, 1)
dbarbera's avatar
dbarbera committed
751
    else:
752
        return core.Constant.int(g.i1, 0)
Maxime Perrotin's avatar
Maxime Perrotin committed
753
754


Maxime Perrotin's avatar
Maxime Perrotin committed
755
@expression.register(ogAST.PrimEmptyString)
Maxime Perrotin's avatar
Maxime Perrotin committed
756
757
def _empty_string(primary):
    ''' Generate code for an empty SEQUENCE OF: {} '''
758
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
759
760


Maxime Perrotin's avatar
Maxime Perrotin committed
761
@expression.register(ogAST.PrimStringLiteral)
Maxime Perrotin's avatar
Maxime Perrotin committed
762
763
def _string_literal(primary):
    ''' Generate code for a string (Octet String) '''
dbarbera's avatar
dbarbera committed
764
    return _get_string_cons(str(primary.value[1:-1]))
Maxime Perrotin's avatar
Maxime Perrotin committed
765
766


Maxime Perrotin's avatar
Maxime Perrotin committed
767
@expression.register(ogAST.PrimConstant)
Maxime Perrotin's avatar
Maxime Perrotin committed
768
769
def _constant(primary):
    ''' Generate code for a reference to an ASN.1 constant '''
770
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
771
772


Maxime Perrotin's avatar
Maxime Perrotin committed
773
@expression.register(ogAST.PrimMantissaBaseExp)
Maxime Perrotin's avatar
Maxime Perrotin committed
774
775
def _mantissa_base_exp(primary):
    ''' Generate code for a Real with Mantissa-base-Exponent representation '''
776
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
777
778


Maxime Perrotin's avatar
Maxime Perrotin committed
779
@expression.register(ogAST.PrimIfThenElse)
dbarbera's avatar
dbarbera committed
780
def _if_then_else(ifthen):
dbarbera's avatar
dbarbera committed
781
    ''' Generate the code for ternary operator '''
782
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
783
784


Maxime Perrotin's avatar
Maxime Perrotin committed
785
@expression.register(ogAST.PrimSequence)
Maxime Perrotin's avatar
Maxime Perrotin committed
786
def _sequence(seq):
dbarbera's avatar
dbarbera committed
787
    ''' Generate the code for an ASN.1 SEQUENCE '''
dbarbera's avatar
dbarbera committed
788
789
790
791
792
793
794
795
796
797
798
    struct = g.structs[seq.exprType.ReferencedTypeName]
    struct_ptr = g.builder.alloca(struct.ty)
    zero_cons = core.Constant.int(g.i32, 0)

    for field_name, field_expr in seq.value.viewitems():
        field_val = expression(field_expr)
        field_idx_cons = core.Constant.int(g.i32, struct.idx(field_name))
        field_ptr = g.builder.gep(struct_ptr, [zero_cons, field_idx_cons])
        g.builder.store(field_val, field_ptr)

    return struct_ptr
Maxime Perrotin's avatar
Maxime Perrotin committed
799
800


Maxime Perrotin's avatar
Maxime Perrotin committed
801
@expression.register(ogAST.PrimSequenceOf)
Maxime Perrotin's avatar
Maxime Perrotin committed
802
def _sequence_of(seqof):
dbarbera's avatar
dbarbera committed
803
    ''' Generate the code for an ASN.1 SEQUENCE OF '''
804
    ty = _generate_type(seqof.exprType)
805
806
807
    struct_ptr = g.builder.alloca(ty)
    zero_cons = core.Constant.int(g.i32, 0)
    array_ptr = g.builder.gep(struct_ptr, [zero_cons, zero_cons])
808
809

    for idx, expr in enumerate(seqof.value):
810
        idx_cons = core.Constant.int(g.i32, idx)
811
        expr_val = expression(expr)
812
813
        pos_ptr = g.builder.gep(array_ptr, [zero_cons, idx_cons])
        g.builder.store(expr_val, pos_ptr)
814
815

    return struct_ptr
Maxime Perrotin's avatar
Maxime Perrotin committed
816
817


Maxime Perrotin's avatar
Maxime Perrotin committed
818
@expression.register(ogAST.PrimChoiceItem)
Maxime Perrotin's avatar
Maxime Perrotin committed
819
def _choiceitem(choice):
dbarbera's avatar
dbarbera committed
820
    ''' Generate the code for a CHOICE expression '''
821
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
822
823
824
825


@generate.register(ogAST.Decision)
def _decision(dec):
dbarbera's avatar
dbarbera committed
826
    ''' Generate the code for a decision '''
827
    func = g.builder.basic_block.function
dbarbera's avatar
dbarbera committed
828
829
830
831

    ans_cond_blocks = [func.append_basic_block('ans_cond') for ans in dec.answers]
    end_block = func.append_basic_block('end')

832
    g.builder.branch(ans_cond_blocks[0])
dbarbera's avatar
dbarbera committed
833
834
835
836
837

    for idx, ans in enumerate(dec.answers):
        ans_cond_block = ans_cond_blocks[idx]
        if ans.transition:
            ans_tr_block = func.append_basic_block('ans_tr')
838
        g.builder.position_at_end(ans_cond_block)
dbarbera's avatar
dbarbera committed
839
840

        if ans.kind == 'constant':
dbarbera's avatar
dbarbera committed
841
            next_block = ans_cond_blocks[idx+1] if idx < len(ans_cond_blocks)-1 else end_block
dbarbera's avatar
dbarbera committed
842
843
844
845
846
847

            expr = ans.openRangeOp()
            expr.left = dec.question
            expr.right = ans.constant
            expr_val = expression(expr)

848
849
850
            true_cons = core.Constant.int(g.i1, 1)
            cond_val = g.builder.icmp(core.ICMP_EQ, expr_val, true_cons)
            g.builder.cbranch(cond_val, ans_tr_block if ans.transition else end_block, next_block)
dbarbera's avatar
dbarbera committed
851
852
        elif ans.kind == 'else':
            if ans.transition:
853
                g.builder.branch(ans_tr_block)
dbarbera's avatar
dbarbera committed
854
            else:
855
                g.builder.branch(end_block)
dbarbera's avatar
dbarbera committed
856
857
858
859
        else:
            raise NotImplementedError

        if ans.transition:
860
            g.builder.position_at_end(ans_tr_block)
dbarbera's avatar
dbarbera committed
861
            generate(ans.transition)
862
            g.builder.branch(end_block)
dbarbera's avatar
dbarbera committed
863

864
    g.builder.position_at_end(end_block)
Maxime Perrotin's avatar
Maxime Perrotin committed
865
866
867
868


@generate.register(ogAST.Label)
def _label(tr):
dbarbera's avatar
dbarbera committed
869
    ''' TGenerate the code for a Label '''
870
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
871
872
873
874


@generate.register(ogAST.Transition)
def _transition(tr):
dbarbera's avatar
dbarbera committed
875
    ''' Generate the code for a transition '''
876
877
878
879
880
881
    for action in tr.actions:
        generate(action)
        if isinstance(action, ogAST.Label):
            return
    if tr.terminator:
        _generate_terminator(tr.terminator)
882
883


884
def _generate_terminator(term):
dbarbera's avatar
dbarbera committed
885
    ''' Generate the code for a transition termiantor '''
886
    if term.label:
887
        raise NotImplementedError
888
889
890
    if term.kind == 'next_state':
        state = term.inputString.lower()
        if state.strip() != '-':
891
            next_id_cons = core.Constant.int(g.i32, term.next_id)
892
            g.builder.store(next_id_cons, g.scope.resolve('id'))
893
            if term.next_id == -1:
894
                state_ptr = g.global_scope.resolve('state')
895
896
                state_id_cons = g.states[state]
                g.builder.store(state_id_cons, state_ptr)
897
        else:
898
            raise NotImplementedError
899
    elif term.kind == 'join':
900
        raise NotImplementedError
901
    elif term.kind == 'stop':
902
        raise NotImplementedError
903
    elif term.kind == 'return':
904
905
906
907
908
909
910
911
        if term.next_id == -1 and term.return_expr:
            g.builder.ret(expression(term.return_expr))
        elif term.next_id == -1:
            g.builder.ret_void()
        else:
            next_id_cons = core.Constant.int(g.i32, term.next_id)
            g.builder.store(next_id_cons, g.scope.resolve('id'))
            g.builder.ret_void()
Maxime Perrotin's avatar
Maxime Perrotin committed
912
913
914
915


@generate.register(ogAST.Floating_label)
def _floating_label(label):
dbarbera's avatar
dbarbera committed
916
    ''' Generate the code for a floating label '''
917
    raise NotImplementedError