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.regalloc.ia32;
014    
015    import java.util.ArrayList;
016    import java.util.Enumeration;
017    import org.jikesrvm.VM;
018    import org.jikesrvm.ArchitectureSpecificOpt.PhysicalRegisterSet;
019    import org.jikesrvm.compilers.opt.ir.MIR_BinaryAcc;
020    import org.jikesrvm.compilers.opt.ir.MIR_CacheOp;
021    import org.jikesrvm.compilers.opt.ir.MIR_Compare;
022    import org.jikesrvm.compilers.opt.ir.MIR_CondMove;
023    import org.jikesrvm.compilers.opt.ir.MIR_DoubleShift;
024    import org.jikesrvm.compilers.opt.ir.MIR_LowTableSwitch;
025    import org.jikesrvm.compilers.opt.ir.MIR_Move;
026    import org.jikesrvm.compilers.opt.ir.MIR_Set;
027    import org.jikesrvm.compilers.opt.ir.MIR_Test;
028    import org.jikesrvm.compilers.opt.ir.MIR_Unary;
029    import org.jikesrvm.compilers.opt.ir.MIR_UnaryNoRes;
030    import org.jikesrvm.compilers.opt.ir.BasicBlock;
031    import org.jikesrvm.compilers.opt.ir.Instruction;
032    import org.jikesrvm.compilers.opt.ir.Operators;
033    import org.jikesrvm.compilers.opt.ir.Register;
034    import org.jikesrvm.compilers.opt.ir.operand.MemoryOperand;
035    import org.jikesrvm.compilers.opt.ir.operand.Operand;
036    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
037    import org.jikesrvm.compilers.opt.ir.operand.ia32.BURSManagedFPROperand;
038    import org.jikesrvm.compilers.opt.regalloc.GenericRegisterRestrictions;
039    import org.jikesrvm.compilers.opt.regalloc.LiveIntervalElement;
040    
041    /**
042     * An instance of this class encapsulates restrictions on register
043     * assignment.
044     */
045    public class RegisterRestrictions extends GenericRegisterRestrictions
046        implements Operators, PhysicalRegisterConstants {
047    
048      /**
049       * Allow scratch registers in PEIs?
050       */
051      public static final boolean SCRATCH_IN_PEI = true;
052    
053      /**
054       * Default Constructor
055       */
056      protected RegisterRestrictions(PhysicalRegisterSet phys) {
057        super(phys);
058      }
059    
060      @Override
061      public void addArchRestrictions(BasicBlock bb, ArrayList<LiveIntervalElement> symbolics) {
062        // If there are any registers used in catch blocks, we want to ensure
063        // that these registers are not used or evicted from scratch registers
064        // at a relevant PEI, so that the assumptions of register homes in the
065        // catch block remain valid.  For now, we do this by forcing any
066        // register used in such a PEI as not spilled.  TODO: relax this
067        // restriction for better code.
068        for (Enumeration<Instruction> ie = bb.forwardInstrEnumerator(); ie.hasMoreElements();) {
069          Instruction s = ie.nextElement();
070          if (s.isPEI() && s.operator != IR_PROLOGUE) {
071            if (bb.hasApplicableExceptionalOut(s) || !SCRATCH_IN_PEI) {
072              for (Enumeration<Operand> e = s.getOperands(); e.hasMoreElements();) {
073                Operand op = e.nextElement();
074                if (op != null && op.isRegister()) {
075                  noteMustNotSpill(op.asRegister().getRegister());
076                  handle8BitRestrictions(s);
077                }
078              }
079            }
080          }
081    
082          // handle special cases
083          switch (s.getOpcode()) {
084            case MIR_LOWTABLESWITCH_opcode: {
085              RegisterOperand op = MIR_LowTableSwitch.getMethodStart(s);
086              noteMustNotSpill(op.getRegister());
087              op = MIR_LowTableSwitch.getIndex(s);
088              noteMustNotSpill(op.getRegister());
089            }
090            break;
091            case IA32_MOVZX__B_opcode:
092            case IA32_MOVSX__B_opcode: {
093              if (MIR_Unary.getVal(s).isRegister()) {
094                RegisterOperand val = MIR_Unary.getVal(s).asRegister();
095                restrictTo8Bits(val.getRegister());
096              }
097            }
098            break;
099            case IA32_SET__B_opcode: {
100              if (MIR_Set.getResult(s).isRegister()) {
101                RegisterOperand op = MIR_Set.getResult(s).asRegister();
102                restrictTo8Bits(op.getRegister());
103              }
104            }
105            break;
106    
107            default:
108              handle8BitRestrictions(s);
109              break;
110          }
111        }
112        for (Enumeration<Instruction> ie = bb.forwardInstrEnumerator(); ie.hasMoreElements();) {
113          Instruction s = ie.nextElement();
114          if (s.operator == IA32_FNINIT) {
115            // No floating point register survives across an FNINIT
116            for (LiveIntervalElement symb : symbolics) {
117              if (symb.getRegister().isFloatingPoint()) {
118                if (contains(symb, s.scratch)) {
119                  addRestrictions(symb.getRegister(), phys.getFPRs());
120                }
121              }
122            }
123          } else if (s.operator == IA32_FCLEAR) {
124            // Only some FPRs survive across an FCLEAR
125            for (LiveIntervalElement symb : symbolics) {
126              if (symb.getRegister().isFloatingPoint()) {
127                if (contains(symb, s.scratch)) {
128                  int nSave = MIR_UnaryNoRes.getVal(s).asIntConstant().value;
129                  for (int i = nSave; i < NUM_FPRS; i++) {
130                    addRestriction(symb.getRegister(), phys.getFPR(i));
131                  }
132                }
133              }
134            }
135          }
136        }
137      }
138    
139      /**
140       * Does instruction s contain an 8-bit memory operand?
141       */
142      final boolean has8BitMemoryOperand(Instruction s) {
143        for (Enumeration<Operand> me = s.getMemoryOperands(); me.hasMoreElements();) {
144          MemoryOperand mop = (MemoryOperand) me.nextElement();
145          if (mop.size == 1) {
146            return true;
147          }
148        }
149        return false;
150      }
151    
152      /**
153       * Ensure that if an operand has an 8 bit memory operand that
154       * all of its register operands are in 8 bit registers.
155       * @param s the instruction to restrict
156       */
157      final void handle8BitRestrictions(Instruction s) {
158        for (Enumeration<Operand> me = s.getMemoryOperands(); me.hasMoreElements();) {
159          MemoryOperand mop = (MemoryOperand) me.nextElement();
160          if (mop.size == 1) {
161            for (Enumeration<Operand> e2 = s.getRootOperands(); e2.hasMoreElements();) {
162              Operand rootOp = e2.nextElement();
163              if (rootOp.isRegister()) {
164                restrictTo8Bits(rootOp.asRegister().getRegister());
165              }
166            }
167          }
168        }
169      }
170    
171      /**
172       * Ensure that a particular register is only assigned to AL, BL, CL, or
173       * DL, since these are the only 8-bit registers we normally address.
174       */
175      final void restrictTo8Bits(Register r) {
176        Register ESP = phys.getESP();
177        Register EBP = phys.getEBP();
178        Register ESI = phys.getESI();
179        Register EDI = phys.getEDI();
180        addRestriction(r, ESP);
181        addRestriction(r, EBP);
182        addRestriction(r, ESI);
183        addRestriction(r, EDI);
184      }
185    
186      /**
187       * Given symbolic register r that appears in instruction s, does the
188       * architecture demand that r be assigned to a physical register in s?
189       */
190      public static boolean mustBeInRegister(Register r, Instruction s) {
191        switch (s.getOpcode()) {
192          case IA32_PREFETCHNTA_opcode: {
193            RegisterOperand op = MIR_CacheOp.getAddress(s).asRegister();
194            if (op.register == r) return true;
195          }
196          break;
197    
198          case IA32_SQRTSS_opcode:
199          case IA32_SQRTSD_opcode:
200          case IA32_CVTSD2SI_opcode:
201          case IA32_CVTSD2SS_opcode:
202          case IA32_CVTSI2SD_opcode:
203          case IA32_CVTSS2SD_opcode:
204          case IA32_CVTSS2SI_opcode:
205          case IA32_CVTTSD2SI_opcode:
206          case IA32_CVTTSS2SI_opcode:
207          case IA32_CVTSI2SS_opcode: {
208            RegisterOperand op = MIR_Unary.getResult(s).asRegister();
209            if (op.getRegister() == r) return true;
210          }
211          break;
212    
213          // Instructions that require 16byte alignment (not guaranteed by our
214          // spills) must be forced to always use registers
215          case IA32_ANDPS_opcode:
216          case IA32_ANDNPS_opcode:
217          case IA32_ORPS_opcode:
218          case IA32_XORPS_opcode:
219          case IA32_ANDPD_opcode:
220          case IA32_ANDNPD_opcode:
221          case IA32_ORPD_opcode:
222          case IA32_XORPD_opcode:
223            return true;
224    
225          case IA32_ADDSS_opcode:
226          case IA32_CMPEQSS_opcode:
227          case IA32_CMPLTSS_opcode:
228          case IA32_CMPLESS_opcode:
229          case IA32_CMPUNORDSS_opcode:
230          case IA32_CMPNESS_opcode:
231          case IA32_CMPNLTSS_opcode:
232          case IA32_CMPNLESS_opcode:
233          case IA32_CMPORDSS_opcode:
234          case IA32_DIVSS_opcode:
235          case IA32_MULSS_opcode:
236          case IA32_SUBSS_opcode:
237          case IA32_ADDSD_opcode:
238          case IA32_CMPEQSD_opcode:
239          case IA32_CMPLTSD_opcode:
240          case IA32_CMPLESD_opcode:
241          case IA32_CMPUNORDSD_opcode:
242          case IA32_CMPNESD_opcode:
243          case IA32_CMPNLTSD_opcode:
244          case IA32_CMPNLESD_opcode:
245          case IA32_CMPORDSD_opcode:
246          case IA32_DIVSD_opcode:
247          case IA32_MULSD_opcode:
248          case IA32_SUBSD_opcode: {
249            RegisterOperand op = MIR_BinaryAcc.getResult(s).asRegister();
250            if (op.getRegister() == r) return true;
251          }
252          break;
253    
254          case IA32_UCOMISD_opcode:
255          case IA32_UCOMISS_opcode: {
256            RegisterOperand op = MIR_Compare.getVal1(s).asRegister();
257            if (op.getRegister() == r) return true;
258          }
259          break;
260    
261          case IA32_SHRD_opcode:
262          case IA32_SHLD_opcode: {
263            RegisterOperand op = MIR_DoubleShift.getSource(s);
264            if (op.getRegister() == r) return true;
265          }
266          break;
267          case IA32_FCOMI_opcode:
268          case IA32_FCOMIP_opcode: {
269            Operand op = MIR_Compare.getVal2(s);
270            if (!(op instanceof BURSManagedFPROperand)) {
271              if (op.asRegister().getRegister() == r) return true;
272            }
273          }
274          break;
275          case IA32_IMUL2_opcode: {
276            RegisterOperand op = MIR_BinaryAcc.getResult(s).asRegister();
277            if (op.getRegister() == r) return true;
278          }
279          break;
280          case MIR_LOWTABLESWITCH_opcode: {
281            RegisterOperand op = MIR_LowTableSwitch.getIndex(s);
282            if (op.getRegister() == r) return true;
283          }
284          break;
285          case IA32_CMOV_opcode:
286          case IA32_FCMOV_opcode: {
287            RegisterOperand op = MIR_CondMove.getResult(s).asRegister();
288            if (op.getRegister() == r) return true;
289          }
290          break;
291          case IA32_MOVD_opcode: {
292            RegisterOperand res = MIR_Move.getResult(s).asRegister();
293            if (!res.isFloat() && !res.isDouble()) {
294              // result is integer so source must be MM/XMM register and
295              // result must remain a register
296              if (VM.VerifyAssertions) {
297                Operand val = MIR_Move.getValue(s);
298                VM._assert(val.isRegister() && (val.isFloat() || val.isDouble()));
299              }
300              return true;
301            }
302            Operand val = MIR_Move.getValue(s);
303            if (!val.isFloat() && !val.isDouble()) {
304              // source is integer so destination must be MM/XMM register and
305              // source must remain a register
306              if (VM.VerifyAssertions) {
307                VM._assert(res.isRegister() && (res.isFloat() || res.isDouble()));
308              }
309              return true;
310            }
311          }
312          break;
313          case IA32_MOVZX__B_opcode:
314          case IA32_MOVSX__B_opcode: {
315            RegisterOperand op = MIR_Unary.getResult(s).asRegister();
316            if (op.getRegister() == r) return true;
317          }
318          break;
319          case IA32_MOVZX__W_opcode:
320          case IA32_MOVSX__W_opcode: {
321            RegisterOperand op = MIR_Unary.getResult(s).asRegister();
322            if (op.getRegister() == r) return true;
323          }
324          break;
325          case IA32_SET__B_opcode: {
326            if (MIR_Set.getResult(s).isRegister()) {
327              RegisterOperand op = MIR_Set.getResult(s).asRegister();
328              if (op.asRegister().getRegister() == r) return true;
329            }
330          }
331          break;
332          case IA32_TEST_opcode: {
333            // at least 1 of the two operands must be in a register
334            if (!MIR_Test.getVal2(s).isConstant()) {
335              if (MIR_Test.getVal1(s).isRegister()) {
336                if (MIR_Test.getVal1(s).asRegister().getRegister() == r) return true;
337              } else if (MIR_Test.getVal2(s).isRegister()) {
338                if (MIR_Test.getVal2(s).asRegister().getRegister() == r) return true;
339              }
340            }
341          }
342          break;
343          case IA32_BT_opcode: {
344            // val2 of bit test must be either a constant or register
345            if (!MIR_Test.getVal2(s).isConstant()) {
346              if (MIR_Test.getVal2(s).isRegister()) {
347                if (MIR_Test.getVal2(s).asRegister().getRegister() == r) return true;
348              }
349            }
350          }
351          break;
352    
353          default:
354            break;
355        }
356        return false;
357      }
358    
359      /**
360       * Can physical register r hold an 8-bit value?
361       */
362      private boolean okFor8(Register r) {
363        Register ESP = phys.getESP();
364        Register EBP = phys.getEBP();
365        Register ESI = phys.getESI();
366        Register EDI = phys.getEDI();
367        return (r != ESP && r != EBP && r != ESI && r != EDI);
368      }
369    
370      @Override
371      public boolean isForbidden(Register symb, Register r, Instruction s) {
372    
373        // Look at 8-bit restrictions.
374        switch (s.operator.opcode) {
375          case IA32_MOVZX__B_opcode:
376          case IA32_MOVSX__B_opcode: {
377            if (MIR_Unary.getVal(s).isRegister()) {
378              RegisterOperand val = MIR_Unary.getVal(s).asRegister();
379              if (val.getRegister() == symb) {
380                return !okFor8(r);
381              }
382            }
383          }
384          break;
385          case IA32_SET__B_opcode: {
386            if (MIR_Set.getResult(s).isRegister()) {
387              RegisterOperand op = MIR_Set.getResult(s).asRegister();
388              if (op.asRegister().getRegister() == symb) {
389                return !okFor8(r);
390              }
391            }
392          }
393          break;
394        }
395    
396        if (has8BitMemoryOperand(s)) {
397          return !okFor8(r);
398        }
399    
400        // Otherwise, it's OK.
401        return false;
402      }
403    }