All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jdk.graal.compiler.asm.aarch64.AArch64ASIMDMacroAssembler Maven / Gradle / Ivy

There is a newer version: 24.1.1
Show newest version
/*
 * Copyright (c) 2021, 2023, 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * 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 jdk.graal.compiler.asm.aarch64;

import static jdk.vm.ci.aarch64.AArch64.CPU;
import static jdk.vm.ci.aarch64.AArch64.SIMD;

import jdk.graal.compiler.core.common.NumUtil;
import jdk.graal.compiler.debug.GraalError;
import jdk.vm.ci.code.Register;

public class AArch64ASIMDMacroAssembler extends AArch64ASIMDAssembler {
    private final AArch64MacroAssembler masm;

    public AArch64ASIMDMacroAssembler(AArch64MacroAssembler masm) {
        super(masm);
        this.masm = masm;
    }

    /**
     * Replicates a value to entirely fill an imm64.
     */
    private static long replicateValueToImm64(ElementSize eSize, long val) {
        int elementWidth = eSize.bits();
        assert elementWidth == 64 || NumUtil.isSignedNbit(elementWidth, val);

        long eVal = val & NumUtil.getNbitNumberLong(elementWidth);
        switch (eSize) {
            case Byte:
                return eVal << 56 | eVal << 48 | eVal << 40 | eVal << 32 | eVal << 24 | eVal << 16 | eVal << 8 | eVal;
            case HalfWord:
                return eVal << 48 | eVal << 32 | eVal << 16 | eVal;
            case Word:
                return eVal << 32 | eVal;
            case DoubleWord:
                return eVal;
        }

        throw GraalError.shouldNotReachHereUnexpectedValue(eSize); // ExcludeFromJacocoGeneratedReport
    }

    /**
     * Checks whether a value, which will be placed in all elements, can be encoded as an immediate
     * operand in a vector move instruction.
     */
    public static boolean isMoveImmediate(ElementSize eSize, long imm) {
        long imm64 = replicateValueToImm64(eSize, imm);
        return ASIMDImmediateTable.isEncodable(imm64, ImmediateOp.MOVI) || ASIMDImmediateTable.isEncodable(~imm64, ImmediateOp.MVNI);
    }

    /**
     * Checks whether the provided 64-bit immediate value can be encoded within either a movi or
     * mvni vector instruction.
     */
    private void moveVI(ASIMDSize size, Register reg, long imm64) {
        if (ASIMDImmediateTable.isEncodable(imm64, ImmediateOp.MOVI)) {
            moviVI(size, reg, imm64);
        } else if (ASIMDImmediateTable.isEncodable(~imm64, ImmediateOp.MVNI)) {
            /* Moving not(not(imm64)). */
            mvniVI(size, reg, ~imm64);
        } else {
            throw GraalError.shouldNotReachHereUnexpectedValue(imm64); // ExcludeFromJacocoGeneratedReport
        }
    }

    /**
     * Moves an immediate value into each element of the result.
* * for i in 0..n-1 do dst[i] = imm * * @param size register size. * @param eSize element size. Must be ElementSize.Word or ElementSize.DoubleWord. Note * ElementSize.DoubleWord is only applicable when size is 128 (i.e. the operation is * performed on more than one element). * @param dst SIMD register. * @param imm value to copy into each element. */ public void moveVI(ASIMDSize size, ElementSize eSize, Register dst, long imm) { moveVI(size, dst, replicateValueToImm64(eSize, imm)); } /** * Checks whether a float, which will be placed in all elements, can be encoded as an immediate * operand in a vector move instruction. */ public static boolean isMoveImmediate(float imm) { long imm64 = replicateValueToImm64(ElementSize.Word, Float.floatToIntBits(imm)); return ASIMDImmediateTable.isEncodable(imm64, ImmediateOp.FMOVSP); } /** * Moves an immediate value into each element of the result.
* * for i in 0..n-1 do dst[i] = imm * * @param size register size. * @param dst SIMD register. * @param imm value to copy into each element. */ public void moveVI(ASIMDSize size, Register dst, float imm) { ElementSize eSize = ElementSize.Word; fmovVI(size, eSize, dst, replicateValueToImm64(eSize, Float.floatToIntBits(imm))); } /** * Checks whether a double, which will be placed in all elements, can be encoded as an immediate * operand in a vector move instruction. */ public static boolean isMoveImmediate(double imm) { return ASIMDImmediateTable.isEncodable(Double.doubleToLongBits(imm), ImmediateOp.FMOVDP); } /** * Moves an immediate value into each element of the result.
* * for i in 0..n-1 do dst[i] = imm */ public void moveVI(ASIMDSize size, Register dst, double imm) { fmovVI(size, ElementSize.DoubleWord, dst, Double.doubleToLongBits(imm)); } /** * Moves a vector. This instruction copies the vector in the source SIMD register into the * destination SIMD register.
* * for i in 0..n-1 do dst[i] = src[i] */ public void moveVV(ASIMDSize size, Register dst, Register src) { if (!src.equals(dst)) { orrVVV(size, dst, src, src); } } /** * Checks whether a 64-bit value can be encoded as an immediate operand in the given * instruction. */ private static boolean isImmediateEncodable(ImmediateOp op, long imm64) { return ASIMDImmediateTable.isEncodable(imm64, op); } /** * Checks whether a value, which will be placed in all elements, can be encoded as an immediate * operand in the provided operation. */ private static boolean isImmediateEncodable(ImmediateOp op, ElementSize eSize, long imm) { return isImmediateEncodable(op, replicateValueToImm64(eSize, imm)); } /** * Checks whether a value, which will be placed in all elements, can be encoded as an immediate * operand in a vector bitwise inclusive or instruction. */ public static boolean isOrrImmediate(ElementSize eSize, long imm) { return isImmediateEncodable(ImmediateOp.ORR, eSize, imm); } /** * Performs a bitwise inclusive or with the provided immediate on each element. * * for i in 0..n-1 do dst[i] |= imm */ public void orrVI(ASIMDSize size, ElementSize eSize, Register dst, long imm) { long imm64 = replicateValueToImm64(eSize, imm); assert isImmediateEncodable(ImmediateOp.ORR, imm64); orrVI(size, dst, imm64); } /** * Checks whether a value, which will be placed in all elements, can be encoded as an immediate * operand in a vector bit clear instruction. */ public static boolean isBicImmediate(ElementSize eSize, long imm) { return isImmediateEncodable(ImmediateOp.BIC, eSize, imm); } /** * Performs a bitwise bit clear with the provided immediate on each element. * * for i in 0..n-1 do dst[i] &^= imm */ public void bicVI(ASIMDSize size, ElementSize eSize, Register dst, long imm) { long imm64 = replicateValueToImm64(eSize, imm); assert isImmediateEncodable(ImmediateOp.BIC, imm64); bicVI(size, dst, imm64); } /** * Performs right rotate on the provided register. */ public void elementRor(ASIMDSize size, ElementSize eSize, Register dst, Register src, int rorAmt) { int byteRorAmt = eSize.bytes() * rorAmt; // can't perform a full rotation assert byteRorAmt >= 0 && byteRorAmt < size.bytes() : byteRorAmt + " " + size; extVVV(size, dst, src, src, byteRorAmt); } /** * Moves an indexed SIMD element to a floating-point or general-purpose register.
* * dst = src[index] * * @param dstESize width of destination element. * @param srcESize width of source element. * @param dst Either floating-point or general-purpose register. If general-purpose, register * may not be stackpointer or zero register. * @param src SIMD register. * @param index lane position of element to copy. */ public void moveFromIndex(ElementSize dstESize, ElementSize srcESize, Register dst, Register src, int index) { assert src.getRegisterCategory().equals(SIMD); boolean sameWidth = dstESize == srcESize; int dstBits = dstESize.bits(); if (index == 0 && sameWidth && (dstBits == 32 || dstBits == 64)) { masm.fmov(dstBits, dst, src); } else if (sameWidth && dst.getRegisterCategory().equals(CPU)) { umovGX(srcESize, dst, src, index); } else if (dst.getRegisterCategory().equals(CPU)) { assert !sameWidth : dstESize + " " + srcESize + " " + dst + " " + src + " " + index; smovGX(dstESize, srcESize, dst, src, index); } else { assert dst.getRegisterCategory().equals(SIMD); dupSX(srcESize, dst, src, index); } } /** * Reverse the byte-order (endianess) of each element. * * @param size register size. * @param eSize element size. * @param dst SIMD register. * @param src SIMD register. */ public void revVV(ASIMDSize size, ElementSize eSize, Register dst, Register src) { switch (eSize) { case Byte: // nothing to do - only 1 byte break; case HalfWord: masm.neon.rev16VV(size, dst, src); break; case Word: masm.neon.rev32VV(size, ElementSize.Byte, dst, src); break; case DoubleWord: masm.neon.rev64VV(size, ElementSize.Byte, dst, src); break; default: throw GraalError.shouldNotReachHereUnexpectedValue(eSize); // ExcludeFromJacocoGeneratedReport } } /** * C7.2.200 Move vector element to another vector element.
*

* Preferred alias for insert vector element from another vector element. * * @param eSize size of value to duplicate. * @param dst SIMD register. * @param dstIdx offset of value to store. * @param src SIMD register. * @param srcIdx offset of value to duplicate. */ public void movXX(ElementSize eSize, Register dst, int dstIdx, Register src, int srcIdx) { insXX(eSize, dst, dstIdx, src, srcIdx); } /** * C7.2.207 Bitwise not.
*

* Preferred alias for bitwise not (NOT). * * @param size register size. * @param dst SIMD register. * @param src SIMD register. */ public void mvnVV(ASIMDSize size, Register dst, Register src) { notVV(size, dst, src); } /** * C7.2.338 Signed extend long.
*

* Preferred alias for sshll when only sign-extending the vector elements. * * Extracts vector elements from the lower half of the source register. * * @param srcESize source element size. Cannot be ElementSize.DoubleWord. The destination * element size will be double this width. * @param dst SIMD register. * @param src SIMD register. */ public void sxtlVV(ElementSize srcESize, Register dst, Register src) { sshllVVI(srcESize, dst, src, 0); } /** * C7.2.338 Signed extend long.
*

* Preferred alias for sshll2 when only sign-extending the vector elements. * * Extracts vector elements from the upper half of the source register. * * @param srcESize source element size. Cannot be ElementSize.DoubleWord. The destination * element size will be double this width. * @param dst SIMD register. * @param src SIMD register. */ public void sxtl2VV(ElementSize srcESize, Register dst, Register src) { sshll2VVI(srcESize, dst, src, 0); } /** * C7.2.398 Unsigned extend long.
*

* Preferred alias for ushll when only zero-extending the vector elements. * * Extracts vector elements from the lower half of the source register. * * @param srcESize source element size. Cannot be ElementSize.DoubleWord. The destination * element size will be double this width. * @param dst SIMD register. * @param src SIMD register. */ public void uxtlVV(ElementSize srcESize, Register dst, Register src) { ushllVVI(srcESize, dst, src, 0); } /** * C7.2.398 Unsigned extend long.
*

* Preferred alias for ushll2 when only zero-extending the vector elements. * * Extracts vector elements from the upper half of the source register. * * @param srcESize source element size. Cannot be ElementSize.DoubleWord. The destination * element size will be double this width. * @param dst SIMD register. * @param src SIMD register. */ public void uxtl2VV(ElementSize srcESize, Register dst, Register src) { ushll2VVI(srcESize, dst, src, 0); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy