Commit a3c8eebb authored by Mythri A's avatar Mythri A Committed by Commit Bot

[turboprop] Add intrinsics to tier up from Turboprop to TurboFan

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: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72668}
parent 724b2eb4
......@@ -256,9 +256,25 @@ RUNTIME_FUNCTION(Runtime_DynamicCheckMapsEnabled) {
return isolate->heap()->ToBoolean(FLAG_turbo_dynamic_map_checks);
}
RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
HandleScope scope(isolate);
RUNTIME_FUNCTION(Runtime_IsTopTierTurboprop) {
SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length());
return isolate->heap()->ToBoolean(FLAG_turboprop_as_toptier);
}
RUNTIME_FUNCTION(Runtime_IsMidTierTurboprop) {
SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length());
return isolate->heap()->ToBoolean(FLAG_turboprop &&
!FLAG_turboprop_as_toptier);
}
namespace {
enum class TierupKind { kTierupBytecode, kTierupBytecodeOrMidTier };
Object OptimizeFunctionOnNextCall(RuntimeArguments& args, Isolate* isolate,
TierupKind tierup_kind) {
if (args.length() != 1 && args.length() != 2) {
return CrashUnlessFuzzing(isolate);
}
......@@ -297,7 +313,10 @@ RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
PendingOptimizationTable::MarkedForOptimization(isolate, function);
}
if (function->HasAvailableOptimizedCode()) {
CodeKind kind = CodeKindForTopTier();
if ((tierup_kind == TierupKind::kTierupBytecode &&
function->HasAvailableOptimizedCode()) ||
function->HasAvailableCodeKind(kind)) {
DCHECK(function->HasAttachedOptimizedCode() ||
function->ChecksOptimizationMarker());
if (FLAG_testing_d8_test_runner) {
......@@ -337,8 +356,6 @@ RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
return ReadOnlyRoots(isolate).undefined_value();
}
namespace {
bool EnsureFeedbackVector(Handle<JSFunction> function) {
// Check function allows lazy compilation.
if (!function->shared().allows_lazy_compilation()) return false;
......@@ -368,6 +385,17 @@ bool EnsureFeedbackVector(Handle<JSFunction> function) {
} // namespace
RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
HandleScope scope(isolate);
return OptimizeFunctionOnNextCall(args, isolate, TierupKind::kTierupBytecode);
}
RUNTIME_FUNCTION(Runtime_TierupFunctionOnNextCall) {
HandleScope scope(isolate);
return OptimizeFunctionOnNextCall(args, isolate,
TierupKind::kTierupBytecodeOrMidTier);
}
RUNTIME_FUNCTION(Runtime_EnsureFeedbackVectorForFunction) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......
......@@ -469,6 +469,8 @@ namespace internal {
F(DisallowWasmCodegen, 1, 1) \
F(DisassembleFunction, 1, 1) \
F(DynamicCheckMapsEnabled, 0, 1) \
F(IsTopTierTurboprop, 0, 1) \
F(IsMidTierTurboprop, 0, 1) \
F(EnableCodeLoggingForTesting, 0, 1) \
F(EnsureFeedbackVectorForFunction, 1, 1) \
F(FreezeWasmLazyCompilation, 1, 1) \
......@@ -525,6 +527,7 @@ namespace internal {
F(NeverOptimizeFunction, 1, 1) \
F(NotifyContextDisposed, 0, 1) \
F(OptimizeFunctionOnNextCall, -1, 1) \
F(TierupFunctionOnNextCall, -1, 1) \
F(OptimizeOsr, -1, 1) \
F(NewRegExpWithBacktrackLimit, 3, 1) \
F(PrepareFunctionForOptimization, -1, 1) \
......
......@@ -25,7 +25,7 @@
// (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
// Flags: --allow-natives-syntax --expose-gc --no-always-opt --opt
var a = new Int32Array(1024);
......@@ -97,29 +97,69 @@ 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(dictionary_map_array, 5, true);
%PrepareFunctionForOptimization(test_base);
test_base(dictionary_map_array, 6, true);
test_base(dictionary_map_array, 5, false);
test_base(dictionary_map_array, 6, false);
%OptimizeFunctionOnNextCall(test_base);
test_base(dictionary_map_array, -2, true);
assertUnoptimized(test_base);
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);
// Forget about the dictionary_map_array's map.
%ClearFunctionFeedback(test_base);
%PrepareFunctionForOptimization(test_base);
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;
}
}
test_base(a, 5, true);
test_base(a, 6, true);
test_base(a, 5, false);
test_base(a, 6, false);
%OptimizeFunctionOnNextCall(test_base);
test_base(a, 2048, true);
assertUnoptimized(test_base);
%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;
......@@ -178,7 +218,7 @@ short_test(short_a, 50);
%OptimizeFunctionOnNextCall(short_test);
short_a.length = 10;
short_test(short_a, 0);
assertUnoptimized(test_base);
assertUnoptimized(short_test);
// A test for when we would modify a phi index.
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --turboprop --no-use-osr --opt --no-always-opt
// Flags: --allow-natives-syntax --turboprop --opt --no-always-opt
var v_0 = {};
......@@ -21,9 +21,16 @@ f_0(v_0, 42);
f_0(v_0, 42);
// TP tier up
for (let i = 0; i < 100000; i++) {
f_1();
}
%PrepareFunctionForOptimization(f_1);
f_1();
f_1();
%OptimizeFunctionOnNextCall(f_1);
f_1();
// Now TF tier up
%PrepareFunctionForOptimization(f_1);
f_1();
%TierupFunctionOnNextCall(f_1);
f_1();
assertOptimized(f_0);
// TODO(mythria): Add an option to assert on the optimization tier and assert
......@@ -33,5 +40,9 @@ assertOptimized(f_1);
f_0(v_0, 53);
// f_0 does a eager deopt and lets the interpreter update the field constness.
assertUnoptimized(f_0);
if (!%IsTopTierTurboprop()) {
// f_1 has TurboFan code and should deopt because of dependency change.
assertUnoptimized(f_1);
}
assertEquals(v_0.f, 53);
assertEquals(f_1(), 53);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment