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

"""
    OpenGEODE - A tiny SDL Editor for TASTE

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

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

    Copyright (c) 2012-2013 European Space Agency

    Designed and implemented by Maxime Perrotin

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

import logging
21

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

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

LOG = logging.getLogger(__name__)

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

Maxime Perrotin's avatar
Maxime Perrotin committed
32

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


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

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

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

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

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

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

dbarbera's avatar
dbarbera committed
79

80
81
class StructType():
    def __init__(self, name, field_names, field_types):
dbarbera's avatar
dbarbera committed
82
        self.name = name
83
84
85
86
87
        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
88
89


90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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
105
            print name
106
107
            raise NameError

dbarbera's avatar
dbarbera committed
108

Maxime Perrotin's avatar
Maxime Perrotin committed
109
110
111
112
@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
113

dbarbera's avatar
dbarbera committed
114

Maxime Perrotin's avatar
Maxime Perrotin committed
115
116
117
# Processing of the AST
@generate.register(ogAST.Process)
def _process(process):
dbarbera's avatar
dbarbera committed
118
    ''' Generate LLVM IR code '''
dbarbera's avatar
dbarbera committed
119
120
    process_name = str(process.processName)
    LOG.info('Generating LLVM IR code for process ' + process_name)
121

122
123
    global g
    g = GlobalState(process)
124

dbarbera's avatar
dbarbera committed
125
126
127
128
129
130
    # 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
131

132
133
134
    # Initialize states enum
    for name in process.mapping.iterkeys():
        if not name.endswith('START'):
135
136
            cons = core.Constant.int(g.i32, len(g.states))
            g.states[name] = cons
137

138
    # Generate state var
139
140
    state_cons = g.module.add_global_variable(g.i32, 'state')
    state_cons.initializer = core.Constant.int(g.i32, -1)
141
    g.scope.define('state', state_cons)
142

143
144
145
    # Generare process-level vars
    for name, (ty, expr) in process.variables.viewitems():
        var_ty = _generate_type(ty)
146
        global_var = g.module.add_global_variable(var_ty, str(name))
147
        global_var.initializer = core.Constant.null(var_ty)
148
        g.scope.define(str(name).lower(), global_var)
149

dbarbera's avatar
dbarbera committed
150
151
152
    # Declare timer set/reset functions
    for timer in process.timers:
        # TODO: Should be uint?
153
154
        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
155

156
    # Declare output signal functions
dbarbera's avatar
dbarbera committed
157
    for signal in process.output_signals:
158
159
160
161
        if 'type' in signal:
            param_tys = [core.Type.pointer(_generate_type(signal['type']))]
        else:
            param_tys = []
162
        decl_func(str(signal['name']), g.void, param_tys, True)
dbarbera's avatar
dbarbera committed
163

164
    # Declare external procedures functions
dbarbera's avatar
dbarbera committed
165
166
    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]
167
        decl_func(str(proc.inputString), g.void, param_tys, True)
dbarbera's avatar
dbarbera committed
168

169
170
    # Generate internal procedures
    for proc in process.content.inner_procedures:
171
        generate(proc)
172

173
    # Generate process functions
174
    _generate_runtr_func(process)
175
    _generate_startup_func(process)
176

177
178
179
180
    # Generate input signals
    for signal in process.input_signals:
        _generate_input_signal(signal, mapping[signal['name']])

dbarbera's avatar
dbarbera committed
181
182
    g.module.verify()

dbarbera's avatar
dbarbera committed
183
    with open(g.name + '.ll', 'w') as ll_file:
dbarbera's avatar
dbarbera committed
184
        ll_file.write(str(g.module))
185
186
187


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

191
192
    _push_scope()

193
194
195
196
197
    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
198
    g.builder = core.Builder.new(entry_block)
199
200

    # entry
dbarbera's avatar
dbarbera committed
201
    id_ptr = g.builder.alloca(g.i32, None, 'id')
202
    g.scope.define('id', id_ptr)
dbarbera's avatar
dbarbera committed
203
204
    g.builder.store(func.args[0], id_ptr)
    g.builder.branch(cond_block)
205
206

    # cond
dbarbera's avatar
dbarbera committed
207
    g.builder.position_at_end(cond_block)
208
    no_tr_cons = core.Constant.int(g.i32, -1)
209
210
    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
211
    g.builder.cbranch(cond_val, body_block, exit_block)
212
213

    # body
dbarbera's avatar
dbarbera committed
214
215
    g.builder.position_at_end(body_block)
    switch = g.builder.switch(func.args[0], exit_block)
216
217
218
219

    # transitions
    for idx, tr in enumerate(process.transitions):
        tr_block = func.append_basic_block('tr%d' % idx)
220
        const = core.Constant.int(g.i32, idx)
221
        switch.add_case(const, tr_block)
dbarbera's avatar
dbarbera committed
222
        g.builder.position_at_end(tr_block)
223
        generate(tr)
dbarbera's avatar
dbarbera committed
224
        g.builder.branch(cond_block)
225
226

    # exit
dbarbera's avatar
dbarbera committed
227
228
    g.builder.position_at_end(exit_block)
    g.builder.ret_void()
229

230
231
    _pop_scope()

232
233
234
235
    func.verify()
    return func


236
def _generate_startup_func(process):
dbarbera's avatar
dbarbera committed
237
    ''' Generate code for the startup function '''
238
    func = decl_func(g.name + '_startup', g.void, [])
239

240
241
    _push_scope()

242
    entry_block = func.append_basic_block('entry')
243
    g.builder = core.Builder.new(entry_block)
244

245
246
247
    # Initialize process level variables
    for name, (ty, expr) in process.variables.viewitems():
        if expr:
dbarbera's avatar
dbarbera committed
248
            global_var = g.scope.resolve(str(name))
249
250
            _generate_assign(global_var, expression(expr))

251
252
    g.builder.call(g.funcs['run_transition'], [core.Constant.int(g.i32, 0)])
    g.builder.ret_void()
Maxime Perrotin's avatar
Maxime Perrotin committed
253

254
255
    _pop_scope()

256
257
    func.verify()
    return func
Maxime Perrotin's avatar
Maxime Perrotin committed
258
259


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

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

269
270
    _push_scope()

271
272
    entry_block = func.append_basic_block('entry')
    exit_block = func.append_basic_block('exit')
273
    g.builder = core.Builder.new(entry_block)
274

275
    g_state_val = g.builder.load(g.global_scope.resolve('state'))
276
    switch = g.builder.switch(g_state_val, exit_block)
277

278
    for state_name, state_id in g.states.iteritems():
279
280
        state_block = func.append_basic_block('state_%s' % str(state_name))
        switch.add_case(state_id, state_block)
281
        g.builder.position_at_end(state_block)
282
283
284

        # TODO: Nested states

285
286
287
        input = inputs.get(state_name)
        if input:
            for var_name in input.parameters:
288
                var_val = g.scope.resolve(str(var_name))
289
290
                _generate_assign(var_val, func.args[0])
            if input.transition:
291
                id_val = core.Constant.int(g.i32, input.transition_id)
292
                g.builder.call(g.funcs['run_transition'], [id_val])
293

294
        g.builder.ret_void()
295

296
297
    g.builder.position_at_end(exit_block)
    g.builder.ret_void()
298

299
300
    _pop_scope()

301
302
303
    func.verify()


Maxime Perrotin's avatar
Maxime Perrotin committed
304
305
306
307
@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
308
309
310
    for out in output.output:
        name = out['outputName'].lower()

311
        if name == 'write':
dbarbera's avatar
dbarbera committed
312
313
            _generate_write(out['params'])
            continue
314
315
316
        elif name == 'writeln':
            _generate_writeln(out['params'])
            continue
dbarbera's avatar
dbarbera committed
317
318
319
320
321
322
323
        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
324
        func = g.funcs[str(name).lower()]
325
326
327
328
329
330
331
332
333
334
335
336
337

        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
338
339
340
341


def _generate_write(params):
    ''' Generate the code for the write operator '''
342
    zero = core.Constant.int(g.i32, 0)
343
344
345
    for param in params:
        basic_ty = find_basic_type(param.exprType)
        expr_val = expression(param)
346
347
348
349

        if basic_ty.kind != 'StringType' and expr_val.type.kind == core.TYPE_POINTER:
            expr_val = g.builder.load(expr_val)

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


def _generate_writeln(params):
    ''' Generate the code for the writeln operator '''
    _generate_write(params)
375
376

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


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

    g.builder.call(reset_func, [])
dbarbera's avatar
dbarbera committed
389
390
391
392


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

    expr_val = expression(timer_expr)

    if type(timer_expr) in [ogAST.PrimPath, ogAST.PrimVariable]:
        expr_val = g.builder.load(expr_val)

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

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


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


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


@generate.register(ogAST.TaskForLoop)
def _task_forloop(task):
dbarbera's avatar
dbarbera committed
423
    ''' Generate the code for a for loop '''
dbarbera's avatar
dbarbera committed
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
    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'])
        if type(loop['range']['start']) in [ogAST.PrimPath, ogAST.PrimVariable]:
            start_val = g.builder.load(start_val)
        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'])
    if type(loop['range']['stop']) in [ogAST.PrimPath, ogAST.PrimVariable]:
        stop_val = g.builder.load(stop_val)
    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'''
480
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
481

dbarbera's avatar
dbarbera committed
482

Maxime Perrotin's avatar
Maxime Perrotin committed
483
484
485
486
# ------ expressions --------

@singledispatch
def expression(expr):
dbarbera's avatar
dbarbera committed
487
    ''' Generate the code for Expression-classes '''
Maxime Perrotin's avatar
Maxime Perrotin committed
488
489
490
491
    raise TypeError('Unsupported expression: ' + str(expr))


@expression.register(ogAST.PrimVariable)
Maxime Perrotin's avatar
Maxime Perrotin committed
492
def _primary_variable(prim):
dbarbera's avatar
dbarbera committed
493
    ''' Generate the code for a single variable reference '''
494
    return g.scope.resolve(str(prim.value[0]))
Maxime Perrotin's avatar
Maxime Perrotin committed
495
496


Maxime Perrotin's avatar
Maxime Perrotin committed
497
@expression.register(ogAST.PrimPath)
dbarbera's avatar
dbarbera committed
498
def _prim_path(prim):
dbarbera's avatar
dbarbera committed
499
    ''' Generate the code for an of an element list (path) '''
dbarbera's avatar
dbarbera committed
500

501
502
503
504
505
506
507
508
509
510
511
512
513
514
    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'])

    return generate_accessor(prim.value)
dbarbera's avatar
dbarbera committed
515

516
517
518
519
520
521

def generate_accessor(id_names):
    var_name = id_names.pop(0).lower()
    var_ptr = g.scope.resolve(str(var_name))

    if not id_names:
522
        return var_ptr
dbarbera's avatar
dbarbera committed
523
524
525

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

526
    for field_name in id_names:
dbarbera's avatar
dbarbera committed
527
        var_ty = var_ptr.type
528
529
530
531
        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
dbarbera's avatar
dbarbera committed
532

533
    return var_ptr
Maxime Perrotin's avatar
Maxime Perrotin committed
534
535


536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
def generate_length(params):
    raise NotImplementedError


def generate_present(params):
    raise NotImplementedError


def generate_abs(params):
    raise NotImplementedError


def generate_fix(params):
    raise NotImplementedError


def generate_float(params):
    raise NotImplementedError


def generate_power(params):
    left_val = expression(params[0])
    if type(params[0]) in [ogAST.PrimPath, ogAST.PrimVariable]:
        left_val = g.builder.load(left_val)

    right_val = expression(params[1])
    if type(params[1]) in [ogAST.PrimPath, ogAST.PrimVariable]:
        right_val = g.builder.load(right_val)

    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
573
574
575
576
577
578
579
580
581
582
583
584
@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
585
586
def _basic(expr):
    ''' Generate the code for an arithmetic of relational expression '''
587
588
    lefttmp = expression(expr.left)
    righttmp = expression(expr.right)
589
590

    # load the value of the expression if it is a pointer
591
    if lefttmp.type.kind == core.TYPE_POINTER:
592
        lefttmp = g.builder.load(lefttmp, 'lefttmp')
593
    if righttmp.type.kind == core.TYPE_POINTER:
dbarbera's avatar
dbarbera committed
594
        righttmp = g.builder.load(righttmp, 'righttmp')
595
596
597
598
599
600

    if lefttmp.type.kind != righttmp.type.kind:
        raise NotImplementedError

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

Maxime Perrotin's avatar
Maxime Perrotin committed
655

656
657
@expression.register(ogAST.ExprAssign)
def _assign(expr):
dbarbera's avatar
dbarbera committed
658
    ''' Generate the code for an assign expression '''
659
660
    left = expression(expr.left)
    right = expression(expr.right)
661

662
663
    _generate_assign(left, right)
    return left
664

665
666
667
668
669

def _generate_assign(left, right):
    ''' Generate code for an assign from two LLVM values'''
    # This is extracted as an standalone function because is used by
    # multiple generation rules
670
    if left.type.pointee.kind == core.TYPE_STRUCT:
671
672
        size = core.Constant.sizeof(left.type.pointee)
        align = core.Constant.int(g.i32, 0)
673
        volatile = core.Constant.int(g.i1, 0)
674

675
676
        right_ptr = g.builder.bitcast(right, g.i8_ptr)
        left_ptr = g.builder.bitcast(left, g.i8_ptr)
677

dbarbera's avatar
dbarbera committed
678
        g.builder.call(g.funcs['memcpy'], [left_ptr, right_ptr, size, align, volatile])
679
    else:
680
681
        if right.type.kind == core.TYPE_POINTER:
            right = g.builder.load(right)
682
        g.builder.store(right, left)
dbarbera's avatar
dbarbera committed
683

Maxime Perrotin's avatar
Maxime Perrotin committed
684

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

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

    # load the value of the expression if it is a pointer
    if lefttmp.type.kind == core.TYPE_POINTER:
699
        lefttmp = g.builder.load(lefttmp, 'lefttmp')
dbarbera's avatar
dbarbera committed
700
    if righttmp.type.kind == core.TYPE_POINTER:
dbarbera's avatar
dbarbera committed
701
        righttmp = g.builder.load(righttmp, 'righttmp')
dbarbera's avatar
dbarbera committed
702

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':
907
908
909
910
911
912
913
914
        if term.next_id == -1 and term.return_expr:
            g.builder.ret(expression(term.return_expr))
        elif term.next_id == -1:
            g.builder.ret_void()
        else:
            next_id_cons = core.Constant.int(g.i32, term.next_id)
            g.builder.store(next_id_cons, g.scope.resolve('id'))
            g.builder.ret_void()