LlvmGenerator.py 34.3 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
class Scope:
    def __init__(self, parent=None):
        self.vars = {}
dbarbera's avatar
dbarbera committed
99
        self.labels = {}
100
101
102
103
104
105
106
107
108
109
110
111
        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
112
            raise NameError("name '%s' is not defined" % name)
113

dbarbera's avatar
dbarbera committed
114
115
116
117
118
119
120
121
122
    def label(self, name):
        name = name.lower()
        label_block = self.labels.get(name)
        if not label_block:
            func = g.builder.basic_block.function
            label_block = func.append_basic_block(name)
            self.labels[name] = label_block
        return label_block

dbarbera's avatar
dbarbera committed
123

Maxime Perrotin's avatar
Maxime Perrotin committed
124
125
126
127
@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
128

dbarbera's avatar
dbarbera committed
129

Maxime Perrotin's avatar
Maxime Perrotin committed
130
131
132
# Processing of the AST
@generate.register(ogAST.Process)
def _process(process):
dbarbera's avatar
dbarbera committed
133
    ''' Generate LLVM IR code '''
dbarbera's avatar
dbarbera committed
134
135
    process_name = str(process.processName)
    LOG.info('Generating LLVM IR code for process ' + process_name)
136

137
138
    global g
    g = GlobalState(process)
139

dbarbera's avatar
dbarbera committed
140
141
142
143
144
145
    # 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
146

147
148
149
    # Initialize states enum
    for name in process.mapping.iterkeys():
        if not name.endswith('START'):
150
151
            cons = core.Constant.int(g.i32, len(g.states))
            g.states[name] = cons
152

153
    # Generate state var
154
155
    state_cons = g.module.add_global_variable(g.i32, 'state')
    state_cons.initializer = core.Constant.int(g.i32, -1)
156
    g.scope.define('state', state_cons)
157

158
159
160
    # Generare process-level vars
    for name, (ty, expr) in process.variables.viewitems():
        var_ty = _generate_type(ty)
161
        global_var = g.module.add_global_variable(var_ty, str(name))
162
        global_var.initializer = core.Constant.null(var_ty)
163
        g.scope.define(str(name).lower(), global_var)
164

dbarbera's avatar
dbarbera committed
165
166
167
    # Declare timer set/reset functions
    for timer in process.timers:
        # TODO: Should be uint?
168
169
        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
170

171
    # Declare output signal functions
dbarbera's avatar
dbarbera committed
172
    for signal in process.output_signals:
173
174
175
176
        if 'type' in signal:
            param_tys = [core.Type.pointer(_generate_type(signal['type']))]
        else:
            param_tys = []
177
        decl_func(str(signal['name']), g.void, param_tys, True)
dbarbera's avatar
dbarbera committed
178

179
    # Declare external procedures functions
dbarbera's avatar
dbarbera committed
180
181
    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]
182
        decl_func(str(proc.inputString), g.void, param_tys, True)
dbarbera's avatar
dbarbera committed
183

184
185
    # Generate internal procedures
    for proc in process.content.inner_procedures:
186
        generate(proc)
187

188
    # Generate process functions
189
    _generate_runtr_func(process)
190
    _generate_startup_func(process)
191

192
193
194
195
    # Generate input signals
    for signal in process.input_signals:
        _generate_input_signal(signal, mapping[signal['name']])

dbarbera's avatar
dbarbera committed
196
197
    g.module.verify()

dbarbera's avatar
dbarbera committed
198
    with open(g.name + '.ll', 'w') as ll_file:
dbarbera's avatar
dbarbera committed
199
        ll_file.write(str(g.module))
200
201
202


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

206
207
    _push_scope()

208
209
210
211
212
    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
213
    g.builder = core.Builder.new(entry_block)
214
215

    # entry
dbarbera's avatar
dbarbera committed
216
    id_ptr = g.builder.alloca(g.i32, None, 'id')
217
    g.scope.define('id', id_ptr)
