Commit a7581443 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Fix invalid comparison operator narrowing.

When we narrow a signed32 comparison to uint8 or uint16 representation,
we also need to change the condition to unsigned comparisons otherwise
the comparison will be done on int16/int8 which interprets the narrowed
bits wrong.

R=epertoso@chromium.org
BUG=v8:5254

Review-Url: https://codereview.chromium.org/2202803003
Cr-Commit-Position: refs/heads/master@{#38231}
parent 1575072c
......@@ -1216,10 +1216,7 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
// Tries to match the size of the given opcode to that of the operands, if
// possible.
InstructionCode TryNarrowOpcodeSize(InstructionCode opcode, Node* left,
Node* right) {
if (opcode != kIA32Cmp && opcode != kIA32Test) {
return opcode;
}
Node* right, FlagsContinuation* cont) {
// Currently, if one of the two operands is not a Load, we don't know what its
// machine representation is, so we bail out.
// TODO(epertoso): we can probably get some size information out of immediates
......@@ -1229,19 +1226,39 @@ InstructionCode TryNarrowOpcodeSize(InstructionCode opcode, Node* left,
}
// If the load representations don't match, both operands will be
// zero/sign-extended to 32bit.
LoadRepresentation left_representation = LoadRepresentationOf(left->op());
if (left_representation != LoadRepresentationOf(right->op())) {
return opcode;
}
switch (left_representation.representation()) {
case MachineRepresentation::kBit:
case MachineRepresentation::kWord8:
return opcode == kIA32Cmp ? kIA32Cmp8 : kIA32Test8;
case MachineRepresentation::kWord16:
return opcode == kIA32Cmp ? kIA32Cmp16 : kIA32Test16;
default:
return opcode;
MachineType left_type = LoadRepresentationOf(left->op());
MachineType right_type = LoadRepresentationOf(right->op());
if (left_type == right_type) {
switch (left_type.representation()) {
case MachineRepresentation::kBit:
case MachineRepresentation::kWord8: {
if (opcode == kIA32Test) return kIA32Test8;
if (opcode == kIA32Cmp) {
if (left_type.semantic() == MachineSemantic::kUint32) {
cont->OverwriteUnsignedIfSigned();
} else {
CHECK_EQ(MachineSemantic::kInt32, left_type.semantic());
}
return kIA32Cmp8;
}
break;
}
case MachineRepresentation::kWord16:
if (opcode == kIA32Test) return kIA32Test16;
if (opcode == kIA32Cmp) {
if (left_type.semantic() == MachineSemantic::kUint32) {
cont->OverwriteUnsignedIfSigned();
} else {
CHECK_EQ(MachineSemantic::kInt32, left_type.semantic());
}
return kIA32Cmp16;
}
break;
default:
break;
}
}
return opcode;
}
// Shared routine for multiple float32 compare operations (inputs commuted).
......@@ -1268,7 +1285,8 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
InstructionCode narrowed_opcode = TryNarrowOpcodeSize(opcode, left, right);
InstructionCode narrowed_opcode =
TryNarrowOpcodeSize(opcode, left, right, cont);
int effect_level = selector->GetEffectLevel(node);
if (cont->IsBranch()) {
......
......@@ -386,6 +386,25 @@ class FlagsContinuation final {
if (negate) Negate();
}
void OverwriteUnsignedIfSigned() {
switch (condition_) {
case kSignedLessThan:
condition_ = kUnsignedLessThan;
break;
case kSignedLessThanOrEqual:
condition_ = kUnsignedLessThanOrEqual;
break;
case kSignedGreaterThan:
condition_ = kUnsignedGreaterThan;
break;
case kSignedGreaterThanOrEqual:
condition_ = kUnsignedGreaterThanOrEqual;
break;
default:
break;
}
}
// Encodes this flags continuation into the given opcode.
InstructionCode Encode(InstructionCode opcode) {
opcode |= FlagsModeField::encode(mode_);
......
......@@ -1581,10 +1581,7 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
// Tries to match the size of the given opcode to that of the operands, if
// possible.
InstructionCode TryNarrowOpcodeSize(InstructionCode opcode, Node* left,
Node* right) {
if (opcode != kX64Cmp32 && opcode != kX64Test32) {
return opcode;
}
Node* right, FlagsContinuation* cont) {
// Currently, if one of the two operands is not a Load, we don't know what its
// machine representation is, so we bail out.
// TODO(epertoso): we can probably get some size information out of immediates
......@@ -1594,19 +1591,39 @@ InstructionCode TryNarrowOpcodeSize(InstructionCode opcode, Node* left,
}
// If the load representations don't match, both operands will be
// zero/sign-extended to 32bit.
LoadRepresentation left_representation = LoadRepresentationOf(left->op());
if (left_representation != LoadRepresentationOf(right->op())) {
return opcode;
}
switch (left_representation.representation()) {
case MachineRepresentation::kBit:
case MachineRepresentation::kWord8:
return opcode == kX64Cmp32 ? kX64Cmp8 : kX64Test8;
case MachineRepresentation::kWord16:
return opcode == kX64Cmp32 ? kX64Cmp16 : kX64Test16;
default:
return opcode;
MachineType left_type = LoadRepresentationOf(left->op());
MachineType right_type = LoadRepresentationOf(right->op());
if (left_type == right_type) {
switch (left_type.representation()) {
case MachineRepresentation::kBit:
case MachineRepresentation::kWord8: {
if (opcode == kX64Test32) return kX64Test8;
if (opcode == kX64Cmp32) {
if (left_type.semantic() == MachineSemantic::kUint32) {
cont->OverwriteUnsignedIfSigned();
} else {
CHECK_EQ(MachineSemantic::kInt32, left_type.semantic());
}
return kX64Cmp8;
}
break;
}
case MachineRepresentation::kWord16:
if (opcode == kX64Test32) return kX64Test16;
if (opcode == kX64Cmp32) {
if (left_type.semantic() == MachineSemantic::kUint32) {
cont->OverwriteUnsignedIfSigned();
} else {
CHECK_EQ(MachineSemantic::kInt32, left_type.semantic());
}
return kX64Cmp16;
}
break;
default:
break;
}
}
return opcode;
}
// Shared routine for multiple word compare operations.
......@@ -1616,7 +1633,7 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
opcode = TryNarrowOpcodeSize(opcode, left, right);
opcode = TryNarrowOpcodeSize(opcode, left, right, cont);
// If one of the two inputs is an immediate, make sure it's on the right, or
// if one of the two inputs is a memory operand, make sure it's on the left.
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
var foo = (function() {
"use asm";
var a = new Uint16Array(2);
a[0] = 32815;
a[1] = 32114;
function foo() {
var x = a[0]|0;
var y = a[1]|0;
if (x < 0) x = 4294967296 + x|0;
if (y < 0) y = 4294967296 + y|0;
return x >= y;
}
return foo;
})();
assertTrue(foo());
assertTrue(foo());
%OptimizeFunctionOnNextCall(foo);
assertTrue(foo());
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
var foo = (function() {
"use asm";
var a = new Uint8Array(2);
a[0] = 128;
a[1] = 127;
function foo() {
var x = a[0]|0;
var y = a[1]|0;
if (x < 0) x = 4294967296 + x|0;
if (y < 0) y = 4294967296 + y|0;
return x >= y;
}
return foo;
})();
assertTrue(foo());
assertTrue(foo());
%OptimizeFunctionOnNextCall(foo);
assertTrue(foo());
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