Commit 1ee49a67 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #659 from tjhance/displacement

Use less large constants
parents 9686c587 32d7224f
...@@ -670,7 +670,24 @@ void Assembler::decl(Indirect mem) { ...@@ -670,7 +670,24 @@ void Assembler::decl(Indirect mem) {
} }
} }
void Assembler::incl(Immediate imm) {
emitByte(0xff);
emitByte(0x04);
emitByte(0x25);
emitInt(imm.val, 4);
}
void Assembler::decl(Immediate imm) {
emitByte(0xff);
emitByte(0x0c);
emitByte(0x25);
emitInt(imm.val, 4);
}
void Assembler::call(Immediate imm) {
emitByte(0xe8);
emitInt(imm.val, 4);
}
void Assembler::callq(Register r) { void Assembler::callq(Register r) {
assert(r == R11 && "untested"); assert(r == R11 && "untested");
......
...@@ -149,9 +149,14 @@ public: ...@@ -149,9 +149,14 @@ public:
void add(Immediate imm, Register reg); void add(Immediate imm, Register reg);
void sub(Immediate imm, Register reg); void sub(Immediate imm, Register reg);
void incl(Indirect mem); void incl(Indirect mem);
void decl(Indirect mem); void decl(Indirect mem);
void incl(Immediate mem);
void decl(Immediate mem);
void call(Immediate imm); // the value is the offset
void callq(Register reg); void callq(Register reg);
void retq(); void retq();
void leave(); void leave();
...@@ -187,6 +192,7 @@ public: ...@@ -187,6 +192,7 @@ public:
void fillWithNopsExcept(int bytes); void fillWithNopsExcept(int bytes);
void emitAnnotation(int num); void emitAnnotation(int num);
uint8_t* startAddr() const { return start_addr; }
int bytesLeft() const { return end_addr - addr; } int bytesLeft() const { return end_addr - addr; }
int bytesWritten() const { return addr - start_addr; } int bytesWritten() const { return addr - start_addr; }
uint8_t* curInstPointer() { return addr; } uint8_t* curInstPointer() { return addr; }
......
...@@ -75,6 +75,16 @@ void ICSlotRewrite::abort() { ...@@ -75,6 +75,16 @@ void ICSlotRewrite::abort() {
ic->retry_in = ic->retry_backoff; ic->retry_in = ic->retry_backoff;
} }
ICSlotInfo* ICSlotRewrite::prepareEntry() {
this->ic_entry = ic->pickEntryForRewrite(debug_name);
return this->ic_entry;
}
uint8_t* ICSlotRewrite::getSlotStart() {
assert(ic_entry != NULL);
return (uint8_t*)ic->start_addr + ic_entry->idx * ic->getSlotSize();
}
void ICSlotRewrite::commit(CommitHook* hook) { void ICSlotRewrite::commit(CommitHook* hook) {
bool still_valid = true; bool still_valid = true;
for (int i = 0; i < dependencies.size(); i++) { for (int i = 0; i < dependencies.size(); i++) {
...@@ -91,14 +101,10 @@ void ICSlotRewrite::commit(CommitHook* hook) { ...@@ -91,14 +101,10 @@ void ICSlotRewrite::commit(CommitHook* hook) {
return; return;
} }
ICSlotInfo* ic_entry = ic->pickEntryForRewrite(debug_name); uint8_t* slot_start = getSlotStart();
if (ic_entry == NULL)
return;
uint8_t* slot_start = (uint8_t*)ic->start_addr + ic_entry->idx * ic->getSlotSize();
uint8_t* continue_point = (uint8_t*)ic->continue_addr; uint8_t* continue_point = (uint8_t*)ic->continue_addr;
bool do_commit = hook->finishAssembly(ic_entry, continue_point - slot_start); bool do_commit = hook->finishAssembly(continue_point - slot_start);
if (!do_commit) if (!do_commit)
return; return;
...@@ -111,6 +117,8 @@ void ICSlotRewrite::commit(CommitHook* hook) { ...@@ -111,6 +117,8 @@ void ICSlotRewrite::commit(CommitHook* hook) {
invalidator->addDependent(ic_entry); invalidator->addDependent(ic_entry);
} }
ic->next_slot_to_try++;
// if (VERBOSITY()) printf("Commiting to %p-%p\n", start, start + ic->slot_size); // if (VERBOSITY()) printf("Commiting to %p-%p\n", start, start + ic->slot_size);
memcpy(slot_start, buf, ic->getSlotSize()); memcpy(slot_start, buf, ic->getSlotSize());
...@@ -166,10 +174,10 @@ ICSlotInfo* ICInfo::pickEntryForRewrite(const char* debug_name) { ...@@ -166,10 +174,10 @@ ICSlotInfo* ICInfo::pickEntryForRewrite(const char* debug_name) {
continue; continue;
if (VERBOSITY() >= 4) { if (VERBOSITY() >= 4) {
printf("committing %s icentry to in-use slot %d at %p\n", debug_name, i, start_addr); printf("picking %s icentry to in-use slot %d at %p\n", debug_name, i, start_addr);
} }
next_slot_to_try = i + 1;
next_slot_to_try = i;
return &sinfo; return &sinfo;
} }
if (VERBOSITY() >= 4) if (VERBOSITY() >= 4)
...@@ -177,8 +185,6 @@ ICSlotInfo* ICInfo::pickEntryForRewrite(const char* debug_name) { ...@@ -177,8 +185,6 @@ ICSlotInfo* ICInfo::pickEntryForRewrite(const char* debug_name) {
return NULL; return NULL;
} }
ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int num_slots, ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int num_slots,
int slot_size, llvm::CallingConv::ID calling_conv, const std::unordered_set<int>& live_outs, int slot_size, llvm::CallingConv::ID calling_conv, const std::unordered_set<int>& live_outs,
assembler::GenericRegister return_register, TypeRecorder* type_recorder) assembler::GenericRegister return_register, TypeRecorder* type_recorder)
......
...@@ -48,7 +48,7 @@ public: ...@@ -48,7 +48,7 @@ public:
class CommitHook { class CommitHook {
public: public:
virtual ~CommitHook() {} virtual ~CommitHook() {}
virtual bool finishAssembly(ICSlotInfo* picked_slot, int fastpath_offset) = 0; virtual bool finishAssembly(int fastpath_offset) = 0;
}; };
private: private:
...@@ -60,6 +60,8 @@ private: ...@@ -60,6 +60,8 @@ private:
std::vector<std::pair<ICInvalidator*, int64_t>> dependencies; std::vector<std::pair<ICInvalidator*, int64_t>> dependencies;
ICSlotInfo* ic_entry;
ICSlotRewrite(ICInfo* ic, const char* debug_name); ICSlotRewrite(ICInfo* ic, const char* debug_name);
public: public:
...@@ -69,11 +71,14 @@ public: ...@@ -69,11 +71,14 @@ public:
int getSlotSize(); int getSlotSize();
int getScratchRspOffset(); int getScratchRspOffset();
int getScratchSize(); int getScratchSize();
uint8_t* getSlotStart();
TypeRecorder* getTypeRecorder(); TypeRecorder* getTypeRecorder();
assembler::GenericRegister returnRegister(); assembler::GenericRegister returnRegister();
ICSlotInfo* prepareEntry();
void addDependenceOn(ICInvalidator&); void addDependenceOn(ICInvalidator&);
void commit(CommitHook* hook); void commit(CommitHook* hook);
void abort(); void abort();
......
...@@ -813,17 +813,14 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr ...@@ -813,17 +813,14 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr
if (has_side_effects) { if (has_side_effects) {
if (!marked_inside_ic) { if (!marked_inside_ic) {
// assembler->trap(); uintptr_t counter_addr = (uintptr_t)(&picked_slot->num_inside);
if (isLargeConstant(counter_addr)) {
// TODO this is super hacky: we don't know the address that we want to inc/dec, since assembler::Register reg = allocReg(Location::any(), getReturnDestination());
// it depends on the slot that we end up picking, so just write out an arbitrary assembler->mov(assembler::Immediate(counter_addr), reg);
// constant an we'll rewrite it later assembler->incl(assembler::Indirect(reg, 0));
// TODO if we can guarantee that the mark_addr will fit in 32 bits, } else {
// we can use a more compact instruction encoding assembler->incl(assembler::Immediate(counter_addr));
mark_addr_addrs.push_back((void**)(assembler->curInstPointer() + 2)); }
assembler::Register reg = allocReg(Location::any());
assembler->mov(assembler::Immediate(0x1234567890abcdefL), reg);
assembler->incl(assembler::Indirect(reg, 0));
assertConsistent(); assertConsistent();
marked_inside_ic = true; marked_inside_ic = true;
...@@ -953,8 +950,16 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr ...@@ -953,8 +950,16 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr
} }
#endif #endif
const_loader.loadConstIntoReg((uint64_t)func_addr, r); uint64_t asm_address = (uint64_t)assembler->curInstPointer() + 5;
assembler->callq(r); uint64_t real_asm_address = asm_address + (uint64_t)rewrite->getSlotStart() - (uint64_t)assembler->startAddr();
int64_t offset = (int64_t)((uint64_t)func_addr - real_asm_address);
if (isLargeConstant(offset)) {
const_loader.loadConstIntoReg((uint64_t)func_addr, r);
assembler->callq(r);
} else {
assembler->call(assembler::Immediate(offset));
assert(asm_address == (uint64_t)assembler->curInstPointer());
}
assert(vars_by_location.count(assembler::RAX) == 0); assert(vars_by_location.count(assembler::RAX) == 0);
result->initializeInReg(assembler::RAX); result->initializeInReg(assembler::RAX);
...@@ -1071,6 +1076,12 @@ void Rewriter::commit() { ...@@ -1071,6 +1076,12 @@ void Rewriter::commit() {
on_done_guarding(); on_done_guarding();
} }
picked_slot = rewrite->prepareEntry();
if (picked_slot == NULL) {
on_assemblyfail();
return;
}
// Now, start emitting assembly; check if we're dong guarding after each. // Now, start emitting assembly; check if we're dong guarding after each.
for (int i = 0; i < actions.size(); i++) { for (int i = 0; i < actions.size(); i++) {
actions[i].action(); actions[i].action();
...@@ -1090,15 +1101,14 @@ void Rewriter::commit() { ...@@ -1090,15 +1101,14 @@ void Rewriter::commit() {
if (marked_inside_ic) { if (marked_inside_ic) {
assembler->comment("mark inside ic"); assembler->comment("mark inside ic");
// TODO this is super hacky: we don't know the address that we want to inc/dec, since uintptr_t counter_addr = (uintptr_t)(&picked_slot->num_inside);
// it depends on the slot that we end up picking, so just write out an arbitrary if (isLargeConstant(counter_addr)) {
// constant an we'll rewrite it later assembler::Register reg = allocReg(Location::any(), getReturnDestination());
// TODO if we can guarantee that the mark_addr will fit in 32 bits, assembler->mov(assembler::Immediate(counter_addr), reg);
// we can use a more compact instruction encoding assembler->decl(assembler::Indirect(reg, 0));
mark_addr_addrs.push_back((void**)(assembler->curInstPointer() + 2)); } else {
assembler::Register reg = allocReg(Location::any(), getReturnDestination()); assembler->decl(assembler::Immediate(counter_addr));
assembler->mov(assembler::Immediate(0x1234567890abcdefL), reg); }
assembler->decl(assembler::Indirect(reg, 0));
} }
assembler->comment("live outs"); assembler->comment("live outs");
...@@ -1242,16 +1252,8 @@ void Rewriter::commit() { ...@@ -1242,16 +1252,8 @@ void Rewriter::commit() {
ic_rewrites_total_bytes.log(asm_size_bytes); ic_rewrites_total_bytes.log(asm_size_bytes);
} }
bool Rewriter::finishAssembly(ICSlotInfo* picked_slot, int continue_offset) { bool Rewriter::finishAssembly(int continue_offset) {
if (marked_inside_ic) { assert(picked_slot);
void* mark_addr = &picked_slot->num_inside;
// Go back and rewrite the faked constants to point to the correct address:
for (void** mark_addr_addr : mark_addr_addrs) {
assert(*mark_addr_addr == (void*)0x1234567890abcdefL);
*mark_addr_addr = mark_addr;
}
}
assembler->jmp(assembler::JumpDestination::fromStart(continue_offset)); assembler->jmp(assembler::JumpDestination::fromStart(continue_offset));
...@@ -1679,6 +1681,7 @@ TypeRecorder* Rewriter::getTypeRecorder() { ...@@ -1679,6 +1681,7 @@ TypeRecorder* Rewriter::getTypeRecorder() {
Rewriter::Rewriter(std::unique_ptr<ICSlotRewrite> rewrite, int num_args, const std::vector<int>& live_outs) Rewriter::Rewriter(std::unique_ptr<ICSlotRewrite> rewrite, int num_args, const std::vector<int>& live_outs)
: rewrite(std::move(rewrite)), : rewrite(std::move(rewrite)),
assembler(this->rewrite->getAssembler()), assembler(this->rewrite->getAssembler()),
picked_slot(NULL),
const_loader(this), const_loader(this),
return_location(this->rewrite->returnRegister()), return_location(this->rewrite->returnRegister()),
failed(false), failed(false),
......
...@@ -317,6 +317,8 @@ protected: ...@@ -317,6 +317,8 @@ protected:
std::unique_ptr<ICSlotRewrite> rewrite; std::unique_ptr<ICSlotRewrite> rewrite;
assembler::Assembler* assembler; assembler::Assembler* assembler;
ICSlotInfo* picked_slot;
ConstLoader const_loader; ConstLoader const_loader;
std::vector<RewriterVar*> vars; std::vector<RewriterVar*> vars;
...@@ -370,7 +372,6 @@ protected: ...@@ -370,7 +372,6 @@ protected:
} }
bool added_changing_action; bool added_changing_action;
bool marked_inside_ic; bool marked_inside_ic;
std::vector<void**> mark_addr_addrs;
int last_guard_action; int last_guard_action;
...@@ -408,7 +409,7 @@ protected: ...@@ -408,7 +409,7 @@ protected:
// Do the bookkeeping to say that var is no longer in location l // Do the bookkeeping to say that var is no longer in location l
void removeLocationFromVar(RewriterVar* var, Location l); void removeLocationFromVar(RewriterVar* var, Location l);
bool finishAssembly(ICSlotInfo* picked_slot, int continue_offset) override; bool finishAssembly(int continue_offset) override;
void _trap(); void _trap();
void _loadConst(RewriterVar* result, int64_t val); void _loadConst(RewriterVar* result, int64_t val);
......
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