blob: d9c466dd075511e9c550dc0abbf5dd9f658e8726 [file] [log] [blame] [edit]
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// 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.
// Verify that List bound check is eliminated in a simple for-loop
// over growable list.
import 'package:vm/testing/il_matchers.dart';
@pragma('vm:never-inline')
void myprint(Object o) {
print(o);
}
@pragma('vm:never-inline')
@pragma('vm:testing:print-flow-graph')
useList(List<int> a) {
for (int i = 0; i < a.length; ++i) {
final value = a[i];
myprint(value);
}
}
main() {
useList([]);
useList([100]);
}
void matchIL$useList(FlowGraph graph) {
graph.dump();
graph.match([
match.block('Graph', [
'c_null' << match.Constant(value: null),
'c_zero' << match.UnboxedConstant(value: 0),
'c_one' << match.UnboxedConstant(value: 1),
]),
match.block('Function', [
'a' << match.Parameter(index: 0),
match.CheckStackOverflow(),
match.Goto('B5'),
]),
'B5' <<
match.block('Join', [
'i' << match.Phi('c_zero', 'i+1'),
match.CheckStackOverflow(),
'a.length' <<
match.LoadField('a', slot: 'GrowableObjectArray.length'),
if (is32BitConfiguration) ...[
'i_32a' << match.IntConverter('i', from: 'int64', to: 'int32'),
'a.length_unboxed' << match.UnboxInt32('a.length'),
] else ...[
'a.length_unboxed' << match.UnboxInt64('a.length'),
],
match.Branch(
match.RelationalOp(
is32BitConfiguration ? 'i_32a' : 'i',
'a.length_unboxed',
kind: '<',
),
ifTrue: 'B3',
ifFalse: 'B4',
),
]),
'B3' <<
match.block('Target', [
// No bounds check here.
if (is32BitConfiguration)
'i_boxed' << match.BoxInt64('i', skipUntilMatched: false),
'a.data' <<
match.LoadField(
'a',
slot: 'GrowableObjectArray.data',
skipUntilMatched: false,
),
'value' <<
match.LoadIndexed(
'a.data',
is32BitConfiguration ? 'i_boxed' : 'i',
skipUntilMatched: false,
),
'value_unboxed' << match.UnboxInt64('value'),
match.StaticCall('value_unboxed'),
if (is32BitConfiguration) ...[
'i_32' << match.IntConverter('i', from: 'int64', to: 'int32'),
'i+1_32' << match.BinaryInt32Op('i_32', 'c_one', op_kind: '+'),
'i+1' << match.IntConverter('i+1_32', from: 'int32', to: 'int64'),
] else ...[
'i+1' << match.BinaryInt64Op('i', 'c_one', op_kind: '+'),
],
match.Goto('B5'),
]),
'B4' << match.block('Target', [match.DartReturn('c_null')]),
]);
}