diff --git a/External/FEXCore/Scripts/json_ir_generator.py b/External/FEXCore/Scripts/json_ir_generator.py index c506b4c09..90bbb3f08 100644 --- a/External/FEXCore/Scripts/json_ir_generator.py +++ b/External/FEXCore/Scripts/json_ir_generator.py @@ -115,6 +115,7 @@ def print_ir_sizes(ops, defines): output_file.write("std::string_view const& GetName(IROps Op);\n") output_file.write("uint8_t GetArgs(IROps Op);\n") output_file.write("FEXCore::IR::RegisterClassType GetRegClass(IROps Op);\n\n") + output_file.write("bool HasSideEffects(IROps Op);\n") output_file.write("#undef IROP_SIZES\n") output_file.write("#endif\n\n") @@ -187,6 +188,25 @@ def print_ir_getraargs(ops, defines): output_file.write("#undef IROP_GETRAARGS_IMPL\n") output_file.write("#endif\n\n") +def print_ir_hassideeffects(ops, defines): + output_file.write("#ifdef IROP_HASSIDEEFFECTS_IMPL\n") + + output_file.write("constexpr std::array SideEffects = {\n") + for op_key, op_vals in ops.items(): + HasSideEffects = False + if ("HasSideEffects" in op_vals): + SSAArgs = op_vals["HasSideEffects"] + + output_file.write("\t%s,\n" % ("true" if SSAArgs else "false")) + + output_file.write("};\n\n") + + output_file.write("bool HasSideEffects(IROps Op) {\n") + output_file.write(" return SideEffects[Op];\n") + output_file.write("}\n") + + output_file.write("#undef IROP_HASSIDEEFFECTS_IMPL\n") + output_file.write("#endif\n\n") # Print out IR argument printing def print_ir_arg_printer(ops, defines): @@ -619,6 +639,7 @@ print_ir_sizes(ops, defines) print_ir_reg_classes(ops, defines) print_ir_getname(ops, defines) print_ir_getraargs(ops, defines) +print_ir_hassideeffects(ops, defines) print_ir_arg_printer(ops, defines) print_ir_allocator_helpers(ops, defines) print_ir_parser_allocator_helpers(ops, defines) diff --git a/External/FEXCore/Source/Interface/IR/IR.cpp b/External/FEXCore/Source/Interface/IR/IR.cpp index 3cdfa8a9f..2131dcf12 100644 --- a/External/FEXCore/Source/Interface/IR/IR.cpp +++ b/External/FEXCore/Source/Interface/IR/IR.cpp @@ -7,6 +7,7 @@ namespace FEXCore::IR { #define IROP_GETNAME_IMPL #define IROP_GETRAARGS_IMPL #define IROP_REG_CLASSES_IMPL +#define IROP_HASSIDEEFFECTS_IMPL #include diff --git a/External/FEXCore/Source/Interface/IR/IR.json b/External/FEXCore/Source/Interface/IR/IR.json index c3006d44c..714bf9e40 100644 --- a/External/FEXCore/Source/Interface/IR/IR.json +++ b/External/FEXCore/Source/Interface/IR/IR.json @@ -41,6 +41,7 @@ "Ops": { "Dummy": { + "HasSideEffects": true, "OpClass": "Misc", "SwitchGen": false }, @@ -72,6 +73,7 @@ }, "EndBlock": { + "HasSideEffects": true, "OpClass": "Misc", "SwitchGen": false, "Args": [ @@ -103,6 +105,7 @@ }, "CASPair": { + "HasSideEffects": true, "OpClass": "Atomic", "Desc": ["Does a compare and exchange with two GPRPair values", "ssa0 is the comparison value", @@ -138,6 +141,7 @@ }, "StoreContextPair": { + "HasSideEffects": true, "OpClass": "Memory", "Desc": ["Stores a pair of values back in to the context"], "SSAArgs": "1", @@ -213,6 +217,7 @@ }, "Break": { + "HasSideEffects": true, "OpClass": "Misc", "Args": [ "uint8_t", "Reason", @@ -221,10 +226,12 @@ }, "ExitFunction": { + "HasSideEffects": true, "OpClass": "Branch" }, "Jump": { + "HasSideEffects": true, "OpClass": "Branch", "SSAArgs": "1", "SSANames": [ @@ -234,6 +241,7 @@ }, "CondJump": { + "HasSideEffects": true, "OpClass": "Branch", "SSAArgs": "3", "RAOverride": "1", @@ -320,6 +328,7 @@ }, "StoreContext": { + "HasSideEffects": true, "Desc": ["Stores a value to the context with offset", "Ctx[Offset] = Value" ], @@ -359,6 +368,7 @@ }, "StoreContextIndexed": { + "HasSideEffects": true, "Desc": ["Stores a value to the context with offset and indexed by SSA value", "Ctx[BaseOffset + Index * Stride] = Value" ], @@ -377,6 +387,7 @@ }, "SpillRegister": { + "HasSideEffects": true, "Desc": ["Spills an SSA value to memory", "Spill slots are register allocated and has live ranges calculated to handle slot calculation", "```diff\n- !Don't use this op. It is for RA to handle spilling and filling!\n```" @@ -421,6 +432,7 @@ }, "StoreFlag": { + "HasSideEffects": true, "Desc": ["Stores 1-bit of the flag in to the specified x86-64 flag", "Specialized to allow flexible implementation of flag handling" ], @@ -435,6 +447,7 @@ }, "Syscall": { + "HasSideEffects": true, "OpClass": "Branch", "HasDest": true, "DestClass": "GPR", @@ -468,6 +481,7 @@ }, "StoreMem": { + "HasSideEffects": true, "OpClass": "Memory", "SSAArgs": "2", "SSANames": [ @@ -900,6 +914,7 @@ }, "CAS": { + "HasSideEffects": true, "Desc": ["Does a compare and swap of values to a memory location", "This mostly matches the C++ atomic_compare_exchange_strong function", "Dest = atomic_compare_exchange_strong(%Addr, %Expected, %Desired)", @@ -922,6 +937,7 @@ }, "AtomicAdd": { + "HasSideEffects": true, "Desc": ["Atomic integer add" ], "OpClass": "Atomic", @@ -936,6 +952,7 @@ }, "AtomicSub": { + "HasSideEffects": true, "Desc": ["Atomic integer sub" ], "OpClass": "Atomic", @@ -950,6 +967,7 @@ }, "AtomicAnd": { + "HasSideEffects": true, "Desc": ["Atomic binary and" ], "OpClass": "Atomic", @@ -964,6 +982,7 @@ }, "AtomicOr": { + "HasSideEffects": true, "Desc": ["Atomic binary or" ], "OpClass": "Atomic", @@ -978,6 +997,7 @@ }, "AtomicXor": { + "HasSideEffects": true, "Desc": ["Atomic binary exclusive or" ], "OpClass": "Atomic", @@ -992,6 +1012,7 @@ }, "AtomicSwap": { + "HasSideEffects": true, "Desc": ["Atomic swap", "Atomically swaps contents of GPR and memory location" ], @@ -1010,6 +1031,7 @@ }, "AtomicFetchAdd": { + "HasSideEffects": true, "Desc": ["Atomic integer fetch and add", "Atomically fetches %Addr and adds %value to the memory location", "Dest is the value prior to operating on the value in memory" @@ -1029,6 +1051,7 @@ }, "AtomicFetchSub": { + "HasSideEffects": true, "Desc": ["Atomic integer fetch and sub", "Atomically fetches %Addr and subtracts %value to the memory location", "Dest is the value prior to operating on the value in memory" @@ -1049,6 +1072,7 @@ }, "AtomicFetchAnd": { + "HasSideEffects": true, "Desc": ["Atomic integer fetch and binary and", "Atomically fetches %Addr and binary ands %value to the memory location", "Dest is the value prior to operating on the value in memory" @@ -1068,6 +1092,7 @@ }, "AtomicFetchOr": { + "HasSideEffects": true, "Desc": ["Atomic integer fetch and binary or", "Atomically fetches %Addr and binary ors %value to the memory location", "Dest is the value prior to operating on the value in memory" @@ -1087,6 +1112,7 @@ }, "AtomicFetchXor": { + "HasSideEffects": true, "Desc": ["Atomic integer fetch and binary exclusive or", "Atomically fetches %Addr and binary exclusive ors %value to the memory location", "Dest is the value prior to operating on the value in memory" @@ -1180,11 +1206,13 @@ }, "Print": { + "HasSideEffects": true, "Desc": ["Debug operation that prints an SSA value to the console", "May only print 64bits of the value", "Depending on backend, may only support GPR printing" ], "OpClass": "Misc", + "DestSize": "GetOpSize(ssa0)", "SSAArgs": "1", "SSANames": [ "Value" diff --git a/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp index 7a83b7fb4..da6393be2 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp @@ -1,6 +1,8 @@ #include "Interface/IR/PassManager.h" #include "Interface/Core/OpcodeDispatcher.h" +#include + #include namespace FEXCore::IR { @@ -42,38 +44,13 @@ bool DeadCodeElimination::Run(IREmitter *IREmit) { OrderedNode *CodeNode = CodeOp->GetNode(ListBegin); auto IROp = CodeNode->Op(DataBegin); - switch (IROp->Op) { - // State/memory storage - case OP_STORECONTEXTINDEXED: - case OP_STORECONTEXT: - case OP_STORECONTEXTPAIR: - case OP_STOREFLAG: - case OP_STOREMEM: - case OP_CAS: - case OP_PRINT: - // Keep - break; - // IO - case OP_SYSCALL: - // Keep - break; - // Control flow - case OP_BREAK: - case OP_JUMP: - case OP_EXITFUNCTION: - case OP_CONDJUMP: - // Keep - break; - case OP_DUMMY: - case OP_ENDBLOCK: - // Keep, so we don't have to update block first/last - break; - default: + // Skip over anything that has side effects + // Use count tracking can't safely remove anything with side effects + if (!IR::HasSideEffects(IROp->Op)) { if (CodeNode->GetUses() == 0) { NumRemoved++; IREmit->Remove(CodeNode); } - break; } if (CodeLast == CodeBegin) {