Moving alloy/ into xenia/cpu/ to start simplifying things.

This commit is contained in:
Ben Vanik
2015-03-24 07:46:18 -07:00
parent 59395318f3
commit 29912f44c0
519 changed files with 2246 additions and 2296 deletions

View File

@@ -0,0 +1,43 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/cpu/hir/block.h"
#include "xenia/cpu/hir/instr.h"
namespace xe {
namespace cpu {
namespace hir {
void Block::AssertNoCycles() {
Instr* hare = instr_head;
Instr* tortoise = instr_head;
if (!hare) {
return;
}
while ((hare = hare->next)) {
if (hare == tortoise) {
// Cycle!
assert_always();
}
hare = hare->next;
if (hare == tortoise) {
// Cycle!
assert_always();
}
tortoise = tortoise->next;
if (!hare || !tortoise) {
return;
}
}
}
} // namespace hir
} // namespace cpu
} // namespace xe

73
src/xenia/cpu/hir/block.h Normal file
View File

@@ -0,0 +1,73 @@
/**
******************************************************************************
* 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_HIR_BLOCK_H_
#define XENIA_HIR_BLOCK_H_
#include "poly/arena.h"
namespace llvm {
class BitVector;
} // namespace llvm
namespace xe {
namespace cpu {
namespace hir {
class Block;
class HIRBuilder;
class Instr;
class Label;
class Edge {
public:
enum EdgeFlags {
UNCONDITIONAL = (1 << 0),
DOMINATES = (1 << 1),
};
public:
Edge* outgoing_next;
Edge* outgoing_prev;
Edge* incoming_next;
Edge* incoming_prev;
Block* src;
Block* dest;
uint32_t flags;
};
class Block {
public:
poly::Arena* arena;
Block* next;
Block* prev;
Edge* incoming_edge_head;
Edge* outgoing_edge_head;
llvm::BitVector* incoming_values;
Label* label_head;
Label* label_tail;
Instr* instr_head;
Instr* instr_tail;
uint16_t ordinal;
void AssertNoCycles();
};
} // namespace hir
} // namespace cpu
} // namespace xe
#endif // XENIA_HIR_BLOCK_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,267 @@
/**
******************************************************************************
* 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_HIR_HIR_BUILDER_H_
#define XENIA_HIR_HIR_BUILDER_H_
#include <vector>
#include "xenia/cpu/hir/block.h"
#include "xenia/cpu/hir/instr.h"
#include "xenia/cpu/hir/label.h"
#include "xenia/cpu/hir/opcodes.h"
#include "xenia/cpu/hir/value.h"
#include "poly/arena.h"
#include "poly/string_buffer.h"
namespace xe {
namespace cpu {
namespace hir {
enum FunctionAttributes {
FUNCTION_ATTRIB_INLINE = (1 << 1),
};
class HIRBuilder {
public:
HIRBuilder();
virtual ~HIRBuilder();
virtual void Reset();
virtual int Finalize();
void Dump(poly::StringBuffer* str);
void AssertNoCycles();
poly::Arena* arena() const { return arena_; }
uint32_t attributes() const { return attributes_; }
void set_attributes(uint32_t value) { attributes_ = value; }
std::vector<Value*>& locals() { return locals_; }
uint32_t max_value_ordinal() const { return next_value_ordinal_; }
Block* first_block() const { return block_head_; }
Block* last_block() const { return block_tail_; }
Block* current_block() const;
Instr* last_instr() const;
Label* NewLabel();
void MarkLabel(Label* label, Block* block = 0);
void InsertLabel(Label* label, Instr* prev_instr);
void ResetLabelTags();
void AddEdge(Block* src, Block* dest, uint32_t flags);
void MergeAdjacentBlocks(Block* left, Block* right);
// static allocations:
// Value* AllocStatic(size_t length);
void Comment(const char* format, ...);
void Nop();
void SourceOffset(uint64_t offset);
void TraceSource(uint64_t offset);
void TraceSource(uint64_t offset, uint8_t index, Value* value);
void TraceSource(uint64_t offset, uint8_t index_0, Value* value_0,
uint8_t index_1, Value* value_1);
// trace info/etc
void DebugBreak();
void DebugBreakTrue(Value* cond);
void Trap(uint16_t trap_code = 0);
void TrapTrue(Value* cond, uint16_t trap_code = 0);
void Call(runtime::FunctionInfo* symbol_info, uint32_t call_flags = 0);
void CallTrue(Value* cond, runtime::FunctionInfo* symbol_info,
uint32_t call_flags = 0);
void CallIndirect(Value* value, uint32_t call_flags = 0);
void CallIndirectTrue(Value* cond, Value* value, uint32_t call_flags = 0);
void CallExtern(runtime::FunctionInfo* symbol_info);
void Return();
void ReturnTrue(Value* cond);
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, uint32_t branch_flags = 0);
// phi type_name, Block* b1, Value* v1, Block* b2, Value* v2, etc
Value* Assign(Value* value);
Value* Cast(Value* value, TypeName target_type);
Value* ZeroExtend(Value* value, TypeName target_type);
Value* SignExtend(Value* value, TypeName target_type);
Value* Truncate(Value* value, TypeName target_type);
Value* Convert(Value* value, TypeName target_type,
RoundMode round_mode = ROUND_TO_ZERO);
Value* Round(Value* value, RoundMode round_mode);
Value* VectorConvertI2F(Value* value, uint32_t arithmetic_flags = 0);
Value* VectorConvertF2I(Value* value, uint32_t arithmetic_flags = 0);
Value* LoadZero(TypeName type);
Value* LoadConstant(int8_t value);
Value* LoadConstant(uint8_t value);
Value* LoadConstant(int16_t value);
Value* LoadConstant(uint16_t value);
Value* LoadConstant(int32_t value);
Value* LoadConstant(uint32_t value);
Value* LoadConstant(int64_t value);
Value* LoadConstant(uint64_t value);
Value* LoadConstant(float value);
Value* LoadConstant(double value);
Value* LoadConstant(const vec128_t& value);
Value* LoadVectorShl(Value* sh);
Value* LoadVectorShr(Value* sh);
Value* LoadClock();
Value* AllocLocal(TypeName type);
Value* LoadLocal(Value* slot);
void StoreLocal(Value* slot, Value* value);
Value* LoadContext(size_t offset, TypeName type);
void StoreContext(size_t offset, Value* value);
Value* Load(Value* address, TypeName type, uint32_t load_flags = 0);
void Store(Value* address, Value* value, uint32_t store_flags = 0);
void Prefetch(Value* address, size_t length, uint32_t prefetch_flags = 0);
Value* Max(Value* value1, Value* value2);
Value* VectorMax(Value* value1, Value* value2, TypeName part_type,
uint32_t arithmetic_flags = 0);
Value* Min(Value* value1, Value* value2);
Value* VectorMin(Value* value1, Value* value2, TypeName part_type,
uint32_t arithmetic_flags = 0);
Value* Select(Value* cond, Value* value1, Value* value2);
Value* IsTrue(Value* value);
Value* IsFalse(Value* value);
Value* CompareEQ(Value* value1, Value* value2);
Value* CompareNE(Value* value1, Value* value2);
Value* CompareSLT(Value* value1, Value* value2);
Value* CompareSLE(Value* value1, Value* value2);
Value* CompareSGT(Value* value1, Value* value2);
Value* CompareSGE(Value* value1, Value* value2);
Value* CompareULT(Value* value1, Value* value2);
Value* CompareULE(Value* value1, Value* value2);
Value* CompareUGT(Value* value1, Value* value2);
Value* CompareUGE(Value* value1, Value* value2);
Value* DidCarry(Value* value);
Value* DidOverflow(Value* value);
Value* DidSaturate(Value* value);
Value* VectorCompareEQ(Value* value1, Value* value2, TypeName part_type);
Value* VectorCompareSGT(Value* value1, Value* value2, TypeName part_type);
Value* VectorCompareSGE(Value* value1, Value* value2, TypeName part_type);
Value* VectorCompareUGT(Value* value1, Value* value2, TypeName part_type);
Value* VectorCompareUGE(Value* value1, Value* value2, TypeName part_type);
Value* Add(Value* value1, Value* value2, uint32_t arithmetic_flags = 0);
Value* AddWithCarry(Value* value1, Value* value2, Value* value3,
uint32_t arithmetic_flags = 0);
Value* VectorAdd(Value* value1, Value* value2, TypeName part_type,
uint32_t arithmetic_flags = 0);
Value* Sub(Value* value1, Value* value2, uint32_t arithmetic_flags = 0);
Value* VectorSub(Value* value1, Value* value2, TypeName part_type,
uint32_t arithmetic_flags = 0);
Value* Mul(Value* value1, Value* value2, uint32_t arithmetic_flags = 0);
Value* MulHi(Value* value1, Value* value2, uint32_t arithmetic_flags = 0);
Value* Div(Value* value1, Value* value2, uint32_t arithmetic_flags = 0);
Value* MulAdd(Value* value1, Value* value2, Value* value3); // (1 * 2) + 3
Value* MulSub(Value* value1, Value* value2, Value* value3); // (1 * 2) - 3
Value* Neg(Value* value);
Value* Abs(Value* value);
Value* Sqrt(Value* value);
Value* RSqrt(Value* value);
Value* Pow2(Value* value);
Value* Log2(Value* value);
Value* DotProduct3(Value* value1, Value* value2);
Value* DotProduct4(Value* value1, Value* value2);
Value* And(Value* value1, Value* value2);
Value* Or(Value* value1, Value* value2);
Value* Xor(Value* value1, Value* value2);
Value* Not(Value* value);
Value* Shl(Value* value1, Value* value2);
Value* Shl(Value* value1, int8_t value2);
Value* VectorShl(Value* value1, Value* value2, TypeName part_type);
Value* Shr(Value* value1, Value* value2);
Value* Shr(Value* value1, int8_t value2);
Value* VectorShr(Value* value1, Value* value2, TypeName part_type);
Value* Sha(Value* value1, Value* value2);
Value* Sha(Value* value1, int8_t value2);
Value* VectorSha(Value* value1, Value* value2, TypeName part_type);
Value* RotateLeft(Value* value1, Value* value2);
Value* VectorRotateLeft(Value* value1, Value* value2, TypeName part_type);
Value* VectorAverage(Value* value1, Value* value2, TypeName part_type,
uint32_t arithmetic_flags);
Value* ByteSwap(Value* value);
Value* CountLeadingZeros(Value* value);
Value* Insert(Value* value, Value* index, Value* part);
Value* Insert(Value* value, uint64_t index, Value* part);
Value* Extract(Value* value, Value* index, TypeName target_type);
Value* Extract(Value* value, uint8_t index, TypeName target_type);
// i8->i16/i32/... (i8|i8 / i8|i8|i8|i8 / ...)
// i8/i16/i32 -> vec128
Value* Splat(Value* value, TypeName target_type);
Value* Permute(Value* control, Value* value1, Value* value2,
TypeName part_type);
Value* Swizzle(Value* value, TypeName part_type, uint32_t swizzle_mask);
// SelectBits(cond, value1, value2)
Value* Pack(Value* value, uint32_t pack_flags = 0);
Value* Pack(Value* value1, Value* value2, uint32_t pack_flags = 0);
Value* Unpack(Value* value, uint32_t pack_flags = 0);
Value* CompareExchange(Value* address, Value* compare_value,
Value* exchange_value);
Value* AtomicExchange(Value* address, Value* new_value);
Value* AtomicAdd(Value* address, Value* value);
Value* AtomicSub(Value* address, Value* value);
protected:
void DumpValue(poly::StringBuffer* str, Value* value);
void DumpOp(poly::StringBuffer* str, OpcodeSignatureType sig_type,
Instr::Op* op);
Value* AllocValue(TypeName type = INT64_TYPE);
Value* CloneValue(Value* source);
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);
Value* VectorCompareXX(const OpcodeInfo& opcode, Value* value1, Value* value2,
TypeName part_type);
protected:
poly::Arena* arena_;
uint32_t attributes_;
uint32_t next_label_id_;
uint32_t next_value_ordinal_;
std::vector<Value*> locals_;
Block* block_head_;
Block* block_tail_;
Block* current_block_;
};
} // namespace hir
} // namespace cpu
} // namespace xe
#endif // XENIA_HIR_HIR_BUILDER_H_

120
src/xenia/cpu/hir/instr.cc Normal file
View File

@@ -0,0 +1,120 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
#include "xenia/cpu/hir/instr.h"
#include "xenia/cpu/hir/block.h"
namespace xe {
namespace cpu {
namespace hir {
void Instr::set_src1(Value* value) {
if (src1.value == value) {
return;
}
if (src1_use) {
src1.value->RemoveUse(src1_use);
}
src1.value = value;
src1_use = value ? value->AddUse(block->arena, this) : NULL;
}
void Instr::set_src2(Value* value) {
if (src2.value == value) {
return;
}
if (src2_use) {
src2.value->RemoveUse(src2_use);
}
src2.value = value;
src2_use = value ? value->AddUse(block->arena, this) : NULL;
}
void Instr::set_src3(Value* value) {
if (src3.value == value) {
return;
}
if (src3_use) {
src3.value->RemoveUse(src3_use);
}
src3.value = value;
src3_use = value ? value->AddUse(block->arena, this) : NULL;
}
void Instr::MoveBefore(Instr* other) {
if (next == other) {
return;
}
// Remove from current location.
if (prev) {
prev->next = next;
} else {
block->instr_head = next;
}
if (next) {
next->prev = prev;
} else {
block->instr_tail = prev;
}
// Insert into new location.
block = other->block;
next = other;
prev = other->prev;
other->prev = this;
if (prev) {
prev->next = this;
}
if (other == block->instr_head) {
block->instr_head = this;
}
}
void Instr::Replace(const OpcodeInfo* opcode, uint16_t flags) {
this->opcode = opcode;
this->flags = flags;
if (src1_use) {
src1.value->RemoveUse(src1_use);
src1.value = NULL;
src1_use = NULL;
}
if (src2_use) {
src2.value->RemoveUse(src2_use);
src2.value = NULL;
src2_use = NULL;
}
if (src3_use) {
src3.value->RemoveUse(src3_use);
src3.value = NULL;
src3_use = NULL;
}
}
void Instr::Remove() {
// Remove all srcs/dest.
Replace(&OPCODE_NOP_info, 0);
if (prev) {
prev->next = next;
} else {
block->instr_head = next;
}
if (next) {
next->prev = prev;
} else {
block->instr_tail = prev;
}
}
} // namespace hir
} // namespace cpu
} // namespace xe

70
src/xenia/cpu/hir/instr.h Normal file
View File

@@ -0,0 +1,70 @@
/**
******************************************************************************
* 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_HIR_INSTR_H_
#define XENIA_HIR_INSTR_H_
#include "xenia/cpu/hir/opcodes.h"
#include "xenia/cpu/hir/value.h"
namespace xe {
namespace cpu {
namespace runtime {
class FunctionInfo;
} // namespace runtime
} // 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 {
runtime::FunctionInfo* symbol_info;
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* opcode, uint16_t flags);
void Remove();
};
} // namespace hir
} // namespace cpu
} // namespace xe
#endif // XENIA_HIR_INSTR_H_

35
src/xenia/cpu/hir/label.h Normal file
View File

@@ -0,0 +1,35 @@
/**
******************************************************************************
* 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_HIR_LABEL_H_
#define XENIA_HIR_LABEL_H_
namespace xe {
namespace cpu {
namespace hir {
class Block;
class Label {
public:
Block* block;
Label* next;
Label* prev;
uint32_t id;
char* name;
void* tag;
};
} // namespace hir
} // namespace cpu
} // namespace xe
#endif // XENIA_HIR_LABEL_H_

View File

@@ -0,0 +1,25 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
#include "xenia/cpu/hir/opcodes.h"
namespace xe {
namespace cpu {
namespace hir {
#define DEFINE_OPCODE(num, name, sig, flags) \
const OpcodeInfo num##_info = { \
flags, sig, name, num, \
};
#include "xenia/cpu/hir/opcodes.inl"
#undef DEFINE_OPCODE
} // namespace hir
} // namespace cpu
} // namespace xe

295
src/xenia/cpu/hir/opcodes.h Normal file
View File

@@ -0,0 +1,295 @@
/**
******************************************************************************
* 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_HIR_OPCODES_H_
#define XENIA_HIR_OPCODES_H_
#include <cstdint>
namespace xe {
namespace cpu {
namespace hir {
enum CallFlags {
CALL_TAIL = (1 << 1),
CALL_POSSIBLE_RETURN = (1 << 2),
};
enum BranchFlags {
BRANCH_LIKELY = (1 << 1),
BRANCH_UNLIKELY = (1 << 2),
};
enum RoundMode {
// to zero/nearest/etc
ROUND_TO_ZERO = 0,
ROUND_TO_NEAREST,
ROUND_TO_MINUS_INFINITY,
ROUND_TO_POSITIVE_INFINITY,
};
enum LoadFlags {
LOAD_NO_ALIAS = (1 << 1),
LOAD_ALIGNED = (1 << 2),
LOAD_UNALIGNED = (1 << 3),
LOAD_VOLATILE = (1 << 4),
};
enum StoreFlags {
STORE_NO_ALIAS = (1 << 1),
STORE_ALIGNED = (1 << 2),
STORE_UNALIGNED = (1 << 3),
STORE_VOLATILE = (1 << 4),
};
enum PrefetchFlags {
PREFETCH_LOAD = (1 << 1),
PREFETCH_STORE = (1 << 2),
};
enum ArithmeticFlags {
ARITHMETIC_SET_CARRY = (1 << 1),
ARITHMETIC_UNSIGNED = (1 << 2),
ARITHMETIC_SATURATE = (1 << 3),
};
#define PERMUTE_MASK(sel_x, x, sel_y, y, sel_z, z, sel_w, w) \
((((x)&0x3) << 0) | (sel_x << 2) | (((y)&0x3) << 8) | (sel_y << 10) | \
(((z)&0x3) << 16) | (sel_z << 18) | (((w)&0x3) << 24) | (sel_w << 26))
enum Permutes {
PERMUTE_IDENTITY = PERMUTE_MASK(0, 0, 0, 1, 0, 2, 0, 3),
};
#define SWIZZLE_MASK(x, y, z, w) \
((((x)&0x3) << 0) | (((y)&0x3) << 2) | (((z)&0x3) << 4) | (((w)&0x3) << 6))
enum Swizzles {
SWIZZLE_XYZW_TO_XYZW = SWIZZLE_MASK(0, 1, 2, 3),
SWIZZLE_XYZW_TO_YZWX = SWIZZLE_MASK(1, 2, 3, 0),
SWIZZLE_XYZW_TO_ZWXY = SWIZZLE_MASK(2, 3, 0, 1),
SWIZZLE_XYZW_TO_WXYZ = SWIZZLE_MASK(3, 0, 1, 2),
};
enum PackType : uint16_t {
// Special types:
PACK_TYPE_D3DCOLOR = 0,
PACK_TYPE_FLOAT16_2 = 1,
PACK_TYPE_FLOAT16_4 = 2,
PACK_TYPE_SHORT_2 = 3,
// Types which use the bitmasks below for configuration:
PACK_TYPE_8_IN_16 = 4,
PACK_TYPE_16_IN_32 = 5,
PACK_TYPE_MODE = 0x000F, // just to get the mode
// Unpack to low or high parts.
PACK_TYPE_TO_LO = 0 << 12,
PACK_TYPE_TO_HI = 1 << 12,
// Input/output arithmetic flags:
PACK_TYPE_IN_SIGNED = 0 << 13,
PACK_TYPE_IN_UNSIGNED = 1 << 13,
PACK_TYPE_OUT_SIGNED = 0 << 14,
PACK_TYPE_OUT_UNSIGNED = 1 << 14,
PACK_TYPE_OUT_UNSATURATE = 0 << 15,
PACK_TYPE_OUT_SATURATE = 1 << 15,
};
inline bool IsPackToHi(uint32_t flags) {
return (flags & PACK_TYPE_TO_HI) == PACK_TYPE_TO_HI;
}
inline bool IsPackToLo(uint32_t flags) { return !IsPackToHi(flags); }
inline bool IsPackInUnsigned(uint32_t flags) {
return (flags & PACK_TYPE_IN_UNSIGNED) == PACK_TYPE_IN_UNSIGNED;
}
inline bool IsPackOutUnsigned(uint32_t flags) {
return (flags & PACK_TYPE_OUT_UNSIGNED) == PACK_TYPE_OUT_UNSIGNED;
}
inline bool IsPackOutSaturate(uint32_t flags) {
return (flags & PACK_TYPE_OUT_SATURATE) == PACK_TYPE_OUT_SATURATE;
}
enum Opcode {
OPCODE_COMMENT,
OPCODE_NOP,
OPCODE_SOURCE_OFFSET,
OPCODE_TRACE_SOURCE,
OPCODE_DEBUG_BREAK,
OPCODE_DEBUG_BREAK_TRUE,
OPCODE_TRAP,
OPCODE_TRAP_TRUE,
OPCODE_CALL,
OPCODE_CALL_TRUE,
OPCODE_CALL_INDIRECT,
OPCODE_CALL_INDIRECT_TRUE,
OPCODE_CALL_EXTERN,
OPCODE_RETURN,
OPCODE_RETURN_TRUE,
OPCODE_SET_RETURN_ADDRESS,
OPCODE_BRANCH,
OPCODE_BRANCH_TRUE,
OPCODE_BRANCH_FALSE,
OPCODE_ASSIGN,
OPCODE_CAST,
OPCODE_ZERO_EXTEND,
OPCODE_SIGN_EXTEND,
OPCODE_TRUNCATE,
OPCODE_CONVERT,
OPCODE_ROUND,
OPCODE_VECTOR_CONVERT_I2F,
OPCODE_VECTOR_CONVERT_F2I,
OPCODE_LOAD_VECTOR_SHL,
OPCODE_LOAD_VECTOR_SHR,
OPCODE_LOAD_CLOCK,
OPCODE_LOAD_LOCAL,
OPCODE_STORE_LOCAL,
OPCODE_LOAD_CONTEXT,
OPCODE_STORE_CONTEXT,
OPCODE_LOAD,
OPCODE_STORE,
OPCODE_PREFETCH,
OPCODE_MAX,
OPCODE_VECTOR_MAX,
OPCODE_MIN,
OPCODE_VECTOR_MIN,
OPCODE_SELECT,
OPCODE_IS_TRUE,
OPCODE_IS_FALSE,
OPCODE_COMPARE_EQ,
OPCODE_COMPARE_NE,
OPCODE_COMPARE_SLT,
OPCODE_COMPARE_SLE,
OPCODE_COMPARE_SGT,
OPCODE_COMPARE_SGE,
OPCODE_COMPARE_ULT,
OPCODE_COMPARE_ULE,
OPCODE_COMPARE_UGT,
OPCODE_COMPARE_UGE,
OPCODE_DID_CARRY,
OPCODE_DID_OVERFLOW,
OPCODE_DID_SATURATE,
OPCODE_VECTOR_COMPARE_EQ,
OPCODE_VECTOR_COMPARE_SGT,
OPCODE_VECTOR_COMPARE_SGE,
OPCODE_VECTOR_COMPARE_UGT,
OPCODE_VECTOR_COMPARE_UGE,
OPCODE_ADD,
OPCODE_ADD_CARRY,
OPCODE_VECTOR_ADD,
OPCODE_SUB,
OPCODE_VECTOR_SUB,
OPCODE_MUL,
OPCODE_MUL_HI, // TODO(benvanik): remove this and add INT128 type.
OPCODE_DIV,
OPCODE_MUL_ADD,
OPCODE_MUL_SUB,
OPCODE_NEG,
OPCODE_ABS,
OPCODE_SQRT,
OPCODE_RSQRT,
OPCODE_POW2,
OPCODE_LOG2,
OPCODE_DOT_PRODUCT_3,
OPCODE_DOT_PRODUCT_4,
OPCODE_AND,
OPCODE_OR,
OPCODE_XOR,
OPCODE_NOT,
OPCODE_SHL,
OPCODE_VECTOR_SHL,
OPCODE_SHR,
OPCODE_VECTOR_SHR,
OPCODE_SHA,
OPCODE_VECTOR_SHA,
OPCODE_ROTATE_LEFT,
OPCODE_VECTOR_ROTATE_LEFT,
OPCODE_VECTOR_AVERAGE,
OPCODE_BYTE_SWAP,
OPCODE_CNTLZ,
OPCODE_INSERT,
OPCODE_EXTRACT,
OPCODE_SPLAT,
OPCODE_PERMUTE,
OPCODE_SWIZZLE,
OPCODE_PACK,
OPCODE_UNPACK,
OPCODE_COMPARE_EXCHANGE,
OPCODE_ATOMIC_EXCHANGE,
OPCODE_ATOMIC_ADD,
OPCODE_ATOMIC_SUB,
__OPCODE_MAX_VALUE, // Keep at end.
};
enum OpcodeFlags {
OPCODE_FLAG_BRANCH = (1 << 1),
OPCODE_FLAG_MEMORY = (1 << 2),
OPCODE_FLAG_COMMUNATIVE = (1 << 3),
OPCODE_FLAG_VOLATILE = (1 << 4),
OPCODE_FLAG_IGNORE = (1 << 5),
OPCODE_FLAG_HIDE = (1 << 6),
OPCODE_FLAG_PAIRED_PREV = (1 << 7),
};
enum OpcodeSignatureType {
// 3 bits max (0-7)
OPCODE_SIG_TYPE_X = 0,
OPCODE_SIG_TYPE_L = 1,
OPCODE_SIG_TYPE_O = 2,
OPCODE_SIG_TYPE_S = 3,
OPCODE_SIG_TYPE_V = 4,
};
enum OpcodeSignature {
OPCODE_SIG_X = (OPCODE_SIG_TYPE_X),
OPCODE_SIG_X_L = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_L << 3),
OPCODE_SIG_X_O = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3),
OPCODE_SIG_X_O_V =
(OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3) | (OPCODE_SIG_TYPE_V << 6),
OPCODE_SIG_X_O_V_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3) |
(OPCODE_SIG_TYPE_V << 6) | (OPCODE_SIG_TYPE_V << 9),
OPCODE_SIG_X_S = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_S << 3),
OPCODE_SIG_X_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3),
OPCODE_SIG_X_V_L =
(OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_L << 6),
OPCODE_SIG_X_V_L_L = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3) |
(OPCODE_SIG_TYPE_L << 6) | (OPCODE_SIG_TYPE_L << 9),
OPCODE_SIG_X_V_O =
(OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_O << 6),
OPCODE_SIG_X_V_S =
(OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_S << 6),
OPCODE_SIG_X_V_V =
(OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_V << 6),
OPCODE_SIG_X_V_V_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3) |
(OPCODE_SIG_TYPE_V << 6) | (OPCODE_SIG_TYPE_V << 9),
OPCODE_SIG_V = (OPCODE_SIG_TYPE_V),
OPCODE_SIG_V_O = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_O << 3),
OPCODE_SIG_V_V = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3),
OPCODE_SIG_V_V_O =
(OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_O << 6),
OPCODE_SIG_V_V_O_V = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) |
(OPCODE_SIG_TYPE_O << 6) | (OPCODE_SIG_TYPE_V << 9),
OPCODE_SIG_V_V_V =
(OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_V << 6),
OPCODE_SIG_V_V_V_O = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) |
(OPCODE_SIG_TYPE_V << 6) | (OPCODE_SIG_TYPE_O << 9),
OPCODE_SIG_V_V_V_V = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) |
(OPCODE_SIG_TYPE_V << 6) | (OPCODE_SIG_TYPE_V << 9),
};
#define GET_OPCODE_SIG_TYPE_DEST(sig) (OpcodeSignatureType)(sig & 0x7)
#define GET_OPCODE_SIG_TYPE_SRC1(sig) (OpcodeSignatureType)((sig >> 3) & 0x7)
#define GET_OPCODE_SIG_TYPE_SRC2(sig) (OpcodeSignatureType)((sig >> 6) & 0x7)
#define GET_OPCODE_SIG_TYPE_SRC3(sig) (OpcodeSignatureType)((sig >> 9) & 0x7)
typedef struct {
uint32_t flags;
uint32_t signature;
const char* name;
Opcode num;
} OpcodeInfo;
#define DEFINE_OPCODE(num, name, sig, flags) extern const OpcodeInfo num##_info;
#include "xenia/cpu/hir/opcodes.inl"
#undef DEFINE_OPCODE
} // namespace hir
} // namespace cpu
} // namespace xe
#endif // XENIA_HIR_OPCODES_H_

View File

@@ -0,0 +1,636 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
DEFINE_OPCODE(
OPCODE_COMMENT,
"comment",
OPCODE_SIG_X_O,
OPCODE_FLAG_IGNORE)
DEFINE_OPCODE(
OPCODE_NOP,
"nop",
OPCODE_SIG_X,
OPCODE_FLAG_IGNORE)
DEFINE_OPCODE(
OPCODE_SOURCE_OFFSET,
"source_offset",
OPCODE_SIG_X_O,
OPCODE_FLAG_IGNORE | OPCODE_FLAG_HIDE)
DEFINE_OPCODE(
OPCODE_TRACE_SOURCE,
"trace_source",
OPCODE_SIG_X_O_V_V,
OPCODE_FLAG_IGNORE | OPCODE_FLAG_HIDE)
DEFINE_OPCODE(
OPCODE_DEBUG_BREAK,
"debug_break",
OPCODE_SIG_X,
OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_DEBUG_BREAK_TRUE,
"debug_break_true",
OPCODE_SIG_X_V,
OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_TRAP,
"trap",
OPCODE_SIG_X,
OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_TRAP_TRUE,
"trap_true",
OPCODE_SIG_X_V,
OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_CALL,
"call",
OPCODE_SIG_X_S,
OPCODE_FLAG_BRANCH | OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_CALL_TRUE,
"call_true",
OPCODE_SIG_X_V_S,
OPCODE_FLAG_BRANCH | OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_CALL_INDIRECT,
"call_indirect",
OPCODE_SIG_X_V,
OPCODE_FLAG_BRANCH | OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_CALL_INDIRECT_TRUE,
"call_indirect_true",
OPCODE_SIG_X_V_V,
OPCODE_FLAG_BRANCH | OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_CALL_EXTERN,
"call_extern",
OPCODE_SIG_X_S,
OPCODE_FLAG_BRANCH | OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_RETURN,
"return",
OPCODE_SIG_X,
OPCODE_FLAG_BRANCH | OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_RETURN_TRUE,
"return_true",
OPCODE_SIG_X_V,
OPCODE_FLAG_BRANCH | OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_SET_RETURN_ADDRESS,
"set_return_address",
OPCODE_SIG_X_V,
0)
DEFINE_OPCODE(
OPCODE_BRANCH,
"branch",
OPCODE_SIG_X_L,
OPCODE_FLAG_BRANCH)
DEFINE_OPCODE(
OPCODE_BRANCH_TRUE,
"branch_true",
OPCODE_SIG_X_V_L,
OPCODE_FLAG_BRANCH | OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_BRANCH_FALSE,
"branch_false",
OPCODE_SIG_X_V_L,
OPCODE_FLAG_BRANCH | OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_ASSIGN,
"assign",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_CAST,
"cast",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_ZERO_EXTEND,
"zero_extend",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_SIGN_EXTEND,
"sign_extend",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_TRUNCATE,
"truncate",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_CONVERT,
"convert",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_ROUND,
"round",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_CONVERT_I2F,
"vector_convert_i2f",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_CONVERT_F2I,
"vector_convert_f2i",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_LOAD_VECTOR_SHL,
"load_vector_shl",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_LOAD_VECTOR_SHR,
"load_vector_shr",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_LOAD_CLOCK,
"load_clock",
OPCODE_SIG_V,
0)
DEFINE_OPCODE(
OPCODE_LOAD_LOCAL,
"load_local",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_STORE_LOCAL,
"store_local",
OPCODE_SIG_X_V_V,
0)
DEFINE_OPCODE(
OPCODE_LOAD_CONTEXT,
"load_context",
OPCODE_SIG_V_O,
0)
DEFINE_OPCODE(
OPCODE_STORE_CONTEXT,
"store_context",
OPCODE_SIG_X_O_V,
0)
DEFINE_OPCODE(
OPCODE_LOAD,
"load",
OPCODE_SIG_V_V,
OPCODE_FLAG_MEMORY)
DEFINE_OPCODE(
OPCODE_STORE,
"store",
OPCODE_SIG_X_V_V,
OPCODE_FLAG_MEMORY)
DEFINE_OPCODE(
OPCODE_PREFETCH,
"prefetch",
OPCODE_SIG_X_V_O,
0)
DEFINE_OPCODE(
OPCODE_MAX,
"max",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_MAX,
"vector_max",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_MIN,
"min",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_MIN,
"vector_min",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_SELECT,
"select",
OPCODE_SIG_V_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_IS_TRUE,
"is_true",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_IS_FALSE,
"is_false",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_COMPARE_EQ,
"compare_eq",
OPCODE_SIG_V_V_V,
OPCODE_FLAG_COMMUNATIVE)
DEFINE_OPCODE(
OPCODE_COMPARE_NE,
"compare_ne",
OPCODE_SIG_V_V_V,
OPCODE_FLAG_COMMUNATIVE)
DEFINE_OPCODE(
OPCODE_COMPARE_SLT,
"compare_slt",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_COMPARE_SLE,
"compare_sle",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_COMPARE_SGT,
"compare_sgt",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_COMPARE_SGE,
"compare_sge",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_COMPARE_ULT,
"compare_ult",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_COMPARE_ULE,
"compare_ule",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_COMPARE_UGT,
"compare_ugt",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_COMPARE_UGE,
"compare_uge",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_DID_CARRY,
"did_carry",
OPCODE_SIG_V_V,
OPCODE_FLAG_PAIRED_PREV)
DEFINE_OPCODE(
OPCODE_DID_OVERFLOW,
"did_overflow",
OPCODE_SIG_V_V,
OPCODE_FLAG_PAIRED_PREV)
DEFINE_OPCODE(
OPCODE_DID_SATURATE,
"did_saturate",
OPCODE_SIG_V_V,
OPCODE_FLAG_PAIRED_PREV)
DEFINE_OPCODE(
OPCODE_VECTOR_COMPARE_EQ,
"vector_compare_eq",
OPCODE_SIG_V_V_V,
OPCODE_FLAG_COMMUNATIVE)
DEFINE_OPCODE(
OPCODE_VECTOR_COMPARE_SGT,
"vector_compare_sgt",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_COMPARE_SGE,
"vector_compare_sge",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_COMPARE_UGT,
"vector_compare_ugt",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_COMPARE_UGE,
"vector_compare_uge",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_ADD,
"add",
OPCODE_SIG_V_V_V,
OPCODE_FLAG_COMMUNATIVE)
DEFINE_OPCODE(
OPCODE_ADD_CARRY,
"add_carry",
OPCODE_SIG_V_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_ADD,
"vector_add",
OPCODE_SIG_V_V_V,
OPCODE_FLAG_COMMUNATIVE)
DEFINE_OPCODE(
OPCODE_SUB,
"sub",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_SUB,
"vector_sub",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_MUL,
"mul",
OPCODE_SIG_V_V_V,
OPCODE_FLAG_COMMUNATIVE)
DEFINE_OPCODE(
OPCODE_MUL_HI,
"mul_hi",
OPCODE_SIG_V_V_V,
OPCODE_FLAG_COMMUNATIVE)
DEFINE_OPCODE(
OPCODE_DIV,
"div",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_MUL_ADD,
"mul_add",
OPCODE_SIG_V_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_MUL_SUB,
"mul_sub",
OPCODE_SIG_V_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_NEG,
"neg",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_ABS,
"abs",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_SQRT,
"sqrt",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_RSQRT,
"rsqrt",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_POW2,
"pow2",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_LOG2,
"log2",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_DOT_PRODUCT_3,
"dot_product_3",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_DOT_PRODUCT_4,
"dot_product_4",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_AND,
"and",
OPCODE_SIG_V_V_V,
OPCODE_FLAG_COMMUNATIVE)
DEFINE_OPCODE(
OPCODE_OR,
"or",
OPCODE_SIG_V_V_V,
OPCODE_FLAG_COMMUNATIVE)
DEFINE_OPCODE(
OPCODE_XOR,
"xor",
OPCODE_SIG_V_V_V,
OPCODE_FLAG_COMMUNATIVE)
DEFINE_OPCODE(
OPCODE_NOT,
"not",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_SHL,
"shl",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_SHL,
"vector_shl",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_SHR,
"shr",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_SHR,
"vector_shr",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_SHA,
"sha",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_SHA,
"vector_sha",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_ROTATE_LEFT,
"rotate_left",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_ROTATE_LEFT,
"vector_rotate_left",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_VECTOR_AVERAGE,
"vector_average",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_BYTE_SWAP,
"byte_swap",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_CNTLZ,
"cntlz",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_INSERT,
"insert",
OPCODE_SIG_V_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_EXTRACT,
"extract",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_SPLAT,
"splat",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_PERMUTE,
"permute",
OPCODE_SIG_V_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_SWIZZLE,
"swizzle",
OPCODE_SIG_V_V_O,
0)
DEFINE_OPCODE(
OPCODE_PACK,
"pack",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_UNPACK,
"unpack",
OPCODE_SIG_V_V,
0)
DEFINE_OPCODE(
OPCODE_COMPARE_EXCHANGE,
"compare_exchange",
OPCODE_SIG_V_V_V_V,
OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_ATOMIC_EXCHANGE,
"atomic_exchange",
OPCODE_SIG_V_V_V,
OPCODE_FLAG_VOLATILE)
DEFINE_OPCODE(
OPCODE_ATOMIC_ADD,
"atomic_add",
OPCODE_SIG_V_V_V,
0)
DEFINE_OPCODE(
OPCODE_ATOMIC_SUB,
"atomic_sub",
OPCODE_SIG_V_V_V,
0)

View File

@@ -0,0 +1,17 @@
# Copyright 2013 Ben Vanik. All Rights Reserved.
{
'sources': [
'block.cc',
'block.h',
'hir_builder.cc',
'hir_builder.h',
'instr.cc',
'instr.h',
'label.h',
'opcodes.cc',
'opcodes.h',
'opcodes.inl',
'value.cc',
'value.h',
],
}

623
src/xenia/cpu/hir/value.cc Normal file
View File

@@ -0,0 +1,623 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
#include "xenia/cpu/hir/value.h"
#include <cmath>
namespace xe {
namespace cpu {
namespace hir {
Value::Use* Value::AddUse(poly::Arena* arena, Instr* instr) {
Use* use = arena->Alloc<Use>();
use->instr = instr;
use->prev = NULL;
use->next = use_head;
if (use_head) {
use_head->prev = use;
}
use_head = use;
return use;
}
void Value::RemoveUse(Use* use) {
if (use == use_head) {
use_head = use->next;
} else {
use->prev->next = use->next;
}
if (use->next) {
use->next->prev = use->prev;
}
}
uint32_t Value::AsUint32() {
assert_true(IsConstant());
switch (type) {
case INT8_TYPE:
return constant.i8;
case INT16_TYPE:
return constant.i16;
case INT32_TYPE:
return constant.i32;
case INT64_TYPE:
return (uint32_t)constant.i64;
default:
assert_unhandled_case(type);
return 0;
}
}
uint64_t Value::AsUint64() {
assert_true(IsConstant());
switch (type) {
case INT8_TYPE:
return constant.i8;
case INT16_TYPE:
return constant.i16;
case INT32_TYPE:
return constant.i32;
case INT64_TYPE:
return constant.i64;
default:
assert_unhandled_case(type);
return 0;
}
}
void Value::Cast(TypeName target_type) {
// TODO(benvanik): big matrix.
assert_always();
}
void Value::ZeroExtend(TypeName target_type) {
switch (type) {
case INT8_TYPE:
type = target_type;
constant.i64 = constant.i64 & 0xFF;
return;
case INT16_TYPE:
type = target_type;
constant.i64 = constant.i64 & 0xFFFF;
return;
case INT32_TYPE:
type = target_type;
constant.i64 = constant.i64 & 0xFFFFFFFF;
return;
default:
assert_unhandled_case(type);
break;
}
}
void Value::SignExtend(TypeName target_type) {
switch (type) {
case INT8_TYPE:
type = target_type;
switch (target_type) {
case INT16_TYPE:
constant.i16 = constant.i8;
return;
case INT32_TYPE:
constant.i32 = constant.i8;
return;
case INT64_TYPE:
constant.i64 = constant.i8;
return;
default:
assert_unhandled_case(target_type);
return;
}
case INT16_TYPE:
type = target_type;
switch (target_type) {
case INT32_TYPE:
constant.i32 = constant.i16;
return;
case INT64_TYPE:
constant.i64 = constant.i16;
return;
default:
assert_unhandled_case(target_type);
return;
}
case INT32_TYPE:
type = target_type;
switch (target_type) {
case INT64_TYPE:
constant.i64 = constant.i32;
return;
default:
assert_unhandled_case(target_type);
return;
}
default:
assert_unhandled_case(type);
return;
}
}
void Value::Truncate(TypeName target_type) {
switch (type) {
case INT16_TYPE:
switch (target_type) {
case INT8_TYPE:
type = target_type;
constant.i64 = constant.i64 & 0xFF;
return;
default:
assert_unhandled_case(target_type);
return;
}
case INT32_TYPE:
switch (target_type) {
case INT8_TYPE:
type = target_type;
constant.i64 = constant.i64 & 0xFF;
return;
case INT16_TYPE:
type = target_type;
constant.i64 = constant.i64 & 0xFFFF;
return;
default:
assert_unhandled_case(target_type);
return;
}
case INT64_TYPE:
switch (target_type) {
case INT8_TYPE:
type = target_type;
constant.i64 = constant.i64 & 0xFF;
return;
case INT16_TYPE:
type = target_type;
constant.i64 = constant.i64 & 0xFFFF;
return;
case INT32_TYPE:
type = target_type;
constant.i64 = constant.i64 & 0xFFFFFFFF;
return;
default:
assert_unhandled_case(target_type);
return;
}
default:
assert_unhandled_case(type);
return;
}
}
void Value::Convert(TypeName target_type, RoundMode round_mode) {
// TODO(benvanik): big matrix.
assert_always();
}
void Value::Round(RoundMode round_mode) {
// TODO(benvanik): big matrix.
assert_always();
}
bool Value::Add(Value* other) {
#define CHECK_DID_CARRY(v1, v2) (((uint64_t)v2) > ~((uint64_t)v1))
#define ADD_DID_CARRY(a, b) CHECK_DID_CARRY(a, b)
assert_true(type == other->type);
bool did_carry = false;
switch (type) {
case INT8_TYPE:
did_carry = ADD_DID_CARRY(constant.i8, other->constant.i8);
constant.i8 += other->constant.i8;
break;
case INT16_TYPE:
did_carry = ADD_DID_CARRY(constant.i16, other->constant.i16);
constant.i16 += other->constant.i16;
break;
case INT32_TYPE:
did_carry = ADD_DID_CARRY(constant.i32, other->constant.i32);
constant.i32 += other->constant.i32;
break;
case INT64_TYPE:
did_carry = ADD_DID_CARRY(constant.i64, other->constant.i64);
constant.i64 += other->constant.i64;
break;
case FLOAT32_TYPE:
constant.f32 += other->constant.f32;
break;
case FLOAT64_TYPE:
constant.f64 += other->constant.f64;
break;
default:
assert_unhandled_case(type);
break;
}
return did_carry;
}
bool Value::Sub(Value* other) {
#define SUB_DID_CARRY(a, b) (b > a)
assert_true(type == other->type);
bool did_carry = false;
switch (type) {
case INT8_TYPE:
did_carry = SUB_DID_CARRY(constant.i8, other->constant.i8);
constant.i8 -= other->constant.i8;
break;
case INT16_TYPE:
did_carry = SUB_DID_CARRY(constant.i16, other->constant.i16);
constant.i16 -= other->constant.i16;
break;
case INT32_TYPE:
did_carry = SUB_DID_CARRY(constant.i32, other->constant.i32);
constant.i32 -= other->constant.i32;
break;
case INT64_TYPE:
did_carry = SUB_DID_CARRY(constant.i64, other->constant.i64);
constant.i64 -= other->constant.i64;
break;
case FLOAT32_TYPE:
constant.f32 -= other->constant.f32;
break;
case FLOAT64_TYPE:
constant.f64 -= other->constant.f64;
break;
default:
assert_unhandled_case(type);
break;
}
return did_carry;
}
void Value::Mul(Value* other) {
assert_true(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 *= other->constant.i8;
break;
case INT16_TYPE:
constant.i16 *= other->constant.i16;
break;
case INT32_TYPE:
constant.i32 *= other->constant.i32;
break;
case INT64_TYPE:
constant.i64 *= other->constant.i64;
break;
case FLOAT32_TYPE:
constant.f32 *= other->constant.f32;
break;
case FLOAT64_TYPE:
constant.f64 *= other->constant.f64;
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::Div(Value* other) {
assert_true(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 /= other->constant.i8;
break;
case INT16_TYPE:
constant.i16 /= other->constant.i16;
break;
case INT32_TYPE:
constant.i32 /= other->constant.i32;
break;
case INT64_TYPE:
constant.i64 /= other->constant.i64;
break;
case FLOAT32_TYPE:
constant.f32 /= other->constant.f32;
break;
case FLOAT64_TYPE:
constant.f64 /= other->constant.f64;
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::MulAdd(Value* dest, Value* value1, Value* value2, Value* value3) {
// TODO(benvanik): big matrix.
assert_always();
}
void Value::MulSub(Value* dest, Value* value1, Value* value2, Value* value3) {
// TODO(benvanik): big matrix.
assert_always();
}
void Value::Neg() {
switch (type) {
case INT8_TYPE:
constant.i8 = -constant.i8;
break;
case INT16_TYPE:
constant.i16 = -constant.i16;
break;
case INT32_TYPE:
constant.i32 = -constant.i32;
break;
case INT64_TYPE:
constant.i64 = -constant.i64;
break;
case FLOAT32_TYPE:
constant.f32 = -constant.f32;
break;
case FLOAT64_TYPE:
constant.f64 = -constant.f64;
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::Abs() {
switch (type) {
case INT8_TYPE:
constant.i8 = abs(constant.i8);
break;
case INT16_TYPE:
constant.i16 = abs(constant.i16);
break;
case INT32_TYPE:
constant.i32 = abs(constant.i32);
break;
case INT64_TYPE:
constant.i64 = abs(constant.i64);
break;
case FLOAT32_TYPE:
constant.f32 = abs(constant.f32);
break;
case FLOAT64_TYPE:
constant.f64 = abs(constant.f64);
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::Sqrt() {
switch (type) {
case FLOAT32_TYPE:
constant.f32 = 1.0f / sqrtf(constant.f32);
break;
case FLOAT64_TYPE:
constant.f64 = 1.0 / sqrt(constant.f64);
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::RSqrt() {
switch (type) {
case FLOAT32_TYPE:
constant.f32 = sqrt(constant.f32);
break;
case FLOAT64_TYPE:
constant.f64 = sqrt(constant.f64);
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::And(Value* other) {
assert_true(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 &= other->constant.i8;
break;
case INT16_TYPE:
constant.i16 &= other->constant.i16;
break;
case INT32_TYPE:
constant.i32 &= other->constant.i32;
break;
case INT64_TYPE:
constant.i64 &= other->constant.i64;
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::Or(Value* other) {
assert_true(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 |= other->constant.i8;
break;
case INT16_TYPE:
constant.i16 |= other->constant.i16;
break;
case INT32_TYPE:
constant.i32 |= other->constant.i32;
break;
case INT64_TYPE:
constant.i64 |= other->constant.i64;
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::Xor(Value* other) {
assert_true(type == other->type);
switch (type) {
case INT8_TYPE:
constant.i8 ^= other->constant.i8;
break;
case INT16_TYPE:
constant.i16 ^= other->constant.i16;
break;
case INT32_TYPE:
constant.i32 ^= other->constant.i32;
break;
case INT64_TYPE:
constant.i64 ^= other->constant.i64;
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::Not() {
switch (type) {
case INT8_TYPE:
constant.i8 = ~constant.i8;
break;
case INT16_TYPE:
constant.i16 = ~constant.i16;
break;
case INT32_TYPE:
constant.i32 = ~constant.i32;
break;
case INT64_TYPE:
constant.i64 = ~constant.i64;
break;
case VEC128_TYPE:
constant.v128.low = ~constant.v128.low;
constant.v128.high = ~constant.v128.high;
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::Shl(Value* other) {
assert_true(other->type == INT8_TYPE);
switch (type) {
case INT8_TYPE:
constant.i8 <<= other->constant.i8;
break;
case INT16_TYPE:
constant.i16 <<= other->constant.i8;
break;
case INT32_TYPE:
constant.i32 <<= other->constant.i8;
break;
case INT64_TYPE:
constant.i64 <<= other->constant.i8;
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::Shr(Value* other) {
assert_true(other->type == INT8_TYPE);
switch (type) {
case INT8_TYPE:
constant.i8 = (uint8_t)constant.i8 >> other->constant.i8;
break;
case INT16_TYPE:
constant.i16 = (uint16_t)constant.i16 >> other->constant.i8;
break;
case INT32_TYPE:
constant.i32 = (uint32_t)constant.i32 >> other->constant.i8;
break;
case INT64_TYPE:
constant.i64 = (uint16_t)constant.i64 >> other->constant.i8;
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::Sha(Value* other) {
assert_true(other->type == INT8_TYPE);
switch (type) {
case INT8_TYPE:
constant.i8 = constant.i8 >> other->constant.i8;
break;
case INT16_TYPE:
constant.i16 = constant.i16 >> other->constant.i8;
break;
case INT32_TYPE:
constant.i32 = constant.i32 >> other->constant.i8;
break;
case INT64_TYPE:
constant.i64 = constant.i64 >> other->constant.i8;
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::ByteSwap() {
switch (type) {
case INT8_TYPE:
constant.i8 = constant.i8;
break;
case INT16_TYPE:
constant.i16 = poly::byte_swap(constant.i16);
break;
case INT32_TYPE:
constant.i32 = poly::byte_swap(constant.i32);
break;
case INT64_TYPE:
constant.i64 = poly::byte_swap(constant.i64);
break;
case VEC128_TYPE:
for (int n = 0; n < 4; n++) {
constant.v128.u32[n] = poly::byte_swap(constant.v128.u32[n]);
}
break;
default:
assert_unhandled_case(type);
break;
}
}
void Value::CountLeadingZeros(const Value* other) {
switch (other->type) {
case INT8_TYPE:
constant.i8 = poly::lzcnt(constant.i8);
break;
case INT16_TYPE:
constant.i8 = poly::lzcnt(constant.i16);
break;
case INT32_TYPE:
constant.i8 = poly::lzcnt(constant.i32);
break;
case INT64_TYPE:
constant.i8 = poly::lzcnt(constant.i64);
break;
default:
assert_unhandled_case(type);
break;
}
}
bool Value::Compare(Opcode opcode, Value* other) {
// TODO(benvanik): big matrix.
assert_always();
return false;
}
} // namespace hir
} // namespace cpu
} // namespace xe

411
src/xenia/cpu/hir/value.h Normal file
View File

@@ -0,0 +1,411 @@
/**
******************************************************************************
* 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_HIR_VALUE_H_
#define XENIA_HIR_VALUE_H_
#include "xenia/cpu/backend/machine_info.h"
#include "xenia/cpu/hir/opcodes.h"
#include "poly/arena.h"
#include "poly/poly.h"
#include "poly/vec128.h"
namespace xe {
namespace cpu {
namespace hir {
class Instr;
using vec128_t = poly::vec128_t;
enum TypeName {
// Many tables rely on this ordering.
INT8_TYPE = 0,
INT16_TYPE = 1,
INT32_TYPE = 2,
INT64_TYPE = 3,
FLOAT32_TYPE = 4,
FLOAT64_TYPE = 5,
VEC128_TYPE = 6,
MAX_TYPENAME,
};
inline size_t GetTypeSize(TypeName type_name) {
switch (type_name) {
case INT8_TYPE:
return 1;
case INT16_TYPE:
return 2;
case INT32_TYPE:
return 4;
case INT64_TYPE:
return 8;
case FLOAT32_TYPE:
return 4;
case FLOAT64_TYPE:
return 8;
case VEC128_TYPE:
return 16;
default:
assert_unhandled_case(type_name);
return 0;
}
}
enum ValueFlags {
VALUE_IS_CONSTANT = (1 << 1),
VALUE_IS_ALLOCATED = (1 << 2), // Used by backends. Do not set.
};
struct RegAssignment {
const backend::MachineInfo::RegisterSet* set;
int32_t index;
};
class Value {
public:
typedef struct Use_s {
Instr* instr;
Use_s* prev;
Use_s* next;
} Use;
typedef union {
int8_t i8;
int16_t i16;
int32_t i32;
int64_t i64;
float f32;
double f64;
vec128_t v128;
} ConstantValue;
public:
uint32_t ordinal;
TypeName type;
uint32_t flags;
RegAssignment reg;
ConstantValue constant;
Instr* def;
Use* use_head;
// NOTE: for performance reasons this is not maintained during construction.
Instr* last_use;
Value* local_slot;
// TODO(benvanik): remove to shrink size.
void* tag;
Use* AddUse(poly::Arena* arena, Instr* instr);
void RemoveUse(Use* use);
int8_t get_constant(int8_t) const { return constant.i8; }
int16_t get_constant(int16_t) const { return constant.i16; }
int32_t get_constant(int32_t) const { return constant.i32; }
int64_t get_constant(int64_t) const { return constant.i64; }
float get_constant(float) const { return constant.f32; }
double get_constant(double) const { return constant.f64; }
vec128_t get_constant(vec128_t&) const { return constant.v128; }
void set_zero(TypeName type) {
this->type = type;
flags |= VALUE_IS_CONSTANT;
constant.v128.low = constant.v128.high = 0;
}
void set_constant(int8_t value) {
type = INT8_TYPE;
flags |= VALUE_IS_CONSTANT;
constant.i8 = value;
}
void set_constant(uint8_t value) {
type = INT8_TYPE;
flags |= VALUE_IS_CONSTANT;
constant.i8 = value;
}
void set_constant(int16_t value) {
type = INT16_TYPE;
flags |= VALUE_IS_CONSTANT;
constant.i16 = value;
}
void set_constant(uint16_t value) {
type = INT16_TYPE;
flags |= VALUE_IS_CONSTANT;
constant.i16 = value;
}
void set_constant(int32_t value) {
type = INT32_TYPE;
flags |= VALUE_IS_CONSTANT;
constant.i32 = value;
}
void set_constant(uint32_t value) {
type = INT32_TYPE;
flags |= VALUE_IS_CONSTANT;
constant.i32 = value;
}
void set_constant(int64_t value) {
type = INT64_TYPE;
flags |= VALUE_IS_CONSTANT;
constant.i64 = value;
}
void set_constant(uint64_t value) {
type = INT64_TYPE;
flags |= VALUE_IS_CONSTANT;
constant.i64 = value;
}
void set_constant(float value) {
type = FLOAT32_TYPE;
flags |= VALUE_IS_CONSTANT;
constant.f32 = value;
}
void set_constant(double value) {
type = FLOAT64_TYPE;
flags |= VALUE_IS_CONSTANT;
constant.f64 = value;
}
void set_constant(const vec128_t& value) {
type = VEC128_TYPE;
flags |= VALUE_IS_CONSTANT;
constant.v128 = value;
}
void set_from(const Value* other) {
type = other->type;
flags = other->flags;
constant.v128 = other->constant.v128;
}
inline bool IsConstant() const { return !!(flags & VALUE_IS_CONSTANT); }
bool IsConstantTrue() const {
if (type == VEC128_TYPE) {
assert_always();
}
return (flags & VALUE_IS_CONSTANT) && !!constant.i64;
}
bool IsConstantFalse() const {
if (type == VEC128_TYPE) {
assert_always();
}
return (flags & VALUE_IS_CONSTANT) && !constant.i64;
}
bool IsConstantZero() const {
if (type == VEC128_TYPE) {
return (flags & VALUE_IS_CONSTANT) && !constant.v128.low &&
!constant.v128.high;
}
return (flags & VALUE_IS_CONSTANT) && !constant.i64;
}
bool IsConstantEQ(Value* other) const {
if (type == VEC128_TYPE) {
assert_always();
}
return (flags & VALUE_IS_CONSTANT) && (other->flags & VALUE_IS_CONSTANT) &&
constant.i64 == other->constant.i64;
}
bool IsConstantNE(Value* other) const {
if (type == VEC128_TYPE) {
assert_always();
}
return (flags & VALUE_IS_CONSTANT) && (other->flags & VALUE_IS_CONSTANT) &&
constant.i64 != other->constant.i64;
}
bool IsConstantSLT(Value* other) const {
assert_true(flags & VALUE_IS_CONSTANT && other->flags & VALUE_IS_CONSTANT);
switch (type) {
case INT8_TYPE:
return constant.i8 < other->constant.i8;
case INT16_TYPE:
return constant.i16 < other->constant.i16;
case INT32_TYPE:
return constant.i32 < other->constant.i32;
case INT64_TYPE:
return constant.i64 < other->constant.i64;
case FLOAT32_TYPE:
return constant.f32 < other->constant.f32;
case FLOAT64_TYPE:
return constant.f64 < other->constant.f64;
default:
assert_always();
return false;
}
}
bool IsConstantSLE(Value* other) const {
assert_true(flags & VALUE_IS_CONSTANT && other->flags & VALUE_IS_CONSTANT);
switch (type) {
case INT8_TYPE:
return constant.i8 <= other->constant.i8;
case INT16_TYPE:
return constant.i16 <= other->constant.i16;
case INT32_TYPE:
return constant.i32 <= other->constant.i32;
case INT64_TYPE:
return constant.i64 <= other->constant.i64;
case FLOAT32_TYPE:
return constant.f32 <= other->constant.f32;
case FLOAT64_TYPE:
return constant.f64 <= other->constant.f64;
default:
assert_always();
return false;
}
}
bool IsConstantSGT(Value* other) const {
assert_true(flags & VALUE_IS_CONSTANT && other->flags & VALUE_IS_CONSTANT);
switch (type) {
case INT8_TYPE:
return constant.i8 > other->constant.i8;
case INT16_TYPE:
return constant.i16 > other->constant.i16;
case INT32_TYPE:
return constant.i32 > other->constant.i32;
case INT64_TYPE:
return constant.i64 > other->constant.i64;
case FLOAT32_TYPE:
return constant.f32 > other->constant.f32;
case FLOAT64_TYPE:
return constant.f64 > other->constant.f64;
default:
assert_always();
return false;
}
}
bool IsConstantSGE(Value* other) const {
assert_true(flags & VALUE_IS_CONSTANT && other->flags & VALUE_IS_CONSTANT);
switch (type) {
case INT8_TYPE:
return constant.i8 >= other->constant.i8;
case INT16_TYPE:
return constant.i16 >= other->constant.i16;
case INT32_TYPE:
return constant.i32 >= other->constant.i32;
case INT64_TYPE:
return constant.i64 >= other->constant.i64;
case FLOAT32_TYPE:
return constant.f32 >= other->constant.f32;
case FLOAT64_TYPE:
return constant.f64 >= other->constant.f64;
default:
assert_always();
return false;
}
}
bool IsConstantULT(Value* other) const {
assert_true(flags & VALUE_IS_CONSTANT && other->flags & VALUE_IS_CONSTANT);
switch (type) {
case INT8_TYPE:
return (uint8_t)constant.i8 < (uint8_t)other->constant.i8;
case INT16_TYPE:
return (uint16_t)constant.i16 < (uint16_t)other->constant.i16;
case INT32_TYPE:
return (uint32_t)constant.i32 < (uint32_t)other->constant.i32;
case INT64_TYPE:
return (uint64_t)constant.i64 < (uint64_t)other->constant.i64;
case FLOAT32_TYPE:
return constant.f32 < other->constant.f32;
case FLOAT64_TYPE:
return constant.f64 < other->constant.f64;
default:
assert_always();
return false;
}
}
bool IsConstantULE(Value* other) const {
assert_true(flags & VALUE_IS_CONSTANT && other->flags & VALUE_IS_CONSTANT);
switch (type) {
case INT8_TYPE:
return (uint8_t)constant.i8 <= (uint8_t)other->constant.i8;
case INT16_TYPE:
return (uint16_t)constant.i16 <= (uint16_t)other->constant.i16;
case INT32_TYPE:
return (uint32_t)constant.i32 <= (uint32_t)other->constant.i32;
case INT64_TYPE:
return (uint64_t)constant.i64 <= (uint64_t)other->constant.i64;
case FLOAT32_TYPE:
return constant.f32 <= other->constant.f32;
case FLOAT64_TYPE:
return constant.f64 <= other->constant.f64;
default:
assert_always();
return false;
}
}
bool IsConstantUGT(Value* other) const {
assert_true(flags & VALUE_IS_CONSTANT && other->flags & VALUE_IS_CONSTANT);
switch (type) {
case INT8_TYPE:
return (uint8_t)constant.i8 > (uint8_t)other->constant.i8;
case INT16_TYPE:
return (uint16_t)constant.i16 > (uint16_t)other->constant.i16;
case INT32_TYPE:
return (uint32_t)constant.i32 > (uint32_t)other->constant.i32;
case INT64_TYPE:
return (uint64_t)constant.i64 > (uint64_t)other->constant.i64;
case FLOAT32_TYPE:
return constant.f32 > other->constant.f32;
case FLOAT64_TYPE:
return constant.f64 > other->constant.f64;
default:
assert_always();
return false;
}
}
bool IsConstantUGE(Value* other) const {
assert_true(flags & VALUE_IS_CONSTANT && other->flags & VALUE_IS_CONSTANT);
switch (type) {
case INT8_TYPE:
return (uint8_t)constant.i8 >= (uint8_t)other->constant.i8;
case INT16_TYPE:
return (uint16_t)constant.i16 >= (uint16_t)other->constant.i16;
case INT32_TYPE:
return (uint32_t)constant.i32 >= (uint32_t)other->constant.i32;
case INT64_TYPE:
return (uint64_t)constant.i64 >= (uint64_t)other->constant.i64;
case FLOAT32_TYPE:
return constant.f32 >= other->constant.f32;
case FLOAT64_TYPE:
return constant.f64 >= other->constant.f64;
default:
assert_always();
return false;
}
}
uint32_t AsUint32();
uint64_t AsUint64();
void Cast(TypeName target_type);
void ZeroExtend(TypeName target_type);
void SignExtend(TypeName target_type);
void Truncate(TypeName target_type);
void Convert(TypeName target_type, RoundMode round_mode);
void Round(RoundMode round_mode);
bool Add(Value* other);
bool Sub(Value* other);
void Mul(Value* other);
void Div(Value* other);
static void MulAdd(Value* dest, Value* value1, Value* value2, Value* value3);
static void MulSub(Value* dest, Value* value1, Value* value2, Value* value3);
void Neg();
void Abs();
void Sqrt();
void RSqrt();
void And(Value* other);
void Or(Value* other);
void Xor(Value* other);
void Not();
void Shl(Value* other);
void Shr(Value* other);
void Sha(Value* other);
void ByteSwap();
void CountLeadingZeros(const Value* other);
bool Compare(Opcode opcode, Value* other);
};
} // namespace hir
} // namespace cpu
} // namespace xe
#endif // XENIA_HIR_VALUE_H_