luau/CodeGen/include/Luau/CodeGen.h
aaron 9c588be16d
Sync to upstream/release/610 (#1154)
# 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>
2024-01-26 19:20:56 -08:00

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