Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
# coding=utf-8
2
#
3
# Copyright © 2011 Intel Corporation
4
#
5
# Permission is hereby granted, free of charge, to any person obtaining a
6
# copy of this software and associated documentation files (the "Software"),
7
# to deal in the Software without restriction, including without limitation
8
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
# and/or sell copies of the Software, and to permit persons to whom the
10
# Software is furnished to do so, subject to the following conditions:
11
#
12
# The above copyright notice and this permission notice (including the next
13
# paragraph) shall be included in all copies or substantial portions of the
14
# Software.
15
#
16
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
# DEALINGS IN THE SOFTWARE.
23
 
24
import os
25
import os.path
26
import re
27
import subprocess
28
import sys
29
 
30
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) # For access to sexps.py, which is in parent dir
31
from sexps import *
32
 
33
def make_test_case(f_name, ret_type, body):
34
    """Create a simple optimization test case consisting of a single
35
    function with the given name, return type, and body.
36
 
37
    Global declarations are automatically created for any undeclared
38
    variables that are referenced by the function.  All undeclared
39
    variables are assumed to be floats.
40
    """
41
    check_sexp(body)
42
    declarations = {}
43
    def make_declarations(sexp, already_declared = ()):
44
        if isinstance(sexp, list):
45
            if len(sexp) == 2 and sexp[0] == 'var_ref':
46
                if sexp[1] not in already_declared:
47
                    declarations[sexp[1]] = [
48
                        'declare', ['in'], 'float', sexp[1]]
49
            elif len(sexp) == 4 and sexp[0] == 'assign':
50
                assert sexp[2][0] == 'var_ref'
51
                if sexp[2][1] not in already_declared:
52
                    declarations[sexp[2][1]] = [
53
                        'declare', ['out'], 'float', sexp[2][1]]
54
                make_declarations(sexp[3], already_declared)
55
            else:
56
                already_declared = set(already_declared)
57
                for s in sexp:
58
                    if isinstance(s, list) and len(s) >= 4 and \
59
                            s[0] == 'declare':
60
                        already_declared.add(s[3])
61
                    else:
62
                        make_declarations(s, already_declared)
63
    make_declarations(body)
64
    return declarations.values() + \
65
        [['function', f_name, ['signature', ret_type, ['parameters'], body]]]
66
 
67
 
68
# The following functions can be used to build expressions.
69
 
70
def const_float(value):
71
    """Create an expression representing the given floating point value."""
72
    return ['constant', 'float', ['{0:.6f}'.format(value)]]
73
 
74
def const_bool(value):
75
    """Create an expression representing the given boolean value.
76
 
77
    If value is not a boolean, it is converted to a boolean.  So, for
78
    instance, const_bool(1) is equivalent to const_bool(True).
79
    """
80
    return ['constant', 'bool', ['{0}'.format(1 if value else 0)]]
81
 
82
def gt_zero(var_name):
83
    """Create Construct the expression var_name > 0"""
84
    return ['expression', 'bool', '>', ['var_ref', var_name], const_float(0)]
85
 
86
 
87
# The following functions can be used to build complex control flow
88
# statements.  All of these functions return statement lists (even
89
# those which only create a single statement), so that statements can
90
# be sequenced together using the '+' operator.
91
 
92
def return_(value = None):
93
    """Create a return statement."""
94
    if value is not None:
95
        return [['return', value]]
96
    else:
97
        return [['return']]
98
 
99
def break_():
100
    """Create a break statement."""
101
    return ['break']
102
 
103
def continue_():
104
    """Create a continue statement."""
105
    return ['continue']
106
 
107
def simple_if(var_name, then_statements, else_statements = None):
108
    """Create a statement of the form
109
 
110
    if (var_name > 0.0) {
111
       
112
    } else {
113
       
114
    }
115
 
116
    else_statements may be omitted.
117
    """
118
    if else_statements is None:
119
        else_statements = []
120
    check_sexp(then_statements)
121
    check_sexp(else_statements)
122
    return [['if', gt_zero(var_name), then_statements, else_statements]]
123
 
124
def loop(statements):
125
    """Create a loop containing the given statements as its loop
126
    body.
127
    """
