Fixed a bug with readback_resolve and readback_memexport that was responsible for a large portion of their overhead. readback_memexport and resolve are now usable for games, depending on your hardware. in my case games that were slideshows now run at like 20-30 fps, and my hardware isnt the best for xenia.

add split_map class for mapping keys to values in a way that optimizes for frequent searches and infrequent insertions/removals
remove jump table implementation of GetColorRenderTargetFormatComponentCount, it was appearing relatively high in profiles. instead pack the component counts into a single 32 bit word, which is indexed by shifting
Add cvar to align all basic blocks to a boundary
Add mmio aware load paths
liberally apply XE_RESTRICT in ringbuffer related code
Removed the IS_TRUE and IS_FALSE opcodes, they were pointless duplicates of COMPARE_EQ/COMPARE_NE and i want to simplify our set of opcodes for future backends
More work on LVSR/LVSL/STVR/STVL opcodes
Optimized X64 translated code emission, now only compute instrkey once
Add code for pre-computing integer division magic numbers
Optimized GetHostViewportInfo a little
Move args for GetHostViewportInfo into a class, cache the result and compare for future queries. moved GetHostViewportInfo far lower on the profile
Add (currently not functional, and very racy) asynchronous memcpy code. will improve it and actually use it in future commits.
Add non-temporal memcpy function for huge page-aligned allocations. Used for copying to shared memory/readback
hoist are_accumulated_render_targets_valid_ check out of loop in render_target_cache already bound check.
Add stosb/movsb code for small constant memcpys/memsets that arent worth the overhead of memcpy/memset
This commit is contained in:
chss95cs@gmail.com
2022-08-28 14:24:25 -07:00
parent 335a390d43
commit f31869092c
32 changed files with 1576 additions and 507 deletions

View File