dbarbera's avatar
dbarbera committed
218
219
    g.builder.store(func.args[0], id_ptr)
    g.builder.branch(cond_block)
220
221

    # cond
dbarbera's avatar
dbarbera committed
222
    g.builder.position_at_end(cond_block)
223
    no_tr_cons = core.Constant.int(g.i32, -1)
224
225
    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
226
    g.builder.cbranch(cond_val, body_block, exit_block)
227
228

    # body
dbarbera's avatar
dbarbera committed
229
230
    g.builder.position_at_end(body_block)
    switch = g.builder.switch(func.args[0], exit_block)
231
232
233
234

    # transitions
    for idx, tr in enumerate(process.transitions):
        tr_block = func.append_basic_block('tr%d' % idx)
235
        const = core.Constant.int(g.i32, idx)
236
        switch.add_case(const, tr_block)
dbarbera's avatar
dbarbera committed
237
        g.builder.position_at_end(tr_block)
238
        generate(tr)
dbarbera's avatar
dbarbera committed
239
240
        if not g.builder.basic_block.terminator:
            g.builder.branch(cond_block)
241
242

    # exit
dbarbera's avatar
dbarbera committed
243
244
    g.builder.position_at_end(exit_block)
    g.builder.ret_void()
245

dbarbera's avatar
dbarbera committed
246
247
248
249
250
251
252
253
254
    Helper.inner_labels_to_floating(process)
    for label in process.content.floating_labels:
        generate(label)

    # TODO: Use defined cond_block instead?
    next_tr_label_block = g.scope.label('next_transition')
    g.builder.position_at_end(next_tr_label_block)
    g.builder.branch(cond_block)

255
256
    _pop_scope()

257
258
259
260
    func.verify()
    return func


261
def _generate_startup_func(process):
dbarbera's avatar
dbarbera committed
262
    ''' Generate code for the startup function '''
263
    func = decl_func(g.name + '_startup', g.void, [])
264

265
266
    _push_scope()

267
    entry_block = func.append_basic_block('entry')
268
    g.builder = core.Builder.new(entry_block)
269

270
271
272
    # Initialize process level variables
    for name, (ty, expr) in process.variables.viewitems():
        if expr:
dbarbera's avatar
dbarbera committed
273
            global_var = g.scope.resolve(str(name))
dbarbera's avatar
dbarbera committed
274
            generate_assign(global_var, expression(expr))
275

276
277
    g.builder.call(g.funcs['run_transition'], [core.Constant.int(g.i32, 0)])
    g.builder.ret_void()
Maxime Perrotin's avatar
Maxime Perrotin committed
278

279
280
    _pop_scope()

281
282
    func.verify()
    return func
Maxime Perrotin's avatar
Maxime Perrotin committed
283
284


285
def _generate_input_signal(signal, inputs):
dbarbera's avatar
dbarbera committed
286
    ''' Generate code for an input signal '''
dbarbera's avatar
dbarbera committed
287
    func_name = g.name + "_" + str(signal['name'])
288
289
290
    param_tys = []
    if 'type' in signal:
        param_tys.append(core.Type.pointer(_generate_type(signal['type'])))
291
292

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

294
295
    _push_scope()

296
297
    entry_block = func.append_basic_block('entry')
    exit_block = func.append_basic_block('exit')
298
    g.builder = core.Builder.new(entry_block)
299

300
    g_state_val = g.builder.load(g.global_scope.resolve('state'))
301
    switch = g.builder.switch(g_state_val, exit_block)
302

303
    for state_name, state_id in g.states.iteritems():
304
305
        state_block = func.append_basic_block('state_%s' % str(state_name))
        switch.add_case(state_id, state_block)
306
        g.builder.position_at_end(state_block)
307
308
309

        # TODO: Nested states

310
311
312
        input = inputs.get(state_name)
        if input:
            for var_name in input.parameters:
dbarbera's avatar
dbarbera committed
313
                var_ptr = g.scope.resolve(str(var_name))
