SPARCArithmetic.java revision 12651:6ef01bd40ce2
1184610Salfred/*
2184610Salfred * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
3184610Salfred * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4184610Salfred *
5184610Salfred * This code is free software; you can redistribute it and/or modify it
6184610Salfred * under the terms of the GNU General Public License version 2 only, as
7184610Salfred * published by the Free Software Foundation.
8184610Salfred *
9184610Salfred * This code is distributed in the hope that it will be useful, but WITHOUT
10184610Salfred * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11184610Salfred * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12184610Salfred * version 2 for more details (a copy is included in the LICENSE file that
13184610Salfred * accompanied this code).
14184610Salfred *
15184610Salfred * You should have received a copy of the GNU General Public License version
16184610Salfred * 2 along with this work; if not, write to the Free Software Foundation,
17184610Salfred * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18184610Salfred *
19184610Salfred * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20184610Salfred * or visit www.oracle.com if you need additional information or have any
21184610Salfred * questions.
22184610Salfred */
23184610Salfredpackage org.graalvm.compiler.lir.sparc;
24184610Salfred
25184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC;
26184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_V_SHIFT;
27184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_XCC_SHIFT;
28184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.FBPCC;
29184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13;
30184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL;
31184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL;
32184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN;
33184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0;
34184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
35184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal;
36184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Ordered;
37184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmpd;
38184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmps;
39184610Salfredimport static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
40184610Salfredimport static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
41184610Salfredimport static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
42184610Salfredimport static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
43184610Salfredimport static jdk.vm.ci.code.ValueUtil.asRegister;
44184610Salfredimport static jdk.vm.ci.code.ValueUtil.isRegister;
45184610Salfredimport static jdk.vm.ci.sparc.SPARC.g0;
46184610Salfredimport static jdk.vm.ci.sparc.SPARCKind.DOUBLE;
47184610Salfredimport static jdk.vm.ci.sparc.SPARCKind.SINGLE;
48184610Salfredimport static jdk.vm.ci.sparc.SPARCKind.WORD;
49184610Salfredimport static jdk.vm.ci.sparc.SPARCKind.XWORD;
50184610Salfred
51184610Salfredimport org.graalvm.compiler.asm.Label;
52184610Salfredimport org.graalvm.compiler.asm.sparc.SPARCAssembler;
53184610Salfredimport org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
54184610Salfredimport org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
55184610Salfredimport org.graalvm.compiler.core.common.LIRKind;
56184610Salfredimport org.graalvm.compiler.debug.GraalError;
57184610Salfredimport org.graalvm.compiler.lir.LIRFrameState;
58184610Salfredimport org.graalvm.compiler.lir.LIRInstructionClass;
59184610Salfredimport org.graalvm.compiler.lir.Opcode;
60184610Salfredimport org.graalvm.compiler.lir.asm.CompilationResultBuilder;
61184610Salfredimport org.graalvm.compiler.lir.gen.LIRGeneratorTool;
62184610Salfred
63184610Salfredimport jdk.vm.ci.code.Register;
64184610Salfredimport jdk.vm.ci.meta.AllocatableValue;
65184610Salfredimport jdk.vm.ci.meta.Value;
66184610Salfredimport jdk.vm.ci.sparc.SPARC;
67184610Salfred
68184610Salfredpublic class SPARCArithmetic {
69184610Salfred    public static final class FloatConvertOp extends SPARCLIRInstruction {
70184610Salfred        public static final LIRInstructionClass<FloatConvertOp> TYPE = LIRInstructionClass.create(FloatConvertOp.class);
71184610Salfred        public static final SizeEstimate SIZE = SizeEstimate.create(5);
72184610Salfred
73184610Salfred        @Opcode private final FloatConvert opcode;
74184610Salfred        @Def({REG, HINT}) protected Value result;
75184610Salfred        @Use({REG}) protected Value x;
76184610Salfred
77184610Salfred        public enum FloatConvert {
78184610Salfred            F2I,
79184610Salfred            D2I,
80184610Salfred            F2L,
81184610Salfred            D2L
82184610Salfred        }
83184610Salfred
84184610Salfred        public FloatConvertOp(FloatConvert opcode, Value x, Value result) {
85184610Salfred            super(TYPE, SIZE);
86184610Salfred            this.opcode = opcode;
87184610Salfred            this.x = x;
88184610Salfred            this.result = result;
89184610Salfred        }
90184610Salfred
91184610Salfred        @Override
92184610Salfred        protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
93184610Salfred            Label notOrdered = new Label();
94184610Salfred            switch (opcode) {
95184610Salfred                case F2L:
96184610Salfred                    masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE));
97184610Salfred                    FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered);
98184610Salfred                    masm.fstox(asRegister(x, SINGLE), asRegister(result, DOUBLE));
99184610Salfred                    masm.fxtod(asRegister(result), asRegister(result));
100184610Salfred                    masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE));
101184610Salfred                    masm.bind(notOrdered);
102184610Salfred                    break;
103184610Salfred                case F2I:
104184610Salfred                    masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE));
105184610Salfred                    FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered);
106184610Salfred                    masm.fstoi(asRegister(x, SINGLE), asRegister(result, SINGLE));
107184610Salfred                    masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE));
108184610Salfred                    masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE));
109184610Salfred                    masm.bind(notOrdered);
110184610Salfred                    break;
111184610Salfred                case D2L:
112184610Salfred                    masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE));
113184610Salfred                    FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered);
114184610Salfred                    masm.fdtox(asRegister(x, DOUBLE), asRegister(result, DOUBLE));
115184610Salfred                    masm.fxtod(asRegister(result, DOUBLE), asRegister(result, DOUBLE));
116184610Salfred                    masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE));
117184610Salfred                    masm.bind(notOrdered);
118184610Salfred                    break;
119184610Salfred                case D2I:
120184610Salfred                    masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE));
121184610Salfred                    FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered);
122184610Salfred                    masm.fdtoi(asRegister(x, DOUBLE), asRegister(result, SINGLE));
123184610Salfred                    masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE));
124184610Salfred                    masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE));
125184610Salfred                    masm.bind(notOrdered);
126184610Salfred                    break;
127184610Salfred                default:
128184610Salfred                    throw GraalError.shouldNotReachHere("missing: " + opcode);
129184610Salfred            }
130184610Salfred        }
131184610Salfred    }
132184610Salfred
133184610Salfred    /**
134184610Salfred     * Special LIR instruction as it requires a bunch of scratch registers.
135184610Salfred     */
136184610Salfred    public static final class RemOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
137184610Salfred        public static final LIRInstructionClass<RemOp> TYPE = LIRInstructionClass.create(RemOp.class);
138184610Salfred        public static final SizeEstimate SIZE = SizeEstimate.create(4);
139184610Salfred
140184610Salfred        @Opcode private final Rem opcode;
141184610Salfred        @Def({REG}) protected Value result;
142184610Salfred        @Alive({REG, CONST}) protected Value x;
143184610Salfred        @Alive({REG, CONST}) protected Value y;
144184610Salfred        @Temp({REG}) protected Value scratch1;
145184610Salfred        @Temp({REG}) protected Value scratch2;
146184610Salfred        @State protected LIRFrameState state;
147184610Salfred
148184610Salfred        public enum Rem {
149184610Salfred            IUREM,
150184610Salfred            LUREM
151184610Salfred        }
152184610Salfred
153184610Salfred        public RemOp(Rem opcode, Value result, Value x, Value y, Value scratch1, Value scratch2, LIRFrameState state) {
154184610Salfred            super(TYPE, SIZE);
155184610Salfred            this.opcode = opcode;
156184610Salfred            this.result = result;
157184610Salfred            this.x = x;
158184610Salfred            this.y = y;
159184610Salfred            this.scratch1 = scratch1;
160184610Salfred            this.scratch2 = scratch2;
161184610Salfred            this.state = state;
162184610Salfred        }
163184610Salfred
164184610Salfred        @Override
165184610Salfred        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
166184610Salfred            if (!isJavaConstant(x) && isJavaConstant(y)) {
167                assert isSimm13(crb.asIntConst(y));
168                assert !x.equals(scratch1);
169                assert !x.equals(scratch2);
170                assert !y.equals(scratch1);
171                switch (opcode) {
172                    case LUREM:
173                        crb.recordImplicitException(masm.position(), state);
174                        masm.udivx(asRegister(x, XWORD), crb.asIntConst(y), asRegister(scratch1, XWORD));
175                        masm.mulx(asRegister(scratch1, XWORD), crb.asIntConst(y), asRegister(scratch2, XWORD));
176                        getDelayedControlTransfer().emitControlTransfer(crb, masm);
177                        masm.sub(asRegister(x, XWORD), asRegister(scratch2, XWORD), asRegister(result, XWORD));
178                        break;
179                    case IUREM:
180                        GraalError.unimplemented();
181                        break;
182                    default:
183                        throw GraalError.shouldNotReachHere();
184                }
185            } else if (isRegister(x) && isRegister(y)) {
186                Value xLeft = x;
187                switch (opcode) {
188                    case LUREM:
189                        if (isJavaConstant(x)) {
190                            masm.setx(crb.asLongConst(x), asRegister(scratch2, XWORD), false);
191                            xLeft = scratch2;
192                        }
193                        assert !asRegister(xLeft, XWORD).equals(asRegister(scratch1, XWORD));
194                        assert !asRegister(y, XWORD).equals(asRegister(scratch1, XWORD));
195                        crb.recordImplicitException(masm.position(), state);
196                        masm.udivx(asRegister(xLeft, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD));
197                        masm.mulx(asRegister(scratch1, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD));
198                        getDelayedControlTransfer().emitControlTransfer(crb, masm);
199                        masm.sub(asRegister(xLeft, XWORD), asRegister(scratch1, XWORD), asRegister(result, XWORD));
200                        break;
201                    case IUREM:
202                        assert !asRegister(result, WORD).equals(asRegister(scratch1, WORD));
203                        assert !asRegister(result, WORD).equals(asRegister(scratch2, WORD));
204                        masm.srl(asRegister(x, WORD), 0, asRegister(scratch1, WORD));
205                        masm.srl(asRegister(y, WORD), 0, asRegister(result, WORD));
206                        crb.recordImplicitException(masm.position(), state);
207                        masm.udivx(asRegister(scratch1, WORD), asRegister(result, WORD), asRegister(scratch2, WORD));
208                        masm.mulx(asRegister(scratch2, WORD), asRegister(result, WORD), asRegister(result, WORD));
209                        getDelayedControlTransfer().emitControlTransfer(crb, masm);
210                        masm.sub(asRegister(scratch1, WORD), asRegister(result, WORD), asRegister(result, WORD));
211                        break;
212                    default:
213                        throw GraalError.shouldNotReachHere();
214                }
215            } else {
216                throw GraalError.shouldNotReachHere();
217            }
218        }
219    }
220
221    public static final class SPARCIMulccOp extends SPARCLIRInstruction {
222        public static final LIRInstructionClass<SPARCIMulccOp> TYPE = LIRInstructionClass.create(SPARCIMulccOp.class);
223        public static final SizeEstimate SIZE = SizeEstimate.create(10);
224        @Def({REG}) protected Value result;
225        @Alive({REG}) protected Value x;
226        @Alive({REG}) protected Value y;
227
228        public SPARCIMulccOp(Value result, Value x, Value y) {
229            super(TYPE, SIZE);
230            this.result = result;
231            this.x = x;
232            this.y = y;
233        }
234
235        @Override
236        protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
237            try (ScratchRegister tmpScratch = masm.getScratchRegister()) {
238                Register tmp = tmpScratch.getRegister();
239                Register resultRegister = asRegister(result, WORD);
240                Register xRegister = asRegister(x, WORD);
241                Register yRegister = asRegister(y, WORD);
242                masm.sra(xRegister, 0, xRegister);
243                masm.sra(yRegister, 0, yRegister);
244                masm.mulx(xRegister, yRegister, resultRegister);
245                Label noOverflow = new Label();
246                masm.sra(resultRegister, 0, tmp);
247                masm.compareBranch(tmp, resultRegister, Equal, Xcc, noOverflow, PREDICT_TAKEN, null);
248                masm.wrccr(SPARC.g0, 1 << (SPARCAssembler.CCR_ICC_SHIFT + SPARCAssembler.CCR_V_SHIFT));
249                masm.bind(noOverflow);
250            }
251        }
252    }
253
254    /**
255     * Calculates the product and condition code for long multiplication of long values.
256     */
257    public static final class SPARCLMulccOp extends SPARCLIRInstruction {
258        public static final LIRInstructionClass<SPARCLMulccOp> TYPE = LIRInstructionClass.create(SPARCLMulccOp.class);
259        public static final SizeEstimate SIZE = SizeEstimate.create(13);
260
261        @Def({REG}) protected Value result;
262        @Alive({REG}) protected Value x;
263        @Alive({REG}) protected Value y;
264        @Temp({REG}) protected Value scratch1;
265        @Temp({REG}) protected Value scratch2;
266
267        public SPARCLMulccOp(Value result, Value x, Value y, LIRGeneratorTool gen) {
268            super(TYPE, SIZE);
269            this.result = result;
270            this.x = x;
271            this.y = y;
272            this.scratch1 = gen.newVariable(LIRKind.combine(x, y));
273            this.scratch2 = gen.newVariable(LIRKind.combine(x, y));
274        }
275
276        @Override
277        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
278            Label noOverflow = new Label();
279            masm.mulx(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(result, XWORD));
280
281            // Calculate the upper 64 bit signed := (umulxhi product - (x{63}&y + y{63}&x))
282            masm.umulxhi(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD));
283            masm.srax(asRegister(x, XWORD), 63, asRegister(scratch2, XWORD));
284            masm.and(asRegister(scratch2, XWORD), asRegister(y, XWORD), asRegister(scratch2, XWORD));
285            masm.sub(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD), asRegister(scratch1, XWORD));
286
287            masm.srax(asRegister(y, XWORD), 63, asRegister(scratch2, XWORD));
288            masm.and(asRegister(scratch2, XWORD), asRegister(x, XWORD), asRegister(scratch2, XWORD));
289            masm.sub(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD), asRegister(scratch1, XWORD));
290
291            // Now construct the lower half and compare
292            masm.srax(asRegister(result, XWORD), 63, asRegister(scratch2, XWORD));
293            masm.cmp(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD));
294            BPCC.emit(masm, Xcc, Equal, NOT_ANNUL, PREDICT_TAKEN, noOverflow);
295            masm.nop();
296            masm.wrccr(g0, 1 << (CCR_XCC_SHIFT + CCR_V_SHIFT));
297            masm.bind(noOverflow);
298        }
299    }
300
301    public static final class MulHighOp extends SPARCLIRInstruction {
302        public static final LIRInstructionClass<MulHighOp> TYPE = LIRInstructionClass.create(MulHighOp.class);
303        public static final SizeEstimate SIZE = SizeEstimate.create(4);
304
305        @Opcode private final MulHigh opcode;
306        @Def({REG}) public AllocatableValue result;
307        @Alive({REG}) public AllocatableValue x;
308        @Alive({REG}) public AllocatableValue y;
309        @Temp({REG}) public AllocatableValue scratch;
310
311        public enum MulHigh {
312            IMUL,
313            LMUL
314        }
315
316        public MulHighOp(MulHigh opcode, AllocatableValue x, AllocatableValue y, AllocatableValue result, AllocatableValue scratch) {
317            super(TYPE, SIZE);
318            this.opcode = opcode;
319            this.x = x;
320            this.y = y;
321            this.scratch = scratch;
322            this.result = result;
323        }
324
325        @Override
326        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
327            assert isRegister(x) && isRegister(y) && isRegister(result) && isRegister(scratch);
328            switch (opcode) {
329                case IMUL:
330                    masm.sra(asRegister(x), 0, asRegister(x));
331                    masm.sra(asRegister(y), 0, asRegister(y));
332                    masm.mulx(asRegister(x, WORD), asRegister(y, WORD), asRegister(result, WORD));
333                    masm.srax(asRegister(result, WORD), 32, asRegister(result, WORD));
334                    break;
335                case LMUL:
336                    assert !asRegister(scratch, XWORD).equals(asRegister(result, XWORD));
337                    masm.umulxhi(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(result, XWORD));
338
339                    masm.srlx(asRegister(x, XWORD), 63, asRegister(scratch, XWORD));
340                    masm.mulx(asRegister(scratch, XWORD), asRegister(y, XWORD), asRegister(scratch, XWORD));
341                    masm.sub(asRegister(result, XWORD), asRegister(scratch, XWORD), asRegister(result, XWORD));
342
343                    masm.srlx(asRegister(y, XWORD), 63, asRegister(scratch, XWORD));
344                    masm.mulx(asRegister(scratch, XWORD), asRegister(x, XWORD), asRegister(scratch, XWORD));
345                    masm.sub(asRegister(result, XWORD), asRegister(scratch, XWORD), asRegister(result, XWORD));
346                    break;
347                default:
348                    throw GraalError.shouldNotReachHere();
349            }
350        }
351    }
352}
353