128
    check_sexp(statements)
129
    return [['loop', [], [], [], [], statements]]
130
 
131
def declare_temp(var_type, var_name):
132
    """Create a declaration of the form
133
 
134
    (declare (temporary)  
135
    """
136
    return [['declare', ['temporary'], var_type, var_name]]
137
 
138
def assign_x(var_name, value):
139
    """Create a statement that assigns  to the variable
140
    .  The assignment uses the mask (x).
141
    """
142
    check_sexp(value)
143
    return [['assign', ['x'], ['var_ref', var_name], value]]
144
 
145
def complex_if(var_prefix, statements):
146
    """Create a statement of the form
147
 
148
    if (a > 0.0) {
149
       if (b > 0.0) {
150
          
151
       }
152
    }
153
 
154
    This is useful in testing jump lowering, because if 
155
    ends in a jump, lower_jumps.cpp won't try to combine this
156
    construct with the code that follows it, as it might do for a
157
    simple if.
158
 
159
    All variables used in the if statement are prefixed with
160
    var_prefix.  This can be used to ensure uniqueness.
161
    """
162
    check_sexp(statements)
163
    return simple_if(var_prefix + 'a', simple_if(var_prefix + 'b', statements))
164
 
165
def declare_execute_flag():
166
    """Create the statements that lower_jumps.cpp uses to declare and
167
    initialize the temporary boolean execute_flag.
168
    """
169
    return declare_temp('bool', 'execute_flag') + \
170
        assign_x('execute_flag', const_bool(True))
171
 
172
def declare_return_flag():
173
    """Create the statements that lower_jumps.cpp uses to declare and
174
    initialize the temporary boolean return_flag.
175
    """
176
    return declare_temp('bool', 'return_flag') + \
177
        assign_x('return_flag', const_bool(False))
178
 
179
def declare_return_value():
180
    """Create the statements that lower_jumps.cpp uses to declare and
181
    initialize the temporary variable return_value.  Assume that
182
    return_value is a float.
183
    """
184
    return declare_temp('float', 'return_value')
185
 
186
def declare_break_flag():
187
    """Create the statements that lower_jumps.cpp uses to declare and
188
    initialize the temporary boolean break_flag.
189
    """
190
    return declare_temp('bool', 'break_flag') + \
191
        assign_x('break_flag', const_bool(False))
192
 
193
def lowered_return_simple(value = None):
194
    """Create the statements that lower_jumps.cpp lowers a return
195
    statement to, in situations where it does not need to clear the
196
    execute flag.
197
    """
198
    if value:
199
        result = assign_x('return_value', value)
200
    else:
201
        result = []
202
    return result + assign_x('return_flag', const_bool(True))
203
 
204
def lowered_return(value = None):
205
    """Create the statements that lower_jumps.cpp lowers a return
206
    statement to, in situations where it needs to clear the execute
207
    flag.
208
    """
209
    return lowered_return_simple(value) + \
210
        assign_x('execute_flag', const_bool(False))
211
 
212
def lowered_continue():
213
    """Create the statement that lower_jumps.cpp lowers a continue
214
    statement to.
215
    """
216
    return assign_x('execute_flag', const_bool(False))
217
 
218
def lowered_break_simple():
219
    """Create the statement that lower_jumps.cpp lowers a break
220
    statement to, in situations where it does not need to clear the
221
    execute flag.
222
    """
223
    return assign_x('break_flag', const_bool(True))
224
 
225
def lowered_break():
226
    """Create the statement that lower_jumps.cpp lowers a break
227
    statement to, in situations where it needs to clear the execute
228
    flag.
229
    """
230
    return lowered_break_simple() + assign_x('execute_flag', const_bool(False))
231
 
232
def if_execute_flag(statements):
233
    """Wrap statements in an if test so that they will only execute if
234
    execute_flag is True.
235
    """
236
    check_sexp(statements)
237
    return [['if', ['var_ref', 'execute_flag'], statements, []]]
238
 
239
def if_not_return_flag(statements):
240
    """Wrap statements in an if test so that they will only execute if
241
    return_flag is False.
242
    """
243
    check_sexp(statements)
244
    return [['if', ['var_ref', 'return_flag'], [], statements]]
