001/*
002 * Copyright (c) 2013, 2015, 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.hotspot.sparc;
024
025import static com.oracle.graal.hotspot.HotSpotBackend.*;
026import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
027import static jdk.internal.jvmci.code.ValueUtil.*;
028import static jdk.internal.jvmci.hotspot.HotSpotCompressedNullConstant.*;
029import static jdk.internal.jvmci.sparc.SPARC.*;
030
031import java.util.*;
032
033import jdk.internal.jvmci.code.*;
034import jdk.internal.jvmci.common.*;
035import jdk.internal.jvmci.hotspot.*;
036import jdk.internal.jvmci.hotspot.HotSpotVMConfig.CompressEncoding;
037import jdk.internal.jvmci.meta.*;
038import jdk.internal.jvmci.sparc.*;
039
040import com.oracle.graal.compiler.common.calc.*;
041import com.oracle.graal.compiler.common.spi.*;
042import com.oracle.graal.compiler.sparc.*;
043import com.oracle.graal.hotspot.*;
044import com.oracle.graal.hotspot.debug.*;
045import com.oracle.graal.hotspot.meta.*;
046import com.oracle.graal.hotspot.stubs.*;
047import com.oracle.graal.lir.*;
048import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
049import com.oracle.graal.lir.gen.*;
050import com.oracle.graal.lir.sparc.*;
051import com.oracle.graal.lir.sparc.SPARCMove.CompareAndSwapOp;
052import com.oracle.graal.lir.sparc.SPARCMove.LoadOp;
053import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp;
054import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp;
055import com.oracle.graal.lir.sparc.SPARCMove.StoreOp;
056
057public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator {
058
059    final HotSpotVMConfig config;
060    private HotSpotLockStack lockStack;
061    private LIRFrameState currentRuntimeCallInfo;
062
063    public SPARCHotSpotLIRGenerator(HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) {
064        this(new DefaultLIRKindTool(providers.getCodeCache().getTarget().wordKind), providers, config, cc, lirGenRes);
065    }
066
067    protected SPARCHotSpotLIRGenerator(LIRKindTool lirKindTool, HotSpotProviders providers, HotSpotVMConfig config, CallingConvention cc, LIRGenerationResult lirGenRes) {
068        super(lirKindTool, providers, cc, lirGenRes);
069        assert config.basicLockSize == 8;
070        this.config = config;
071    }
072
073    @Override
074    public HotSpotProviders getProviders() {
075        return (HotSpotProviders) super.getProviders();
076    }
077
078    /**
079     * The slot reserved for storing the original return address when a frame is marked for
080     * deoptimization. The return address slot in the callee is overwritten with the address of a
081     * deoptimization stub.
082     */
083    private StackSlot deoptimizationRescueSlot;
084
085    /**
086     * Value where the address for safepoint poll is kept.
087     */
088    private AllocatableValue safepointAddressValue;
089
090    @Override
091    public StackSlotValue getLockSlot(int lockDepth) {
092        return getLockStack().makeLockSlot(lockDepth);
093    }
094
095    private HotSpotLockStack getLockStack() {
096        assert lockStack != null;
097        return lockStack;
098    }
099
100    protected void setLockStack(HotSpotLockStack lockStack) {
101        assert this.lockStack == null;
102        this.lockStack = lockStack;
103    }
104
105    @Override
106    public boolean needOnlyOopMaps() {
107        // Stubs only need oop maps
108        return getStub() != null;
109    }
110
111    public Stub getStub() {
112        return ((SPARCHotSpotLIRGenerationResult) getResult()).getStub();
113    }
114
115    @Override
116    public void beforeRegisterAllocation() {
117        super.beforeRegisterAllocation();
118        boolean hasDebugInfo = getResult().getLIR().hasDebugInfo();
119        if (hasDebugInfo) {
120            ((SPARCHotSpotLIRGenerationResult) getResult()).setDeoptimizationRescueSlot(((SPARCFrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot());
121        }
122    }
123
124    @Override
125    protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
126        currentRuntimeCallInfo = info;
127        super.emitForeignCallOp(linkage, result, arguments, temps, info);
128    }
129
130    @Override
131    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
132        HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
133        Variable result;
134        LIRFrameState debugInfo = null;
135        if (hotspotLinkage.needsDebugInfo()) {
136            debugInfo = state;
137            assert debugInfo != null || getStub() != null;
138        }
139
140        if (linkage.destroysRegisters() || hotspotLinkage.needsJavaFrameAnchor()) {
141            HotSpotRegistersProvider registers = getProviders().getRegisters();
142            Register thread = registers.getThreadRegister();
143            Value threadTemp = newVariable(LIRKind.value(Kind.Long));
144            Register stackPointer = registers.getStackPointerRegister();
145            Variable spScratch = newVariable(LIRKind.value(target().wordKind));
146            append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread, stackPointer, threadTemp, spScratch));
147            result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
148            append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), thread, threadTemp));
149        } else {
150            result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
151        }
152
153        return result;
154    }
155
156    @Override
157    public void emitReturn(Value input) {
158        AllocatableValue operand = Value.ILLEGAL;
159        if (input != null) {
160            operand = resultOperandFor(input.getLIRKind());
161            emitMove(operand, input);
162        }
163        append(new SPARCHotSpotReturnOp(operand, getStub() != null, runtime().getConfig(), getSafepointAddressValue()));
164    }
165
166    @Override
167    public void emitTailcall(Value[] args, Value address) {
168        throw JVMCIError.unimplemented();
169    }
170
171    @Override
172    public void emitUnwind(Value exception) {
173        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
174        CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
175        assert linkageCc.getArgumentCount() == 2;
176        RegisterValue exceptionParameter = (RegisterValue) linkageCc.getArgument(0);
177        emitMove(exceptionParameter, exception);
178        append(new SPARCHotSpotUnwindOp(exceptionParameter));
179    }
180
181    private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) {
182        moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset);
183        moveValueToThread(speculation, config.pendingFailedSpeculationOffset);
184    }
185
186    private void moveValueToThread(Value v, int offset) {
187        LIRKind wordKind = LIRKind.value(getProviders().getCodeCache().getTarget().wordKind);
188        RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
189        SPARCAddressValue pendingDeoptAddress = new SPARCImmediateAddressValue(wordKind, thread, offset);
190        append(new StoreOp(v.getKind(), pendingDeoptAddress, load(v), null));
191    }
192
193    @Override
194    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
195        moveDeoptValuesToThread(actionAndReason, speculation);
196        append(new SPARCDeoptimizeOp(state, target().wordKind));
197    }
198
199    @Override
200    public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
201        moveDeoptValuesToThread(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0), JavaConstant.NULL_POINTER);
202        append(new SPARCHotSpotDeoptimizeCallerOp());
203    }
204
205    @Override
206    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
207        SPARCAddressValue loadAddress = asAddressValue(address);
208        Variable result = newVariable(kind);
209        append(new LoadOp((Kind) kind.getPlatformKind(), result, loadAddress, state));
210        return result;
211    }
212
213    private static boolean canStoreConstant(JavaConstant c) {
214        // SPARC can only store integer null constants (via g0)
215        switch (c.getKind()) {
216            case Float:
217            case Double:
218                return false;
219            default:
220                return c.isDefaultForKind();
221        }
222    }
223
224    @Override
225    public boolean canInlineConstant(JavaConstant c) {
226        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
227            return true;
228        } else if (c instanceof HotSpotObjectConstant) {
229            return false;
230        } else {
231            return super.canInlineConstant(c);
232        }
233    }
234
235    @Override
236    public void emitStore(LIRKind kind, Value address, Value inputVal, LIRFrameState state) {
237        SPARCAddressValue storeAddress = asAddressValue(address);
238        if (isConstant(inputVal)) {
239            JavaConstant c = asConstant(inputVal);
240            if (canStoreConstant(c)) {
241                append(new StoreConstantOp((Kind) kind.getPlatformKind(), storeAddress, c, state));
242                return;
243            }
244        }
245        Variable input = load(inputVal);
246        append(new StoreOp((Kind) kind.getPlatformKind(), storeAddress, input, state));
247    }
248
249    public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
250
251        LIRKind kind = newValue.getLIRKind();
252        assert kind.equals(expectedValue.getLIRKind());
253        Kind memKind = (Kind) kind.getPlatformKind();
254        Variable result = newVariable(newValue.getLIRKind());
255        append(new CompareAndSwapOp(result, asAllocatable(address), asAllocatable(expectedValue), asAllocatable(newValue)));
256        return emitConditionalMove(memKind, expectedValue, result, Condition.EQ, true, trueValue, falseValue);
257    }
258
259    public void emitPrefetchAllocate(Value address) {
260        SPARCAddressValue addr = asAddressValue(address);
261        append(new SPARCPrefetchOp(addr, config.allocatePrefetchInstr));
262    }
263
264    public StackSlot getDeoptimizationRescueSlot() {
265        return deoptimizationRescueSlot;
266    }
267
268    @Override
269    protected SPARCLIRInstruction createMove(AllocatableValue dst, Value src) {
270        Value usedSource;
271        if (COMPRESSED_NULL.equals(src)) {
272            usedSource = INT_0;
273        } else {
274            usedSource = src;
275        }
276        return super.createMove(dst, usedSource);
277    }
278
279    @Override
280    public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
281                    double trueDestinationProbability) {
282        Value localX = x;
283        Value localY = y;
284        if (localX instanceof HotSpotObjectConstant) {
285            localX = load(localX);
286        }
287        if (localY instanceof HotSpotObjectConstant) {
288            localY = load(localY);
289        }
290        super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability);
291    }
292
293    @Override
294    protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b) {
295        Value localA = a;
296        Value localB = b;
297        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(localA)) {
298            localA = SPARC.g0.asValue(LIRKind.value(Kind.Int));
299        } else if (localA instanceof HotSpotObjectConstant) {
300            localA = load(localA);
301        }
302        if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(localB)) {
303            localB = SPARC.g0.asValue(LIRKind.value(Kind.Int));
304        } else if (localB instanceof HotSpotObjectConstant) {
305            localB = load(localB);
306        }
307        return super.emitCompare(cmpKind, localA, localB);
308    }
309
310    @Override
311    public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
312        LIRKind inputKind = pointer.getLIRKind();
313        assert inputKind.getPlatformKind() == Kind.Long || inputKind.getPlatformKind() == Kind.Object;
314        if (inputKind.isReference(0)) {
315            // oop
316            Variable result = newVariable(LIRKind.reference(Kind.Int));
317            append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
318            return result;
319        } else {
320            // metaspace pointer
321            Variable result = newVariable(LIRKind.value(Kind.Int));
322            AllocatableValue base = Value.ILLEGAL;
323            if (encoding.base != 0) {
324                base = emitMove(JavaConstant.forLong(encoding.base));
325            }
326            append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
327            return result;
328        }
329    }
330
331    @Override
332    public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
333        LIRKind inputKind = pointer.getLIRKind();
334        assert inputKind.getPlatformKind() == Kind.Int;
335        if (inputKind.isReference(0)) {
336            // oop
337            Variable result = newVariable(LIRKind.reference(Kind.Object));
338            append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
339            return result;
340        } else {
341            // metaspace pointer
342            Variable result = newVariable(LIRKind.value(Kind.Long));
343            AllocatableValue base = Value.ILLEGAL;
344            if (encoding.base != 0) {
345                base = emitMove(JavaConstant.forLong(encoding.base));
346            }
347            append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
348            return result;
349        }
350    }
351
352    /**
353     * @param savedRegisters the registers saved by this operation which may be subject to pruning
354     * @param savedRegisterLocations the slots to which the registers are saved
355     * @param supportsRemove determines if registers can be pruned
356     */
357    protected SPARCSaveRegistersOp emitSaveRegisters(Register[] savedRegisters, StackSlotValue[] savedRegisterLocations, boolean supportsRemove) {
358        SPARCSaveRegistersOp save = new SPARCSaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
359        append(save);
360        return save;
361    }
362
363    public SaveRegistersOp emitSaveAllRegisters() {
364        // We save all registers that were not saved by the save instruction.
365        // @formatter:off
366        Register[] savedRegisters = {
367                        // CPU
368                        g1, g3, g4, g5,
369                        // FPU, use only every second register as doubles are stored anyways
370                        f0,  /*f1, */ f2,  /*f3, */ f4,  /*f5, */ f6,  /*f7, */
371                        f8,  /*f9, */ f10, /*f11,*/ f12, /*f13,*/ f14, /*f15,*/
372                        f16, /*f17,*/ f18, /*f19,*/ f20, /*f21,*/ f22, /*f23,*/
373                        f24, /*f25,*/ f26, /*f27,*/ f28, /*f29,*/ f30, /*f31 */
374                        d32,          d34,          d36,          d38,
375                        d40,          d42,          d44,          d46,
376                        d48,          d50,          d52,          d54,
377                        d56,          d58,          d60,          d62
378        };
379        // @formatter:on
380        StackSlotValue[] savedRegisterLocations = new StackSlotValue[savedRegisters.length];
381        for (int i = 0; i < savedRegisters.length; i++) {
382            PlatformKind kind = target().arch.getLargestStorableKind(savedRegisters[i].getRegisterCategory());
383            assert kind != Kind.Illegal;
384            VirtualStackSlot spillSlot = getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind));
385            savedRegisterLocations[i] = spillSlot;
386        }
387        return emitSaveRegisters(savedRegisters, savedRegisterLocations, false);
388    }
389
390    public void emitLeaveCurrentStackFrame(SaveRegistersOp saveRegisterOp) {
391        append(new SPARCHotSpotLeaveCurrentStackFrameOp());
392    }
393
394    public void emitLeaveDeoptimizedStackFrame(Value frameSize, Value initialInfo) {
395        append(new SPARCHotSpotLeaveDeoptimizedStackFrameOp());
396    }
397
398    public void emitEnterUnpackFramesStackFrame(Value framePc, Value senderSp, Value senderFp, SaveRegistersOp saveRegisterOp) {
399        Register thread = getProviders().getRegisters().getThreadRegister();
400        Variable framePcVariable = load(framePc);
401        Variable senderSpVariable = load(senderSp);
402        Variable scratchVariable = newVariable(LIRKind.value(getHostWordKind()));
403        append(new SPARCHotSpotEnterUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), framePcVariable, senderSpVariable, scratchVariable,
404                        target().wordKind));
405    }
406
407    public void emitLeaveUnpackFramesStackFrame(SaveRegistersOp saveRegisterOp) {
408        Register thread = getProviders().getRegisters().getThreadRegister();
409        append(new SPARCHotSpotLeaveUnpackFramesStackFrameOp(thread, config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset()));
410    }
411
412    public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) {
413        Variable frameSizeVariable = load(frameSize);
414        Variable framePcVariable = load(framePc);
415        Variable senderSpVariable = load(senderSp);
416        Variable initialInfoVariable = load(initialInfo);
417        append(new SPARCHotSpotPushInterpreterFrameOp(frameSizeVariable, framePcVariable, senderSpVariable, initialInfoVariable));
418    }
419
420    public Value emitUncommonTrapCall(Value trapRequest, SaveRegistersOp saveRegisterOp) {
421        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP);
422
423        Register threadRegister = getProviders().getRegisters().getThreadRegister();
424        Value threadTemp = newVariable(LIRKind.value(target().wordKind));
425        Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister();
426        Variable spScratch = newVariable(LIRKind.value(target().wordKind));
427        append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister, threadTemp, spScratch));
428        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(target().wordKind)), trapRequest);
429        append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister, threadTemp));
430
431        Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = ((SPARCHotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo();
432        assert currentRuntimeCallInfo != null;
433        assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
434        calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp);
435
436        return result;
437    }
438
439    @Override
440    public Value emitDeoptimizationFetchUnrollInfoCall(SaveRegistersOp saveRegisterOp) {
441        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(FETCH_UNROLL_INFO);
442
443        Register threadRegister = getProviders().getRegisters().getThreadRegister();
444        Value threadTemp = newVariable(LIRKind.value(target().wordKind));
445        Register stackPointerRegister = getProviders().getRegisters().getStackPointerRegister();
446        Variable spScratch = newVariable(LIRKind.value(target().wordKind));
447        append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), threadRegister, stackPointerRegister, threadTemp, spScratch));
448        Variable result = super.emitForeignCall(linkage, null, threadRegister.asValue(LIRKind.value(target().wordKind)));
449        append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), threadRegister, threadTemp));
450
451        Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = ((SPARCHotSpotLIRGenerationResult) getResult()).getCalleeSaveInfo();
452        assert currentRuntimeCallInfo != null;
453        assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo);
454        calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp);
455
456        return result;
457    }
458
459    @Override
460    public void emitNullCheck(Value address, LIRFrameState state) {
461        PlatformKind kind = address.getPlatformKind();
462        if (kind == Kind.Int) {
463            CompressEncoding encoding = config.getOopEncoding();
464            Value uncompressed = emitUncompress(address, encoding, false);
465            append(new NullCheckOp(asAddressValue(uncompressed), state));
466        } else {
467            super.emitNullCheck(address, state);
468        }
469    }
470
471    @Override
472    public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
473        if (BenchmarkCounters.enabled) {
474            return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config);
475        } else {
476            return null;
477        }
478    }
479
480    @Override
481    public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
482        if (BenchmarkCounters.enabled) {
483            return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config);
484        } else {
485            return null;
486        }
487    }
488
489    public AllocatableValue getSafepointAddressValue() {
490        if (this.safepointAddressValue == null) {
491            this.safepointAddressValue = newVariable(LIRKind.value(target().wordKind));
492        }
493        return this.safepointAddressValue;
494    }
495}