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