245
 
246
def final_return():
247
    """Create the return statement that lower_jumps.cpp places at the
248
    end of a function when lowering returns.
249
    """
250
    return [['return', ['var_ref', 'return_value']]]
251
 
252
def final_break():
253
    """Create the conditional break statement that lower_jumps.cpp
254
    places at the end of a function when lowering breaks.
255
    """
256
    return [['if', ['var_ref', 'break_flag'], break_(), []]]
257
 
258
def bash_quote(*args):
259
    """Quote the arguments appropriately so that bash will understand
260
    each argument as a single word.
261
    """
262
    def quote_word(word):
263
        for c in word:
264
            if not (c.isalpha() or c.isdigit() or c in '@%_-+=:,./'):
265
                break
266
        else:
267
            if not word:
268
                return "''"
269
            return word
270
        return "'{0}'".format(word.replace("'", "'\"'\"'"))
271
    return ' '.join(quote_word(word) for word in args)
272
 
273
def create_test_case(doc_string, input_sexp, expected_sexp, test_name,
274
                     pull_out_jumps=False, lower_sub_return=False,
275
                     lower_main_return=False, lower_continue=False,
276
                     lower_break=False):
277
    """Create a test case that verifies that do_lower_jumps transforms
278
    the given code in the expected way.
279
    """
280
    doc_lines = [line.strip() for line in doc_string.splitlines()]
281
    doc_string = ''.join('# {0}\n'.format(line) for line in doc_lines if line != '')
282
    check_sexp(input_sexp)
283
    check_sexp(expected_sexp)
284
    input_str = sexp_to_string(sort_decls(input_sexp))
285
    expected_output = sexp_to_string(sort_decls(expected_sexp))
286
 
287
    optimization = (
288
        'do_lower_jumps({0:d}, {1:d}, {2:d}, {3:d}, {4:d})'.format(
289
            pull_out_jumps, lower_sub_return, lower_main_return,
290
            lower_continue, lower_break))
291
    args = ['../../glsl_test', 'optpass', '--quiet', '--input-ir', optimization]
292
    test_file = '{0}.opt_test'.format(test_name)
293
    with open(test_file, 'w') as f:
294
        f.write('#!/bin/bash\n#\n# This file was generated by create_test_cases.py.\n#\n')
295
        f.write(doc_string)
296
        f.write('{0} <
297
        f.write('{0}\nEOF\n'.format(input_str))
298
    os.chmod(test_file, 0774)
299
    expected_file = '{0}.opt_test.expected'.format(test_name)
300
    with open(expected_file, 'w') as f:
301
        f.write('{0}\n'.format(expected_output))
302
 
303
def test_lower_returns_main():
304
    doc_string = """Test that do_lower_jumps respects the lower_main_return
305
    flag in deciding whether to lower returns in the main
306
    function.
307
    """
308
    input_sexp = make_test_case('main', 'void', (
309
            complex_if('', return_())
310
            ))
311
    expected_sexp = make_test_case('main', 'void', (
312
            declare_execute_flag() +
313
            declare_return_flag() +
314
            complex_if('', lowered_return())
315
            ))
316
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_main_true',
317
                     lower_main_return=True)
318
    create_test_case(doc_string, input_sexp, input_sexp, 'lower_returns_main_false',
319
                     lower_main_return=False)
320
 
321
def test_lower_returns_sub():
322
    doc_string = """Test that do_lower_jumps respects the lower_sub_return flag
323
    in deciding whether to lower returns in subroutines.
324
    """
325
    input_sexp = make_test_case('sub', 'void', (
326
            complex_if('', return_())
327
            ))
328
    expected_sexp = make_test_case('sub', 'void', (
329
            declare_execute_flag() +
330
            declare_return_flag() +
331
            complex_if('', lowered_return())
332
            ))
333
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_sub_true',
334
                     lower_sub_return=True)
335
    create_test_case(doc_string, input_sexp, input_sexp, 'lower_returns_sub_false',
336
                     lower_sub_return=False)
337
 
338
def test_lower_returns_1():
339
    doc_string = """Test that a void return at the end of a function is
340
    eliminated.
341
    """
