LlvmGenerator.py 28.7 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
98
99
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:
            raise NameError

dbarbera's avatar
dbarbera committed
100

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

dbarbera's avatar
dbarbera committed
106

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

113
114
    global g
    g = GlobalState(process)
115

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

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

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

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

dbarbera's avatar
dbarbera committed
141
142
    # Initialize output signals
    for signal in process.output_signals:
143
144
145
146
        if 'type' in signal:
            param_tys = [core.Type.pointer(_generate_type(signal['type']))]
        else:
            param_tys = []
147
        func_ty = core.Type.function(g.void, param_tys)
dbarbera's avatar
dbarbera committed
148
149
150
        func_name = str(signal['name'])
        func = core.Function.new(g.module, func_ty, func_name)
        g.funcs[func_name.lower()] = func
dbarbera's avatar
dbarbera committed
151
152
153
154

    # Initialize external procedures
    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]
155
        func_ty = core.Type.function(g.void, param_tys)
dbarbera's avatar
dbarbera committed
156
157
158
        func_name = str(proc.inputString)
        func = core.Function.new(g.module, func_ty, func_name)
        g.funcs[func_name.lower()] = func
dbarbera's avatar
dbarbera committed
159

160
161
    # Generate internal procedures
    for proc in process.content.inner_procedures:
162
        generate(proc)
163

164
    # Generate process functions
165
    _generate_runtr_func(process)
166
    _generate_startup_func(process)
167

168
169
170
171
    # Generate input signals
    for signal in process.input_signals:
        _generate_input_signal(signal, mapping[signal['name']])

dbarbera's avatar
dbarbera committed
172
173
    g.module.verify()

dbarbera's avatar
dbarbera committed
174
    with open(g.name  + '.ll', 'w') as ll_file:
dbarbera's avatar
dbarbera committed
175
        ll_file.write(str(g.module))
176
177
178


def _generate_runtr_func(process):
dbarbera's avatar
dbarbera committed
179
    ''' Generate code for the run_transition function '''
180
    func_name = 'run_transition'
181
182
    func_type = core.Type.function(g.void, [g.i32])
    func = core.Function.new(g.module, func_type, func_name)
183
    g.funcs[func_name] = func
184

185
186
    _push_scope()

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

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

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

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

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

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

224
225
    _pop_scope()

226
227
228
229
    func.verify()
    return func


230
def _generate_startup_func(process):
dbarbera's avatar
dbarbera committed
231
    ''' Generate code for the startup function '''
dbarbera's avatar
dbarbera committed
232
    func_name = g.name + '_startup'
233
234
    func_type = core.Type.function(g.void, [])
    func = core.Function.new(g.module, func_type, func_name)
235
    g.funcs[func_name] = func
236

237
238
    _push_scope()

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

242
243
244
    # Initialize process level variables
    for name, (ty, expr) in process.variables.viewitems():
        if expr:
245
            global_var = _resolve(str(name))
246
247
            _generate_assign(global_var, expression(expr))

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

251
252
    _pop_scope()

253
254
    func.verify()
    return func
Maxime Perrotin's avatar
Maxime Perrotin committed
255
256


257
def _generate_input_signal(signal, inputs):
dbarbera's avatar
dbarbera committed
258
    ''' Generate code for an input signal '''
dbarbera's avatar
dbarbera committed
259
    func_name = g.name + "_" + str(signal['name'])
260
261
262
    param_tys = []
    if 'type' in signal:
        param_tys.append(core.Type.pointer(_generate_type(signal['type'])))
263
264
    func_type = core.Type.function(g.void, param_tys)
    func = core.Function.new(g.module, func_type, func_name)
dbarbera's avatar
dbarbera committed
265
    g.funcs[func_name.lower()] = func
266

267
268
    _push_scope()

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

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

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

        # TODO: Nested states

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

292
        g.builder.ret_void()
293

294
295
    g.builder.position_at_end(exit_block)
    g.builder.ret_void()
296

297
298
    _pop_scope()

299
300
301
    func.verify()


