LlvmGenerator.py 32.4 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
                var_ptr = g.scope.resolve(str(var_name))
295
296
297
298
                if is_struct_ptr(var_ptr):
                    generate_assign(var_ptr, func.args[0])
                else:
                    generate_assign(var_ptr, g.builder.load(func.args[0]))
299
            if input.transition:
300
                id_val = core.Constant.int(g.i32, input.transition_id)
301
                g.builder.call(g.funcs['run_transition'], [id_val])
302

303
        g.builder.ret_void()
304

305
306
    g.builder.position_at_end(exit_block)
    g.builder.ret_void()
307

308
309
    _pop_scope()

310
311
312
    func.verify()


Maxime Perrotin's avatar
Maxime Perrotin committed
313
314
315
316
@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
317
318
319
    for out in output.output:
        name = out['outputName'].lower()

320
        if name == 'write':
dbarbera's avatar
dbarbera committed
321
322
            _generate_write(out['params'])
            continue
323
324
325
        elif name == 'writeln':
            _generate_writeln(out['params'])
            continue
dbarbera's avatar
dbarbera committed
326
327
328
329
330
331
332
        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
333
        func = g.funcs[str(name).lower()]
334
335
336
337
338
339
340
341
342
343
344
345
346

        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
347
348
349
350


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

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


def _generate_writeln(params):
    ''' Generate the code for the writeln operator '''
    _generate_write(params)
381
382

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


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

    g.builder.call(reset_func, [])
dbarbera's avatar
dbarbera committed
395
396
397
398


def _generate_set_timer(params):
    ''' Generate the code for the set timer operator '''
dbarbera's avatar
dbarbera committed
399
    timer_expr, timer_id = params
400
    set_func_name = 'set_%s' % timer_id.value[0]
dbarbera's avatar
dbarbera committed
401
402
403
404
405
406
407
408
    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
409
410
411
412


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


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


@generate.register(ogAST.TaskForLoop)
def _task_forloop(task):
dbarbera's avatar
dbarbera committed
426
    ''' Generate the code for a for loop '''
dbarbera's avatar
dbarbera committed
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
476
477
478
    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'''
479
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
480

dbarbera's avatar
dbarbera committed
481

dbarbera's avatar
dbarbera committed
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
511
512
513
@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
514
515
516

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


@expression.register(ogAST.PrimVariable)
Maxime Perrotin's avatar
Maxime Perrotin committed
522
def _primary_variable(prim):
dbarbera's avatar
dbarbera committed
523
524
525
    ''' 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
526
527


Maxime Perrotin's avatar
Maxime Perrotin committed
528
@expression.register(ogAST.PrimPath)
dbarbera's avatar
dbarbera committed
529
def _prim_path(prim):
dbarbera's avatar
dbarbera committed
530
    ''' Generate the code for an of path expression '''
531
532
533
534
535
536
537
538
539
540
541
542
543
    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
544
545
    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
546
547


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


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


def generate_abs(params):
dbarbera's avatar
dbarbera committed
559
    ''' Generate the code for the built-in abs operation'''
dbarbera's avatar
dbarbera committed
560
    expr_val = expression(params[0])
dbarbera's avatar
dbarbera committed
561

dbarbera's avatar
dbarbera committed
562
563
564
    if expr_val.type.kind == core.TYPE_INTEGER:
        expr_conv = g.builder.sitofp(expr_val, g.double)
        res_val = g.builder.call(g.funcs['fabs'], [expr_conv])
dbarbera's avatar
dbarbera committed
565
566
        return g.builder.fptosi(res_val, g.i32)
    else:
dbarbera's avatar
dbarbera committed
567
        return g.builder.call(g.funcs['fabs'], [expr_val])
568
569
570


def generate_fix(params):
dbarbera's avatar
dbarbera committed
571
    ''' Generate the code for the built-in fix operation'''
dbarbera's avatar
dbarbera committed
572
573
    expr_val = expression(params[0])
    return g.builder.fptosi(expr_val, g.i32)
