Run GVN earlier.
Rationale:
Running GVN earlier allows for better subsequent
instruction simplifation. For example, running GVN
before select generation also finds the MIN in:
if (x > a[i])
x = a[i];
Bug: b/74026074
Test: test-art-host,target
Change-Id: I633046375637c7809a3603fdf7c5cf77e8f21167
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index c0c721d..1462404 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -1353,6 +1353,11 @@
HInstruction* index = instruction->InputAt(1);
HInstruction* value = instruction->InputAt(2);
HInstruction* offset = nullptr;
+ // For narrow types, explicit type conversion may have been
+ // optimized way, so set the no hi bits restriction here.
+ if (DataType::Size(type) <= 2) {
+ restrictions |= kNoHiBits;
+ }
if (TrySetVectorType(type, &restrictions) &&
node->loop_info->IsDefinedOutOfTheLoop(base) &&
induction_range_.IsUnitStride(instruction, index, graph_, &offset) &&
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 7916582..cadefc3 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -643,15 +643,13 @@
MaybeRunInliner(graph, codegen, dex_compilation_unit, pass_observer, handles);
OptimizationDef optimizations2[] = {
- // SelectGenerator depends on the InstructionSimplifier removing
- // redundant suspend checks to recognize empty blocks.
+ OptDef(OptimizationPass::kSideEffectsAnalysis, "side_effects$before_gvn"),
+ OptDef(OptimizationPass::kGlobalValueNumbering),
OptDef(OptimizationPass::kSelectGenerator),
- // TODO: if we don't inline we can also skip fold2.
OptDef(OptimizationPass::kConstantFolding, "constant_folding$after_inlining"),
OptDef(OptimizationPass::kInstructionSimplifier, "instruction_simplifier$after_inlining"),
OptDef(OptimizationPass::kDeadCodeElimination, "dead_code_elimination$after_inlining"),
- OptDef(OptimizationPass::kSideEffectsAnalysis, "side_effects$before_gvn"),
- OptDef(OptimizationPass::kGlobalValueNumbering),
+ OptDef(OptimizationPass::kSideEffectsAnalysis, "side_effects$before_licm"),
OptDef(OptimizationPass::kInvariantCodeMotion),
OptDef(OptimizationPass::kInductionVarAnalysis),
OptDef(OptimizationPass::kBoundsCheckElimination),
diff --git a/compiler/optimizing/select_generator.cc b/compiler/optimizing/select_generator.cc
index 3f52bdd..f9acf5a 100644
--- a/compiler/optimizing/select_generator.cc
+++ b/compiler/optimizing/select_generator.cc
@@ -16,6 +16,7 @@
#include "select_generator.h"
+#include "base/scoped_arena_containers.h"
#include "reference_type_propagation.h"
namespace art {
@@ -90,9 +91,13 @@
}
void HSelectGenerator::Run() {
+ // Select cache with local allocator.
+ ScopedArenaAllocator allocator(graph_->GetArenaStack());
+ ScopedArenaSafeMap<HInstruction*, HSelect*> cache(
+ std::less<HInstruction*>(), allocator.Adapter(kArenaAllocSelectGenerator));
+
// Iterate in post order in the unlikely case that removing one occurrence of
// the selection pattern empties a branch block of another occurrence.
- // Otherwise the order does not matter.
for (HBasicBlock* block : graph_->GetPostOrder()) {
if (!block->EndsWithIf()) continue;
@@ -143,7 +148,8 @@
DCHECK(both_successors_return || phi != nullptr);
// Create the Select instruction and insert it in front of the If.
- HSelect* select = new (graph_->GetAllocator()) HSelect(if_instruction->InputAt(0),
+ HInstruction* condition = if_instruction->InputAt(0);
+ HSelect* select = new (graph_->GetAllocator()) HSelect(condition,
true_value,
false_value,
if_instruction->GetDexPc());
@@ -180,6 +186,26 @@
MaybeRecordStat(stats_, MethodCompilationStat::kSelectGenerated);
+ // Very simple way of finding common subexpressions in the generated HSelect statements
+ // (since this runs after GVN). Lookup by condition, and reuse latest one if possible
+ // (due to post order, latest select is most likely replacement). If needed, we could
+ // improve this by e.g. using the operands in the map as well.
+ auto it = cache.find(condition);
+ if (it == cache.end()) {
+ cache.Put(condition, select);
+ } else {
+ // Found cached value. See if latest can replace cached in the HIR.
+ HSelect* cached = it->second;
+ DCHECK_EQ(cached->GetCondition(), select->GetCondition());
+ if (cached->GetTrueValue() == select->GetTrueValue() &&
+ cached->GetFalseValue() == select->GetFalseValue() &&
+ select->StrictlyDominates(cached)) {
+ cached->ReplaceWith(select);
+ cached->GetBlock()->RemoveInstruction(cached);
+ }
+ it->second = select; // always cache latest
+ }
+
// No need to update dominance information, as we are simplifying
// a simple diamond shape, where the join block is merged with the
// entry block. Any following blocks would have had the join block
diff --git a/libartbase/base/arena_allocator.cc b/libartbase/base/arena_allocator.cc
index 348a812..183e5c9 100644
--- a/libartbase/base/arena_allocator.cc
+++ b/libartbase/base/arena_allocator.cc
@@ -77,6 +77,7 @@
"SsaLiveness ",
"SsaPhiElim ",
"RefTypeProp ",
+ "SelectGen ",
"SideEffects ",
"RegAllocator ",
"RegAllocVldt ",
diff --git a/libartbase/base/arena_allocator.h b/libartbase/base/arena_allocator.h
index 3143fba..4d535df 100644
--- a/libartbase/base/arena_allocator.h
+++ b/libartbase/base/arena_allocator.h
@@ -87,6 +87,7 @@
kArenaAllocSsaLiveness,
kArenaAllocSsaPhiElimination,
kArenaAllocReferenceTypePropagation,
+ kArenaAllocSelectGenerator,
kArenaAllocSideEffectsAnalysis,
kArenaAllocRegisterAllocator,
kArenaAllocRegisterAllocatorValidate,
diff --git a/test/458-checker-instruct-simplification/src/Main.java b/test/458-checker-instruct-simplification/src/Main.java
index 7797f31..444b455 100644
--- a/test/458-checker-instruct-simplification/src/Main.java
+++ b/test/458-checker-instruct-simplification/src/Main.java
@@ -2572,7 +2572,7 @@
/// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
/// CHECK-DAG: <<Const255:i\d+>> IntConstant 255
/// CHECK-DAG: <<Select:i\d+>> Select [<<Const0>>,<<Const1>>,<<Arg>>]
- /// CHECK-DAG: <<And:i\d+>> And [<<Const255>>,<<Select>>]
+ /// CHECK-DAG: <<And:i\d+>> And [<<Select>>,<<Const255>>]
/// CHECK-DAG: <<Conv:b\d+>> TypeConversion [<<And>>]
/// CHECK-DAG: Return [<<Conv>>]
diff --git a/test/551-checker-shifter-operand/src/Main.java b/test/551-checker-shifter-operand/src/Main.java
index 3177ec0..fb76904 100644
--- a/test/551-checker-shifter-operand/src/Main.java
+++ b/test/551-checker-shifter-operand/src/Main.java
@@ -728,40 +728,9 @@
/// CHECK: UShr
/// CHECK-NOT: UShr
//
- // Note: simplification followed by GVN exposes the common subexpressions between shifts with larger distance
- // `b << 62`, `b << 63` etc. and the equivalent smaller distances.
- //
- /// CHECK-START: void Main.$opt$validateShiftInt(int, int) GVN (after)
- /// CHECK: Shl
- /// CHECK: Shl
- /// CHECK: Shl
- /// CHECK: Shl
- /// CHECK: Shl
- /// CHECK: Shl
- /// CHECK: Shl
- /// CHECK: Shl
- /// CHECK: Shl
- /// CHECK-NOT: Shl
- /// CHECK: Shr
- /// CHECK: Shr
- /// CHECK: Shr
- /// CHECK: Shr
- /// CHECK: Shr
- /// CHECK: Shr
- /// CHECK: Shr
- /// CHECK: Shr
- /// CHECK: Shr
- /// CHECK-NOT: Shl
- /// CHECK: UShr
- /// CHECK: UShr
- /// CHECK: UShr
- /// CHECK: UShr
- /// CHECK: UShr
- /// CHECK: UShr
- /// CHECK: UShr
- /// CHECK: UShr
- /// CHECK: UShr
- /// CHECK-NOT: UShr
+ // Note: running extra simplification before GVN would expose the common subexpressions between
+ // shifts with larger distance `b << 62`, `b << 63` etc. and the equivalent smaller distances.
+ // TODO: b/78171933
//
/// CHECK-START-ARM: void Main.$opt$validateShiftInt(int, int) instruction_simplifier_arm (after)
/// CHECK: DataProcWithShifterOp
@@ -791,6 +760,12 @@
/// CHECK: DataProcWithShifterOp
/// CHECK: DataProcWithShifterOp
/// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
/// CHECK-NOT: DataProcWithShifterOp
/// CHECK-START-ARM: void Main.$opt$validateShiftInt(int, int) instruction_simplifier_arm (after)
@@ -826,6 +801,12 @@
/// CHECK: DataProcWithShifterOp
/// CHECK: DataProcWithShifterOp
/// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
/// CHECK-NOT: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$validateShiftInt(int, int) instruction_simplifier_arm64 (after)
diff --git a/test/565-checker-doublenegbitwise/src/Main.java b/test/565-checker-doublenegbitwise/src/Main.java
index 816cafc..80358cd 100644
--- a/test/565-checker-doublenegbitwise/src/Main.java
+++ b/test/565-checker-doublenegbitwise/src/Main.java
@@ -101,13 +101,13 @@
/// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
/// CHECK-DAG: <<Select1:i\d+>> Select [<<Const1>>,<<Const0>>,<<P1>>]
/// CHECK-DAG: <<Select2:i\d+>> Select [<<Const1>>,<<Const0>>,<<P2>>]
- /// CHECK-DAG: <<And:i\d+>> And [<<Select2>>,<<Select1>>]
+ /// CHECK-DAG: <<And:i\d+>> And [<<Select1>>,<<Select2>>]
/// CHECK-DAG: Return [<<And>>]
/// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier$after_inlining (after)
/// CHECK-DAG: <<Cond1:z\d+>> ParameterValue
/// CHECK-DAG: <<Cond2:z\d+>> ParameterValue
- /// CHECK-DAG: <<Or:i\d+>> Or [<<Cond2>>,<<Cond1>>]
+ /// CHECK-DAG: <<Or:i\d+>> Or [<<Cond1>>,<<Cond2>>]
/// CHECK-DAG: <<BooleanNot:z\d+>> BooleanNot [<<Or>>]
/// CHECK-DAG: Return [<<BooleanNot>>]
@@ -172,13 +172,13 @@
/// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
/// CHECK-DAG: <<Select1:i\d+>> Select [<<Const1>>,<<Const0>>,<<P1>>]
/// CHECK-DAG: <<Select2:i\d+>> Select [<<Const1>>,<<Const0>>,<<P2>>]
- /// CHECK-DAG: <<Or:i\d+>> Or [<<Select2>>,<<Select1>>]
+ /// CHECK-DAG: <<Or:i\d+>> Or [<<Select1>>,<<Select2>>]
/// CHECK-DAG: Return [<<Or>>]
/// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier$after_inlining (after)
/// CHECK-DAG: <<Cond1:z\d+>> ParameterValue
/// CHECK-DAG: <<Cond2:z\d+>> ParameterValue
- /// CHECK-DAG: <<And:i\d+>> And [<<Cond2>>,<<Cond1>>]
+ /// CHECK-DAG: <<And:i\d+>> And [<<Cond1>>,<<Cond2>>]
/// CHECK-DAG: <<BooleanNot:z\d+>> BooleanNot [<<And>>]
/// CHECK-DAG: Return [<<BooleanNot>>]
@@ -282,13 +282,13 @@
/// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
/// CHECK-DAG: <<Select1:i\d+>> Select [<<Const1>>,<<Const0>>,<<P1>>]
/// CHECK-DAG: <<Select2:i\d+>> Select [<<Const1>>,<<Const0>>,<<P2>>]
- /// CHECK-DAG: <<Xor:i\d+>> Xor [<<Select2>>,<<Select1>>]
+ /// CHECK-DAG: <<Xor:i\d+>> Xor [<<Select1>>,<<Select2>>]
/// CHECK-DAG: Return [<<Xor>>]
/// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier$after_inlining (after)
/// CHECK-DAG: <<Cond1:z\d+>> ParameterValue
/// CHECK-DAG: <<Cond2:z\d+>> ParameterValue
- /// CHECK-DAG: <<Xor:i\d+>> Xor [<<Cond2>>,<<Cond1>>]
+ /// CHECK-DAG: <<Xor:i\d+>> Xor [<<Cond1>>,<<Cond2>>]
/// CHECK-DAG: Return [<<Xor>>]
/// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier$after_bce (after)
diff --git a/test/651-checker-simd-minmax/src/ByteSimdMinMax.java b/test/651-checker-simd-minmax/src/ByteSimdMinMax.java
index 8dacd5d..fff15fa 100644
--- a/test/651-checker-simd-minmax/src/ByteSimdMinMax.java
+++ b/test/651-checker-simd-minmax/src/ByteSimdMinMax.java
@@ -174,6 +174,30 @@
}
}
+ /// CHECK-START-{ARM,ARM64}: void ByteSimdMinMax.doitMinAlt(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
+ private static void doitMinAlt(byte[] x, byte[] y, byte[] z) {
+ int n = Math.min(x.length, Math.min(y.length, z.length));
+ for (int i = 0; i < n; ++i) {
+ x[i] = y[i] < z[i] ? y[i] : z[i];
+ }
+ }
+
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void ByteSimdMinMax.doitMaxAlt(byte[], byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
+ private static void doitMaxAlt(byte[] x, byte[] y, byte[] z) {
+ int n = Math.min(x.length, Math.min(y.length, z.length));
+ for (int i = 0; i < n; ++i) {
+ x[i] = y[i] > z[i] ? y[i] : z[i];
+ }
+ }
+
public static void main() {
// Initialize cross-values for all possible values.
int total = 256 * 256;
@@ -228,7 +252,16 @@
byte expected = (byte) (u < 11 ? 11 : (u > 23 ? 23 : u));
expectEquals(expected, x[i]);
}
-
+ doitMinAlt(x, y, z);
+ for (int i = 0; i < total; i++) {
+ byte expected = (byte) Math.min(y[i], z[i]);
+ expectEquals(expected, x[i]);
+ }
+ doitMaxAlt(x, y, z);
+ for (int i = 0; i < total; i++) {
+ byte expected = (byte) Math.max(y[i], z[i]);
+ expectEquals(expected, x[i]);
+ }
System.out.println("ByteSimdMinMax passed");
}
diff --git a/test/651-checker-simd-minmax/src/IntSimdMinMax.java b/test/651-checker-simd-minmax/src/IntSimdMinMax.java
index 6373ae1..ad88843 100644
--- a/test/651-checker-simd-minmax/src/IntSimdMinMax.java
+++ b/test/651-checker-simd-minmax/src/IntSimdMinMax.java
@@ -57,6 +57,38 @@
}
}
+ /// CHECK-START-{ARM,ARM64}: int IntSimdMinMax.findMin(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar loop:none
+ /// CHECK-DAG: <<VPhi:d\d+>> Phi [<<Rep>>,<<Max:d\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad [{{l\d+}},{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Max>> VecMin [<<Get>>,<<VPhi>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<VPhi>>] loop:none
+ /// CHECK-DAG: VecExtractScalar [<<Red>>] loop:none
+ private static int findMin(int[] a) {
+ int x = Integer.MAX_VALUE;
+ for (int i = 0; i < a.length; i++) {
+ if (a[i] < x)
+ x = a[i];
+ }
+ return x;
+ }
+
+ /// CHECK-START-{ARM,ARM64}: int IntSimdMinMax.findMax(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar loop:none
+ /// CHECK-DAG: <<VPhi:d\d+>> Phi [<<Rep>>,<<Max:d\d+>>] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad [{{l\d+}},{{i\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Max>> VecMax [<<Get>>,<<VPhi>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Red:d\d+>> VecReduce [<<VPhi>>] loop:none
+ /// CHECK-DAG: VecExtractScalar [<<Red>>] loop:none
+ private static int findMax(int[] a) {
+ int x = Integer.MIN_VALUE;
+ for (int i = 0; i < a.length; i++) {
+ if (a[i] > x)
+ x = a[i];
+ }
+ return x;
+ }
+
public static void main() {
int[] interesting = {
0x00000000, 0x00000001, 0x00007fff, 0x00008000, 0x00008001, 0x0000ffff,
@@ -92,6 +124,12 @@
int expected = Math.max(y[i], z[i]);
expectEquals(expected, x[i]);
}
+ expectEquals(Integer.MIN_VALUE, findMin(x));
+ expectEquals(Integer.MAX_VALUE, findMax(x));
+ expectEquals(Integer.MIN_VALUE, findMin(y));
+ expectEquals(Integer.MAX_VALUE, findMax(y));
+ expectEquals(Integer.MIN_VALUE, findMin(z));
+ expectEquals(Integer.MAX_VALUE, findMax(z));
System.out.println("IntSimdMinMax passed");
}
diff --git a/test/679-checker-minmax/src/Main.java b/test/679-checker-minmax/src/Main.java
index e330a53..48de1da 100644
--- a/test/679-checker-minmax/src/Main.java
+++ b/test/679-checker-minmax/src/Main.java
@@ -309,19 +309,42 @@
return a >= b ? a : b;
}
-
//
// Complications.
//
- // TODO: coming soon, under discussion
+ /// CHECK-START: int Main.min0(int[], int[]) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Ar1:i\d+>> ArrayGet [{{l\d+}},{{i\d+}}]
+ /// CHECK-DAG: <<Ar2:i\d+>> ArrayGet [{{l\d+}},{{i\d+}}]
+ /// CHECK-DAG: <<Cnd:z\d+>> GreaterThan [<<Ar1>>,<<Ar2>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Ar1>>,<<Ar2>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.min0(int[], int[]) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Min:i\d+>> Min
+ /// CHECK-DAG: Return [<<Min>>]
+ //
+ /// CHECK-START: int Main.min0(int[], int[]) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
public static int min0(int[] a, int[] b) {
// Repeat of array references needs finding the common subexpressions
// prior to doing the select and min/max recognition.
return a[0] <= b[0] ? a[0] : b[0];
}
- // TODO: coming soon, under discussion
+ /// CHECK-START: int Main.max0(int[], int[]) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Ar1:i\d+>> ArrayGet [{{l\d+}},{{i\d+}}]
+ /// CHECK-DAG: <<Ar2:i\d+>> ArrayGet [{{l\d+}},{{i\d+}}]
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Ar1>>,<<Ar2>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Ar1>>,<<Ar2>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.max0(int[], int[]) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Max:i\d+>> Max
+ /// CHECK-DAG: Return [<<Max>>]
+ //
+ /// CHECK-START: int Main.max0(int[], int[]) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
public static int max0(int[] a, int[] b) {
// Repeat of array references needs finding the common subexpressions
// prior to doing the select and min/max recognition.
@@ -417,8 +440,102 @@
return (x < -100) ? -100 : ((x > 100) ? 100 : x);
}
+ /// CHECK-START: int Main.minmaxCSEScalar(int, int) select_generator (after)
+ /// CHECK-DAG: <<Par1:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Par2:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Cnd1:z\d+>> LessThanOrEqual [<<Par1>>,<<Par2>>]
+ /// CHECK-DAG: <<Sel1:i\d+>> Select [<<Par1>>,<<Par2>>,<<Cnd1>>]
+ /// CHECK-DAG: <<Cnd2:z\d+>> GreaterThanOrEqual [<<Par1>>,<<Par2>>]
+ /// CHECK-DAG: <<Sel2:i\d+>> Select [<<Par1>>,<<Par2>>,<<Cnd2>>]
+ /// CHECK-DAG: <<Add1:i\d+>> Add [<<Sel1>>,<<Sel2>>]
+ /// CHECK-DAG: <<Add2:i\d+>> Add [<<Sel1>>,<<Add1>>]
+ /// CHECK-DAG: <<Add3:i\d+>> Add [<<Sel2>>,<<Add2>>]
+ /// CHECK-DAG: <<Add4:i\d+>> Add [<<Sel1>>,<<Add3>>]
+ /// CHECK-DAG: <<Add5:i\d+>> Add [<<Sel2>>,<<Add4>>]
+ /// CHECK-DAG: Return [<<Add5>>]
+ //
+ /// CHECK-START: int Main.minmaxCSEScalar(int, int) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par1:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Par2:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Max:i\d+>> Max [<<Par1>>,<<Par2>>]
+ /// CHECK-DAG: <<Min:i\d+>> Min [<<Par1>>,<<Par2>>]
+ /// CHECK-DAG: <<Add1:i\d+>> Add [<<Max>>,<<Min>>]
+ /// CHECK-DAG: <<Add2:i\d+>> Add [<<Max>>,<<Add1>>]
+ /// CHECK-DAG: <<Add3:i\d+>> Add [<<Min>>,<<Add2>>]
+ /// CHECK-DAG: <<Add4:i\d+>> Add [<<Max>>,<<Add3>>]
+ /// CHECK-DAG: <<Add5:i\d+>> Add [<<Min>>,<<Add4>>]
+ /// CHECK-DAG: Return [<<Add5>>]
+ public static int minmaxCSEScalar(int x, int y) {
+ int t1 = (x > y) ? x : y;
+ int t2 = (x < y) ? x : y;
+ int t3 = (x > y) ? x : y;
+ int t4 = (x < y) ? x : y;
+ int t5 = (x > y) ? x : y;
+ int t6 = (x < y) ? x : y;
+ // Make sure min/max is CSEed.
+ return t1 + t2 + t3 + t4 + t5 + t6;
+ }
+
+ /// CHECK-START: int Main.minmaxCSEArray(int[], int[]) select_generator (after)
+ /// CHECK-DAG: <<Arr1:i\d+>> ArrayGet
+ /// CHECK-DAG: <<Arr2:i\d+>> ArrayGet
+ /// CHECK-DAG: <<Cnd1:z\d+>> LessThanOrEqual [<<Arr1>>,<<Arr2>>]
+ /// CHECK-DAG: <<Sel1:i\d+>> Select [<<Arr1>>,<<Arr2>>,<<Cnd1>>]
+ /// CHECK-DAG: <<Cnd2:z\d+>> GreaterThanOrEqual [<<Arr1>>,<<Arr2>>]
+ /// CHECK-DAG: <<Sel2:i\d+>> Select [<<Arr1>>,<<Arr2>>,<<Cnd2>>]
+ /// CHECK-DAG: <<Add1:i\d+>> Add [<<Sel1>>,<<Sel2>>]
+ /// CHECK-DAG: <<Add2:i\d+>> Add [<<Sel1>>,<<Add1>>]
+ /// CHECK-DAG: <<Add3:i\d+>> Add [<<Sel2>>,<<Add2>>]
+ /// CHECK-DAG: <<Add4:i\d+>> Add [<<Sel1>>,<<Add3>>]
+ /// CHECK-DAG: <<Add5:i\d+>> Add [<<Sel2>>,<<Add4>>]
+ /// CHECK-DAG: Return [<<Add5>>]
+ //
+ /// CHECK-START: int Main.minmaxCSEArray(int[], int[]) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Arr1:i\d+>> ArrayGet
+ /// CHECK-DAG: <<Arr2:i\d+>> ArrayGet
+ /// CHECK-DAG: <<Max:i\d+>> Max [<<Arr1>>,<<Arr2>>]
+ /// CHECK-DAG: <<Min:i\d+>> Min [<<Arr1>>,<<Arr2>>]
+ /// CHECK-DAG: <<Add1:i\d+>> Add [<<Max>>,<<Min>>]
+ /// CHECK-DAG: <<Add2:i\d+>> Add [<<Max>>,<<Add1>>]
+ /// CHECK-DAG: <<Add3:i\d+>> Add [<<Min>>,<<Add2>>]
+ /// CHECK-DAG: <<Add4:i\d+>> Add [<<Max>>,<<Add3>>]
+ /// CHECK-DAG: <<Add5:i\d+>> Add [<<Min>>,<<Add4>>]
+ /// CHECK-DAG: Return [<<Add5>>]
+ public static int minmaxCSEArray(int[] x, int[] y) {
+ int t1 = (x[0] > y[0]) ? x[0] : y[0];
+ int t2 = (x[0] < y[0]) ? x[0] : y[0];
+ int t3 = (x[0] > y[0]) ? x[0] : y[0];
+ int t4 = (x[0] < y[0]) ? x[0] : y[0];
+ int t5 = (x[0] > y[0]) ? x[0] : y[0];
+ int t6 = (x[0] < y[0]) ? x[0] : y[0];
+ // Make sure min/max is CSEed.
+ return t1 + t2 + t3 + t4 + t5 + t6;
+ }
+
+ /// CHECK-START: int Main.minmaxCSEScalarAndCond(int, int) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par1:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Par2:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Max:i\d+>> Max [<<Par1>>,<<Par2>>]
+ /// CHECK-DAG: <<Min:i\d+>> Min [<<Par1>>,<<Par2>>]
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Max>>,<<Min>>]
+ /// CHECK-DAG: Return [<<Add>>]
+ /// CHECK-DAG: <<Add1:i\d+>> Add [<<Max>>,<<Min>>]
+ /// CHECK-DAG: <<Add2:i\d+>> Add [<<Max>>,<<Add1>>]
+ /// CHECK-DAG: <<Add3:i\d+>> Add [<<Min>>,<<Add2>>]
+ /// CHECK-DAG: Return [<<Add3>>]
+ public static int minmaxCSEScalarAndCond(int x, int y) {
+ int t1 = (x > y) ? x : y;
+ int t2 = (x < y) ? x : y;
+ if (x == y)
+ return t1 + t2;
+ int t3 = (x > y) ? x : y;
+ int t4 = (x < y) ? x : y;
+ // Make sure min/max is CSEed.
+ return t1 + t2 + t3 + t4;
+ }
+
public static void main(String[] args) {
- // Types.
+ // Intrinsics.
expectEquals(10, minI(10));
expectEquals(20, minI(25));
expectEquals(10L, minL(10L));
@@ -427,6 +544,7 @@
expectEquals(25, maxI(25));
expectEquals(20L, maxL(10L));
expectEquals(25L, maxL(25L));
+ // Types.
expectEquals(10, min1(10, 20));
expectEquals(10, min2(10, 20));
expectEquals(10, min3(10, 20));
@@ -458,6 +576,10 @@
expectEquals(-100, minmax4(-200));
expectEquals(10, minmax4(10));
expectEquals(100, minmax4(200));
+ expectEquals(90, minmaxCSEScalar(10, 20));
+ expectEquals(90, minmaxCSEArray(a, b));
+ expectEquals(20, minmaxCSEScalarAndCond(10, 10));
+ expectEquals(60, minmaxCSEScalarAndCond(10, 20));
System.out.println("passed");
}
diff --git a/test/681-checker-abs/src/Main.java b/test/681-checker-abs/src/Main.java
index d1ba7c6..2b95a8d 100644
--- a/test/681-checker-abs/src/Main.java
+++ b/test/681-checker-abs/src/Main.java
@@ -19,6 +19,10 @@
*/
public class Main {
+ //
+ // Intrinsics.
+ //
+
/// CHECK-START: int Main.absI(int) instruction_simplifier (before)
/// CHECK-DAG: <<Par:i\d+>> ParameterValue
/// CHECK-DAG: <<Abs:i\d+>> InvokeStaticOrDirect [<<Par>>] intrinsic:MathAbsInt
@@ -51,6 +55,10 @@
return Math.abs(a);
}
+ //
+ // Types.
+ //
+
/// CHECK-START: int Main.abs1(int) instruction_simplifier$after_inlining (before)
/// CHECK-DAG: <<Par:i\d+>> ParameterValue
/// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
@@ -185,6 +193,29 @@
}
//
+ // Complications.
+ //
+
+ /// CHECK-START: int Main.abs0(int[]) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Arr:i\d+>> ArrayGet [{{l\d+}},{{i\d+}}]
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Arr>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:i\d+>> [<<Arr>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Arr>>,<<Neg>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.abs0(int[]) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Arr:i\d+>> ArrayGet [{{l\d+}},{{i\d+}}]
+ /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Arr>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: int Main.abs0(int[]) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int abs0(int[] a) {
+ return a[0] >= 0 ? a[0] : -a[0];
+ }
+
+ //
// Nop zero extension.
//
@@ -248,10 +279,12 @@
}
public static void main(String[] args) {
+ // Intrinsics.
expectEquals(10, absI(-10));
expectEquals(20, absI(20));
expectEquals(10L, absL(-10L));
expectEquals(20L, absL(20L));
+ // Types.
expectEquals(10, abs1(-10));
expectEquals(20, abs1(20));
expectEquals(10, abs2(-10));
@@ -266,6 +299,12 @@
expectEquals(20, abs6((byte) 20));
expectEquals(10L, abs7(-10L));
expectEquals(20L, abs7(20L));
+ // Complications.
+ int[] a = { 13 };
+ int[] b = { -11 };
+ expectEquals(13, abs0(a));
+ expectEquals(11, abs0(b));
+ // Nop zero extension.
expectEquals(1, zabs1((byte) 1));
expectEquals(0xff, zabs1((byte) -1));
expectEquals(1, zabs2((short) 1));