Maxime Perrotin's avatar
Maxime Perrotin committed
302
303
304
305
@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 '''
306
    zero = core.Constant.int(g.i32, 0)
dbarbera's avatar
dbarbera committed
307
308
309
    for out in output.output:
        name = out['outputName'].lower()

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

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


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

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

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


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

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


def _generate_reset_timer(params):
    ''' Generate the code for the reset timer operator '''
    raise NotImplementedError


def _generate_set_timer(params):
    ''' Generate the code for the set timer operator '''
388
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
389
390
391
392


@generate.register(ogAST.TaskAssign)
def _task_assign(task):
dbarbera's avatar
dbarbera committed
393
    ''' Generate the code of a list of assignments '''
394
395
    for expr in task.elems:
        expression(expr)
Maxime Perrotin's avatar
Maxime Perrotin committed
396
397
398
399
400


@generate.register(ogAST.TaskInformalText)
def _task_informal_text(task):
    ''' Generate comments for informal text '''
401
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
402
403
404
405


@generate.register(ogAST.TaskForLoop)
def _task_forloop(task):
dbarbera's avatar
dbarbera committed
406
    ''' Generate the code for a for loop '''
407
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
408

dbarbera's avatar
dbarbera committed
409

Maxime Perrotin's avatar
Maxime Perrotin committed
410
411
412
413
# ------ expressions --------

@singledispatch
def expression(expr):
dbarbera's avatar
dbarbera committed
414
    ''' Generate the code for Expression-classes '''
Maxime Perrotin's avatar
Maxime Perrotin committed
415
416
417
418
    raise TypeError('Unsupported expression: ' + str(expr))


@expression.register(ogAST.PrimVariable)
Maxime Perrotin's avatar
Maxime Perrotin committed
419
def _primary_variable(prim):
dbarbera's avatar
dbarbera committed
420
    ''' Generate the code for a single variable reference '''
421
    return g.scope.resolve(str(prim.value[0]))
Maxime Perrotin's avatar
Maxime Perrotin committed
422
423


Maxime Perrotin's avatar
Maxime Perrotin committed
424
@expression.register(ogAST.PrimPath)
dbarbera's avatar
dbarbera committed
425
def _prim_path(prim):
dbarbera's avatar
dbarbera committed
426
    ''' Generate the code for an of an element list (path) '''
dbarbera's avatar
dbarbera committed
427

428
    var_ptr = g.scope.resolve(str(prim.value.pop(0)))
dbarbera's avatar
dbarbera committed
429
430

    if not prim.value:
431
        return var_ptr
dbarbera's avatar
dbarbera committed
432
433
434
435
436
437
438
439
440
441
442
443
444

    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

445
    return var_ptr
Maxime Perrotin's avatar
Maxime Perrotin committed
446
447


Maxime Perrotin's avatar
Maxime Perrotin committed
448
449
450
451
452
453
454
455
456
457
458
459
@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
460
461
def _basic(expr):
    ''' Generate the code for an arithmetic of relational expression '''
462
463
    lefttmp = expression(expr.left)
    righttmp = expression(expr.right)
464
465

    # load the value of the expression if it is a pointer
466
    if lefttmp.type.kind == core.TYPE_POINTER:
467
        lefttmp = g.builder.load(lefttmp, 'lefttmp')
468
    if righttmp.type.kind == core.TYPE_POINTER:
dbarbera's avatar
dbarbera committed
469
        righttmp = g.builder.load(righttmp, 'righttmp')
470
471
472
473
474
475

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

    if lefttmp.type.kind == core.TYPE_INTEGER:
        if expr.operand == '+':
476
            return g.builder.add(lefttmp, righttmp, 'addtmp')
477
        elif expr.operand == '-':
478
            return g.builder.sub(lefttmp, righttmp, 'subtmp')
479
        elif expr.operand == '*':
480
            return g.builder.mul(lefttmp, righttmp, 'multmp')
481
        elif expr.operand == '/':
482
            return g.builder.sdiv(lefttmp, righttmp, 'divtmp')
483
        elif expr.operand == 'mod':
484
            # l mod r == (((l rem r) + r) rem r)
485
486
487
            remtmp = g.builder.srem(lefttmp, righttmp)
            addtmp = g.builder.add(remtmp, righttmp)
            return g.builder.srem(addtmp, righttmp, 'modtmp')
488
        elif expr.operand == 'rem':
489
            return g.builder.srem(lefttmp, righttmp, 'remtmp')
490
        elif expr.operand == '<':
491
            return g.builder.icmp(core.ICMP_SLT, lefttmp, righttmp, 'lttmp')
492
        elif expr.operand == '<=':
493
            return g.builder.icmp(core.ICMP_SLE, lefttmp, righttmp, 'letmp')
494
        elif expr.operand == '=':
495
            return g.builder.icmp(core.ICMP_EQ, lefttmp, righttmp, 'eqtmp')
496
        elif expr.operand == '/=':
497
            return g.builder.icmp(core.ICMP_NE, lefttmp, righttmp, 'netmp')
498
        elif expr.operand == '>=':
499
            return g.builder.icmp(core.ICMP_SGE, lefttmp, righttmp, 'getmp')
500
        elif expr.operand == '>':
501
            return g.builder.icmp(core.ICMP_SGT, lefttmp, righttmp, 'gttmp')
502
503
504
505
        else:
            raise NotImplementedError
    elif lefttmp.type.kind == core.TYPE_DOUBLE:
        if expr.operand == '+':
506
            return g.builder.fadd(lefttmp, righttmp, 'addtmp')
507
        elif expr.operand == '-':
508
            return g.builder.fsub(lefttmp, righttmp, 'subtmp')
509
        elif expr.operand == '*':
510
            return g.builder.fmul(lefttmp, righttmp, 'multmp')
511
        elif expr.operand == '/':
512
            return g.builder.fdiv(lefttmp, righttmp, 'divtmp')
513
        elif expr.operand == '<':
514
            return g.builder.fcmp(core.FCMP_OLT, lefttmp, righttmp, 'lttmp')
515
        elif expr.operand == '<=':
516
            return g.builder.fcmp(core.FCMP_OLE, lefttmp, righttmp, 'letmp')
517
        elif expr.operand == '=':
518
            return g.builder.fcmp(core.FCMP_OEQ, lefttmp, righttmp, 'eqtmp')
519
        elif expr.operand == '/=':
520
            return g.builder.fcmp(core.FCMP_ONE, lefttmp, righttmp, 'netmp')
521
        elif expr.operand == '>=':
522
            return g.builder.fcmp(core.FCMP_OGE, lefttmp, righttmp, 'getmp')
523
        elif expr.operand == '>':
524
            return g.builder.fcmp(core.FCMP_OGT, lefttmp, righttmp, 'gttmp')
525
526
        else:
            raise NotImplementedError
527
    else:
528
        raise NotImplementedError
529

Maxime Perrotin's avatar
Maxime Perrotin committed
530

531
532
@expression.register(ogAST.ExprAssign)
def _assign(expr):
dbarbera's avatar
dbarbera committed
533
    ''' Generate the code for an assign expression '''
534
535
    left = expression(expr.left)
    right = expression(expr.right)
536

537
538
    _generate_assign(left, right)
    return left
539

540
541
542
543
544

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
545
    if left.type.pointee.kind == core.TYPE_STRUCT:
546
547
        size = core.Constant.sizeof(left.type.pointee)
        align = core.Constant.int(g.i32, 0)
548
        volatile = core.Constant.int(g.i1, 0)
549

550
551
        right_ptr = g.builder.bitcast(right, g.i8_ptr)
        left_ptr = g.builder.bitcast(left, g.i8_ptr)
552

dbarbera's avatar
dbarbera committed
553
        g.builder.call(g.funcs['memcpy'], [left_ptr, right_ptr, size, align, volatile])
554
    else:
555
556
        if right.type.kind == core.TYPE_POINTER:
            right = g.builder.load(right)
557
        g.builder.store(right, left)
dbarbera's avatar
dbarbera committed
558

Maxime Perrotin's avatar
Maxime Perrotin committed
559

Maxime Perrotin's avatar
Maxime Perrotin committed
560
561
562
@expression.register(ogAST.ExprOr)
@expression.register(ogAST.ExprAnd)
@expression.register(ogAST.ExprXor)
dbarbera's avatar
dbarbera committed
563
564
def _logical(expr):
    ''' Generate the code for a logical expression '''
dbarbera's avatar
dbarbera committed
565
566
567
568
569
570
571
572
573
    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:
574
        lefttmp = g.builder.load(lefttmp, 'lefttmp')
dbarbera's avatar
dbarbera committed
575
    if righttmp.type.kind == core.TYPE_POINTER:
dbarbera's avatar
dbarbera committed
576
        righttmp = g.builder.load(righttmp, 'righttmp')
dbarbera's avatar
dbarbera committed
577

dbarbera's avatar
dbarbera committed
578
579
580
    if expr.operand == 'and':
        return g.builder.and_(lefttmp, righttmp, 'andtmp')
    elif expr.operand == 'or':
581
        return g.builder.or_(lefttmp, righttmp, 'ortmp')
dbarbera's avatar
dbarbera committed
582
    else:
583
        return g.builder.xor(lefttmp, righttmp, 'xortmp')
dbarbera's avatar
dbarbera committed
584

Maxime Perrotin's avatar
Maxime Perrotin committed
585

Maxime Perrotin's avatar
Maxime Perrotin committed
586
@expression.register(ogAST.ExprAppend)
Maxime Perrotin's avatar
Maxime Perrotin committed
587
588
def _append(expr):
    ''' Generate code for the APPEND construct: a // b '''
589
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
590
591


Maxime Perrotin's avatar
Maxime Perrotin committed
592
@expression.register(ogAST.ExprIn)
Maxime Perrotin's avatar
Maxime Perrotin committed
593
def _expr_in(expr):
dbarbera's avatar
dbarbera committed
594
    ''' Generate the code for an in expression '''
595
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
596
597


Maxime Perrotin's avatar
Maxime Perrotin committed
598
@expression.register(ogAST.PrimEnumeratedValue)
Maxime Perrotin's avatar
Maxime Perrotin committed
599
600
def _enumerated_value(primary):
    ''' Generate code for an enumerated value '''
dbarbera's avatar
dbarbera committed
601
602
603
    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
604
605


Maxime Perrotin's avatar
Maxime Perrotin committed
606
@expression.register(ogAST.PrimChoiceDeterminant)
Maxime Perrotin's avatar
Maxime Perrotin committed
607
608
def _choice_determinant(primary):
    ''' Generate code for a choice determinant (enumerated) '''
609
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
610
611


Maxime Perrotin's avatar
Maxime Perrotin committed
612
@expression.register(ogAST.PrimInteger)
613
614
def _integer(primary):
    ''' Generate code for a raw integer value  '''
615
    return core.Constant.int(g.i32, primary.value[0])
