Path: blob/master/CodeGen/include/Luau/AssemblyBuilderX64.h
2727 views
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details1#pragma once23#include "Luau/Common.h"4#include "Luau/DenseHash.h"5#include "Luau/Label.h"6#include "Luau/ConditionX64.h"7#include "Luau/OperandX64.h"8#include "Luau/RegisterX64.h"910#include <string>11#include <vector>1213namespace Luau14{15namespace CodeGen16{17namespace X6418{1920enum FeaturesX6421{22Feature_FMA3 = 1 << 0,23Feature_AVX = 1 << 124};2526enum class RoundingModeX6427{28RoundToNearestEven = 0b00,29RoundToNegativeInfinity = 0b01,30RoundToPositiveInfinity = 0b10,31RoundToZero = 0b11,32};3334enum class AlignmentDataX6435{36Nop,37Int3,38Ud2, // int3 will be used as a fall-back if it doesn't fit39};4041enum class ABIX6442{43Windows,44SystemV,45};4647class AssemblyBuilderX6448{49public:50explicit AssemblyBuilderX64(bool logText, ABIX64 abi, unsigned int features = 0);51explicit AssemblyBuilderX64(bool logText, unsigned int features = 0);52~AssemblyBuilderX64();5354// Base two operand instructions with 9 opcode selection55void add(OperandX64 lhs, OperandX64 rhs);56void sub(OperandX64 lhs, OperandX64 rhs);57void cmp(OperandX64 lhs, OperandX64 rhs);58void and_(OperandX64 lhs, OperandX64 rhs);59void or_(OperandX64 lhs, OperandX64 rhs);60void xor_(OperandX64 lhs, OperandX64 rhs);6162// Binary shift instructions with special rhs handling63void sal(OperandX64 lhs, OperandX64 rhs);64void sar(OperandX64 lhs, OperandX64 rhs);65void shl(OperandX64 lhs, OperandX64 rhs);66void shr(OperandX64 lhs, OperandX64 rhs);67void rol(OperandX64 lhs, OperandX64 rhs);68void ror(OperandX64 lhs, OperandX64 rhs);6970// Two operand mov instruction has additional specialized encodings71void mov(OperandX64 lhs, OperandX64 rhs);72void mov64(RegisterX64 lhs, int64_t imm);73void movsx(RegisterX64 lhs, OperandX64 rhs);74void movzx(RegisterX64 lhs, OperandX64 rhs);7576// Base one operand instruction with 2 opcode selection77void div(OperandX64 op);78void idiv(OperandX64 op);79void mul(OperandX64 op);80void imul(OperandX64 op);81void neg(OperandX64 op);82void not_(OperandX64 op);83void dec(OperandX64 op);84void inc(OperandX64 op);8586// Additional forms of imul87void imul(OperandX64 lhs, OperandX64 rhs);88void imul(OperandX64 dst, OperandX64 lhs, int32_t rhs);8990void test(OperandX64 lhs, OperandX64 rhs);91void lea(OperandX64 lhs, OperandX64 rhs);92void setcc(ConditionX64 cond, OperandX64 op);93void cmov(ConditionX64 cond, RegisterX64 lhs, OperandX64 rhs);9495void push(OperandX64 op);96void pop(OperandX64 op);97void ret();9899// Control flow100void jcc(ConditionX64 cond, Label& label);101void jmp(Label& label);102void jmp(OperandX64 op);103104void call(Label& label);105void call(OperandX64 op);106107void lea(RegisterX64 lhs, Label& label);108109void int3();110void ud2();111112void bsr(RegisterX64 dst, OperandX64 src);113void bsf(RegisterX64 dst, OperandX64 src);114void bswap(RegisterX64 dst);115116// Code alignment117void nop(uint32_t length = 1);118void align(uint32_t alignment, AlignmentDataX64 data = AlignmentDataX64::Nop);119120// AVX121void vaddpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);122void vaddps(OperandX64 dst, OperandX64 src1, OperandX64 src2);123void vaddsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);124void vaddss(OperandX64 dst, OperandX64 src1, OperandX64 src2);125126void vsubsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);127void vsubss(OperandX64 dst, OperandX64 src1, OperandX64 src2);128void vsubps(OperandX64 dst, OperandX64 src1, OperandX64 src2);129void vmulsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);130void vmulss(OperandX64 dst, OperandX64 src1, OperandX64 src2);131void vmulps(OperandX64 dst, OperandX64 src1, OperandX64 src2);132void vdivsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);133void vdivss(OperandX64 dst, OperandX64 src1, OperandX64 src2);134void vdivps(OperandX64 dst, OperandX64 src1, OperandX64 src2);135136void vandps(OperandX64 dst, OperandX64 src1, OperandX64 src2);137void vandpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);138void vandnpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);139140void vxorps(OperandX64 dst, OperandX64 src1, OperandX64 src2);141void vxorpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);142void vorps(OperandX64 dst, OperandX64 src1, OperandX64 src2);143void vorpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);144145void vucomisd(OperandX64 src1, OperandX64 src2);146void vucomiss(OperandX64 src1, OperandX64 src2);147148void vcvttsd2si(OperandX64 dst, OperandX64 src);149void vcvtsi2sd(OperandX64 dst, OperandX64 src1, OperandX64 src2);150void vcvtsi2ss(OperandX64 dst, OperandX64 src1, OperandX64 src2);151void vcvtsd2ss(OperandX64 dst, OperandX64 src1, OperandX64 src2);152void vcvtss2sd(OperandX64 dst, OperandX64 src1, OperandX64 src2);153154void vroundsd(OperandX64 dst, OperandX64 src1, OperandX64 src2, RoundingModeX64 roundingMode); // inexact155void vroundss(OperandX64 dst, OperandX64 src1, OperandX64 src2, RoundingModeX64 roundingMode); // inexact156void vroundps(OperandX64 dst, OperandX64 src, RoundingModeX64 roundingMode); // inexact157158void vsqrtpd(OperandX64 dst, OperandX64 src);159void vsqrtps(OperandX64 dst, OperandX64 src);160void vsqrtsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);161void vsqrtss(OperandX64 dst, OperandX64 src1, OperandX64 src2);162163void vmovsd(OperandX64 dst, OperandX64 src);164void vmovsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);165void vmovss(OperandX64 dst, OperandX64 src);166void vmovss(OperandX64 dst, OperandX64 src1, OperandX64 src2);167void vmovapd(OperandX64 dst, OperandX64 src);168void vmovaps(OperandX64 dst, OperandX64 src);169void vmovupd(OperandX64 dst, OperandX64 src);170void vmovups(OperandX64 dst, OperandX64 src);171void vmovq(OperandX64 lhs, OperandX64 rhs);172173void vmaxps(OperandX64 dst, OperandX64 src1, OperandX64 src2);174void vmaxsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);175void vmaxss(OperandX64 dst, OperandX64 src1, OperandX64 src2);176void vminps(OperandX64 dst, OperandX64 src1, OperandX64 src2);177void vminsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);178void vminss(OperandX64 dst, OperandX64 src1, OperandX64 src2);179180void vcmpeqsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);181void vcmpltsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);182void vcmpltss(OperandX64 dst, OperandX64 src1, OperandX64 src2);183void vcmpeqps(OperandX64 dst, OperandX64 src1, OperandX64 src2);184185void vblendvps(RegisterX64 dst, RegisterX64 src1, OperandX64 src2, RegisterX64 mask);186void vblendvpd(RegisterX64 dst, RegisterX64 src1, OperandX64 src2, RegisterX64 mask);187188void vpshufps(RegisterX64 dst, RegisterX64 src1, OperandX64 src2, uint8_t shuffle);189void vpinsrd(RegisterX64 dst, RegisterX64 src1, OperandX64 src2, uint8_t offset);190void vpextrd(RegisterX64 dst, RegisterX64 src, uint8_t offset);191192void vdpps(OperandX64 dst, OperandX64 src1, OperandX64 src2, uint8_t mask);193void vfmadd213ps(OperandX64 dst, OperandX64 src1, OperandX64 src2);194void vfmadd213pd(OperandX64 dst, OperandX64 src1, OperandX64 src2);195196// Run final checks197bool finalize();198199// Places a label at current location and returns it200Label setLabel();201202// Assigns label position to the current location203void setLabel(Label& label);204205// Extracts code offset (in bytes) from label206uint32_t getLabelOffset(const Label& label)207{208CODEGEN_ASSERT(label.location != ~0u);209return label.location;210}211212// Constant allocation (uses rip-relative addressing)213OperandX64 i32(int32_t value);214OperandX64 i64(int64_t value);215OperandX64 f32(float value);216OperandX64 f64(double value);217OperandX64 u32x4(uint32_t x, uint32_t y, uint32_t z, uint32_t w);218OperandX64 f32x4(float x, float y, float z, float w);219OperandX64 f64x2(double x, double y);220OperandX64 bytes(const void* ptr, size_t size, size_t align = 8);221222void logAppend(const char* fmt, ...) LUAU_PRINTF_ATTR(2, 3);223224// Code size is measured in 'code' array units - uint8_t on x64 and uint32_t on arm64225uint32_t getCodeSize() const;226227unsigned getInstructionCount() const;228229// Resulting data and code that need to be copied over one after the other230// The *end* of 'data' has to be aligned to 16 bytes, this will also align 'code'231std::vector<uint8_t> data;232std::vector<uint8_t> code;233234std::string text;235236const bool logText = false;237238const ABIX64 abi;239240const unsigned int features = 0;241242private:243// Instruction archetypes244void placeBinary(245const char* name,246OperandX64 lhs,247OperandX64 rhs,248uint8_t codeimm8,249uint8_t codeimm,250uint8_t codeimmImm8,251uint8_t code8rev,252uint8_t coderev,253uint8_t code8,254uint8_t code,255uint8_t opreg256);257void placeBinaryRegMemAndImm(OperandX64 lhs, OperandX64 rhs, uint8_t code8, uint8_t code, uint8_t codeImm8, uint8_t opreg);258void placeBinaryRegAndRegMem(OperandX64 lhs, OperandX64 rhs, uint8_t code8, uint8_t code);259void placeBinaryRegMemAndReg(OperandX64 lhs, OperandX64 rhs, uint8_t code8, uint8_t code);260261void placeUnaryModRegMem(const char* name, OperandX64 op, uint8_t code8, uint8_t code, uint8_t opreg);262263void placeShift(const char* name, OperandX64 lhs, OperandX64 rhs, uint8_t opreg);264265void placeJcc(const char* name, Label& label, uint8_t cc);266267void placeAvx(const char* name, OperandX64 dst, OperandX64 src, uint8_t code, bool setW, uint8_t mode, uint8_t prefix);268void placeAvx(const char* name, OperandX64 dst, OperandX64 src, uint8_t code, uint8_t coderev, bool setW, uint8_t mode, uint8_t prefix);269void placeAvx(const char* name, OperandX64 dst, OperandX64 src1, OperandX64 src2, uint8_t code, bool setW, uint8_t mode, uint8_t prefix);270void placeAvx(271const char* name,272OperandX64 dst,273OperandX64 src1,274OperandX64 src2,275uint8_t imm8,276uint8_t code,277bool setW,278uint8_t mode,279uint8_t prefix280);281282// Instruction components283void placeRegAndModRegMem(OperandX64 lhs, OperandX64 rhs, int32_t extraCodeBytes = 0);284void placeModRegMem(OperandX64 rhs, uint8_t regop, int32_t extraCodeBytes = 0);285void placeRex(RegisterX64 op);286void placeRex(OperandX64 op);287void placeRexNoW(OperandX64 op);288void placeRex(RegisterX64 lhs, OperandX64 rhs);289void placeVex(OperandX64 dst, OperandX64 src1, OperandX64 src2, bool setW, uint8_t mode, uint8_t prefix);290void placeImm8Or32(int32_t imm);291void placeImm8(int32_t imm);292void placeImm16(int16_t imm);293void placeImm32(int32_t imm);294void placeImm64(int64_t imm);295void placeLabel(Label& label);296void place(uint8_t byte);297298void commit();299LUAU_NOINLINE void extend();300301// Data302size_t allocateData(size_t size, size_t align);303304// Logging of assembly in text form (Intel asm with VS disassembly formatting)305LUAU_NOINLINE void log(const char* opcode);306LUAU_NOINLINE void log(const char* opcode, OperandX64 op);307LUAU_NOINLINE void log(const char* opcode, OperandX64 op1, OperandX64 op2);308LUAU_NOINLINE void log(const char* opcode, OperandX64 op1, OperandX64 op2, OperandX64 op3);309LUAU_NOINLINE void log(const char* opcode, OperandX64 op1, OperandX64 op2, OperandX64 op3, OperandX64 op4);310LUAU_NOINLINE void log(Label label);311LUAU_NOINLINE void log(const char* opcode, Label label);312LUAU_NOINLINE void log(const char* opcode, RegisterX64 reg, Label label);313void log(OperandX64 op);314315const char* getSizeName(SizeX64 size) const;316const char* getRegisterName(RegisterX64 reg) const;317318uint32_t nextLabel = 1;319std::vector<Label> pendingLabels;320std::vector<uint32_t> labelLocations;321322DenseHashMap<uint32_t, int32_t> constCache32;323DenseHashMap<uint64_t, int32_t> constCache64;324325bool finalized = false;326327size_t dataPos = 0;328329uint8_t* codePos = nullptr;330uint8_t* codeEnd = nullptr;331332unsigned instructionCount = 0;333};334335} // namespace X64336} // namespace CodeGen337} // namespace Luau338339340