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
            raise NameError("name '%s' is not defined" % name)
112

dbarbera's avatar
dbarbera committed
113

Maxime Perrotin's avatar
Maxime Perrotin committed
114
115
116
117
@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
118

dbarbera's avatar
dbarbera committed
119

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

127
128
    global g
    g = GlobalState(process)
129

dbarbera's avatar
dbarbera committed
130
131
132
133
134
135
    # 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
136

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

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

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

dbarbera's avatar
dbarbera committed
155
156
157
    # Declare timer set/reset functions
    for timer in process.timers:
        # TODO: Should be uint?
158
159
        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
160

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

169
    # Declare external procedures functions
dbarbera's avatar
dbarbera committed
170
171
    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]
172
        decl_func(str(proc.inputString), g.void, param_tys, True)
dbarbera's avatar
dbarbera committed
173

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

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

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

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

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


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

196
197
    _push_scope()

198
199
200
201
202
    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
203
    g.builder = core.Builder.new(entry_block)
204
205

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

    # cond
dbarbera's avatar
dbarbera committed
212
    g.builder.position_at_end(cond_block)
213
    no_tr_cons = core.Constant.int(g.i32, -1)
214
215
    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
216
    g.builder.cbranch(cond_val, body_block, exit_block)
217
218

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

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

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

235
236
    _pop_scope()

237
238
239
240
    func.verify()
    return func


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

245
246
    _push_scope()

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

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

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

259
260
    _pop_scope()

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


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

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

274
275
    _push_scope()

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

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

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

        # TODO: Nested states

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

302
        g.builder.ret_void()
303

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

307
308
    _pop_scope()

309
310
311
    func.verify()


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

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

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


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

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


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

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


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

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


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


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


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


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

dbarbera's avatar
dbarbera committed
480

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

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


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


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


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


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


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

dbarbera's avatar
dbarbera committed
561
562
563
    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
564
565
        return g.builder.fptosi(res_val, g.i32)
    else:
dbarbera's avatar
dbarbera committed
566
        return g.builder.call(g.funcs['fabs'], [expr_val])
567
568
569


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


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


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

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

Maxime Perrotin's avatar
Maxime Perrotin committed
667

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

673

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

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

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

Maxime Perrotin's avatar
Maxime Perrotin committed
690

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

Maxime Perrotin's avatar
Maxime Perrotin committed
710

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


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


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


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


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


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


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


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


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


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


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


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


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


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

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

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


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


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

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

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

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

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

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

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

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

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


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


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


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