616
617


Maxime Perrotin's avatar
Maxime Perrotin committed
618
@expression.register(ogAST.PrimReal)
619
620
def _real(primary):
    ''' Generate code for a raw real value  '''
621
    return core.Constant.real(g.double, primary.value[0])
622
623


Maxime Perrotin's avatar
Maxime Perrotin committed
624
@expression.register(ogAST.PrimBoolean)
625
626
def _boolean(primary):
    ''' Generate code for a raw boolean value  '''
dbarbera's avatar
dbarbera committed
627
    if primary.value[0].lower() == 'true':
628
        return core.Constant.int(g.i1, 1)
dbarbera's avatar
dbarbera committed
629
    else:
630
        return core.Constant.int(g.i1, 0)
Maxime Perrotin's avatar
Maxime Perrotin committed
631
632


Maxime Perrotin's avatar
Maxime Perrotin committed
633
@expression.register(ogAST.PrimEmptyString)
Maxime Perrotin's avatar
Maxime Perrotin committed
634
635
def _empty_string(primary):
    ''' Generate code for an empty SEQUENCE OF: {} '''
636
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
637
638


Maxime Perrotin's avatar
Maxime Perrotin committed
639
@expression.register(ogAST.PrimStringLiteral)
Maxime Perrotin's avatar
Maxime Perrotin committed
640
641
def _string_literal(primary):
    ''' Generate code for a string (Octet String) '''
dbarbera's avatar
dbarbera committed
642
    return _get_string_cons(str(primary.value[1:-1]))
Maxime Perrotin's avatar
Maxime Perrotin committed
643
644


