LlvmGenerator.py 30.9 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
70
            self.module, core.INTR_MEMCPY,
            [self.i8_ptr, self.i8_ptr, self.i64]
        )
Maxime Perrotin's avatar
Maxime Perrotin committed
71

dbarbera's avatar
dbarbera committed
72

73
74
class StructType():
    def __init__(self, name, field_names, field_types):
dbarbera's avatar
dbarbera committed
75
        self.name = name
76
77
78
79
80
        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
81
82


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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
98
            print name
99
100
            raise NameError

dbarbera's avatar
dbarbera committed
101

Maxime Perrotin's avatar
Maxime Perrotin committed
102
103
104
105
@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
106

dbarbera's avatar
dbarbera committed
107

Maxime Perrotin's avatar
Maxime Perrotin committed
108
109
110
# Processing of the AST
@generate.register(ogAST.Process)
def _process(process):
dbarbera's avatar
dbarbera committed
111
    ''' Generate LLVM IR code '''
dbarbera's avatar
dbarbera committed
112
113
    process_name = str(process.processName)
    LOG.info('Generating LLVM IR code for process ' + process_name)
114

115
116
    global g
    g = GlobalState(process)
117

dbarbera's avatar
dbarbera committed
118
119
120
121
122
123
    # 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
124

125
126
127
    # Initialize states enum
    for name in process.mapping.iterkeys():
        if not name.endswith('START'):
128
129
            cons = core.Constant.int(g.i32, len(g.states))
            g.states[name] = cons
130

131
    # Generate state var
132
133
    state_cons = g.module.add_global_variable(g.i32, 'state')
    state_cons.initializer = core.Constant.int(g.i32, -1)
134
    g.scope.define('state', state_cons)
135

136
137
138
    # Generare process-level vars
    for name, (ty, expr) in process.variables.viewitems():
        var_ty = _generate_type(ty)
139
        global_var = g.module.add_global_variable(var_ty, str(name))
140
        global_var.initializer = core.Constant.null(var_ty)
141
        g.scope.define(str(name).lower(), global_var)
142

dbarbera's avatar
dbarbera committed
143
144
145
146
147
148
149
150
    # Declare timer set/reset functions
    for timer in process.timers:
        func_name = '%s_RI_set_%s' % (process_name, str(timer))
        # TODO: Should be uint?
        decl_func(func_name, g.void, [g.i32_ptr])
        func_name = '%s_RI_reset_%s' % (process_name, str(timer))
        decl_func(func_name, g.void, [])

151
    # Declare output signal functions
dbarbera's avatar
dbarbera committed
152
    for signal in process.output_signals:
153
154
155
156
        if 'type' in signal:
            param_tys = [core.Type.pointer(_generate_type(signal['type']))]
        else:
            param_tys = []
157
        decl_func(str(signal['name']), g.void, param_tys)
dbarbera's avatar
dbarbera committed
158

159
    # Declare external procedures functions
dbarbera's avatar
dbarbera committed
160
161
    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]
162
        decl_func(str(proc.inputString), g.void, param_tys)
dbarbera's avatar
dbarbera committed
163

164
165
    # Generate internal procedures
    for proc in process.content.inner_procedures:
166
        generate(proc)
167

168
    # Generate process functions
169
    _generate_runtr_func(process)
170
    _generate_startup_func(process)
171

172
173
174
175
    # Generate input signals
    for signal in process.input_signals:
        _generate_input_signal(signal, mapping[signal['name']])

dbarbera's avatar
dbarbera committed
176
177
    g.module.verify()

dbarbera's avatar
dbarbera committed
178
    with open(g.name + '.ll', 'w') as ll_file:
dbarbera's avatar
dbarbera committed
179
        ll_file.write(str(g.module))
180
181
182


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

186
187
    _push_scope()

188
189
190
191
192
    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
193
    g.builder = core.Builder.new(entry_block)
194
195

    # entry
dbarbera's avatar
dbarbera committed
196
    id_ptr = g.builder.alloca(g.i32, None, 'id')
197
    g.scope.define('id', id_ptr)
dbarbera's avatar
dbarbera committed
198
199
    g.builder.store(func.args[0], id_ptr)
    g.builder.branch(cond_block)
200
201

    # cond
dbarbera's avatar
dbarbera committed
202
    g.builder.position_at_end(cond_block)
203
    no_tr_cons = core.Constant.int(g.i32, -1)
204
205
    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
206
    g.builder.cbranch(cond_val, body_block, exit_block)
207
208

    # body
dbarbera's avatar
dbarbera committed
209
210
    g.builder.position_at_end(body_block)
    switch = g.builder.switch(func.args[0], exit_block)
211
212
213
214

    # transitions
    for idx, tr in enumerate(process.transitions):
        tr_block = func.append_basic_block('tr%d' % idx)
215
        const = core.Constant.int(g.i32, idx)
216
        switch.add_case(const, tr_block)
dbarbera's avatar
dbarbera committed
217
        g.builder.position_at_end(tr_block)
218
        generate(tr)
dbarbera's avatar
dbarbera committed
219
        g.builder.branch(cond_block)
220
221

    # exit
dbarbera's avatar
dbarbera committed
222
223
    g.builder.position_at_end(exit_block)
    g.builder.ret_void()
224

225
226
    _pop_scope()

227
228
229
230
    func.verify()
    return func


231
def _generate_startup_func(process):
dbarbera's avatar
dbarbera committed
232
    ''' Generate code for the startup function '''
233
    func = decl_func(g.name + '_startup', g.void, [])
234

235
236
    _push_scope()

237
    entry_block = func.append_basic_block('entry')
238
    g.builder = core.Builder.new(entry_block)
239

240
241
242
    # Initialize process level variables
    for name, (ty, expr) in process.variables.viewitems():
        if expr:
dbarbera's avatar
dbarbera committed
243
            global_var = g.scope.resolve(str(name))
244
245
            _generate_assign(global_var, expression(expr))

246
247
    g.builder.call(g.funcs['run_transition'], [core.Constant.int(g.i32, 0)])
    g.builder.ret_void()
Maxime Perrotin's avatar
Maxime Perrotin committed
248

249
250
    _pop_scope()

251
252
    func.verify()
    return func
Maxime Perrotin's avatar
Maxime Perrotin committed
253
254


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

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

264
265
    _push_scope()

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

270
    g_state_val = g.builder.load(g.global_scope.resolve('state'))
271
    switch = g.builder.switch(g_state_val, exit_block)
272

273
    for state_name, state_id in g.states.iteritems():
274
275
        state_block = func.append_basic_block('state_%s' % str(state_name))
        switch.add_case(state_id, state_block)
276
        g.builder.position_at_end(state_block)
277
278
279

        # TODO: Nested states

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

289
        g.builder.ret_void()
290

291
292
    g.builder.position_at_end(exit_block)
    g.builder.ret_void()
293

294
295
    _pop_scope()

296
297
298
    func.verify()


Maxime Perrotin's avatar
Maxime Perrotin committed
299
300
301
302
@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
303
304
305
    for out in output.output:
        name = out['outputName'].lower()

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

        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
333
334
335
336


def _generate_write(params):
    ''' Generate the code for the write operator '''
337
    zero = core.Constant.int(g.i32, 0)
338
339
340
    for param in params:
        basic_ty = find_basic_type(param.exprType)
        expr_val = expression(param)
341
342
343
344

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

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


def _generate_writeln(params):
    ''' Generate the code for the writeln operator '''
    _generate_write(params)
370
371

    zero = core.Constant.int(g.i32, 0)
372
    str_cons = _get_string_cons('\n')
373
    str_ptr = g.builder.gep(str_cons, [zero, zero])
dbarbera's avatar
dbarbera committed
374
    g.builder.call(g.funcs['printf'], [str_ptr])
dbarbera's avatar
dbarbera committed
375
376
377
378


def _generate_reset_timer(params):
    ''' Generate the code for the reset timer operator '''
dbarbera's avatar
dbarbera committed
379
380
381
382
383
    timer_id = params[0]
    reset_func_name = '%s_RI_reset_%s' % (g.name, timer_id.value[0])
    reset_func = g.funcs[reset_func_name.lower()]

    g.builder.call(reset_func, [])
