[vm/dbc] Support UnboxedWidthExtender on DBC

Change-Id: If6446665f65c0b39dc3a0496c85f367b7738d79a
Cq-Include-Trybots: luci.dart.try:vm-kernel-linux-debug-simdbc64-try, vm-kernel-linux-release-simdbc64-try, vm-kernel-mac-debug-simdbc64-try, vm-kernel-mac-release-simdbc64-try, vm-kernel-reload-mac-debug-simdbc64-try, vm-kernel-reload-mac-release-simdbc64-try, vm-kernel-linux-debug-ia32-try, vm-dartkb-linux-debug-simarm64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/100541
Auto-Submit: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Samir Jindel <sjindel@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
This commit is contained in:
Daco Harkes
2019-04-26 07:21:28 +00:00
committed by commit-bot@chromium.org
parent ed8e4255a4
commit a23def41f9
14 changed files with 235 additions and 96 deletions
@@ -6,6 +6,7 @@
#if defined(TARGET_ARCH_DBC)
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/backend/locations.h"
#include "vm/compiler/compiler_state.h"
#include "vm/stack_frame.h"
#include "vm/symbols.h"
@@ -2479,6 +2480,97 @@ ASSEMBLER_TEST_RUN(WriteIntoMint, test) {
EXPECT_EQ(kMaxInt64, Mint::Cast(obj).value());
}
// - UnboxedWidthExtender rA rB C
//
// Sign- or zero-extends an unboxed integer in FP[rB] into an unboxed
// integer in FP[rA]. C contains SmallRepresentation which determines how
// the integer is extended.
ASSEMBLER_TEST_GENERATE(UnboxedWidthExtenderInt8Positive, assembler) {
__ Frame(3);
__ LoadConstant(0, Integer::Handle(Integer::New(kMaxInt8 + 0xFFFFFF00)));
__ UnboxInt64(1, 0);
// The lower bits contain 0x7F, overwrite the upper bits with 0.
__ UnboxedWidthExtender(2, 1, kSmallUnboxedInt8);
__ Return(2);
}
ASSEMBLER_TEST_RUN(UnboxedWidthExtenderInt8Positive, test) {
EXPECT_EQ(kMaxInt8,
kMaxUint32 & EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code()));
}
ASSEMBLER_TEST_GENERATE(UnboxedWidthExtenderInt8Negative, assembler) {
__ Frame(3);
__ LoadConstant(0, Integer::Handle(Integer::New(kMaxInt32)));
__ UnboxInt64(1, 0);
// The lower bits contain 0xFF, overwrite the upper bits with 1.
__ UnboxedWidthExtender(2, 1, kSmallUnboxedInt8);
__ Return(2);
}
ASSEMBLER_TEST_RUN(UnboxedWidthExtenderInt8Negative, test) {
// least significant 32 bits set to 1.
EXPECT_EQ(kMaxUint32,
kMaxUint32 & EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code()));
}
ASSEMBLER_TEST_GENERATE(UnboxedWidthExtenderUint8, assembler) {
__ Frame(3);
__ LoadConstant(0, Integer::Handle(Integer::New(kMaxUint32)));
__ UnboxInt64(1, 0);
// The lower bits contain 0xFF, overwrite the upper bits with 0.
__ UnboxedWidthExtender(2, 1, kSmallUnboxedUint8);
__ Return(2);
}
ASSEMBLER_TEST_RUN(UnboxedWidthExtenderUint8, test) {
EXPECT_EQ(kMaxUint8,
kMaxUint32 & EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code()));
}
ASSEMBLER_TEST_GENERATE(UnboxedWidthExtenderInt16Positive, assembler) {
__ Frame(3);
__ LoadConstant(0, Integer::Handle(Integer::New(kMaxInt16 + 0xFFFF0000)));
__ UnboxInt64(1, 0);
// The lower bits contain 0x7FFF, overwrite the upper bits with 0.
__ UnboxedWidthExtender(2, 1, kSmallUnboxedInt16);
__ Return(2);
}
ASSEMBLER_TEST_RUN(UnboxedWidthExtenderInt16Positive, test) {
EXPECT_EQ(kMaxInt16,
kMaxUint32 & EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code()));
}
ASSEMBLER_TEST_GENERATE(UnboxedWidthExtenderInt16Negative, assembler) {
__ Frame(3);
__ LoadConstant(0, Integer::Handle(Integer::New(kMaxInt32)));
__ UnboxInt64(1, 0);
// The lower bits contain 0xFFFF, overwrite the upper bits with 1.
__ UnboxedWidthExtender(2, 1, kSmallUnboxedInt16);
__ Return(2);
}
ASSEMBLER_TEST_RUN(UnboxedWidthExtenderInt16Negative, test) {
// least significant 32 bits set to 1.
EXPECT_EQ(kMaxUint32,
kMaxUint32 & EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code()));
}
ASSEMBLER_TEST_GENERATE(UnboxedWidthExtenderUint16, assembler) {
__ Frame(3);
__ LoadConstant(0, Integer::Handle(Integer::New(kMaxUint32)));
__ UnboxInt64(1, 0);
// The lower bits contain 0xFFFF, overwrite the upper bits with 0.
__ UnboxedWidthExtender(2, 1, kSmallUnboxedUint16);
__ Return(2);
}
ASSEMBLER_TEST_RUN(UnboxedWidthExtenderUint16, test) {
EXPECT_EQ(kMaxUint16,
kMaxUint32 & EXECUTE_TEST_CODE_INTPTR_UNBOXED(test->code()));
}
#if defined(ARCH_IS_64_BIT)
// - UnboxDouble rA, rD
//
+22 -6
View File
@@ -7715,12 +7715,14 @@ class UnboxedWidthExtenderInstr : public TemplateDefinition<1, NoThrow, Pure> {
public:
UnboxedWidthExtenderInstr(Value* value,
Representation rep,
intptr_t from_width_bytes)
SmallRepresentation from_rep)
: TemplateDefinition(DeoptId::kNone),
representation_(rep),
from_width_bytes_(from_width_bytes) {
ASSERT(from_width_bytes == 1 || from_width_bytes == 2);
ASSERT(rep == kUnboxedInt32 || rep == kUnboxedUint32);
from_representation_(from_rep) {
ASSERT(rep == kUnboxedInt32 && (from_rep == kSmallUnboxedInt8 ||
from_rep == kSmallUnboxedInt16) ||
rep == kUnboxedUint32 && (from_rep == kSmallUnboxedUint8 ||
from_rep == kSmallUnboxedUint16));
SetInputAt(0, value);
}
@@ -7728,6 +7730,10 @@ class UnboxedWidthExtenderInstr : public TemplateDefinition<1, NoThrow, Pure> {
Representation representation() const { return representation_; }
SmallRepresentation from_representation() const {
return from_representation_;
}
bool ComputeCanDeoptimize() const { return false; }
virtual Representation RequiredInputRepresentation(intptr_t idx) const {
@@ -7739,7 +7745,7 @@ class UnboxedWidthExtenderInstr : public TemplateDefinition<1, NoThrow, Pure> {
ASSERT(other->IsUnboxedWidthExtender());
const UnboxedWidthExtenderInstr* ext = other->AsUnboxedWidthExtender();
return ext->representation() == representation() &&
ext->from_width_bytes_ == from_width_bytes_;
ext->from_representation_ == from_representation_;
}
virtual CompileType ComputeType() const { return CompileType::Int(); }
@@ -7749,8 +7755,18 @@ class UnboxedWidthExtenderInstr : public TemplateDefinition<1, NoThrow, Pure> {
PRINT_OPERANDS_TO_SUPPORT
private:
intptr_t from_width_bytes() const {
if (from_representation_ == kSmallUnboxedInt8 ||
from_representation_ == kSmallUnboxedUint8) {
return 1;
}
ASSERT(from_representation_ == kSmallUnboxedInt16 ||
from_representation_ == kSmallUnboxedUint16);
return 2;
}
const Representation representation_;
const intptr_t from_width_bytes_;
const SmallRepresentation from_representation_;
DISALLOW_COPY_AND_ASSIGN(UnboxedWidthExtenderInstr);
};
+1 -1
View File
@@ -6712,7 +6712,7 @@ void UnboxedWidthExtenderInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register reg = locs()->in(0).reg();
// There are no builtin sign- or zero-extension instructions, so we'll have to
// use shifts instead.
const intptr_t shift_length = (kWordSize - from_width_bytes_) * kBitsPerByte;
const intptr_t shift_length = (kWordSize - from_width_bytes()) * kBitsPerByte;
__ Lsl(reg, reg, Operand(shift_length));
switch (representation_) {
case kUnboxedInt32: // Sign extend operand.
+11 -23
View File
@@ -5928,30 +5928,18 @@ LocationSummary* UnboxedWidthExtenderInstr::MakeLocationSummary(
void UnboxedWidthExtenderInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register reg = locs()->in(0).reg();
switch (representation_) {
case kUnboxedInt32: // Sign extend operand.
switch (from_width_bytes_) {
case 1:
__ sxtb(reg, reg);
break;
case 2:
__ sxth(reg, reg);
break;
default:
UNREACHABLE();
}
switch (from_representation()) {
case kSmallUnboxedInt8: // Sign extend operand.
__ sxtb(reg, reg);
break;
case kUnboxedUint32: // Zero extend operand.
switch (from_width_bytes_) {
case 1:
__ uxtb(reg, reg);
break;
case 2:
__ uxth(reg, reg);
break;
default:
UNREACHABLE();
}
case kSmallUnboxedInt16:
__ sxth(reg, reg);
break;
case kSmallUnboxedUint8: // Zero extend operand.
__ uxtb(reg, reg);
break;
case kSmallUnboxedUint16:
__ uxth(reg, reg);
break;
default:
UNREACHABLE();
+7 -2
View File
@@ -45,8 +45,7 @@ DECLARE_FLAG(int, optimization_counter_threshold);
M(SpeculativeShiftUint32Op) \
M(TruncDivMod) \
M(UnaryUint32Op) \
M(IntConverter) \
M(UnboxedWidthExtender)
M(IntConverter)
// List of instructions that are not used by DBC.
// Things we aren't planning to implement for DBC:
@@ -1797,6 +1796,12 @@ void UnboxInstr::EmitLoadInt64FromBoxOrSmi(FlowGraphCompiler* compiler) {
#endif // defined(ARCH_IS_64_BIT)
}
EMIT_NATIVE_CODE(UnboxedWidthExtender, 1, Location::RequiresRegister()) {
const Register out = locs()->out(0).reg();
const Register value = locs()->in(0).reg();
__ UnboxedWidthExtender(out, value, from_representation());
}
EMIT_NATIVE_CODE(DoubleToSmi, 1, Location::RequiresRegister()) {
const Register value = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
+11 -23
View File
@@ -6064,30 +6064,18 @@ LocationSummary* UnboxedWidthExtenderInstr::MakeLocationSummary(
}
void UnboxedWidthExtenderInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
switch (representation_) {
case kUnboxedInt32: // Sign-extend operand.
switch (from_width_bytes_) {
case 1:
__ movsxb(EAX, AL);
break;
case 2:
__ movsxw(EAX, EAX);
break;
default:
UNREACHABLE();
}
switch (from_representation()) {
case kSmallUnboxedInt8: // Sign extend operand.
__ movsxb(EAX, AL);
break;
case kUnboxedUint32: // Zero-extend operand.
switch (from_width_bytes_) {
case 1:
__ movzxb(EAX, AL);
break;
case 2:
__ movzxw(EAX, EAX);
break;
default:
UNREACHABLE();
}
case kSmallUnboxedInt16:
__ movsxw(EAX, EAX);
break;
case kSmallUnboxedUint8: // Zero extend operand.
__ movzxb(EAX, AL);
break;
case kSmallUnboxedUint16:
__ movzxw(EAX, EAX);
break;
default:
UNREACHABLE();
+1 -1
View File
@@ -1001,7 +1001,7 @@ void IntConverterInstr::PrintOperandsTo(BufferFormatter* f) const {
}
void UnboxedWidthExtenderInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%" Pd " -> 4 (%s), ", from_width_bytes_,
f->Print("%" Pd " -> 4 (%s), ", from_width_bytes(),
RepresentationToCString(representation()));
Definition::PrintOperandsTo(f);
}
+11 -23
View File
@@ -6211,30 +6211,18 @@ LocationSummary* UnboxedWidthExtenderInstr::MakeLocationSummary(
}
void UnboxedWidthExtenderInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
switch (representation_) {
case kUnboxedInt32: // Sign extend operand.
switch (from_width_bytes_) {
case 1:
__ movsxb(RAX, RAX);
break;
case 2:
__ movsxw(RAX, RAX);
break;
default:
UNREACHABLE();
}
switch (from_representation()) {
case kSmallUnboxedInt8: // Sign extend operand.
__ movsxb(RAX, RAX);
break;
case kUnboxedUint32: // Zero extend operand.
switch (from_width_bytes_) {
case 1:
__ movzxb(RAX, RAX);
break;
case 2:
__ movzxw(RAX, RAX);
break;
default:
UNREACHABLE();
}
case kSmallUnboxedInt16:
__ movsxw(RAX, RAX);
break;
case kSmallUnboxedUint8: // Zero extend operand.
__ movzxb(RAX, RAX);
break;
case kSmallUnboxedUint16:
__ movzxw(RAX, RAX);
break;
default:
UNREACHABLE();
+10
View File
@@ -38,6 +38,16 @@ enum Representation {
kNumRepresentations
};
// The representation of 8 and 16 bit integers in 32 bit. SmallRepresentation
// tracks the real representation of these small integers.
enum SmallRepresentation {
kNoSmallRepresentation,
kSmallUnboxedInt8,
kSmallUnboxedUint8,
kSmallUnboxedInt16,
kSmallUnboxedUint16,
};
// 'UnboxedFfiIntPtr' should be able to hold a pointer of the target word-size.
// On a 32-bit platform, it's an unsigned 32-bit int because it should be
// zero-extended to 64-bits, not sign-extended (pointers are inherently
+21 -10
View File
@@ -3,7 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
#include "vm/compiler/ffi.h"
#include <algorithm>
#include "platform/globals.h"
#include "vm/compiler/runtime_api.h"
@@ -13,8 +15,6 @@ namespace compiler {
namespace ffi {
#if !defined(TARGET_ARCH_DBC)
static const size_t kSizeUnknown = 0;
static const intptr_t kNumElementSizes = kFfiVoidCid - kFfiPointerCid + 1;
@@ -73,6 +73,23 @@ Representation TypeRepresentation(const AbstractType& result_type) {
}
}
SmallRepresentation TypeSmallRepresentation(const AbstractType& ffi_type) {
switch (ffi_type.type_class_id()) {
case kFfiInt8Cid:
return kSmallUnboxedInt8;
case kFfiInt16Cid:
return kSmallUnboxedInt16;
case kFfiUint8Cid:
return kSmallUnboxedUint8;
case kFfiUint16Cid:
return kSmallUnboxedUint16;
default:
return kNoSmallRepresentation;
}
}
#if !defined(TARGET_ARCH_DBC)
bool NativeTypeIsVoid(const AbstractType& result_type) {
return result_type.type_class_id() == kFfiVoidCid;
}
@@ -299,16 +316,10 @@ intptr_t NumStackSlots(const ZoneGrowableArray<Location>& locations) {
return max_height_in_slots;
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
#else
size_t ElementSizeInBytes(intptr_t class_id) {
UNREACHABLE();
}
#endif // !defined(TARGET_ARCH_DBC)
#endif // !defined(DART_PRECOMPILED_RUNTIME)
} // namespace ffi
} // namespace compiler
+4
View File
@@ -28,6 +28,10 @@ size_t ElementSizeInBytes(intptr_t class_id);
// Unboxed representation of an FFI type (extends 'ffi.NativeType').
Representation TypeRepresentation(const AbstractType& result_type);
// Unboxed representation of an FFI type (extends 'ffi.NativeType') for 8 and 16
// bit integers.
SmallRepresentation TypeSmallRepresentation(const AbstractType& result_type);
// Whether a type which extends 'ffi.NativeType' also extends 'ffi.Pointer'.
bool NativeTypeIsPointer(const AbstractType& result_type);
+5 -5
View File
@@ -2433,12 +2433,12 @@ Fragment FlowGraphBuilder::Box(Representation from) {
Fragment FlowGraphBuilder::FfiUnboxedExtend(Representation representation,
const AbstractType& ffi_type) {
const intptr_t width =
compiler::ffi::ElementSizeInBytes(ffi_type.type_class_id());
if (width >= compiler::ffi::kMinimumArgumentWidth) return {};
const SmallRepresentation from_representation =
compiler::ffi::TypeSmallRepresentation(ffi_type);
if (from_representation == kNoSmallRepresentation) return {};
auto* extend =
new (Z) UnboxedWidthExtenderInstr(Pop(), representation, width);
auto* extend = new (Z)
UnboxedWidthExtenderInstr(Pop(), representation, from_representation);
Push(extend);
return Fragment(extend);
}
+7
View File
@@ -311,6 +311,12 @@ namespace dart {
// following instruction should be a jump to a label after the slow path
// allocating a Mint box and writing into the Mint box.)
//
// - UnboxedWidthExtender rA rB C
//
// Sign- or zero-extends an unboxed integer in FP[rB] into an unboxed
// integer in FP[rA]. C contains SmallRepresentation which determines how
// the integer is extended.
//
// - WriteIntoMint rA, rD
//
// Box the integer in FP[rD] using the Mint box in FP[rA].
@@ -833,6 +839,7 @@ namespace dart {
V(BoxUint32, A_D, reg, reg, ___) \
V(UnboxInt64, A_D, reg, reg, ___) \
V(BoxInt64, A_D, reg, reg, ___) \
V(UnboxedWidthExtender, A_B_C, reg, reg, num) \
V(SmiToDouble, A_D, reg, reg, ___) \
V(DoubleToSmi, A_D, reg, reg, ___) \
V(DAdd, A_B_C, reg, reg, reg) \
+32 -2
View File
@@ -16,6 +16,7 @@
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/assembler/disassembler.h"
#include "vm/compiler/backend/locations.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/constants_dbc.h"
#include "vm/cpu.h"
@@ -2107,6 +2108,35 @@ SwitchDispatch:
DISPATCH();
}
{
BYTECODE(UnboxedWidthExtender, A_B_C);
auto rep = static_cast<SmallRepresentation>(rC);
const intptr_t value_32_or_64_bit = reinterpret_cast<intptr_t>(FP[rB]);
int32_t value = value_32_or_64_bit & kMaxUint32; // Prevent overflow.
switch (rep) {
case kSmallUnboxedInt8:
// Sign extend the top 24 bits from the sign bit.
value <<= 24;
value >>= 24;
break;
case kSmallUnboxedUint8:
value &= 0x000000FF; // Throw away upper bits.
break;
case kSmallUnboxedInt16:
// Sign extend the top 16 bits from the sign bit.
value <<= 16;
value >>= 16;
break;
case kSmallUnboxedUint16:
value &= 0x0000FFFF; // Throw away upper bits.
break;
default:
UNREACHABLE();
}
FP[rA] = reinterpret_cast<RawObject*>(value);
DISPATCH();
}
#if defined(ARCH_IS_64_BIT)
{
BYTECODE(WriteIntoDouble, A_D);
@@ -2685,7 +2715,7 @@ SwitchDispatch:
BYTECODE(ReturnTOS, 0);
result = *SP;
// Fall through to the ReturnImpl.
// Fall through to the ReturnImpl.
ReturnImpl:
// Restore caller PC.
@@ -3073,7 +3103,7 @@ SwitchDispatch:
NativeArguments native_args(thread, 5, SP + 1, SP - 4);
INVOKE_RUNTIME(DRT_Instanceof, native_args);
}
// clang-format on
// clang-format on
InstanceOfOk:
SP -= 4;