Maxime Perrotin's avatar
Maxime Perrotin committed
645
@expression.register(ogAST.PrimConstant)
Maxime Perrotin's avatar
Maxime Perrotin committed
646
647
def _constant(primary):
    ''' Generate code for a reference to an ASN.1 constant '''
648
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
649
650


Maxime Perrotin's avatar
Maxime Perrotin committed
651
@expression.register(ogAST.PrimMantissaBaseExp)
Maxime Perrotin's avatar
Maxime Perrotin committed
652
653
def _mantissa_base_exp(primary):
    ''' Generate code for a Real with Mantissa-base-Exponent representation '''
654
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
655
656


Maxime Perrotin's avatar
Maxime Perrotin committed
657
@expression.register(ogAST.PrimIfThenElse)
dbarbera's avatar
dbarbera committed
658
def _if_then_else(ifthen):
dbarbera's avatar
dbarbera committed
659
    ''' Generate the code for ternary operator '''
660
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
661
662


Maxime Perrotin's avatar
Maxime Perrotin committed
663
@expression.register(ogAST.PrimSequence)
Maxime Perrotin's avatar
Maxime Perrotin committed
664
def _sequence(seq):
dbarbera's avatar
dbarbera committed
665
    ''' Generate the code for an ASN.1 SEQUENCE '''
dbarbera's avatar
dbarbera committed
666
667
668
669
670
671
672
673
674
675
676
    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
677
678


Maxime Perrotin's avatar
Maxime Perrotin committed
679
@expression.register(ogAST.PrimSequenceOf)
Maxime Perrotin's avatar
Maxime Perrotin committed
680
def _sequence_of(seqof):
dbarbera's avatar
dbarbera committed
681
    ''' Generate the code for an ASN.1 SEQUENCE OF '''
682
    ty = _generate_type(seqof.exprType)
683
684
685
    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])
686
687

    for idx, expr in enumerate(seqof.value):
688
        idx_cons = core.Constant.int(g.i32, idx)
689
        expr_val = expression(expr)
690
691
        pos_ptr = g.builder.gep(array_ptr, [zero_cons, idx_cons])
        g.builder.store(expr_val, pos_ptr)
692
693

    return struct_ptr
Maxime Perrotin's avatar
Maxime Perrotin committed
694
695


Maxime Perrotin's avatar
Maxime Perrotin committed
696
@expression.register(ogAST.PrimChoiceItem)
Maxime Perrotin's avatar
Maxime Perrotin committed
697
def _choiceitem(choice):
dbarbera's avatar
dbarbera committed
698
    ''' Generate the code for a CHOICE expression '''
699
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
700
701
702
703


@generate.register(ogAST.Decision)
def _decision(dec):
dbarbera's avatar
dbarbera committed
704
    ''' Generate the code for a decision '''
705
    func = g.builder.basic_block.function
dbarbera's avatar
dbarbera committed
706
707
708
709

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

710
    g.builder.branch(ans_cond_blocks[0])
dbarbera's avatar
dbarbera committed
711
712
713
714
715

    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')
716
        g.builder.position_at_end(ans_cond_block)
dbarbera's avatar
dbarbera committed
717
718

        if ans.kind == 'constant':
dbarbera's avatar
dbarbera committed
719
            next_block = ans_cond_blocks[idx+1] if idx < len(ans_cond_blocks)-1 else end_block
dbarbera's avatar
dbarbera committed
720
721
722
723
724
725

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

726
727
728
            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
729
730
        elif ans.kind == 'else':
            if ans.transition:
731
                g.builder.branch(ans_tr_block)
dbarbera's avatar
dbarbera committed
732
            else:
733
                g.builder.branch(end_block)
dbarbera's avatar
dbarbera committed
734
735
736
737
        else:
            raise NotImplementedError

        if ans.transition:
738
            g.builder.position_at_end(ans_tr_block)
dbarbera's avatar
dbarbera committed
739
            generate(ans.transition)
740
            g.builder.branch(end_block)
dbarbera's avatar
dbarbera committed
741

742
    g.builder.position_at_end(end_block)
Maxime Perrotin's avatar
Maxime Perrotin committed
743
744
745
746


@generate.register(ogAST.Label)
def _label(tr):
dbarbera's avatar
dbarbera committed
747
    ''' TGenerate the code for a Label '''
748
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
749
750
751
752