dbarbera's avatar
dbarbera committed
384
385
386
387


def _generate_set_timer(params):
    ''' Generate the code for the set timer operator '''
dbarbera's avatar
dbarbera committed
388
389
390
391
392
393
394
395
396
397
398
399
400
    timer_expr, timer_id = params
    set_func_name = '%s_RI_set_%s' % (g.name, timer_id.value[0])
    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
401
402
403
404


@generate.register(ogAST.TaskAssign)
def _task_assign(task):
dbarbera's avatar
dbarbera committed
405
    ''' Generate the code of a list of assignments '''
406
407
    for expr in task.elems:
        expression(expr)
Maxime Perrotin's avatar
Maxime Perrotin committed
408
409
410
411
412


@generate.register(ogAST.TaskInformalText)
def _task_informal_text(task):
    ''' Generate comments for informal text '''
413
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
414
415
416
417


@generate.register(ogAST.TaskForLoop)
def _task_forloop(task):
dbarbera's avatar
dbarbera committed
418
    ''' Generate the code for a for loop '''
dbarbera's avatar
dbarbera committed
419
420
421
422
423
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
    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'''
475
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
476

dbarbera's avatar
dbarbera committed
477

Maxime Perrotin's avatar
Maxime Perrotin committed
478
479
480
481
# ------ expressions --------

@singledispatch
def expression(expr):
dbarbera's avatar
dbarbera committed
482
    ''' Generate the code for Expression-classes '''
Maxime Perrotin's avatar
Maxime Perrotin committed
483
484
485
486
    raise TypeError('Unsupported expression: ' + str(expr))


@expression.register(ogAST.PrimVariable)
Maxime Perrotin's avatar
Maxime Perrotin committed
487
def _primary_variable(prim):
dbarbera's avatar
dbarbera committed
488
    ''' Generate the code for a single variable reference '''
489
    return g.scope.resolve(str(prim.value[0]))
Maxime Perrotin's avatar
Maxime Perrotin committed
490
491


Maxime Perrotin's avatar
Maxime Perrotin committed
492
@expression.register(ogAST.PrimPath)
dbarbera's avatar
dbarbera committed
493
def _prim_path(prim):
dbarbera's avatar
dbarbera committed
494
    ''' Generate the code for an of an element list (path) '''
dbarbera's avatar
dbarbera committed
495

496
    var_ptr = g.scope.resolve(str(prim.value.pop(0)))
dbarbera's avatar
dbarbera committed
497
498

    if not prim.value:
499
        return var_ptr
dbarbera's avatar
dbarbera committed
500
501
502
503
504
505
506
507
508
509
510
511
512

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

    for field_name in prim.value:
        var_ty = var_ptr.type
        if var_ty.kind == core.TYPE_POINTER and var_ty.pointee.kind == core.TYPE_STRUCT:
            struct = g.structs[var_ty.pointee.name]
            field_idx_cons = core.Constant.int(g.i32, struct.idx(field_name))
            field_ptr = g.builder.gep(var_ptr, [zero_cons, field_idx_cons])
            var_ptr = field_ptr
        else:
            raise NotImplementedError

513
    return var_ptr
Maxime Perrotin's avatar
Maxime Perrotin committed
514
515


Maxime Perrotin's avatar
Maxime Perrotin committed
516
517
518
519
520
521
522
523
524
525
526
527
@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
528
529
def _basic(expr):
    ''' Generate the code for an arithmetic of relational expression '''
530
531
    lefttmp = expression(expr.left)
    righttmp = expression(expr.right)
532
533

    # load the value of the expression if it is a pointer
534
    if lefttmp.type.kind == core.TYPE_POINTER:
535
        lefttmp = g.builder.load(lefttmp, 'lefttmp')
536
    if righttmp.type.kind == core.TYPE_POINTER:
dbarbera's avatar
dbarbera committed
537
        righttmp = g.builder.load(righttmp, 'righttmp')
538
539
540
541
542
543

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

    if lefttmp.type.kind == core.TYPE_INTEGER:
        if expr.operand == '+':
544
            return g.builder.add(lefttmp, righttmp, 'addtmp')
545
        elif expr.operand == '-':
546
            return g.builder.sub(lefttmp, righttmp, 'subtmp')
547
        elif expr.operand == '*':
548
            return g.builder.mul(lefttmp, righttmp, 'multmp')
549
        elif expr.operand == '/':
550
            return g.builder.sdiv(lefttmp, righttmp, 'divtmp')
551
        elif expr.operand == 'mod':
552
            # l mod r == (((l rem r) + r) rem r)
553
554
555
            remtmp = g.builder.srem(lefttmp, righttmp)
            addtmp = g.builder.add(remtmp, righttmp)
            return g.builder.srem(addtmp, righttmp, 'modtmp')
556
        elif expr.operand == 'rem':
557
            return g.builder.srem(lefttmp, righttmp, 'remtmp')
558
        elif expr.operand == '<':
559
            return g.builder.icmp(core.ICMP_SLT, lefttmp, righttmp, 'lttmp')
560
        elif expr.operand == '<=':
561
            return g.builder.icmp(core.ICMP_SLE, lefttmp, righttmp, 'letmp')
562
        elif expr.operand == '=':
563
            return g.builder.icmp(core.ICMP_EQ, lefttmp, righttmp, 'eqtmp')
564
        elif expr.operand == '/=':
565
            return g.builder.icmp(core.ICMP_NE, lefttmp, righttmp, 'netmp')
566
        elif expr.operand == '>=':
567
            return g.builder.icmp(core.ICMP_SGE, lefttmp, righttmp, 'getmp')
568
        elif expr.operand == '>':
569
            return g.builder.icmp(core.ICMP_SGT, lefttmp, righttmp, 'gttmp')
570
571
572
573
        else:
            raise NotImplementedError
    elif lefttmp.type.kind == core.TYPE_DOUBLE:
        if expr.operand == '+':
574
            return g.builder.fadd(lefttmp, righttmp, 'addtmp')
575
        elif expr.operand == '-':
576
            return g.builder.fsub(lefttmp, righttmp, 'subtmp')
577
        elif expr.operand == '*':
578
            return g.builder.fmul(lefttmp, righttmp, 'multmp')
579
        elif expr.operand == '/':
580
            return g.builder.fdiv(lefttmp, righttmp, 'divtmp')
581
        elif expr.operand == '<':
582
            return g.builder.fcmp(core.FCMP_OLT, lefttmp, righttmp, 'lttmp')
583
        elif expr.operand == '<=':
584
            return g.builder.fcmp(core.FCMP_OLE, lefttmp, righttmp, 'letmp')
585
        elif expr.operand == '=':
586
            return g.builder.fcmp(core.FCMP_OEQ, lefttmp, righttmp, 'eqtmp')
587
        elif expr.operand == '/=':
588
            return g.builder.fcmp(core.FCMP_ONE, lefttmp, righttmp, 'netmp')
589
        elif expr.operand == '>=':
590
            return g.builder.fcmp(core.FCMP_OGE, lefttmp, righttmp, 'getmp')
591
        elif expr.operand == '>':
592
            return g.builder.fcmp(core.FCMP_OGT, lefttmp, righttmp, 'gttmp')
593
594
        else:
            raise NotImplementedError
595
    else:
596
        raise NotImplementedError
597

Maxime Perrotin's avatar
Maxime Perrotin committed
598

599
600
@expression.register(ogAST.ExprAssign)
def _assign(expr):
dbarbera's avatar
dbarbera committed
601
    ''' Generate the code for an assign expression '''
602
603
    left = expression(expr.left)
    right = expression(expr.right)
604

605
606
    _generate_assign(left, right)
    return left
607

608
609
610
611
612

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
613
    if left.type.pointee.kind == core.TYPE_STRUCT:
614
615
        size = core.Constant.sizeof(left.type.pointee)
        align = core.Constant.int(g.i32, 0)
616
        volatile = core.Constant.int(g.i1, 0)
617

618
619
        right_ptr = g.builder.bitcast(right, g.i8_ptr)
        left_ptr = g.builder.bitcast(left, g.i8_ptr)
620

dbarbera's avatar
dbarbera committed
621
        g.builder.call(g.funcs['memcpy'], [left_ptr, right_ptr, size, align, volatile])
622
    else:
623
624
        if right.type.kind == core.TYPE_POINTER:
            right = g.builder.load(right)
625
        g.builder.store(right, left)
dbarbera's avatar
dbarbera committed
626

Maxime Perrotin's avatar
Maxime Perrotin committed
627

Maxime Perrotin's avatar
Maxime Perrotin committed
628
629
630
@expression.register(ogAST.ExprOr)
@expression.register(ogAST.ExprAnd)
@expression.register(ogAST.ExprXor)
dbarbera's avatar
dbarbera committed
631
632
def _logical(expr):
    ''' Generate the code for a logical expression '''
dbarbera's avatar
dbarbera committed
633
634
635
636
637
638
639
640
641
    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:
642
        lefttmp = g.builder.load(lefttmp, 'lefttmp')
dbarbera's avatar
dbarbera committed
643
    if righttmp.type.kind == core.TYPE_POINTER:
dbarbera's avatar
dbarbera committed
644
        righttmp = g.builder.load(righttmp, 'righttmp')
dbarbera's avatar
dbarbera committed
645

dbarbera's avatar
dbarbera committed
646
647
648
    if expr.operand == 'and':
        return g.builder.and_(lefttmp, righttmp, 'andtmp')
    elif expr.operand == 'or':
649
        return g.builder.or_(lefttmp, righttmp, 'ortmp')
dbarbera's avatar
dbarbera committed
650
    else:
651
        return g.builder.xor(lefttmp, righttmp, 'xortmp')
dbarbera's avatar
dbarbera committed
652

Maxime Perrotin's avatar
Maxime Perrotin committed
653

Maxime Perrotin's avatar
Maxime Perrotin committed
654
@expression.register(ogAST.ExprAppend)
Maxime Perrotin's avatar
Maxime Perrotin committed
655
656
def _append(expr):
    ''' Generate code for the APPEND construct: a // b '''
657
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
658
659


Maxime Perrotin's avatar
Maxime Perrotin committed
660
@expression.register(ogAST.ExprIn)
Maxime Perrotin's avatar
Maxime Perrotin committed
661
def _expr_in(expr):
dbarbera's avatar
dbarbera committed
662
    ''' Generate the code for an in expression '''
663
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
664
665


Maxime Perrotin's avatar
Maxime Perrotin committed
666
@expression.register(ogAST.PrimEnumeratedValue)
Maxime Perrotin's avatar
Maxime Perrotin committed
667
668
def _enumerated_value(primary):
    ''' Generate code for an enumerated value '''
dbarbera's avatar
dbarbera committed
669
670
671
    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
672
673


Maxime Perrotin's avatar
Maxime Perrotin committed
674
@expression.register(ogAST.PrimChoiceDeterminant)
Maxime Perrotin's avatar
Maxime Perrotin committed
675
676
def _choice_determinant(primary):
    ''' Generate code for a choice determinant (enumerated) '''
677
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
678
679


Maxime Perrotin's avatar
Maxime Perrotin committed
680
@expression.register(ogAST.PrimInteger)
681
682
def _integer(primary):
    ''' Generate code for a raw integer value  '''
683
    return core.Constant.int(g.i32, primary.value[0])
