mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 22:35:43 +08:00
9c588be16d
# What's changed? * Check interrupt handler inside the pattern match engine to eliminate potential for programs to hang during string library function execution. * Allow iteration over table properties to pass the old type solver. ### Native Code Generation * Use in-place memory operands for math library operations on x64. * Replace opaque bools with separate enum classes in IrDump to improve code maintainability. * Translate operations on inferred vectors to IR. * Enable support for debugging native-compiled functions in Roblox Studio. ### New Type Solver * Rework type inference for boolean and string literals to introduce bounded free types (bounded below by the singleton type, and above by the primitive type) and reworked primitive type constraint to decide which is the appropriate type for the literal. * Introduce `FunctionCheckConstraint` to handle bidirectional typechecking for function calls, pushing the expected parameter types from the function onto the arguments. * Introduce `union` and `intersect` type families to compute deferred simplified unions and intersections to be employed by the constraint generation logic in the new solver. * Implement support for expanding the domain of local types in `Unifier2`. * Rework type inference for iteration variables bound by for in loops to use local types. * Change constraint blocking logic to use a set to prevent accidental re-blocking. * Add logic to detect missing return statements in functions. ### Internal Contributors Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Vighnesh <vvijay@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: David Cope <dcope@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
211 lines
5.7 KiB
C++
211 lines
5.7 KiB
C++
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
struct lua_State;
|
|
|
|
namespace Luau
|
|
{
|
|
namespace CodeGen
|
|
{
|
|
|
|
enum CodeGenFlags
|
|
{
|
|
// Only run native codegen for modules that have been marked with --!native
|
|
CodeGen_OnlyNativeModules = 1 << 0,
|
|
// Run native codegen for functions that the compiler considers not profitable
|
|
CodeGen_ColdFunctions = 1 << 1,
|
|
};
|
|
|
|
enum class CodeGenCompilationResult
|
|
{
|
|
Success, // Successfully generated code for at least one function
|
|
NothingToCompile, // There were no new functions to compile
|
|
|
|
CodeGenNotInitialized, // Native codegen system is not initialized
|
|
CodeGenFailed, // Native codegen failed due to an internal compiler error
|
|
AllocationFailed, // Native codegen failed due to an allocation error
|
|
};
|
|
|
|
struct CompilationStats
|
|
{
|
|
size_t bytecodeSizeBytes = 0;
|
|
size_t nativeCodeSizeBytes = 0;
|
|
size_t nativeDataSizeBytes = 0;
|
|
size_t nativeMetadataSizeBytes = 0;
|
|
|
|
uint32_t functionsCompiled = 0;
|
|
};
|
|
|
|
using AllocationCallback = void(void* context, void* oldPointer, size_t oldSize, void* newPointer, size_t newSize);
|
|
|
|
bool isSupported();
|
|
|
|
void create(lua_State* L, AllocationCallback* allocationCallback, void* allocationCallbackContext);
|
|
void create(lua_State* L);
|
|
|
|
// Builds target function and all inner functions
|
|
CodeGenCompilationResult compile(lua_State* L, int idx, unsigned int flags = 0, CompilationStats* stats = nullptr);
|
|
|
|
using AnnotatorFn = void (*)(void* context, std::string& result, int fid, int instpos);
|
|
|
|
// Output "#" before IR blocks and instructions
|
|
enum class IncludeIrPrefix
|
|
{
|
|
No,
|
|
Yes
|
|
};
|
|
|
|
// Output user count and last use information of blocks and instructions
|
|
enum class IncludeUseInfo
|
|
{
|
|
No,
|
|
Yes
|
|
};
|
|
|
|
// Output CFG informations like block predecessors, successors and etc
|
|
enum class IncludeCfgInfo
|
|
{
|
|
No,
|
|
Yes
|
|
};
|
|
|
|
// Output VM register live in/out information for blocks
|
|
enum class IncludeRegFlowInfo
|
|
{
|
|
No,
|
|
Yes
|
|
};
|
|
|
|
struct AssemblyOptions
|
|
{
|
|
enum Target
|
|
{
|
|
Host,
|
|
A64,
|
|
A64_NoFeatures,
|
|
X64_Windows,
|
|
X64_SystemV,
|
|
};
|
|
|
|
Target target = Host;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
bool outputBinary = false;
|
|
|
|
bool includeAssembly = false;
|
|
bool includeIr = false;
|
|
bool includeOutlinedCode = false;
|
|
|
|
IncludeIrPrefix includeIrPrefix = IncludeIrPrefix::Yes;
|
|
IncludeUseInfo includeUseInfo = IncludeUseInfo::Yes;
|
|
IncludeCfgInfo includeCfgInfo = IncludeCfgInfo::Yes;
|
|
IncludeRegFlowInfo includeRegFlowInfo = IncludeRegFlowInfo::Yes;
|
|
|
|
// Optional annotator function can be provided to describe each instruction, it takes function id and sequential instruction id
|
|
AnnotatorFn annotator = nullptr;
|
|
void* annotatorContext = nullptr;
|
|
};
|
|
|
|
struct BlockLinearizationStats
|
|
{
|
|
unsigned int constPropInstructionCount = 0;
|
|
double timeSeconds = 0.0;
|
|
|
|
BlockLinearizationStats& operator+=(const BlockLinearizationStats& that)
|
|
{
|
|
this->constPropInstructionCount += that.constPropInstructionCount;
|
|
this->timeSeconds += that.timeSeconds;
|
|
|
|
return *this;
|
|
}
|
|
|
|
BlockLinearizationStats operator+(const BlockLinearizationStats& other) const
|
|
{
|
|
BlockLinearizationStats result(*this);
|
|
result += other;
|
|
return result;
|
|
}
|
|
};
|
|
|
|
enum FunctionStatsFlags
|
|
{
|
|
// Enable stats collection per function
|
|
FunctionStats_Enable = 1 << 0,
|
|
// Compute function bytecode summary
|
|
FunctionStats_BytecodeSummary = 1 << 1,
|
|
};
|
|
|
|
struct FunctionStats
|
|
{
|
|
std::string name;
|
|
int line = -1;
|
|
unsigned bcodeCount = 0;
|
|
unsigned irCount = 0;
|
|
unsigned asmCount = 0;
|
|
unsigned asmSize = 0;
|
|
std::vector<std::vector<unsigned>> bytecodeSummary;
|
|
};
|
|
|
|
struct LoweringStats
|
|
{
|
|
unsigned totalFunctions = 0;
|
|
unsigned skippedFunctions = 0;
|
|
int spillsToSlot = 0;
|
|
int spillsToRestore = 0;
|
|
unsigned maxSpillSlotsUsed = 0;
|
|
unsigned blocksPreOpt = 0;
|
|
unsigned blocksPostOpt = 0;
|
|
unsigned maxBlockInstructions = 0;
|
|
|
|
int regAllocErrors = 0;
|
|
int loweringErrors = 0;
|
|
|
|
BlockLinearizationStats blockLinearizationStats;
|
|
|
|
unsigned functionStatsFlags = 0;
|
|
std::vector<FunctionStats> functions;
|
|
|
|
LoweringStats operator+(const LoweringStats& other) const
|
|
{
|
|
LoweringStats result(*this);
|
|
result += other;
|
|
return result;
|
|
}
|
|
|
|
LoweringStats& operator+=(const LoweringStats& that)
|
|
{
|
|
this->totalFunctions += that.totalFunctions;
|
|
this->skippedFunctions += that.skippedFunctions;
|
|
this->spillsToSlot += that.spillsToSlot;
|
|
this->spillsToRestore += that.spillsToRestore;
|
|
this->maxSpillSlotsUsed = std::max(this->maxSpillSlotsUsed, that.maxSpillSlotsUsed);
|
|
this->blocksPreOpt += that.blocksPreOpt;
|
|
this->blocksPostOpt += that.blocksPostOpt;
|
|
this->maxBlockInstructions = std::max(this->maxBlockInstructions, that.maxBlockInstructions);
|
|
this->regAllocErrors += that.regAllocErrors;
|
|
this->loweringErrors += that.loweringErrors;
|
|
this->blockLinearizationStats += that.blockLinearizationStats;
|
|
if (this->functionStatsFlags & FunctionStats_Enable)
|
|
this->functions.insert(this->functions.end(), that.functions.begin(), that.functions.end());
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
// Generates assembly for target function and all inner functions
|
|
std::string getAssembly(lua_State* L, int idx, AssemblyOptions options = {}, LoweringStats* stats = nullptr);
|
|
|
|
using PerfLogFn = void (*)(void* context, uintptr_t addr, unsigned size, const char* symbol);
|
|
|
|
void setPerfLog(void* context, PerfLogFn logFn);
|
|
|
|
} // namespace CodeGen
|
|
} // namespace Luau
|