Skip to content

Commit d9a9346

Browse files
aartbikcommit-bot@chromium.org
authored andcommitted
[vm/compiler] Fix truncating logic
Rationale: The representation mask should not be used to do the truncation, which is more subtle around the sign bit. With regression test. #38147 Change-Id: I9745f6d73f4761eb6210e0b60b2b0504994f5cbf Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/115607 Reviewed-by: Alexander Markov <[email protected]> Commit-Queue: Aart Bik <[email protected]>
1 parent d2dc053 commit d9a9346

File tree

2 files changed

+54
-8
lines changed

2 files changed

+54
-8
lines changed

runtime/vm/compiler/backend/il.cc

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1982,6 +1982,26 @@ static int64_t RepresentationMask(Representation r) {
19821982
(64 - RepresentationBits(r)));
19831983
}
19841984

1985+
static int64_t TruncateTo(int64_t v, Representation r) {
1986+
switch (r) {
1987+
case kTagged: {
1988+
// Smi occupies word minus kSmiTagShift bits.
1989+
const intptr_t kTruncateBits =
1990+
(kBitsPerInt64 - kBitsPerWord) + kSmiTagShift;
1991+
return Utils::ShiftLeftWithTruncation(v, kTruncateBits) >> kTruncateBits;
1992+
}
1993+
case kUnboxedInt32:
1994+
return Utils::ShiftLeftWithTruncation(v, kBitsPerInt32) >> kBitsPerInt32;
1995+
case kUnboxedUint32:
1996+
return v & kMaxUint32;
1997+
case kUnboxedInt64:
1998+
return v;
1999+
default:
2000+
UNREACHABLE();
2001+
return 0;
2002+
}
2003+
}
2004+
19852005
static bool ToIntegerConstant(Value* value, int64_t* result) {
19862006
if (!value->BindsToConstant()) {
19872007
UnboxInstr* unbox = value->definition()->AsUnbox();
@@ -1993,7 +2013,7 @@ static bool ToIntegerConstant(Value* value, int64_t* result) {
19932013

19942014
case kUnboxedUint32:
19952015
if (ToIntegerConstant(unbox->value(), result)) {
1996-
*result &= RepresentationMask(kUnboxedUint32);
2016+
*result = TruncateTo(*result, kUnboxedUint32);
19972017
return true;
19982018
}
19992019
break;
@@ -2341,8 +2361,8 @@ RawInteger* BinaryIntegerOpInstr::Evaluate(const Integer& left,
23412361

23422362
if (!result.IsNull()) {
23432363
if (is_truncating()) {
2344-
int64_t truncated = result.AsTruncatedInt64Value();
2345-
truncated &= RepresentationMask(representation());
2364+
const int64_t truncated =
2365+
TruncateTo(result.AsTruncatedInt64Value(), representation());
23462366
result = Integer::New(truncated, Heap::kOld);
23472367
ASSERT(IsRepresentable(result, representation()));
23482368
} else if (!IsRepresentable(result, representation())) {
@@ -2475,7 +2495,6 @@ Definition* BinaryIntegerOpInstr::Canonicalize(FlowGraph* flow_graph) {
24752495
return this;
24762496
}
24772497

2478-
const int64_t range_mask = RepresentationMask(representation());
24792498
if (is_truncating()) {
24802499
switch (op_kind()) {
24812500
case Token::kMUL:
@@ -2484,7 +2503,7 @@ Definition* BinaryIntegerOpInstr::Canonicalize(FlowGraph* flow_graph) {
24842503
case Token::kBIT_AND:
24852504
case Token::kBIT_OR:
24862505
case Token::kBIT_XOR:
2487-
rhs = (rhs & range_mask);
2506+
rhs = TruncateTo(rhs, representation());
24882507
break;
24892508
default:
24902509
break;
@@ -2527,21 +2546,21 @@ Definition* BinaryIntegerOpInstr::Canonicalize(FlowGraph* flow_graph) {
25272546
case Token::kBIT_AND:
25282547
if (rhs == 0) {
25292548
return right()->definition();
2530-
} else if (rhs == range_mask) {
2549+
} else if (rhs == RepresentationMask(representation())) {
25312550
return left()->definition();
25322551
}
25332552
break;
25342553
case Token::kBIT_OR:
25352554
if (rhs == 0) {
25362555
return left()->definition();
2537-
} else if (rhs == range_mask) {
2556+
} else if (rhs == RepresentationMask(representation())) {
25382557
return right()->definition();
25392558
}
25402559
break;
25412560
case Token::kBIT_XOR:
25422561
if (rhs == 0) {
25432562
return left()->definition();
2544-
} else if (rhs == range_mask) {
2563+
} else if (rhs == RepresentationMask(representation())) {
25452564
UnaryIntegerOpInstr* bit_not = UnaryIntegerOpInstr::Make(
25462565
representation(), Token::kBIT_NOT, left()->CopyWithType(),
25472566
GetDeoptId(), range());
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// VMOptions=--deterministic --optimization_counter_threshold=10
6+
7+
import "package:expect/expect.dart";
8+
9+
import 'dart:typed_data';
10+
11+
// Found by DartFuzzing: truncating shift
12+
// https://github.com/dart-lang/sdk/issues/38147
13+
14+
int bar(int x, int y) {
15+
return (x << y) & 0xffff;
16+
}
17+
18+
@pragma("vm:never-inline")
19+
int foo() {
20+
return bar(-61, 12);
21+
}
22+
23+
main() {
24+
for (int i = 0; i < 20; i++) {
25+
Expect.equals(12288, foo());
26+
}
27+
}

0 commit comments

Comments
 (0)