1 /* ***********************************************************
  2    *                                                         *
  3    * Copyright, (C) Honeywell Information Systems Inc., 1982 *
  4    *                                                         *
  5    * Copyright (c) 1972 by Massachusetts Institute of        *
  6    * Technology and Honeywell Information Systems, Inc.      *
  7    *                                                         *
  8    *********************************************************** */
  9 
 10 
 11 /* combine_tests runs on the statements produced by optimize_if's processing of
 12    an if statement.  It looks for consecutive tests on the same word and tries
 13    to combine them.  If 2 tests to the same word are found, the following
 14    equations are used:
 15 
 16    jump_true(target,r1), jump_true(target,r2) -> jump_true(target,and_bits(r,mask))
 17 
 18    jump_true(next,r1), jump_false(target,r2) -> jump_false(target,and_bits(r,mask))
 19 
 20    jump_false(next,r1), jump_true(target,r2) -> jump_if_eq(target,and_bits(r,mask),mask)
 21 
 22    jump_false(target,r1), jump_false(target,r2) -> jump_if_ne(target,and_bits(r,mask),mask)
 23 
 24 
 25    jump_true(target,r1), jump_true(target,and_bits(r2,mask1)) -> jump_true(target,and_bits(r,mask2))
 26 
 27    jump_true(next,r1), jump_false(target,and_bits(r2,mask1)) -> jump_false(target,and_bits(r,mask2))
 28 
 29    jump_false(next_r1), jump_if_eq(target,and_bits(r2,mask1),mask1) -> jump_if_eq(target,and_bits(r,mask2),mask2)
 30 
 31    jump_false(target,r1), jump_if_ne(target,and_bits(r2,mask1),mask1) -> jump_if_ne(target,and_bits(r,mask2),mask2)
 32 
 33    Initial Version: 17 January 1977 by Richard A. Barnes
 34           Modified: 9 March 1977 by RAB to change mod_word handling
 35           Modified: 9 March 1977 by RAB to remove some dead code
 36           Modified: 9 April 1977 to remove mod_word operator          */
 37 
 38 
 39 combine_tests: proc(first,last);
 40 
 41 dcl       first ptr,          /* first component of the if stmt */
 42           last ptr;           /* last component of the if stmt */
 43 
 44 dcl       (s1,s2,stop_ptr,r1,r2,o1,o2) ptr;
 45 dcl       (just_combined,is_next,is_target) bit(1) aligned;
 46 dcl       (opcode1,opcode2) bit(9) aligned;
 47 dcl       cfo(2) fixed bin(6);
 48 dcl       wo(2) fixed bin(18);
 49 dcl       based_bs bit(36) aligned based;
 50 dcl       mask bit(36) aligned auto;
 51 
 52 dcl       declare_temporary entry(bit(36) aligned,fixed bin(31),fixed bin(15),ptr) returns(ptr);
 53 dcl       generate_constant entry(bit(*) aligned,fixed bin) returns(ptr);
 54 dcl       create_operator entry(bit(9) aligned,fixed bin(15)) returns(ptr);
 55 dcl       create_reference entry(ptr) returns(ptr);
 56 dcl       share_expression entry(ptr) returns(ptr);
 57 dcl       adjust_ref_count entry(ptr,fixed bin);
 58 dcl       free_node entry(ptr);
 59 
 60 dcl       (divide,mod,null,substr) builtin;
 61 
 62 %include cgsystem;
 63 %include boundary;
 64 %include op_codes;
 65 %include nodes;
 66 %include label;
 67 %include list;
 68 %include symbol;
 69 %include reference;
 70 %include operator;
 71 %include statement;
 72 %include mask;
 73 
 74           just_combined = "0"b;
 75           stop_ptr = first;
 76 
 77           do s2 = last repeat s1 while (s2 ^= stop_ptr);
 78                s1 = s2 -> statement.back;
 79 
 80                if s2 -> statement.labels = null
 81                then do;
 82                     o2 = s2 -> statement.root;
 83                     opcode2 = o2 -> operator.op_code;
 84 
 85                     if just_combined
 86                     then r2 = o2 -> operand(2) -> operand(2);
 87                     else do;
 88                          if opcode2 ^= jump_true & opcode2 ^= jump_false
 89                               then goto next;
 90                          r2 = o2 -> operand(2);
 91                          if ^ candidate(r2)
 92                               then goto next;
 93                          end;
 94 
 95                     o1 = s1 -> statement.root;
 96                     r1 = o1 -> operand(2);
 97                     opcode1 = o1 -> operator.op_code;
 98 
 99                     if opcode1 = jump_true | opcode1 = jump_false
