package org.graalvm.compiler.core.aarch64;
import jdk.internal.vm.compiler.collections.EconomicMap;
import jdk.internal.vm.compiler.collections.Equivalence;
import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ExtendType;
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.calc.CanonicalCondition;
import org.graalvm.compiler.core.common.calc.FloatConvert;
import org.graalvm.compiler.core.gen.NodeMatchRules;
import org.graalvm.compiler.core.match.ComplexMatchResult;
import org.graalvm.compiler.core.match.MatchRule;
import org.graalvm.compiler.core.match.MatchableNode;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.lir.LIRFrameState;
import org.graalvm.compiler.lir.LabelRef;
import org.graalvm.compiler.lir.Variable;
import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp;
import org.graalvm.compiler.lir.aarch64.AArch64BitFieldOp;
import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow;
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.DeoptimizingNode;
import org.graalvm.compiler.nodes.FixedNode;
import org.graalvm.compiler.nodes.IfNode;
import org.graalvm.compiler.nodes.NodeView;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.AddNode;
import org.graalvm.compiler.nodes.calc.AndNode;
import org.graalvm.compiler.nodes.calc.BinaryNode;
import org.graalvm.compiler.nodes.calc.FloatConvertNode;
import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
import org.graalvm.compiler.nodes.calc.LeftShiftNode;
import org.graalvm.compiler.nodes.calc.MulNode;
import org.graalvm.compiler.nodes.calc.NarrowNode;
import org.graalvm.compiler.nodes.calc.NegateNode;
import org.graalvm.compiler.nodes.calc.NotNode;
import org.graalvm.compiler.nodes.calc.OrNode;
import org.graalvm.compiler.nodes.calc.RightShiftNode;
import org.graalvm.compiler.nodes.calc.SignExtendNode;
import org.graalvm.compiler.nodes.calc.SubNode;
import org.graalvm.compiler.nodes.calc.UnaryNode;
import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode;
import org.graalvm.compiler.nodes.calc.XorNode;
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
import org.graalvm.compiler.nodes.memory.MemoryAccess;
import jdk.vm.ci.aarch64.AArch64Kind;
import jdk.vm.ci.code.CodeUtil;
import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.Value;
@MatchableNode(nodeClass = AArch64PointerAddNode.class, inputs = {"base", "offset"})
public class AArch64NodeMatchRules extends NodeMatchRules {
private static final EconomicMap<Class<? extends BinaryNode>, AArch64ArithmeticOp> binaryOpMap;
private static final EconomicMap<Class<? extends BinaryNode>, AArch64BitFieldOp.BitFieldOpCode> bitFieldOpMap;
private static final EconomicMap<Class<? extends BinaryNode>, AArch64MacroAssembler.ShiftType> shiftTypeMap;
private static final EconomicMap<Class<? extends BinaryNode>, AArch64ArithmeticOp> logicalNotOpMap;
static {
binaryOpMap = EconomicMap.create(Equivalence.IDENTITY, 9);
binaryOpMap.put(AddNode.class, AArch64ArithmeticOp.ADD);
binaryOpMap.put(SubNode.class, AArch64ArithmeticOp.SUB);
binaryOpMap.put(MulNode.class, AArch64ArithmeticOp.MUL);
binaryOpMap.put(AndNode.class, AArch64ArithmeticOp.AND);
binaryOpMap.put(OrNode.class, AArch64ArithmeticOp.OR);
binaryOpMap.put(XorNode.class, AArch64ArithmeticOp.XOR);
binaryOpMap.put(LeftShiftNode.class, AArch64ArithmeticOp.SHL);
binaryOpMap.put(RightShiftNode.class, AArch64ArithmeticOp.ASHR);
binaryOpMap.put(UnsignedRightShiftNode.class, AArch64ArithmeticOp.LSHR);
bitFieldOpMap = EconomicMap.create(Equivalence.IDENTITY, 2);
bitFieldOpMap.put(UnsignedRightShiftNode.class, AArch64BitFieldOp.BitFieldOpCode.UBFX);
bitFieldOpMap.put(LeftShiftNode.class, AArch64BitFieldOp.BitFieldOpCode.UBFIZ);
logicalNotOpMap = EconomicMap.create(Equivalence.IDENTITY, 3);
logicalNotOpMap.put(AndNode.class, AArch64ArithmeticOp.BIC);
logicalNotOpMap.put(OrNode.class, AArch64ArithmeticOp.ORN);
logicalNotOpMap.put(XorNode.class, AArch64ArithmeticOp.EON);
shiftTypeMap = EconomicMap.create(Equivalence.IDENTITY, 3);
shiftTypeMap.put(LeftShiftNode.class, AArch64MacroAssembler.ShiftType.LSL);
shiftTypeMap.put(RightShiftNode.class, AArch64MacroAssembler.ShiftType.ASR);
shiftTypeMap.put(UnsignedRightShiftNode.class, AArch64MacroAssembler.ShiftType.LSR);
}
public AArch64NodeMatchRules(LIRGeneratorTool gen) {
super(gen);
}
protected LIRFrameState getState(MemoryAccess access) {
if (access instanceof DeoptimizingNode) {
return state((DeoptimizingNode) access);
}
return null;
}
protected AArch64Kind getMemoryKind(MemoryAccess access) {
return (AArch64Kind) gen.getLIRKind(((ValueNode) access).stamp(NodeView.DEFAULT)).getPlatformKind();
}
private static ExtendType getZeroExtendType(int fromBits) {
switch (fromBits) {
case Byte.SIZE:
return ExtendType.UXTB;
case Short.SIZE:
return ExtendType.UXTH;
case Integer.SIZE:
return ExtendType.UXTW;
case Long.SIZE:
return ExtendType.UXTX;
default:
GraalError.shouldNotReachHere("extended from " + fromBits + "bits is not supported!");
return null;
}
}
private static ExtendType getSignExtendType(int fromBits) {
switch (fromBits) {
case Byte.SIZE:
return ExtendType.SXTB;
case Short.SIZE:
return ExtendType.SXTH;
case Integer.SIZE:
return ExtendType.SXTW;
case Long.SIZE:
return ExtendType.SXTX;
default:
GraalError.shouldNotReachHere("extended from " + fromBits + "bits is not supported!");
return null;
}
}
private AllocatableValue moveSp(AllocatableValue value) {
return getLIRGeneratorTool().moveSp(value);
}
private ComplexMatchResult emitBitField(AArch64BitFieldOp.BitFieldOpCode op, ValueNode value, int lsb, int width) {
assert op != null;
assert value.getStackKind().isNumericInteger();
return builder -> {
Value a = operand(value);
Variable result = gen.newVariable(LIRKind.combine(a));
AllocatableValue src = moveSp(gen.asAllocatable(a));
gen.append(new AArch64BitFieldOp(op, result, src, lsb, width));
return result;
};
}
private ComplexMatchResult emitBinaryShift(AArch64ArithmeticOp op, ValueNode value, BinaryNode shift) {
AArch64MacroAssembler.ShiftType shiftType = shiftTypeMap.get(shift.getClass());
assert shiftType != null;
assert value.getStackKind().isNumericInteger();
assert shift.getX().getStackKind().isNumericInteger();
assert shift.getY() instanceof ConstantNode;
return builder -> {
Value a = operand(value);
Value b = operand(shift.getX());
Variable result = gen.newVariable(LIRKind.combine(a, b));
AllocatableValue x = moveSp(gen.asAllocatable(a));
AllocatableValue y = moveSp(gen.asAllocatable(b));
int shiftAmount = shift.getY().asJavaConstant().asInt();
gen.append(new AArch64ArithmeticOp.BinaryShiftOp(op, result, x, y, shiftType, shiftAmount));
return result;
};
}
private ComplexMatchResult emitBitTestAndBranch(FixedNode trueSuccessor, FixedNode falseSuccessor,
ValueNode value, double trueProbability, int nbits) {
return builder -> {
LabelRef trueDestination = getLIRBlock(trueSuccessor);
LabelRef falseDestination = getLIRBlock(falseSuccessor);
AllocatableValue src = moveSp(gen.asAllocatable(operand(value)));
gen.append(new AArch64ControlFlow.BitTestAndBranchOp(trueDestination, falseDestination, src,
trueProbability, nbits));
return null;
};
}
private static boolean isNarrowingLongToInt(NarrowNode narrow) {
return narrow.getInputBits() == Long.SIZE && narrow.getResultBits() == Integer.SIZE;
}
private ComplexMatchResult emitExtendedAddSubShift(BinaryNode op, ValueNode x, ValueNode y, ExtendType extType, int shiftAmt) {
assert op instanceof AddNode || op instanceof SubNode;
return builder -> {
AllocatableValue src1 = moveSp(gen.asAllocatable(operand(x)));
AllocatableValue src2 = moveSp(gen.asAllocatable(operand(y)));
Variable result = gen.newVariable(LIRKind.combine(operand(x), operand(y)));
AArch64ArithmeticOp arithmeticOp = op instanceof AddNode ? AArch64ArithmeticOp.ADD : AArch64ArithmeticOp.SUB;
gen.append(new AArch64ArithmeticOp.ExtendedAddSubShiftOp(arithmeticOp, result, src1, src2, extType, shiftAmt));
return result;
};
}
@MatchRule("(Add=op x (LeftShift (SignExtend=ext y) Constant=lshift))")
@MatchRule("(Sub=op x (LeftShift (SignExtend=ext y) Constant=lshift))")
@MatchRule("(Add=op x (LeftShift (ZeroExtend=ext y) Constant=lshift))")
@MatchRule("(Sub=op x (LeftShift (ZeroExtend=ext y) Constant=lshift))")
public ComplexMatchResult mergeSignExtendByShiftIntoAddSub(BinaryNode op, UnaryNode ext, ValueNode x, ValueNode y, ConstantNode lshift) {
assert lshift.getStackKind().isNumericInteger();
int shiftAmt = lshift.asJavaConstant().asInt();
if (shiftAmt > 4 || shiftAmt < 0) {
return null;
}
ExtendType extType;
if (ext instanceof SignExtendNode) {
extType = getSignExtendType(((SignExtendNode) ext).getInputBits());
} else {
extType = getZeroExtendType(((ZeroExtendNode) ext).getInputBits());
}
return emitExtendedAddSubShift(op, x, y, extType, shiftAmt);
}
@MatchRule("(Add=op x (LeftShift (And y Constant=constant) Constant=lshift))")
@MatchRule("(Sub=op x (LeftShift (And y Constant=constant) Constant=lshift))")
public ComplexMatchResult mergeShiftDowncastIntoAddSub(BinaryNode op, ValueNode x, ValueNode y, ConstantNode constant, ConstantNode lshift) {
assert lshift.getStackKind().isNumericInteger();
assert constant.getStackKind().isNumericInteger();
int shiftAmt = lshift.asJavaConstant().asInt();
long mask = constant.asJavaConstant().asLong();
if (shiftAmt > 4 || shiftAmt < 0) {
return null;
}
if (mask != 0xff && mask != 0xffff && mask != 0xffffffffL) {
return null;
}
ExtendType extType = getZeroExtendType(Long.toBinaryString(mask).length());
return emitExtendedAddSubShift(op, x, y, extType, shiftAmt);
}
@MatchRule("(Add=op x (RightShift (LeftShift y Constant=shiftConst) Constant=shiftConst))")
@MatchRule("(Sub=op x (RightShift (LeftShift y Constant=shiftConst) Constant=shiftConst))")
public ComplexMatchResult mergePairShiftIntoAddSub(BinaryNode op, ValueNode x, ValueNode y, ConstantNode shiftConst) {
assert shiftConst.getStackKind().isNumericInteger();
int shift = shiftConst.asJavaConstant().asInt();
if (shift != 16 && shift != 24 && shift != 32 && shift != 48 && shift != 56) {
return null;
}
int extractBits = shift >= 32 ? Long.SIZE - shift : Integer.SIZE - shift;
return emitExtendedAddSubShift(op, x, y, getSignExtendType(extractBits), 0);
}
@MatchRule("(Add=op x (LeftShift (RightShift (LeftShift y Constant=shiftConst) Constant=shiftConst) Constant=lshift))")
@MatchRule("(Sub=op x (LeftShift (RightShift (LeftShift y Constant=shiftConst) Constant=shiftConst) Constant=lshift))")
public ComplexMatchResult mergeShiftedPairShiftIntoAddSub(BinaryNode op, ValueNode x, ValueNode y, ConstantNode shiftConst, ConstantNode lshift) {
assert shiftConst.getStackKind().isNumericInteger();
int shift = shiftConst.asJavaConstant().asInt();
int shiftAmt = lshift.asJavaConstant().asInt();
if (shiftAmt > 4 || shiftAmt < 0) {
return null;
}
if (shift != 16 && shift != 24 && shift != 32 && shift != 48 && shift != 56) {
return null;
}
int extractBits = shift >= 32 ? Long.SIZE - shift : Integer.SIZE - shift;
return emitExtendedAddSubShift(op, x, y, getSignExtendType(extractBits), shiftAmt);
}
@MatchRule("(AArch64PointerAdd=addP base ZeroExtend)")
@MatchRule("(AArch64PointerAdd=addP base (LeftShift ZeroExtend Constant))")
public ComplexMatchResult extendedPointerAddShift(AArch64PointerAddNode addP) {
ValueNode offset = addP.getOffset();
ZeroExtendNode zeroExtend;
int shiftNum;
if (offset instanceof ZeroExtendNode) {
zeroExtend = (ZeroExtendNode) offset;
shiftNum = 0;
} else {
LeftShiftNode shift = (LeftShiftNode) offset;
zeroExtend = (ZeroExtendNode) shift.getX();
shiftNum = shift.getY().asJavaConstant().asInt();
}
int fromBits = zeroExtend.getInputBits();
int toBits = zeroExtend.getResultBits();
if (toBits != 64) {
return null;
}
assert fromBits <= toBits;
ExtendType extendType = getZeroExtendType(fromBits);
if (shiftNum >= 0 && shiftNum <= 4) {
ValueNode base = addP.getBase();
return builder -> {
AllocatableValue x = gen.asAllocatable(operand(base));
AllocatableValue y = gen.asAllocatable(operand(zeroExtend.getValue()));
AllocatableValue baseReference = LIRKind.derivedBaseFromValue(x);
LIRKind kind = LIRKind.combineDerived(gen.getLIRKind(addP.stamp(NodeView.DEFAULT)),
baseReference, null);
Variable result = gen.newVariable(kind);
gen.append(new AArch64ArithmeticOp.ExtendedAddSubShiftOp(AArch64ArithmeticOp.ADD, result, x, moveSp(y),
extendType, shiftNum));
return result;
};
}
return null;
}
@MatchRule("(And (UnsignedRightShift=shift a Constant=b) Constant=c)")
@MatchRule("(LeftShift=shift (And a Constant=c) Constant=b)")
public ComplexMatchResult unsignedBitField(BinaryNode shift, ValueNode a, ConstantNode b, ConstantNode c) {
JavaKind srcKind = a.getStackKind();
assert srcKind.isNumericInteger();
AArch64BitFieldOp.BitFieldOpCode op = bitFieldOpMap.get(shift.getClass());
assert op != null;
int distance = b.asJavaConstant().asInt();
long mask = c.asJavaConstant().asLong();
distance = distance & (srcKind == JavaKind.Int ? 0x1f : 0x3f);
if (!CodeUtil.isPowerOf2(mask + 1)) {
return null;
}
int width = CodeUtil.log2(mask + 1);
int srcBits = srcKind.getBitCount();
if (width >= srcBits - 1) {
return null;
}
if (width + distance > srcBits) {
return null;
}
return emitBitField(op, a, distance, width);
}
@MatchRule("(Or=op (LeftShift=x src Constant=shiftAmt1) (UnsignedRightShift src Constant=shiftAmt2))")
@MatchRule("(Or=op (UnsignedRightShift=x src Constant=shiftAmt1) (LeftShift src Constant=shiftAmt2))")
@MatchRule("(Add=op (LeftShift=x src Constant=shiftAmt1) (UnsignedRightShift src Constant=shiftAmt2))")
@MatchRule("(Add=op (UnsignedRightShift=x src Constant=shiftAmt1) (LeftShift src Constant=shiftAmt2))")
public ComplexMatchResult rotationConstant(ValueNode op, ValueNode x, ValueNode src, ConstantNode shiftAmt1, ConstantNode shiftAmt2) {
assert src.getStackKind().isNumericInteger();
assert shiftAmt1.getStackKind().getBitCount() == 32;
assert shiftAmt2.getStackKind().getBitCount() == 32;
int shift1 = shiftAmt1.asJavaConstant().asInt();
int shift2 = shiftAmt2.asJavaConstant().asInt();
if (op instanceof AddNode && (0 == shift1 || 0 == shift2)) {
return null;
}
if ((0 == shift1 + shift2) || (src.getStackKind().getBitCount() == shift1 + shift2)) {
return builder -> {
Value a = operand(src);
Value b = x instanceof LeftShiftNode ? operand(shiftAmt2) : operand(shiftAmt1);
return getArithmeticLIRGenerator().emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.ROR, false, a, b);
};
}
return null;
}
@MatchRule("(Or (LeftShift=x src shiftAmount) (UnsignedRightShift src (Sub=y Constant shiftAmount)))")
@MatchRule("(Or (UnsignedRightShift=x src shiftAmount) (LeftShift src (Sub=y Constant shiftAmount)))")
@MatchRule("(Or (LeftShift=x src (Negate shiftAmount)) (UnsignedRightShift src (Add=y Constant shiftAmount)))")
@MatchRule("(Or (UnsignedRightShift=x src (Negate shiftAmount)) (LeftShift src (Add=y Constant shiftAmount)))")
@MatchRule("(Or (LeftShift=x src shiftAmount) (UnsignedRightShift src (Negate=y shiftAmount)))")
@MatchRule("(Or (UnsignedRightShift=x src shiftAmount) (LeftShift src (Negate=y shiftAmount)))")
public ComplexMatchResult rotationExpander(ValueNode src, ValueNode shiftAmount, ValueNode x, ValueNode y) {
assert src.getStackKind().isNumericInteger();
assert shiftAmount.getStackKind().getBitCount() == 32;
if (y instanceof SubNode || y instanceof AddNode) {
BinaryNode binary = (BinaryNode) y;
ConstantNode delta = (ConstantNode) (binary.getX() instanceof ConstantNode ? binary.getX() : binary.getY());
if (delta.asJavaConstant().asInt() != src.getStackKind().getBitCount()) {
return null;
}
}
return builder -> {
Value a = operand(src);
Value b;
if (y instanceof AddNode) {
b = x instanceof LeftShiftNode ? operand(shiftAmount) : getArithmeticLIRGenerator().emitNegate(operand(shiftAmount));
} else {
b = x instanceof LeftShiftNode ? getArithmeticLIRGenerator().emitNegate(operand(shiftAmount)) : operand(shiftAmount);
}
return getArithmeticLIRGenerator().emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.RORV, false, a, b);
};
}
@MatchRule("(Add=binary a (LeftShift=shift b Constant))")
@MatchRule("(Add=binary a (RightShift=shift b Constant))")
@MatchRule("(Add=binary a (UnsignedRightShift=shift b Constant))")
@MatchRule("(Sub=binary a (LeftShift=shift b Constant))")
@MatchRule("(Sub=binary a (RightShift=shift b Constant))")
@MatchRule("(Sub=binary a (UnsignedRightShift=shift b Constant))")
public ComplexMatchResult addSubShift(BinaryNode binary, ValueNode a, BinaryNode shift) {
AArch64ArithmeticOp op = binaryOpMap.get(binary.getClass());
assert op != null;
return emitBinaryShift(op, a, shift);
}
@MatchRule("(And=binary a (LeftShift=shift b Constant))")
@MatchRule("(And=binary a (RightShift=shift b Constant))")
@MatchRule("(And=binary a (UnsignedRightShift=shift b Constant))")
@MatchRule("(Or=binary a (LeftShift=shift b Constant))")
@MatchRule("(Or=binary a (RightShift=shift b Constant))")
@MatchRule("(Or=binary a (UnsignedRightShift=shift b Constant))")
@MatchRule("(Xor=binary a (LeftShift=shift b Constant))")
@MatchRule("(Xor=binary a (RightShift=shift b Constant))")
@MatchRule("(Xor=binary a (UnsignedRightShift=shift b Constant))")
@MatchRule("(And=binary a (Not (LeftShift=shift b Constant)))")
@MatchRule("(And=binary a (Not (RightShift=shift b Constant)))")
@MatchRule("(And=binary a (Not (UnsignedRightShift=shift b Constant)))")
@MatchRule("(Or=binary a (Not (LeftShift=shift b Constant)))")
@MatchRule("(Or=binary a (Not (RightShift=shift b Constant)))")
@MatchRule("(Or=binary a (Not (UnsignedRightShift=shift b Constant)))")
@MatchRule("(Xor=binary a (Not (LeftShift=shift b Constant)))")
@MatchRule("(Xor=binary a (Not (RightShift=shift b Constant)))")
@MatchRule("(Xor=binary a (Not (UnsignedRightShift=shift b Constant)))")
public ComplexMatchResult logicShift(BinaryNode binary, ValueNode a, BinaryNode shift) {
AArch64ArithmeticOp op;
ValueNode operand = binary.getX() == a ? binary.getY() : binary.getX();
if (operand instanceof NotNode) {
op = logicalNotOpMap.get(binary.getClass());
} else {
op = binaryOpMap.get(binary.getClass());
}
assert op != null;
return emitBinaryShift(op, a, shift);
}
@MatchRule("(And=logic value1 (Not=not value2))")
@MatchRule("(Or=logic value1 (Not=not value2))")
@MatchRule("(Xor=logic value1 (Not=not value2))")
public ComplexMatchResult bitwiseLogicNot(BinaryNode logic, NotNode not) {
assert logic.getStackKind().isNumericInteger();
AArch64ArithmeticOp op = logicalNotOpMap.get(logic.getClass());
assert op != null;
ValueNode src1 = logic.getX() == not ? logic.getY() : logic.getX();
ValueNode src2 = not.getValue();
return builder -> {
Value a = operand(src1);
Value b = operand(src2);
LIRKind resultKind = LIRKind.combine(a, b);
return getArithmeticLIRGenerator().emitBinary(resultKind, op, false, a, b);
};
}
@MatchRule("(Not=not (Xor value1 value2))")
public ComplexMatchResult bitwiseNotXor(NotNode not) {
assert not.getStackKind().isNumericInteger();
return builder -> {
XorNode xor = (XorNode) not.getValue();
Value a = operand(xor.getX());
Value b = operand(xor.getY());
LIRKind resultKind = LIRKind.combine(a, b);
return getArithmeticLIRGenerator().emitBinary(resultKind, AArch64ArithmeticOp.EON, false, a, b);
};
}
@MatchRule("(Add=binary (Mul (SignExtend a) (SignExtend b)) c)")
@MatchRule("(Sub=binary c (Mul (SignExtend a) (SignExtend b)))")
public ComplexMatchResult signedMultiplyAddSubLong(BinaryNode binary, ValueNode a, ValueNode b, ValueNode c) {
assert a.getStackKind() == JavaKind.Int && b.getStackKind() == JavaKind.Int && c.getStackKind() == JavaKind.Long;
if (binary instanceof AddNode) {
return builder -> getArithmeticLIRGenerator().emitIntegerMAdd(operand(a), operand(b), operand(c), true);
}
return builder -> getArithmeticLIRGenerator().emitIntegerMSub(operand(a), operand(b), operand(c), true);
}
@MatchRule("(Negate (Mul=mul (SignExtend a) (SignExtend b)))")
@MatchRule("(Mul=mul (Negate (SignExtend a)) (SignExtend b))")
public ComplexMatchResult signedMultiplyNegLong(MulNode mul, ValueNode a, ValueNode b) {
assert a.getStackKind() == JavaKind.Int && b.getStackKind() == JavaKind.Int;
LIRKind resultKind = LIRKind.fromJavaKind(gen.target().arch, mul.getStackKind());
return builder -> getArithmeticLIRGenerator().emitBinary(
resultKind, AArch64ArithmeticOp.SMNEGL, true, operand(a), operand(b));
}
@MatchRule("(Mul=mul (SignExtend a) (SignExtend b))")
public ComplexMatchResult signedMultiplyLong(MulNode mul, ValueNode a, ValueNode b) {
assert a.getStackKind() == JavaKind.Int && b.getStackKind() == JavaKind.Int;
LIRKind resultKind = LIRKind.fromJavaKind(gen.target().arch, mul.getStackKind());
return builder -> getArithmeticLIRGenerator().emitBinary(
resultKind, AArch64ArithmeticOp.SMULL, true, operand(a), operand(b));
}
@MatchRule("(Add=binary (Narrow=narrow a) (Narrow b))")
@MatchRule("(Sub=binary (Narrow=narrow a) (Narrow b))")
@MatchRule("(Mul=binary (Narrow=narrow a) (Narrow b))")
@MatchRule("(And=binary (Narrow=narrow a) (Narrow b))")
@MatchRule("(Or=binary (Narrow=narrow a) (Narrow b))")
@MatchRule("(Xor=binary (Narrow=narrow a) (Narrow b))")
@MatchRule("(LeftShift=binary (Narrow=narrow a) (Narrow b))")
@MatchRule("(RightShift=binary (Narrow=narrow a) (Narrow b))")
@MatchRule("(UnsignedRightShift=binary (Narrow=narrow a) (Narrow b))")
@MatchRule("(Add=binary a (Narrow=narrow b))")
@MatchRule("(Sub=binary a (Narrow=narrow b))")
@MatchRule("(Mul=binary a (Narrow=narrow b))")
@MatchRule("(And=binary a (Narrow=narrow b))")
@MatchRule("(Or=binary a (Narrow=narrow b))")
@MatchRule("(Xor=binary a (Narrow=narrow b))")
@MatchRule("(LeftShift=binary a (Narrow=narrow b))")
@MatchRule("(RightShift=binary a (Narrow=narrow b))")
@MatchRule("(UnsignedRightShift=binary a (Narrow=narrow b))")
@MatchRule("(Sub=binary (Narrow=narrow a) b)")
@MatchRule("(LeftShift=binary (Narrow=narrow a) b)")
@MatchRule("(RightShift=binary (Narrow=narrow a) b)")
@MatchRule("(UnsignedRightShift=binary (Narrow=narrow a) b)")
public ComplexMatchResult elideL2IForBinary(BinaryNode binary, NarrowNode narrow) {
assert binary.getStackKind().isNumericInteger();
ValueNode a = narrow;
ValueNode b = binary.getX() == narrow ? binary.getY() : binary.getX();
boolean isL2Ia = isNarrowingLongToInt((NarrowNode) a);
boolean isL2Ib = (b instanceof NarrowNode) && isNarrowingLongToInt((NarrowNode) b);
if (!isL2Ia && !isL2Ib) {
return null;
}
ValueNode src1 = isL2Ia ? ((NarrowNode) a).getValue() : a;
ValueNode src2 = isL2Ib ? ((NarrowNode) b).getValue() : b;
AArch64ArithmeticOp op = binaryOpMap.get(binary.getClass());
assert op != null;
boolean commutative = binary.getNodeClass().isCommutative();
LIRKind resultKind = LIRKind.fromJavaKind(gen.target().arch, binary.getStackKind());
if (a == binary.getX()) {
return builder -> getArithmeticLIRGenerator().emitBinary(
resultKind, op, commutative, operand(src1), operand(src2));
}
return builder -> getArithmeticLIRGenerator().emitBinary(
resultKind, op, commutative, operand(src2), operand(src1));
}
@MatchRule("(Add=op x (And y Constant=constant))")
@MatchRule("(Sub=op x (And y Constant=constant))")
public ComplexMatchResult mergeDowncastIntoAddSub(BinaryNode op, ValueNode x, ValueNode y, ConstantNode constant) {
assert constant.getStackKind().isNumericInteger();
long mask = constant.asJavaConstant().asLong();
if (mask != 0xff && mask != 0xffff && mask != 0xffffffffL) {
return null;
}
ExtendType extType = getZeroExtendType(Long.toBinaryString(mask).length());
return emitExtendedAddSubShift(op, x, y, extType, 0);
}
@MatchRule("(Add=op x (SignExtend=ext y))")
@MatchRule("(Sub=op x (SignExtend=ext y))")
@MatchRule("(Add=op x (ZeroExtend=ext y))")
@MatchRule("(Sub=op x (ZeroExtend=ext y))")
public ComplexMatchResult mergeSignExtendIntoAddSub(BinaryNode op, UnaryNode ext, ValueNode x, ValueNode y) {
ExtendType extType;
if (ext instanceof SignExtendNode) {
extType = getSignExtendType(((SignExtendNode) ext).getInputBits());
} else {
extType = getZeroExtendType(((ZeroExtendNode) ext).getInputBits());
}
return emitExtendedAddSubShift(op, x, y, extType, 0);
}
@MatchRule("(Negate=unary (Narrow=narrow value))")
@MatchRule("(Not=unary (Narrow=narrow value))")
public ComplexMatchResult elideL2IForUnary(UnaryNode unary, NarrowNode narrow) {
assert unary.getStackKind().isNumericInteger();
if (!isNarrowingLongToInt(narrow)) {
return null;
}
AArch64ArithmeticOp op = unary instanceof NegateNode ? AArch64ArithmeticOp.NEG
: AArch64ArithmeticOp.NOT;
return builder -> {
AllocatableValue input = gen.asAllocatable(operand(narrow.getValue()));
LIRKind resultKind = LIRKind.fromJavaKind(gen.target().arch, unary.getStackKind());
Variable result = gen.newVariable(resultKind);
gen.append(new AArch64ArithmeticOp.UnaryOp(op, result, moveSp(input)));
return result;
};
}
@MatchRule("(Mul (Negate a) b)")
@MatchRule("(Negate (Mul a b))")
public ComplexMatchResult multiplyNegate(ValueNode a, ValueNode b) {
if (a.getStackKind().isNumericInteger() && b.getStackKind().isNumericInteger()) {
return builder -> getArithmeticLIRGenerator().emitMNeg(operand(a), operand(b));
}
return null;
}
@MatchRule("(Add=binary (Mul a b) c)")
@MatchRule("(Sub=binary c (Mul a b))")
public ComplexMatchResult multiplyAddSub(BinaryNode binary, ValueNode a, ValueNode b, ValueNode c) {
JavaKind kindA = a.getStackKind();
JavaKind kindB = b.getStackKind();
JavaKind kindC = c.getStackKind();
if (!kindA.isNumericInteger() || !kindB.isNumericInteger() || !kindC.isNumericInteger()) {
return null;
}
if (binary instanceof AddNode) {
return builder -> getArithmeticLIRGenerator().emitIntegerMAdd(operand(a), operand(b), operand(c), false);
}
return builder -> getArithmeticLIRGenerator().emitIntegerMSub(operand(a), operand(b), operand(c), false);
}
@MatchRule("(If (IntegerTest value Constant=a))")
public ComplexMatchResult testBitAndBranch(IfNode root, ValueNode value, ConstantNode a) {
if (value.getStackKind().isNumericInteger()) {
long constant = a.asJavaConstant().asLong();
if (Long.bitCount(constant) == 1) {
return emitBitTestAndBranch(root.trueSuccessor(), root.falseSuccessor(), value,
root.getTrueSuccessorProbability(), Long.numberOfTrailingZeros(constant));
}
}
return null;
}
@MatchRule("(If (IntegerLessThan=lessNode x Constant=y))")
public ComplexMatchResult checkNegativeAndBranch(IfNode root, IntegerLessThanNode lessNode, ValueNode x, ConstantNode y) {
JavaKind xKind = x.getStackKind();
assert xKind.isNumericInteger();
if (y.isJavaConstant() && (0 == y.asJavaConstant().asLong()) && lessNode.condition().equals(CanonicalCondition.LT)) {
return emitBitTestAndBranch(root.falseSuccessor(), root.trueSuccessor(), x,
1.0 - root.getTrueSuccessorProbability(), xKind.getBitCount() - 1);
}
return null;
}
@MatchRule("(FloatConvert=a (Sqrt (FloatConvert=b c)))")
public ComplexMatchResult floatSqrt(FloatConvertNode a, FloatConvertNode b, ValueNode c) {
if (c.getStackKind().isNumericFloat() && a.getStackKind().isNumericFloat()) {
if (a.getFloatConvert() == FloatConvert.D2F && b.getFloatConvert() == FloatConvert.F2D) {
return builder -> getArithmeticLIRGenerator().emitMathSqrt(operand(c));
}
}
return null;
}
@MatchRule("(SignExtend=extend (Narrow value))")
@MatchRule("(ZeroExtend=extend (Narrow value))")
public ComplexMatchResult mergeNarrowExtend(UnaryNode extend, ValueNode value) {
if (extend instanceof SignExtendNode) {
SignExtendNode sxt = (SignExtendNode) extend;
return builder -> getArithmeticLIRGenerator().emitSignExtend(operand(value), sxt.getInputBits(), sxt.getResultBits());
}
assert extend instanceof ZeroExtendNode;
ZeroExtendNode zxt = (ZeroExtendNode) extend;
return builder -> getArithmeticLIRGenerator().emitZeroExtend(operand(value), zxt.getInputBits(), zxt.getResultBits());
}
@Override
public AArch64LIRGenerator getLIRGeneratorTool() {
return (AArch64LIRGenerator) gen;
}
protected AArch64ArithmeticLIRGenerator getArithmeticLIRGenerator() {
return (AArch64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic();
}
}