574
575
576


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


def generate_power(params):
dbarbera's avatar
dbarbera committed
583
    ''' Generate the code for the built-in power operation'''
584
585
586
587
588
589
590
591
592
593
594
    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
595
596
597
598
599
600
601
602
603
604
605
606
@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
607
608
def _basic(expr):
    ''' Generate the code for an arithmetic of relational expression '''
609
610
    lefttmp = expression(expr.left)
    righttmp = expression(expr.right)
611

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

Maxime Perrotin's avatar
Maxime Perrotin committed
668

669
670
@expression.register(ogAST.ExprAssign)
def _assign(expr):
dbarbera's avatar
dbarbera committed
671
    ''' Generate the code for an assign expression '''
dbarbera's avatar
dbarbera committed
672
    generate_assign(reference(expr.left), expression(expr.right))
673

674

dbarbera's avatar
dbarbera committed
675
def generate_assign(left, right):
676
677
678
    ''' 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
679
    if is_struct_ptr(left):
680
681
        size = core.Constant.sizeof(left.type.pointee)
        align = core.Constant.int(g.i32, 0)
682
        volatile = core.Constant.int(g.i1, 0)
683

684
685
        right_ptr = g.builder.bitcast(right, g.i8_ptr)
        left_ptr = g.builder.bitcast(left, g.i8_ptr)
686

dbarbera's avatar
dbarbera committed
687
        g.builder.call(g.funcs['memcpy'], [left_ptr, right_ptr, size, align, volatile])
688
    else:
689
        g.builder.store(right, left)
dbarbera's avatar
dbarbera committed
690

Maxime Perrotin's avatar
Maxime Perrotin committed
691

Maxime Perrotin's avatar
Maxime Perrotin committed
692
693
694
@expression.register(ogAST.ExprOr)
@expression.register(ogAST.ExprAnd)
@expression.register(ogAST.ExprXor)
dbarbera's avatar
dbarbera committed
695
696
def _logical(expr):
    ''' Generate the code for a logical expression '''
dbarbera's avatar
dbarbera committed
697
698
699
700
701
702
703
    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
704
705
706
    if expr.operand == 'and':
        return g.builder.and_(lefttmp, righttmp, 'andtmp')
    elif expr.operand == 'or':
707
        return g.builder.or_(lefttmp, righttmp, 'ortmp')
dbarbera's avatar
dbarbera committed
708
    else:
709
        return g.builder.xor(lefttmp, righttmp, 'xortmp')
dbarbera's avatar
dbarbera committed
710

Maxime Perrotin's avatar
Maxime Perrotin committed
711

Maxime Perrotin's avatar
Maxime Perrotin committed
712
@expression.register(ogAST.ExprAppend)
Maxime Perrotin's avatar
Maxime Perrotin committed
713
714
def _append(expr):
    ''' Generate code for the APPEND construct: a // b '''
715
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
716
717


Maxime Perrotin's avatar
Maxime Perrotin committed
718
@expression.register(ogAST.ExprIn)
Maxime Perrotin's avatar
Maxime Perrotin committed
719
def _expr_in(expr):
dbarbera's avatar
dbarbera committed
720
    ''' Generate the code for an in expression '''
721
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
722
723


Maxime Perrotin's avatar
Maxime Perrotin committed
724
@expression.register(ogAST.PrimEnumeratedValue)
Maxime Perrotin's avatar
Maxime Perrotin committed
725
726
def _enumerated_value(primary):
    ''' Generate code for an enumerated value '''
dbarbera's avatar
dbarbera committed
727
728
729
    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
730
731


Maxime Perrotin's avatar
Maxime Perrotin committed
732
@expression.register(ogAST.PrimChoiceDeterminant)
Maxime Perrotin's avatar
Maxime Perrotin committed
733
734
def _choice_determinant(primary):
    ''' Generate code for a choice determinant (enumerated) '''
735
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
736
737


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


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


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


