| -- Test cases for "flag elimination" optimization. Used to optimize away | |
| -- registers that are always used immediately after assignment as branch conditions. | |
| [case testFlagEliminationSimple] | |
| def c() -> bool: | |
| return True | |
| def d() -> bool: | |
| return True | |
| def f(x: bool) -> int: | |
| if x: | |
| b = c() | |
| else: | |
| b = d() | |
| if b: | |
| return 1 | |
| else: | |
| return 2 | |
| [out] | |
| def c(): | |
| L0: | |
| return 1 | |
| def d(): | |
| L0: | |
| return 1 | |
| def f(x): | |
| x, r0, r1 :: bool | |
| L0: | |
| if x goto L1 else goto L2 :: bool | |
| L1: | |
| r0 = c() | |
| if r0 goto L3 else goto L4 :: bool | |
| L2: | |
| r1 = d() | |
| if r1 goto L3 else goto L4 :: bool | |
| L3: | |
| return 2 | |
| L4: | |
| return 4 | |
| [case testFlagEliminationOneAssignment] | |
| def c() -> bool: | |
| return True | |
| def f(x: bool) -> int: | |
| # Not applied here | |
| b = c() | |
| if b: | |
| return 1 | |
| else: | |
| return 2 | |
| [out] | |
| def c(): | |
| L0: | |
| return 1 | |
| def f(x): | |
| x, r0, b :: bool | |
| L0: | |
| r0 = c() | |
| b = r0 | |
| if b goto L1 else goto L2 :: bool | |
| L1: | |
| return 2 | |
| L2: | |
| return 4 | |
| [case testFlagEliminationThreeCases] | |
| def c(x: int) -> bool: | |
| return True | |
| def f(x: bool, y: bool) -> int: | |
| if x: | |
| b = c(1) | |
| elif y: | |
| b = c(2) | |
| else: | |
| b = c(3) | |
| if b: | |
| return 1 | |
| else: | |
| return 2 | |
| [out] | |
| def c(x): | |
| x :: int | |
| L0: | |
| return 1 | |
| def f(x, y): | |
| x, y, r0, r1, r2 :: bool | |
| L0: | |
| if x goto L1 else goto L2 :: bool | |
| L1: | |
| r0 = c(2) | |
| if r0 goto L5 else goto L6 :: bool | |
| L2: | |
| if y goto L3 else goto L4 :: bool | |
| L3: | |
| r1 = c(4) | |
| if r1 goto L5 else goto L6 :: bool | |
| L4: | |
| r2 = c(6) | |
| if r2 goto L5 else goto L6 :: bool | |
| L5: | |
| return 2 | |
| L6: | |
| return 4 | |
| [case testFlagEliminationAssignmentNotLastOp] | |
| def f(x: bool) -> int: | |
| y = 0 | |
| if x: | |
| b = True | |
| y = 1 | |
| else: | |
| b = False | |
| if b: | |
| return 1 | |
| else: | |
| return 2 | |
| [out] | |
| def f(x): | |
| x :: bool | |
| y :: int | |
| b :: bool | |
| L0: | |
| y = 0 | |
| if x goto L1 else goto L2 :: bool | |
| L1: | |
| b = 1 | |
| y = 2 | |
| goto L3 | |
| L2: | |
| b = 0 | |
| L3: | |
| if b goto L4 else goto L5 :: bool | |
| L4: | |
| return 2 | |
| L5: | |
| return 4 | |
| [case testFlagEliminationAssignmentNoDirectGoto] | |
| def f(x: bool) -> int: | |
| if x: | |
| b = True | |
| else: | |
| b = False | |
| if x: | |
| if b: | |
| return 1 | |
| else: | |
| return 2 | |
| return 4 | |
| [out] | |
| def f(x): | |
| x, b :: bool | |
| L0: | |
| if x goto L1 else goto L2 :: bool | |
| L1: | |
| b = 1 | |
| goto L3 | |
| L2: | |
| b = 0 | |
| L3: | |
| if x goto L4 else goto L7 :: bool | |
| L4: | |
| if b goto L5 else goto L6 :: bool | |
| L5: | |
| return 2 | |
| L6: | |
| return 4 | |
| L7: | |
| return 8 | |
| [case testFlagEliminationBranchNotNextOpAfterGoto] | |
| def f(x: bool) -> int: | |
| if x: | |
| b = True | |
| else: | |
| b = False | |
| y = 1 # Prevents the optimization | |
| if b: | |
| return 1 | |
| else: | |
| return 2 | |
| [out] | |
| def f(x): | |
| x, b :: bool | |
| y :: int | |
| L0: | |
| if x goto L1 else goto L2 :: bool | |
| L1: | |
| b = 1 | |
| goto L3 | |
| L2: | |
| b = 0 | |
| L3: | |
| y = 2 | |
| if b goto L4 else goto L5 :: bool | |
| L4: | |
| return 2 | |
| L5: | |
| return 4 | |
| [case testFlagEliminationFlagReadTwice] | |
| def f(x: bool) -> bool: | |
| if x: | |
| b = True | |
| else: | |
| b = False | |
| if b: | |
| return b # Prevents the optimization | |
| else: | |
| return False | |
| [out] | |
| def f(x): | |
| x, b :: bool | |
| L0: | |
| if x goto L1 else goto L2 :: bool | |
| L1: | |
| b = 1 | |
| goto L3 | |
| L2: | |
| b = 0 | |
| L3: | |
| if b goto L4 else goto L5 :: bool | |
| L4: | |
| return b | |
| L5: | |
| return 0 | |
| [case testFlagEliminationArgumentNotEligible] | |
| def f(x: bool, b: bool) -> bool: | |
| if x: | |
| b = True | |
| else: | |
| b = False | |
| if b: | |
| return True | |
| else: | |
| return False | |
| [out] | |
| def f(x, b): | |
| x, b :: bool | |
| L0: | |
| if x goto L1 else goto L2 :: bool | |
| L1: | |
| b = 1 | |
| goto L3 | |
| L2: | |
| b = 0 | |
| L3: | |
| if b goto L4 else goto L5 :: bool | |
| L4: | |
| return 1 | |
| L5: | |
| return 0 | |
| [case testFlagEliminationFlagNotAlwaysDefined] | |
| def f(x: bool, y: bool) -> bool: | |
| if x: | |
| b = True | |
| elif y: | |
| b = False | |
| else: | |
| bb = False # b not assigned here -> can't optimize | |
| if b: | |
| return True | |
| else: | |
| return False | |
| [out] | |
| def f(x, y): | |
| x, y, r0, b, bb, r1 :: bool | |
| L0: | |
| r0 = <error> :: bool | |
| b = r0 | |
| if x goto L1 else goto L2 :: bool | |
| L1: | |
| b = 1 | |
| goto L5 | |
| L2: | |
| if y goto L3 else goto L4 :: bool | |
| L3: | |
| b = 0 | |
| goto L5 | |
| L4: | |
| bb = 0 | |
| L5: | |
| if is_error(b) goto L6 else goto L7 | |
| L6: | |
| r1 = raise UnboundLocalError('local variable "b" referenced before assignment') | |
| unreachable | |
| L7: | |
| if b goto L8 else goto L9 :: bool | |
| L8: | |
| return 1 | |
| L9: | |
| return 0 |