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.ir.ia32;
014    
015    import java.util.Enumeration;
016    
017    import org.jikesrvm.VM;
018    import org.jikesrvm.classloader.TypeReference;
019    import org.jikesrvm.compilers.opt.OptimizingCompilerException;
020    import org.jikesrvm.compilers.opt.ir.Empty;
021    import org.jikesrvm.compilers.opt.ir.MIR_CondBranch;
022    import org.jikesrvm.compilers.opt.ir.MIR_CondBranch2;
023    import org.jikesrvm.compilers.opt.ir.MIR_Move;
024    import org.jikesrvm.compilers.opt.ir.BasicBlock;
025    import org.jikesrvm.compilers.opt.ir.IR;
026    import org.jikesrvm.compilers.opt.ir.Instruction;
027    import org.jikesrvm.compilers.opt.ir.MachineSpecificIR;
028    import org.jikesrvm.compilers.opt.ir.Operator;
029    import static org.jikesrvm.compilers.opt.ir.Operators.ADVISE_ESP;
030    import static org.jikesrvm.compilers.opt.ir.Operators.DUMMY_DEF;
031    import static org.jikesrvm.compilers.opt.ir.Operators.DUMMY_USE;
032    import static org.jikesrvm.compilers.opt.ir.Operators.GET_CURRENT_PROCESSOR_opcode;
033    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FCLEAR;
034    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FMOV;
035    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FMOV_ENDING_LIVE_RANGE;
036    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FNINIT;
037    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_JCC;
038    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_2ADDR_opcode;
039    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ADD_opcode;
040    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_AND_opcode;
041    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_MOVE_opcode;
042    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_NEG_opcode;
043    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_OR_opcode;
044    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SHL_opcode;
045    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SHR_opcode;
046    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SUB_opcode;
047    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_USHR_opcode;
048    import static org.jikesrvm.compilers.opt.ir.Operators.LONG_XOR_opcode;
049    import static org.jikesrvm.compilers.opt.ir.Operators.NOP;
050    import static org.jikesrvm.compilers.opt.ir.Operators.PREFETCH_opcode;
051    import org.jikesrvm.compilers.opt.ir.Register;
052    import org.jikesrvm.compilers.opt.ir.operand.Operand;
053    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
054    import org.jikesrvm.compilers.opt.ir.operand.ia32.BURSManagedFPROperand;
055    import org.jikesrvm.compilers.opt.ir.operand.ia32.IA32ConditionOperand;
056    import org.jikesrvm.compilers.opt.regalloc.LiveIntervalElement;
057    
058    /**
059     * Wrappers around IA32-specific IR common to both 32 & 64 bit
060     */
061    public abstract class MachineSpecificIRIA extends MachineSpecificIR {
062    
063      /**
064       * Wrappers around IA32-specific IR (32-bit specific)
065       */
066      public static final class IA32 extends MachineSpecificIRIA {
067        public static final IA32 singleton = new IA32();
068    
069        /* common to all ISAs */
070        @Override
071        public boolean mayEscapeThread(Instruction instruction) {
072          switch (instruction.getOpcode()) {
073            case PREFETCH_opcode:
074              return false;
075            case GET_CURRENT_PROCESSOR_opcode:
076              return true;
077            default:
078              throw new OptimizingCompilerException("SimpleEscape: Unexpected " + instruction);
079          }
080        }
081    
082        @Override
083        public boolean mayEscapeMethod(Instruction instruction) {
084          return mayEscapeThread(instruction); // at this stage we're no more specific
085        }
086      }
087    
088      /**
089       * Wrappers around EMT64-specific IR (64-bit specific)
090       */
091      public static final class EM64T extends MachineSpecificIRIA {
092        public static final EM64T singleton = new EM64T();
093    
094        /* common to all ISAs */
095        @Override
096        public boolean mayEscapeThread(Instruction instruction) {
097          switch (instruction.getOpcode()) {
098            case PREFETCH_opcode:
099              return false;
100            case GET_CURRENT_PROCESSOR_opcode:
101            case LONG_OR_opcode:
102            case LONG_AND_opcode:
103            case LONG_XOR_opcode:
104            case LONG_SUB_opcode:
105            case LONG_SHL_opcode:
106            case LONG_ADD_opcode:
107            case LONG_SHR_opcode:
108            case LONG_USHR_opcode:
109            case LONG_NEG_opcode:
110            case LONG_MOVE_opcode:
111            case LONG_2ADDR_opcode:
112              return true;
113            default:
114              throw new OptimizingCompilerException("SimpleEscapge: Unexpected " + instruction);
115          }
116        }
117    
118        @Override
119        public boolean mayEscapeMethod(Instruction instruction) {
120          return mayEscapeThread(instruction); // at this stage we're no more specific
121        }
122      }
123    
124      /*
125      * Generic (32/64 neutral) IA support
126      */
127    
128      /* common to all ISAs */
129    
130      @Override
131      public boolean isConditionOperand(Operand operand) {
132        return operand instanceof IA32ConditionOperand;
133      }
134    
135      @Override
136      public void mutateMIRCondBranch(Instruction cb) {
137        MIR_CondBranch.mutate(cb,
138                              IA32_JCC,
139                              MIR_CondBranch2.getCond1(cb),
140                              MIR_CondBranch2.getTarget1(cb),
141                              MIR_CondBranch2.getBranchProfile1(cb));
142      }
143    
144      @Override
145      public boolean isHandledByRegisterUnknown(char opcode) {
146        return (opcode == PREFETCH_opcode);
147      }
148    
149      /* unique to IA */
150      @Override
151      public boolean isAdviseESP(Operator operator) {
152        return operator == ADVISE_ESP;
153      }
154    
155      @Override
156      public boolean isFClear(Operator operator) {
157        return operator == IA32_FCLEAR;
158      }
159    
160      @Override
161      public boolean isFNInit(Operator operator) {
162        return operator == IA32_FNINIT;
163      }
164    
165      @Override
166      public boolean isBURSManagedFPROperand(Operand operand) {
167        return operand instanceof BURSManagedFPROperand;
168      }
169    
170      @Override
171      public int getBURSManagedFPRValue(Operand operand) {
172        return ((BURSManagedFPROperand) operand).regNum;
173      }
174    
175      /**
176       * Mutate FMOVs that end live ranges
177       *
178       * @param live The live interval for a basic block/reg pair
179       * @param register The register for this live interval
180       * @param dfnbegin The (adjusted) begin for this interval
181       * @param dfnend The (adjusted) end for this interval
182       */
183      @Override
184      public boolean mutateFMOVs(LiveIntervalElement live, Register register, int dfnbegin, int dfnend) {
185        Instruction end = live.getEnd();
186        if (end != null && end.operator == IA32_FMOV) {
187          if (dfnend == dfnbegin) {
188            // if end, an FMOV, both begins and ends the live range,
189            // then end is dead.  Change it to a NOP and return null.
190            Empty.mutate(end, NOP);
191            return false;
192          } else {
193            if (!end.isPEI()) {
194              if (VM.VerifyAssertions) {
195                Operand value = MIR_Move.getValue(end);
196                VM._assert(value.isRegister());
197                VM._assert(MIR_Move.getValue(end).asRegister().getRegister() == register);
198              }
199              end.operator = IA32_FMOV_ENDING_LIVE_RANGE;
200            }
201          }
202        }
203        return true;
204      }
205    
206      /**
207       *  Rewrite floating point registers to reflect changes in stack
208       *  height induced by BURS.
209       *
210       *  Side effect: update the fpStackHeight in MIRInfo
211       */
212      @Override
213      public void rewriteFPStack(IR ir) {
214        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
215        for (Enumeration<BasicBlock> b = ir.getBasicBlocks(); b.hasMoreElements();) {
216          BasicBlock bb = b.nextElement();
217    
218          // The following holds the floating point stack offset from its
219          // 'normal' position.
220          int fpStackOffset = 0;
221    
222          for (Enumeration<Instruction> inst = bb.forwardInstrEnumerator(); inst.hasMoreElements();) {
223            Instruction s = inst.nextElement();
224            for (Enumeration<Operand> ops = s.getOperands(); ops.hasMoreElements();) {
225              Operand op = ops.nextElement();
226              if (op.isRegister()) {
227                RegisterOperand rop = op.asRegister();
228                Register r = rop.getRegister();
229    
230                // Update MIR state for every physical FPR we see
231                if (r.isPhysical() && r.isFloatingPoint() && s.operator() != DUMMY_DEF && s.operator() != DUMMY_USE) {
232                  int n = PhysicalRegisterSet.getFPRIndex(r);
233                  if (fpStackOffset != 0) {
234                    n += fpStackOffset;
235                    rop.setRegister(phys.getFPR(n));
236                  }
237                  ir.MIRInfo.fpStackHeight = Math.max(ir.MIRInfo.fpStackHeight, n + 1);
238                }
239              } else if (op instanceof BURSManagedFPROperand) {
240                int regNum = ((BURSManagedFPROperand) op).regNum;
241                s.replaceOperand(op, new RegisterOperand(phys.getFPR(regNum), TypeReference.Double));
242              }
243            }
244            // account for any effect s has on the floating point stack
245            // position.
246            if (s.operator().isFpPop()) {
247              fpStackOffset--;
248            } else if (s.operator().isFpPush()) {
249              fpStackOffset++;
250            }
251            if (VM.VerifyAssertions) VM._assert(fpStackOffset >= 0);
252          }
253        }
254      }
255    }