342
    input_sexp = make_test_case('main', 'void', (
343
            assign_x('a', const_float(1)) +
344
            return_()
345
            ))
346
    expected_sexp = make_test_case('main', 'void', (
347
            assign_x('a', const_float(1))
348
            ))
349
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_1',
350
                     lower_main_return=True)
351
 
352
def test_lower_returns_2():
353
    doc_string = """Test that lowering is not performed on a non-void return at
354
    the end of subroutine.
355
    """
356
    input_sexp = make_test_case('sub', 'float', (
357
            assign_x('a', const_float(1)) +
358
            return_(const_float(1))
359
            ))
360
    create_test_case(doc_string, input_sexp, input_sexp, 'lower_returns_2',
361
                     lower_sub_return=True)
362
 
363
def test_lower_returns_3():
364
    doc_string = """Test lowering of returns when there is one nested inside a
365
    complex structure of ifs, and one at the end of a function.
366
 
367
    In this case, the latter return needs to be lowered because it
368
    will not be at the end of the function once the final return
369
    is inserted.
370
    """
371
    input_sexp = make_test_case('sub', 'float', (
372
            complex_if('', return_(const_float(1))) +
373
            return_(const_float(2))
374
            ))
375
    expected_sexp = make_test_case('sub', 'float', (
376
            declare_execute_flag() +
377
            declare_return_value() +
378
            declare_return_flag() +
379
            complex_if('', lowered_return(const_float(1))) +
380
            if_execute_flag(lowered_return(const_float(2))) +
381
            final_return()
382
            ))
383
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_3',
384
                     lower_sub_return=True)
385
 
386
def test_lower_returns_4():
387
    doc_string = """Test that returns are properly lowered when they occur in
388
    both branches of an if-statement.
389
    """
390
    input_sexp = make_test_case('sub', 'float', (
391
            simple_if('a', return_(const_float(1)),
392
                      return_(const_float(2)))
393
            ))
394
    expected_sexp = make_test_case('sub', 'float', (
395
            declare_execute_flag() +
396
            declare_return_value() +
397
            declare_return_flag() +
398
            simple_if('a', lowered_return(const_float(1)),
399
                      lowered_return(const_float(2))) +
400
            final_return()
401
            ))
402
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_4',
403
                     lower_sub_return=True)
404
 
405
def test_lower_unified_returns():
406
    doc_string = """If both branches of an if statement end in a return, and
407
    pull_out_jumps is True, then those returns should be lifted
408
    outside the if and then properly lowered.
409
 
410
    Verify that this lowering occurs during the same pass as the
411
    lowering of other returns by checking that extra temporary
412
    variables aren't generated.
413
    """
414
    input_sexp = make_test_case('main', 'void', (
415
            complex_if('a', return_()) +
416
            simple_if('b', simple_if('c', return_(), return_()))
417
            ))
418
    expected_sexp = make_test_case('main', 'void', (
419
            declare_execute_flag() +
420
            declare_return_flag() +
421
            complex_if('a', lowered_return()) +
422
            if_execute_flag(simple_if('b', (simple_if('c', [], []) +
423
                                            lowered_return())))
424
            ))
425
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_unified_returns',
426
                     lower_main_return=True, pull_out_jumps=True)
427
 
428
def test_lower_pulled_out_jump():
429
    doc_string = """If one branch of an if ends in a jump, and control cannot
430
    fall out the bottom of the other branch, and pull_out_jumps is
431
    True, then the jump is lifted outside the if.
432
 
433
    Verify that this lowering occurs during the same pass as the
434
    lowering of other jumps by checking that extra temporary
435
    variables aren't generated.
436
    """
437
    input_sexp = make_test_case('main', 'void', (
438
            complex_if('a', return_()) +
439
            loop(simple_if('b', simple_if('c', break_(), continue_()),
440
                           return_())) +
441
            assign_x('d', const_float(1))
442
            ))
443
    # Note: optimization produces two other effects: the break
444
    # gets lifted out of the if statements, and the code after the
445
    # loop gets guarded so that it only executes if the return
446
    # flag is clear.
447
    expected_sexp = make_test_case('main', 'void', (
448
            declare_execute_flag() +
449
            declare_return_flag() +
450
            complex_if('a', lowered_return()) +
451
            if_execute_flag(
452
                loop(simple_if('b', simple_if('c', [], continue_()),
453
                               lowered_return_simple()) +
454
                     break_()) +
455
                if_not_return_flag(assign_x('d', const_float(1))))
456
            ))
457
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_pulled_out_jump',
458
                     lower_main_return=True, pull_out_jumps=True)
459
 
460
def test_lower_breaks_1():
461
    doc_string = """If a loop contains an unconditional break at the bottom of
462
    it, it should not be lowered."""
463
    input_sexp = make_test_case('main', 'void', (
464
            loop(assign_x('a', const_float(1)) +
465
                 break_())
466
            ))
467
    expected_sexp = input_sexp
468
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_1', lower_break=True)
469
 
470
def test_lower_breaks_2():
471
    doc_string = """If a loop contains a conditional break at the bottom of it,
472
    it should not be lowered if it is in the then-clause.
473
    """
474
    input_sexp = make_test_case('main', 'void', (
475
            loop(assign_x('a', const_float(1)) +
476
                 simple_if('b', break_()))
477
            ))
478
    expected_sexp = input_sexp
479
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_2', lower_break=True)
480
 
481
def test_lower_breaks_3():
482
    doc_string = """If a loop contains a conditional break at the bottom of it,
483
    it should not be lowered if it is in the then-clause, even if
484
    there are statements preceding the break.
485
    """
486
    input_sexp = make_test_case('main', 'void', (
487
            loop(assign_x('a', const_float(1)) +
488
                 simple_if('b', (assign_x('c', const_float(1)) +
489
                                 break_())))
490
            ))
491
    expected_sexp = input_sexp
492
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_3', lower_break=True)
493
 
494
def test_lower_breaks_4():
495
    doc_string = """If a loop contains a conditional break at the bottom of it,
496
    it should not be lowered if it is in the else-clause.
497
    """
498
    input_sexp = make_test_case('main', 'void', (
499
            loop(assign_x('a', const_float(1)) +
500
                 simple_if('b', [], break_()))
501
            ))
502
    expected_sexp = input_sexp
503
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_4', lower_break=True)
504
 
505
def test_lower_breaks_5():
506
    doc_string = """If a loop contains a conditional break at the bottom of it,
507
    it should not be lowered if it is in the else-clause, even if
508
    there are statements preceding the break.
509
    """
510
    input_sexp = make_test_case('main', 'void', (
511
            loop(assign_x('a', const_float(1)) +
512
                 simple_if('b', [], (assign_x('c', const_float(1)) +
513
                                     break_())))
514
            ))
515
    expected_sexp = input_sexp
516
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_5', lower_break=True)
517
 
518
def test_lower_breaks_6():
519
    doc_string = """If a loop contains conditional breaks and continues, and
520
    ends in an unconditional break, then the unconditional break
521
    needs to be lowered, because it will no longer be at the end
522
    of the loop after the final break is added.
523
    """
524
    input_sexp = make_test_case('main', 'void', (
525
            loop(simple_if('a', (complex_if('b', continue_()) +
526
                                 complex_if('c', break_()))) +
527
                 break_())
528
            ))
529
    expected_sexp = make_test_case('main', 'void', (
530
            declare_break_flag() +
531
            loop(declare_execute_flag() +
532
                 simple_if(
533
                    'a',
534
                    (complex_if('b', lowered_continue()) +
535
                     if_execute_flag(
536
                            complex_if('c', lowered_break())))) +
537
                 if_execute_flag(lowered_break_simple()) +
538
                 final_break())
539
            ))
540
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_6',
541
                     lower_break=True, lower_continue=True)
542
 
543
def test_lower_guarded_conditional_break():
544
    doc_string = """Normally a conditional break at the end of a loop isn't
545
    lowered, however if the conditional break gets placed inside
546
    an if(execute_flag) because of earlier lowering of continues,
547
    then the break needs to be lowered.
548
    """
549
    input_sexp = make_test_case('main', 'void', (
550
            loop(complex_if('a', continue_()) +
551
                 simple_if('b', break_()))
552
            ))