Maxime Perrotin's avatar
Maxime Perrotin committed
759
@expression.register(ogAST.PrimEmptyString)
Maxime Perrotin's avatar
Maxime Perrotin committed
760
761
def _empty_string(primary):
    ''' Generate code for an empty SEQUENCE OF: {} '''
762
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
763
764


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


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


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


Maxime Perrotin's avatar
Maxime Perrotin committed
783
@expression.register(ogAST.PrimIfThenElse)
dbarbera's avatar
dbarbera committed
784
def _if_then_else(ifthen):
dbarbera's avatar
dbarbera committed
785
    ''' Generate the code for ternary operator '''
786
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
787
788


Maxime Perrotin's avatar
Maxime Perrotin committed
789
@expression.register(ogAST.PrimSequence)
Maxime Perrotin's avatar
Maxime Perrotin committed
790
def _sequence(seq):
dbarbera's avatar
dbarbera committed
791
    ''' Generate the code for an ASN.1 SEQUENCE '''
dbarbera's avatar
dbarbera committed
792
793
794
795
796
797
798
799
800
801
802
    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
803
804


Maxime Perrotin's avatar
Maxime Perrotin committed
805
@expression.register(ogAST.PrimSequenceOf)
Maxime Perrotin's avatar
Maxime Perrotin committed
806
def _sequence_of(seqof):
dbarbera's avatar
dbarbera committed
807
    ''' Generate the code for an ASN.1 SEQUENCE OF '''
808
    ty = _generate_type(seqof.exprType)
809
810
811
    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])
812
813

    for idx, expr in enumerate(seqof.value):
814
        idx_cons = core.Constant.int(g.i32, idx)
815
        expr_val = expression(expr)
816
817
        pos_ptr = g.builder.gep(array_ptr, [zero_cons, idx_cons])
        g.builder.store(expr_val, pos_ptr)
818
819

    return struct_ptr
Maxime Perrotin's avatar
Maxime Perrotin committed
820
821


Maxime Perrotin's avatar
Maxime Perrotin committed
822
@expression.register(ogAST.PrimChoiceItem)
Maxime Perrotin's avatar
Maxime Perrotin committed
823
def _choiceitem(choice):
dbarbera's avatar
dbarbera committed
824
    ''' Generate the code for a CHOICE expression '''
825
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
826
827
828
829


@generate.register(ogAST.Decision)
def _decision(dec):
dbarbera's avatar
dbarbera committed
830
    ''' Generate the code for a decision '''
831
    func = g.builder.basic_block.function
dbarbera's avatar
dbarbera committed
832
833
834
835

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

836
    g.builder.branch(ans_cond_blocks[0])
dbarbera's avatar
dbarbera committed
837
838
839
840
841

    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')
842
        g.builder.position_at_end(ans_cond_block)
dbarbera's avatar
dbarbera committed
843
844

        if ans.kind == 'constant':
dbarbera's avatar
dbarbera committed
845
            next_block = ans_cond_blocks[idx+1] if idx < len(ans_cond_blocks)-1 else end_block
dbarbera's avatar
dbarbera committed
846
847
848
849
850
851

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

852
853
854
            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
855
856
        elif ans.kind == 'else':
            if ans.transition:
857
                g.builder.branch(ans_tr_block)
dbarbera's avatar
dbarbera committed
858
            else:
859
                g.builder.branch(end_block)
dbarbera's avatar
dbarbera committed
860
861
862
863
        else:
            raise NotImplementedError

        if ans.transition:
864
            g.builder.position_at_end(ans_tr_block)
dbarbera's avatar
dbarbera committed
865
            generate(ans.transition)
866
            g.builder.branch(end_block)
dbarbera's avatar
dbarbera committed
867

868
    g.builder.position_at_end(end_block)
Maxime Perrotin's avatar
Maxime Perrotin committed
869
870
871
872


@generate.register(ogAST.Label)
def _label(tr):
dbarbera's avatar
dbarbera committed
873
    ''' TGenerate the code for a Label '''
874
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
875
876
877
878


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


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