From 22c4922c6b31e154a6814c4abe9015d9ba156911 Mon Sep 17 00:00:00 2001 From: Roland Levillain Date: Fri, 18 Mar 2016 14:04:28 +0000 Subject: [PATCH] Ensure art::HRor support boolean, byte, short and char inputs. Also extend tests covering the IntegerRotateLeft, LongRotateLeft, IntegerRotateRight and LongRotateRight intrinsics and their translation into an art::HRor instruction. Bug: 27682579 Change-Id: I89f6ea6a7315659a172482bf09875cfb7e7422a1 --- compiler/optimizing/code_generator_arm.cc | 13 +- compiler/optimizing/code_generator_arm.h | 2 - compiler/optimizing/code_generator_x86.cc | 3 +- compiler/optimizing/common_arm64.h | 6 +- compiler/optimizing/graph_checker.cc | 2 +- compiler/optimizing/instruction_simplifier.cc | 24 +- compiler/optimizing/nodes.h | 7 +- test/565-checker-rotate/src/Main.java | 572 ++++++++++++++++++++++---- 8 files changed, 526 insertions(+), 103 deletions(-) diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 34fd9ff2a..c164f2b34 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -3273,7 +3273,8 @@ void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) { __ Bind(&end); } } -void LocationsBuilderARM::HandleRotate(HRor* ror) { + +void LocationsBuilderARM::VisitRor(HRor* ror) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall); switch (ror->GetResultType()) { @@ -3300,7 +3301,7 @@ void LocationsBuilderARM::HandleRotate(HRor* ror) { } } -void InstructionCodeGeneratorARM::HandleRotate(HRor* ror) { +void InstructionCodeGeneratorARM::VisitRor(HRor* ror) { LocationSummary* locations = ror->GetLocations(); Primitive::Type type = ror->GetResultType(); switch (type) { @@ -3318,14 +3319,6 @@ void InstructionCodeGeneratorARM::HandleRotate(HRor* ror) { } } -void LocationsBuilderARM::VisitRor(HRor* op) { - HandleRotate(op); -} - -void InstructionCodeGeneratorARM::VisitRor(HRor* op) { - HandleRotate(op); -} - void LocationsBuilderARM::HandleShift(HBinaryOperation* op) { DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 5c0f31c0c..cc4aa144c 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -174,7 +174,6 @@ class LocationsBuilderARM : public HGraphVisitor { void HandleCondition(HCondition* condition); void HandleIntegerRotate(LocationSummary* locations); void HandleLongRotate(LocationSummary* locations); - void HandleRotate(HRor* ror); void HandleShift(HBinaryOperation* operation); void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); @@ -222,7 +221,6 @@ class InstructionCodeGeneratorARM : public InstructionCodeGenerator { void HandleCondition(HCondition* condition); void HandleIntegerRotate(LocationSummary* locations); void HandleLongRotate(LocationSummary* locations); - void HandleRotate(HRor* ror); void HandleShift(HBinaryOperation* operation); void GenerateWideAtomicStore(Register addr, uint32_t offset, diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 9acaa1d00..68c10d4e9 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -3981,8 +3981,7 @@ void InstructionCodeGeneratorX86::VisitRor(HRor* ror) { __ cmovl(kNotEqual, first_reg_hi, first_reg_lo); __ cmovl(kNotEqual, first_reg_lo, temp_reg); } else { - int32_t shift_amt = - CodeGenerator::GetInt64ValueOf(second.GetConstant()) & kMaxLongShiftValue; + int32_t shift_amt = CodeGenerator::GetInt64ValueOf(second.GetConstant()) & kMaxLongShiftValue; if (shift_amt == 0) { // Already fine. return; diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h index 10d83439f..6c551945e 100644 --- a/compiler/optimizing/common_arm64.h +++ b/compiler/optimizing/common_arm64.h @@ -194,7 +194,8 @@ static inline vixl::Operand OperandFromMemOperand(const vixl::MemOperand& mem_op } static bool CanEncodeConstantAsImmediate(HConstant* constant, HInstruction* instr) { - DCHECK(constant->IsIntConstant() || constant->IsLongConstant() || constant->IsNullConstant()); + DCHECK(constant->IsIntConstant() || constant->IsLongConstant() || constant->IsNullConstant()) + << constant->DebugName(); // For single uses we let VIXL handle the constant generation since it will // use registers that are not managed by the register allocator (wip0, wip1). @@ -221,7 +222,8 @@ static bool CanEncodeConstantAsImmediate(HConstant* constant, HInstruction* inst instr->IsBoundsCheck() || instr->IsCompare() || instr->IsCondition() || - instr->IsSub()); + instr->IsSub()) + << instr->DebugName(); // Uses aliases of ADD/SUB instructions. // If `value` does not fit but `-value` does, VIXL will automatically use // the 'opposite' instruction. diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc index 1fbb2d527..11e3689a8 100644 --- a/compiler/optimizing/graph_checker.cc +++ b/compiler/optimizing/graph_checker.cc @@ -945,7 +945,7 @@ void GraphChecker::VisitBinaryOperation(HBinaryOperation* op) { Primitive::PrettyDescriptor(result_type))); } } else { - // Use the first input, so that we can also make this check for shift operations. + // Use the first input, so that we can also make this check for shift and rotate operations. if (Primitive::PrimitiveKind(result_type) != Primitive::PrimitiveKind(lhs_type)) { AddError(StringPrintf("Binary operation %s %d has a result kind different " "from its input kind: %s vs %s.", diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index dd2977f79..4a8186a65 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -96,7 +96,7 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor { bool CanEnsureNotNullAt(HInstruction* instr, HInstruction* at) const; - void SimplifyRotate(HInvoke* invoke, bool is_left); + void SimplifyRotate(HInvoke* invoke, bool is_left, Primitive::Type type); void SimplifySystemArrayCopy(HInvoke* invoke); void SimplifyStringEquals(HInvoke* invoke); void SimplifyCompare(HInvoke* invoke, bool is_signum, Primitive::Type type); @@ -262,10 +262,8 @@ static bool IsSubRegBitsMinusOther(HSub* sub, size_t reg_bits, HInstruction* oth bool InstructionSimplifierVisitor::ReplaceRotateWithRor(HBinaryOperation* op, HUShr* ushr, HShl* shl) { - DCHECK(op->IsAdd() || op->IsXor() || op->IsOr()); - HRor* ror = new (GetGraph()->GetArena()) HRor(ushr->GetType(), - ushr->GetLeft(), - ushr->GetRight()); + DCHECK(op->IsAdd() || op->IsXor() || op->IsOr()) << op->DebugName(); + HRor* ror = new (GetGraph()->GetArena()) HRor(ushr->GetType(), ushr->GetLeft(), ushr->GetRight()); op->GetBlock()->ReplaceAndRemoveInstructionWith(op, ror); if (!ushr->HasUses()) { ushr->GetBlock()->RemoveInstruction(ushr); @@ -1232,7 +1230,7 @@ void InstructionSimplifierVisitor::VisitMul(HMul* instruction) { // with // SHL dst, src, log2(pow_of_2) HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor)); - HShl* shl = new(allocator) HShl(type, input_other, shift); + HShl* shl = new (allocator) HShl(type, input_other, shift); block->ReplaceAndRemoveInstructionWith(instruction, shl); RecordSimplification(); } else if (IsPowerOfTwo(factor - 1)) { @@ -1531,7 +1529,9 @@ void InstructionSimplifierVisitor::SimplifyStringEquals(HInvoke* instruction) { } } -void InstructionSimplifierVisitor::SimplifyRotate(HInvoke* invoke, bool is_left) { +void InstructionSimplifierVisitor::SimplifyRotate(HInvoke* invoke, + bool is_left, + Primitive::Type type) { DCHECK(invoke->IsInvokeStaticOrDirect()); DCHECK_EQ(invoke->GetOriginalInvokeType(), InvokeType::kStatic); HInstruction* value = invoke->InputAt(0); @@ -1541,7 +1541,7 @@ void InstructionSimplifierVisitor::SimplifyRotate(HInvoke* invoke, bool is_left) distance = new (GetGraph()->GetArena()) HNeg(distance->GetType(), distance); invoke->GetBlock()->InsertInstructionBefore(distance, invoke); } - HRor* ror = new (GetGraph()->GetArena()) HRor(value->GetType(), value, distance); + HRor* ror = new (GetGraph()->GetArena()) HRor(type, value, distance); invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, ror); // Remove ClinitCheck and LoadClass, if possible. HInstruction* clinit = invoke->InputAt(invoke->InputCount() - 1); @@ -1694,12 +1694,16 @@ void InstructionSimplifierVisitor::VisitInvoke(HInvoke* instruction) { SimplifySystemArrayCopy(instruction); break; case Intrinsics::kIntegerRotateRight: + SimplifyRotate(instruction, /* is_left */ false, Primitive::kPrimInt); + break; case Intrinsics::kLongRotateRight: - SimplifyRotate(instruction, false); + SimplifyRotate(instruction, /* is_left */ false, Primitive::kPrimLong); break; case Intrinsics::kIntegerRotateLeft: + SimplifyRotate(instruction, /* is_left */ true, Primitive::kPrimInt); + break; case Intrinsics::kLongRotateLeft: - SimplifyRotate(instruction, true); + SimplifyRotate(instruction, /* is_left */ true, Primitive::kPrimLong); break; case Intrinsics::kIntegerCompare: SimplifyCompare(instruction, /* is_signum */ false, Primitive::kPrimInt); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index e2a54f42c..46377ee50 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -4689,7 +4689,12 @@ class HXor : public HBinaryOperation { class HRor : public HBinaryOperation { public: HRor(Primitive::Type result_type, HInstruction* value, HInstruction* distance) - : HBinaryOperation(result_type, value, distance) {} + : HBinaryOperation(result_type, value, distance) { + if (kIsDebugBuild) { + DCHECK_EQ(result_type, Primitive::PrimitiveKind(value->GetType())); + DCHECK_EQ(Primitive::kPrimInt, Primitive::PrimitiveKind(distance->GetType())); + } + } template T Compute(T x, U y, V max_shift_value) const { diff --git a/test/565-checker-rotate/src/Main.java b/test/565-checker-rotate/src/Main.java index 33bbe0255..d7f57d8ce 100644 --- a/test/565-checker-rotate/src/Main.java +++ b/test/565-checker-rotate/src/Main.java @@ -16,112 +16,534 @@ public class Main { - /// CHECK-START: int Main.rotateLeft32(int, int) intrinsics_recognition (after) - /// CHECK-DAG: <> InvokeStaticOrDirect intrinsic:IntegerRotateLeft - /// CHECK-DAG: Return [<>] - private static int rotateLeft32(int x, int y) { - return Integer.rotateLeft(x, y); + /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) intrinsics_recognition (after) + /// CHECK-DAG: <> CurrentMethod + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> IntConstant 0 + /// CHECK-DAG: <> IntConstant 1 + /// CHECK-DAG: <> Phi [<>,<>] + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>,<>] intrinsic:IntegerRotateLeft + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> IntConstant 0 + /// CHECK-DAG: <> IntConstant 1 + /// CHECK-DAG: <> Phi [<>,<>] + /// CHECK-DAG: <> Neg [<>] + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier (after) + /// CHECK-NOT: InvokeStaticOrDirect + + /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) select_generator (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> IntConstant 0 + /// CHECK-DAG: <> IntConstant 1 + /// CHECK-DAG: <> Select [<>,<>,<>] + /// CHECK-DAG: <> Neg [<>] + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) select_generator (after) + /// CHECK-NOT: Phi + + /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier_after_bce (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> Neg [<>] + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateLeftBoolean(boolean, int) instruction_simplifier_after_bce (after) + /// CHECK-NOT: Select + + private static int rotateLeftBoolean(boolean value, int distance) { + return Integer.rotateLeft(value ? 1 : 0, distance); } - /// CHECK-START: long Main.rotateLeft64(long, int) intrinsics_recognition (after) - /// CHECK-DAG: <> InvokeStaticOrDirect intrinsic:LongRotateLeft - /// CHECK-DAG: Return [<>] - private static long rotateLeft64(long x, int y) { - return Long.rotateLeft(x, y); + /// CHECK-START: int Main.rotateLeftByte(byte, int) intrinsics_recognition (after) + /// CHECK-DAG: <> CurrentMethod + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>,<>] intrinsic:IntegerRotateLeft + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> Neg [<>] + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after) + /// CHECK-NOT: InvokeStaticOrDirect + + private static int rotateLeftByte(byte value, int distance) { + return Integer.rotateLeft(value, distance); } - /// CHECK-START: int Main.rotateRight32(int, int) intrinsics_recognition (after) - /// CHECK-DAG: <> InvokeStaticOrDirect intrinsic:IntegerRotateRight - /// CHECK-DAG: Return [<>] - private static int rotateRight32(int x, int y) { - return Integer.rotateRight(x, y); + /// CHECK-START: int Main.rotateLeftShort(short, int) intrinsics_recognition (after) + /// CHECK-DAG: <> CurrentMethod + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>,<>] intrinsic:IntegerRotateLeft + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> Neg [<>] + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after) + /// CHECK-NOT: InvokeStaticOrDirect + + private static int rotateLeftShort(short value, int distance) { + return Integer.rotateLeft(value, distance); } - /// CHECK-START: long Main.rotateRight64(long, int) intrinsics_recognition (after) - /// CHECK-DAG: <> InvokeStaticOrDirect intrinsic:LongRotateRight - /// CHECK-DAG: Return [<>] - private static long rotateRight64(long x, int y) { - return Long.rotateRight(x, y); + /// CHECK-START: int Main.rotateLeftChar(char, int) intrinsics_recognition (after) + /// CHECK-DAG: <> CurrentMethod + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>,<>] intrinsic:IntegerRotateLeft + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> Neg [<>] + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after) + /// CHECK-NOT: InvokeStaticOrDirect + + private static int rotateLeftChar(char value, int distance) { + return Integer.rotateLeft(value, distance); } - public static void main(String args[]) { - expectEquals32(0x00000001, rotateLeft32(0x00000001, 0)); - expectEquals32(0x00000002, rotateLeft32(0x00000001, 1)); - expectEquals32(0x80000000, rotateLeft32(0x00000001, 31)); - expectEquals32(0x00000001, rotateLeft32(0x00000001, 32)); // overshoot - expectEquals32(0x00000003, rotateLeft32(0x80000001, 1)); - expectEquals32(0x00000006, rotateLeft32(0x80000001, 2)); - expectEquals32(0x23456781, rotateLeft32(0x12345678, 4)); - expectEquals32(0xBCDEF09A, rotateLeft32(0x9ABCDEF0, 8)); + /// CHECK-START: int Main.rotateLeftInt(int, int) intrinsics_recognition (after) + /// CHECK-DAG: <> CurrentMethod + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>,<>] intrinsic:IntegerRotateLeft + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> Neg [<>] + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after) + /// CHECK-NOT: InvokeStaticOrDirect + + private static int rotateLeftInt(int value, int distance) { + return Integer.rotateLeft(value, distance); + } + + /// CHECK-START: long Main.rotateLeftLong(long, int) intrinsics_recognition (after) + /// CHECK-DAG: <> CurrentMethod + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>,<>] intrinsic:LongRotateLeft + /// CHECK-DAG: Return [<>] + + /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> Neg [<>] + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after) + /// CHECK-NOT: InvokeStaticOrDirect + + private static long rotateLeftLong(long value, int distance) { + return Long.rotateLeft(value, distance); + } + + + /// CHECK-START: int Main.rotateRightBoolean(boolean, int) intrinsics_recognition (after) + /// CHECK-DAG: <> CurrentMethod + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> IntConstant 0 + /// CHECK-DAG: <> IntConstant 1 + /// CHECK-DAG: <> Phi [<>,<>] + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>,<>] intrinsic:IntegerRotateRight + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> IntConstant 0 + /// CHECK-DAG: <> IntConstant 1 + /// CHECK-DAG: <> Phi [<>,<>] + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier (after) + /// CHECK-NOT: InvokeStaticOrDirect + + /// CHECK-START: int Main.rotateRightBoolean(boolean, int) select_generator (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> IntConstant 0 + /// CHECK-DAG: <> IntConstant 1 + /// CHECK-DAG: <> Select [<>,<>,<>] + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateRightBoolean(boolean, int) select_generator (after) + /// CHECK-NOT: Phi + + /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier_after_bce (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateRightBoolean(boolean, int) instruction_simplifier_after_bce (after) + /// CHECK-NOT: Select + + private static int rotateRightBoolean(boolean value, int distance) { + return Integer.rotateRight(value ? 1 : 0, distance); + } + + /// CHECK-START: int Main.rotateRightByte(byte, int) intrinsics_recognition (after) + /// CHECK-DAG: <> CurrentMethod + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>,<>] intrinsic:IntegerRotateRight + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after) + /// CHECK-NOT: InvokeStaticOrDirect + + private static int rotateRightByte(byte value, int distance) { + return Integer.rotateRight(value, distance); + } + + /// CHECK-START: int Main.rotateRightShort(short, int) intrinsics_recognition (after) + /// CHECK-DAG: <> CurrentMethod + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>,<>] intrinsic:IntegerRotateRight + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after) + /// CHECK-NOT: InvokeStaticOrDirect + + private static int rotateRightShort(short value, int distance) { + return Integer.rotateRight(value, distance); + } + + /// CHECK-START: int Main.rotateRightChar(char, int) intrinsics_recognition (after) + /// CHECK-DAG: <> CurrentMethod + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>,<>] intrinsic:IntegerRotateRight + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after) + /// CHECK-NOT: InvokeStaticOrDirect + + private static int rotateRightChar(char value, int distance) { + return Integer.rotateRight(value, distance); + } + + /// CHECK-START: int Main.rotateRightInt(int, int) intrinsics_recognition (after) + /// CHECK-DAG: <> CurrentMethod + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>,<>] intrinsic:IntegerRotateRight + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after) + /// CHECK-NOT: InvokeStaticOrDirect + + private static int rotateRightInt(int value, int distance) { + return Integer.rotateRight(value, distance); + } + + /// CHECK-START: long Main.rotateRightLong(long, int) intrinsics_recognition (after) + /// CHECK-DAG: <> CurrentMethod + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>,<>] intrinsic:LongRotateRight + /// CHECK-DAG: Return [<>] + + /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after) + /// CHECK: <> ParameterValue + /// CHECK: <> ParameterValue + /// CHECK-DAG: <> Ror [<>,<>] + /// CHECK-DAG: Return [<>] + + /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after) + /// CHECK-NOT: InvokeStaticOrDirect + + private static long rotateRightLong(long value, int distance) { + return Long.rotateRight(value, distance); + } + + + public static void testRotateLeftBoolean() { + for (int i = 0; i < 40; i++) { // overshoot a bit + int j = i & 31; + expectEqualsInt(0, rotateLeftBoolean(false, i)); + expectEqualsInt(1 << i, rotateLeftBoolean(true, i)); + } + } + + public static void testRotateLeftByte() { + expectEqualsInt(0x00000001, rotateLeftByte((byte)0x01, 0)); + expectEqualsInt(0x00000002, rotateLeftByte((byte)0x01, 1)); + expectEqualsInt(0x80000000, rotateLeftByte((byte)0x01, 31)); + expectEqualsInt(0x00000001, rotateLeftByte((byte)0x01, 32)); // overshoot + expectEqualsInt(0xFFFFFF03, rotateLeftByte((byte)0x81, 1)); + expectEqualsInt(0xFFFFFE07, rotateLeftByte((byte)0x81, 2)); + expectEqualsInt(0x00000120, rotateLeftByte((byte)0x12, 4)); + expectEqualsInt(0xFFFF9AFF, rotateLeftByte((byte)0x9A, 8)); + for (int i = 0; i < 40; i++) { // overshoot a bit + int j = i & 31; + expectEqualsInt(0x00000000, rotateLeftByte((byte)0x0000, i)); + expectEqualsInt(0xFFFFFFFF, rotateLeftByte((byte)0xFFFF, i)); + expectEqualsInt((1 << j), rotateLeftByte((byte)0x0001, i)); + expectEqualsInt((0x12 << j) | (0x12 >>> -j), rotateLeftByte((byte)0x12, i)); + } + } + + public static void testRotateLeftShort() { + expectEqualsInt(0x00000001, rotateLeftShort((short)0x0001, 0)); + expectEqualsInt(0x00000002, rotateLeftShort((short)0x0001, 1)); + expectEqualsInt(0x80000000, rotateLeftShort((short)0x0001, 31)); + expectEqualsInt(0x00000001, rotateLeftShort((short)0x0001, 32)); // overshoot + expectEqualsInt(0xFFFF0003, rotateLeftShort((short)0x8001, 1)); + expectEqualsInt(0xFFFE0007, rotateLeftShort((short)0x8001, 2)); + expectEqualsInt(0x00012340, rotateLeftShort((short)0x1234, 4)); + expectEqualsInt(0xFF9ABCFF, rotateLeftShort((short)0x9ABC, 8)); + for (int i = 0; i < 40; i++) { // overshoot a bit + int j = i & 31; + expectEqualsInt(0x00000000, rotateLeftShort((short)0x0000, i)); + expectEqualsInt(0xFFFFFFFF, rotateLeftShort((short)0xFFFF, i)); + expectEqualsInt((1 << j), rotateLeftShort((short)0x0001, i)); + expectEqualsInt((0x1234 << j) | (0x1234 >>> -j), rotateLeftShort((short)0x1234, i)); + } + } + + public static void testRotateLeftChar() { + expectEqualsInt(0x00000001, rotateLeftChar((char)0x0001, 0)); + expectEqualsInt(0x00000002, rotateLeftChar((char)0x0001, 1)); + expectEqualsInt(0x80000000, rotateLeftChar((char)0x0001, 31)); + expectEqualsInt(0x00000001, rotateLeftChar((char)0x0001, 32)); // overshoot + expectEqualsInt(0x00010002, rotateLeftChar((char)0x8001, 1)); + expectEqualsInt(0x00020004, rotateLeftChar((char)0x8001, 2)); + expectEqualsInt(0x00012340, rotateLeftChar((char)0x1234, 4)); + expectEqualsInt(0x009ABC00, rotateLeftChar((char)0x9ABC, 8)); + expectEqualsInt(0x00FF0000, rotateLeftChar((char)0xFF00, 8)); for (int i = 0; i < 40; i++) { // overshoot a bit int j = i & 31; - expectEquals32(0x00000000, rotateLeft32(0x00000000, i)); - expectEquals32(0xFFFFFFFF, rotateLeft32(0xFFFFFFFF, i)); - expectEquals32(1 << j, rotateLeft32(0x00000001, i)); - expectEquals32((0x12345678 << j) | (0x12345678 >>> -j), - rotateLeft32(0x12345678, i)); + expectEqualsInt(0x00000000, rotateLeftChar((char)0x0000, i)); + expectEqualsInt((1 << j), rotateLeftChar((char)0x0001, i)); + expectEqualsInt((0x1234 << j) | (0x1234 >>> -j), rotateLeftChar((char)0x1234, i)); } + } - expectEquals64(0x0000000000000001L, rotateLeft64(0x0000000000000001L, 0)); - expectEquals64(0x0000000000000002L, rotateLeft64(0x0000000000000001L, 1)); - expectEquals64(0x8000000000000000L, rotateLeft64(0x0000000000000001L, 63)); - expectEquals64(0x0000000000000001L, rotateLeft64(0x0000000000000001L, 64)); // overshoot - expectEquals64(0x0000000000000003L, rotateLeft64(0x8000000000000001L, 1)); - expectEquals64(0x0000000000000006L, rotateLeft64(0x8000000000000001L, 2)); - expectEquals64(0x23456789ABCDEF01L, rotateLeft64(0x123456789ABCDEF0L, 4)); - expectEquals64(0x3456789ABCDEF012L, rotateLeft64(0x123456789ABCDEF0L, 8)); + public static void testRotateLeftInt() { + expectEqualsInt(0x00000001, rotateLeftInt(0x00000001, 0)); + expectEqualsInt(0x00000002, rotateLeftInt(0x00000001, 1)); + expectEqualsInt(0x80000000, rotateLeftInt(0x00000001, 31)); + expectEqualsInt(0x00000001, rotateLeftInt(0x00000001, 32)); // overshoot + expectEqualsInt(0x00000003, rotateLeftInt(0x80000001, 1)); + expectEqualsInt(0x00000006, rotateLeftInt(0x80000001, 2)); + expectEqualsInt(0x23456781, rotateLeftInt(0x12345678, 4)); + expectEqualsInt(0xBCDEF09A, rotateLeftInt(0x9ABCDEF0, 8)); + for (int i = 0; i < 40; i++) { // overshoot a bit + int j = i & 31; + expectEqualsInt(0x00000000, rotateLeftInt(0x00000000, i)); + expectEqualsInt(0xFFFFFFFF, rotateLeftInt(0xFFFFFFFF, i)); + expectEqualsInt(1 << j, rotateLeftInt(0x00000001, i)); + expectEqualsInt((0x12345678 << j) | (0x12345678 >>> -j), rotateLeftInt(0x12345678, i)); + } + } + + public static void testRotateLeftLong() { + expectEqualsLong(0x0000000000000001L, rotateLeftLong(0x0000000000000001L, 0)); + expectEqualsLong(0x0000000000000002L, rotateLeftLong(0x0000000000000001L, 1)); + expectEqualsLong(0x8000000000000000L, rotateLeftLong(0x0000000000000001L, 63)); + expectEqualsLong(0x0000000000000001L, rotateLeftLong(0x0000000000000001L, 64)); // overshoot + expectEqualsLong(0x0000000000000003L, rotateLeftLong(0x8000000000000001L, 1)); + expectEqualsLong(0x0000000000000006L, rotateLeftLong(0x8000000000000001L, 2)); + expectEqualsLong(0x23456789ABCDEF01L, rotateLeftLong(0x123456789ABCDEF0L, 4)); + expectEqualsLong(0x3456789ABCDEF012L, rotateLeftLong(0x123456789ABCDEF0L, 8)); for (int i = 0; i < 70; i++) { // overshoot a bit int j = i & 63; - expectEquals64(0x0000000000000000L, rotateLeft64(0x0000000000000000L, i)); - expectEquals64(0xFFFFFFFFFFFFFFFFL, rotateLeft64(0xFFFFFFFFFFFFFFFFL, i)); - expectEquals64(1L << j, rotateLeft64(0x0000000000000001, i)); - expectEquals64((0x123456789ABCDEF0L << j) | (0x123456789ABCDEF0L >>> -j), - rotateLeft64(0x123456789ABCDEF0L, i)); + expectEqualsLong(0x0000000000000000L, rotateLeftLong(0x0000000000000000L, i)); + expectEqualsLong(0xFFFFFFFFFFFFFFFFL, rotateLeftLong(0xFFFFFFFFFFFFFFFFL, i)); + expectEqualsLong(1L << j, rotateLeftLong(0x0000000000000001, i)); + expectEqualsLong((0x123456789ABCDEF0L << j) | (0x123456789ABCDEF0L >>> -j), + rotateLeftLong(0x123456789ABCDEF0L, i)); + } + } + + public static void testRotateRightBoolean() { + for (int i = 0; i < 40; i++) { // overshoot a bit + int j = i & 31; + expectEqualsInt(0, rotateRightBoolean(false, i)); + expectEqualsInt(1 << (32 - i), rotateRightBoolean(true, i)); + } + } + + public static void testRotateRightByte() { + expectEqualsInt(0xFFFFFF80, rotateRightByte((byte)0x80, 0)); + expectEqualsInt(0x7FFFFFC0, rotateRightByte((byte)0x80, 1)); + expectEqualsInt(0xFFFFFF01, rotateRightByte((byte)0x80, 31)); + expectEqualsInt(0xFFFFFF80, rotateRightByte((byte)0x80, 32)); // overshoot + expectEqualsInt(0xFFFFFFC0, rotateRightByte((byte)0x81, 1)); + expectEqualsInt(0x7FFFFFE0, rotateRightByte((byte)0x81, 2)); + expectEqualsInt(0x20000001, rotateRightByte((byte)0x12, 4)); + expectEqualsInt(0x9AFFFFFF, rotateRightByte((byte)0x9A, 8)); + for (int i = 0; i < 40; i++) { // overshoot a bit + int j = i & 31; + expectEqualsInt(0x00000000, rotateRightByte((byte)0x00, i)); + expectEqualsInt(0xFFFFFFFF, rotateRightByte((byte)0xFF, i)); + expectEqualsInt(1 << (32 - j), rotateRightByte((byte)0x01, i)); + expectEqualsInt((0x12 >>> j) | (0x12 << -j), rotateRightByte((byte)0x12, i)); + } + } + + public static void testRotateRightShort() { + expectEqualsInt(0xFFFF8000, rotateRightShort((short)0x8000, 0)); + expectEqualsInt(0x7FFFC000, rotateRightShort((short)0x8000, 1)); + expectEqualsInt(0xFFFF0001, rotateRightShort((short)0x8000, 31)); + expectEqualsInt(0xFFFF8000, rotateRightShort((short)0x8000, 32)); // overshoot + expectEqualsInt(0xFFFFC000, rotateRightShort((short)0x8001, 1)); + expectEqualsInt(0x7FFFE000, rotateRightShort((short)0x8001, 2)); + expectEqualsInt(0x40000123, rotateRightShort((short)0x1234, 4)); + expectEqualsInt(0xBCFFFF9A, rotateRightShort((short)0x9ABC, 8)); + for (int i = 0; i < 40; i++) { // overshoot a bit + int j = i & 31; + expectEqualsInt(0x00000000, rotateRightShort((short)0x0000, i)); + expectEqualsInt(0xFFFFFFFF, rotateRightShort((short)0xFFFF, i)); + expectEqualsInt(1 << (32 - j), rotateRightShort((short)0x0001, i)); + expectEqualsInt((0x1234 >>> j) | (0x1234 << -j), rotateRightShort((short)0x1234, i)); } + } - expectEquals32(0x80000000, rotateRight32(0x80000000, 0)); - expectEquals32(0x40000000, rotateRight32(0x80000000, 1)); - expectEquals32(0x00000001, rotateRight32(0x80000000, 31)); - expectEquals32(0x80000000, rotateRight32(0x80000000, 32)); // overshoot - expectEquals32(0xC0000000, rotateRight32(0x80000001, 1)); - expectEquals32(0x60000000, rotateRight32(0x80000001, 2)); - expectEquals32(0x81234567, rotateRight32(0x12345678, 4)); - expectEquals32(0xF09ABCDE, rotateRight32(0x9ABCDEF0, 8)); + public static void testRotateRightChar() { + expectEqualsInt(0x00008000, rotateRightChar((char)0x8000, 0)); + expectEqualsInt(0x00004000, rotateRightChar((char)0x8000, 1)); + expectEqualsInt(0x00010000, rotateRightChar((char)0x8000, 31)); + expectEqualsInt(0x00008000, rotateRightChar((char)0x8000, 32)); // overshoot + expectEqualsInt(0x80004000, rotateRightChar((char)0x8001, 1)); + expectEqualsInt(0x40002000, rotateRightChar((char)0x8001, 2)); + expectEqualsInt(0x40000123, rotateRightChar((char)0x1234, 4)); + expectEqualsInt(0xBC00009A, rotateRightChar((char)0x9ABC, 8)); for (int i = 0; i < 40; i++) { // overshoot a bit int j = i & 31; - expectEquals32(0x00000000, rotateRight32(0x00000000, i)); - expectEquals32(0xFFFFFFFF, rotateRight32(0xFFFFFFFF, i)); - expectEquals32(0x80000000 >>> j, rotateRight32(0x80000000, i)); - expectEquals32((0x12345678 >>> j) | (0x12345678 << -j), - rotateRight32(0x12345678, i)); + expectEqualsInt(0x00000000, rotateRightChar((char)0x0000, i)); + expectEqualsInt(1 << (32 - j), rotateRightChar((char)0x0001, i)); + expectEqualsInt((0x1234 >>> j) | (0x1234 << -j), rotateRightChar((char)0x1234, i)); } + } + + public static void testRotateRightInt() { + expectEqualsInt(0x80000000, rotateRightInt(0x80000000, 0)); + expectEqualsInt(0x40000000, rotateRightInt(0x80000000, 1)); + expectEqualsInt(0x00000001, rotateRightInt(0x80000000, 31)); + expectEqualsInt(0x80000000, rotateRightInt(0x80000000, 32)); // overshoot + expectEqualsInt(0xC0000000, rotateRightInt(0x80000001, 1)); + expectEqualsInt(0x60000000, rotateRightInt(0x80000001, 2)); + expectEqualsInt(0x81234567, rotateRightInt(0x12345678, 4)); + expectEqualsInt(0xF09ABCDE, rotateRightInt(0x9ABCDEF0, 8)); + for (int i = 0; i < 40; i++) { // overshoot a bit + int j = i & 31; + expectEqualsInt(0x00000000, rotateRightInt(0x00000000, i)); + expectEqualsInt(0xFFFFFFFF, rotateRightInt(0xFFFFFFFF, i)); + expectEqualsInt(0x80000000 >>> j, rotateRightInt(0x80000000, i)); + expectEqualsInt((0x12345678 >>> j) | (0x12345678 << -j), rotateRightInt(0x12345678, i)); + } + } - expectEquals64(0x8000000000000000L, rotateRight64(0x8000000000000000L, 0)); - expectEquals64(0x4000000000000000L, rotateRight64(0x8000000000000000L, 1)); - expectEquals64(0x0000000000000001L, rotateRight64(0x8000000000000000L, 63)); - expectEquals64(0x8000000000000000L, rotateRight64(0x8000000000000000L, 64)); // overshoot - expectEquals64(0xC000000000000000L, rotateRight64(0x8000000000000001L, 1)); - expectEquals64(0x6000000000000000L, rotateRight64(0x8000000000000001L, 2)); - expectEquals64(0x0123456789ABCDEFL, rotateRight64(0x123456789ABCDEF0L, 4)); - expectEquals64(0xF0123456789ABCDEL, rotateRight64(0x123456789ABCDEF0L, 8)); + public static void testRotateRightLong() { + expectEqualsLong(0x8000000000000000L, rotateRightLong(0x8000000000000000L, 0)); + expectEqualsLong(0x4000000000000000L, rotateRightLong(0x8000000000000000L, 1)); + expectEqualsLong(0x0000000000000001L, rotateRightLong(0x8000000000000000L, 63)); + expectEqualsLong(0x8000000000000000L, rotateRightLong(0x8000000000000000L, 64)); // overshoot + expectEqualsLong(0xC000000000000000L, rotateRightLong(0x8000000000000001L, 1)); + expectEqualsLong(0x6000000000000000L, rotateRightLong(0x8000000000000001L, 2)); + expectEqualsLong(0x0123456789ABCDEFL, rotateRightLong(0x123456789ABCDEF0L, 4)); + expectEqualsLong(0xF0123456789ABCDEL, rotateRightLong(0x123456789ABCDEF0L, 8)); for (int i = 0; i < 70; i++) { // overshoot a bit int j = i & 63; - expectEquals64(0x0000000000000000L, rotateRight64(0x0000000000000000L, i)); - expectEquals64(0xFFFFFFFFFFFFFFFFL, rotateRight64(0xFFFFFFFFFFFFFFFFL, i)); - expectEquals64(0x8000000000000000L >>> j, rotateRight64(0x8000000000000000L, i)); - expectEquals64((0x123456789ABCDEF0L >>> j) | (0x123456789ABCDEF0L << -j), - rotateRight64(0x123456789ABCDEF0L, i)); + expectEqualsLong(0x0000000000000000L, rotateRightLong(0x0000000000000000L, i)); + expectEqualsLong(0xFFFFFFFFFFFFFFFFL, rotateRightLong(0xFFFFFFFFFFFFFFFFL, i)); + expectEqualsLong(0x8000000000000000L >>> j, rotateRightLong(0x8000000000000000L, i)); + expectEqualsLong((0x123456789ABCDEF0L >>> j) | (0x123456789ABCDEF0L << -j), + rotateRightLong(0x123456789ABCDEF0L, i)); } + } + + + public static void main(String args[]) { + testRotateLeftBoolean(); + testRotateLeftByte(); + testRotateLeftShort(); + testRotateLeftChar(); + testRotateLeftInt(); + testRotateLeftLong(); + + testRotateRightBoolean(); + testRotateRightByte(); + testRotateRightShort(); + testRotateRightChar(); + testRotateRightInt(); + testRotateRightLong(); System.out.println("passed"); } - private static void expectEquals32(int expected, int result) { + + private static void expectEqualsInt(int expected, int result) { if (expected != result) { throw new Error("Expected: " + expected + ", found: " + result); } } - private static void expectEquals64(long expected, long result) { + + private static void expectEqualsLong(long expected, long result) { if (expected != result) { throw new Error("Expected: " + expected + ", found: " + result); } -- 2.11.0