100                     then if candidate(r1)
101                     then if same_word(r1,r2)
102                     then do;
103                          is_target = o1 -> operand(1) = o2 -> operand(1);
104                          is_next = "0"b;
105                          if o1 -> operand(1) -> node.type = label_node
106                          then if o1 -> operand(1) -> label.statement = s2 -> statement.next
107                               then is_next = "1"b;
108 
109                          if just_combined
110                          then do;
111                               if opcode1 = jump_true
112                                         & ((opcode2 = jump_true & is_target) | (opcode2 = jump_false & is_next))
113                                | opcode1 = jump_false
114                                         & ((opcode2 = jump_if_eq & is_next) | (opcode2 = jump_if_ne & is_target))
115                               then do;
116                                    call continue_combining;
117                                    go to step;
118                                    end;
119                               end;
120 
121                          else do;
122                               if opcode1 = jump_true
123                               then if opcode2 = jump_true
124                                    then if is_target
125                                         then do;
126                                              call combine(jump_true,2);
127                                              go to step;
128                                              end;
129                                         else;
130                                    else if is_next
131                                         then do;
132                                              call combine(jump_false,2);
133                                              go to step;
134                                              end;
135                                         else;
136                               else if opcode2 = jump_true
137                                    then if is_next
138                                         then do;
139                                              call combine(jump_if_eq,3);
140                                              go to step;
141                                              end;
142                                         else;
143                                    else if is_target
144                                         then do;
145                                              call combine(jump_if_ne,3);
146                                              go to step;
147                                              end;
148                               end;
149                          end;
150                     end;
151 
152 next:          just_combined = "0"b;
153 step:
154                end;
155 
156           return;
157 
158 
159 candidate:     proc(p) returns(bit(1) aligned);
160 
161 dcl            p ptr;         /* ptr to node that might be a candidate */
162 
163                if p -> node.type = reference_node
164                then if p -> reference.c_length = 1
165                then if p -> reference.symbol -> symbol.packed
166                then if ^ p -> reference.fo_in_qual & ^ p -> reference.padded_ref & ^ p -> reference.aligned_ref
167                then if p -> reference.units = 0 | p -> reference.units = word_
168                      | p -> reference.offset = null | p -> reference.modword_in_offset
169                then return("1"b);
170 
171                return("0"b);
172 
173                end;
174 
175 
176 same_word:     proc(p1,p2) returns(bit(1) aligned);
177 
178 dcl            (p1,p2) ptr;
179 
180 dcl            (r(2),adam(2),a) ptr;
181 dcl            i fixed bin;
182 
183                r(1) = p1;
184                r(2) = p2;
185 
186                if r(1) -> reference.offset = r(2) -> reference.offset
187                 & r(1) -> reference.qualifier = r(2) -> reference.qualifier
188                then do;
189                     do i = 1 to 2;
190                          wo(i) = divide(r(i) -> reference.c_offset,units_per_word(r(i) -> reference.units),18,0);
191                          cfo(i) = mod(r(i) -> reference.c_offset * convert_offset(r(i) -> reference.units), bits_per_word);
192                          if cfo(i) ^= 0
193                          then if r(i) -> reference.c_offset < 0
194                               then wo(i) = wo(i) - 1;
195 
196                          do a = r(i) -> reference.symbol repeat a -> symbol.father
197                               while (a -> symbol.father ^= null);
198                               end;
199                          adam(i) = a;
200                          end;
201 
202                     if wo(1) = wo(2) & adam(1) = adam(2)
203                          then return("1"b);
204                     end;
205 
206                return("0"b);
207 
208                end;
209 
210 
211 continue_combining: proc;
212 
213 dcl            p ptr;
214 
215                mask = o2 -> operand(2) -> operand(3) -> reference.symbol -> symbol.initial -> based_bs;
216                substr(mask,cfo(1)+1,1) = "1"b;
217                p = generate_constant(mask,1);
218                o2 -> operand(2) -> operand(3) = p;
219                if o2 -> operator.number = 3
220                     then o2 -> operand(3) = p;
221 
222                call merge_and_unthread;
223 
224                just_combined = "1"b;
225 
226                end;
227 
228 
229 combine:       proc(op_code,num);
230 
231 dcl            op_code bit(9) aligned,
232                num fixed bin(15);
233 
234 dcl            (a,p,r,m) ptr;
235 
236                if num ^= 2
237                then do;
238                     p = create_operator(op_code,num);
239                     p -> operand(1) = o2 -> operand(1);
240                     call free_node(o2);
241                     o2 = p;
242                     end;
243                else /* o2 -> operator.op_code = op_code */ ;
244 
245                r = create_reference(null);
246                r -> reference = r2 -> reference;
247                if ^ r -> reference.shared
248                then do;
249                     r -> reference.ref_count = 1;
250                     if r -> reference.qualifier ^= null
251                          then r -> reference.qualifier = share_expression((r -> reference.qualifier));
252                     if r -> reference.offset ^= null
253                          then r -> reference.offset = share_expression((r -> reference.offset));
254                     call adjust_ref_count(r2,-1);
255                     end;
256 
257                r -> reference.c_length = bits_per_word;
258 
259                if r -> reference.units ^= 0 & r -> reference.units < word_
260                then do;
261                     r -> reference.units = word_;
262                     r -> reference.c_offset = wo(2);
263                     r -> reference.modword_in_offset = "0"b;
264                     end;
265 
266                a = create_operator(and_bits,3);
267                a -> operand(2) = r;
268                a -> operand(1) = declare_temporary(bit_mask|aligned_mask,(bits_per_word),0,null);
269 
270                mask = (36)"0"b;
271                substr(mask,cfo(1)+1,1) = "1"b;
272                substr(mask,cfo(2)+1,1) = "1"b;
273                p = generate_constant(mask,1);
274                a -> operand(3) = p;
275 
276                o2 -> operand(2) = a;
277                if num > 2
278                     then o2 -> operand(3) = p;
279 
280                call merge_and_unthread;
281 
282                just_combined = "1"b;
283 
284                end;
285 
286 
287 merge_and_unthread: proc;
288 
289                /* moves operator from s2 to s1, unthreads s2, and frees tree
290                   originally hanging from s1 */
291 
292                s1 -> statement.root = o2;
293                call free_node(s2);
294 
295                call decrement_target_expression((o1 -> operand(1)));
296                if ^ o1 -> operand(2) -> reference.shared
297                     then call adjust_ref_count((o1 -> operand(2)), -1);
298                call free_node(o1);
299 
300                end;
301 
302 
303 decrement_target_expression:  proc(pt);
304 
305 dcl            (p,pt,s,vector,l) ptr;
306 dcl            i fixed bin;
307 
308                /* operator_semantics has ensured that the target of a conditional
309                   jump will not be an operator nor a reference with expressions
310                   hanging off it */
311 
312                p = pt;
313 
314                if p -> node.type = label_node
315                then do;
316                     s = p -> label.statement;
317                     s -> statement.reference_count = s -> statement.reference_count - 1;
318                     return;
319                     end;
320 
321                if p -> node.type = reference_node
322                then if p -> reference.symbol ^= null
323                then if p -> reference.symbol -> node.type = label_node
324                then do;
325                     l = p -> reference.symbol;
326                     vector = l -> label.statement;
327 
328                     s = vector -> element(p -> reference.c_offset + 1);
329                     s -> statement.reference_count = s -> statement.reference_count - 1;
330                     end;
331 
332                call adjust_ref_count(p,-1);
333 
334                end;
335 
336           end;