diff options
author | xueliang.zhong <xueliang.zhong@linaro.org> | 2017-10-13 12:06:56 +0100 |
---|---|---|
committer | Evgeny Astigeevich <evgeny.astigeevich@linaro.org> | 2018-11-02 10:07:12 +0000 |
commit | cb58b07d233c5f8e910e6e5946da8ac4ec3099f5 (patch) | |
tree | bd19cb9a44555adf51e2d145c322a592c6cd3527 | |
parent | e2acc339ede3c620a476827880cf68d044dcd53e (diff) | |
download | android_art-cb58b07d233c5f8e910e6e5946da8ac4ec3099f5.tar.gz android_art-cb58b07d233c5f8e910e6e5946da8ac4ec3099f5.tar.bz2 android_art-cb58b07d233c5f8e910e6e5946da8ac4ec3099f5.zip |
ART: Add CRC32.udate(int,int) intrinsic for ARM64
Use crc32 instructions for java.util.zip.CRC32.update(int,int).
Note that CRC32 is an optional feature on ARMv8, this intrinsic
is only enabled for devices with CRC32 intruction support.
Original author: tim.zhang@linaro.org
Performance improvements in CRC32Bench.UpdateInt:
Pixel 2: 22.8x
Nexus 6P:
little core: 28.3x
big core : 21.6x
Test: m test-art-target-gtest
Test: testrunner.py --target --optimizing --jit --interpreter
Test: 580-crc32
Change-Id: I1a9bc2befd2934b04103a27ce05806e919874070
-rw-r--r-- | compiler/optimizing/intrinsics_arm64.cc | 34 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_arm_vixl.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_mips.cc | 2 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_mips64.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_x86.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_x86_64.cc | 1 | ||||
-rw-r--r-- | runtime/art_method-inl.h | 1 | ||||
-rw-r--r-- | runtime/image.cc | 2 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_intrinsics.cc | 1 | ||||
-rw-r--r-- | runtime/intrinsics_list.h | 1 | ||||
-rw-r--r-- | test/580-crc32/expected.txt | 0 | ||||
-rw-r--r-- | test/580-crc32/info.txt | 1 | ||||
-rw-r--r-- | test/580-crc32/src/Main.java | 131 |
13 files changed, 176 insertions, 1 deletions
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 7684dc79f2..6d04b0e9d9 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -2916,6 +2916,40 @@ void IntrinsicLocationsBuilderARM64::VisitReachabilityFence(HInvoke* invoke) { void IntrinsicCodeGeneratorARM64::VisitReachabilityFence(HInvoke* invoke ATTRIBUTE_UNUSED) { } +void IntrinsicLocationsBuilderARM64::VisitCRC32Update(HInvoke* invoke) { + if (!codegen_->GetInstructionSetFeatures().HasCRC()) { + return; + } + + LocationSummary* locations = new (allocator_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister()); +} + +// Lower the invoke of CRC32.update(int crc, int b). +void IntrinsicCodeGeneratorARM64::VisitCRC32Update(HInvoke* invoke) { + DCHECK(codegen_->GetInstructionSetFeatures().HasCRC()); + + MacroAssembler* masm = GetVIXLAssembler(); + + Register crc = InputRegisterAt(invoke, 0); + Register val = InputRegisterAt(invoke, 1); + Register out = OutputRegister(invoke); + + // The general algorithm of the CRC32 calculation is: + // crc = ~crc + // result = crc32_for_byte(crc, b) + // crc = ~result + // It is directly lowered to three instructions. + __ Mvn(out, crc); + __ Crc32b(out, out, val); + __ Mvn(out, out); +} + UNIMPLEMENTED_INTRINSIC(ARM64, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(ARM64, StringStringIndexOf); diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index 38e4c8968a..0c463a280e 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -3059,6 +3059,7 @@ UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRoundDouble) // Could be done by changing UNIMPLEMENTED_INTRINSIC(ARMVIXL, UnsafeCASLong) // High register pressure. UNIMPLEMENTED_INTRINSIC(ARMVIXL, SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(ARMVIXL, ReferenceGetReferent) +UNIMPLEMENTED_INTRINSIC(ARMVIXL, CRC32Update) UNIMPLEMENTED_INTRINSIC(ARMVIXL, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(ARMVIXL, StringStringIndexOfAfter); diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc index 6f7f5e49c1..21fb7d7f1c 100644 --- a/compiler/optimizing/intrinsics_mips.cc +++ b/compiler/optimizing/intrinsics_mips.cc @@ -2696,6 +2696,8 @@ UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeCASLong) UNIMPLEMENTED_INTRINSIC(MIPS, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopy) +UNIMPLEMENTED_INTRINSIC(MIPS, CRC32Update) + UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOfAfter); UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferAppend); diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc index 2eb252908c..4b86f5d423 100644 --- a/compiler/optimizing/intrinsics_mips64.cc +++ b/compiler/optimizing/intrinsics_mips64.cc @@ -2346,6 +2346,7 @@ void IntrinsicCodeGeneratorMIPS64::VisitReachabilityFence(HInvoke* invoke ATTRIB UNIMPLEMENTED_INTRINSIC(MIPS64, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(MIPS64, SystemArrayCopy) +UNIMPLEMENTED_INTRINSIC(MIPS64, CRC32Update) UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOfAfter); diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 3504d7a6f8..6dd4681847 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -2967,6 +2967,7 @@ UNIMPLEMENTED_INTRINSIC(X86, IntegerHighestOneBit) UNIMPLEMENTED_INTRINSIC(X86, LongHighestOneBit) UNIMPLEMENTED_INTRINSIC(X86, IntegerLowestOneBit) UNIMPLEMENTED_INTRINSIC(X86, LongLowestOneBit) +UNIMPLEMENTED_INTRINSIC(X86, CRC32Update) UNIMPLEMENTED_INTRINSIC(X86, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(X86, StringStringIndexOfAfter); diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 96f6eaaf33..7db26dc9be 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -2732,6 +2732,7 @@ void IntrinsicCodeGeneratorX86_64::VisitReachabilityFence(HInvoke* invoke ATTRIB UNIMPLEMENTED_INTRINSIC(X86_64, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(X86_64, FloatIsInfinite) UNIMPLEMENTED_INTRINSIC(X86_64, DoubleIsInfinite) +UNIMPLEMENTED_INTRINSIC(X86_64, CRC32Update) UNIMPLEMENTED_INTRINSIC(X86_64, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(X86_64, StringStringIndexOfAfter); diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index e9c17eeab5..d8da9129ed 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -402,6 +402,7 @@ inline hiddenapi::ApiList ArtMethod::GetHiddenApiAccessFlags() case Intrinsics::kUnsafeLoadFence: case Intrinsics::kUnsafeStoreFence: case Intrinsics::kUnsafeFullFence: + case Intrinsics::kCRC32Update: // These intrinsics are on the light greylist and will fail a DCHECK in // SetIntrinsic() if their flags change on the respective dex methods. // Note that the DCHECK currently won't fail if the dex methods are diff --git a/runtime/image.cc b/runtime/image.cc index 376742afbc..59ac283779 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -26,7 +26,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '6', '\0' }; // Add metadata section. +const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '7', '\0' }; // Added CRC32 intrinsic ImageHeader::ImageHeader(uint32_t image_begin, uint32_t image_size, diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc index 17b3cd45aa..24a026a92e 100644 --- a/runtime/interpreter/interpreter_intrinsics.cc +++ b/runtime/interpreter/interpreter_intrinsics.cc @@ -558,6 +558,7 @@ bool MterpHandleIntrinsic(ShadowFrame* shadow_frame, UNIMPLEMENTED_CASE(ReferenceGetReferent /* ()Ljava/lang/Object; */) UNIMPLEMENTED_CASE(IntegerValueOf /* (I)Ljava/lang/Integer; */) UNIMPLEMENTED_CASE(ThreadInterrupted /* ()Z */) + UNIMPLEMENTED_CASE(CRC32Update /* (II)I */) INTRINSIC_CASE(VarHandleFullFence) INTRINSIC_CASE(VarHandleAcquireFence) INTRINSIC_CASE(VarHandleReleaseFence) diff --git a/runtime/intrinsics_list.h b/runtime/intrinsics_list.h index 2f91f5dfe0..093dd7f400 100644 --- a/runtime/intrinsics_list.h +++ b/runtime/intrinsics_list.h @@ -219,6 +219,7 @@ V(VarHandleLoadLoadFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "loadLoadFence", "()V") \ V(VarHandleStoreStoreFence, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "storeStoreFence", "()V") \ V(ReachabilityFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/ref/Reference;", "reachabilityFence", "(Ljava/lang/Object;)V") \ + V(CRC32Update, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/util/zip/CRC32;", "update", "(II)I") \ SIGNATURE_POLYMORPHIC_INTRINSICS_LIST(V) #endif // ART_RUNTIME_INTRINSICS_LIST_H_ diff --git a/test/580-crc32/expected.txt b/test/580-crc32/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/580-crc32/expected.txt diff --git a/test/580-crc32/info.txt b/test/580-crc32/info.txt new file mode 100644 index 0000000000..24f31e0e1b --- /dev/null +++ b/test/580-crc32/info.txt @@ -0,0 +1 @@ +This test case is used to test java.util.zip.CRC32. diff --git a/test/580-crc32/src/Main.java b/test/580-crc32/src/Main.java new file mode 100644 index 0000000000..7fc1273600 --- /dev/null +++ b/test/580-crc32/src/Main.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.zip.CRC32; + +/** + * The ART compiler can use intrinsics for the java.util.zip.CRC32 method: + * private native static int update(int crc, int b) + * + * As the method is private it is not possible to check the use of intrinsics + * for it directly. + * The tests check that correct checksums are produced. + */ +public class Main { + private static CRC32 crc32 = new CRC32(); + + public Main() { + } + + public static long TestInt(int value) { + crc32.reset(); + crc32.update(value); + return crc32.getValue(); + } + + public static long TestInt(int... values) { + crc32.reset(); + for (int value : values) { + crc32.update(value); + } + return crc32.getValue(); + } + + public static void assertEqual(long expected, long actual) { + if (expected != actual) { + throw new Error("Expected: " + expected + ", found: " + actual); + } + } + + public static void main(String args[]) { + // public void update(int b) + // + // Tests for checksums of the byte 0x0 + assertEqual(0xD202EF8DL, TestInt(0x0)); + assertEqual(0xD202EF8DL, TestInt(0x0100)); + assertEqual(0xD202EF8DL, TestInt(0x010000)); + assertEqual(0xD202EF8DL, TestInt(0x01000000)); + assertEqual(0xD202EF8DL, TestInt(0xff00)); + assertEqual(0xD202EF8DL, TestInt(0xffff00)); + assertEqual(0xD202EF8DL, TestInt(0xffffff00)); + assertEqual(0xD202EF8DL, TestInt(0x1200)); + assertEqual(0xD202EF8DL, TestInt(0x123400)); + assertEqual(0xD202EF8DL, TestInt(0x12345600)); + assertEqual(0xD202EF8DL, TestInt(Integer.MIN_VALUE)); + + // Tests for checksums of the byte 0x1 + assertEqual(0xA505DF1BL, TestInt(0x1)); + assertEqual(0xA505DF1BL, TestInt(0x0101)); + assertEqual(0xA505DF1BL, TestInt(0x010001)); + assertEqual(0xA505DF1BL, TestInt(0x01000001)); + assertEqual(0xA505DF1BL, TestInt(0xff01)); + assertEqual(0xA505DF1BL, TestInt(0xffff01)); + assertEqual(0xA505DF1BL, TestInt(0xffffff01)); + assertEqual(0xA505DF1BL, TestInt(0x1201)); + assertEqual(0xA505DF1BL, TestInt(0x123401)); + assertEqual(0xA505DF1BL, TestInt(0x12345601)); + + // Tests for checksums of the byte 0x0f + assertEqual(0x42BDF21CL, TestInt(0x0f)); + assertEqual(0x42BDF21CL, TestInt(0x010f)); + assertEqual(0x42BDF21CL, TestInt(0x01000f)); + assertEqual(0x42BDF21CL, TestInt(0x0100000f)); + assertEqual(0x42BDF21CL, TestInt(0xff0f)); + assertEqual(0x42BDF21CL, TestInt(0xffff0f)); + assertEqual(0x42BDF21CL, TestInt(0xffffff0f)); + assertEqual(0x42BDF21CL, TestInt(0x120f)); + assertEqual(0x42BDF21CL, TestInt(0x12340f)); + assertEqual(0x42BDF21CL, TestInt(0x1234560f)); + + // Tests for checksums of the byte 0xff + assertEqual(0xFF000000L, TestInt(0x00ff)); + assertEqual(0xFF000000L, TestInt(0x01ff)); + assertEqual(0xFF000000L, TestInt(0x0100ff)); + assertEqual(0xFF000000L, TestInt(0x010000ff)); + assertEqual(0xFF000000L, TestInt(0x0000ffff)); + assertEqual(0xFF000000L, TestInt(0x00ffffff)); + assertEqual(0xFF000000L, TestInt(0xffffffff)); + assertEqual(0xFF000000L, TestInt(0x12ff)); + assertEqual(0xFF000000L, TestInt(0x1234ff)); + assertEqual(0xFF000000L, TestInt(0x123456ff)); + assertEqual(0xFF000000L, TestInt(Integer.MAX_VALUE)); + + // Tests for sequences + assertEqual(0xFF41D912L, TestInt(0, 0, 0)); + assertEqual(0xFF41D912L, TestInt(0x0100, 0x010000, 0x01000000)); + assertEqual(0xFF41D912L, TestInt(0xff00, 0xffff00, 0xffffff00)); + assertEqual(0xFF41D912L, TestInt(0x1200, 0x123400, 0x12345600)); + + assertEqual(0x909FB2F2L, TestInt(1, 1, 1)); + assertEqual(0x909FB2F2L, TestInt(0x0101, 0x010001, 0x01000001)); + assertEqual(0x909FB2F2L, TestInt(0xff01, 0xffff01, 0xffffff01)); + assertEqual(0x909FB2F2L, TestInt(0x1201, 0x123401, 0x12345601)); + + assertEqual(0xE33A9F71L, TestInt(0x0f, 0x0f, 0x0f)); + assertEqual(0xE33A9F71L, TestInt(0x010f, 0x01000f, 0x0100000f)); + assertEqual(0xE33A9F71L, TestInt(0xff0f, 0xffff0f, 0xffffff0f)); + assertEqual(0xE33A9F71L, TestInt(0x120f, 0x12340f, 0x1234560f)); + + assertEqual(0xFFFFFF00L, TestInt(0x0ff, 0x0ff, 0x0ff)); + assertEqual(0xFFFFFF00L, TestInt(0x01ff, 0x0100ff, 0x010000ff)); + assertEqual(0xFFFFFF00L, TestInt(0x00ffff, 0x00ffffff, 0xffffffff)); + assertEqual(0xFFFFFF00L, TestInt(0x12ff, 0x1234ff, 0x123456ff)); + + assertEqual(0xB6CC4292L, TestInt(0x01, 0x02)); + + assertEqual(0xB2DE047CL, TestInt(0x0, -1, Integer.MIN_VALUE, Integer.MAX_VALUE)); + } +} |