a3c8eebb08
Currently %OptimizeFunctionOnNextCall returns if there is the function is already optimized. This cl changes this function to allow tiering up till we reach top tier. That allows us to tier up from Turboprop to Turbofan using intrinsics. This cl also introduces a runtime-test function to check if turboprop-as-toptier or turboprop-as-midtier is enabled. Bug: chromium:1172797, v8:9684 Change-Id: Idbd99b816d4b93e4e619be5d4ccdfe89fc561a9e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2682638 Commit-Queue: Mythri Alle <mythria@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#72668}
279 lines
7.9 KiB
JavaScript
279 lines
7.9 KiB
JavaScript
// Copyright 2011 the V8 project authors. All rights reserved.
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following
|
|
// disclaimer in the documentation and/or other materials provided
|
|
// with the distribution.
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
// Flags: --allow-natives-syntax --expose-gc --no-always-opt --opt
|
|
|
|
var a = new Int32Array(1024);
|
|
|
|
// Test that we do not assert if the accessed index has not an int32 rep.
|
|
var v = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
function test_do_not_assert_on_non_int32(vector, base) {
|
|
var r = 0;
|
|
var a1 = base + 1;
|
|
var a2 = base + 2;
|
|
var a3 = base + 3;
|
|
var a4 = base + 4;
|
|
if (a1 == 2) {
|
|
r += vector[a1];
|
|
r += vector[a4];
|
|
r += vector[a2];
|
|
r += vector[a3];
|
|
}
|
|
return r;
|
|
}
|
|
%PrepareFunctionForOptimization(test_do_not_assert_on_non_int32);
|
|
test_do_not_assert_on_non_int32(v,1);
|
|
test_do_not_assert_on_non_int32(v,1);
|
|
test_do_not_assert_on_non_int32(v,"a");
|
|
test_do_not_assert_on_non_int32(v,"a");
|
|
%OptimizeFunctionOnNextCall(test_do_not_assert_on_non_int32);
|
|
test_do_not_assert_on_non_int32(v,0);
|
|
|
|
function test_base(a, base, condition) {
|
|
a[base + 1] = 1;
|
|
a[base + 4] = 2;
|
|
a[base + 3] = 3;
|
|
a[base + 2] = 4;
|
|
a[base + 4] = base + 4;
|
|
if (condition) {
|
|
a[base + 1] = 1;
|
|
a[base + 2] = 2;
|
|
a[base + 2] = 3;
|
|
a[base + 2] = 4;
|
|
a[base + 4] = base + 4;
|
|
} else {
|
|
a[base + 6] = 1;
|
|
a[base + 4] = 2;
|
|
a[base + 3] = 3;
|
|
a[base + 2] = 4;
|
|
a[base + 4] = base - 4;
|
|
}
|
|
}
|
|
|
|
function check_test_base(a, base, condition) {
|
|
if (condition) {
|
|
assertEquals(1, a[base + 1]);
|
|
assertEquals(4, a[base + 2]);
|
|
assertEquals(base + 4, a[base + 4]);
|
|
} else {
|
|
assertEquals(1, a[base + 6]);
|
|
assertEquals(3, a[base + 3]);
|
|
assertEquals(4, a[base + 2]);
|
|
assertEquals(base - 4, a[base + 4]);
|
|
}
|
|
}
|
|
|
|
%PrepareFunctionForOptimization(test_base);
|
|
test_base(a, 1, true);
|
|
test_base(a, 2, true);
|
|
test_base(a, 1, false);
|
|
test_base(a, 2, false);
|
|
%OptimizeFunctionOnNextCall(test_base);
|
|
test_base(a, 3, true);
|
|
check_test_base(a, 3, true);
|
|
test_base(a, 3, false);
|
|
check_test_base(a, 3, false);
|
|
assertOptimized(test_base);
|
|
|
|
function test_base_for_dictionary_map(a, base, condition) {
|
|
a[base + 1] = 1;
|
|
a[base + 4] = 2;
|
|
a[base + 3] = 3;
|
|
a[base + 2] = 4;
|
|
a[base + 4] = base + 4;
|
|
if (condition) {
|
|
a[base + 1] = 1;
|
|
a[base + 2] = 2;
|
|
a[base + 2] = 3;
|
|
a[base + 2] = 4;
|
|
a[base + 4] = base + 4;
|
|
} else {
|
|
a[base + 6] = 1;
|
|
a[base + 4] = 2;
|
|
a[base + 3] = 3;
|
|
a[base + 2] = 4;
|
|
a[base + 4] = base - 4;
|
|
}
|
|
}
|
|
|
|
// Test that we deopt on failed bounds checks.
|
|
var dictionary_map_array = new Int32Array(128);
|
|
test_base_for_dictionary_map(dictionary_map_array, 5, true);
|
|
%PrepareFunctionForOptimization(test_base_for_dictionary_map);
|
|
test_base_for_dictionary_map(dictionary_map_array, 6, true);
|
|
test_base_for_dictionary_map(dictionary_map_array, 5, false);
|
|
test_base_for_dictionary_map(dictionary_map_array, 6, false);
|
|
%OptimizeFunctionOnNextCall(test_base_for_dictionary_map);
|
|
test_base_for_dictionary_map(dictionary_map_array, -2, true);
|
|
assertUnoptimized(test_base_for_dictionary_map);
|
|
|
|
function test_base_for_oob(a, base, condition) {
|
|
a[base + 1] = 1;
|
|
a[base + 4] = 2;
|
|
a[base + 3] = 3;
|
|
a[base + 2] = 4;
|
|
a[base + 4] = base + 4;
|
|
if (condition) {
|
|
a[base + 1] = 1;
|
|
a[base + 2] = 2;
|
|
a[base + 2] = 3;
|
|
a[base + 2] = 4;
|
|
a[base + 4] = base + 4;
|
|
} else {
|
|
a[base + 6] = 1;
|
|
a[base + 4] = 2;
|
|
a[base + 3] = 3;
|
|
a[base + 2] = 4;
|
|
a[base + 4] = base - 4;
|
|
}
|
|
}
|
|
|
|
%PrepareFunctionForOptimization(test_base_for_oob);
|
|
test_base_for_oob(a, 5, true);
|
|
test_base_for_oob(a, 6, true);
|
|
test_base_for_oob(a, 5, false);
|
|
test_base_for_oob(a, 6, false);
|
|
%OptimizeFunctionOnNextCall(test_base_for_oob);
|
|
test_base_for_oob(a, 2048, true);
|
|
assertUnoptimized(test_base_for_oob);
|
|
|
|
function test_minus(base,cond) {
|
|
a[base - 1] = 1;
|
|
a[base - 2] = 2;
|
|
a[base + 4] = 3;
|
|
a[base] = 4;
|
|
a[base + 4] = base + 4;
|
|
if (cond) {
|
|
a[base - 4] = 1;
|
|
a[base + 5] = 2;
|
|
a[base + 3] = 3;
|
|
a[base + 2] = 4;
|
|
a[base + 4] = base + 4;
|
|
} else {
|
|
a[base + 6] = 1;
|
|
a[base + 4] = 2;
|
|
a[base + 3] = 3;
|
|
a[base + 2] = 4;
|
|
a[base + 4] = base - 4;
|
|
}
|
|
}
|
|
|
|
function check_test_minus(base,cond) {
|
|
if (cond) {
|
|
assertEquals(2, a[base + 5]);
|
|
assertEquals(3, a[base + 3]);
|
|
assertEquals(4, a[base + 2]);
|
|
assertEquals(base + 4, a[base + 4]);
|
|
} else {
|
|
assertEquals(1, a[base + 6]);
|
|
assertEquals(3, a[base + 3]);
|
|
assertEquals(4, a[base + 2]);
|
|
assertEquals(base - 4, a[base + 4]);
|
|
}
|
|
}
|
|
|
|
%PrepareFunctionForOptimization(test_minus);
|
|
test_minus(5,true);
|
|
test_minus(6,true);
|
|
%OptimizeFunctionOnNextCall(test_minus);
|
|
test_minus(7,true);
|
|
check_test_minus(7,true);
|
|
test_minus(7,false);
|
|
check_test_minus(7,false);
|
|
|
|
// Specific test on negative offsets.
|
|
var short_a = new Array(100);
|
|
for (var i = 0; i < short_a.length; i++) short_a[i] = 0;
|
|
function short_test(a, i) {
|
|
a[i + 9] = 0;
|
|
a[i - 10] = 0;
|
|
}
|
|
%PrepareFunctionForOptimization(short_test);
|
|
short_test(short_a, 50);
|
|
short_test(short_a, 50);
|
|
%OptimizeFunctionOnNextCall(short_test);
|
|
short_a.length = 10;
|
|
short_test(short_a, 0);
|
|
assertUnoptimized(short_test);
|
|
|
|
|
|
// A test for when we would modify a phi index.
|
|
var data_phi = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
|
function test_phi(a, base, check) {
|
|
var index;
|
|
if (check) {
|
|
index = base + 1;
|
|
} else {
|
|
index = base + 2;
|
|
}
|
|
var result = a[index];
|
|
result += a[index + 1];
|
|
result += a[index - 1];
|
|
return result;
|
|
}
|
|
%PrepareFunctionForOptimization(test_phi);
|
|
var result_phi = 0;
|
|
result_phi = test_phi(data_phi, 3, true);
|
|
assertEquals(12, result_phi);
|
|
result_phi = test_phi(data_phi, 3, true);
|
|
assertEquals(12, result_phi);
|
|
%OptimizeFunctionOnNextCall(test_phi);
|
|
result_phi = test_phi(data_phi, 3, true);
|
|
assertEquals(12, result_phi);
|
|
|
|
|
|
// A test for recursive decomposition
|
|
var data_composition_long = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
|
var data_composition_short = [0, 1, 2, 3, 4];
|
|
function test_composition(a, base0, check) {
|
|
var base1 = ((base0 + 2));
|
|
var base2 = ((base1 + 8) >> 2);
|
|
var base3 = ((base2 + 6) >> 1);
|
|
var base4 = ((base3 + 8) >> 1);
|
|
|
|
var result = 0;
|
|
result += a[base0];
|
|
result += a[base1];
|
|
result += a[base2];
|
|
result += a[base3];
|
|
result += a[base4];
|
|
|
|
return result;
|
|
}
|
|
%PrepareFunctionForOptimization(test_composition);
|
|
var result_composition = 0;
|
|
result_composition = test_composition(data_composition_long, 2);
|
|
assertEquals(19, result_composition);
|
|
result_composition = test_composition(data_composition_long, 2);
|
|
assertEquals(19, result_composition);
|
|
%OptimizeFunctionOnNextCall(test_composition);
|
|
result_composition = test_composition(data_composition_short, 2);
|
|
assertEquals(NaN, result_composition);
|
|
|
|
|
|
gc();
|