diff options
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 17 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 5 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_mips.cc | 5 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_mips64.cc | 5 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 7 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 10 | ||||
| -rw-r--r-- | runtime/utils.h | 12 | ||||
| -rwxr-xr-x | test/143-string-value/check | 2 | ||||
| -rw-r--r-- | test/561-divrem/expected.txt | 0 | ||||
| -rw-r--r-- | test/561-divrem/info.txt | 2 | ||||
| -rw-r--r-- | test/561-divrem/src/Main.java | 103 | ||||
| -rw-r--r-- | test/701-easy-div-rem/genMain.py | 10 | ||||
| -rw-r--r-- | test/Android.run-test.mk | 12 |
13 files changed, 158 insertions, 32 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 7b167e48f4..24f06a3a65 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -2906,8 +2906,7 @@ void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instructi Register dividend = locations->InAt(0).AsRegister<Register>(); Register temp = locations->GetTemp(0).AsRegister<Register>(); int32_t imm = second.GetConstant()->AsIntConstant()->GetValue(); - uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm)); - DCHECK(IsPowerOfTwo(abs_imm)); + uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm)); int ctz_imm = CTZ(abs_imm); if (ctz_imm == 1) { @@ -2983,7 +2982,7 @@ void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperatio // Do not generate anything. DivZeroCheck would prevent any code to be executed. } else if (imm == 1 || imm == -1) { DivRemOneOrMinusOne(instruction); - } else if (IsPowerOfTwo(std::abs(imm))) { + } else if (IsPowerOfTwo(AbsOrMin(imm))) { DivRemByPowerOfTwo(instruction); } else { DCHECK(imm <= -2 || imm >= 2); @@ -3012,12 +3011,12 @@ void LocationsBuilderARM::VisitDiv(HDiv* div) { locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant())); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); - int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue()); - if (abs_imm <= 1) { + int32_t value = div->InputAt(1)->AsIntConstant()->GetValue(); + if (value == 1 || value == 0 || value == -1) { // No temp register required. } else { locations->AddTemp(Location::RequiresRegister()); - if (!IsPowerOfTwo(abs_imm)) { + if (!IsPowerOfTwo(AbsOrMin(value))) { locations->AddTemp(Location::RequiresRegister()); } } @@ -3138,12 +3137,12 @@ void LocationsBuilderARM::VisitRem(HRem* rem) { locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant())); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); - int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue()); - if (abs_imm <= 1) { + int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue(); + if (value == 1 || value == 0 || value == -1) { // No temp register required. } else { locations->AddTemp(Location::RequiresRegister()); - if (!IsPowerOfTwo(abs_imm)) { + if (!IsPowerOfTwo(AbsOrMin(value))) { locations->AddTemp(Location::RequiresRegister()); } } diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index b3d0945991..1ad487d940 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -2534,8 +2534,7 @@ void InstructionCodeGeneratorARM64::DivRemByPowerOfTwo(HBinaryOperation* instruc Register out = OutputRegister(instruction); Register dividend = InputRegisterAt(instruction, 0); int64_t imm = Int64FromConstant(second.GetConstant()); - uint64_t abs_imm = static_cast<uint64_t>(std::abs(imm)); - DCHECK(IsPowerOfTwo(abs_imm)); + uint64_t abs_imm = static_cast<uint64_t>(AbsOrMin(imm)); int ctz_imm = CTZ(abs_imm); UseScratchRegisterScope temps(GetVIXLAssembler()); @@ -2627,7 +2626,7 @@ void InstructionCodeGeneratorARM64::GenerateDivRemIntegral(HBinaryOperation* ins // Do not generate anything. DivZeroCheck would prevent any code to be executed. } else if (imm == 1 || imm == -1) { DivRemOneOrMinusOne(instruction); - } else if (IsPowerOfTwo(std::abs(imm))) { + } else if (IsPowerOfTwo(AbsOrMin(imm))) { DivRemByPowerOfTwo(instruction); } else { DCHECK(imm <= -2 || imm >= 2); diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index ee14c6d140..7bc0635e75 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -2314,8 +2314,7 @@ void InstructionCodeGeneratorMIPS::DivRemByPowerOfTwo(HBinaryOperation* instruct Register out = locations->Out().AsRegister<Register>(); Register dividend = locations->InAt(0).AsRegister<Register>(); int32_t imm = second.GetConstant()->AsIntConstant()->GetValue(); - uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm)); - DCHECK(IsPowerOfTwo(abs_imm)); + uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm)); int ctz_imm = CTZ(abs_imm); if (instruction->IsDiv()) { @@ -2418,7 +2417,7 @@ void InstructionCodeGeneratorMIPS::GenerateDivRemIntegral(HBinaryOperation* inst // Do not generate anything. DivZeroCheck would prevent any code to be executed. } else if (imm == 1 || imm == -1) { DivRemOneOrMinusOne(instruction); - } else if (IsPowerOfTwo(std::abs(imm))) { + } else if (IsPowerOfTwo(AbsOrMin(imm))) { DivRemByPowerOfTwo(instruction); } else { DCHECK(imm <= -2 || imm >= 2); diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index e334100e1c..7682ca7800 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -1955,8 +1955,7 @@ void InstructionCodeGeneratorMIPS64::DivRemByPowerOfTwo(HBinaryOperation* instru GpuRegister out = locations->Out().AsRegister<GpuRegister>(); GpuRegister dividend = locations->InAt(0).AsRegister<GpuRegister>(); int64_t imm = Int64FromConstant(second.GetConstant()); - uint64_t abs_imm = static_cast<uint64_t>(std::abs(imm)); - DCHECK(IsPowerOfTwo(abs_imm)); + uint64_t abs_imm = static_cast<uint64_t>(AbsOrMin(imm)); int ctz_imm = CTZ(abs_imm); if (instruction->IsDiv()) { @@ -2138,7 +2137,7 @@ void InstructionCodeGeneratorMIPS64::GenerateDivRemIntegral(HBinaryOperation* in // Do not generate anything. DivZeroCheck would prevent any code to be executed. } else if (imm == 1 || imm == -1) { DivRemOneOrMinusOne(instruction); - } else if (IsPowerOfTwo(std::abs(imm))) { + } else if (IsPowerOfTwo(AbsOrMin(imm))) { DivRemByPowerOfTwo(instruction); } else { DCHECK(imm <= -2 || imm >= 2); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 8910249f20..4a0c2f47dc 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -3227,11 +3227,12 @@ void InstructionCodeGeneratorX86::DivByPowerOfTwo(HDiv* instruction) { Register out_register = locations->Out().AsRegister<Register>(); Register input_register = locations->InAt(0).AsRegister<Register>(); int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); + DCHECK(IsPowerOfTwo(AbsOrMin(imm))); + uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm)); - DCHECK(IsPowerOfTwo(std::abs(imm))); Register num = locations->GetTemp(0).AsRegister<Register>(); - __ leal(num, Address(input_register, std::abs(imm) - 1)); + __ leal(num, Address(input_register, abs_imm - 1)); __ testl(input_register, input_register); __ cmovl(kGreaterEqual, num, input_register); int shift = CTZ(imm); @@ -3344,7 +3345,7 @@ void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instr // Do not generate anything for 0. DivZeroCheck would forbid any generated code. } else if (imm == 1 || imm == -1) { DivRemOneOrMinusOne(instruction); - } else if (is_div && IsPowerOfTwo(std::abs(imm))) { + } else if (is_div && IsPowerOfTwo(AbsOrMin(imm))) { DivByPowerOfTwo(instruction->AsDiv()); } else { DCHECK(imm <= -2 || imm >= 2); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 126c83b17e..ec62d84b79 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -3354,13 +3354,13 @@ void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) { CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>(); int64_t imm = Int64FromConstant(second.GetConstant()); - - DCHECK(IsPowerOfTwo(std::abs(imm))); + DCHECK(IsPowerOfTwo(AbsOrMin(imm))); + uint64_t abs_imm = AbsOrMin(imm); CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>(); if (instruction->GetResultType() == Primitive::kPrimInt) { - __ leal(tmp, Address(numerator, std::abs(imm) - 1)); + __ leal(tmp, Address(numerator, abs_imm - 1)); __ testl(numerator, numerator); __ cmov(kGreaterEqual, tmp, numerator); int shift = CTZ(imm); @@ -3375,7 +3375,7 @@ void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) { DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); CpuRegister rdx = locations->GetTemp(0).AsRegister<CpuRegister>(); - codegen_->Load64BitValue(rdx, std::abs(imm) - 1); + codegen_->Load64BitValue(rdx, abs_imm - 1); __ addq(rdx, numerator); __ testq(numerator, numerator); __ cmov(kGreaterEqual, rdx, numerator); @@ -3533,7 +3533,7 @@ void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* in // Do not generate anything. DivZeroCheck would prevent any code to be executed. } else if (imm == 1 || imm == -1) { DivRemOneOrMinusOne(instruction); - } else if (instruction->IsDiv() && IsPowerOfTwo(std::abs(imm))) { + } else if (instruction->IsDiv() && IsPowerOfTwo(AbsOrMin(imm))) { DivByPowerOfTwo(instruction->AsDiv()); } else { DCHECK(imm <= -2 || imm >= 2); diff --git a/runtime/utils.h b/runtime/utils.h index 49406e20c9..153749eff4 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -99,6 +99,18 @@ static inline bool NeedsEscaping(uint16_t ch) { return (ch < ' ' || ch > '~'); } +template <typename T> T SafeAbs(T value) { + // std::abs has undefined behavior on min limits. + DCHECK_NE(value, std::numeric_limits<T>::min()); + return std::abs(value); +} + +template <typename T> T AbsOrMin(T value) { + return (value == std::numeric_limits<T>::min()) + ? value + : std::abs(value); +} + std::string PrintableChar(uint16_t ch); // Returns an ASCII string corresponding to the given UTF-8 string. diff --git a/test/143-string-value/check b/test/143-string-value/check index 865950026a..cdf7b783a3 100755 --- a/test/143-string-value/check +++ b/test/143-string-value/check @@ -15,6 +15,6 @@ # limitations under the License. # Strip run-specific numbers (pid and line number) -sed -e 's/^art E [0-9]\+ [0-9]\+ art\/runtime\/native\/java_lang_Class.cc:[0-9]\+\] //' "$2" > "$2.tmp" +sed -e 's/^art E[ ]\+[0-9]\+[ ]\+[0-9]\+ art\/runtime\/native\/java_lang_Class.cc:[0-9]\+\] //' "$2" > "$2.tmp" diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null diff --git a/test/561-divrem/expected.txt b/test/561-divrem/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/561-divrem/expected.txt diff --git a/test/561-divrem/info.txt b/test/561-divrem/info.txt new file mode 100644 index 0000000000..71c9601574 --- /dev/null +++ b/test/561-divrem/info.txt @@ -0,0 +1,2 @@ +Regression test for div/rem taking Integer.MIN_VALUE and +Long.MIN_VALUE. diff --git a/test/561-divrem/src/Main.java b/test/561-divrem/src/Main.java new file mode 100644 index 0000000000..082783df2d --- /dev/null +++ b/test/561-divrem/src/Main.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 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. + */ + +public class Main { + public static void assertEquals(int expected, int actual) { + if (expected != actual) { + throw new Error("Expected " + expected + ", got " + actual); + } + } + + public static void assertEquals(long expected, long actual) { + if (expected != actual) { + throw new Error("Expected " + expected + ", got " + actual); + } + } + + public static void main(String[] args) { + assertEquals(0, $noinline$divInt(1)); + assertEquals(1, $noinline$remInt(1)); + + assertEquals(0, $noinline$divInt(-1)); + assertEquals(-1, $noinline$remInt(-1)); + + assertEquals(0, $noinline$divInt(0)); + assertEquals(0, $noinline$remInt(0)); + + assertEquals(1, $noinline$divInt(Integer.MIN_VALUE)); + assertEquals(0, $noinline$remInt(Integer.MIN_VALUE)); + + assertEquals(0, $noinline$divInt(Integer.MAX_VALUE)); + assertEquals(Integer.MAX_VALUE, $noinline$remInt(Integer.MAX_VALUE)); + + assertEquals(0, $noinline$divInt(Integer.MAX_VALUE - 1)); + assertEquals(Integer.MAX_VALUE - 1, $noinline$remInt(Integer.MAX_VALUE - 1)); + + assertEquals(0, $noinline$divInt(Integer.MIN_VALUE + 1)); + assertEquals(Integer.MIN_VALUE + 1, $noinline$remInt(Integer.MIN_VALUE + 1)); + + assertEquals(0L, $noinline$divLong(1L)); + assertEquals(1L, $noinline$remLong(1L)); + + assertEquals(0L, $noinline$divLong(-1L)); + assertEquals(-1L, $noinline$remLong(-1L)); + + assertEquals(0L, $noinline$divLong(0L)); + assertEquals(0L, $noinline$remLong(0L)); + + assertEquals(1L, $noinline$divLong(Long.MIN_VALUE)); + assertEquals(0L, $noinline$remLong(Long.MIN_VALUE)); + + assertEquals(0L, $noinline$divLong(Long.MAX_VALUE)); + assertEquals(Long.MAX_VALUE, $noinline$remLong(Long.MAX_VALUE)); + + assertEquals(0L, $noinline$divLong(Long.MAX_VALUE - 1)); + assertEquals(Long.MAX_VALUE - 1, $noinline$remLong(Long.MAX_VALUE - 1)); + + assertEquals(0L, $noinline$divLong(Integer.MIN_VALUE + 1)); + assertEquals(Long.MIN_VALUE + 1, $noinline$remLong(Long.MIN_VALUE + 1)); + } + + public static int $noinline$divInt(int value) { + if (doThrow) { + throw new Error(""); + } + return value / Integer.MIN_VALUE; + } + + public static int $noinline$remInt(int value) { + if (doThrow) { + throw new Error(""); + } + return value % Integer.MIN_VALUE; + } + + public static long $noinline$divLong(long value) { + if (doThrow) { + throw new Error(""); + } + return value / Long.MIN_VALUE; + } + + public static long $noinline$remLong(long value) { + if (doThrow) { + throw new Error(""); + } + return value % Long.MIN_VALUE; + } + + static boolean doThrow = false; +} diff --git a/test/701-easy-div-rem/genMain.py b/test/701-easy-div-rem/genMain.py index 75eee17fe6..b6c769fd55 100644 --- a/test/701-easy-div-rem/genMain.py +++ b/test/701-easy-div-rem/genMain.py @@ -13,25 +13,27 @@ # limitations under the License. upper_bound_int_pow2 = 31 +upper_bound_int_pow2_neg = 32 upper_bound_long_pow2 = 63 +upper_bound_long_pow2_neg = 64 upper_bound_constant = 100 all_tests = [ ({'@INT@': 'int', '@SUFFIX@':''}, [('CheckDiv', 'idiv_by_pow2_', [2**i for i in range(upper_bound_int_pow2)]), - ('CheckDiv', 'idiv_by_pow2_neg_', [-2**i for i in range(upper_bound_int_pow2)]), + ('CheckDiv', 'idiv_by_pow2_neg_', [-2**i for i in range(upper_bound_int_pow2_neg)]), ('CheckDiv', 'idiv_by_constant_', [i for i in range(1, upper_bound_constant)]), ('CheckDiv', 'idiv_by_constant_neg_', [-i for i in range(1, upper_bound_constant)]), ('CheckRem', 'irem_by_pow2_', [2**i for i in range(upper_bound_int_pow2)]), - ('CheckRem', 'irem_by_pow2_neg_', [-2**i for i in range(upper_bound_int_pow2)]), + ('CheckRem', 'irem_by_pow2_neg_', [-2**i for i in range(upper_bound_int_pow2_neg)]), ('CheckRem', 'irem_by_constant_', [i for i in range(1, upper_bound_constant)]), ('CheckRem', 'irem_by_constant_neg_', [-i for i in range(1, upper_bound_constant)])]), ({'@INT@': 'long', '@SUFFIX@': 'l'}, [('CheckDiv', 'ldiv_by_pow2_', [2**i for i in range(upper_bound_long_pow2)]), - ('CheckDiv', 'ldiv_by_pow2_neg_', [-2**i for i in range(upper_bound_long_pow2)]), + ('CheckDiv', 'ldiv_by_pow2_neg_', [-2**i for i in range(upper_bound_long_pow2_neg)]), ('CheckDiv', 'ldiv_by_constant_', [i for i in range(1, upper_bound_constant)]), ('CheckDiv', 'ldiv_by_constant_neg_', [-i for i in range(1, upper_bound_constant)]), ('CheckRem', 'lrem_by_pow2_', [2**i for i in range(upper_bound_long_pow2)]), - ('CheckRem', 'lrem_by_pow2_neg_', [-2**i for i in range(upper_bound_long_pow2)]), + ('CheckRem', 'lrem_by_pow2_neg_', [-2**i for i in range(upper_bound_long_pow2_neg)]), ('CheckRem', 'lrem_by_constant_', [i for i in range(1, upper_bound_constant)]), ('CheckRem', 'lrem_by_constant_neg_', [-i for i in range(1, upper_bound_constant)])]) ] diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index 2c16ab8845..569a0214fc 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -273,10 +273,20 @@ TEST_ART_BROKEN_HOST_RUN_TESTS := \ ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,host,$(RUN_TYPES),$(PREBUILD_TYPES), \ $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \ - $(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_BROKEN_PREBUILD_RUN_TESTS), $(ALL_ADDRESS_SIZES)) + $(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_BROKEN_HOST_RUN_TESTS), $(ALL_ADDRESS_SIZES)) TEST_ART_BROKEN_HOST_RUN_TESTS := +# 143-string-value tests for a LOG(E) tag, which is only supported on host. +TEST_ART_BROKEN_TARGET_RUN_TESTS := \ + 143-string-value \ + +ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \ + $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \ + $(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_BROKEN_TARGET_RUN_TESTS), $(ALL_ADDRESS_SIZES)) + +TEST_ART_BROKEN_TARGET_RUN_TESTS := + # 554-jit-profile-file is disabled because it needs a primary oat file to know what it should save. TEST_ART_BROKEN_NO_PREBUILD_TESTS := \ 117-nopatchoat \ |