#include <perms.h>

//          Edinburgh IMP77 Compiler - Version 8.4
//
//     1  !
//     2  ! The hand-generated code below should be producable by PSR's compiler if it:
//     3  ! A) delays stores as late as possible
//     4  !
//     5  ! B) remembers registers over procedure calls
//     6  !
//     7  ! C) has a general algorithm for drop-through conditionally executed
//     8  !    instructions, i.e. if there are no instructions between a conditional
//     9  !    branch and its destination which set the condition codes, and the
//    10  !    sequence is less that a certain length, then all the instructions
//    11  !    within the sequence can be made conditional.
//    12  !
//    13  ! D) does as above, but also allows instructions within the sequence
//    14  !    whose subsequent execution depends on the same condition, e.g.
//    15  !
//    16  !    %if a=b %and c=d %then a=b
//    17  !
//    18  !    CmpS   R0,R1            NAIVE STYLE
//    19  !    Bne    elsepart
//    20  !    Cmps   R2,R3
//    21  !    Bne    elsepart
//    22  !    Mov    R0,R2
//    23  !
//    24  !    CmpS   R0,R1            RULE (C) ABOVE
//    25  !    Bne    elsepart
//    26  !    CmpS   R2,R3
//    27  !    MovEQ  R0,R2
//    28  !
//    29  !    CmpS   R0,R1            RULE (D) SPECIAL CASE
//    30  !    CmpSEQ R2,R3
//    31  !    MovEQ  R0,R2
//    32  !
//    33  ! E) alters conditions to generate similar condition codes on
//    34  !    condition AND condition AND condition to generate more cases
//    35  !    to which rule (D) can be applied.
//    36  !
//    37  ! F) adjusts constants in < or <= cases to favour above, i.e. turning
//    38  !    CMP R,#const & BLE ... into CMP R,#const-1 & BLT ... etc.
//    39  !
//    40  ! G) changes Newline back from the current implicit printsymbol(10) -
//    41  !    there is no run-time overhead in moving the MOV R0,#10 over to
//    42  !    the procedure body instead of having it in every call where it
//    43  !    takes up space - after all, Peter's code-moving stuff ought to
//    44  !    get %permroutine newline;printsymbol(10);%end correct - it will
//    45  !    place the Mov R0,#10 before the body of %permroutine printsymbol
//    46  !    and generate a suitable entry point for it...
//    47  !       Personally, I would recommend stacking/restoring R0 as well
//    48  !    as it might keep another variable in a register for a bit longer...
//    49  !
//    50  ! I've only suggested optimisations which fit into the style of PSR's
//    51  ! compilers...
//    52  !
//    53
//    54
//    55  %begin

int main(int argc, char **argv) { /*%begin*/
  _imp_initialise(argc, argv);

  //    56  %integer a,i,b

  int A;
  int I;
  int B;

  //    57
  //    58    read(a)

  _imp_READ(/*?*/ &A);

  //    59  ! BL     read_fn
  //    60
  //    61  ! Str    R0,a
  //    62    read(i)

  _imp_READ(/*?*/ &I);

  //    63  ! BL     read_fn
  //    64
  //    65  ! Str    R0,i
  //    66    read(b)

  _imp_READ(/*?*/ &B);

  //    67  ! BL     read_fn
  //    68
  //    69    %if a <= i <= b %start

  {
// Double-sided test on I (Part I)
    int tmp;
    if (A > (tmp = I)) goto L_0001;
// Double-sided test on I (Part II)
    if (tmp > B) goto L_0001;
  }

  //    70  ! Ldr R1,a
  //    71  ! Ldr R2,i
  //    72  ! CmpS   R1,R2
  //    73  ! CmpSLE R2,R0
  //    74      i = 22

  I = 22;

  //    75  ! MovLE  R2,#22
  //    76    %finish

L_0001:;

//    77
//    78    %if 22 <= i <= b %start

  {
// Double-sided test on I (Part I)
    int tmp;
    if (22 > (tmp = I)) goto L_0002;
// Double-sided test on I (Part II)
    if (tmp > B) goto L_0002;
  }

  //    79  ! CmpS   R2,#22-1
  //    80  ! CmpSGT R2,R0
  //    81      i = 44

  I = 44;

  //    82  ! MovGT  R2,#44
  //    83    %finish

L_0002:;

//    84
//    85    %if a <= i <= 77 %start

  {
// Double-sided test on I (Part I)
    int tmp;
    if (A > (tmp = I)) goto L_0003;
// Double-sided test on I (Part II)
    if (tmp > 77) goto L_0003;
  }

  //    86  ! CmpS   R1,R2
  //    87  ! CmpSLE R2,#77
  //    88      i = 99

  I = 99;

  //    89  ! MovLE  R2,#99
  //    90    %finish

L_0003:;

//    91
//    92    %if 11 <= i <= 100 %start     ;! Peter's special case when both const is good

  {
// Double-sided test on I (Part I)
    int tmp;
    if (11 > (tmp = I)) goto L_0004;
// Double-sided test on I (Part II)
    if (tmp > 100) goto L_0004;
  }

  //    93  ! Sub   R2,#11                  ;! but usually corrupts a register needed later
  //    94  ! CmpS  R2,#100-11
  //    95      i = 1

  I = 1;

  //    96  ! MovLS R2,#1
  //    97    %finish

L_0004:;

//    98
//    99  ! Str   R0,b
//   100    write(a,0)

  _imp_WRITE(A, 0);

  //   101  ! Mov   R0,R1
  //   102  ! Mov   R1,#0
  //   103  ! Bl    Write
  //   104
  //   105    newline

  _imp_NEWLINE();

  //   106  ! Bl    Newline
  //   107
  //   108  ! Mov   R0,R2
  //   109    write(i,0)

  _imp_WRITE(I, 0);

  //   110  ! Bl    write
  //   111
  //   112    newline

  _imp_NEWLINE();

  //   113  ! Bl    newline
  //   114
  //   115    write(b,0)

  _imp_WRITE(B, 0);

  //   116  ! Ldr   R0,b
  //   117  ! Bl    write
  //   118
  //   119    newline

  _imp_NEWLINE();

  //   120  ! Bl    newline
  //   121
  //   122  %endofprogram

  _imp_stop(0);
  return 0;
end_0:;
}