001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt.lir2mir;
014
015import org.jikesrvm.VM;
016import org.jikesrvm.compilers.opt.OptimizingCompilerException;
017import org.jikesrvm.compilers.opt.ir.ALoad;
018import org.jikesrvm.compilers.opt.ir.AStore;
019import org.jikesrvm.compilers.opt.ir.Binary;
020import org.jikesrvm.compilers.opt.ir.Load;
021import org.jikesrvm.compilers.opt.ir.Instruction;
022import org.jikesrvm.compilers.opt.ir.Store;
023import org.jikesrvm.compilers.opt.ir.operand.DoubleConstantOperand;
024import org.jikesrvm.compilers.opt.ir.operand.FloatConstantOperand;
025import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
026import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
027import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand;
028import org.jikesrvm.compilers.opt.ir.operand.MemoryOperand;
029import org.jikesrvm.compilers.opt.ir.operand.Operand;
030import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
031import org.vmmagic.unboxed.Offset;
032import static org.jikesrvm.compilers.opt.ir.IRTools.TG;
033
034/**
035 * Contains common BURS helper functions for platforms with memory operands.
036 */
037public abstract class BURS_MemOp_Helpers extends BURS_Common_Helpers {
038  // word size for memory operands
039  protected static final byte B  = 0x01;  // byte (8 bits)
040  protected static final byte W  = 0x02;  // word (16 bits)
041  protected static final byte DW = 0x04;  // doubleword (32 bits)
042  protected static final byte QW = 0x08;  // quadword (64 bits)
043  protected static final byte PARAGRAPH = 0x10; // paragraph (128 bits)
044
045  protected static final byte B_S = 0x00;  // byte (8*2^0 bits)
046  protected static final byte W_S = 0x01;  // word (8*2^116 bits)
047  protected static final byte DW_S = 0x02;  // doubleword (8*2^2 bits)
048  protected static final byte QW_S = 0x03;  // quadword (8*2^3 bits)
049
050  protected BURS_MemOp_Helpers(BURS burs) {
051    super(burs);
052  }
053
054  // Cost functions better suited to grammars with multiple non-termials
055  protected static int ADDRESS_EQUAL(Instruction store, Instruction load, int trueCost) {
056    return ADDRESS_EQUAL(store, load, trueCost, INFINITE);
057  }
058
059  protected static int ADDRESS_EQUAL(Instruction store, Instruction load, int trueCost, int falseCost) {
060    if (Store.getAddress(store).similar(Load.getAddress(load)) &&
061        Store.getOffset(store).similar(Load.getOffset(load))) {
062      return trueCost;
063    } else {
064      return falseCost;
065    }
066  }
067
068  protected static int ARRAY_ADDRESS_EQUAL(Instruction store, Instruction load, int trueCost) {
069    return ARRAY_ADDRESS_EQUAL(store, load, trueCost, INFINITE);
070  }
071
072  protected static int ARRAY_ADDRESS_EQUAL(Instruction store, Instruction load, int trueCost, int falseCost) {
073    if (AStore.getArray(store).similar(ALoad.getArray(load)) && AStore.getIndex(store).similar(ALoad.getIndex(load))) {
074      return trueCost;
075    } else {
076      return falseCost;
077    }
078  }
079
080  // support to remember an address being computed in a subtree
081  private static final class AddrStackElement {
082    RegisterOperand base;
083    RegisterOperand index;
084    byte scale;
085    Offset displacement;
086    AddrStackElement next;
087
088    AddrStackElement(RegisterOperand b, RegisterOperand i, byte s, Offset d, AddrStackElement n) {
089      base = b;
090      index = i;
091      scale = s;
092      displacement = d;
093      next = n;
094    }
095  }
096
097  private AddrStackElement AddrStack;
098
099  protected final void pushAddress(RegisterOperand base, RegisterOperand index, byte scale, Offset disp) {
100    AddrStack = new AddrStackElement(base, index, scale, disp, AddrStack);
101  }
102
103  protected final void augmentAddress(Operand op) {
104    if (VM.VerifyAssertions) VM._assert(AddrStack != null, "No address to augment");
105    if (op.isRegister()) {
106      RegisterOperand rop = op.asRegister();
107      if (AddrStack.base == null) {
108        AddrStack.base = rop;
109      } else if (AddrStack.index == null) {
110        if (VM.VerifyAssertions) VM._assert(AddrStack.scale == (byte) 0);
111        AddrStack.index = rop;
112      } else {
113        throw new OptimizingCompilerException("three base registers in address");
114      }
115    } else {
116      if (VM.fullyBooted) {
117        if (VM.BuildFor64Addr && op instanceof IntConstantOperand)  throw new OptimizingCompilerException("augmenting int to address in 64bit code");
118        if (VM.BuildFor32Addr && op instanceof LongConstantOperand) throw new OptimizingCompilerException("augmenting long to address in 32bit code");
119      }
120      int disp = op instanceof LongConstantOperand ? (int)((LongConstantOperand) op).value : ((IntConstantOperand) op).value;
121      AddrStack.displacement = AddrStack.displacement.plus(disp);
122    }
123  }
124
125  protected final void combineAddresses() {
126    if (VM.VerifyAssertions) VM._assert(AddrStack != null, "No address to combine");
127    AddrStackElement tmp = AddrStack;
128    AddrStack = AddrStack.next;
129    if (VM.VerifyAssertions) VM._assert(AddrStack != null, "only 1 address to combine");
130    if (tmp.base != null) {
131      if (AddrStack.base == null) {
132        AddrStack.base = tmp.base;
133      } else if (AddrStack.index == null) {
134        if (VM.VerifyAssertions) VM._assert(AddrStack.scale == (byte) 0);
135        AddrStack.index = tmp.base;
136      } else {
137        throw new OptimizingCompilerException("three base registers in address");
138      }
139    }
140    if (tmp.index != null) {
141      if (AddrStack.index == null) {
142        if (VM.VerifyAssertions) VM._assert(AddrStack.scale == (byte) 0);
143        AddrStack.index = tmp.index;
144        AddrStack.scale = tmp.scale;
145      } else if (AddrStack.base == null && tmp.scale == (byte) 0) {
146        AddrStack.base = tmp.base;
147      } else {
148        throw new OptimizingCompilerException("two scaled registers in address");
149      }
150    }
151    AddrStack.displacement = AddrStack.displacement.plus(tmp.displacement.toInt());
152  }
153
154  protected final MemoryOperand consumeAddress(byte size, LocationOperand loc, Operand guard) {
155    if (VM.VerifyAssertions) VM._assert(AddrStack != null, "No address to consume");
156    MemoryOperand mo =
157        new MemoryOperand(AddrStack.base,
158                              AddrStack.index,
159                              AddrStack.scale,
160                              AddrStack.displacement,
161                              size,
162                              loc,
163                              guard);
164    AddrStack = AddrStack.next;
165    return mo;
166  }
167
168  // support to remember a memory operand computed in a subtree
169  private static final class MOStackElement {
170    MemoryOperand mo;
171    MOStackElement next;
172
173    MOStackElement(MemoryOperand m, MOStackElement n) {
174      mo = m;
175      next = n;
176    }
177  }
178
179  private MOStackElement MOStack;
180
181  protected final void pushMO(MemoryOperand mo) {
182    MOStack = new MOStackElement(mo, MOStack);
183  }
184
185  protected final MemoryOperand consumeMO() {
186    if (VM.VerifyAssertions) VM._assert(MOStack != null, "No memory operand to consume");
187    MemoryOperand mo = MOStack.mo;
188    MOStack = MOStack.next;
189    return mo;
190  }
191
192  protected final MemoryOperand MO_L(Instruction s, byte size) {
193    return MO_L(s, size, 0);
194  }
195
196  protected final MemoryOperand MO_L(Instruction s, byte size, int disp) {
197    if (VM.VerifyAssertions) VM._assert(Load.conforms(s));
198    return MO(Load.getAddress(s),
199              Load.getOffset(s),
200              size,
201              Offset.fromIntSignExtend(disp),
202              Load.getLocation(s),
203              Load.getGuard(s));
204  }
205
206  protected final MemoryOperand MO_S(Instruction s, byte size) {
207    return MO_S(s, size, 0);
208  }
209
210  protected final MemoryOperand MO_S(Instruction s, byte size, int disp) {
211    if (VM.VerifyAssertions) VM._assert(Store.conforms(s));
212    return MO(Store.getAddress(s),
213              Store.getOffset(s),
214              size,
215              Offset.fromIntSignExtend(disp),
216              Store.getLocation(s),
217              Store.getGuard(s));
218  }
219
220  protected final MemoryOperand MO(Operand base, Operand offset, byte size, LocationOperand loc,
221                                       Operand guard) {
222    if (VM.BuildFor32Addr) {
223      if (base instanceof IntConstantOperand) {
224        if (offset instanceof IntConstantOperand) {
225          return MO_D(Offset.fromIntSignExtend(IV(base) + IV(offset)), size, loc, guard);
226        } else {
227          return MO_BD(offset, Offset.fromIntSignExtend(IV(base)), size, loc, guard);
228        }
229      } else {
230        if (offset instanceof IntConstantOperand) {
231          return MO_BD(base, Offset.fromIntSignExtend(IV(offset)), size, loc, guard);
232        } else {
233          return MO_BI(base, offset, size, loc, guard);
234        }
235      }
236    } else {
237      if (base instanceof LongConstantOperand) {
238        if (offset instanceof LongConstantOperand) {
239          return MO_D(Offset.fromLong(LV(base) + LV(offset)), size, loc, guard);
240        } else if (offset instanceof IntConstantOperand) {
241          return MO_D(Offset.fromLong(LV(base) + IV(offset)), size, loc, guard);
242        } else {
243          return MO_BD(offset, Offset.fromLong(LV(base)), size, loc, guard);
244        }
245      } else if (base instanceof IntConstantOperand) {
246        if (offset instanceof IntConstantOperand) {
247          return MO_D(Offset.fromIntSignExtend(IV(base) + IV(offset)), size, loc, guard);
248        } else if (offset instanceof LongConstantOperand) {
249          return MO_D(Offset.fromLong(IV(base) + LV(offset)), size, loc, guard);
250        } else {
251          return MO_BD(offset, Offset.fromIntSignExtend(IV(base)), size, loc, guard);
252        }
253      } else {
254        if (offset instanceof LongConstantOperand) {
255          return MO_BD(base, Offset.fromLong(LV(offset)), size, loc, guard);
256        } else if (offset instanceof IntConstantOperand) {
257          return MO_BD(base, Offset.fromIntSignExtend(IV(offset)), size, loc, guard);
258        } else {
259          return MO_BI(base, offset, size, loc, guard);
260        }
261      }
262    }
263  }
264
265  protected final MemoryOperand MO(Operand base, Operand offset, byte size, LocationOperand loc,
266      Operand guard, int disp) {
267    if (VM.BuildFor32Addr) {
268      if (base instanceof IntConstantOperand) {
269        if (offset instanceof IntConstantOperand) {
270          return MO_D(Offset.fromIntSignExtend(IV(base) + IV(offset) + disp), size, loc, guard);
271        } else {
272          return MO_BD(offset, Offset.fromIntSignExtend(IV(base) + disp), size, loc, guard);
273        }
274      } else {
275        if (offset instanceof IntConstantOperand) {
276          return MO_BD(base, Offset.fromIntSignExtend(IV(offset) + disp), size, loc, guard);
277        } else {
278          return MO_BID(base, offset, Offset.fromIntSignExtend(disp), size, loc, guard);
279        }
280      }
281    } else {
282      if (base instanceof LongConstantOperand) {
283        if (offset instanceof LongConstantOperand) {
284          return MO_D(Offset.fromLong(LV(base) + LV(offset) + disp), size, loc, guard);
285        } else if (offset instanceof IntConstantOperand) {
286          return MO_D(Offset.fromLong(LV(base) + IV(offset) + disp), size, loc, guard);
287        } else {
288          return MO_BD(offset, Offset.fromLong(LV(base) + disp), size, loc, guard);
289        }
290      } else if (base instanceof IntConstantOperand) {
291        if (offset instanceof LongConstantOperand) {
292          return MO_D(Offset.fromLong(IV(base) + LV(offset) + disp), size, loc, guard);
293        } else if (offset instanceof IntConstantOperand) {
294          return MO_D(Offset.fromIntSignExtend(IV(base) + IV(offset) + disp), size, loc, guard);
295        } else {
296          return MO_BD(offset, Offset.fromIntSignExtend(IV(base) + disp), size, loc, guard);
297        }
298      } else {
299        if (offset instanceof LongConstantOperand) {
300          return MO_BD(base, Offset.fromLong(LV(offset) + disp), size, loc, guard);
301        } else if (offset instanceof IntConstantOperand) {
302          return MO_BD(base, Offset.fromIntSignExtend(IV(offset) + disp), size, loc, guard);
303        } else {
304          return MO_BID(base, offset, Offset.fromIntSignExtend(disp), size, loc, guard);
305        }
306      }
307    }
308  }
309
310  protected final MemoryOperand MO(Operand base, Operand offset, byte size, Offset disp,
311                                       LocationOperand loc, Operand guard) {
312    if (VM.BuildFor32Addr) {
313      if (base instanceof IntConstantOperand) {
314        if (offset instanceof IntConstantOperand) {
315          return MO_D(disp.plus(IV(base) + IV(offset)), size, loc, guard);
316        } else {
317          return MO_BD(offset, disp.plus(IV(base)), size, loc, guard);
318        }
319      } else {
320        if (offset instanceof IntConstantOperand) {
321          return MO_BD(base, disp.plus(IV(offset)), size, loc, guard);
322        } else {
323          return MO_BID(base, offset, disp, size, loc, guard);
324        }
325      }
326    } else {
327      if (base instanceof LongConstantOperand) {
328        if (offset instanceof LongConstantOperand) {
329          return MO_D(Offset.fromLong(disp.toLong() + LV(base) + LV(offset)), size, loc, guard);
330        } else if (offset instanceof IntConstantOperand) {
331          return MO_D(Offset.fromLong(disp.toLong() + LV(base) + IV(offset)), size, loc, guard);
332        } else {
333          return MO_BD(offset, Offset.fromLong(disp.toLong() + LV(base)), size, loc, guard);
334        }
335      } else if (base instanceof IntConstantOperand) {
336        if (offset instanceof LongConstantOperand) {
337          return MO_D(Offset.fromLong(disp.toLong() + IV(base) + LV(offset)), size, loc, guard);
338        } else if (offset instanceof IntConstantOperand) {
339          return MO_D(disp.plus(IV(base) + IV(offset)), size, loc, guard);
340        } else {
341          return MO_BD(offset, disp.plus(IV(base)), size, loc, guard);
342        }
343      } else {
344        if (offset instanceof LongConstantOperand) {
345          return MO_BD(base, disp.plus(Offset.fromLong(LV(offset))), size, loc, guard);
346        } else if (offset instanceof IntConstantOperand) {
347          return MO_BD(base, disp.plus(IV(offset)), size, loc, guard);
348        } else {
349          return MO_BID(base, offset, disp, size, loc, guard);
350        }
351      }
352    }
353  }
354
355
356  protected final MemoryOperand MO_B(Operand base, byte size, LocationOperand loc, Operand guard) {
357    return MemoryOperand.B(R(base), size, loc, guard);
358  }
359
360  protected final MemoryOperand MO_BI(Operand base, Operand index, byte size, LocationOperand loc,
361                                          Operand guard) {
362    return MemoryOperand.BI(R(base), R(index), size, loc, guard);
363  }
364
365  protected final MemoryOperand MO_BD(Operand base, Offset disp, byte size, LocationOperand loc,
366                                          Operand guard) {
367    return MemoryOperand.BD(R(base), disp, size, loc, guard);
368  }
369
370  protected final MemoryOperand MO_BID(Operand base, Operand index, Offset disp, byte size,
371                                           LocationOperand loc, Operand guard) {
372    return MemoryOperand.BID(R(base), R(index), disp, size, loc, guard);
373  }
374
375  protected final MemoryOperand MO_BIS(Operand base, Operand index, byte scale, byte size,
376                                           LocationOperand loc, Operand guard) {
377    return MemoryOperand.BIS(R(base), R(index), scale, size, loc, guard);
378  }
379
380  protected final MemoryOperand MO_D(Offset disp, byte size, LocationOperand loc, Operand guard) {
381    return MemoryOperand.D(disp.toWord().toAddress(), size, loc, guard);
382  }
383
384  protected final MemoryOperand MO_AL(Instruction s, byte scale, byte size) {
385    return MO_AL(s, scale, size, 0);
386  }
387
388  protected final MemoryOperand MO_AL(Instruction s, byte scale, byte size, int disp) {
389    if (VM.VerifyAssertions) VM._assert(ALoad.conforms(s));
390    return MO_ARRAY(ALoad.getArray(s),
391                    ALoad.getIndex(s),
392                    scale,
393                    size,
394                    Offset.fromIntSignExtend(disp),
395                    ALoad.getLocation(s),
396                    ALoad.getGuard(s));
397  }
398
399  protected final MemoryOperand MO_AS(Instruction s, byte scale, byte size) {
400    return MO_AS(s, scale, size, 0);
401  }
402
403
404  protected final MemoryOperand MO_AS(Instruction s, byte scale, byte size, int disp) {
405    if (VM.VerifyAssertions) VM._assert(AStore.conforms(s));
406    return MO_ARRAY(AStore.getArray(s),
407                    AStore.getIndex(s),
408                    scale,
409                    size,
410                    Offset.fromIntSignExtend(disp),
411                    AStore.getLocation(s),
412                    AStore.getGuard(s));
413  }
414
415  private MemoryOperand MO_ARRAY(Operand base, Operand index, byte scale, byte size, Offset disp,
416                                             LocationOperand loc, Operand guard) {
417    if (index instanceof IntConstantOperand) {
418      if (VM.BuildFor32Addr && base instanceof IntConstantOperand) {
419        return MO_D(disp.plus(IV(base) + (IV(index) << scale)), size, loc, guard);
420      } else if (VM.BuildFor64Addr && base instanceof LongConstantOperand) {
421        return MO_D(disp.plus(Offset.fromLong(LV(base) + (IV(index) << scale))), size, loc, guard);
422      } else {
423        return MO_BD(base, disp.plus(IV(index) << scale), size, loc, guard);
424      }
425    } else {
426      if (VM.BuildFor32Addr && base instanceof IntConstantOperand) {
427        return new MemoryOperand(null, R(index), scale, disp.plus(IV(base)), size, loc, guard);
428      } else if (VM.BuildFor64Addr && base instanceof LongConstantOperand) {
429        return new MemoryOperand(null, R(index), scale, disp.plus(Offset.fromLong(LV(base))), size, loc, guard);
430      } else {
431        return new MemoryOperand(R(base), R(index), scale, disp, size, loc, guard);
432      }
433    }
434  }
435
436  protected final MemoryOperand MO_MC(Instruction s) {
437    Operand base = Binary.getVal1(s); // JTOC
438    Operand val = Binary.getVal2(s); // float or double value
439    if (val instanceof FloatConstantOperand) {
440      FloatConstantOperand fc = (FloatConstantOperand) val;
441      Offset offset = fc.offset;
442      LocationOperand loc = new LocationOperand(offset);
443      if (base instanceof IntConstantOperand) {
444        return MO_D(offset.plus(IV(base)), DW, loc, TG());
445      } else if (VM.BuildFor64Addr && base instanceof LongConstantOperand) {
446        return MO_D(offset.plus(Offset.fromLong(LV(base))), DW, loc, TG());
447      } else {
448        return MO_BD(base, offset, DW, loc, TG());
449      }
450    } else {
451      DoubleConstantOperand dc = (DoubleConstantOperand) val;
452      Offset offset = dc.offset;
453      LocationOperand loc = new LocationOperand(offset);
454      if (base instanceof IntConstantOperand) {
455        return MO_D(offset.plus(IV(base)), QW, loc, TG());
456      } else if (VM.BuildFor64Addr && base instanceof LongConstantOperand) {
457        return MO_D(offset.plus(Offset.fromLong(LV(base))), QW, loc, TG());
458      } else {
459        return MO_BD(Binary.getVal1(s), dc.offset, QW, loc, TG());
460      }
461    }
462  }
463}