684
685


Maxime Perrotin's avatar
Maxime Perrotin committed
686
@expression.register(ogAST.PrimReal)
687
688
def _real(primary):
    ''' Generate code for a raw real value  '''
689
    return core.Constant.real(g.double, primary.value[0])
690
691


Maxime Perrotin's avatar
Maxime Perrotin committed
692
@expression.register(ogAST.PrimBoolean)
693
694
def _boolean(primary):
    ''' Generate code for a raw boolean value  '''
dbarbera's avatar
dbarbera committed
695
    if primary.value[0].lower() == 'true':
696
        return core.Constant.int(g.i1, 1)
dbarbera's avatar
dbarbera committed
697
    else:
698
        return core.Constant.int(g.i1, 0)
Maxime Perrotin's avatar
Maxime Perrotin committed
699
700


Maxime Perrotin's avatar
Maxime Perrotin committed
701
@expression.register(ogAST.PrimEmptyString)
Maxime Perrotin's avatar
Maxime Perrotin committed
702
703
def _empty_string(primary):
    ''' Generate code for an empty SEQUENCE OF: {} '''
704
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
705
706


Maxime Perrotin's avatar
Maxime Perrotin committed
707
@expression.register(ogAST.PrimStringLiteral)
Maxime Perrotin's avatar
Maxime Perrotin committed
708
709
def _string_literal(primary):
    ''' Generate code for a string (Octet String) '''
