package org.graalvm.compiler.lir.amd64;
import static jdk.vm.ci.code.ValueUtil.asRegister;
import static jdk.vm.ci.code.ValueUtil.isRegister;
import static jdk.vm.ci.code.ValueUtil.isStackSlot;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
import java.util.Objects;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.asm.amd64.AMD64Address;
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.asm.amd64.AMD64Assembler;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexMoveOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRMIOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRMOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp;
import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize;
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
import org.graalvm.compiler.asm.amd64.AVXKind;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.lir.ConstantValue;
import org.graalvm.compiler.lir.LIRInstructionClass;
import org.graalvm.compiler.lir.Opcode;
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.amd64.AMD64.CPUFeature;
import jdk.vm.ci.amd64.AMD64Kind;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.Value;
@Opcode("AMD64_ARRAY_INDEX_OF")
public final class AMD64ArrayIndexOfOp extends AMD64LIRInstruction {
public static final LIRInstructionClass<AMD64ArrayIndexOfOp> TYPE = LIRInstructionClass.create(AMD64ArrayIndexOfOp.class);
private final JavaKind valueKind;
private final int nValues;
private final boolean findTwoConsecutive;
private final AMD64Kind vectorKind;
private final int arrayBaseOffset;
private final Scale arrayIndexScale;
@Def({REG}) protected Value resultValue;
@Alive({REG}) protected Value arrayPtrValue;
@Alive({REG}) protected Value arrayLengthValue;
@Use({REG}) protected Value fromIndexValue;
@Alive({REG, STACK, CONST}) protected Value searchValue1;
@Alive({REG, STACK, CONST, ILLEGAL}) protected Value searchValue2;
@Alive({REG, STACK, CONST, ILLEGAL}) protected Value searchValue3;
@Alive({REG, STACK, CONST, ILLEGAL}) protected Value searchValue4;
@Temp({REG}) protected Value comparisonResult1;
@Temp({REG, ILLEGAL}) protected Value comparisonResult2;
@Temp({REG, ILLEGAL}) protected Value vectorCompareVal1;
@Temp({REG, ILLEGAL}) protected Value vectorCompareVal2;
@Temp({REG, ILLEGAL}) protected Value vectorCompareVal3;
@Temp({REG, ILLEGAL}) protected Value vectorCompareVal4;
@Temp({REG, ILLEGAL}) protected Value vectorArray1;
@Temp({REG, ILLEGAL}) protected Value vectorArray2;
@Temp({REG, ILLEGAL}) protected Value vectorArray3;
@Temp({REG, ILLEGAL}) protected Value vectorArray4;
public AMD64ArrayIndexOfOp(JavaKind arrayKind, JavaKind valueKind, boolean findTwoConsecutive, int maxVectorSize, LIRGeneratorTool tool,
Value result, Value arrayPtr, Value arrayLength, Value fromIndex, Value... searchValues) {
super(TYPE);
this.valueKind = valueKind;
this.arrayBaseOffset = tool.getProviders().getMetaAccess().getArrayBaseOffset(arrayKind);
this.arrayIndexScale = Objects.requireNonNull(Scale.fromInt(tool.getProviders().getMetaAccess().getArrayIndexScale(valueKind)));
this.findTwoConsecutive = findTwoConsecutive;
assert 0 < searchValues.length && searchValues.length <= 4;
assert byteMode(valueKind) || charMode(valueKind);
assert supports(tool, CPUFeature.SSE2) || supports(tool, CPUFeature.AVX) || supportsAVX2(tool);
nValues = searchValues.length;
assert !findTwoConsecutive || nValues == 1;
resultValue = result;
arrayPtrValue = arrayPtr;
arrayLengthValue = arrayLength;
fromIndexValue = fromIndex;
searchValue1 = searchValues[0];
searchValue2 = nValues > 1 ? searchValues[1] : Value.ILLEGAL;
searchValue3 = nValues > 2 ? searchValues[2] : Value.ILLEGAL;
searchValue4 = nValues > 3 ? searchValues[3] : Value.ILLEGAL;
comparisonResult1 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind()));
comparisonResult2 = findTwoConsecutive ? tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())) : Value.ILLEGAL;
vectorKind = supportsAVX2(tool) && (maxVectorSize < 0 || maxVectorSize >= 32) ? byteMode(valueKind) ? AMD64Kind.V256_BYTE : AMD64Kind.V256_WORD
: byteMode(valueKind) ? AMD64Kind.V128_BYTE : AMD64Kind.V128_WORD;
vectorCompareVal1 = tool.newVariable(LIRKind.value(vectorKind));
vectorCompareVal2 = nValues > 1 ? tool.newVariable(LIRKind.value(vectorKind)) : Value.ILLEGAL;
vectorCompareVal3 = nValues > 2 ? tool.newVariable(LIRKind.value(vectorKind)) : Value.ILLEGAL;
vectorCompareVal4 = nValues > 3 ? tool.newVariable(LIRKind.value(vectorKind)) : Value.ILLEGAL;
vectorArray1 = tool.newVariable(LIRKind.value(vectorKind));
vectorArray2 = tool.newVariable(LIRKind.value(vectorKind));
vectorArray3 = tool.newVariable(LIRKind.value(vectorKind));
vectorArray4 = tool.newVariable(LIRKind.value(vectorKind));
}
private static boolean byteMode(JavaKind kind) {
return kind == JavaKind.Byte;
}
private static boolean charMode(JavaKind kind) {
return kind == JavaKind.Char;
}
private JavaKind getComparisonKind() {
return findTwoConsecutive ? (byteMode(valueKind) ? JavaKind.Char : JavaKind.Int) : valueKind;
}
private AVXKind.AVXSize getVectorSize() {
return AVXKind.getDataSize(vectorKind);
}
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) {
int nVectors = nValues == 1 ? 4 : nValues == 2 ? 2 : 1;
Register arrayPtr = asRegister(arrayPtrValue);
Register arrayLength = asRegister(arrayLengthValue);
Register fromIndex = asRegister(fromIndexValue);
Register index = asRegister(resultValue);
Value[] searchValue = {
nValues > 0 ? searchValue1 : null,
nValues > 1 ? searchValue2 : null,
nValues > 2 ? searchValue3 : null,
nValues > 3 ? searchValue4 : null,
};
Register[] vecCmp = {
nValues > 0 ? asRegister(vectorCompareVal1) : null,
nValues > 1 ? asRegister(vectorCompareVal2) : null,
nValues > 2 ? asRegister(vectorCompareVal3) : null,
nValues > 3 ? asRegister(vectorCompareVal4) : null,
};
Register[] vecArray = {
asRegister(vectorArray1),
asRegister(vectorArray2),
asRegister(vectorArray3),
asRegister(vectorArray4),
};
Register[] cmpResult = {
asRegister(comparisonResult1),
findTwoConsecutive ? asRegister(comparisonResult2) : null,
};
Label ret = new Label();
Label bulkVectorLoop = new Label();
Label singleVectorLoop = new Label();
Label[] vectorFound = {
new Label(),
new Label(),
new Label(),
new Label(),
};
Label runVectorized = new Label();
Label elementWiseLoop = new Label();
Label elementWiseFound = new Label();
Label elementWiseNotFound = new Label();
Label skipBulkVectorLoop = new Label();
int vectorSize = getVectorSize().getBytes() / valueKind.getByteCount();
int bulkSize = vectorSize * nVectors;
JavaKind vectorCompareKind = valueKind;
if (findTwoConsecutive) {
bulkSize /= 2;
vectorCompareKind = byteMode(valueKind) ? JavaKind.Char : JavaKind.Int;
}
asm.leaq(index, new AMD64Address(fromIndex, vectorSize + (findTwoConsecutive ? 1 : 0)));
asm.cmpqAndJcc(index, arrayLength, ConditionFlag.LessEqual, runVectorized, true);
asm.subq(index, vectorSize);
asm.cmpqAndJcc(index, arrayLength, ConditionFlag.GreaterEqual, elementWiseNotFound, true);
asm.bind(elementWiseLoop);
OperandSize cmpSize = getOpSize(getComparisonKind());
AMD64Address arrayAddr = new AMD64Address(arrayPtr, index, arrayIndexScale, arrayBaseOffset - (findTwoConsecutive ? valueKind.getByteCount() : 0));
boolean valuesOnStack = searchValuesOnStack(searchValue);
if (valuesOnStack) {
(cmpSize == OperandSize.BYTE ? AMD64RMOp.MOVB : AMD64RMOp.MOV).emit(asm, cmpSize, cmpResult[0], arrayAddr);
for (int i = 0; i < nValues; i++) {
if (isConstant(searchValue[i])) {
int imm = asConstant(searchValue[i]).asInt();
AMD64Assembler.AMD64BinaryArithmetic.CMP.getMIOpcode(cmpSize, NumUtil.isByte(imm)).emit(asm, cmpSize, cmpResult[0], imm);
} else if (isStackSlot(searchValue[i])) {
AMD64Assembler.AMD64BinaryArithmetic.CMP.getRMOpcode(cmpSize).emit(asm, cmpSize, cmpResult[0], (AMD64Address) crb.asAddress(searchValue[i]));
} else {
AMD64Assembler.AMD64BinaryArithmetic.CMP.getRMOpcode(cmpSize).emit(asm, cmpSize, cmpResult[0], asRegister(searchValue[i]));
}
asm.jccb(AMD64Assembler.ConditionFlag.Equal, elementWiseFound);
}
} else {
for (int i = 0; i < nValues; i++) {
if (isConstant(searchValue[i])) {
int imm = asConstant(searchValue[i]).asInt();
AMD64Assembler.AMD64BinaryArithmetic.CMP.getMIOpcode(cmpSize, NumUtil.isByte(imm)).emit(asm, cmpSize, arrayAddr, imm);
} else {
AMD64Assembler.AMD64BinaryArithmetic.CMP.getRMOpcode(cmpSize).emit(asm, cmpSize, asRegister(searchValue[i]), arrayAddr);
}
asm.jccb(AMD64Assembler.ConditionFlag.Equal, elementWiseFound);
}
}
asm.incrementq(index, 1);
asm.cmpqAndJcc(index, arrayLength, ConditionFlag.Less, elementWiseLoop, true);
asm.bind(elementWiseNotFound);
asm.xorq(index, index);
if (findTwoConsecutive) {
asm.bind(elementWiseFound);
asm.decrementq(index, 1);
} else {
asm.decrementq(index, 1);
asm.bind(elementWiseFound);
}
asm.jmp(ret);
asm.bind(runVectorized);
for (int i = 0; i < nValues; i++) {
broadcastSearchValue(crb, asm, vecCmp[i], searchValue[i], cmpResult[0], vecArray[0]);
}
emitVectorCompare(asm, vectorCompareKind, findTwoConsecutive ? 2 : 1, arrayPtr, index, vecCmp, vecArray, cmpResult, vectorFound, false, false);
asm.leaq(cmpResult[0], new AMD64Address(arrayPtr, arrayBaseOffset));
if (charMode(valueKind)) {
asm.shrq(cmpResult[0], 1);
}
asm.addq(index, cmpResult[0]);
asm.andq(index, ~(vectorSize - 1));
asm.subq(index, cmpResult[0]);
asm.addq(index, bulkSize);
asm.cmpqAndJcc(index, arrayLength, ConditionFlag.Greater, skipBulkVectorLoop, true);
emitAlign(crb, asm);
asm.bind(bulkVectorLoop);
emitVectorCompare(asm, vectorCompareKind, nVectors, arrayPtr, index, vecCmp, vecArray, cmpResult, vectorFound, false, !findTwoConsecutive);
asm.addq(index, bulkSize);
asm.cmpqAndJcc(index, arrayLength, ConditionFlag.LessEqual, bulkVectorLoop, true);
asm.bind(skipBulkVectorLoop);
if ((findTwoConsecutive && nVectors == 2) || nVectors == 1) {
asm.movq(index, arrayLength);
emitVectorCompare(asm, vectorCompareKind, findTwoConsecutive ? 2 : 1, arrayPtr, index, vecCmp, vecArray, cmpResult, vectorFound, true, false);
} else {
asm.subq(index, bulkSize);
emitAlign(crb, asm);
asm.bind(singleVectorLoop);
asm.addq(index, vectorSize);
asm.cmpq(index, arrayLength);
asm.cmovq(AMD64Assembler.ConditionFlag.Greater, index, arrayLength);
emitVectorCompare(asm, vectorCompareKind, findTwoConsecutive ? 2 : 1, arrayPtr, index, vecCmp, vecArray, cmpResult, vectorFound, true, false);
asm.cmpqAndJcc(index, arrayLength, ConditionFlag.Less, singleVectorLoop, true);
}
asm.movl(index, -1);
asm.jmpb(ret);
if (findTwoConsecutive) {
Label vectorFound2Done = new Label();
asm.bind(vectorFound[2]);
asm.subq(index, getResultIndexDelta(2));
asm.jmpb(vectorFound2Done);
asm.bind(vectorFound[0]);
asm.subq(index, getResultIndexDelta(0));
asm.bind(vectorFound2Done);
asm.bsfq(cmpResult[0], cmpResult[0]);
if (charMode(valueKind)) {
asm.shrl(cmpResult[0], 1);
}
asm.addq(index, cmpResult[0]);
asm.jmpb(ret);
Label minResult = new Label();
Label minResultDone = new Label();
if (nVectors > 2) {
asm.bind(vectorFound[3]);
asm.subq(index, getResultIndexDelta(3));
asm.jmpb(minResult);
}
asm.bind(vectorFound[1]);
asm.subq(index, getResultIndexDelta(1));
asm.bind(minResult);
asm.bsfq(cmpResult[1], cmpResult[1]);
asm.testqAndJcc(cmpResult[0], cmpResult[0], ConditionFlag.Zero, minResultDone, true);
asm.bsfq(cmpResult[0], cmpResult[0]);
asm.addq(cmpResult[0], valueKind.getByteCount());
asm.cmpq(cmpResult[1], cmpResult[0]);
asm.cmovq(AMD64Assembler.ConditionFlag.Greater, cmpResult[1], cmpResult[0]);
asm.bind(minResultDone);
if (charMode(valueKind)) {
asm.shrl(cmpResult[1], 1);
}
asm.addq(index, cmpResult[1]);
} else {
Label end = new Label();
for (int i = 0; i < nVectors; i++) {
asm.bind(vectorFound[i]);
asm.subq(index, getResultIndexDelta(i));
if (i < nVectors - 1) {
asm.jmpb(end);
}
}
asm.bind(end);
asm.bsfq(cmpResult[0], cmpResult[0]);
if (charMode(valueKind)) {
asm.shrl(cmpResult[0], 1);
}
asm.addq(index, cmpResult[0]);
}
asm.bind(ret);
}
private boolean searchValuesOnStack(Value[] searchValue) {
for (int i = 0; i < nValues; i++) {
if (isStackSlot(searchValue[i])) {
return true;
}
}
return false;
}
private int getResultIndexDelta(int i) {
return (((findTwoConsecutive ? i / 2 : i) + 1) * (getVectorSize().getBytes() / valueKind.getByteCount())) + (findTwoConsecutive ? (i & 1) : 0);
}
private int getVectorOffset(int i) {
return arrayBaseOffset - getResultIndexDelta(i) * valueKind.getByteCount();
}
private void broadcastSearchValue(CompilationResultBuilder crb, AMD64MacroAssembler asm, Register dst, Value srcVal, Register tmpReg, Register tmpVector) {
Register src = asRegOrTmpReg(crb, asm, srcVal, tmpReg);
if (asm.supports(CPUFeature.AVX)) {
VexMoveOp.VMOVD.emit(asm, AVXKind.AVXSize.DWORD, dst, src);
} else {
asm.movdl(dst, src);
}
emitBroadcast(asm, getComparisonKind(), dst, tmpVector, getVectorSize());
}
private static boolean isConstant(Value val) {
assert !(val instanceof ConstantValue) || ((ConstantValue) val).isJavaConstant();
return val instanceof ConstantValue;
}
private static JavaConstant asConstant(Value val) {
return ((ConstantValue) val).getJavaConstant();
}
private static Register asRegOrTmpReg(CompilationResultBuilder crb, AMD64MacroAssembler asm, Value val, Register tmpReg) {
if (isRegister(val)) {
return asRegister(val);
} else if (isStackSlot(val)) {
asm.movl(tmpReg, (AMD64Address) crb.asAddress(val));
return tmpReg;
} else {
assert isConstant(val);
asm.movl(tmpReg, asConstant(val).asInt());
return tmpReg;
}
}
private static void emitAlign(CompilationResultBuilder crb, AMD64MacroAssembler asm) {
asm.align(crb.target.wordSize * 2);
}
private static void emitBroadcast(AMD64MacroAssembler asm, JavaKind kind, Register vecDst, Register vecTmp, AVXKind.AVXSize vectorSize) {
switch (kind) {
case Byte:
if (asm.supports(CPUFeature.AVX2)) {
VexRMOp.VPBROADCASTB.emit(asm, vectorSize, vecDst, vecDst);
} else if (asm.supports(CPUFeature.AVX)) {
VexRVMOp.VPXOR.emit(asm, vectorSize, vecTmp, vecTmp, vecTmp);
VexRVMOp.VPSHUFB.emit(asm, vectorSize, vecDst, vecDst, vecTmp);
} else if (asm.supports(CPUFeature.SSSE3)) {
asm.pxor(vecTmp, vecTmp);
asm.pshufb(vecDst, vecTmp);
} else {
asm.punpcklbw(vecDst, vecDst);
asm.punpcklbw(vecDst, vecDst);
asm.pshufd(vecDst, vecDst, 0);
}
break;
case Short:
case Char:
if (asm.supports(CPUFeature.AVX2)) {
VexRMOp.VPBROADCASTW.emit(asm, vectorSize, vecDst, vecDst);
} else if (asm.supports(CPUFeature.AVX)) {
VexRMIOp.VPSHUFLW.emit(asm, vectorSize, vecDst, vecDst, 0);
VexRMIOp.VPSHUFD.emit(asm, vectorSize, vecDst, vecDst, 0);
} else {
asm.pshuflw(vecDst, vecDst, 0);
asm.pshufd(vecDst, vecDst, 0);
}
break;
case Int:
if (asm.supports(CPUFeature.AVX2)) {
VexRMOp.VPBROADCASTD.emit(asm, vectorSize, vecDst, vecDst);
} else if (asm.supports(CPUFeature.AVX)) {
VexRMIOp.VPSHUFD.emit(asm, vectorSize, vecDst, vecDst, 0);
} else {
asm.pshufd(vecDst, vecDst, 0);
}
break;
default:
throw new UnsupportedOperationException();
}
}
private void emitVectorCompare(AMD64MacroAssembler asm,
JavaKind kind,
int nVectors,
Register arrayPtr,
Register index,
Register[] vecCmp,
Register[] vecArray,
Register[] cmpResult,
Label[] vectorFound,
boolean shortJmp,
boolean alignedLoad) {
for (int i = 0; i < nVectors; i++) {
int base = i * nValues;
for (int j = 0; j < nValues; j++) {
emitArrayLoad(asm, getVectorSize(), vecArray[base + j], arrayPtr, index, getVectorOffset(nVectors - (i + 1)), alignedLoad);
}
}
if (!findTwoConsecutive) {
for (int i = 0; i < nVectors; i++) {
int base = i * nValues;
for (int j = 0; j < nValues; j++) {
emitVectorCompareInst(asm, kind, getVectorSize(), vecArray[base + j], vecCmp[j]);
if ((j & 1) == 1) {
emitPOR(asm, getVectorSize(), vecArray[base + j - 1], vecArray[base + j]);
}
}
if (nValues > 2) {
emitPOR(asm, getVectorSize(), vecArray[base], vecArray[base + 2]);
}
emitMOVMSK(asm, getVectorSize(), cmpResult[0], vecArray[base]);
asm.testlAndJcc(cmpResult[0], cmpResult[0], ConditionFlag.NotZero, vectorFound[nVectors - (i + 1)], shortJmp);
}
} else {
for (int i = 0; i < nVectors; i += 2) {
emitVectorCompareInst(asm, kind, getVectorSize(), vecArray[i], vecCmp[0]);
emitVectorCompareInst(asm, kind, getVectorSize(), vecArray[i + 1], vecCmp[0]);
emitMOVMSK(asm, getVectorSize(), cmpResult[1], vecArray[i]);
emitMOVMSK(asm, getVectorSize(), cmpResult[0], vecArray[i + 1]);
asm.testlAndJcc(cmpResult[1], cmpResult[1], ConditionFlag.NotZero, vectorFound[nVectors - (i + 1)], shortJmp);
asm.testlAndJcc(cmpResult[0], cmpResult[0], ConditionFlag.NotZero, vectorFound[nVectors - (i + 2)], shortJmp);
}
}
}
private void emitArrayLoad(AMD64MacroAssembler asm, AVXKind.AVXSize vectorSize, Register vecDst, Register arrayPtr, Register index, int offset, boolean alignedLoad) {
AMD64Address src = new AMD64Address(arrayPtr, index, arrayIndexScale, offset);
if (asm.supports(CPUFeature.AVX)) {
VexMoveOp loadOp = alignedLoad ? VexMoveOp.VMOVDQA32 : VexMoveOp.VMOVDQU32;
loadOp.emit(asm, vectorSize, vecDst, src);
} else {
asm.movdqu(vecDst, src);
}
}
private static void emitVectorCompareInst(AMD64MacroAssembler asm, JavaKind kind, AVXKind.AVXSize vectorSize, Register vecArray, Register vecCmp) {
switch (kind) {
case Byte:
if (asm.supports(CPUFeature.AVX)) {
VexRVMOp.VPCMPEQB.emit(asm, vectorSize, vecArray, vecCmp, vecArray);
} else {
asm.pcmpeqb(vecArray, vecCmp);
}
break;
case Short:
case Char:
if (asm.supports(CPUFeature.AVX)) {
VexRVMOp.VPCMPEQW.emit(asm, vectorSize, vecArray, vecCmp, vecArray);
} else {
asm.pcmpeqw(vecArray, vecCmp);
}
break;
case Int:
if (asm.supports(CPUFeature.AVX)) {
VexRVMOp.VPCMPEQD.emit(asm, vectorSize, vecArray, vecCmp, vecArray);
} else {
asm.pcmpeqd(vecArray, vecCmp);
}
break;
default:
throw new UnsupportedOperationException();
}
}
private static void emitPOR(AMD64MacroAssembler asm, AVXKind.AVXSize vectorSize, Register dst, Register vecSrc) {
if (asm.supports(CPUFeature.AVX)) {
VexRVMOp.VPOR.emit(asm, vectorSize, dst, dst, vecSrc);
} else {
asm.por(dst, vecSrc);
}
}
private static void emitMOVMSK(AMD64MacroAssembler asm, AVXKind.AVXSize vectorSize, Register dst, Register vecSrc) {
if (asm.supports(CPUFeature.AVX)) {
VexRMOp.VPMOVMSKB.emit(asm, vectorSize, dst, vecSrc);
} else {
asm.pmovmskb(dst, vecSrc);
}
}
private static OperandSize getOpSize(JavaKind kind) {
switch (kind) {
case Byte:
return OperandSize.BYTE;
case Short:
case Char:
return OperandSize.WORD;
case Int:
return OperandSize.DWORD;
default:
return OperandSize.QWORD;
}
}
private static boolean supportsAVX2(LIRGeneratorTool tool) {
return supports(tool, CPUFeature.AVX2);
}
private static boolean supports(LIRGeneratorTool tool, CPUFeature cpuFeature) {
return ((AMD64) tool.target().arch).getFeatures().contains(cpuFeature);
}
@Override
public boolean needsClearUpperVectorRegisters() {
return true;
}
}