#pragma once #include #include "Array.h" #include "Text.h" #include "Writer.h" namespace Framework { namespace Assembly { enum Operation { // no real operation, used for labels NOP, // Arithmetic Operations ADD, // Addition ADDPD, // Add Packed Double-Precision Floating-Point Values ADDPS, // Add Packed Single-Precision Floating-Point Values ADDSD, // Add Scalar Double-Precision Floating-Point Values ADDSS, // Add Scalar Single-Precision Floating-Point Values SUB, // Subtraction SUBPD, // Subtract Packed Double-Precision Floating-Point Values SUBPS, // Subtract Packed Single-Precision Floating-Point Values SUBSD, // Subtract Scalar Double-Precision Floating-Point Values SUBSS, // Subtract Scalar Single-Precision Floating-Point Values MUL, // Multiply unsigned IMUL, // Multiply signed MULPD, // Multiply Packed Double Precision Floating-Point Values MULPS, // Multiply Packed Single Precision Floating-Point Values MULSD, // Multiply Scalar Double Precision Floating-Point Value MULSS, // Multiply Scalar Single Precision Floating-Point Values DIV, // Division unsigned IDIV, // Division signed DIVPD, // Divide Packed Double-Precision Floating-Point Values DIVPS, // Divide Packed Single-Precision Floating-Point Values DIVSD, // Divide Scalar Double-Precision Floating-Point Values DIVSS, // Divide Scalar Single-Precision Floating-Point Values NEG, // Negation INC, // Increment // Logical Operations AND, // Bitwise AND OR, // Bitwise OR XOR, // Bitwise XOR NOT, // Bitwise NOT // Comparison Operations // Bitwise AND without storing the result. only // SpecialRegister.FLAGS (SF, ZF, PF) is affected TEST, // Compare // temporary subtracts op2 from op without storing the result. only // SpecialRegister.FLAGS is affected CMP, // Compare Packed Double Precision Floating-Point Values CMPPD, // Compare Packed Single Precision Floating-Point Values CMPPS, // Compare Scalar Double Precision Floating-Point Value CMPSD, // Compare Scalar Single Precision Floating-Point Value CMPSS, // Compare Scalar Ordered Double Precision Floating-Point Values // writes to SpecialRegister.FLAGS (ZF, PF, CF) // UNORDERED (one of the values was NAN) = 0b111 // GREATER_THAN = 0b000 // LESS_THAN = 0b001 // EQUAL = 0b100 COMISD, // Compare Scalar Ordered Single Precision Floating-Point Values // writes to SpecialRegister.FLAGS (ZF, PF, CF) // UNORDERED (one of the values was NAN) = 0b111 // GREATER_THAN = 0b000 // LESS_THAN = 0b001 // EQUAL = 0b100 COMISS, // Data Movement MOV, // Move data from source to destination // Move Unaligned Packed Double-Precision Floating-Point Value MOVUPD, // Move Unaligned Packed Single-Precision Floating-Point Value MOVUPS, MOVSD, // Move Scalar Double-Precision Floating-Point Value MOVSS, // Move Scalar Single-Precision Floating-Point Value LEA, // Load Effective Address // DATA Conversion // Convert Integer to Scalar Double Precision Floating-Point Value CVTSI2SD, // Convert Integer to Scalar Single Precision Floating-Point Value CVTSI2SS, // Convert With Truncation Scalar Double Precision Floating-Point // Value to Signed Integer CVTTSD2SI, // Convert With Truncation Scalar Single Precision Floating-Point // Value to Signed Integer CVTTSS2SI, // Convert Scalar Double Precision Floating-Point Value to Integer // with rounding according to the bits 13 an 14 of the MXCSR // register value: // // 0b00: (default) round to nearest integer value // 0b01: round to the next lower integer value // 0b10: round to the next heigher integer value // 0b11: truncate (like CVTTSS2SI) CVTSD2SI, // Convert Scalar Single Precision Floating-Point Value to Integer // with rounding according to the bits 13 an 14 of the MXCSR // register value: // // 0b00: (default) round to nearest integer value // 0b01: round to the next lower integer value // 0b10: round to the next heigher integer value // 0b11: truncate (like CVTTSS2SI) CVTSS2SI, // Control Flow // Unconditional Jump JMP, // Jump if Zero: SpecialRegister.FLAGS(ZF) = 1 JZ, // Jump if equal: SpecialRegister.FLAGS(ZF) = 1 JE = JZ, // Jump if Not Zero: SpecialRegister.FLAGS(ZF) = 0 JNZ, // Jump if Not Equal: SpecialRegister.FLAGS(ZF) = 0 JNE = JNZ, // Jump if Greater: SpecialRegister.FLAGS(SF) = // SpecialRegister.FLAGS(OF) and SpecialRegister.FLAGS(ZF) = 0 JG, // Jump if Greater or Equal: SpecialRegister.FLAGS(SF) = // SpecialRegister.FLAGS(OF) JGE, // Jump if Less: SpecialRegister.FLAGS(SF) != // SpecialRegister.FLAGS(OF) JL, // Jump if Less or Equal: SpecialRegister.FLAGS(SF) != // SpecialRegister.FLAGS(OF) or SpecialRegister.FLAGS(ZF) = 1 JLE, // Jump if above: SpecialRegister.FLAGS(CF) = 0 and // SpecialRegister.FLAGS(ZF) = 0 JA, // Jump if carry: SpecialRegister.FLAGS(CF) = 1 JC, // Jump if below: SpecialRegister.FLAGS(CF) = 1 JB = JC, // Jump if not carry: SpecialRegister.FLAGS(CF) = 0 JNC, // Jump if not below: SpecialRegister.FLAGS(CF) = 0 JNB = JNC, // Jump if below or equal: SpecialRegister.FLAGS(CF) = 1 or // SpecialRegister.FLAGS(ZF) = 1 JBE, JO, // Jump if overflow: SpecialRegister.FLAGS(OF) = 1 JNO, // Jump if not overflow: SpecialRegister.FLAGS(OF) = 0 JP, // Jump if parity even: SpecialRegister.FLAGS(PF) = 1 JNP, // Jump if not parity odd: SpecialRegister.FLAGS(PF) = 0 JS, // Jump if sign: SpecialRegister.FLAGS(SF) = 1 JNS, // Jump if not sign: SpecialRegister.FLAGS(SF) = 0 CALL, // Call subroutine RET, // Return from subroutine // Stack Operations PUSH, // Push onto stack POP // Pop from stack }; enum CMP_IMM8 { EQ_OQ = 0, // Equal (ordered, non-signaling) LT_OS = 1, // Less than (ordered, signaling) LE_OS = 2, // Less than or equal (ordered, signaling UNORD_Q = 3, // Unordered (non-signaling) NEQ_UQ = 4, // Not-equal (unordered, non-signaling) NLT_US = 5, // Not less than (unordered, signaling) NLE_US = 6, // Not-less-than-or-equal (unordered, signaling) ORD_Q = 7, // Ordered (non-signaling) EQ_US = 8, // Equal (unordered, signaling) NGE_US = 9, // Not-greater-than-or-equal (unordered, signaling) NGT_US = 10, // Not-greater-than (unordered, signaling) FALSE_OQ = 11, // False (ordered, non-signaling) NEQ_OQ = 12, // Not-equal (ordered, non-signaling) GE_OS = 13, // Greater-than-or-equal (ordered, signaling) GT_OS = 14, // Greater-than (ordered, signaling) TRUE_UQ = 15, // True (unordered, non-signaling) EQ_OS = 16, // Equal (ordered, signaling) LT_OQ = 17, // Less-than (ordered, non-signaling) LE_OQ = 18, // Less-than-or-equal (ordered, non UNORD_S = 19, // Unordered (signaling) NEQ_US = 20, // Not-equal (unordered, signaling) NLT_UQ = 21, // Not-less-than (unordered, non-sign NLE_UQ = 22, // Not-less-than-or-equal (unordered, non-signaling) ORD_S = 23, // Ordered (signaling) EQ_UQ = 24, // Equal (unordered, non-signaling) NGE_UQ = 25, // Not-greater-than-or-equal ( NGT_UQ = 26, // Not-greater-than (unordered, non-signaling) FALSE_OS = 27, // False (ordered, signaling) NEQ_OS = 28, // Not-equal (ordered, signaling) GE_OQ = 29, // Greater-than-or-equal (ordered, non GT_OQ = 30, // Greater-than (ordered, non-signaling) TRUE_S = 31 // True (signaling) }; enum FPDataType { SINGLE_FLOAT, SINGLE_DOUBLE, PACKED_FLOAT, PACKED_DOUBLE }; enum FuncReturnType { NO_VALUE, INT_VALUE, FLOAT_VALUE }; // General Purpose Registers enum GPRegister { // volatile register (can be altered by a function call) RAX = 0b0000, // non-volatile register (mus be restored on return) RBX = 0b0011, // volatile register (can be altered by a function call) RCX = 0b0001, // volatile register (can be altered by a function call) RDX = 0b0010, // Stack pointer points to the position of the last item that was // pushed to the stack. The stack grows downwards so lower means // more elements in the stack. needs to be aligned to 16 bytes // non-volatile register (mus be restored on return) RSP = 0b0100, // base pointer points to the base of the current stack frame // non-volatile register (mus be restored on return) RBP = 0b0101, // non-volatile register (mus be restored on return) RSI = 0b0110, // non-volatile register (mus be restored on return) RDI = 0b0111, // volatile register (can be altered by a function call) R8 = 0b1000, // volatile register (can be altered by a function call) R9 = 0b1001, // volatile register (can be altered by a function call) R10 = 0b1010, // volatile register (can be altered by a function call) R11 = 0b1011, // non-volatile register (mus be restored on return) R12 = 0b1100, // non-volatile register (mus be restored on return) R13 = 0b1101, // non-volatile register (mus be restored on return) R14 = 0b1110, // non-volatile register (mus be restored on return) R15 = 0b1111 }; enum SpecialRegister { // Instruction pointer points to the instruction that is executed // next RIP, /** only lower 16 bits are used: - CF: Carry Flag - PF: Parity Flag (1 if an even number of bits was set to 1 in the result of the last operation) - AF: Adjust Flag - ZF: Zero Flag (1 if the result of the last operation was zero) - SF: Sign Flag (1 if the result of the last operation was a positive number) - TF: Trap Flag - IF: Interrupt Flag - DF: Direction Flag - OF: Overflow Flag */ FLAGS, /** * controls the behaviour of some operations. */ MXCSR, }; /** floating point registers */ enum FPRegister { MM0, // volatile register (can be altered by a function call) MM1, // volatile register (can be altered by a function call) MM2, // volatile register (can be altered by a function call) MM3, // volatile register (can be altered by a function call) MM4, // volatile register (can be altered by a function call) MM5, // volatile register (can be altered by a function call) MM6, // non volatile register (mus be restored on return) MM7, // non volatile register (mus be restored on return) MM8, // non volatile register (mus be restored on return) MM9, // non volatile register (mus be restored on return) MM10, // non volatile register (mus be restored on return) MM11, // non volatile register (mus be restored on return) MM12, // non volatile register (mus be restored on return) MM13, // non volatile register (mus be restored on return) MM14, // non volatile register (mus be restored on return) MM15, // non volatile register (mus be restored on return) __FP_REGISTER_COUNT }; /** describes the bits of the specified register that should be used. */ enum GPRegisterPart { LOWER8, HIGHER8, LOWER16, LOWER32, FULL64 }; /** describes the bits of the specified register that should be used. */ enum FPRegisterPart { X, Y, // Z }; class AssemblyBlock; class GPRegisterArgument; class FPRegisterArgument; class MemoryAccessArgument; class ConstantArgument; class JumpTargetArgument; /** An argument for an Instruction. */ class OperationArgument { private: public: /** * checks if a register is used in this argument. * * \param reg the register to check * \return true if the register is used */ DLLEXPORT virtual bool usesRegister(GPRegister reg) const; /** * checks if a register is used in this argument. * * \param reg the register to check * \return true if the register is used */ DLLEXPORT virtual bool usesRegister(FPRegister reg) const; /** * replaces a register with another register. * * \param oldReg the register to replace * \param newReg the register to use instead */ DLLEXPORT virtual void replaceRegister( GPRegister oldReg, GPRegister newReg); /** * replaces a register with another register. * * \param oldReg the register to replace * \param newReg the register to use instead */ DLLEXPORT virtual void replaceRegister( FPRegister oldReg, FPRegister newReg); /** * adds a prefix to all jump labels in this argument to avoid * conflicts if the assembly block that contains this argument is * inlined into another block. * * \param labelPrefix the label prefix to add */ DLLEXPORT virtual void addJumpLabelPrefix(Text labelPrefix); /** * \return the GPRegisterArgument or 0 if it is not a * GPRegisterArgument */ DLLEXPORT const GPRegisterArgument* asGPRegisterArgument() const; /** * \return the GPRegisterArgument or 0 if it is not a * GPRegisterArgument */ DLLEXPORT const MemoryAccessArgument* asMemoryAccessArgument() const; /** * \return the ConstantArgument or 0 if it is not a * ConstantArgument */ DLLEXPORT const ConstantArgument* asConstantArgument() const; /** * \return the FPRegisterArgument or 0 if it is not a * FPRegisterArgument */ DLLEXPORT const FPRegisterArgument* asFPRegisterArgument() const; /** * \return the JumpTargetArgument or 0 if it is not a * JumpTargetArgument */ DLLEXPORT const JumpTargetArgument* asJumpTargetArgument() const; }; /** Represents the usage of a GPRegister as an Instruction Argument. */ class GPRegisterArgument : public OperationArgument { private: GPRegister reg; GPRegisterPart part; public: DLLEXPORT GPRegisterArgument( GPRegister reg, GPRegisterPart part = GPRegisterPart::FULL64); DLLEXPORT bool usesRegister(GPRegister reg) const override; DLLEXPORT void replaceRegister( GPRegister oldReg, GPRegister newReg) override; DLLEXPORT GPRegister getRegister() const; DLLEXPORT GPRegisterPart getPart() const; }; /** Represents the usage of a FPRegister as an Instruction Argument. */ class FPRegisterArgument : public OperationArgument { private: FPRegister reg; FPRegisterPart part; public: DLLEXPORT FPRegisterArgument(FPRegister reg, FPRegisterPart = X); DLLEXPORT bool usesRegister(FPRegister reg) const override; DLLEXPORT void replaceRegister( FPRegister oldReg, FPRegister newReg) override; DLLEXPORT FPRegister getRegister() const; DLLEXPORT FPRegisterPart getPart() const; }; enum class MemoryBlockSize { // 8 bist BYTE = 1, // 16 bits WORD = 2, // 32 bits DWORD = 4, // 64 bits QWORD = 8, // 128 bits M128 = 16, // 256 bits M256 = 32, // 512 bits // M512 = 64 }; /** Represents the usage of a Memory Read Request as an Instruction Argument. */ class MemoryAccessArgument : public OperationArgument { private: MemoryBlockSize blockSize; // size of the block to access (1,2,4,8) bool useAddressReg; GPRegister address; int offset; // offset from the address in the register GPRegister offsetReg; bool useOffsetReg; public: DLLEXPORT MemoryAccessArgument(MemoryBlockSize blockSize, GPRegister address, bool useAddressReg = true, int offset = 0, bool useOffsetReg = false, GPRegister offsetReg = RAX); DLLEXPORT bool usesRegister(GPRegister reg) const override; DLLEXPORT void replaceRegister( GPRegister oldReg, GPRegister newReg) override; DLLEXPORT bool isUsingAddressRegister() const; DLLEXPORT GPRegister getAddressRegister() const; DLLEXPORT int getOffset() const; DLLEXPORT bool isUsingOffsetRegister() const; DLLEXPORT GPRegister getOffsetRegister() const; DLLEXPORT MemoryBlockSize getBlockSize() const; }; /** Represents the usage of a const value as an Instruction Argument. */ class ConstantArgument : public OperationArgument { private: __int64 value; MemoryBlockSize size; // size in byte public: DLLEXPORT ConstantArgument( __int64 value, MemoryBlockSize size = MemoryBlockSize::QWORD); DLLEXPORT ConstantArgument( int value, MemoryBlockSize size = MemoryBlockSize::DWORD); DLLEXPORT ConstantArgument( short value, MemoryBlockSize size = MemoryBlockSize::WORD); DLLEXPORT ConstantArgument( char value, MemoryBlockSize size = MemoryBlockSize::BYTE); DLLEXPORT __int64 getValue() const; DLLEXPORT MemoryBlockSize getSize() const; }; /** Represents the usage of a jump label as an Instruction Argument. */ class JumpTargetArgument : public OperationArgument { private: Text name; public: DLLEXPORT JumpTargetArgument(Text name); DLLEXPORT void addJumpLabelPrefix(Text labelPrefix) override; const Text& getLabel() const; }; /** Represents a single assembly instruction with its arguments. */ class Instruction : public Framework::ReferenceCounter { private: Operation op; std::vector args; std::vector implicitReadGPs; std::vector implicitReadFPs; std::vector implicitWriteGPs; std::vector implicitWriteFPs; public: DLLEXPORT Instruction( Operation op, std::initializer_list params); DLLEXPORT Instruction(Operation op, std::initializer_list params, std::initializer_list implicitReadGPs, std::initializer_list implicitReadFPs, std::initializer_list implicitWriteGPs, std::initializer_list implicitWriteFPs); DLLEXPORT ~Instruction(); /** * checks if this instruction reads from a specified register. * * \param reg the register to check * \return true if the instruction reads from the register */ DLLEXPORT bool writesToRegister( GPRegister reg, const AssemblyBlock* block) const; /** * checks if this instruction reads from a specified register. * * \param reg the register to check * \return true if the instruction reads from the register */ DLLEXPORT bool writesToRegister( FPRegister reg, const AssemblyBlock* block) const; /** * checks if this instruction reads from a specified register. * * \param reg the register to check * \return true if the instruction reads from the register */ DLLEXPORT bool readsFromRegister( GPRegister reg, const AssemblyBlock* block) const; /** * checks if this instruction reads from a specified register. * * \param reg the register to check * \return true if the instruction reads from the register */ DLLEXPORT bool readsFromRegister( FPRegister reg, const AssemblyBlock* block) const; /** * checks if a register can be replaced by another register. * * \param oldReg the register to replace * \param newReg the register to use instead * \return true if the replacement is possible */ DLLEXPORT bool isReplacementPossible(GPRegister oldReg, GPRegister newReg, const AssemblyBlock* block) const; /** * checks if a register can be replaced by another register. * * \param oldReg the register to replace * \param newReg the register to use instead * \return true if the replacement is possible */ DLLEXPORT bool isReplacementPossible(FPRegister oldReg, FPRegister newReg, const AssemblyBlock* block) const; /** * replaces a register with another register. * * \param oldReg the register to replace * \param newReg the register to use instead */ DLLEXPORT void replaceRegister( GPRegister oldReg, GPRegister newReg); /** * replaces a register with another register. * * \param oldReg the register to replace * \param newReg the register to use instead */ DLLEXPORT void replaceRegister( FPRegister oldReg, FPRegister newReg); /** * adds a prefix to all jump labels in this instruction to avoid * conflicts if the assembly block that contains this instruction is * inlined into another block. * * \param labelPrefix the label prefix to add */ DLLEXPORT void addJumpLabelPrefix(Text labelPrefix); /** * compiles this Instruction to macine code. * * \param machineCodeWriter the machine code will be written to this * writer * \param block the block that contains this instruction. needed to * resolve jump labels */ DLLEXPORT void compile(StreamWriter* machineCodeWriter, const AssemblyBlock* block) const; /** * test if this instruction is valid. * * \param block the code block that contains this instruction * \return true if the instruction can be compiled */ DLLEXPORT bool isValid(const AssemblyBlock* block) const; /** * calculates the bytes needed for this instruction in machine code. * * \return the bytes needed */ DLLEXPORT int compiledSize(const AssemblyBlock* block) const; /** * \return the op code of this instruction */ DLLEXPORT Operation getOperation() const; /** * \return true if the given label is defined by this operation */ DLLEXPORT bool definesLabel(Text label) const; /** * \return the arguments of this instruction */ DLLEXPORT const std::vector& getArguments() const; }; /** Represents a block of assembly instructions that can be compiled to machine code or inlined into another AssemblyBlock with addBlock(...). */ class AssemblyBlock { private: RCArray instructions; int inlineIndex; void* compiledCode; public: DLLEXPORT AssemblyBlock(); DLLEXPORT ~AssemblyBlock(); /** * adds an instruction. * * \param instr the instruction to add. */ DLLEXPORT void addInstruction(Instruction* instr); /** * defines a new jump target label. * * \param name the name of the label. */ DLLEXPORT void defineJumpTarget(Text name); /** * adds a jump instruction that jumps to the next Instaruction after * the definition of the given label. * * \param jumpOp the op code of the jump iperation. * \param targetName the label to jump to. */ DLLEXPORT void addJump(Operation jumpOp, Text targetName); /** * adds the value of the source register to the value of the target * register and stores the result in the target register. single * operation. * * \param target the target register * \param source the source register * \param part the register part */ DLLEXPORT void addAddition(GPRegister target, GPRegister source, GPRegisterPart part = FULL64); /** * adds the value of the source register to the value of the target * register and stores the result in the target register. single * operation. * * \param target the target register * \param source the source register * \param type the data type stored in the registers * \param part the register part */ DLLEXPORT void addAddition(FPRegister target, FPRegister source, FPDataType type, FPRegisterPart part = Y); /** * subtracts the value of the target register from the value of the * source register and stores the result in the target register. * single operation. * * \param target the target register * \param source the source register * \param part the register part */ DLLEXPORT void addSubtraction(GPRegister target, GPRegister source, GPRegisterPart part = FULL64); /** * subtracts the value of the target register from the value of the * source register and stores the result in the target register. * single operation. * * \param target the target register * \param source the source register * \param type the data type stored in the registers * \param part the register part */ DLLEXPORT void addSubtraction(FPRegister target, FPRegister source, FPDataType type, FPRegisterPart part = Y); /** * multiplies the value of the source register to the value of the * target register and stores the result in the target register. * single operation. * * \param target the target register * \param source the source register * \param part the register part */ DLLEXPORT void addMultiplication(GPRegister target, GPRegister source, GPRegisterPart part = FULL64); /** * multiplies the value of the source register to the value of the * target register and stores the result in the target register. * single operation. * * \param target the target register * \param source the source register * \param type the data type stored in the registers * \param part the register part */ DLLEXPORT void addMultiplication(FPRegister target, FPRegister source, FPDataType type, FPRegisterPart part = Y); /** * devides the value of the target register by the value of the * source register and stores the result in the target register. * single operation. * * \param target the target register * \param source the source register * \param part the register part */ DLLEXPORT void addDivision(GPRegister target, GPRegister source, GPRegisterPart part = FULL64); /** * devides the value of the target register by the value of the * source register and stores the result in the target register. * single operation. * * \param target the target register * \param source the source register * \param type the data type stored in the registers * \param part the register part */ DLLEXPORT void addDivision(FPRegister target, FPRegister source, FPDataType type, FPRegisterPart part = Y); /** * performes bitwise AND without storing the result. only * SpecialRegister.FLAGS (SF, ZF, PF) is affected. Single operation. * * \param r1 the first value * \param r2 the second value * \param part the part of the values to test */ DLLEXPORT void addTest( GPRegister r1, GPRegister r2, GPRegisterPart part = FULL64); /** * subtracts the value of r2 from r1 and sets FLAGS (CF, OF, SF, ZF, * AF, PF) according to the result. The result is discarded. * * \param r1 the first value * \param r2 the second value * \param part the part of the values to compare */ DLLEXPORT void addCompare( GPRegister r1, GPRegister r2, GPRegisterPart part = FULL64); /** * subtracts the value from r1 and sets FLAGS (CF, OF, SF, ZF, * AF, PF) according to the result. The result is discarded. * * \param r1 the first value * \param value the value to subtract */ DLLEXPORT void addCompare(GPRegister r1, char value); /** * subtracts the value from r1 and sets FLAGS (CF, OF, SF, ZF, * AF, PF) according to the result. The result is discarded. * * \param r1 the first value * \param value the value to subtract */ DLLEXPORT void addCompare(GPRegister r1, short value); /** * subtracts the value from r1 and sets FLAGS (CF, OF, SF, ZF, * AF, PF) according to the result. The result is discarded. * * \param r1 the first value * \param value the value to subtract */ DLLEXPORT void addCompare(GPRegister r1, int value); /** * subtracts the value of r2 from r1 and sets FLAGS (ZF, PF, CF). * the result is discarded * * UNORDERED: ZF,PF,CF := 111; * GREATER_THAN: ZF,PF,CF := 000; * LESS_THAN: ZF,PF,CF := 001; * EUAL: ZF,PF,CF := 100; * * \param r1 the first value * \param r2 the second value * \param type the datatype to compare. only SINGLE types are valid */ DLLEXPORT void addCompare( FPRegister r1, FPRegister r2, FPDataType type); /** * computes bitwise AND for the values in source and target * register and stores the result in the target register. single * operation * * \param target the target register * \param source the source register * \param part the register part */ DLLEXPORT void addAnd(GPRegister target, GPRegister source, GPRegisterPart part = FULL64); /** * computes bitwise AND for the values in source and target register * and stores the result in the target register. single operation * * \param target the target register * \param source the source register * \param part the register part */ DLLEXPORT void addOr(GPRegister target, GPRegister source, GPRegisterPart part = FULL64); /** * writes the specified valueAddress pointer into a register. * * \param valueAddress the pointer to the value witch address should * be stored * \param target the register where the address should be stored */ DLLEXPORT void addLoadValue(char* valueAddress, GPRegister target); /** * writes the specified valueAddress pointer into a register. * * \param valueAddress the pointer to the value witch address should * be stored * \param target the register where the address should be stored */ DLLEXPORT void addLoadValue(short* valueAddress, GPRegister target); /** * writes the specified valueAddress pointer into a register. * * \param valueAddress the pointer to the value witch address should * be stored * \param target the register where the address should be stored */ DLLEXPORT void addLoadValue(int* valueAddress, GPRegister target); /** * writes the specified valueAddress pointer into a register. * * \param valueAddress the pointer to the value witch address should * be stored * \param target the register where the address should be stored */ DLLEXPORT void addLoadValue( __int64* valueAddress, GPRegister target); /** * loads the value at the address stored in addressRegister into the * target register. Single operation. * * \param addressRegister a register that contains a memory address * \param target the target register to store the value into * \param targetPart the part of the target register that will be * written to */ DLLEXPORT void addLoadValue(GPRegister addressRegister, GPRegister target, GPRegisterPart targetPart, int offset = 0); /** * writes the specified valueAddress pointer into a register. * * \param valueAddress the pointer to the value witch address should * be stored * \param target the register where the address should be stored */ DLLEXPORT void addLoadValue( float* valueAddress, FPRegister target, GPRegister temp = RAX); /** * writes the specified valueAddress pointer into a register. * * \param valueAddress the pointer to the value witch address should * be stored * \param target the register where the address should be stored */ DLLEXPORT void addLoadValue( double* valueAddress, FPRegister target, GPRegister temp = RAX); /** * calls a function at a specified memory address. * * \param functionAddress pointet to the address of the function to * call */ template DLLEXPORT void addLoadAddress(T* addr, GPRegister temp = RAX) { instructions.add(new Instruction(MOV, {new GPRegisterArgument(temp), new ConstantArgument( reinterpret_cast<__int64>(addr))})); } /** * moves the given value to LOWER8 bits of target register. * * \param target the register to move the value to * \param value the value to move */ DLLEXPORT void addMoveValue(GPRegister target, char value); /** * moves the given value to LOWER16 bits of target register. * * \param target the register to move the value to * \param value the value to move */ DLLEXPORT void addMoveValue(GPRegister target, short value); /** * moves the given value to LOWER32 bits of target register. * * \param target the register to move the value to * \param value the value to move */ DLLEXPORT void addMoveValue(GPRegister target, int value); /** * moves the given value to LOWER64 bits of target register. * * \param target the register to move the value to * \param value the value to move */ DLLEXPORT void addMoveValue(GPRegister target, __int64 value); /** * moves the given value to LOWER32 bits of target register. * The value needs to be temporarily pushed to the stack, so * addLoadValue should be used if performance is critical. * * \param target the register to move the value to * \param value the value to move * \param temp temporary register that can be used us store the * value */ DLLEXPORT void addMoveValue( FPRegister target, float value, GPRegister temp = RAX); /** * moves the given value to LOWER64 bits of target register. * The value needs to be temporarily pushed to the stack, so * addLoadValue should be used if performance is critical. * * \param target the register to move the value to * \param value the value to move * \param temp temporary register that can be used us store the * value */ DLLEXPORT void addMoveValue( FPRegister target, double value, GPRegister temp = RAX); /** * moves the value from source register to target register. * * \param target the register to move the value to * \param source the register to move the value from * \param part the part of the register to move */ DLLEXPORT void addMoveValue(GPRegister target, GPRegister source, GPRegisterPart part = FULL64); /** * moves the value from source register to target register. * * \param target the register to move the value to * \param source the register to move the value from * \param part the part of the register to move */ DLLEXPORT void addMoveValue(FPRegister target, FPRegister source, FPDataType type, FPRegisterPart part = Y); /** * converts a floating point value from source register into a * signed integer value and writes it into the target register. * Single operation. * * \param target the target register * \param source the source register * \param type the datatype of the source register. Only SINGLE * types are valid. * \param targetPart the register part to write the result into. * Only LOWER32 or FULL64 are valid. * \param round if true the value is rounded acourding to bits 13 * and 14 of the MXCSR register value */ DLLEXPORT void addConversion(GPRegister target, FPRegister source, FPDataType type, GPRegisterPart targetPart, bool round = 0); /** * converts a signed integer from source register into a floating * point value and writes it into the target register. Single * operation * * \param target the target register * \param source the source register * \param targetType the data type after the conversion. Only SINGLE * types are valid. * \param sourcePart the register part that contains the signed * integer. Only LOWER32 and FULL64 are valid. */ DLLEXPORT void addConversion(FPRegister target, GPRegister source, FPDataType targetType, GPRegisterPart sourcePart); /** * calls a function at a specified memory address. * * \param functionAddress pointet to the address of the function to * call * \param gpParams must be the the every n-th entry of the register * list (RCX, RDX, R8, R9) for each n-th function parameter that is * of type integer * \param fpParams must be the the every n-th entry of the register * list (MM0, MM1, MM2, MM3) for each n-th function parameter that * is of type float/double * \param temp temporary register to store the address of the * function * \param bpTemp temporary register to store the stack pointer * before ligning the stack pointer to a 16 byte boundry. The stack * pointer will be automatically restored after the function call * using the value of this register. A non-volatile register must be * used. */ DLLEXPORT void addCall(void* functionAddress, FuncReturnType returnType = NO_VALUE, std::initializer_list gpParams = {}, std::initializer_list fpParams = {}, GPRegister temp = RAX, GPRegister bpTemp = RBP); /** * calls a function at a specified memory address. * * \param functionAddress pointet to the address of the function to * call * \param gpParams must be the the every n-th entry of the register * list (RCX, RDX, R8, R9) for each n-th function parameter that is * of type integer * \param fpParams must be the the every n-th entry of the register * list (MM0, MM1, MM2, MM3) for each n-th function parameter that * is of type float/double * \param temp temporary register to store the address of the * function * \param bpTemp temporary register to store the stack pointer * before ligning the stack pointer to a 16 byte boundry. The stack * pointer will be automatically restored after the function call * using the value of this register. A non-volatile register must be * used. */ template DLLEXPORT void addMemberCall(T&& functionAddress, FuncReturnType returnType = NO_VALUE, std::initializer_list gpParams = {}, std::initializer_list fpParams = {}, GPRegister temp = RAX, GPRegister bpTemp = RBP) { addCall((void*&)functionAddress, returnType, gpParams, fpParams, temp, bpTemp); } /** * returns from executing the compiled assembly function. */ DLLEXPORT void addReturn(); /** * pushes a register into the stack. * * \param reg the register to push * \param part the part of the register to push */ DLLEXPORT void addPush( GPRegister reg, GPRegisterPart part = FULL64); /** * pops a value from the sack into a specified register. * * \param reg the register to store the popped value * \param part the part of the register to store the popped value */ DLLEXPORT void addPop(GPRegister reg, GPRegisterPart part = FULL64); /** * pushes a register into the stack. * * \param reg the register to push * \param type the datatype of the register * \param part the part of the register */ DLLEXPORT void addPush( FPRegister reg, FPDataType type, FPRegisterPart part = X); /** * pops a value from the sack into a specified register. * * \param reg the register to store the popped value * \param type the datatype of the register * \param part the part of the register */ DLLEXPORT void addPop( FPRegister reg, FPDataType type, FPRegisterPart part = X); private: DLLEXPORT void addPop(RCArray& instructionList, FPRegister reg, FPDataType type, FPRegisterPart part = X); public: /** * copies the assembly code from a given block of assembly * instructions. * * \param block the block to inline * \param preservedGPRegisters the GP registers that should be * preserved during the inlined block. if a preserved register is * used in the block, it will be replaced by another register or * pushed to the stack if no free register is available. * \param preservedFPRegisters same as preservedGPRegisters but for * FP registers * \param preservedFPDataTypes data types of the preserved FP * registers used to push them to the stack if needed * \param blockResultGpReg if the register this pointer points to * should be preserved this pointer will be set to the register that * was selected to replace the register during execution of the * block. Ignored if 0. * \param blockResultFpReg same as blockResultGpReg but for FP * Registers */ DLLEXPORT void addBlock(AssemblyBlock* block, std::initializer_list preservedGPRegisters, std::initializer_list preservedFPRegisters, std::initializer_list preservedFPDataTypes, GPRegister* blockResultGpReg, FPRegister* blockResultFpReg); /** * checks if this block writes to a specified register. * * \param reg the register to check * \return true if the block writes to the register */ DLLEXPORT bool writesToRegister(GPRegister reg) const; /** * checks if this block writes to a specified register. * * \param reg the register to check * \return true if the block writes to the register */ DLLEXPORT bool writesToRegister(FPRegister reg) const; /** * checks if this block reads from a specified register. * * \param reg the register to check * \return true if the block reads from the register */ DLLEXPORT bool readsFromRegister(GPRegister reg) const; /** * checks if this block reads from a specified register. * * \param reg the register to check * \return true if the block reads from the register */ DLLEXPORT bool readsFromRegister(FPRegister reg) const; /** * checks if a register can be replaced by another register. * * \param oldReg the register to replace * \param newReg the register to use instead * \return true if the replacement is possible */ DLLEXPORT bool isReplacementPossible( GPRegister oldReg, GPRegister newReg) const; /** * checks if a register can be replaced by another register. * * \param oldReg the register to replace * \param newReg the register to use instead * \return true if the replacement is possible */ DLLEXPORT bool isReplacementPossible( FPRegister oldReg, FPRegister newReg) const; /** * replaces a register with another register. * * \param oldReg the register to replace * \param newReg the register to use instead */ DLLEXPORT void replaceRegister( GPRegister oldReg, GPRegister newReg); /** * replaces a register with another register. * * \param oldReg the register to replace * \param newReg the register to use instead */ DLLEXPORT void replaceRegister( FPRegister oldReg, FPRegister newReg); /** * adds a prefix to all jump labels in this block to avoid conflicts * if this block is inlined into another block. * * \param labelPrefix the label prefix to add */ DLLEXPORT void addJumpLabelPrefix(Text labelPrefix); /** * \return the instructions of this block */ DLLEXPORT const RCArray& getInstructions() const; /** * performs optimisations to shorten the needed instructions. * */ DLLEXPORT void optimize(); /** * \return a pointer to a function that contains the compiled byte * code of this assembly block. and can be called directly with * reinterpret_cast(compile())(parameters...) */ DLLEXPORT void* compile(); /** * \return a pointer to a function that contains the compiled byte * code of this assembly block. and can be called directly with */ template DLLEXPORT T compileToFunction() { return reinterpret_cast(compile()); } }; } // namespace Assembly } // namespace Framework