diff options
| author | 2017-09-19 18:27:40 +0000 | |
|---|---|---|
| committer | 2017-09-19 18:27:40 +0000 | |
| commit | 8048bf6d13dd4492df8d59ecb795987558e2e579 (patch) | |
| tree | 2b9b6398727a7e6f74c5c4a4debdf5c9a9f50167 | |
| parent | 486b1b3af37c4a830350689c2bfc969ab2b1b1d8 (diff) | |
| parent | 4f7dd346dee85939572d667e204f459c8100e626 (diff) | |
Merge "Recognize ABS cases."
| -rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 92 | ||||
| -rw-r--r-- | test/660-checker-sad-byte/expected.txt | 1 | ||||
| -rw-r--r-- | test/660-checker-sad-byte/info.txt | 1 | ||||
| -rw-r--r-- | test/660-checker-sad-byte/src/Main.java | 151 | ||||
| -rw-r--r-- | test/660-checker-sad-char/expected.txt | 1 | ||||
| -rw-r--r-- | test/660-checker-sad-char/info.txt | 1 | ||||
| -rw-r--r-- | test/660-checker-sad-char/src/Main.java | 165 | ||||
| -rw-r--r-- | test/660-checker-sad-int/expected.txt | 1 | ||||
| -rw-r--r-- | test/660-checker-sad-int/info.txt | 1 | ||||
| -rw-r--r-- | test/660-checker-sad-int/src/Main.java | 167 | ||||
| -rw-r--r-- | test/660-checker-sad-long/expected.txt | 1 | ||||
| -rw-r--r-- | test/660-checker-sad-long/info.txt | 1 | ||||
| -rw-r--r-- | test/660-checker-sad-long/src/Main.java | 111 | ||||
| -rw-r--r-- | test/660-checker-sad-short/expected.txt | 1 | ||||
| -rw-r--r-- | test/660-checker-sad-short/info.txt | 1 | ||||
| -rw-r--r-- | test/660-checker-sad-short/src/Main.java | 165 |
16 files changed, 861 insertions, 0 deletions
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index f2a829fa56..337177fa80 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -813,6 +813,57 @@ void InstructionSimplifierVisitor::VisitBooleanNot(HBooleanNot* bool_not) { } } +// Constructs a new ABS(x) node in the HIR. +static HInstruction* NewIntegralAbs(ArenaAllocator* arena, HInstruction* x, HInstruction* cursor) { + Primitive::Type type = x->GetType(); + DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong); + // Construct a fake intrinsic with as much context as is needed to allocate one. + // The intrinsic will always be lowered into code later anyway. + // TODO: b/65164101 : moving towards a real HAbs node makes more sense. + HInvokeStaticOrDirect::DispatchInfo dispatch_info = { + HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress, + HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod, + 0u + }; + HInvokeStaticOrDirect* invoke = new (arena) HInvokeStaticOrDirect( + arena, + 1, + type, + x->GetDexPc(), + /*method_idx*/ -1, + /*resolved_method*/ nullptr, + dispatch_info, + kStatic, + MethodReference(nullptr, dex::kDexNoIndex), + HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); + invoke->SetArgumentAt(0, x); + invoke->SetIntrinsic(type == Primitive::kPrimInt ? Intrinsics::kMathAbsInt + : Intrinsics::kMathAbsLong, + kNoEnvironmentOrCache, + kNoSideEffects, + kNoThrow); + cursor->GetBlock()->InsertInstructionBefore(invoke, cursor); + return invoke; +} + +// Returns true if operands a and b consists of widening type conversions +// (either explicit or implicit) to the given to_type. +static bool AreLowerPrecisionArgs(Primitive::Type to_type, HInstruction* a, HInstruction* b) { + if (a->IsTypeConversion() && a->GetType() == to_type) { + a = a->InputAt(0); + } + if (b->IsTypeConversion() && b->GetType() == to_type) { + b = b->InputAt(0); + } + Primitive::Type type1 = a->GetType(); + Primitive::Type type2 = b->GetType(); + return (type1 == Primitive::kPrimByte && type2 == Primitive::kPrimByte) || + (type1 == Primitive::kPrimShort && type2 == Primitive::kPrimShort) || + (type1 == Primitive::kPrimChar && type2 == Primitive::kPrimChar) || + (type1 == Primitive::kPrimInt && type2 == Primitive::kPrimInt && + to_type == Primitive::kPrimLong); +} + void InstructionSimplifierVisitor::VisitSelect(HSelect* select) { HInstruction* replace_with = nullptr; HInstruction* condition = select->GetCondition(); @@ -849,6 +900,47 @@ void InstructionSimplifierVisitor::VisitSelect(HSelect* select) { // Replace (cond ? false : true) with (!cond). replace_with = GetGraph()->InsertOppositeCondition(condition, select); } + } else if (condition->IsCondition()) { + IfCondition cmp = condition->AsCondition()->GetCondition(); + HInstruction* a = condition->InputAt(0); + HInstruction* b = condition->InputAt(1); + Primitive::Type t_type = true_value->GetType(); + Primitive::Type f_type = false_value->GetType(); + // Here we have a <cmp> b ? true_value : false_value. + // Test if both values are same-typed int or long. + if (t_type == f_type && (t_type == Primitive::kPrimInt || t_type == Primitive::kPrimLong)) { + // Try to replace typical integral ABS constructs. + if (true_value->IsNeg()) { + HInstruction* negated = true_value->InputAt(0); + if ((cmp == kCondLT || cmp == kCondLE) && + (a == negated && a == false_value && IsInt64Value(b, 0))) { + // Found a < 0 ? -a : a which can be replaced by ABS(a). + replace_with = NewIntegralAbs(GetGraph()->GetArena(), false_value, select); + } + } else if (false_value->IsNeg()) { + HInstruction* negated = false_value->InputAt(0); + if ((cmp == kCondGT || cmp == kCondGE) && + (a == true_value && a == negated && IsInt64Value(b, 0))) { + // Found a > 0 ? a : -a which can be replaced by ABS(a). + replace_with = NewIntegralAbs(GetGraph()->GetArena(), true_value, select); + } + } else if (true_value->IsSub() && false_value->IsSub()) { + HInstruction* true_sub1 = true_value->InputAt(0); + HInstruction* true_sub2 = true_value->InputAt(1); + HInstruction* false_sub1 = false_value->InputAt(0); + HInstruction* false_sub2 = false_value->InputAt(1); + if ((((cmp == kCondGT || cmp == kCondGE) && + (a == true_sub1 && b == true_sub2 && a == false_sub2 && b == false_sub1)) || + ((cmp == kCondLT || cmp == kCondLE) && + (a == true_sub2 && b == true_sub1 && a == false_sub1 && b == false_sub2))) && + AreLowerPrecisionArgs(t_type, a, b)) { + // Found a > b ? a - b : b - a or + // a < b ? b - a : a - b + // which can be replaced by ABS(a - b) for lower precision operands a, b. + replace_with = NewIntegralAbs(GetGraph()->GetArena(), true_value, select); + } + } + } } if (replace_with != nullptr) { diff --git a/test/660-checker-sad-byte/expected.txt b/test/660-checker-sad-byte/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/660-checker-sad-byte/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/660-checker-sad-byte/info.txt b/test/660-checker-sad-byte/info.txt new file mode 100644 index 0000000000..0c1cbdadae --- /dev/null +++ b/test/660-checker-sad-byte/info.txt @@ -0,0 +1 @@ +Functional tests on SAD scalar operations. diff --git a/test/660-checker-sad-byte/src/Main.java b/test/660-checker-sad-byte/src/Main.java new file mode 100644 index 0000000000..6bcd046bfc --- /dev/null +++ b/test/660-checker-sad-byte/src/Main.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2017 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. + */ + +/** + * Tests for SAD (sum of absolute differences). + */ +public class Main { + + /// CHECK-START: int Main.sad1(byte, byte) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad1(byte, byte) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad1(byte x, byte y) { + return x >= y ? x - y : y - x; + } + + /// CHECK-START: int Main.sad2(byte, byte) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad2(byte, byte) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad2(byte x, byte y) { + int diff = x - y; + if (diff < 0) diff = -diff; + return diff; + } + + /// CHECK-START: int Main.sad3(byte, byte) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad3(byte, byte) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad3(byte x, byte y) { + int diff = x - y; + return diff >= 0 ? diff : -diff; + } + + /// CHECK-START: int Main.sad3Alt(byte, byte) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad3Alt(byte, byte) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad3Alt(byte x, byte y) { + int diff = x - y; + return 0 <= diff ? diff : -diff; + } + + /// CHECK-START: long Main.sadL1(byte, byte) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL1(byte, byte) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL1(byte x, byte y) { + long xl = x; + long yl = y; + return xl >= yl ? xl - yl : yl - xl; + } + + /// CHECK-START: long Main.sadL2(byte, byte) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL2(byte, byte) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL2(byte x, byte y) { + long diff = x - y; + if (diff < 0L) diff = -diff; + return diff; + } + + /// CHECK-START: long Main.sadL3(byte, byte) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL3(byte, byte) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL3(byte x, byte y) { + long diff = x - y; + return diff >= 0L ? diff : -diff; + } + + /// CHECK-START: long Main.sadL3Alt(byte, byte) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL3Alt(byte, byte) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL3Alt(byte x, byte y) { + long diff = x - y; + return 0L <= diff ? diff : -diff; + } + + public static void main(String[] args) { + // Use cross-values to test all cases. + int n = 256; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + byte x = (byte) i; + byte y = (byte) j; + int e = Math.abs(x - y); + expectEquals(e, sad1(x, y)); + expectEquals(e, sad2(x, y)); + expectEquals(e, sad3(x, y)); + expectEquals(e, sad3Alt(x, y)); + expectEquals(e, sadL2(x, y)); + expectEquals(e, sadL3(x, y)); + expectEquals(e, sadL3Alt(x, y)); + } + } + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/660-checker-sad-char/expected.txt b/test/660-checker-sad-char/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/660-checker-sad-char/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/660-checker-sad-char/info.txt b/test/660-checker-sad-char/info.txt new file mode 100644 index 0000000000..0c1cbdadae --- /dev/null +++ b/test/660-checker-sad-char/info.txt @@ -0,0 +1 @@ +Functional tests on SAD scalar operations. diff --git a/test/660-checker-sad-char/src/Main.java b/test/660-checker-sad-char/src/Main.java new file mode 100644 index 0000000000..3033509cdf --- /dev/null +++ b/test/660-checker-sad-char/src/Main.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2017 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. + */ + +/** + * Tests for SAD (sum of absolute differences). + */ +public class Main { + + /// CHECK-START: int Main.sad1(char, char) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad1(char, char) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad1(char x, char y) { + return x >= y ? x - y : y - x; + } + + /// CHECK-START: int Main.sad2(char, char) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad2(char, char) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad2(char x, char y) { + int diff = x - y; + if (diff < 0) diff = -diff; + return diff; + } + + /// CHECK-START: int Main.sad3(char, char) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad3(char, char) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad3(char x, char y) { + int diff = x - y; + return diff >= 0 ? diff : -diff; + } + + /// CHECK-START: int Main.sad3Alt(char, char) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad3Alt(char, char) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad3Alt(char x, char y) { + int diff = x - y; + return 0 <= diff ? diff : -diff; + } + + /// CHECK-START: long Main.sadL1(char, char) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL1(char, char) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL1(char x, char y) { + long xl = x; + long yl = y; + return xl >= yl ? xl - yl : yl - xl; + } + + /// CHECK-START: long Main.sadL2(char, char) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL2(char, char) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL2(char x, char y) { + long diff = x - y; + if (diff < 0L) diff = -diff; + return diff; + } + + /// CHECK-START: long Main.sadL3(char, char) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL3(char, char) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL3(char x, char y) { + long diff = x - y; + return diff >= 0L ? diff : -diff; + } + + /// CHECK-START: long Main.sadL3Alt(char, char) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL3Alt(char, char) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL3Alt(char x, char y) { + long diff = x - y; + return 0L <= diff ? diff : -diff; + } + + public static void main(String[] args) { + // Use cross-values to test all cases. + char[] interesting = { + (char) 0x0000, (char) 0x0001, (char) 0x007f, + (char) 0x0080, (char) 0x0081, (char) 0x00ff, + (char) 0x0100, (char) 0x0101, (char) 0x017f, + (char) 0x0180, (char) 0x0181, (char) 0x01ff, + (char) 0x7f00, (char) 0x7f01, (char) 0x7f7f, + (char) 0x7f80, (char) 0x7f81, (char) 0x7fff, + (char) 0x8000, (char) 0x8001, (char) 0x807f, + (char) 0x8080, (char) 0x8081, (char) 0x80ff, + (char) 0x8100, (char) 0x8101, (char) 0x817f, + (char) 0x8180, (char) 0x8181, (char) 0x81ff, + (char) 0xff00, (char) 0xff01, (char) 0xff7f, + (char) 0xff80, (char) 0xff81, (char) 0xffff + }; + for (int i = 0; i < interesting.length; i++) { + for (int j = 0; j < interesting.length; j++) { + char x = interesting[i]; + char y = interesting[j]; + int e = Math.abs(x - y); + expectEquals(e, sad1(x, y)); + expectEquals(e, sad2(x, y)); + expectEquals(e, sad3(x, y)); + expectEquals(e, sad3Alt(x, y)); + expectEquals(e, sadL1(x, y)); + expectEquals(e, sadL2(x, y)); + expectEquals(e, sadL3(x, y)); + expectEquals(e, sadL3Alt(x, y)); + } + } + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/660-checker-sad-int/expected.txt b/test/660-checker-sad-int/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/660-checker-sad-int/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/660-checker-sad-int/info.txt b/test/660-checker-sad-int/info.txt new file mode 100644 index 0000000000..0c1cbdadae --- /dev/null +++ b/test/660-checker-sad-int/info.txt @@ -0,0 +1 @@ +Functional tests on SAD scalar operations. diff --git a/test/660-checker-sad-int/src/Main.java b/test/660-checker-sad-int/src/Main.java new file mode 100644 index 0000000000..42ecea68da --- /dev/null +++ b/test/660-checker-sad-int/src/Main.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2017 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. + */ + +/** + * Tests for SAD (sum of absolute differences). + */ +public class Main { + + /// CHECK-START: int Main.sad1(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad1(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad1(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-NOT: InvokeStaticOrDirect intrinsic:MathAbsInt + // + // NOTE: for direct 32-bit operands, this is not an ABS. + static int sad1(int x, int y) { + return x >= y ? x - y : y - x; + } + + /// CHECK-START: int Main.sad2(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad2(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad2(int x, int y) { + int diff = x - y; + if (diff < 0) diff = -diff; + return diff; + } + + /// CHECK-START: int Main.sad3(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad3(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad3(int x, int y) { + int diff = x - y; + return diff >= 0 ? diff : -diff; + } + + /// CHECK-START: int Main.sad3Alt(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad3Alt(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad3Alt(int x, int y) { + int diff = x - y; + return 0 <= diff ? diff : -diff; + } + + /// CHECK-START: long Main.sadL1(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL1(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL1(int x, int y) { + long xl = x; + long yl = y; + return xl >= yl ? xl - yl : yl - xl; + } + + /// CHECK-START: long Main.sadL2(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL2(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL2(int x, int y) { + long diff = x - y; + if (diff < 0L) diff = -diff; + return diff; + } + + /// CHECK-START: long Main.sadL3(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL3(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL3(int x, int y) { + long diff = x - y; + return diff >= 0L ? diff : -diff; + } + + /// CHECK-START: long Main.sadL3Alt(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL3Alt(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL3Alt(int x, int y) { + long diff = x - y; + return 0L <= diff ? diff : -diff; + } + + public static void main(String[] args) { + // Use cross-values for the interesting values. + int[] interesting = { + 0x00000000, 0x00000001, 0x00007fff, 0x00008000, 0x00008001, 0x0000ffff, + 0x00010000, 0x00010001, 0x00017fff, 0x00018000, 0x00018001, 0x0001ffff, + 0x7fff0000, 0x7fff0001, 0x7fff7fff, 0x7fff8000, 0x7fff8001, 0x7fffffff, + 0x80000000, 0x80000001, 0x80007fff, 0x80008000, 0x80008001, 0x8000ffff, + 0x80010000, 0x80010001, 0x80017fff, 0x80018000, 0x80018001, 0x8001ffff, + 0xffff0000, 0xffff0001, 0xffff7fff, 0xffff8000, 0xffff8001, 0xffffffff + }; + for (int i = 0; i < interesting.length; i++) { + for (int j = 0; j < interesting.length; j++) { + int x = interesting[i]; + int y = interesting[j]; + int e1 = x >= y ? x - y : y - x; // still select + expectEquals(e1, sad1(x, y)); + int e2 = Math.abs(x - y); // pure abs + expectEquals(e2, sad2(x, y)); + expectEquals(e2, sad3(x, y)); + expectEquals(e2, sad3Alt(x, y)); + long eL1 = Math.abs(((long)x) - ((long)y)); // now, different, but abs + expectEquals(eL1, sadL1(x, y)); + long eL2 = Math.abs((long)(x - y)); // also, different, but abs + expectEquals(eL2, sadL2(x, y)); + expectEquals(eL2, sadL3(x, y)); + expectEquals(eL2, sadL3Alt(x, y)); + } + } + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/660-checker-sad-long/expected.txt b/test/660-checker-sad-long/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/660-checker-sad-long/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/660-checker-sad-long/info.txt b/test/660-checker-sad-long/info.txt new file mode 100644 index 0000000000..0c1cbdadae --- /dev/null +++ b/test/660-checker-sad-long/info.txt @@ -0,0 +1 @@ +Functional tests on SAD scalar operations. diff --git a/test/660-checker-sad-long/src/Main.java b/test/660-checker-sad-long/src/Main.java new file mode 100644 index 0000000000..d2e32acffc --- /dev/null +++ b/test/660-checker-sad-long/src/Main.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2017 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. + */ + +/** + * Tests for SAD (sum of absolute differences). + */ +public class Main { + + /// CHECK-START: long Main.sad1(long, long) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sad1(long, long) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sad1(long, long) instruction_simplifier$after_inlining (after) + /// CHECK-NOT: InvokeStaticOrDirect intrinsic:MathAbsLong + // + // NOTE: for direct 64-bit operands, this is not an ABS. + static long sad1(long x, long y) { + return x >= y ? x - y : y - x; + } + + /// CHECK-START: long Main.sad2(long, long) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sad2(long, long) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sad2(long x, long y) { + long diff = x - y; + if (diff < 0) diff = -diff; + return diff; + } + + /// CHECK-START: long Main.sad3(long, long) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sad3(long, long) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sad3(long x, long y) { + long diff = x - y; + return diff >= 0 ? diff : -diff; + } + + /// CHECK-START: long Main.sad3Alt(long, long) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sad3Alt(long, long) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sad3Alt(long x, long y) { + long diff = x - y; + return 0 <= diff ? diff : -diff; + } + + public static void main(String[] args) { + // Use cross-values for the interesting values. + long[] interesting = { + 0x0000000000000000L, 0x0000000000000001L, 0x000000007fffffffL, + 0x0000000080000000L, 0x0000000080000001L, 0x00000000ffffffffL, + 0x0000000100000000L, 0x0000000100000001L, 0x000000017fffffffL, + 0x0000000180000000L, 0x0000000180000001L, 0x00000001ffffffffL, + 0x7fffffff00000000L, 0x7fffffff00000001L, 0x7fffffff7fffffffL, + 0x7fffffff80000000L, 0x7fffffff80000001L, 0x7fffffffffffffffL, + 0x8000000000000000L, 0x8000000000000001L, 0x800000007fffffffL, + 0x8000000080000000L, 0x8000000080000001L, 0x80000000ffffffffL, + 0x8000000100000000L, 0x8000000100000001L, 0x800000017fffffffL, + 0x8000000180000000L, 0x8000000180000001L, 0x80000001ffffffffL, + 0xffffffff00000000L, 0xffffffff00000001L, 0xffffffff7fffffffL, + 0xffffffff80000000L, 0xffffffff80000001L, 0xffffffffffffffffL + }; + for (int i = 0; i < interesting.length; i++) { + for (int j = 0; j < interesting.length; j++) { + long x = interesting[i]; + long y = interesting[j]; + long e1 = x >= y ? x - y : y - x; // still select + expectEquals(e1, sad1(x, y)); + long e2 = Math.abs(x - y); // pure abs + expectEquals(e2, sad2(x, y)); + expectEquals(e2, sad3(x, y)); + expectEquals(e2, sad3Alt(x, y)); + } + } + System.out.println("passed"); + } + + private static void expectEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/660-checker-sad-short/expected.txt b/test/660-checker-sad-short/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/660-checker-sad-short/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/660-checker-sad-short/info.txt b/test/660-checker-sad-short/info.txt new file mode 100644 index 0000000000..0c1cbdadae --- /dev/null +++ b/test/660-checker-sad-short/info.txt @@ -0,0 +1 @@ +Functional tests on SAD scalar operations. diff --git a/test/660-checker-sad-short/src/Main.java b/test/660-checker-sad-short/src/Main.java new file mode 100644 index 0000000000..182fe8a029 --- /dev/null +++ b/test/660-checker-sad-short/src/Main.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2017 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. + */ + +/** + * Tests for SAD (sum of absolute differences). + */ +public class Main { + + /// CHECK-START: int Main.sad1(short, short) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad1(short, short) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad1(short x, short y) { + return x >= y ? x - y : y - x; + } + + /// CHECK-START: int Main.sad2(short, short) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad2(short, short) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad2(short x, short y) { + int diff = x - y; + if (diff < 0) diff = -diff; + return diff; + } + + /// CHECK-START: int Main.sad3(short, short) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad3(short, short) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad3(short x, short y) { + int diff = x - y; + return diff >= 0 ? diff : -diff; + } + + /// CHECK-START: int Main.sad3Alt(short, short) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:i\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: int Main.sad3Alt(short, short) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect intrinsic:MathAbsInt + /// CHECK-DAG: Return [<<Intrin>>] + static int sad3Alt(short x, short y) { + int diff = x - y; + return 0 <= diff ? diff : -diff; + } + + /// CHECK-START: long Main.sadL1(short, short) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL1(short, short) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL1(short x, short y) { + long xl = x; + long yl = y; + return xl >= yl ? xl - yl : yl - xl; + } + + /// CHECK-START: long Main.sadL2(short, short) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL2(short, short) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL2(short x, short y) { + long diff = x - y; + if (diff < 0L) diff = -diff; + return diff; + } + + /// CHECK-START: long Main.sadL3(short, short) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL3(short, short) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL3(short x, short y) { + long diff = x - y; + return diff >= 0L ? diff : -diff; + } + + /// CHECK-START: long Main.sadL3Alt(short, short) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Select:j\d+>> Select + /// CHECK-DAG: Return [<<Select>>] + // + /// CHECK-START: long Main.sadL3Alt(short, short) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Intrin:j\d+>> InvokeStaticOrDirect intrinsic:MathAbsLong + /// CHECK-DAG: Return [<<Intrin>>] + static long sadL3Alt(short x, short y) { + long diff = x - y; + return 0L <= diff ? diff : -diff; + } + + public static void main(String[] args) { + // Use cross-values to test all cases. + short[] interesting = { + (short) 0x0000, (short) 0x0001, (short) 0x007f, + (short) 0x0080, (short) 0x0081, (short) 0x00ff, + (short) 0x0100, (short) 0x0101, (short) 0x017f, + (short) 0x0180, (short) 0x0181, (short) 0x01ff, + (short) 0x7f00, (short) 0x7f01, (short) 0x7f7f, + (short) 0x7f80, (short) 0x7f81, (short) 0x7fff, + (short) 0x8000, (short) 0x8001, (short) 0x807f, + (short) 0x8080, (short) 0x8081, (short) 0x80ff, + (short) 0x8100, (short) 0x8101, (short) 0x817f, + (short) 0x8180, (short) 0x8181, (short) 0x81ff, + (short) 0xff00, (short) 0xff01, (short) 0xff7f, + (short) 0xff80, (short) 0xff81, (short) 0xffff + }; + for (int i = 0; i < interesting.length; i++) { + for (int j = 0; j < interesting.length; j++) { + short x = interesting[i]; + short y = interesting[j]; + int e = Math.abs(x - y); + expectEquals(e, sad1(x, y)); + expectEquals(e, sad2(x, y)); + expectEquals(e, sad3(x, y)); + expectEquals(e, sad3Alt(x, y)); + expectEquals(e, sadL1(x, y)); + expectEquals(e, sadL2(x, y)); + expectEquals(e, sadL3(x, y)); + expectEquals(e, sadL3Alt(x, y)); + } + } + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} |