Adding implicit branches to ensure flow control remains legit.

This commit is contained in:
Ben Vanik 2013-12-26 19:00:52 -08:00
parent aa021d22dd
commit 7002a3bd57
4 changed files with 71 additions and 10 deletions

View File

@ -407,7 +407,7 @@ int InstrEmit_fcmpx_(PPCFunctionBuilder& f, InstrData& i, bool ordered) {
// TODO(benvanik): update VXSNAN // TODO(benvanik): update VXSNAN
const uint32_t crf = i.X.RT >> 2; const uint32_t crf = i.X.RT >> 2;
// f.UpdateFPRF(v); // f.UpdateFPRF(v);
f.UpdateCR(crf, f.LoadFPR(i.X.RA), f.LoadFPR(i.X.RB), true); f.UpdateCR(crf, f.LoadFPR(i.X.RA), f.LoadFPR(i.X.RB), false);
return 0; return 0;
} }
XEEMITTER(fcmpo, 0xFC000040, X )(PPCFunctionBuilder& f, InstrData& i) { XEEMITTER(fcmpo, 0xFC000040, X )(PPCFunctionBuilder& f, InstrData& i) {

View File

@ -138,7 +138,7 @@ int PPCFunctionBuilder::Emit(FunctionInfo* symbol_info) {
} }
} }
return 0; return Finalize();
} }
void PPCFunctionBuilder::AnnotateLabel(uint64_t address, Label* label) { void PPCFunctionBuilder::AnnotateLabel(uint64_t address, Label* label) {

View File

@ -44,6 +44,41 @@ void FunctionBuilder::Reset() {
current_block_ = NULL; current_block_ = NULL;
} }
int FunctionBuilder::Finalize() {
// Scan blocks in order and add fallthrough branches. These are needed for
// analysis passes to work. We may have also added blocks out of order and
// need to ensure they fall through in the right order.
for (auto block = block_head_; block != NULL; block = block->next) {
bool needs_branch = false;
if (block->instr_tail) {
if (!IsUnconditionalJump(block->instr_tail)) {
// Add tail branch to block that falls through.
needs_branch = true;
}
} else {
// Add tail branch to block with no instructions.
// Hopefully an optimization pass will clean this up later.
needs_branch = true;
}
if (needs_branch) {
current_block_ = block;
if (!block->next) {
// No following block.
// Sometimes VC++ generates functions with bl at the end even if they
// will never return. Just add a return to satisfy things.
XELOGW("Fall-through out of the function.");
Return();
current_block_ = NULL;
break;
}
// Add branch.
Branch(block->next, BRANCH_LIKELY);
current_block_ = NULL;
}
}
return 0;
}
void FunctionBuilder::DumpValue(StringBuffer* str, Value* value) { void FunctionBuilder::DumpValue(StringBuffer* str, Value* value) {
if (value->IsConstant()) { if (value->IsConstant()) {
switch (value->type) { switch (value->type) {
@ -186,14 +221,16 @@ Label* FunctionBuilder::NewLabel() {
return label; return label;
} }
void FunctionBuilder::MarkLabel(Label* label) { void FunctionBuilder::MarkLabel(Label* label, Block* block) {
if (current_block_ && current_block_->instr_tail) { if (!block) {
EndBlock(); if (current_block_ && current_block_->instr_tail) {
EndBlock();
}
if (!current_block_) {
AppendBlock();
}
block = current_block_;
} }
if (!current_block_) {
AppendBlock();
}
Block* block = current_block_;
label->block = block; label->block = block;
label->prev = block->label_tail; label->prev = block->label_tail;
label->next = NULL; label->next = NULL;
@ -299,6 +336,18 @@ void FunctionBuilder::EndBlock() {
current_block_ = NULL; current_block_ = NULL;
} }
bool FunctionBuilder::IsUnconditionalJump(Instr* instr) {
if (instr->opcode == &OPCODE_CALL_info ||
instr->opcode == &OPCODE_CALL_INDIRECT_info) {
return (instr->flags & CALL_TAIL) != 0;
} else if (instr->opcode == &OPCODE_BRANCH_info) {
return true;
} else if (instr->opcode == &OPCODE_RETURN_info) {
return true;
}
return false;
}
Instr* FunctionBuilder::AppendInstr( Instr* FunctionBuilder::AppendInstr(
const OpcodeInfo& opcode_info, uint16_t flags, Value* dest) { const OpcodeInfo& opcode_info, uint16_t flags, Value* dest) {
if (!current_block_) { if (!current_block_) {
@ -489,6 +538,15 @@ void FunctionBuilder::Branch(Label* label, uint32_t branch_flags) {
EndBlock(); EndBlock();
} }
void FunctionBuilder::Branch(Block* block, uint32_t branch_flags) {
if (!block->label_head) {
// Block needs a label.
Label* label = NewLabel();
MarkLabel(label, block);
}
Branch(block->label_head, branch_flags);
}
void FunctionBuilder::BranchTrue( void FunctionBuilder::BranchTrue(
Value* cond, Label* label, uint32_t branch_flags) { Value* cond, Label* label, uint32_t branch_flags) {
if (cond->IsConstant()) { if (cond->IsConstant()) {

View File

@ -31,6 +31,7 @@ public:
virtual ~FunctionBuilder(); virtual ~FunctionBuilder();
virtual void Reset(); virtual void Reset();
virtual int Finalize();
void Dump(StringBuffer* str); void Dump(StringBuffer* str);
@ -44,7 +45,7 @@ public:
Instr* last_instr() const; Instr* last_instr() const;
Label* NewLabel(); Label* NewLabel();
void MarkLabel(Label* label); void MarkLabel(Label* label, Block* block = 0);
void InsertLabel(Label* label, Instr* prev_instr); void InsertLabel(Label* label, Instr* prev_instr);
// static allocations: // static allocations:
@ -75,6 +76,7 @@ public:
void SetReturnAddress(Value* value); void SetReturnAddress(Value* value);
void Branch(Label* label, uint32_t branch_flags = 0); void Branch(Label* label, uint32_t branch_flags = 0);
void Branch(Block* block, uint32_t branch_flags = 0);
void BranchTrue(Value* cond, Label* label, void BranchTrue(Value* cond, Label* label,
uint32_t branch_flags = 0); uint32_t branch_flags = 0);
void BranchFalse(Value* cond, Label* label, void BranchFalse(Value* cond, Label* label,
@ -205,6 +207,7 @@ protected:
private: private:
Block* AppendBlock(); Block* AppendBlock();
void EndBlock(); void EndBlock();
bool IsUnconditionalJump(Instr* instr);
Instr* AppendInstr(const OpcodeInfo& opcode, uint16_t flags, Instr* AppendInstr(const OpcodeInfo& opcode, uint16_t flags,
Value* dest = 0); Value* dest = 0);
Value* CompareXX(const OpcodeInfo& opcode, Value* value1, Value* value2); Value* CompareXX(const OpcodeInfo& opcode, Value* value1, Value* value2);