diff --git a/src/alloy/frontend/ppc/ppc_emit_fpu.cc b/src/alloy/frontend/ppc/ppc_emit_fpu.cc index 4a09cd4b5..f79a220a2 100644 --- a/src/alloy/frontend/ppc/ppc_emit_fpu.cc +++ b/src/alloy/frontend/ppc/ppc_emit_fpu.cc @@ -407,7 +407,7 @@ int InstrEmit_fcmpx_(PPCFunctionBuilder& f, InstrData& i, bool ordered) { // TODO(benvanik): update VXSNAN const uint32_t crf = i.X.RT >> 2; // 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; } XEEMITTER(fcmpo, 0xFC000040, X )(PPCFunctionBuilder& f, InstrData& i) { diff --git a/src/alloy/frontend/ppc/ppc_function_builder.cc b/src/alloy/frontend/ppc/ppc_function_builder.cc index 97eca85ab..564eb97a3 100644 --- a/src/alloy/frontend/ppc/ppc_function_builder.cc +++ b/src/alloy/frontend/ppc/ppc_function_builder.cc @@ -138,7 +138,7 @@ int PPCFunctionBuilder::Emit(FunctionInfo* symbol_info) { } } - return 0; + return Finalize(); } void PPCFunctionBuilder::AnnotateLabel(uint64_t address, Label* label) { diff --git a/src/alloy/hir/function_builder.cc b/src/alloy/hir/function_builder.cc index 1bf7deda4..936ba49df 100644 --- a/src/alloy/hir/function_builder.cc +++ b/src/alloy/hir/function_builder.cc @@ -44,6 +44,41 @@ void FunctionBuilder::Reset() { 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) { if (value->IsConstant()) { switch (value->type) { @@ -186,14 +221,16 @@ Label* FunctionBuilder::NewLabel() { return label; } -void FunctionBuilder::MarkLabel(Label* label) { - if (current_block_ && current_block_->instr_tail) { - EndBlock(); +void FunctionBuilder::MarkLabel(Label* label, Block* block) { + if (!block) { + 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->prev = block->label_tail; label->next = NULL; @@ -299,6 +336,18 @@ void FunctionBuilder::EndBlock() { 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( const OpcodeInfo& opcode_info, uint16_t flags, Value* dest) { if (!current_block_) { @@ -489,6 +538,15 @@ void FunctionBuilder::Branch(Label* label, uint32_t branch_flags) { 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( Value* cond, Label* label, uint32_t branch_flags) { if (cond->IsConstant()) { diff --git a/src/alloy/hir/function_builder.h b/src/alloy/hir/function_builder.h index 9386a9537..aa8ce94f4 100644 --- a/src/alloy/hir/function_builder.h +++ b/src/alloy/hir/function_builder.h @@ -31,6 +31,7 @@ public: virtual ~FunctionBuilder(); virtual void Reset(); + virtual int Finalize(); void Dump(StringBuffer* str); @@ -44,7 +45,7 @@ public: Instr* last_instr() const; Label* NewLabel(); - void MarkLabel(Label* label); + void MarkLabel(Label* label, Block* block = 0); void InsertLabel(Label* label, Instr* prev_instr); // static allocations: @@ -75,6 +76,7 @@ public: void SetReturnAddress(Value* value); void Branch(Label* label, uint32_t branch_flags = 0); + void Branch(Block* block, uint32_t branch_flags = 0); void BranchTrue(Value* cond, Label* label, uint32_t branch_flags = 0); void BranchFalse(Value* cond, Label* label, @@ -205,6 +207,7 @@ protected: private: Block* AppendBlock(); void EndBlock(); + bool IsUnconditionalJump(Instr* instr); Instr* AppendInstr(const OpcodeInfo& opcode, uint16_t flags, Value* dest = 0); Value* CompareXX(const OpcodeInfo& opcode, Value* value1, Value* value2);