use of org.graalvm.compiler.asm.Label in project graal by oracle.
the class AMD64ArrayEqualsOp method emitCode.
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
Register result = asRegister(resultValue);
Register array1 = asRegister(temp1);
Register array2 = asRegister(temp2);
Register length = asRegister(temp3);
Label trueLabel = new Label();
Label falseLabel = new Label();
Label done = new Label();
// Load array base addresses.
masm.leaq(array1, new AMD64Address(asRegister(array1Value), arrayBaseOffset));
masm.leaq(array2, new AMD64Address(asRegister(array2Value), arrayBaseOffset));
// Get array length in bytes.
masm.movl(length, asRegister(lengthValue));
if (arrayIndexScale > 1) {
// scale length
masm.shll(length, NumUtil.log2Ceil(arrayIndexScale));
}
// copy
masm.movl(result, length);
if (supportsAVX2(crb.target)) {
emitAVXCompare(crb, masm, result, array1, array2, length, trueLabel, falseLabel);
} else if (supportsSSE41(crb.target)) {
// this code is used for AVX as well because our backend correctly ensures that
// VEX-prefixed instructions are emitted if AVX is supported
emitSSE41Compare(crb, masm, result, array1, array2, length, trueLabel, falseLabel);
}
emit8ByteCompare(crb, masm, result, array1, array2, length, trueLabel, falseLabel);
emitTailCompares(masm, result, array1, array2, length, trueLabel, falseLabel);
// Return true
masm.bind(trueLabel);
masm.movl(result, 1);
masm.jmpb(done);
// Return false
masm.bind(falseLabel);
masm.xorl(result, result);
// That's it
masm.bind(done);
}
use of org.graalvm.compiler.asm.Label in project graal by oracle.
the class AMD64ArrayEqualsOp method emitFloatCompare.
/**
* Emits code to compare if two floats are bitwise equal or both NaN.
*/
private void emitFloatCompare(AMD64MacroAssembler masm, Register base1, Register base2, Register index, int offset, Label falseLabel, boolean skipBitwiseCompare) {
AMD64Address address1 = new AMD64Address(base1, index, Scale.Times1, offset);
AMD64Address address2 = new AMD64Address(base2, index, Scale.Times1, offset);
Label bitwiseEqual = new Label();
if (!skipBitwiseCompare) {
// Bitwise compare
Register temp = asRegister(temp4);
if (kind == JavaKind.Float) {
masm.movl(temp, address1);
masm.cmpl(temp, address2);
} else {
masm.movq(temp, address1);
masm.cmpq(temp, address2);
}
masm.jccb(ConditionFlag.Equal, bitwiseEqual);
}
emitNaNCheck(masm, address1, falseLabel);
emitNaNCheck(masm, address2, falseLabel);
masm.bind(bitwiseEqual);
}
use of org.graalvm.compiler.asm.Label in project graal by oracle.
the class AMD64ArrayEqualsOp method emitFloatCompareWithinRange.
/**
* Emits code to compare float equality within a range.
*/
private void emitFloatCompareWithinRange(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register base1, Register base2, Register index, int offset, Label falseLabel, int range) {
assert kind.isNumericFloat();
Label loop = new Label();
Register i = asRegister(temp5);
masm.movq(i, range);
masm.negq(i);
// Align the main loop
masm.align(crb.target.wordSize * 2);
masm.bind(loop);
emitFloatCompare(masm, base1, base2, index, offset, falseLabel, kind.getByteCount() == range);
masm.addq(index, kind.getByteCount());
masm.addq(i, kind.getByteCount());
masm.jccb(ConditionFlag.NotZero, loop);
// Floats within the range are equal, revert change to the register index
masm.subq(index, range);
}
use of org.graalvm.compiler.asm.Label in project graal by oracle.
the class AMD64ArrayEqualsOp method emitSSE41Compare.
/**
* Emits code that uses SSE4.1 128-bit (16-byte) vector compares.
*/
private void emitSSE41Compare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) {
assert supportsSSE41(crb.target);
Register vector1 = asRegister(vectorTemp1, AMD64Kind.DOUBLE);
Register vector2 = asRegister(vectorTemp2, AMD64Kind.DOUBLE);
Label loop = new Label();
Label compareTail = new Label();
boolean requiresNaNCheck = kind.isNumericFloat();
Label loopCheck = new Label();
Label nanCheck = new Label();
// Compare 16-byte vectors
// tail count (in bytes)
masm.andl(result, SSE4_1_VECTOR_SIZE - 1);
// vector count (in bytes)
masm.andl(length, ~(SSE4_1_VECTOR_SIZE - 1));
masm.jcc(ConditionFlag.Zero, compareTail);
masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0));
masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0));
masm.negq(length);
// Align the main loop
masm.align(crb.target.wordSize * 2);
masm.bind(loop);
masm.movdqu(vector1, new AMD64Address(array1, length, Scale.Times1, 0));
masm.movdqu(vector2, new AMD64Address(array2, length, Scale.Times1, 0));
masm.pxor(vector1, vector2);
masm.ptest(vector1, vector1);
masm.jcc(ConditionFlag.NotZero, requiresNaNCheck ? nanCheck : falseLabel);
masm.bind(loopCheck);
masm.addq(length, SSE4_1_VECTOR_SIZE);
masm.jcc(ConditionFlag.NotZero, loop);
masm.testl(result, result);
masm.jcc(ConditionFlag.Zero, trueLabel);
if (requiresNaNCheck) {
Label unalignedCheck = new Label();
masm.jmpb(unalignedCheck);
masm.bind(nanCheck);
emitFloatCompareWithinRange(crb, masm, array1, array2, length, 0, falseLabel, SSE4_1_VECTOR_SIZE);
masm.jmpb(loopCheck);
masm.bind(unalignedCheck);
}
/*
* Compare the remaining bytes with an unaligned memory load aligned to the end of the
* array.
*/
masm.movdqu(vector1, new AMD64Address(array1, result, Scale.Times1, -SSE4_1_VECTOR_SIZE));
masm.movdqu(vector2, new AMD64Address(array2, result, Scale.Times1, -SSE4_1_VECTOR_SIZE));
masm.pxor(vector1, vector2);
masm.ptest(vector1, vector1);
if (requiresNaNCheck) {
masm.jcc(ConditionFlag.Zero, trueLabel);
emitFloatCompareWithinRange(crb, masm, array1, array2, result, -SSE4_1_VECTOR_SIZE, falseLabel, SSE4_1_VECTOR_SIZE);
} else {
masm.jcc(ConditionFlag.NotZero, falseLabel);
}
masm.jmp(trueLabel);
masm.bind(compareTail);
masm.movl(length, result);
}
use of org.graalvm.compiler.asm.Label in project graal by oracle.
the class AArch64ArrayEqualsOp method emit8ByteCompare.
/**
* Emits code that uses 8-byte vector compares.
*/
private void emit8ByteCompare(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label breakLabel, Register rscratch1) {
Label loop = new Label();
Label compareTail = new Label();
Register temp = asRegister(temp4);
// tail count (in bytes)
masm.and(64, result, result, VECTOR_SIZE - 1);
// vector count (in bytes)
masm.ands(64, length, length, ~(VECTOR_SIZE - 1));
masm.branchConditionally(ConditionFlag.EQ, compareTail);
masm.lea(array1, AArch64Address.createRegisterOffsetAddress(array1, length, false));
masm.lea(array2, AArch64Address.createRegisterOffsetAddress(array2, length, false));
masm.sub(64, length, zr, length);
// Align the main loop
masm.align(crb.target.wordSize * 2);
masm.bind(loop);
masm.ldr(64, temp, AArch64Address.createRegisterOffsetAddress(array1, length, false));
masm.ldr(64, rscratch1, AArch64Address.createRegisterOffsetAddress(array2, length, false));
masm.eor(64, rscratch1, temp, rscratch1);
masm.cbnz(64, rscratch1, breakLabel);
masm.add(64, length, length, VECTOR_SIZE);
masm.cbnz(64, length, loop);
masm.cbz(64, result, breakLabel);
/*
* Compare the remaining bytes with an unaligned memory load aligned to the end of the
* array.
*/
masm.lea(array1, AArch64Address.createUnscaledImmediateAddress(array1, -VECTOR_SIZE));
masm.lea(array2, AArch64Address.createUnscaledImmediateAddress(array2, -VECTOR_SIZE));
masm.ldr(64, temp, AArch64Address.createRegisterOffsetAddress(array1, result, false));
masm.ldr(64, rscratch1, AArch64Address.createRegisterOffsetAddress(array2, result, false));
masm.eor(64, rscratch1, temp, rscratch1);
masm.jmp(breakLabel);
masm.bind(compareTail);
}
Aggregations