dbarbera's avatar
dbarbera committed
710
    return _get_string_cons(str(primary.value[1:-1]))
Maxime Perrotin's avatar
Maxime Perrotin committed
711
712


Maxime Perrotin's avatar
Maxime Perrotin committed
713
@expression.register(ogAST.PrimConstant)
Maxime Perrotin's avatar
Maxime Perrotin committed
714
715
def _constant(primary):
    ''' Generate code for a reference to an ASN.1 constant '''
716
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
717
718


Maxime Perrotin's avatar
Maxime Perrotin committed
719
@expression.register(ogAST.PrimMantissaBaseExp)
Maxime Perrotin's avatar
Maxime Perrotin committed
720
721
def _mantissa_base_exp(primary):
    ''' Generate code for a Real with Mantissa-base-Exponent representation '''
722
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
723
724


Maxime Perrotin's avatar
Maxime Perrotin committed
725
@expression.register(ogAST.PrimIfThenElse)
dbarbera's avatar
dbarbera committed
726
def _if_then_else(ifthen):
dbarbera's avatar
dbarbera committed
727
    ''' Generate the code for ternary operator '''
728
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
729
730


Maxime Perrotin's avatar
Maxime Perrotin committed
731
@expression.register(ogAST.PrimSequence)
Maxime Perrotin's avatar
Maxime Perrotin committed
732
def _sequence(seq):
dbarbera's avatar
dbarbera committed
733
    ''' Generate the code for an ASN.1 SEQUENCE '''
dbarbera's avatar
dbarbera committed
734
735
736
737
738
739
740
741
742
743
744
    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
745
746


Maxime Perrotin's avatar
Maxime Perrotin committed
747
@expression.register(ogAST.PrimSequenceOf)
Maxime Perrotin's avatar
Maxime Perrotin committed
748
def _sequence_of(seqof):
dbarbera's avatar
dbarbera committed
749
    ''' Generate the code for an ASN.1 SEQUENCE OF '''
750
    ty = _generate_type(seqof.exprType)
751
752
753
    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])
754
755

    for idx, expr in enumerate(seqof.value):
756
        idx_cons = core.Constant.int(g.i32, idx)
757
        expr_val = expression(expr)
758
759
        pos_ptr = g.builder.gep(array_ptr, [zero_cons, idx_cons])
        g.builder.store(expr_val, pos_ptr)
760
761

    return struct_ptr
Maxime Perrotin's avatar
Maxime Perrotin committed
762
763


Maxime Perrotin's avatar
Maxime Perrotin committed
764
@expression.register(ogAST.PrimChoiceItem)
Maxime Perrotin's avatar
Maxime Perrotin committed
765
def _choiceitem(choice):
dbarbera's avatar
dbarbera committed
766
    ''' Generate the code for a CHOICE expression '''
767
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
768
769
770
771


@generate.register(ogAST.Decision)
def _decision(dec):
dbarbera's avatar
dbarbera committed
772
    ''' Generate the code for a decision '''
773
    func = g.builder.basic_block.function
dbarbera's avatar
dbarbera committed
774
775
776
777

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

778
    g.builder.branch(ans_cond_blocks[0])
dbarbera's avatar
dbarbera committed
779
780
781
782
783

    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')
784
        g.builder.position_at_end(ans_cond_block)
dbarbera's avatar
dbarbera committed
785
786

        if ans.kind == 'constant':
dbarbera's avatar
dbarbera committed
787
            next_block = ans_cond_blocks[idx+1] if idx < len(ans_cond_blocks)-1 else end_block
dbarbera's avatar
dbarbera committed
788
789
790
791
792
793

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

794
795
796
            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
797
798
        elif ans.kind == 'else':
            if ans.transition:
799
                g.builder.branch(ans_tr_block)
dbarbera's avatar
dbarbera committed
800
            else:
801
                g.builder.branch(end_block)
dbarbera's avatar
dbarbera committed
802
803
804
805
        else:
            raise NotImplementedError

        if ans.transition:
806
            g.builder.position_at_end(ans_tr_block)
dbarbera's avatar
dbarbera committed
807
            generate(ans.transition)
808
            g.builder.branch(end_block)
dbarbera's avatar
dbarbera committed
809

810
    g.builder.position_at_end(end_block)
Maxime Perrotin's avatar
Maxime Perrotin committed
811
812
813
814


@generate.register(ogAST.Label)
def _label(tr):
dbarbera's avatar
dbarbera committed
815
    ''' TGenerate the code for a Label '''
816
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
817
818
819
820


@generate.register(ogAST.Transition)
def _transition(tr):
dbarbera's avatar
dbarbera committed
821
    ''' Generate the code for a transition '''
822
823
824
825
826
827
    for action in tr.actions:
        generate(action)
        if isinstance(action, ogAST.Label):
            return
    if tr.terminator:
        _generate_terminator(tr.terminator)
828
829


830
def _generate_terminator(term):
dbarbera's avatar
dbarbera committed
831
    ''' Generate the code for a transition termiantor '''
832
    if term.label:
833
        raise NotImplementedError
834
835
836
    if term.kind == 'next_state':
        state = term.inputString.lower()
        if state.strip() != '-':
837
            next_id_cons = core.Constant.int(g.i32, term.next_id)
838
            g.builder.store(next_id_cons, g.scope.resolve('id'))
839
            if term.next_id == -1:
840
                state_ptr = g.global_scope.resolve('state')
841
842
                state_id_cons = g.states[state]
                g.builder.store(state_id_cons, state_ptr)
843
        else:
844
            raise NotImplementedError
845
    elif term.kind == 'join':
846
        raise NotImplementedError
847
    elif term.kind == 'stop':
848
        raise NotImplementedError
849
    elif term.kind == 'return':
850
851
852
853
854
855
856
857
        if term.next_id == -1 and term.return_expr:
            g.builder.ret(expression(term.return_expr))
        elif term.next_id == -1:
            g.builder.ret_void()
        else:
            next_id_cons = core.Constant.int(g.i32, term.next_id)
            g.builder.store(next_id_cons, g.scope.resolve('id'))
            g.builder.ret_void()
Maxime Perrotin's avatar
Maxime Perrotin committed
858
859
860
861


@generate.register(ogAST.Floating_label)
def _floating_label(label):
dbarbera's avatar
dbarbera committed
862
    ''' Generate the code for a floating label '''
863
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
864
865
866
867
868


@generate.register(ogAST.Procedure)
def _inner_procedure(proc):
    ''' Generate the code for a procedure '''
869
    param_tys = [core.Type.pointer(_generate_type(p['type'])) for p in proc.fpar]
870
    func = decl_func(str(proc.inputString), g.void, param_tys)
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890

    _push_scope()

    for arg, param in zip(func.args, proc.fpar):
        g.scope.define(str(param['name']), arg)

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

    for name, (ty, expr) in proc.variables.viewitems():
        raise NotImplementedError

    generate(proc.content.start.transition)

    for label in proc.content.floating_labels:
        raise NotImplementedError

    _pop_scope()

    func.verify()
dbarbera's avatar
dbarbera committed
891
892
893


def _generate_type(ty):
894
    ''' Generate the equivalent LLVM type of a ASN.1 type '''
dbarbera's avatar
dbarbera committed
895
896
    basic_ty = find_basic_type(ty)
    if basic_ty.kind == 'IntegerType':
897
        return g.i32
dbarbera's avatar
dbarbera committed
898
    elif basic_ty.kind == 'BooleanType':
899
        return g.i1
dbarbera's avatar
dbarbera committed
900
    elif basic_ty.kind == 'RealType':
901
        return g.double
902
    elif basic_ty.kind == 'SequenceOfType':