553
    expected_sexp = make_test_case('main', 'void', (
554
            declare_break_flag() +
555
            loop(declare_execute_flag() +
556
                 complex_if('a', lowered_continue()) +
557
                 if_execute_flag(simple_if('b', lowered_break())) +
558
                 final_break())
559
            ))
560
    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_guarded_conditional_break',
561
                     lower_break=True, lower_continue=True)
562
 
563
def test_remove_continue_at_end_of_loop():
564
    doc_string = """Test that a redundant continue-statement at the end of a
565
    loop is removed.
566
    """
567
    input_sexp = make_test_case('main', 'void', (
568
            loop(assign_x('a', const_float(1)) +
569
                 continue_())
570
            ))
571
    expected_sexp = make_test_case('main', 'void', (
572
            loop(assign_x('a', const_float(1)))
573
            ))
574
    create_test_case(doc_string, input_sexp, expected_sexp, 'remove_continue_at_end_of_loop')
575
 
576
def test_lower_return_void_at_end_of_loop():
577
    doc_string = """Test that a return of void at the end of a loop is properly
578
    lowered.
579
    """
580
    input_sexp = make_test_case('main', 'void', (
581
            loop(assign_x('a', const_float(1)) +
582
                 return_()) +
583
            assign_x('b', const_float(2))
584
            ))
585
    expected_sexp = make_test_case('main', 'void', (
586
            declare_return_flag() +
587
            loop(assign_x('a', const_float(1)) +
588
                 lowered_return_simple() +
589
                 break_()) +
590
            if_not_return_flag(assign_x('b', const_float(2)))
591
            ))
592
    create_test_case(doc_string, input_sexp, input_sexp, 'return_void_at_end_of_loop_lower_nothing')
593
    create_test_case(doc_string, input_sexp, expected_sexp, 'return_void_at_end_of_loop_lower_return',
594
                     lower_main_return=True)
595
    create_test_case(doc_string, input_sexp, expected_sexp, 'return_void_at_end_of_loop_lower_return_and_break',
596
                     lower_main_return=True, lower_break=True)
597
 
598
def test_lower_return_non_void_at_end_of_loop():
599
    doc_string = """Test that a non-void return at the end of a loop is
600
    properly lowered.
601
    """
602
    input_sexp = make_test_case('sub', 'float', (
603
            loop(assign_x('a', const_float(1)) +
604
                 return_(const_float(2))) +
605
            assign_x('b', const_float(3)) +
606
            return_(const_float(4))
607
            ))
608
    expected_sexp = make_test_case('sub', 'float', (
609
            declare_execute_flag() +
610
            declare_return_value() +
611
            declare_return_flag() +
612
            loop(assign_x('a', const_float(1)) +
613
                 lowered_return_simple(const_float(2)) +
614
                 break_()) +
615
            if_not_return_flag(assign_x('b', const_float(3)) +
616
                               lowered_return(const_float(4))) +
617
            final_return()
618
            ))
619
    create_test_case(doc_string, input_sexp, input_sexp, 'return_non_void_at_end_of_loop_lower_nothing')
620
    create_test_case(doc_string, input_sexp, expected_sexp, 'return_non_void_at_end_of_loop_lower_return',
621
                     lower_sub_return=True)
622
    create_test_case(doc_string, input_sexp, expected_sexp, 'return_non_void_at_end_of_loop_lower_return_and_break',
623
                     lower_sub_return=True, lower_break=True)
624
 
625
if __name__ == '__main__':
626
    test_lower_returns_main()
627
    test_lower_returns_sub()
628
    test_lower_returns_1()
629
    test_lower_returns_2()
630
    test_lower_returns_3()
631
    test_lower_returns_4()
632
    test_lower_unified_returns()
633
    test_lower_pulled_out_jump()
634
    test_lower_breaks_1()
635
    test_lower_breaks_2()
636
    test_lower_breaks_3()
637
    test_lower_breaks_4()
638
    test_lower_breaks_5()
639
    test_lower_breaks_6()
640
    test_lower_guarded_conditional_break()
641
    test_remove_continue_at_end_of_loop()
642
    test_lower_return_void_at_end_of_loop()
643
    test_lower_return_non_void_at_end_of_loop()