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