mirror of
https://github.com/dart-lang/sdk
synced 2024-09-20 03:31:28 +00:00
Faster 64-bit right-shift for the ia32 compiler.
Review URL: https://codereview.chromium.org//11027060 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@13295 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
980ffae497
commit
3efefbd582
|
@ -1220,7 +1220,7 @@ void Assembler::shll(Register reg, const Immediate& imm) {
|
|||
|
||||
|
||||
void Assembler::shll(Register operand, Register shifter) {
|
||||
EmitGenericShift(4, operand, shifter);
|
||||
EmitGenericShift(4, Operand(operand), shifter);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1230,7 +1230,7 @@ void Assembler::shrl(Register reg, const Immediate& imm) {
|
|||
|
||||
|
||||
void Assembler::shrl(Register operand, Register shifter) {
|
||||
EmitGenericShift(5, operand, shifter);
|
||||
EmitGenericShift(5, Operand(operand), shifter);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1240,7 +1240,12 @@ void Assembler::sarl(Register reg, const Immediate& imm) {
|
|||
|
||||
|
||||
void Assembler::sarl(Register operand, Register shifter) {
|
||||
EmitGenericShift(7, operand, shifter);
|
||||
EmitGenericShift(7, Operand(operand), shifter);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::sarl(const Address& address, Register shifter) {
|
||||
EmitGenericShift(7, Operand(address), shifter);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1252,6 +1257,22 @@ void Assembler::shld(Register dst, Register src) {
|
|||
}
|
||||
|
||||
|
||||
void Assembler::shrd(Register dst, Register src) {
|
||||
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
|
||||
EmitUint8(0x0F);
|
||||
EmitUint8(0xAD);
|
||||
EmitRegisterOperand(src, dst);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::shrd(const Address& dst, Register src) {
|
||||
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
|
||||
EmitUint8(0x0F);
|
||||
EmitUint8(0xAD);
|
||||
EmitOperand(src, Operand(dst));
|
||||
}
|
||||
|
||||
|
||||
void Assembler::negl(Register reg) {
|
||||
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
|
||||
EmitUint8(0xF7);
|
||||
|
@ -1906,7 +1927,7 @@ void Assembler::EmitGenericShift(int rm,
|
|||
|
||||
|
||||
void Assembler::EmitGenericShift(int rm,
|
||||
Register operand,
|
||||
const Operand& operand,
|
||||
Register shifter) {
|
||||
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
|
||||
ASSERT(shifter == ECX);
|
||||
|
|
|
@ -490,7 +490,10 @@ class Assembler : public ValueObject {
|
|||
void shrl(Register operand, Register shifter);
|
||||
void sarl(Register reg, const Immediate& imm);
|
||||
void sarl(Register operand, Register shifter);
|
||||
void sarl(const Address& address, Register shifter);
|
||||
void shld(Register dst, Register src);
|
||||
void shrd(Register dst, Register src);
|
||||
void shrd(const Address& dst, Register src);
|
||||
|
||||
void negl(Register reg);
|
||||
void notl(Register reg);
|
||||
|
@ -657,7 +660,7 @@ class Assembler : public ValueObject {
|
|||
void EmitNearLabelLink(Label* label);
|
||||
|
||||
void EmitGenericShift(int rm, Register reg, const Immediate& imm);
|
||||
void EmitGenericShift(int rm, Register operand, Register shifter);
|
||||
void EmitGenericShift(int rm, const Operand& operand, Register shifter);
|
||||
|
||||
void StoreIntoObjectFilter(Register object, Register value, Label* no_update);
|
||||
|
||||
|
|
|
@ -494,6 +494,19 @@ ASSEMBLER_TEST_GENERATE(LogicalOps, assembler) {
|
|||
__ movl(Address(EAX, 0), EAX);
|
||||
__ Bind(&donetest13);
|
||||
|
||||
Label donetest14;
|
||||
__ subl(ESP, Immediate(kWordSize));
|
||||
__ movl(Address(ESP, 0), Immediate(0x80000000));
|
||||
__ movl(EAX, Immediate(0));
|
||||
__ movl(ECX, Immediate(3));
|
||||
__ sarl(Address(ESP, 0), ECX);
|
||||
__ shrd(Address(ESP, 0), EAX);
|
||||
__ cmpl(Address(ESP, 0), Immediate(0x1e000000));
|
||||
__ j(EQUAL, &donetest14);
|
||||
__ int3();
|
||||
__ Bind(&donetest14);
|
||||
__ addl(ESP, Immediate(kWordSize));
|
||||
|
||||
__ movl(EAX, Immediate(0));
|
||||
__ ret();
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ DECLARE_RUNTIME_ENTRY(UpdateICDataTwoArgs);
|
|||
V(DoubleToDouble) \
|
||||
V(BinarySmiOp) \
|
||||
V(BinaryMintOp) \
|
||||
V(ShiftMintOp) \
|
||||
V(BinaryDoubleOp) \
|
||||
V(InstanceSetterSameTarget) \
|
||||
V(InstanceSetter) \
|
||||
|
|
|
@ -760,52 +760,33 @@ int X86Decoder::CMov(uint8_t* data) {
|
|||
int X86Decoder::D1D3C1Instruction(uint8_t* data) {
|
||||
uint8_t op = *data;
|
||||
ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
|
||||
uint8_t modrm = *(data+1);
|
||||
int mod, regop, rm;
|
||||
GetModRm(modrm, &mod, ®op, &rm);
|
||||
int imm8 = -1;
|
||||
int num_bytes = 2;
|
||||
if (mod == 3) {
|
||||
const char* mnem = NULL;
|
||||
if (op == 0xD1) {
|
||||
imm8 = 1;
|
||||
switch (regop) {
|
||||
case edx: mnem = "rcl"; break;
|
||||
case edi: mnem = "sar"; break;
|
||||
case esp: mnem = "shl"; break;
|
||||
case ebp: mnem = "shr"; break;
|
||||
default: UNIMPLEMENTED();
|
||||
}
|
||||
} else if (op == 0xC1) {
|
||||
imm8 = *(data+2);
|
||||
num_bytes = 3;
|
||||
switch (regop) {
|
||||
case edx: mnem = "rcl"; break;
|
||||
case esp: mnem = "shl"; break;
|
||||
case ebp: mnem = "shr"; break;
|
||||
case edi: mnem = "sar"; break;
|
||||
default: UNIMPLEMENTED();
|
||||
}
|
||||
} else if (op == 0xD3) {
|
||||
switch (regop) {
|
||||
case esp: mnem = "shl"; break;
|
||||
case ebp: mnem = "shr"; break;
|
||||
case edi: mnem = "sar"; break;
|
||||
default: UNIMPLEMENTED();
|
||||
}
|
||||
}
|
||||
ASSERT(mnem != NULL);
|
||||
Print(mnem);
|
||||
Print(" ");
|
||||
PrintCPURegister(rm);
|
||||
Print(",");
|
||||
if (imm8 > 0) {
|
||||
PrintInt(imm8);
|
||||
} else {
|
||||
Print("cl");
|
||||
}
|
||||
GetModRm(*(data+1), &mod, ®op, &rm);
|
||||
int num_bytes = 1;
|
||||
const char* mnem = NULL;
|
||||
switch (regop) {
|
||||
case 2: mnem = "rcl"; break;
|
||||
case 4: mnem = "shl"; break;
|
||||
case 5: mnem = "shr"; break;
|
||||
case 7: mnem = "sar"; break;
|
||||
default: UNIMPLEMENTED();
|
||||
}
|
||||
ASSERT(mnem != NULL);
|
||||
Print(mnem);
|
||||
Print(" ");
|
||||
|
||||
if (op == 0xD1) {
|
||||
num_bytes += PrintRightOperand(data+1);
|
||||
Print(", 1");
|
||||
} else if (op == 0xC1) {
|
||||
num_bytes += PrintRightOperand(data+1);
|
||||
Print(", ");
|
||||
PrintInt(*(data+2));
|
||||
num_bytes++;
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
ASSERT(op == 0xD3);
|
||||
num_bytes += PrintRightOperand(data+1);
|
||||
Print(", cl");
|
||||
}
|
||||
return num_bytes;
|
||||
}
|
||||
|
@ -1336,6 +1317,7 @@ int X86Decoder::InstructionDecode(uword pc) {
|
|||
Print(f0mnem);
|
||||
int mod, regop, rm;
|
||||
GetModRm(*data, &mod, ®op, &rm);
|
||||
Print(" ");
|
||||
data += PrintRightOperand(data);
|
||||
if (f0byte == 0xAB) {
|
||||
Print(",");
|
||||
|
|
|
@ -148,7 +148,8 @@ void FlowGraphOptimizer::SelectRepresentations() {
|
|||
if (join_entry->phis() != NULL) {
|
||||
for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) {
|
||||
PhiInstr* phi = (*join_entry->phis())[i];
|
||||
if ((phi != NULL) && (phi->GetPropagatedCid() == kDoubleCid)) {
|
||||
if (phi == NULL) continue;
|
||||
if (phi->GetPropagatedCid() == kDoubleCid) {
|
||||
phi->set_representation(kUnboxedDouble);
|
||||
}
|
||||
}
|
||||
|
@ -268,7 +269,7 @@ static bool HasOnlySmiOrMint(const ICData& ic_data) {
|
|||
}
|
||||
|
||||
|
||||
static bool HasOnlyTwoSmi(const ICData& ic_data) {
|
||||
static bool HasOnlyTwoSmis(const ICData& ic_data) {
|
||||
return (ic_data.NumberOfChecks() == 1) &&
|
||||
ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid);
|
||||
}
|
||||
|
@ -474,7 +475,7 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
|||
switch (op_kind) {
|
||||
case Token::kADD:
|
||||
case Token::kSUB:
|
||||
if (HasOnlyTwoSmi(ic_data)) {
|
||||
if (HasOnlyTwoSmis(ic_data)) {
|
||||
operands_type = kSmiCid;
|
||||
} else if (HasTwoMintOrSmi(ic_data) &&
|
||||
FlowGraphCompiler::SupportsUnboxedMints()) {
|
||||
|
@ -486,7 +487,7 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
|||
}
|
||||
break;
|
||||
case Token::kMUL:
|
||||
if (HasOnlyTwoSmi(ic_data)) {
|
||||
if (HasOnlyTwoSmis(ic_data)) {
|
||||
operands_type = kSmiCid;
|
||||
} else if (ShouldSpecializeForDouble(ic_data)) {
|
||||
operands_type = kDoubleCid;
|
||||
|
@ -502,7 +503,7 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
|||
}
|
||||
break;
|
||||
case Token::kMOD:
|
||||
if (HasOnlyTwoSmi(ic_data)) {
|
||||
if (HasOnlyTwoSmis(ic_data)) {
|
||||
operands_type = kSmiCid;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -511,7 +512,17 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
|||
case Token::kBIT_AND:
|
||||
case Token::kBIT_OR:
|
||||
case Token::kBIT_XOR:
|
||||
if (HasOnlyTwoSmi(ic_data)) {
|
||||
if (HasOnlyTwoSmis(ic_data)) {
|
||||
operands_type = kSmiCid;
|
||||
} else if (HasTwoMintOrSmi(ic_data) &&
|
||||
FlowGraphCompiler::SupportsUnboxedMints()) {
|
||||
operands_type = kMintCid;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Token::kSHR:
|
||||
if (HasOnlyTwoSmis(ic_data)) {
|
||||
operands_type = kSmiCid;
|
||||
} else if (HasTwoMintOrSmi(ic_data) &&
|
||||
FlowGraphCompiler::SupportsUnboxedMints()) {
|
||||
|
@ -521,9 +532,8 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
|||
}
|
||||
break;
|
||||
case Token::kTRUNCDIV:
|
||||
case Token::kSHR:
|
||||
case Token::kSHL:
|
||||
if (HasOnlyTwoSmi(ic_data)) {
|
||||
if (HasOnlyTwoSmis(ic_data)) {
|
||||
operands_type = kSmiCid;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -554,9 +564,15 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
|||
} else if (operands_type == kMintCid) {
|
||||
Value* left = call->ArgumentAt(0)->value();
|
||||
Value* right = call->ArgumentAt(1)->value();
|
||||
BinaryMintOpInstr* bin_op =
|
||||
new BinaryMintOpInstr(op_kind, left, right, call);
|
||||
call->ReplaceWith(bin_op, current_iterator());
|
||||
if (op_kind == Token::kSHR) {
|
||||
ShiftMintOpInstr* shift_op =
|
||||
new ShiftMintOpInstr(op_kind, left, right, call);
|
||||
call->ReplaceWith(shift_op, current_iterator());
|
||||
} else {
|
||||
BinaryMintOpInstr* bin_op =
|
||||
new BinaryMintOpInstr(op_kind, left, right, call);
|
||||
call->ReplaceWith(bin_op, current_iterator());
|
||||
}
|
||||
RemovePushArguments(call);
|
||||
} else if (op_kind == Token::kMOD) {
|
||||
// TODO(vegorov): implement fast path code for modulo.
|
||||
|
@ -1042,7 +1058,7 @@ static void HandleRelationalOp(FlowGraphOptimizer* optimizer,
|
|||
if (ic_data.NumberOfChecks() != 1) return;
|
||||
ASSERT(ic_data.HasOneTarget());
|
||||
|
||||
if (HasOnlyTwoSmi(ic_data)) {
|
||||
if (HasOnlyTwoSmis(ic_data)) {
|
||||
optimizer->InsertBefore(
|
||||
instr,
|
||||
new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
|
||||
|
@ -2983,6 +2999,13 @@ void ConstantPropagator::VisitBinaryMintOp(
|
|||
}
|
||||
|
||||
|
||||
void ConstantPropagator::VisitShiftMintOp(
|
||||
ShiftMintOpInstr* instr) {
|
||||
// TODO(kmillikin): Handle shift operations.
|
||||
SetValue(instr, non_constant_);
|
||||
}
|
||||
|
||||
|
||||
void ConstantPropagator::VisitUnaryMintOp(
|
||||
UnaryMintOpInstr* instr) {
|
||||
// TODO(kmillikin): Handle unary operations.
|
||||
|
|
|
@ -510,6 +510,14 @@ void BinaryMintOpInstr::PrintOperandsTo(BufferFormatter* f) const {
|
|||
}
|
||||
|
||||
|
||||
void ShiftMintOpInstr::PrintOperandsTo(BufferFormatter* f) const {
|
||||
f->Print("%s, ", Token::Str(op_kind()));
|
||||
left()->PrintTo(f);
|
||||
f->Print(", ");
|
||||
right()->PrintTo(f);
|
||||
}
|
||||
|
||||
|
||||
void UnaryMintOpInstr::PrintOperandsTo(BufferFormatter* f) const {
|
||||
f->Print("%s, ", Token::Str(op_kind()));
|
||||
value()->PrintTo(f);
|
||||
|
|
|
@ -1212,6 +1212,16 @@ intptr_t BinaryMintOpInstr::ResultCid() const {
|
|||
}
|
||||
|
||||
|
||||
RawAbstractType* ShiftMintOpInstr::CompileType() const {
|
||||
return Type::IntType();
|
||||
}
|
||||
|
||||
|
||||
intptr_t ShiftMintOpInstr::ResultCid() const {
|
||||
return kDynamicCid;
|
||||
}
|
||||
|
||||
|
||||
RawAbstractType* UnaryMintOpInstr::CompileType() const {
|
||||
return Type::IntType();
|
||||
}
|
||||
|
|
|
@ -259,6 +259,7 @@ class EmbeddedArray<T, 0> {
|
|||
M(UnboxInteger) \
|
||||
M(BoxInteger) \
|
||||
M(BinaryMintOp) \
|
||||
M(ShiftMintOp) \
|
||||
M(UnaryMintOp) \
|
||||
M(CheckArrayBound) \
|
||||
M(Constraint) \
|
||||
|
@ -516,6 +517,7 @@ FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
|
|||
friend class UnboxDoubleInstr;
|
||||
friend class BinaryDoubleOpInstr;
|
||||
friend class BinaryMintOpInstr;
|
||||
friend class ShiftMintOpInstr;
|
||||
friend class UnaryMintOpInstr;
|
||||
friend class MathSqrtInstr;
|
||||
friend class CheckClassInstr;
|
||||
|
@ -3584,6 +3586,65 @@ class BinaryMintOpInstr : public TemplateDefinition<2> {
|
|||
};
|
||||
|
||||
|
||||
class ShiftMintOpInstr : public TemplateDefinition<2> {
|
||||
public:
|
||||
ShiftMintOpInstr(Token::Kind op_kind,
|
||||
Value* left,
|
||||
Value* right,
|
||||
InstanceCallInstr* instance_call)
|
||||
: op_kind_(op_kind) {
|
||||
ASSERT(left != NULL);
|
||||
ASSERT(right != NULL);
|
||||
ASSERT(op_kind == Token::kSHR);
|
||||
inputs_[0] = left;
|
||||
inputs_[1] = right;
|
||||
deopt_id_ = instance_call->deopt_id();
|
||||
}
|
||||
|
||||
Value* left() const { return inputs_[0]; }
|
||||
Value* right() const { return inputs_[1]; }
|
||||
|
||||
Token::Kind op_kind() const { return op_kind_; }
|
||||
|
||||
virtual void PrintOperandsTo(BufferFormatter* f) const;
|
||||
|
||||
virtual bool CanDeoptimize() const { return true; }
|
||||
|
||||
virtual bool HasSideEffect() const { return false; }
|
||||
|
||||
virtual bool AffectedBySideEffect() const { return false; }
|
||||
|
||||
virtual bool AttributesEqual(Instruction* other) const {
|
||||
return op_kind() == other->AsShiftMintOp()->op_kind();
|
||||
}
|
||||
|
||||
virtual intptr_t ResultCid() const;
|
||||
virtual RawAbstractType* CompileType() const;
|
||||
|
||||
virtual Representation representation() const {
|
||||
return kUnboxedMint;
|
||||
}
|
||||
|
||||
virtual Representation RequiredInputRepresentation(intptr_t idx) const {
|
||||
ASSERT((idx == 0) || (idx == 1));
|
||||
return (idx == 0) ? kUnboxedMint : kTagged;
|
||||
}
|
||||
|
||||
virtual intptr_t DeoptimizationTarget() const {
|
||||
// Direct access since this instuction cannot deoptimize, and the deopt-id
|
||||
// was inherited from another instuction that could deoptimize.
|
||||
return deopt_id_;
|
||||
}
|
||||
|
||||
DECLARE_INSTRUCTION(ShiftMintOp)
|
||||
|
||||
private:
|
||||
const Token::Kind op_kind_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ShiftMintOpInstr);
|
||||
};
|
||||
|
||||
|
||||
class UnaryMintOpInstr : public TemplateDefinition<1> {
|
||||
public:
|
||||
UnaryMintOpInstr(Token::Kind op_kind,
|
||||
|
|
|
@ -2373,10 +2373,10 @@ void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
__ movq(Address(ESP, 0), left);
|
||||
if (op_kind() == Token::kADD) {
|
||||
__ addl(Address(ESP, 0), EAX);
|
||||
__ adcl(Address(ESP, 4), EDX);
|
||||
__ adcl(Address(ESP, 1 * kWordSize), EDX);
|
||||
} else {
|
||||
__ subl(Address(ESP, 0), EAX);
|
||||
__ sbbl(Address(ESP, 4), EDX);
|
||||
__ sbbl(Address(ESP, 1 * kWordSize), EDX);
|
||||
}
|
||||
__ j(OVERFLOW, &overflow);
|
||||
__ movq(left, Address(ESP, 0));
|
||||
|
@ -2393,6 +2393,56 @@ void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
}
|
||||
|
||||
|
||||
LocationSummary* ShiftMintOpInstr::MakeLocationSummary() const {
|
||||
const intptr_t kNumInputs = 2;
|
||||
const intptr_t kNumTemps = 1;
|
||||
LocationSummary* summary =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
summary->set_in(0, Location::RequiresXmmRegister());
|
||||
summary->set_in(1, Location::RegisterLocation(ECX));
|
||||
summary->set_temp(0, Location::RequiresRegister());
|
||||
summary->set_out(Location::SameAsFirstInput());
|
||||
return summary;
|
||||
}
|
||||
|
||||
|
||||
void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
XmmRegister left = locs()->in(0).xmm_reg();
|
||||
Register temp = locs()->temp(0).reg();
|
||||
ASSERT(locs()->in(1).reg() == ECX);
|
||||
ASSERT(locs()->out().xmm_reg() == left);
|
||||
|
||||
switch (op_kind()) {
|
||||
case Token::kSHR: {
|
||||
Label* deopt = compiler->AddDeoptStub(deopt_id(),
|
||||
kDeoptShiftMintOp);
|
||||
__ subl(ESP, Immediate(2 * kWordSize));
|
||||
__ movq(Address(ESP, 0), left);
|
||||
// Deoptimize if shift count is > 31.
|
||||
// sarl operation masks the count to 5 bits and
|
||||
// shrd is undefined with count > operand size (32)
|
||||
// TODO(fschneider): Support shift counts > 31 without deoptimization.
|
||||
__ SmiUntag(ECX);
|
||||
const Immediate kCountLimit = Immediate(31);
|
||||
__ cmpl(ECX, kCountLimit);
|
||||
__ j(ABOVE, deopt);
|
||||
__ movl(temp, Address(ESP, 1 * kWordSize));
|
||||
__ shrd(Address(ESP, 0), temp); // Shift count in CL.
|
||||
__ sarl(Address(ESP, 1 * kWordSize), ECX); // Shift count in CL.
|
||||
__ movq(left, Address(ESP, 0));
|
||||
__ addl(ESP, Immediate(2 * kWordSize));
|
||||
break;
|
||||
}
|
||||
case Token::kSHL:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LocationSummary* UnaryMintOpInstr::MakeLocationSummary() const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
|
|
|
@ -2198,6 +2198,16 @@ void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
}
|
||||
|
||||
|
||||
LocationSummary* ShiftMintOpInstr::MakeLocationSummary() const {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#undef __
|
||||
|
|
|
@ -54,12 +54,13 @@ class BitOperationsTest {
|
|||
TestPositiveValueShifts();
|
||||
TestNoMaskingOfShiftCount();
|
||||
TestNegativeCountShifts();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
TestCornerCasesLeftShifts();
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
TestCornerCasesRightShifts();
|
||||
TestRightShift64Bit();
|
||||
}
|
||||
}
|
||||
|
||||
static void TestCornerCasesLeftShifts() {
|
||||
static void TestCornerCasesRightShifts() {
|
||||
var v32 = 0xFF000000;
|
||||
var v64 = 0xFF00000000000000;
|
||||
Expect.equals(0x3, v32 >> 0x1E);
|
||||
|
@ -70,6 +71,11 @@ class BitOperationsTest {
|
|||
Expect.equals(0x0, v64 >> 0x40);
|
||||
}
|
||||
|
||||
static void TestRightShift64Bit() {
|
||||
var t = 0x1ffffffff;
|
||||
Expect.equals(0xffffffff, t >> 1);
|
||||
}
|
||||
|
||||
static void TestNegativeCountShifts() {
|
||||
bool throwOnLeft(a, b) {
|
||||
try {
|
||||
|
|
Loading…
Reference in a new issue