314
315
316
317
                if is_struct_ptr(var_ptr):
                    generate_assign(var_ptr, func.args[0])
                else:
                    generate_assign(var_ptr, g.builder.load(func.args[0]))
318
            if input.transition:
319
                id_val = core.Constant.int(g.i32, input.transition_id)
320
                g.builder.call(g.funcs['run_transition'], [id_val])
321

322
        g.builder.ret_void()
323

324
325
    g.builder.position_at_end(exit_block)
    g.builder.ret_void()
326

327
328
    _pop_scope()

329
330
331
    func.verify()


Maxime Perrotin's avatar
Maxime Perrotin committed
332
333
334
335
@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
336
337
338
    for out in output.output:
        name = out['outputName'].lower()

339
        if name == 'write':
dbarbera's avatar
dbarbera committed
340
341
            _generate_write(out['params'])
            continue
342
343
344
        elif name == 'writeln':
            _generate_writeln(out['params'])
            continue
dbarbera's avatar
dbarbera committed
345
346
347
348
349
350
351
        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
352
        func = g.funcs[str(name).lower()]
353
354
355
356
357
358
359
360
361
362
363
364
365

        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
366
367
368
369


def _generate_write(params):
    ''' Generate the code for the write operator '''
370
    zero = core.Constant.int(g.i32, 0)
371
372
373
    for param in params:
        basic_ty = find_basic_type(param.exprType)
        expr_val = expression(param)
374

375
        if basic_ty.kind == 'IntegerType':
376
            fmt_val = _get_string_cons('% d')
377
            fmt_ptr = g.builder.gep(fmt_val, [zero, zero])
dbarbera's avatar
dbarbera committed
378
            g.builder.call(g.funcs['printf'], [fmt_ptr, expr_val])
379
        elif basic_ty.kind == 'RealType':
380
            fmt_val = _get_string_cons('% .14E')
381
            fmt_ptr = g.builder.gep(fmt_val, [zero, zero])
dbarbera's avatar
dbarbera committed
382
            g.builder.call(g.funcs['printf'], [fmt_ptr, expr_val])
383
        elif basic_ty.kind == 'BooleanType':
384
            true_str_val = _get_string_cons('TRUE')
385
            true_str_ptr = g.builder.gep(true_str_val, [zero, zero])
386
            false_str_val = _get_string_cons('FALSE')
387
388
            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
389
            g.builder.call(g.funcs['printf'], [str_ptr])
dbarbera's avatar
dbarbera committed
390
391
        elif basic_ty.kind == 'StringType':
            expr_ptr = g.builder.gep(expr_val, [zero, zero])
dbarbera's avatar
dbarbera committed
392
            g.builder.call(g.funcs['printf'], [expr_ptr])
393
394
395
396
397
398
399
        else:
            raise NotImplementedError


def _generate_writeln(params):
    ''' Generate the code for the writeln operator '''
    _generate_write(params)
400
401

    zero = core.Constant.int(g.i32, 0)
402
    str_cons = _get_string_cons('\n')
403
    str_ptr = g.builder.gep(str_cons, [zero, zero])
dbarbera's avatar
dbarbera committed
404
    g.builder.call(g.funcs['printf'], [str_ptr])
dbarbera's avatar
dbarbera committed
405
406
407
408


def _generate_reset_timer(params):
    ''' Generate the code for the reset timer operator '''
dbarbera's avatar
dbarbera committed
409
    timer_id = params[0]
410
    reset_func_name = 'reset_%s' % timer_id.value[0]
dbarbera's avatar
dbarbera committed
411
412
413
    reset_func = g.funcs[reset_func_name.lower()]

    g.builder.call(reset_func, [])
dbarbera's avatar
dbarbera committed
414
415
416
417


def _generate_set_timer(params):
    ''' Generate the code for the set timer operator '''
dbarbera's avatar
dbarbera committed
418
    timer_expr, timer_id = params
