https://github.com/akkartik/mu/blob/master/024jump.cc

      1 //: Jump primitives
      2
      3 :(scenario jump_can_skip_instructions)
      4 def main [
      5   jump 1:offset
      6   1:num <- copy 1
      7 ]
      8 +run: jump {1: "offset"}
      9 -run: {1: "number"} <- copy {1: "literal"}
     10 -mem: storing 1 in location 1
     11
     12 :(before "End Primitive Recipe Declarations")
     13 JUMP,
     14 :(before "End Primitive Recipe Numbers")
     15 put(Recipe_ordinal, "jump", JUMP);
     16 :(before "End Primitive Recipe Checks")
     17 case JUMP: {
     18   if (SIZE(inst.ingredients) != 1) {
     19     raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' should get exactly one ingredient\n" << end();
     20     break;
     21   }
     22   if (!is_literal(inst.ingredients.at(0))) {
     23     raise << maybe(get(Recipe, r).name) << "first ingredient of '" << to_original_string(inst) << "' should be a label or offset, but '" << inst.ingredients.at(0).name << "' has type '" << names_to_string_without_quotes(inst.ingredients.at(0).type) << "'\n" << end();
     24     break;
     25   }
     26   if (!inst.products.empty()) {
     27     raise << maybe(get(Recipe, r).name) << "'jump' instructions write no products\n" << end();
     28     break;
     29   }
     30   break;
     31 }
     32 :(before "End Primitive Recipe Implementations")
     33 case JUMP: {
     34   assert(current_instruction().ingredients.at(0).initialized);
     35   current_step_index() += ingredients.at(0).at(0)+1;
     36   trace(9998, "run") << "jumping to instruction " << current_step_index() << end();
     37   // skip rest of this instruction
     38   write_products = false;
     39   fall_through_to_next_instruction = false;
     40   break;
     41 }
     42
     43 //: special type to designate jump targets
     44 :(before "End Mu Types Initialization")
     45 put(Type_ordinal, "offset", 0);
     46
     47 :(scenario jump_backward)
     48 def main [
     49   jump 1:offset  # 0 -+
     50   jump 3:offset  #    |   +-+ 1
     51                  #   \/  /\ |
     52   jump -2:offset #  2 +-->+ |
     53 ]                #         \/ 3
     54 +run: jump {1: "offset"}
     55 +run: jump {-2: "offset"}
     56 +run: jump {3: "offset"}
     57
     58 :(scenario jump_takes_no_products)
     59 % Hide_errors = true;
     60 def main [
     61   1:num <- jump 1
     62 ]
     63 +error: main: 'jump' instructions write no products
     64
     65 :(before "End Primitive Recipe Declarations")
     66 JUMP_IF,
     67 :(before "End Primitive Recipe Numbers")
     68 put(Recipe_ordinal, "jump-if", JUMP_IF);
     69 :(before "End Primitive Recipe Checks")
     70 case JUMP_IF: {
     71   if (SIZE(inst.ingredients) != 2) {
     72     raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' should get exactly two ingredients\n" << end();
     73     break;
     74   }
     75   if (!is_mu_address(inst.ingredients.at(0)) && !is_mu_scalar(inst.ingredients.at(0))) {
     76     raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' requires a boolean for its first ingredient, but '" << inst.ingredients.at(0).name << "' has type '" << names_to_string_without_quotes(inst.ingredients.at(0).type) << "'\n" << end();
     77     break;
     78   }
     79   if (!is_literal(inst.ingredients.at(1))) {
     80     raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' requires a label or offset for its second ingredient, but '" << inst.ingredients.at(1).name << "' has type '" << names_to_string_without_quotes(inst.ingredients.at(1).type) << "'\n" << end();
     81     break;
     82   }
     83   if (!inst.products.empty()) {
     84     raise << maybe(get(Recipe, r).name) << "'jump-if' instructions write no products\n" << end();
     85     break;
     86   }
     87   // End JUMP_IF Checks
     88   break;
     89 }
     90 :(before "End Primitive Recipe Implementations")
     91 case JUMP_IF: {
     92   assert(current_instruction().ingredients.at(1).initialized);
     93   if (!scalar_ingredient(ingredients, 0)) {
     94     trace(9998, "run") << "jump-if fell through" << end();
     95     break;
     96   }
     97   current_step_index() += ingredients.at(1).at(0)+1;
     98   trace(9998, "run") << "jumping to instruction " << current_step_index() << end();
     99   // skip rest of this instruction
    100   write_products = false;
    101   fall_through_to_next_instruction = false;
    102   break;
    103 }
    104
    105 :(scenario jump_if)
    106 def main [
    107   jump-if 999, 1:offset
    108   123:num <- copy 1
    109 ]
    110 +run: jump-if {999: "literal"}, {1: "offset"}
    111 +run: jumping to instruction 2
    112 -run: {123: "number"} <- copy {1: "literal"}
    113 -mem: storing 1 in location 123
    114
    115 :(scenario jump_if_fallthrough)
    116 def main [
    117   jump-if 0, 1:offset
    118   123:num <- copy 1
    119 ]
    120 +run: jump-if {0: "literal"}, {1: "offset"}
    121 +run: jump-if fell through
    122 +run: {123: "number"} <- copy {1: "literal"}
    123 +mem: storing 1 in location 123
    124
    125 :(scenario jump_if_on_address)
    126 def main [
    127   10:num/alloc-id, 11:num <- copy 0, 999
    128   jump-if 10:&:number, 1:offset
    129   123:num <- copy 1
    130 ]
    131 +run: jump-if {10: ("address" "number")}, {1: "offset"}
    132 +run: jumping to instruction 3
    133 -run: {123: "number"} <- copy {1: "literal"}
    134 -mem: storing 1 in location 123
    135
    136 :(before "End Primitive Recipe Declarations")
    137 JUMP_UNLESS,
    138 :(before "End Primitive Recipe Numbers")
    139 put(Recipe_ordinal, "jump-unless", JUMP_UNLESS);
    140 :(before "End Primitive Recipe Checks")
    141 case JUMP_UNLESS: {
    142   if (SIZE(inst.ingredients) != 2) {
    143     raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' should get exactly two ingredients\n" << end();
    144     break;
    145   }
    146   if (!is_mu_address(inst.ingredients.at(0)) && !is_mu_scalar(inst.ingredients.at(0))) {
    147     raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' requires a boolean for its first ingredient, but '" << inst.ingredients.at(0).name << "' has type '" << names_to_string_without_quotes(inst.ingredients.at(0).type) << "'\n" << end();
    148     break;
    149   }
    150   if (!is_literal(inst.ingredients.at(1))) {
    151     raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' requires a label or offset for its second ingredient, but '" << inst.ingredients.at(1).name << "' has type '" << names_to_string_without_quotes(inst.ingredients.at(1).type) << "'\n" << end();
    152     break;
    153   }
    154   if (!inst.products.empty()) {
    155     raise << maybe(get(Recipe, r).name) << "'jump' instructions write no products\n" << end();
    156     break;
    157   }
    158   // End JUMP_UNLESS Checks
    159   break;
    160 }
    161 :(before "End Primitive Recipe Implementations")
    162 case JUMP_UNLESS: {
    163   assert(current_instruction().ingredients.at(1).initialized);
    164   if (scalar_ingredient(ingredients, 0)) {
    165     trace(9998, "run") << "jump-unless fell through" << end();
    166     break;
    167   }
    168   current_step_index() += ingredients.at(1).at(0)+1;
    169   trace(9998, "run") << "jumping to instruction " << current_step_index() << end();
    170   // skip rest of this instruction
    171   write_products = false;
    172   fall_through_to_next_instruction = false;
    173   break;
    174 }
    175
    176 :(scenario jump_unless)
    177 def main [
    178   jump-unless 0, 1:offset
    179   123:num <- copy 1
    180 ]
    181 +run: jump-unless {0: "literal"}, {1: "offset"}
    182 +run: jumping to instruction 2
    183 -run: {123: "number"} <- copy {1: "literal"}
    184 -mem: storing 1 in location 123
    185
    186 :(scenario jump_unless_fallthrough)
    187 def main [
    188   jump-unless 999, 1:offset
    189   123:num <- copy 1
    190 ]
    191 +run: jump-unless {999: "literal"}, {1: "offset"}
    192 +run: jump-unless fell through
    193 +run: {123: "number"} <- copy {1: "literal"}
    194 +mem: storing 1 in location 123