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.ia32;
014
015import static org.jikesrvm.compilers.opt.ir.Operators.ADDR_2INT_opcode;
016import static org.jikesrvm.compilers.opt.ir.Operators.ADDR_2LONG_opcode;
017import static org.jikesrvm.compilers.opt.ir.Operators.ATTEMPT_ADDR_opcode;
018import static org.jikesrvm.compilers.opt.ir.Operators.ATTEMPT_INT;
019import static org.jikesrvm.compilers.opt.ir.Operators.ATTEMPT_LONG;
020import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_CMP_ADDR_opcode;
021import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_CMP_INT;
022import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_CMP_LONG;
023import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ADD_opcode;
024import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_COND_MOVE_opcode;
025import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_DIV_opcode;
026import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_MUL_opcode;
027import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_NEG_opcode;
028import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_REM_opcode;
029import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_SUB_opcode;
030import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ADD_opcode;
031import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_COND_MOVE_opcode;
032import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_DIV_opcode;
033import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_MUL_opcode;
034import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_NEG_opcode;
035import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_REM_opcode;
036import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_SUB_opcode;
037import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_COND_MOVE_opcode;
038import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRSigExt_opcode;
039import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRZerExt_opcode;
040import static org.jikesrvm.compilers.opt.ir.Operators.INT_2DOUBLE_opcode;
041import static org.jikesrvm.compilers.opt.ir.Operators.INT_2FLOAT_opcode;
042import static org.jikesrvm.compilers.opt.ir.Operators.INT_2LONG;
043import static org.jikesrvm.compilers.opt.ir.Operators.INT_ADD;
044import static org.jikesrvm.compilers.opt.ir.Operators.INT_ALOAD;
045import static org.jikesrvm.compilers.opt.ir.Operators.INT_AND;
046import static org.jikesrvm.compilers.opt.ir.Operators.INT_ASTORE;
047import static org.jikesrvm.compilers.opt.ir.Operators.INT_COND_MOVE_opcode;
048import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP;
049import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD;
050import static org.jikesrvm.compilers.opt.ir.Operators.INT_MOVE;
051import static org.jikesrvm.compilers.opt.ir.Operators.INT_NEG;
052import static org.jikesrvm.compilers.opt.ir.Operators.INT_NOT;
053import static org.jikesrvm.compilers.opt.ir.Operators.INT_OR;
054import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHL;
055import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHR;
056import static org.jikesrvm.compilers.opt.ir.Operators.INT_STORE;
057import static org.jikesrvm.compilers.opt.ir.Operators.INT_SUB;
058import static org.jikesrvm.compilers.opt.ir.Operators.INT_USHR;
059import static org.jikesrvm.compilers.opt.ir.Operators.INT_XOR;
060import static org.jikesrvm.compilers.opt.ir.Operators.LONG_2ADDR_opcode;
061import static org.jikesrvm.compilers.opt.ir.Operators.LONG_2DOUBLE_opcode;
062import static org.jikesrvm.compilers.opt.ir.Operators.LONG_2FLOAT_opcode;
063import static org.jikesrvm.compilers.opt.ir.Operators.LONG_2INT;
064import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ADD;
065import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ALOAD;
066import static org.jikesrvm.compilers.opt.ir.Operators.LONG_AND;
067import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ASTORE;
068import static org.jikesrvm.compilers.opt.ir.Operators.LONG_COND_MOVE_opcode;
069import static org.jikesrvm.compilers.opt.ir.Operators.LONG_IFCMP;
070import static org.jikesrvm.compilers.opt.ir.Operators.LONG_LOAD;
071import static org.jikesrvm.compilers.opt.ir.Operators.LONG_MOVE;
072import static org.jikesrvm.compilers.opt.ir.Operators.LONG_NEG;
073import static org.jikesrvm.compilers.opt.ir.Operators.LONG_NOT;
074import static org.jikesrvm.compilers.opt.ir.Operators.LONG_OR;
075import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SHL;
076import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SHR;
077import static org.jikesrvm.compilers.opt.ir.Operators.LONG_STORE;
078import static org.jikesrvm.compilers.opt.ir.Operators.LONG_SUB;
079import static org.jikesrvm.compilers.opt.ir.Operators.LONG_USHR;
080import static org.jikesrvm.compilers.opt.ir.Operators.LONG_XOR;
081import static org.jikesrvm.compilers.opt.ir.Operators.PREPARE_ADDR_opcode;
082import static org.jikesrvm.compilers.opt.ir.Operators.PREPARE_INT_opcode;
083import static org.jikesrvm.compilers.opt.ir.Operators.PREPARE_LONG_opcode;
084import static org.jikesrvm.compilers.opt.ir.Operators.REF_ADD_opcode;
085import static org.jikesrvm.compilers.opt.ir.Operators.REF_ALOAD_opcode;
086import static org.jikesrvm.compilers.opt.ir.Operators.REF_AND_opcode;
087import static org.jikesrvm.compilers.opt.ir.Operators.REF_ASTORE_opcode;
088import static org.jikesrvm.compilers.opt.ir.Operators.REF_COND_MOVE_opcode;
089import static org.jikesrvm.compilers.opt.ir.Operators.REF_IFCMP_opcode;
090import static org.jikesrvm.compilers.opt.ir.Operators.REF_LOAD_opcode;
091import static org.jikesrvm.compilers.opt.ir.Operators.REF_MOVE_opcode;
092import static org.jikesrvm.compilers.opt.ir.Operators.REF_NEG_opcode;
093import static org.jikesrvm.compilers.opt.ir.Operators.REF_NOT_opcode;
094import static org.jikesrvm.compilers.opt.ir.Operators.REF_OR_opcode;
095import static org.jikesrvm.compilers.opt.ir.Operators.REF_SHL_opcode;
096import static org.jikesrvm.compilers.opt.ir.Operators.REF_SHR_opcode;
097import static org.jikesrvm.compilers.opt.ir.Operators.REF_STORE_opcode;
098import static org.jikesrvm.compilers.opt.ir.Operators.REF_SUB_opcode;
099import static org.jikesrvm.compilers.opt.ir.Operators.REF_USHR_opcode;
100import static org.jikesrvm.compilers.opt.ir.Operators.REF_XOR_opcode;
101import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.CMP_CMOV;
102import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.CMP_FCMOV;
103import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FCMP_CMOV;
104import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FCMP_FCMOV;
105import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FP_ADD;
106import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FP_DIV;
107import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FP_MUL;
108import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FP_NEG;
109import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FP_REM;
110import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.FP_SUB;
111import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.INT_2FP;
112import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.LCMP_CMOV;
113import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.LONG_2FP;
114import static org.jikesrvm.ia32.ArchConstants.SSE2_FULL;
115
116import java.util.Enumeration;
117
118import org.jikesrvm.VM;
119import org.jikesrvm.compilers.opt.OptimizingCompilerException;
120import org.jikesrvm.compilers.opt.Simplifier;
121import org.jikesrvm.compilers.opt.driver.CompilerPhase;
122import org.jikesrvm.compilers.opt.ir.CondMove;
123import org.jikesrvm.compilers.opt.ir.IR;
124import org.jikesrvm.compilers.opt.ir.Instruction;
125
126/**
127 * Reduce the number of ALU operators considered by BURS
128 */
129public final class ConvertALUOperators extends CompilerPhase {
130
131  @Override
132  public String getName() {
133    return "ConvertALUOps";
134  }
135
136  /**
137   * Return this instance of this phase. This phase contains no
138   * per-compilation instance fields.
139   * @param ir not used
140   * @return this
141   */
142  @Override
143  public CompilerPhase newExecution(IR ir) {
144    return this;
145  }
146
147  @Override
148  public void perform(IR ir) {
149    // Calling Simplifier.simplify ensures that the instruction is
150    // in normalized form. This reduces the number of cases we have to
151    // worry about (and does last minute constant folding on the off
152    // chance we've missed an opportunity...)
153    // BURS assumes that this has been done
154    for (Enumeration<Instruction> instrs = ir.forwardInstrEnumerator(); instrs.hasMoreElements();) {
155      Instruction s = instrs.nextElement();
156      Simplifier.simplify(false, ir.regpool, ir.options, s);
157    }
158
159    // Pass over instructions
160    for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements();) {
161      Instruction s = e.nextElement();
162
163      // BURS doesn't really care, so consolidate to reduce rule space
164      switch (s.getOpcode()) {
165      case REF_ADD_opcode:
166        s.changeOperatorTo(VM.BuildFor32Addr ? INT_ADD : LONG_ADD);
167        break;
168      case REF_SUB_opcode:
169        s.changeOperatorTo(VM.BuildFor32Addr ? INT_SUB : LONG_SUB);
170        break;
171      case REF_NEG_opcode:
172        s.changeOperatorTo(VM.BuildFor32Addr ? INT_NEG : LONG_NEG);
173        break;
174      case REF_NOT_opcode:
175        s.changeOperatorTo(VM.BuildFor32Addr ? INT_NOT : LONG_NOT);
176        break;
177      case REF_AND_opcode:
178        s.changeOperatorTo(VM.BuildFor32Addr ? INT_AND : LONG_AND);
179        break;
180      case REF_OR_opcode:
181        s.changeOperatorTo(VM.BuildFor32Addr ? INT_OR : LONG_OR);
182        break;
183      case REF_XOR_opcode:
184        s.changeOperatorTo(VM.BuildFor32Addr ? INT_XOR : LONG_XOR);
185        break;
186      case REF_SHL_opcode:
187        s.changeOperatorTo(VM.BuildFor32Addr ? INT_SHL : LONG_SHL);
188        break;
189      case REF_SHR_opcode:
190        s.changeOperatorTo(VM.BuildFor32Addr ? INT_SHR : LONG_SHR);
191        break;
192      case REF_USHR_opcode:
193        s.changeOperatorTo(VM.BuildFor32Addr ? INT_USHR : LONG_USHR);
194        break;
195      case REF_LOAD_opcode:
196        s.changeOperatorTo(VM.BuildFor32Addr ? INT_LOAD : LONG_LOAD);
197        break;
198      case REF_STORE_opcode:
199        s.changeOperatorTo(VM.BuildFor32Addr ? INT_STORE : LONG_STORE);
200        break;
201      case REF_ALOAD_opcode:
202        s.changeOperatorTo(VM.BuildFor32Addr ? INT_ALOAD : LONG_ALOAD);
203        break;
204      case REF_ASTORE_opcode:
205        s.changeOperatorTo(VM.BuildFor32Addr ? INT_ASTORE : LONG_ASTORE);
206        break;
207      case REF_MOVE_opcode:
208        s.changeOperatorTo(VM.BuildFor32Addr ? INT_MOVE : LONG_MOVE);
209        break;
210      case REF_IFCMP_opcode:
211        s.changeOperatorTo(VM.BuildFor32Addr ? INT_IFCMP : LONG_IFCMP);
212        break;
213      case BOOLEAN_CMP_ADDR_opcode:
214        s.changeOperatorTo(VM.BuildFor32Addr ? BOOLEAN_CMP_INT : BOOLEAN_CMP_LONG);
215        break;
216      case ATTEMPT_ADDR_opcode:
217        s.changeOperatorTo(VM.BuildFor32Addr ? ATTEMPT_INT : ATTEMPT_LONG);
218        break;
219      case PREPARE_ADDR_opcode:
220        s.changeOperatorTo(VM.BuildFor32Addr ? INT_LOAD : LONG_LOAD);
221        break;
222      case PREPARE_INT_opcode:
223        s.changeOperatorTo(INT_LOAD);
224        break;
225      case PREPARE_LONG_opcode:
226        s.changeOperatorTo(LONG_LOAD);
227        break;
228      case INT_2ADDRSigExt_opcode:
229        s.changeOperatorTo(VM.BuildFor32Addr ? INT_MOVE : INT_2LONG);
230        break;
231      case INT_2ADDRZerExt_opcode:
232        if (VM.BuildFor32Addr) {
233          s.changeOperatorTo(INT_MOVE);
234        }
235        break;
236      case ADDR_2INT_opcode:
237        s.changeOperatorTo(VM.BuildFor32Addr ? INT_MOVE : LONG_2INT);
238        break;
239      case ADDR_2LONG_opcode:
240        // Note that a 32-bit ADDR_2LONG cannot be changed to an INT_2LONG because
241        // INT_2LONG uses the Java conventions for widening by default. Java widening
242        // uses sign extension which is not appropriate for addresses. The unboxed
243        // types that Jikes RVM uses define that the toLong() methods use zero-extension.
244        // For example, for 0xFFFF FFFF (32 bit addresses) the result is supposed to be
245        // 0x0000 0000 FFFF FFFF but with sign extension it would be
246        // 0xFFFF FFFF FFFF FFFF.
247        // Therefore, let BURS rules convert to ADDR_2LONG. The BURS rules can use
248        // methods from BURS_Helpers which provide the possibility to emit code for an
249        // INT_2LONG that uses zero-extension.
250        if (VM.BuildFor64Addr) {
251          s.changeOperatorTo(LONG_MOVE);
252        }
253        break;
254      case LONG_2ADDR_opcode:
255        s.changeOperatorTo(VM.BuildFor32Addr ? LONG_2INT : LONG_MOVE);
256        break;
257
258      case FLOAT_ADD_opcode:
259        if (!SSE2_FULL)
260          s.changeOperatorTo(FP_ADD);
261        break;
262      case DOUBLE_ADD_opcode:
263        if (!SSE2_FULL)
264          s.changeOperatorTo(FP_ADD);
265        break;
266      case FLOAT_SUB_opcode:
267        if (!SSE2_FULL)
268          s.changeOperatorTo(FP_SUB);
269        break;
270      case DOUBLE_SUB_opcode:
271        if (!SSE2_FULL)
272          s.changeOperatorTo(FP_SUB);
273        break;
274      case FLOAT_MUL_opcode:
275        if (!SSE2_FULL)
276          s.changeOperatorTo(FP_MUL);
277        break;
278      case DOUBLE_MUL_opcode:
279        if (!SSE2_FULL)
280          s.changeOperatorTo(FP_MUL);
281        break;
282      case FLOAT_DIV_opcode:
283        if (!SSE2_FULL)
284          s.changeOperatorTo(FP_DIV);
285        break;
286      case DOUBLE_DIV_opcode:
287        if (!SSE2_FULL)
288          s.changeOperatorTo(FP_DIV);
289        break;
290      case FLOAT_REM_opcode:
291        if (!SSE2_FULL)
292          s.changeOperatorTo(FP_REM);
293        break;
294      case DOUBLE_REM_opcode:
295        if (!SSE2_FULL)
296          s.changeOperatorTo(FP_REM);
297        break;
298      case FLOAT_NEG_opcode:
299        if (!SSE2_FULL)
300          s.changeOperatorTo(FP_NEG);
301        break;
302      case DOUBLE_NEG_opcode:
303        if (!SSE2_FULL)
304          s.changeOperatorTo(FP_NEG);
305        break;
306
307      case INT_COND_MOVE_opcode:
308      case REF_COND_MOVE_opcode:
309        s.changeOperatorTo(CondMove.getCond(s).isFLOATINGPOINT() ? FCMP_CMOV : (CondMove.getVal1(s).isLong() ? LCMP_CMOV : CMP_CMOV));
310        break;
311      case FLOAT_COND_MOVE_opcode:
312      case DOUBLE_COND_MOVE_opcode:
313        s.changeOperatorTo(CondMove.getCond(s).isFLOATINGPOINT() ? FCMP_FCMOV : CMP_FCMOV);
314        break;
315
316      case GUARD_COND_MOVE_opcode:
317      case LONG_COND_MOVE_opcode:
318        OptimizingCompilerException.TODO("Unimplemented conversion" + s);
319        break;
320
321      case INT_2FLOAT_opcode:
322        if (!SSE2_FULL)
323          s.changeOperatorTo(INT_2FP);
324        break;
325      case INT_2DOUBLE_opcode:
326        if (!SSE2_FULL)
327          s.changeOperatorTo(INT_2FP);
328        break;
329      case LONG_2FLOAT_opcode:
330        if (!SSE2_FULL)
331          s.changeOperatorTo(LONG_2FP);
332        break;
333      case LONG_2DOUBLE_opcode:
334        if (!SSE2_FULL)
335          s.changeOperatorTo(LONG_2FP);
336        break;
337      }
338    }
339  }
340}