Author: [email protected]
Date: Mon Jan 12 09:10:06 2009
New Revision: 1055
Modified:
branches/experimental/toiger/src/assembler-ia32.cc
branches/experimental/toiger/src/assembler-ia32.h
branches/experimental/toiger/src/codegen-ia32.cc
branches/experimental/toiger/src/disasm-ia32.cc
branches/experimental/toiger/src/register-allocator-ia32.cc
branches/experimental/toiger/src/register-allocator-ia32.h
Log:
This is really Kasper's change that I took because Kasper is
unavailable to work on it today.
Combine smi and overflow checks for count operations. This generates
more compact code because we are always using big encodings of jumps
and also it has the effect of spacing jumps.
This can be done for other overflow and smi checks. I'll do that
separately.
Review URL: http://codereview.chromium.org/17611
Modified: branches/experimental/toiger/src/assembler-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/assembler-ia32.cc (original)
+++ branches/experimental/toiger/src/assembler-ia32.cc Mon Jan 12 09:10:06
2009
@@ -1834,6 +1834,16 @@
}
+void Assembler::setcc(Condition cc, Register reg) {
+ ASSERT(reg.is_byte_register());
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ EMIT(0x0F);
+ EMIT(0x90 | cc);
+ EMIT(0xC0 | reg.code());
+}
+
+
void Assembler::cvttss2si(Register dst, const Operand& src) {
ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE2));
EnsureSpace ensure_space(this);
Modified: branches/experimental/toiger/src/assembler-ia32.h
==============================================================================
--- branches/experimental/toiger/src/assembler-ia32.h (original)
+++ branches/experimental/toiger/src/assembler-ia32.h Mon Jan 12 09:10:06
2009
@@ -63,6 +63,8 @@
struct Register {
bool is_valid() const { return 0 <= code_ && code_ < 8; }
bool is(Register reg) const { return code_ == reg.code_; }
+ // eax, ebx, ecx and edx are byte registers, the rest are not.
+ bool is_byte_register() const { return code_ <= 3; }
int code() const {
ASSERT(is_valid());
return code_;
@@ -679,6 +681,7 @@
void frndint();
void sahf();
+ void setcc(Condition cc, Register reg);
void cpuid();
Modified: branches/experimental/toiger/src/codegen-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.cc (original)
+++ branches/experimental/toiger/src/codegen-ia32.cc Mon Jan 12 09:10:06
2009
@@ -4001,6 +4001,20 @@
// writable.
frame_->Spill(value.reg());
ASSERT(allocator_->count(value.reg()) == 1);
+
+ // In order to combine the overflow and the smi check, we need to
+ // be able to allocate a byte register. We attempt to do so
+ // without spilling. If we fail, we will generate separate
+ // overflow and smi checks.
+ //
+ // We need to allocate and clear the temporary byte register
+ // before performing the count operation since clearing the
+ // register using xor will clear the overflow flag.
+ Result tmp = allocator_->AllocateByteRegisterWithoutSpilling();
+ if (tmp.is_valid()) {
+ __ Set(tmp.reg(), Immediate(0));
+ }
+
if (is_increment) {
__ add(Operand(value.reg()), Immediate(Smi::FromInt(1)));
} else {
@@ -4010,9 +4024,20 @@
// If the count operation didn't overflow and the result is a
// valid smi, we're done. Otherwise, we jump to the deferred
// slow-case code.
- deferred->enter()->Branch(overflow, &value, not_taken);
- __ test(value.reg(), Immediate(kSmiTagMask));
- deferred->enter()->Branch(not_zero, &value, not_taken);
+ //
+ // We combine the overflow and the smi check if we could
+ // successfully allocate a temporary byte register.
+ if (tmp.is_valid()) {
+ __ setcc(overflow, tmp.reg());
+ __ or_(Operand(value.reg()), tmp.reg());
+ tmp.Unuse();
+ __ test(value.reg(), Immediate(kSmiTagMask));
+ deferred->enter()->Branch(not_zero, &value, not_taken);
+ } else {
+ deferred->enter()->Branch(overflow, &value, not_taken);
+ __ test(value.reg(), Immediate(kSmiTagMask));
+ deferred->enter()->Branch(not_zero, &value, not_taken);
+ }
// Store the new value in the target if not const.
deferred->exit()->Bind(&value);
Modified: branches/experimental/toiger/src/disasm-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/disasm-ia32.cc (original)
+++ branches/experimental/toiger/src/disasm-ia32.cc Mon Jan 12 09:10:06 2009
@@ -294,6 +294,7 @@
int JumpShort(byte* data);
int JumpConditional(byte* data, const char* comment);
int JumpConditionalShort(byte* data, const char* comment);
+ int SetCC(byte* data);
int FPUInstruction(byte* data);
void AppendToBuffer(const char* format, ...);
@@ -577,6 +578,17 @@
// Returns number of bytes used, including *data.
+int DisassemblerIA32::SetCC(byte* data) {
+ assert(*data == 0x0F);
+ byte cond = *(data+1) & 0x0F;
+ const char* mnem = jump_conditional_mnem[cond];
+ AppendToBuffer("set%s ", mnem);
+ PrintRightOperand(data+2);
+ return 3; // includes 0x0F
+}
+
+
+// Returns number of bytes used, including *data.
int DisassemblerIA32::FPUInstruction(byte* data) {
byte b1 = *data;
byte b2 = *(data + 1);
@@ -821,6 +833,8 @@
f0byte == 0xB7 || f0byte == 0xAF) {
data += 2;
data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
+ } else if ((f0byte & 0xF0) == 0x90) {
+ data += SetCC(data);
} else {
data += 2;
if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
Modified: branches/experimental/toiger/src/register-allocator-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/register-allocator-ia32.cc (original)
+++ branches/experimental/toiger/src/register-allocator-ia32.cc Mon Jan 12
09:10:06 2009
@@ -142,6 +142,18 @@
}
+Result RegisterAllocator::AllocateByteRegisterWithoutSpilling() {
+ Result result = AllocateWithoutSpilling();
+ // Check that the register is a byte register. If not, unuse the
+ // register if valid and return an invalid result.
+ if (result.is_valid() && !result.reg().is_byte_register()) {
+ result.Unuse();
+ return Result(cgen_);
+ }
+ return result;
+}
+
+
Result RegisterAllocator::Allocate() {
Result result = AllocateWithoutSpilling();
if (!result.is_valid()) {
Modified: branches/experimental/toiger/src/register-allocator-ia32.h
==============================================================================
--- branches/experimental/toiger/src/register-allocator-ia32.h (original)
+++ branches/experimental/toiger/src/register-allocator-ia32.h Mon Jan 12
09:10:06 2009
@@ -211,6 +211,10 @@
// fail and return an invalid result.
Result AllocateWithoutSpilling();
+ // Allocate a free byte register without spilling any from the
+ // current frame or fail and return an invalid result.
+ Result AllocateByteRegisterWithoutSpilling();
+
// Copy the internal state to a register file, to be restored later by
// RestoreFrom.
void SaveTo(RegisterFile* register_file) {
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---