@generate.register(ogAST.Transition)
def _transition(tr):
dbarbera's avatar
dbarbera committed
753
    ''' Generate the code for a transition '''
754
755
756
757
758
759
    for action in tr.actions:
        generate(action)
        if isinstance(action, ogAST.Label):
            return
    if tr.terminator:
        _generate_terminator(tr.terminator)
760
761


762
def _generate_terminator(term):
dbarbera's avatar
dbarbera committed
763
    ''' Generate the code for a transition termiantor '''
764
    if term.label:
765
        raise NotImplementedError
766
767
768
    if term.kind == 'next_state':
        state = term.inputString.lower()
        if state.strip() != '-':
769
            next_id_cons = core.Constant.int(g.i32, term.next_id)
770
            g.builder.store(next_id_cons, g.scope.resolve('id'))
771
            if term.next_id == -1:
772
                state_ptr = g.global_scope.resolve('state')
773
774
                state_id_cons = g.states[state]
                g.builder.store(state_id_cons, state_ptr)
775
        else:
776
            raise NotImplementedError
777
    elif term.kind == 'join':
778
        raise NotImplementedError
779
    elif term.kind == 'stop':
780
        raise NotImplementedError
781
    elif term.kind == 'return':
782
783
784
785
786
787
788
789
        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
790
791
792
793


@generate.register(ogAST.Floating_label)
def _floating_label(label):
dbarbera's avatar
dbarbera committed
794
    ''' Generate the code for a floating label '''
795
    raise NotImplementedError
Maxime Perrotin's avatar
Maxime Perrotin committed
796
797
798
799
800


@generate.register(ogAST.Procedure)
def _inner_procedure(proc):
    ''' Generate the code for a procedure '''
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
    func_name = str(proc.inputString)
    param_tys = [core.Type.pointer(_generate_type(p['type'])) for p in proc.fpar]
    func_ty = core.Type.function(g.void, param_tys)
    func = core.Function.new(g.module, func_ty, func_name)
    g.funcs[func_name] = func

    _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
826
827
828


def _generate_type(ty):
829
    ''' Generate the equivalent LLVM type of a ASN.1 type '''
dbarbera's avatar
dbarbera committed
830
831
    basic_ty = find_basic_type(ty)
    if basic_ty.kind == 'IntegerType':
832
        return g.i32
dbarbera's avatar
dbarbera committed
833
    elif basic_ty.kind == 'BooleanType':
834
        return g.i1
dbarbera's avatar
dbarbera committed
835
    elif basic_ty.kind == 'RealType':
836
        return g.double
837
    elif basic_ty.kind == 'SequenceOfType':
dbarbera's avatar
dbarbera committed
838
839
        if ty.ReferencedTypeName in g.structs:
            return g.structs[ty.ReferencedTypeName].ty
840
841
842
843
844
845
846
847

        min_size = int(basic_ty.Max)
        max_size = int(basic_ty.Min)
        if min_size != max_size:
            raise NotImplementedError

        elem_ty = _generate_type(basic_ty.type)
        array_ty = core.Type.array(elem_ty, max_size)
848
        struct = StructType(ty.ReferencedTypeName, ['_'], [array_ty])
dbarbera's avatar
dbarbera committed
849
850
851
852
853
        g.structs[ty.ReferencedTypeName] = struct
        return struct.ty
    elif basic_ty.kind == 'SequenceType':
        if ty.ReferencedTypeName in g.structs:
            return g.structs[ty.ReferencedTypeName].ty
854
855
856
857

        field_names = []
        field_types = []
        for field_name in Helper.sorted_fields(basic_ty):
858
            field_names.append(field_name.replace('-', '_'))
859
860
861
            field_types.append(_generate_type(basic_ty.Children[field_name].type))

        struct = StructType(ty.ReferencedTypeName, field_names, field_types)
dbarbera's avatar
dbarbera committed
862
863
        g.structs[ty.ReferencedTypeName] = struct
        return struct.ty
dbarbera's avatar
dbarbera committed
864
865
    elif basic_ty.kind == 'EnumeratedType':
        return g.i32
dbarbera's avatar
dbarbera committed
866
867
868
869
    else:
        raise NotImplementedError


870
871
872
873
874