@@ -1023,7 +1023,6 @@ Value* HIRBuilder::Truncate(Value* value, TypeName target_type) {
Value* HIRBuilder::Convert(Value* value, TypeName target_type,
RoundMode round_mode) {
Instr* i =
AppendInstr(OPCODE_CONVERT_info, round_mode, AllocValue(target_type));
i->set_src1(value);
@@ -1034,7 +1033,6 @@ Value* HIRBuilder::Convert(Value* value, TypeName target_type,
Value* HIRBuilder::Round(Value* value, RoundMode round_mode) {
ASSERT_FLOAT_OR_VECTOR_TYPE(value);
Instr* i =
AppendInstr(OPCODE_ROUND_info, round_mode, AllocValue(value->type));
i->set_src1(value);
@@ -1248,7 +1246,34 @@ void HIRBuilder::Store(Value* address, Value* value, uint32_t store_flags) {
i->set_src2(value);
i->src3.value = NULL;
}
Value* HIRBuilder::LoadVectorLeft(Value* address) {
ASSERT_ADDRESS_TYPE(address);
Instr* i = AppendInstr(OPCODE_LVL_info, 0, AllocValue(VEC128_TYPE));
i->set_src1(address);
i->src2.value = i->src3.value = NULL;
return i->dest;
}
Value* HIRBuilder::LoadVectorRight(Value* address) {
ASSERT_ADDRESS_TYPE(address);
Instr* i = AppendInstr(OPCODE_LVR_info, 0, AllocValue(VEC128_TYPE));
i->set_src1(address);
i->src2.value = i->src3.value = NULL;
return i->dest;
}
void HIRBuilder::StoreVectorLeft(Value* address, Value* value) {
ASSERT_ADDRESS_TYPE(address);
Instr* i = AppendInstr(OPCODE_STVL_info, 0);
i->set_src1(address);
i->set_src2(value);
i->src3.value = NULL;
}
void HIRBuilder::StoreVectorRight(Value* address, Value* value) {
ASSERT_ADDRESS_TYPE(address);
Instr* i = AppendInstr(OPCODE_STVR_info, 0);
i->set_src1(address);
i->set_src2(value);
i->src3.value = NULL;
}
void HIRBuilder::Memset(Value* address, Value* value, Value* length) {
ASSERT_ADDRESS_TYPE(address);
ASSERT_TYPES_EQUAL(address, length);
@@ -1283,7 +1308,7 @@ void HIRBuilder::SetNJM(Value* value) {
Value* HIRBuilder::Max(Value* value1, Value* value2) {
ASSERT_TYPES_EQUAL(value1, value2);
if (IsScalarIntegralType( value1->type) && value1->IsConstant() &&
if (IsScalarIntegralType(value1->type) && value1->IsConstant() &&
value2->IsConstant()) {
return value1->Compare(OPCODE_COMPARE_SLT, value2) ? value2 : value1;
}
@@ -1351,27 +1376,51 @@ Value* HIRBuilder::Select(Value* cond, Value* value1, Value* value2) {
i->set_src3(value2);
return i->dest;
}
static Value* OrLanes32(HIRBuilder& f, Value* value) {
hir::Value* v1 = f.Extract(value, (uint8_t)0, INT32_TYPE);
hir::Value* v2 = f.Extract(value, (uint8_t)1, INT32_TYPE);
hir::Value* v3 = f.Extract(value, (uint8_t)2, INT32_TYPE);
hir::Value* ored = f.Or(v1, v2);
hir::Value* v4 = f.Extract(value, (uint8_t)3, INT32_TYPE);
ored = f.Or(ored, v3);
ored = f.Or(ored, v4);
return ored;
}
Value* HIRBuilder::IsTrue(Value* value) {
assert_true(value);
if (value->type == VEC128_TYPE) {
// chrispy: this probably doesnt happen often enough to be worth its own
// opcode or special code path but this could be optimized to not require as
// many extracts, we can shuffle and or v128 and then extract the low
return CompareEQ(OrLanes32(*this, value), LoadZeroInt32());
}
if (value->IsConstant()) {
return LoadConstantInt8(value->IsConstantTrue() ? 1 : 0);
}
Instr* i = AppendInstr(OPCODE_IS_TRUE_info, 0, AllocValue(INT8_TYPE));
i->set_src1(value);
i->src2.value = i->src3.value = NULL;
return i->dest;
return CompareNE(value, LoadZero(value->type));
}
Value* HIRBuilder::IsFalse(Value* value) {
assert_true(value);
if (value->type == VEC128_TYPE) {
// chrispy: this probably doesnt happen often enough to be worth its own
// opcode or special code path but this could be optimized to not require as
// many extracts, we can shuffle and or v128 and then extract the low
return CompareEQ(OrLanes32(*this, value), LoadZeroInt32());
}
if (value->IsConstant()) {
return LoadConstantInt8(value->IsConstantFalse() ? 1 : 0);
}
Instr* i = AppendInstr(OPCODE_IS_FALSE_info, 0, AllocValue(INT8_TYPE));
i->set_src1(value);
i->src2.value = i->src3.value = NULL;
return i->dest;
return CompareEQ(value, LoadZero(value->type));
}
Value* HIRBuilder::IsNan(Value* value) {

View File

@@ -166,6 +166,11 @@ class HIRBuilder {
uint32_t store_flags = 0);
Value* Load(Value* address, TypeName type, uint32_t load_flags = 0);
Value* LoadVectorLeft(Value* address);
Value* LoadVectorRight(Value* address);
void StoreVectorLeft(Value* address, Value* value);
void StoreVectorRight(Value* address, Value* value);
void Store(Value* address, Value* value, uint32_t store_flags = 0);
void Memset(Value* address, Value* value, Value* length);
void CacheControl(Value* address, size_t cache_line_size,
@@ -268,6 +273,7 @@ class HIRBuilder {
Value* new_value);
Value* AtomicAdd(Value* address, Value* value);
Value* AtomicSub(Value* address, Value* value);
void SetNJM(Value* value);
protected:

View File

@@ -213,7 +213,19 @@ uint32_t Instr::GuestAddressFor() const {
return 0; // eek.
}
bool Instr::AllScalarIntegral() {
bool result = true;
if (dest) {
if (!IsScalarIntegralType(dest->type)) {
return false;
}
}
VisitValueOperands([&result](Value* v, uint32_t idx) {
result = result && IsScalarIntegralType(v->type);
});
return result;
}
} // namespace hir
} // namespace cpu
} // namespace xe

View File

@@ -171,6 +171,8 @@ if both are constant, return nullptr, nullptr
const hir::Instr* GetNonFakePrev() const;
uint32_t GuestAddressFor() const;
bool AllScalarIntegral(); // dest and all srcs are scalar integral
};
} // namespace hir

View File

@@ -210,10 +210,10 @@ enum Opcode {
OPCODE_STORE,
// chrispy: todo: implement, our current codegen for the unaligned loads is
// very bad
OPCODE_LVLX,
OPCODE_LVRX,
OPCODE_STVLX,
OPCODE_STVRX,
OPCODE_LVL,
OPCODE_LVR,
OPCODE_STVL,
OPCODE_STVR,
OPCODE_MEMSET,
OPCODE_CACHE_CONTROL,
OPCODE_MEMORY_BARRIER,
@@ -222,8 +222,6 @@ enum Opcode {
OPCODE_MIN,
OPCODE_VECTOR_MIN,
OPCODE_SELECT,
OPCODE_IS_TRUE,
OPCODE_IS_FALSE,
OPCODE_IS_NAN,
OPCODE_COMPARE_EQ,
OPCODE_COMPARE_NE,

View File

@@ -303,17 +303,6 @@ DEFINE_OPCODE(
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_IS_NAN,
@@ -706,4 +695,27 @@ DEFINE_OPCODE(
OPCODE_SIG_X_V,
0
)
DEFINE_OPCODE(
OPCODE_LVL,
"loadv_left",
OPCODE_SIG_V_V,
OPCODE_FLAG_MEMORY
)
DEFINE_OPCODE(
OPCODE_LVR,
"loadv_right",
OPCODE_SIG_V_V,
OPCODE_FLAG_MEMORY
)
DEFINE_OPCODE(
OPCODE_STVL,
"storev_left",
OPCODE_SIG_X_V_V,
OPCODE_FLAG_MEMORY)
DEFINE_OPCODE(
OPCODE_STVR,
"storev_right",
OPCODE_SIG_X_V_V,
OPCODE_FLAG_MEMORY)