Significantly improve MSVC interpreter code generation

This patch adds an __assume statement for passed assertations and switches the interpreter loop to using a while-switch instead of a goto-switch loop. This seems to prevent the performance regression experienced on MSVC2022.
This commit is contained in:
Joshua 2025-03-26 17:56:47 -07:00
parent 2621488abe
commit e1e4a7aab2
No known key found for this signature in database
3 changed files with 27 additions and 22 deletions

View file

@ -166,12 +166,6 @@ if(LUAU_EXTERN_C)
target_compile_definitions(Luau.CodeGen PUBLIC LUACODEGEN_API=extern\"C\")
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION GREATER_EQUAL 1924)
# disable partial redundancy elimination which regresses interpreter codegen substantially in VS2022:
# https://developercommunity.visualstudio.com/t/performance-regression-on-a-complex-interpreter-lo/1631863
set_source_files_properties(VM/src/lvmexecute.cpp PROPERTIES COMPILE_FLAGS /d2ssa-pre-)
endif()
if (NOT MSVC)
# disable support for math_errno which allows compilers to lower sqrt() into a single CPU instruction
target_compile_options(Luau.VM PRIVATE -fno-math-errno)

View file

@ -10,6 +10,7 @@
#define LUAU_UNLIKELY(x) x
#define LUAU_UNREACHABLE() __assume(false)
#define LUAU_DEBUGBREAK() __debugbreak()
#define LUAU_ASSUME(x) __assume(x)
#else
#define LUAU_NORETURN __attribute__((__noreturn__))
#define LUAU_NOINLINE __attribute__((noinline))
@ -18,6 +19,7 @@
#define LUAU_UNLIKELY(x) __builtin_expect(x, 0)
#define LUAU_UNREACHABLE() __builtin_unreachable()
#define LUAU_DEBUGBREAK() __builtin_trap()
#define LUAU_ASSUME(x) __attribute__((assume(x)));
#endif
// LUAU_FALLTHROUGH is a C++11-compatible alternative to [[fallthrough]] for use in the VM library
@ -65,7 +67,7 @@ LUAU_NOINLINE inline int assertCallHandler(const char* expression, const char* f
#define LUAU_ASSERT(expr) ((void)(!!(expr) || (Luau::assertCallHandler(#expr, __FILE__, __LINE__, __FUNCTION__) && (LUAU_DEBUGBREAK(), 0))))
#define LUAU_ASSERTENABLED
#else
#define LUAU_ASSERT(expr) (void)sizeof(!!(expr))
#define LUAU_ASSERT(expr) LUAU_ASSUME(expr)
#endif
namespace Luau

View file

@ -77,7 +77,7 @@ LUAU_DYNAMIC_FASTFLAG(LuauPopIncompleteCi)
if (L->status != 0) \
{ \
L->ci->savedpc--; \
goto exit; \
return; \
} \
} \
}
@ -123,10 +123,12 @@ LUAU_DYNAMIC_FASTFLAG(LuauPopIncompleteCi)
#if VM_USE_CGOTO
#define VM_CASE(op) CASE_##op:
#define VM_NEXT() goto*(SingleStep ? &&dispatch : kDispatchTable[LUAU_INSN_OP(*pc)])
#define VM_START() VM_NEXT()
#define VM_CONTINUE(op) goto* kDispatchTable[uint8_t(op)]
#else
#define VM_CASE(op) case op:
#define VM_NEXT() goto dispatch
#define VM_NEXT() continue;
#define VM_START()
#define VM_CONTINUE(op) \
dispatchOp = uint8_t(op); \
goto dispatchContinue
@ -231,10 +233,9 @@ reentry:
base = L->base;
k = cl->l.p->k;
VM_NEXT(); // starts the interpreter "loop"
VM_START(); // starts the interpreter "loop"
{
dispatch:
while (true) {
// Note: this code doesn't always execute! on some platforms we use computed goto which bypasses all of this unless we run in single-step mode
// Therefore only ever put assertions here.
LUAU_ASSERT(base == L->base && L->base == L->ci->base);
@ -249,7 +250,7 @@ reentry:
// allow debugstep hook to put thread into error/yield state
if (L->status != 0)
goto exit;
return;
}
#if VM_USE_CGOTO
@ -976,7 +977,7 @@ reentry:
// yield
if (n < 0)
goto exit;
return;
// ci is our callinfo, cip is our parent
CallInfo* ci = L->ci;
@ -1039,7 +1040,7 @@ reentry:
// we're done!
if (LUAU_UNLIKELY(ci->flags & LUA_CALLINFO_RETURN))
{
goto exit;
return;
}
LUAU_ASSERT(isLua(L->ci));
@ -1053,7 +1054,7 @@ reentry:
if (L->global->ecb.enter(L, nextproto) == 1)
goto reentry;
else
goto exit;
return;
}
#endif
@ -2371,12 +2372,17 @@ reentry:
pc += LUAU_INSN_D(insn);
LUAU_ASSERT(unsigned(pc - cl->l.p->code) < unsigned(cl->l.p->sizecode));
VM_NEXT();
break;
}
index++;
}
if (unsigned(index) < unsigned(sizearray))
{
VM_NEXT();
}
int sizenode = 1 << h->lsizenode;
// then we advance index through the hash portion
@ -2392,12 +2398,17 @@ reentry:
pc += LUAU_INSN_D(insn);
LUAU_ASSERT(unsigned(pc - cl->l.p->code) < unsigned(cl->l.p->sizecode));
VM_NEXT();
break;
}
index++;
}
if (unsigned(index - sizearray) < unsigned(sizenode))
{
VM_NEXT();
}
// fallthrough to exit
pc++;
VM_NEXT();
@ -2487,7 +2498,7 @@ reentry:
if (L->global->ecb.enter(L, p) == 1)
goto reentry;
else
goto exit;
return;
#else
LUAU_ASSERT(!"Opcode is only valid when VM_HAS_NATIVE is defined");
LUAU_UNREACHABLE();
@ -2975,7 +2986,7 @@ reentry:
// allow debugbreak hook to put thread into error/yield state
if (L->status != 0)
goto exit;
return;
}
VM_CONTINUE(op);
@ -3047,8 +3058,6 @@ reentry:
#endif
}
}
exit:;
}
void luau_execute(lua_State* L)