[vm,compiler] Recalculate loops when aligning loop headers

Loop information may be outdated by the time code is generated
(for example, if flow graph is serialized/deserialized).

Recalculate loop information during code generation if it is needed
in order to align loop headers.

TEST=vm/dart/align_loops_verify_alignment_test

Change-Id: I1edd63354cee9940bbd474dc95535b4b74081830
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/401863
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
Alexander Markov
2024-12-20 05:49:02 -08:00
committed by Commit Queue
parent 4a52cbc5de
commit ce8a8b29b6
2 changed files with 41 additions and 20 deletions
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// OtherResources=align_loops_test.dart
import 'dart:convert';
import 'dart:io';
import 'dart:async';
@@ -21,12 +23,20 @@ void checkAligned(Symbol sym) {
}
}
Future<void> testAOT(String dillPath, {bool useAsm = false}) async {
await withTempDir('align-loops-test-${useAsm ? 'asm' : 'elf'}',
(String tempDir) async {
Future<void> testAOT(
String dillPath, {
required bool useAsm,
required bool testILSerialization,
}) async {
await withTempDir('align-loops-test-${useAsm ? 'asm' : 'elf'}', (
String tempDir,
) async {
// Generate the snapshot
final snapshotPath = path.join(tempDir, 'libtest.so');
final commonSnapshotArgs = [dillPath];
final commonSnapshotArgs = [
if (testILSerialization) '--test_il_serialization',
dillPath,
];
if (useAsm) {
final assemblyPath = path.join(tempDir, 'test.S');
@@ -68,24 +78,33 @@ void main() async {
await withTempDir('align_loops', (String tempDir) async {
final testProgram = path.join(
sdkDir, 'runtime', 'tests', 'vm', 'dart', 'align_loops_test.dart');
sdkDir,
'runtime',
'tests',
'vm',
'dart',
'align_loops_test.dart',
);
final aotDillPath = path.join(tempDir, 'aot_test.dill');
await run(genKernel, <String>[
'--aot',
'--platform',
platformDill,
...Platform.executableArguments
.where((arg) => arg.startsWith('--enable-experiment=')),
...Platform.executableArguments.where(
(arg) => arg.startsWith('--enable-experiment='),
),
'-o',
aotDillPath,
testProgram
testProgram,
]);
await Future.wait([
// Test unstripped ELF generation directly.
testAOT(aotDillPath),
testAOT(aotDillPath, useAsm: true),
testAOT(aotDillPath, useAsm: false, testILSerialization: false),
testAOT(aotDillPath, useAsm: true, testILSerialization: false),
testAOT(aotDillPath, useAsm: false, testILSerialization: true),
testAOT(aotDillPath, useAsm: true, testILSerialization: true),
]);
});
}
@@ -663,7 +663,17 @@ static bool IsMarkedWithAlignLoops(const Function& function) {
void FlowGraphCompiler::VisitBlocks() {
CompactBlocks();
if (compiler::Assembler::EmittingComments()) {
#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64)
const bool should_align_loops =
(FLAG_align_all_loops || IsMarkedWithAlignLoops(function())) &&
(kPreferredLoopAlignment > 1);
#else
static_assert(kPreferredLoopAlignment == 1);
const bool should_align_loops = false;
#endif // defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64)
if (should_align_loops || compiler::Assembler::EmittingComments()) {
// The loop_info fields were cleared, recompute.
flow_graph().ComputeLoops();
}
@@ -679,11 +689,6 @@ void FlowGraphCompiler::VisitBlocks() {
const auto inner_lr_state = ComputeInnerLRState(flow_graph());
#endif // defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64)
#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64)
const bool should_align_loops =
FLAG_align_all_loops || IsMarkedWithAlignLoops(function());
#endif // defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64)
for (intptr_t i = 0; i < block_order().length(); ++i) {
// Compile the block entry.
BlockEntryInstr* entry = block_order()[i];
@@ -720,13 +725,10 @@ void FlowGraphCompiler::VisitBlocks() {
}
#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64)
if (should_align_loops && entry->IsLoopHeader() &&
kPreferredLoopAlignment > 1) {
if (should_align_loops && entry->IsLoopHeader()) {
assembler()->mark_should_be_aligned();
assembler()->Align(kPreferredLoopAlignment, 0);
}
#else
static_assert(kPreferredLoopAlignment == 1);
#endif // defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64)
BeginCodeSourceRange(entry->source());