419
    set_func_name = 'set_%s' % timer_id.value[0]
dbarbera's avatar
dbarbera committed
420
421
422
423
424
425
426
427
    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
428
429
430
431


@generate.register(ogAST.TaskAssign)
def _task_assign(task):
dbarbera's avatar
dbarbera committed
432
    ''' Generate the code of a list of assignments '''
433
434
    for expr in task.elems:
        expression(expr)
Maxime Perrotin's avatar
Maxime Perrotin committed
435
436
437
438
439


@generate.register(ogAST.TaskInformalText)
def _task_informal_text(task):
    ''' Generate comments for informal text '''
dbarbera's avatar
dbarbera committed
440
    pass
Maxime Perrotin's avatar
Maxime Perrotin committed
441
442
443
444


@generate.register(ogAST.TaskForLoop)
def _task_forloop(task):
dbarbera's avatar
dbarbera committed
445
    ''' Generate the code for a for loop '''
dbarbera's avatar
dbarbera committed
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
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
    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'''
498
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
499

dbarbera's avatar
dbarbera committed
500

dbarbera's avatar
dbarbera committed
501
502
503
@singledispatch
def reference(prim):
    ''' Generate a variable reference '''
dbarbera's avatar
flake8    
dbarbera committed
504
    raise TypeError('Unsupported reference: ' + str(prim))
dbarbera's avatar
dbarbera committed
505
506
507
508
509
510
511
512
513
514
515


@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 '''
516
    var_name = prim.value[0].lower()
dbarbera's avatar
dbarbera committed
517
518
519
520
521
522
523
    var_ptr = g.scope.resolve(str(var_name))

    if not prim.value:
        return var_ptr

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

dbarbera's avatar
dbarbera committed
524
525
526
527
528
529
530
531
532
533
534
535
536
    for elem in prim.value[1:]:
        if type(elem) == dict:
            if 'index' in elem:
                idx_val = expression(elem['index'][0])
                var_ptr = g.builder.gep(var_ptr, [zero_cons, zero_cons, idx_val])
            else:
                raise NotImplementedError
        else:
            var_ty = var_ptr.type
            struct = g.structs[var_ty.pointee.name]
            field_idx_cons = core.Constant.int(g.i32, struct.idx(elem.lower()))
            field_ptr = g.builder.gep(var_ptr, [zero_cons, field_idx_cons])
            var_ptr = field_ptr
dbarbera's avatar
dbarbera committed
537
538
539

    return var_ptr

Maxime Perrotin's avatar
Maxime Perrotin committed
540
541
542

@singledispatch
def expression(expr):
dbarbera's avatar
dbarbera committed
543
    ''' Generate the code for Expression-classes '''
Maxime Perrotin's avatar
Maxime Perrotin committed
544
545
546
547
    raise TypeError('Unsupported expression: ' + str(expr))


@expression.register(ogAST.PrimVariable)
Maxime Perrotin's avatar
Maxime Perrotin committed
548
def _primary_variable(prim):
dbarbera's avatar
dbarbera committed
549
550
551
    ''' 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
552
553


Maxime Perrotin's avatar
Maxime Perrotin committed
554
@expression.register(ogAST.PrimPath)
dbarbera's avatar
dbarbera committed
555
def _prim_path(prim):
dbarbera's avatar
dbarbera committed
556
    ''' Generate the code for an of path expression '''
557
558
559
560
561
562
563
564
565
    specops_generators = {
        'length': generate_length,
        'present': generate_present,
        'abs': generate_abs,
        'fix': generate_fix,
        'float': generate_float,
        'power': generate_power
    }

dbarbera's avatar
dbarbera committed
566
567
568
569
570
571
572
    name = prim.value[0].lower()
    if name in specops_generators:
        generator = specops_generators[name]
        return generator(prim.value[1]['procParams'])

    return generate_access(prim)

573

dbarbera's avatar
dbarbera committed
574
575
def generate_access(prim):
    ''' Generate the code for an access '''
dbarbera's avatar
dbarbera committed
576
577
    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
578
579


580
def generate_length(params):
dbarbera's avatar
dbarbera committed
581
    ''' Generate the code for the built-in length operation'''
dbarbera's avatar
dbarbera committed
582
583
584
585
586
    seq_ptr = reference(params[0])
    size = core.Constant.sizeof(seq_ptr.type.pointee)
    tmp = g.builder.alloca(size.type)
    g.builder.store(size, tmp)
    return tmp
587
588
589


def generate_present(params):
dbarbera's avatar
dbarbera committed
590
    ''' Generate the code for the built-in present operation'''
591
592
593
594
    raise NotImplementedError


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

dbarbera's avatar
dbarbera committed
598
599
600
    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
601
602
        return g.builder.fptosi(res_val, g.i32)
    else:
dbarbera's avatar
dbarbera committed
603
        return g.builder.call(g.funcs['fabs'], [expr_val])
604
605
606


def generate_fix(params):
dbarbera's avatar
dbarbera committed
607
    ''' Generate the code for the built-in fix operation'''
dbarbera's avatar
dbarbera committed
608
609
    expr_val = expression(params[0])
    return g.builder.fptosi(expr_val, g.i32)
610
611
612


def generate_float(params):
dbarbera's avatar
dbarbera committed
613
    ''' Generate the code for the built-in float operation'''
dbarbera's avatar
dbarbera committed
614
615
    expr_val = expression(params[0])
    return g.builder.sitofp(expr_val, g.double)
616
617
618


def generate_power(params):
dbarbera's avatar
dbarbera committed
619
    ''' Generate the code for the built-in power operation'''
620
621
622
623
624
625
626
627
628
629
630
    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
631
632
633
634
635
636
637
638
639
640
641
642
@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
643
644
def _basic(expr):
    ''' Generate the code for an arithmetic of relational expression '''
645
646
    lefttmp = expression(expr.left)
    righttmp = expression(expr.right)
647

648
649
    if lefttmp.type.kind == core.TYPE_INTEGER:
        if expr.operand == '+':
650
            return g.builder.add(lefttmp, righttmp, 'addtmp')
651
        elif expr.operand == '-':
652
            return g.builder.sub(lefttmp, righttmp, 'subtmp')
653
        elif expr.operand == '*':
654
            return g.builder.mul(lefttmp, righttmp, 'multmp')
655
        elif expr.operand == '/':
656
            return g.builder.sdiv(lefttmp, righttmp, 'divtmp')
657
        elif expr.operand == 'mod':
658
            # l mod r == (((l rem r) + r) rem r)
659
660
661
            remtmp = g.builder.srem(lefttmp, righttmp)
            addtmp = g.builder.add(remtmp, righttmp)
            return g.builder.srem(addtmp, righttmp, 'modtmp')
662
        elif expr.operand == 'rem':
663
            return g.builder.srem(lefttmp, righttmp, 'remtmp')
664
        elif expr.operand == '<':
665
            return g.builder.icmp(core.ICMP_SLT, lefttmp, righttmp, 'lttmp')
666
        elif expr.operand == '<=':
667
            return g.builder.icmp(core.ICMP_SLE, lefttmp, righttmp, 'letmp')
668
        elif expr.operand == '=':
669
            return g.builder.icmp(core.ICMP_EQ, lefttmp, righttmp, 'eqtmp')
670
        elif expr.operand == '/=':
671
            return g.builder.icmp(core.ICMP_NE, lefttmp, righttmp, 'netmp')
672
        elif expr.operand == '>=':
673
            return g.builder.icmp(core.ICMP_SGE, lefttmp, righttmp, 'getmp')
674
        elif expr.operand == '>':
675
            return g.builder.icmp(core.ICMP_SGT, lefttmp, righttmp, 'gttmp')
676
677
678
679
        else:
            raise NotImplementedError
    elif lefttmp.type.kind == core.TYPE_DOUBLE:
        if expr.operand == '+':
680
            return g.builder.fadd(lefttmp, righttmp, 'addtmp')
681
        elif expr.operand == '-':
682
            return g.builder.fsub(lefttmp, righttmp, 'subtmp')
683
        elif expr.operand == '*':
684
            return g.builder.fmul(lefttmp, righttmp, 'multmp')
685
        elif expr.operand == '/':
686
            return g.builder.fdiv(lefttmp, righttmp, 'divtmp')
687
        elif expr.operand == '<':
688
            return g.builder.fcmp(core.FCMP_OLT, lefttmp, righttmp, 'lttmp')
689
        elif expr.operand == '<=':
690
            return g.builder.fcmp(core.FCMP_OLE, lefttmp, righttmp, 'letmp')
691
        elif expr.operand == '=':
692
            return g.builder.fcmp(core.FCMP_OEQ, lefttmp, righttmp, 'eqtmp')
693
        elif expr.operand == '/=':
694
            return g.builder.fcmp(core.FCMP_ONE, lefttmp, righttmp, 'netmp')
695
        elif expr.operand == '>=':
696
            return g.builder.fcmp(core.FCMP_OGE, lefttmp, righttmp, 'getmp')
697
        elif expr.operand == '>':
698
            return g.builder.fcmp(core.FCMP_OGT, lefttmp, righttmp, 'gttmp')
699
700
        else:
            raise NotImplementedError
701
    else:
702
        raise NotImplementedError
703

Maxime Perrotin's avatar
Maxime Perrotin committed
704

705
706
@expression.register(ogAST.ExprAssign)
def _assign(expr):
dbarbera's avatar
dbarbera committed
707
    ''' Generate the code for an assign expression '''
dbarbera's avatar
dbarbera committed
708
    generate_assign(reference(expr.left), expression(expr.right))
709

710

dbarbera's avatar
dbarbera committed
711
def generate_assign(left, right):
712
713
714
    ''' 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
715
    if is_struct_ptr(left):
716
717
        size = core.Constant.sizeof(left.type.pointee)
        align = core.Constant.int(g.i32, 0)
718
        volatile = core.Constant.int(g.i1, 0)
719

720
721
        right_ptr = g.builder.bitcast(right, g.i8_ptr)
        left_ptr = g.builder.bitcast(left, g.i8_ptr)
722

dbarbera's avatar
dbarbera committed
723
        g.builder.call(g.funcs['memcpy'], [left_ptr, right_ptr, size, align, volatile])
724
    else:
725
        g.builder.store(right, left)
dbarbera's avatar
dbarbera committed
726

Maxime Perrotin's avatar
Maxime Perrotin committed
727

Maxime Perrotin's avatar
Maxime Perrotin committed
728
729
730
@expression.register(ogAST.ExprOr)
@expression.register(ogAST.ExprAnd)
@expression.register(ogAST.ExprXor)
dbarbera's avatar
dbarbera committed
731
732
def _logical(expr):
    ''' Generate the code for a logical expression '''
dbarbera's avatar
dbarbera committed
733
734
735
736
737
738
739
    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
740
741
742
    if expr.operand == 'and':
        return g.builder.and_(lefttmp, righttmp, 'andtmp')
    elif expr.operand == 'or':
743
        return g.builder.or_(lefttmp, righttmp, 'ortmp')
dbarbera's avatar
dbarbera committed
744
    else:
745
        return g.builder.xor(lefttmp, righttmp, 'xortmp')
dbarbera's avatar
dbarbera committed
746

Maxime Perrotin's avatar
Maxime Perrotin committed
747

Maxime Perrotin's avatar
Maxime Perrotin committed
748
@expression.register(ogAST.ExprAppend)
Maxime Perrotin's avatar
Maxime Perrotin committed
749
750
def _append(expr):
    ''' Generate code for the APPEND construct: a // b '''
