001/*
002 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.asm.sparc;
024
025import static com.oracle.graal.asm.sparc.SPARCAssembler.Annul.*;
026import static com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag.*;
027import static jdk.internal.jvmci.sparc.SPARC.*;
028
029import java.util.function.*;
030
031import jdk.internal.jvmci.code.*;
032
033import com.oracle.graal.asm.*;
034
035public class SPARCMacroAssembler extends SPARCAssembler {
036
037    /**
038     * A sentinel value used as a place holder in an instruction stream for an address that will be
039     * patched.
040     */
041    private static final SPARCAddress Placeholder = new SPARCAddress(g0, 0);
042    private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(g3), new ScratchRegister(o7)};
043    // Points to the next free scratch register
044    private int nextFreeScratchRegister = 0;
045    /**
046     * Use ld [reg+simm13], reg for loading constants (User has to make sure, that the size of the
047     * constant table does not exceed simm13).
048     */
049    private boolean immediateConstantLoad;
050
051    public SPARCMacroAssembler(TargetDescription target, RegisterConfig registerConfig) {
052        super(target, registerConfig);
053    }
054
055    /**
056     * @see #immediateConstantLoad
057     */
058    public void setImmediateConstantLoad(boolean immediateConstantLoad) {
059        this.immediateConstantLoad = immediateConstantLoad;
060    }
061
062    @Override
063    public void align(int modulus) {
064        while (position() % modulus != 0) {
065            nop();
066        }
067    }
068
069    @Override
070    public void jmp(Label l) {
071        bicc(Always, NOT_ANNUL, l);
072        nop();  // delay slot
073    }
074
075    @Override
076    protected final void patchJumpTarget(int branch, int branchTarget) {
077        final int disp = (branchTarget - branch) / 4;
078        final int inst = getInt(branch);
079        ControlTransferOp op = (ControlTransferOp) getSPARCOp(inst);
080        int newInst = op.setDisp(inst, disp);
081        emitInt(newInst, branch);
082    }
083
084    @Override
085    public AbstractAddress makeAddress(Register base, int displacement) {
086        return new SPARCAddress(base, displacement);
087    }
088
089    @Override
090    public AbstractAddress getPlaceholder() {
091        return Placeholder;
092    }
093
094    @Override
095    public final void ensureUniquePC() {
096        nop();
097    }
098
099    public void cas(Register rs1, Register rs2, Register rd) {
100        casa(rs1, rs2, rd, Asi.ASI_PRIMARY);
101    }
102
103    public void casx(Register rs1, Register rs2, Register rd) {
104        casxa(rs1, rs2, rd, Asi.ASI_PRIMARY);
105    }
106
107    public void clr(Register dst) {
108        or(g0, g0, dst);
109    }
110
111    public void clrb(SPARCAddress addr) {
112        stb(g0, addr);
113    }
114
115    public void clrh(SPARCAddress addr) {
116        sth(g0, addr);
117    }
118
119    public void clrx(SPARCAddress addr) {
120        stx(g0, addr);
121    }
122
123    public void cmp(Register rs1, Register rs2) {
124        subcc(rs1, rs2, g0);
125    }
126
127    public void cmp(Register rs1, int simm13) {
128        subcc(rs1, simm13, g0);
129    }
130
131    public void dec(Register rd) {
132        sub(rd, 1, rd);
133    }
134
135    public void dec(int simm13, Register rd) {
136        sub(rd, simm13, rd);
137    }
138
139    public void jmp(SPARCAddress address) {
140        jmpl(address.getBase(), address.getDisplacement(), g0);
141    }
142
143    public void jmp(Register rd) {
144        jmpl(rd, 0, g0);
145    }
146
147    public void neg(Register rs1, Register rd) {
148        sub(g0, rs1, rd);
149    }
150
151    public void neg(Register rd) {
152        sub(g0, rd, rd);
153    }
154
155    public void mov(Register rs, Register rd) {
156        or(g0, rs, rd);
157    }
158
159    public void mov(int simm13, Register rd) {
160        or(g0, simm13, rd);
161    }
162
163    public void not(Register rs1, Register rd) {
164        xnor(rs1, g0, rd);
165    }
166
167    public void not(Register rd) {
168        xnor(rd, g0, rd);
169    }
170
171    public void restoreWindow() {
172        restore(g0, g0, g0);
173    }
174
175    public void ret() {
176        jmpl(i7, 8, g0);
177    }
178
179    /**
180     * This instruction is like sethi but for 64-bit values.
181     */
182    public static class Sethix {
183
184        private static final int INSTRUCTION_SIZE = 7;
185
186        private long value;
187        private Register dst;
188        private boolean forceRelocatable;
189        private boolean delayed = false;
190        private Consumer<SPARCAssembler> delayedInstructionEmitter;
191
192        public Sethix(long value, Register dst, boolean forceRelocatable, boolean delayed) {
193            this(value, dst, forceRelocatable);
194            assert !(forceRelocatable && delayed) : "Relocatable sethix cannot be delayed";
195            this.delayed = delayed;
196        }
197
198        public Sethix(long value, Register dst, boolean forceRelocatable) {
199            this.value = value;
200            this.dst = dst;
201            this.forceRelocatable = forceRelocatable;
202        }
203
204        public Sethix(long value, Register dst) {
205            this(value, dst, false);
206        }
207
208        private void emitInstruction(Consumer<SPARCAssembler> cb, SPARCMacroAssembler masm) {
209            if (delayed) {
210                if (this.delayedInstructionEmitter != null) {
211                    delayedInstructionEmitter.accept(masm);
212                }
213                delayedInstructionEmitter = cb;
214            } else {
215                cb.accept(masm);
216            }
217        }
218
219        public void emit(SPARCMacroAssembler masm) {
220            final int hi = (int) (value >> 32);
221            final int lo = (int) (value & ~0);
222
223            // This is the same logic as MacroAssembler::internal_set.
224            final int startPc = masm.position();
225
226            if (hi == 0 && lo >= 0) {
227                Consumer<SPARCAssembler> cb = eMasm -> eMasm.sethi(hi22(lo), dst);
228                emitInstruction(cb, masm);
229            } else if (hi == -1) {
230                Consumer<SPARCAssembler> cb = eMasm -> eMasm.sethi(hi22(~lo), dst);
231                emitInstruction(cb, masm);
232                cb = eMasm -> eMasm.xor(dst, ~lo10(~0), dst);
233                emitInstruction(cb, masm);
234            } else {
235                final int shiftcnt;
236                final int shiftcnt2;
237                Consumer<SPARCAssembler> cb = eMasm -> eMasm.sethi(hi22(hi), dst);
238                emitInstruction(cb, masm);
239                if ((hi & 0x3ff) != 0) {                                  // Any bits?
240                    // msb 32-bits are now in lsb 32
241                    cb = eMasm -> eMasm.or(dst, hi & 0x3ff, dst);
242                    emitInstruction(cb, masm);
243                }
244                if ((lo & 0xFFFFFC00) != 0) {                             // done?
245                    if (((lo >> 20) & 0xfff) != 0) {                      // Any bits set?
246                        // Make room for next 12 bits
247                        cb = eMasm -> eMasm.sllx(dst, 12, dst);
248                        emitInstruction(cb, masm);
249                        // Or in next 12
250                        cb = eMasm -> eMasm.or(dst, (lo >> 20) & 0xfff, dst);
251                        emitInstruction(cb, masm);
252                        shiftcnt = 0;                                     // We already shifted
253                    } else {
254                        shiftcnt = 12;
255                    }
256                    if (((lo >> 10) & 0x3ff) != 0) {
257                        // Make room for last 10 bits
258                        cb = eMasm -> eMasm.sllx(dst, shiftcnt + 10, dst);
259                        emitInstruction(cb, masm);
260                        // Or in next 10
261                        cb = eMasm -> eMasm.or(dst, (lo >> 10) & 0x3ff, dst);
262                        emitInstruction(cb, masm);
263                        shiftcnt2 = 0;
264                    } else {
265                        shiftcnt2 = 10;
266                    }
267                    // Shift leaving disp field 0'd
268                    cb = eMasm -> eMasm.sllx(dst, shiftcnt2 + 10, dst);
269                    emitInstruction(cb, masm);
270                } else {
271                    cb = eMasm -> eMasm.sllx(dst, 32, dst);
272                    emitInstruction(cb, masm);
273                }
274            }
275            // Pad out the instruction sequence so it can be patched later.
276            if (forceRelocatable) {
277                while (masm.position() < (startPc + (INSTRUCTION_SIZE * 4))) {
278                    Consumer<SPARCAssembler> cb = eMasm -> eMasm.nop();
279                    emitInstruction(cb, masm);
280                }
281            }
282        }
283
284        public void emitDelayed(SPARCMacroAssembler masm) {
285            assert delayedInstructionEmitter != null;
286            delayedInstructionEmitter.accept(masm);
287        }
288    }
289
290    public static class Setx {
291
292        private long value;
293        private Register dst;
294        private boolean forceRelocatable;
295        private boolean delayed = false;
296        private boolean delayedFirstEmitted = false;
297        private Sethix sethix;
298        private Consumer<SPARCMacroAssembler> delayedAdd;
299
300        public Setx(long value, Register dst, boolean forceRelocatable, boolean delayed) {
301            assert !(forceRelocatable && delayed) : "Cannot use relocatable setx as delayable";
302            this.value = value;
303            this.dst = dst;
304            this.forceRelocatable = forceRelocatable;
305            this.delayed = delayed;
306        }
307
308        public Setx(long value, Register dst, boolean forceRelocatable) {
309            this(value, dst, forceRelocatable, false);
310        }
311
312        public Setx(long value, Register dst) {
313            this(value, dst, false);
314        }
315
316        public void emit(SPARCMacroAssembler masm) {
317            assert !delayed;
318            doEmit(masm);
319        }
320
321        private void doEmit(SPARCMacroAssembler masm) {
322            sethix = new Sethix(value, dst, forceRelocatable, delayed);
323            sethix.emit(masm);
324            int lo = (int) (value & ~0);
325            if (lo10(lo) != 0 || forceRelocatable) {
326                Consumer<SPARCMacroAssembler> add = eMasm -> eMasm.add(dst, lo10(lo), dst);
327                if (delayed) {
328                    sethix.emitDelayed(masm);
329                    sethix = null;
330                    delayedAdd = add;
331                } else {
332                    sethix = null;
333                    add.accept(masm);
334                }
335            }
336        }
337
338        public void emitFirstPartOfDelayed(SPARCMacroAssembler masm) {
339            assert !forceRelocatable : "Cannot use delayed mode with relocatable setx";
340            assert delayed : "Can only be used in delayed mode";
341            doEmit(masm);
342            delayedFirstEmitted = true;
343        }
344
345        public void emitSecondPartOfDelayed(SPARCMacroAssembler masm) {
346            assert !forceRelocatable : "Cannot use delayed mode with relocatable setx";
347            assert delayed : "Can only be used in delayed mode";
348            assert delayedFirstEmitted : "First part has not been emitted so far.";
349            assert delayedAdd == null && sethix != null || delayedAdd != null && sethix == null : "Either add or sethix must be set";
350            if (delayedAdd != null) {
351                delayedAdd.accept(masm);
352            } else {
353                sethix.emitDelayed(masm);
354            }
355
356        }
357    }
358
359    public void signx(Register rs, Register rd) {
360        sra(rs, g0, rd);
361    }
362
363    public void signx(Register rd) {
364        sra(rd, g0, rd);
365    }
366
367    public boolean isImmediateConstantLoad() {
368        return immediateConstantLoad;
369    }
370
371    public ScratchRegister getScratchRegister() {
372        return scratchRegister[nextFreeScratchRegister++];
373    }
374
375    public class ScratchRegister implements AutoCloseable {
376        private final Register register;
377
378        public ScratchRegister(Register register) {
379            super();
380            this.register = register;
381        }
382
383        public Register getRegister() {
384            return register;
385        }
386
387        public void close() {
388            assert nextFreeScratchRegister > 0 : "Close called too often";
389            nextFreeScratchRegister--;
390        }
391    }
392}