Added recognition of impossible comparisons via NZM and optimize them away Recognize (x + -y) and transform to (x - y) for constants Recognize (~x ) + 1 and transform to -x Check and transform comparisons if theyre semantically equal to others Detect comparisons of single-bit values with their only possible non-zero value and transform to true/false tests Transform ==0 to IS_FALSE, !=0 to IS_TRUE Truncate to int8 if operand for IS_TRUE/IS_FALSE has a nzm of 1 Reduced code generated for SubDidCarry slightly Add special case for InstrEmit_srawix if mask == 1 Cut down the code generated for trap instructions, instead of naive or'ing or compare results do a switch and select the best condition Rerun simplification pass until no changes, as some optimizations will enable others to be done Enable rel32 call optimization by default
125 lines
3.2 KiB
C++
125 lines
3.2 KiB
C++
/**
|
|
******************************************************************************
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
******************************************************************************
|
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
******************************************************************************
|
|
*/
|
|
|
|
#ifndef XENIA_CPU_HIR_INSTR_H_
|
|
#define XENIA_CPU_HIR_INSTR_H_
|
|
|
|
#include "xenia/cpu/hir/opcodes.h"
|
|
#include "xenia/cpu/hir/value.h"
|
|
|
|
namespace xe {
|
|
namespace cpu {
|
|
class Function;
|
|
} // namespace cpu
|
|
} // namespace xe
|
|
|
|
namespace xe {
|
|
namespace cpu {
|
|
namespace hir {
|
|
|
|
class Block;
|
|
class Label;
|
|
|
|
class Instr {
|
|
public:
|
|
Block* block;
|
|
Instr* next;
|
|
Instr* prev;
|
|
|
|
const OpcodeInfo* opcode;
|
|
uint16_t flags;
|
|
uint32_t ordinal;
|
|
|
|
typedef union {
|
|
Function* symbol;
|
|
Label* label;
|
|
Value* value;
|
|
uint64_t offset;
|
|
} Op;
|
|
|
|
Value* dest;
|
|
Op src1;
|
|
Op src2;
|
|
Op src3;
|
|
|
|
Value::Use* src1_use;
|
|
Value::Use* src2_use;
|
|
Value::Use* src3_use;
|
|
|
|
void set_src1(Value* value);
|
|
void set_src2(Value* value);
|
|
void set_src3(Value* value);
|
|
|
|
void MoveBefore(Instr* other);
|
|
void Replace(const OpcodeInfo* new_opcode, uint16_t new_flags);
|
|
void Remove();
|
|
template <typename TPredicate>
|
|
std::pair<Value*, Value*> BinaryValueArrangeByPredicateExclusive(
|
|
TPredicate&& pred) {
|
|
auto src1_value = src1.value;
|
|
auto src2_value = src2.value;
|
|
if (!src1_value || !src2_value) return {nullptr, nullptr};
|
|
|
|
if (!opcode) return {nullptr, nullptr}; // impossible!
|
|
|
|
// check if binary opcode taking two values. we dont care if the dest is a
|
|
// value
|
|
|
|
if (!IsOpcodeBinaryValue(opcode->signature)) return {nullptr, nullptr};
|
|
|
|
if (pred(src1_value)) {
|
|
if (pred(src2_value)) {
|
|
return {nullptr, nullptr};
|
|
} else {
|
|
return {src1_value, src2_value};
|
|
}
|
|
} else if (pred(src2_value)) {
|
|
return {src2_value, src1_value};
|
|
} else {
|
|
return {nullptr, nullptr};
|
|
}
|
|
}
|
|
|
|
/*
|
|
if src1 is constant, and src2 is not, return [src1, src2]
|
|
if src2 is constant, and src1 is not, return [src2, src1]
|
|
if neither is constant, return nullptr, nullptr
|
|
if both are constant, return nullptr, nullptr
|
|
*/
|
|
std::pair<Value*, Value*> BinaryValueArrangeAsConstAndVar() {
|
|
return BinaryValueArrangeByPredicateExclusive(
|
|
[](Value* value) { return value->IsConstant(); });
|
|
}
|
|
std::pair<Value*, Value*> BinaryValueArrangeByDefiningOpcode(
|
|
const OpcodeInfo* op_ptr) {
|
|
return BinaryValueArrangeByPredicateExclusive([op_ptr](Value* value) {
|
|
return value->def && value->def->opcode == op_ptr;
|
|
});
|
|
}
|
|
|
|
Instr* GetDestDefSkipAssigns();
|
|
// returns [def op, constant]
|
|
std::pair<Value*, Value*> BinaryValueArrangeByDefOpAndConstant(
|
|
const OpcodeInfo* op_ptr) {
|
|
auto result = BinaryValueArrangeByDefiningOpcode(op_ptr);
|
|
|
|
if (!result.first) return result;
|
|
if (!result.second->IsConstant()) {
|
|
return {nullptr, nullptr};
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
} // namespace hir
|
|
} // namespace cpu
|
|
} // namespace xe
|
|
|
|
#endif // XENIA_CPU_HIR_INSTR_H_
|