751
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
752
753


Maxime Perrotin's avatar
Maxime Perrotin committed
754
@expression.register(ogAST.ExprIn)
Maxime Perrotin's avatar
Maxime Perrotin committed
755
def _expr_in(expr):
dbarbera's avatar
dbarbera committed
756
    ''' Generate the code for an in expression '''
757
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
758
759


Maxime Perrotin's avatar
Maxime Perrotin committed
760
@expression.register(ogAST.PrimEnumeratedValue)
Maxime Perrotin's avatar
Maxime Perrotin committed
761
762
def _enumerated_value(primary):
    ''' Generate code for an enumerated value '''
dbarbera's avatar
dbarbera committed
763
764
765
    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
766
767


Maxime Perrotin's avatar
Maxime Perrotin committed
768
@expression.register(ogAST.PrimChoiceDeterminant)
Maxime Perrotin's avatar
Maxime Perrotin committed
769
770
def _choice_determinant(primary):
    ''' Generate code for a choice determinant (enumerated) '''
771
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
772
773


Maxime Perrotin's avatar
Maxime Perrotin committed
774
@expression.register(ogAST.PrimInteger)
775
776
def _integer(primary):
    ''' Generate code for a raw integer value  '''
777
    return core.Constant.int(g.i32, primary.value[0])
778
779


Maxime Perrotin's avatar
Maxime Perrotin committed
780
@expression.register(ogAST.PrimReal)
781
782
def _real(primary):
    ''' Generate code for a raw real value  '''
783
    return core.Constant.real(g.double, primary.value[0])
784
785


Maxime Perrotin's avatar
Maxime Perrotin committed
786
@expression.register(ogAST.PrimBoolean)
787
788
def _boolean(primary):
    ''' Generate code for a raw boolean value  '''
dbarbera's avatar
dbarbera committed
789
    if primary.value[0].lower() == 'true':
790
        return core.Constant.int(g.i1, 1)
dbarbera's avatar
dbarbera committed
791
    else:
792
        return core.Constant.int(g.i1, 0)
Maxime Perrotin's avatar
Maxime Perrotin committed
793
794


Maxime Perrotin's avatar
Maxime Perrotin committed
795
@expression.register(ogAST.PrimEmptyString)
Maxime Perrotin's avatar
Maxime Perrotin committed
796
797
def _empty_string(primary):
    ''' Generate code for an empty SEQUENCE OF: {} '''
798
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
799
800


Maxime Perrotin's avatar
Maxime Perrotin committed
801
@expression.register(ogAST.PrimStringLiteral)
Maxime Perrotin's avatar
Maxime Perrotin committed
802
803
def _string_literal(primary):
    ''' Generate code for a string (Octet String) '''
dbarbera's avatar
dbarbera committed
804
    return _get_string_cons(str(primary.value[1:-1]))
Maxime Perrotin's avatar
Maxime Perrotin committed
805
806


Maxime Perrotin's avatar
Maxime Perrotin committed
807
@expression.register(ogAST.PrimConstant)
Maxime Perrotin's avatar
Maxime Perrotin committed
808
809
def _constant(primary):
    ''' Generate code for a reference to an ASN.1 constant '''
810
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
811
812


Maxime Perrotin's avatar
Maxime Perrotin committed
813
@expression.register(ogAST.PrimMantissaBaseExp)
Maxime Perrotin's avatar
Maxime Perrotin committed
814
815
def _mantissa_base_exp(primary):
    ''' Generate code for a Real with Mantissa-base-Exponent representation '''
816
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
817
818


Maxime Perrotin's avatar
Maxime Perrotin committed
819
@expression.register(ogAST.PrimIfThenElse)
dbarbera's avatar
dbarbera committed
820
def _if_then_else(ifthen):
dbarbera's avatar
dbarbera committed
821
    ''' Generate the code for ternary operator '''
822
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
823
824


