/*
 * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


package org.graalvm.compiler.asm.amd64;

import static jdk.vm.ci.amd64.AMD64.rbp;
import static jdk.vm.ci.amd64.AMD64.rsp;
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseIncDec;
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmLoadAndClearUpper;
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmRegToRegMoveAll;

import org.graalvm.compiler.core.common.NumUtil;

import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.amd64.AMD64Kind;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.TargetDescription;

This class implements commonly used X86 code patterns.
/** * This class implements commonly used X86 code patterns. */
public class AMD64MacroAssembler extends AMD64Assembler { public AMD64MacroAssembler(TargetDescription target) { super(target); } public final void decrementq(Register reg, int value) { if (value == Integer.MIN_VALUE) { subq(reg, value); return; } if (value < 0) { incrementq(reg, -value); return; } if (value == 0) { return; } if (value == 1 && UseIncDec) { decq(reg); } else { subq(reg, value); } } public final void decrementq(AMD64Address dst, int value) { if (value == Integer.MIN_VALUE) { subq(dst, value); return; } if (value < 0) { incrementq(dst, -value); return; } if (value == 0) { return; } if (value == 1 && UseIncDec) { decq(dst); } else { subq(dst, value); } } public final void enter(int frameSize) { if (NumUtil.isUShort(frameSize)) { // Can use enter instruction only for frame size that fits in 16 bits. emitByte(0xC8); emitShort(frameSize); emitByte(0x00); } else { // Fall back to manual sequence. push(rbp); movq(rbp, rsp); decrementq(rsp, frameSize); } } public void incrementq(Register reg, int value) { if (value == Integer.MIN_VALUE) { addq(reg, value); return; } if (value < 0) { decrementq(reg, -value); return; } if (value == 0) { return; } if (value == 1 && UseIncDec) { incq(reg); } else { addq(reg, value); } } public final void incrementq(AMD64Address dst, int value) { if (value == Integer.MIN_VALUE) { addq(dst, value); return; } if (value < 0) { decrementq(dst, -value); return; } if (value == 0) { return; } if (value == 1 && UseIncDec) { incq(dst); } else { addq(dst, value); } } public final void movptr(Register dst, AMD64Address src) { movq(dst, src); } public final void movptr(AMD64Address dst, Register src) { movq(dst, src); } public final void movptr(AMD64Address dst, int src) { movslq(dst, src); } public final void cmpptr(Register src1, Register src2) { cmpq(src1, src2); } public final void cmpptr(Register src1, AMD64Address src2) { cmpq(src1, src2); } public final void decrementl(Register reg) { decrementl(reg, 1); } public final void decrementl(Register reg, int value) { if (value == Integer.MIN_VALUE) { subl(reg, value); return; } if (value < 0) { incrementl(reg, -value); return; } if (value == 0) { return; } if (value == 1 && UseIncDec) { decl(reg); } else { subl(reg, value); } } public final void decrementl(AMD64Address dst, int value) { if (value == Integer.MIN_VALUE) { subl(dst, value); return; } if (value < 0) { incrementl(dst, -value); return; } if (value == 0) { return; } if (value == 1 && UseIncDec) { decl(dst); } else { subl(dst, value); } } public final void incrementl(Register reg, int value) { if (value == Integer.MIN_VALUE) { addl(reg, value); return; } if (value < 0) { decrementl(reg, -value); return; } if (value == 0) { return; } if (value == 1 && UseIncDec) { incl(reg); } else { addl(reg, value); } } public final void incrementl(AMD64Address dst, int value) { if (value == Integer.MIN_VALUE) { addl(dst, value); return; } if (value < 0) { decrementl(dst, -value); return; } if (value == 0) { return; } if (value == 1 && UseIncDec) { incl(dst); } else { addl(dst, value); } } public void movflt(Register dst, Register src) { assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); if (UseXmmRegToRegMoveAll) { movaps(dst, src); } else { movss(dst, src); } } public void movflt(Register dst, AMD64Address src) { assert dst.getRegisterCategory().equals(AMD64.XMM); movss(dst, src); } public void movflt(AMD64Address dst, Register src) { assert src.getRegisterCategory().equals(AMD64.XMM); movss(dst, src); } public void movdbl(Register dst, Register src) { assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM); if (UseXmmRegToRegMoveAll) { movapd(dst, src); } else { movsd(dst, src); } } public void movdbl(Register dst, AMD64Address src) { assert dst.getRegisterCategory().equals(AMD64.XMM); if (UseXmmLoadAndClearUpper) { movsd(dst, src); } else { movlpd(dst, src); } } public void movdbl(AMD64Address dst, Register src) { assert src.getRegisterCategory().equals(AMD64.XMM); movsd(dst, src); }
Non-atomic write of a 64-bit constant to memory. Do not use if the address might be a volatile field!
/** * Non-atomic write of a 64-bit constant to memory. Do not use if the address might be a * volatile field! */
public final void movlong(AMD64Address dst, long src) { if (NumUtil.isInt(src)) { AMD64MIOp.MOV.emit(this, OperandSize.QWORD, dst, (int) src); } else { AMD64Address high = new AMD64Address(dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4); movl(dst, (int) (src & 0xFFFFFFFF)); movl(high, (int) (src >> 32)); } } public final void setl(ConditionFlag cc, Register dst) { setb(cc, dst); movzbl(dst, dst); } public final void setq(ConditionFlag cc, Register dst) { setb(cc, dst); movzbq(dst, dst); } public final void flog(Register dest, Register value, boolean base10) { if (base10) { fldlg2(); } else { fldln2(); } AMD64Address tmp = trigPrologue(value); fyl2x(); trigEpilogue(dest, tmp); } public final void fsin(Register dest, Register value) { AMD64Address tmp = trigPrologue(value); fsin(); trigEpilogue(dest, tmp); } public final void fcos(Register dest, Register value) { AMD64Address tmp = trigPrologue(value); fcos(); trigEpilogue(dest, tmp); } public final void ftan(Register dest, Register value) { AMD64Address tmp = trigPrologue(value); fptan(); fstp(0); // ftan pushes 1.0 in addition to the actual result, pop trigEpilogue(dest, tmp); } public final void fpop() { ffree(0); fincstp(); } private AMD64Address trigPrologue(Register value) { assert value.getRegisterCategory().equals(AMD64.XMM); AMD64Address tmp = new AMD64Address(AMD64.rsp); subq(AMD64.rsp, AMD64Kind.DOUBLE.getSizeInBytes()); movdbl(tmp, value); fldd(tmp); return tmp; } private void trigEpilogue(Register dest, AMD64Address tmp) { assert dest.getRegisterCategory().equals(AMD64.XMM); fstpd(tmp); movdbl(dest, tmp); addq(AMD64.rsp, AMD64Kind.DOUBLE.getSizeInBytes()); } }