Maxime Perrotin's avatar
Maxime Perrotin committed
825
@expression.register(ogAST.PrimSequence)
Maxime Perrotin's avatar
Maxime Perrotin committed
826
def _sequence(seq):
dbarbera's avatar
dbarbera committed
827
    ''' Generate the code for an ASN.1 SEQUENCE '''
dbarbera's avatar
dbarbera committed
828
829
830
831
832
833
834
835
836
837
838
    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
839
840


Maxime Perrotin's avatar
Maxime Perrotin committed
841
@expression.register(ogAST.PrimSequenceOf)
Maxime Perrotin's avatar
Maxime Perrotin committed
842
def _sequence_of(seqof):
dbarbera's avatar
dbarbera committed
843
    ''' Generate the code for an ASN.1 SEQUENCE OF '''
844
    ty = _generate_type(seqof.exprType)
845
846
847
    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])
848
849

    for idx, expr in enumerate(seqof.value):
850
        idx_cons = core.Constant.int(g.i32, idx)
851
        expr_val = expression(expr)
852
853
        pos_ptr = g.builder.gep(array_ptr, [zero_cons, idx_cons])
        g.builder.store(expr_val, pos_ptr)
854
855

    return struct_ptr
Maxime Perrotin's avatar
Maxime Perrotin committed
856
857


Maxime Perrotin's avatar
Maxime Perrotin committed
858
@expression.register(ogAST.PrimChoiceItem)
Maxime Perrotin's avatar
Maxime Perrotin committed
859
def _choiceitem(choice):
dbarbera's avatar
dbarbera committed
860
    ''' Generate the code for a CHOICE expression '''
861
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
862
863
864
865


@generate.register(ogAST.Decision)
def _decision(dec):
dbarbera's avatar
dbarbera committed
866
    ''' Generate the code for a decision '''
867
    func = g.builder.basic_block.function
dbarbera's avatar
dbarbera committed
868
869
870
871

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

872
    g.builder.branch(ans_cond_blocks[0])
dbarbera's avatar
dbarbera committed
873
874
875
876
877

    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')
878
        g.builder.position_at_end(ans_cond_block)
dbarbera's avatar
dbarbera committed
879
880

        if ans.kind == 'constant':
dbarbera's avatar
flake8    
dbarbera committed
881
            next_block = ans_cond_blocks[idx + 1] if idx < len(ans_cond_blocks) - 1 else end_block
dbarbera's avatar
dbarbera committed
882
883
884
885
886
887

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

888
889
890
            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
891
892
        elif ans.kind == 'else':
            if ans.transition:
893
                g.builder.branch(ans_tr_block)
dbarbera's avatar
dbarbera committed
894
            else:
895
                g.builder.branch(end_block)
dbarbera's avatar
dbarbera committed
896
897
898
899
        else:
            raise NotImplementedError

        if ans.transition:
900
            g.builder.position_at_end(ans_tr_block)
dbarbera's avatar
dbarbera committed
901
            generate(ans.transition)
dbarbera's avatar
dbarbera committed
902
903
            if not g.builder.basic_block.terminator:
                g.builder.branch(end_block)
dbarbera's avatar
dbarbera committed
904

905
    g.builder.position_at_end(end_block)
Maxime Perrotin's avatar
Maxime Perrotin committed
906
907
908


@generate.register(ogAST.Label)
dbarbera's avatar
dbarbera committed
909
910
911
912
def _label(label):
    ''' Generate the code for a Label '''
    label_block = g.scope.label(str(label.inputString))
    g.builder.branch(label_block)
Maxime Perrotin's avatar
Maxime Perrotin committed
913
914
915
916


@generate.register(ogAST.Transition)
def _transition(tr):
dbarbera's avatar
dbarbera committed
917
    ''' Generate the code for a transition '''
918
919
920
921
922
923
    for action in tr.actions:
        generate(action)
        if isinstance(action, ogAST.Label):
            return
    if tr.terminator:
        _generate_terminator(tr.terminator)
924
925