pslang/libs/jit/source/arch/aarch64/instruction_builder.cpp

146 lines
No EOL
5.4 KiB
C++

#include <pslang/jit/arch/aarch64/instruction_builder.hpp>
namespace pslang::jit::aarch64
{
static constexpr std::uint32_t REG_MASK = 0x1fu;
void instruction_builder::movz(std::uint8_t reg, std::uint16_t val, std::uint8_t shift)
{
do_push(0xd2800000u | (reg & REG_MASK) | (val << 5) | ((shift & 0x3u) << 21));
}
void instruction_builder::movk(std::uint8_t reg, std::uint16_t val, std::uint8_t shift)
{
do_push(0xf2800000u | (reg & REG_MASK) | (val << 5) | ((shift & 0x3u) << 21));
}
void instruction_builder::str(std::uint8_t reg_src, std::uint8_t reg_addr, std::uint16_t offset)
{
do_push(0xf9000000u | (reg_src & REG_MASK) | ((reg_addr & REG_MASK) << 5) | ((std::uint16_t(offset) & 0xfffu) << 10));
}
void instruction_builder::str_pre(std::uint8_t reg_src, std::uint8_t reg_addr, std::int16_t offset)
{
do_push(0xf8000c00u | (reg_src & REG_MASK) | ((reg_addr & REG_MASK) << 5) | ((std::uint16_t(offset) & 0x1ffu) << 12));
}
void instruction_builder::ldr(std::uint8_t reg_dst, std::uint8_t reg_addr, std::uint16_t offset)
{
do_push(0xf9400000u | (reg_dst & REG_MASK) | ((reg_addr & REG_MASK) << 5) | ((std::uint16_t(offset) & 0xfffu) << 10));
}
void instruction_builder::ldr_pre(std::uint8_t reg_dst, std::uint8_t reg_addr, std::int16_t offset)
{
do_push(0xf8400c00u | (reg_dst & REG_MASK) | ((reg_addr & REG_MASK) << 5) | ((std::uint16_t(offset) & 0x1ffu) << 12));
}
void instruction_builder::ldr_post(std::uint8_t reg_dst, std::uint8_t reg_addr, std::int16_t offset)
{
do_push(0xf8400400u | (reg_dst & REG_MASK) | ((reg_addr & REG_MASK) << 5) | ((std::uint16_t(offset) & 0x1ffu) << 12));
}
void instruction_builder::add_imm(std::uint8_t reg_src, std::uint8_t reg_dst, std::uint16_t value)
{
do_push(0x91000000u | (reg_dst & REG_MASK) | ((reg_src & REG_MASK) << 5) | ((value & 0xfffu) << 10));
}
void instruction_builder::sub_imm(std::uint8_t reg_src, std::uint8_t reg_dst, std::uint16_t value)
{
do_push(0xd1000000u | (reg_dst & REG_MASK) | ((reg_src & REG_MASK) << 5) | ((value & 0xfffu) << 10));
}
void instruction_builder::add_reg(std::uint8_t reg_src1, std::uint8_t reg_src2, std::uint8_t reg_dst)
{
do_push(0x8b000000u | (reg_dst & REG_MASK) | ((reg_src1 & REG_MASK) << 5) | ((reg_src2 & REG_MASK) << 16));
}
void instruction_builder::sub_reg(std::uint8_t reg_src1, std::uint8_t reg_src2, std::uint8_t reg_dst)
{
do_push(0xcb000000u | (reg_dst & REG_MASK) | ((reg_src1 & REG_MASK) << 5) | ((reg_src2 & REG_MASK) << 16));
}
void instruction_builder::and_reg(std::uint8_t reg_src1, std::uint8_t reg_src2, std::uint8_t reg_dst)
{
do_push(0x8a000000u | (reg_dst & REG_MASK) | ((reg_src1 & REG_MASK) << 5) | ((reg_src2 & REG_MASK) << 16));
}
void instruction_builder::or_reg(std::uint8_t reg_src1, std::uint8_t reg_src2, std::uint8_t reg_dst)
{
do_push(0xaa000000u | (reg_dst & REG_MASK) | ((reg_src1 & REG_MASK) << 5) | ((reg_src2 & REG_MASK) << 16));
}
void instruction_builder::xor_reg(std::uint8_t reg_src1, std::uint8_t reg_src2, std::uint8_t reg_dst)
{
do_push(0xca000000u | (reg_dst & REG_MASK) | ((reg_src1 & REG_MASK) << 5) | ((reg_src2 & REG_MASK) << 16));
}
void instruction_builder::or_not_reg(std::uint8_t reg_src1, std::uint8_t reg_src2, std::uint8_t reg_dst)
{
do_push(0xaa200000u | (reg_dst & REG_MASK) | ((reg_src1 & REG_MASK) << 5) | ((reg_src2 & REG_MASK) << 16));
}
void instruction_builder::mul_reg(std::uint8_t reg_src1, std::uint8_t reg_src2, std::uint8_t reg_dst)
{
do_push(0x9b007c00u | (reg_dst & REG_MASK) | ((reg_src1 & REG_MASK) << 5) | ((reg_src2 & REG_MASK) << 16));
}
void instruction_builder::sdiv_reg(std::uint8_t reg_src1, std::uint8_t reg_src2, std::uint8_t reg_dst)
{
do_push(0x9ac00c00u | (reg_dst & REG_MASK) | ((reg_src1 & REG_MASK) << 5) | ((reg_src2 & REG_MASK) << 16));
}
void instruction_builder::udiv_reg(std::uint8_t reg_src1, std::uint8_t reg_src2, std::uint8_t reg_dst)
{
do_push(0x9ac00800u | (reg_dst & REG_MASK) | ((reg_src1 & REG_MASK) << 5) | ((reg_src2 & REG_MASK) << 16));
}
void instruction_builder::cmp_reg(std::uint8_t reg_src1, std::uint8_t reg_src2)
{
do_push(0xeb20601fu | ((reg_src1 & REG_MASK) << 5) | ((reg_src2 & REG_MASK) << 16));
}
void instruction_builder::cset(std::uint8_t reg_dst, std::uint8_t cond)
{
do_push(0x9a9f07e0u | (reg_dst & REG_MASK) | (((cond & 0xfu) ^ 1) << 12));
}
void instruction_builder::csel(std::uint8_t reg_src1, std::uint8_t reg_src2, std::uint8_t reg_dst, std::uint8_t cond)
{
do_push(0x9a800000u | (reg_dst & REG_MASK) | ((reg_src1 & REG_MASK) << 5) | ((reg_src2 & REG_MASK) << 16) | ((cond & 0xfu) << 12));
}
void instruction_builder::sbfm(std::uint8_t reg_src, std::uint8_t reg_dst, std::uint8_t bit_count)
{
do_push(0x93400000u | (reg_dst & REG_MASK) | ((reg_src & REG_MASK) << 5) | (((bit_count - 1) & 0x3fu) << 10));
}
void instruction_builder::ubfm(std::uint8_t reg_src, std::uint8_t reg_dst, std::uint8_t bit_count)
{
do_push(0xd3400000u | (reg_dst & REG_MASK) | ((reg_src & REG_MASK) << 5) | (((bit_count - 1) & 0x3fu) << 10));
}
void instruction_builder::ret(std::uint8_t reg)
{
do_push(0xd65f0000u | ((reg & REG_MASK) << 5));
}
void instruction_builder::push(std::uint8_t reg)
{
str_pre(reg, 31, -8);
}
void instruction_builder::pop(std::uint8_t reg)
{
ldr_post(reg, 31, 8);
}
void instruction_builder::do_push(std::uint32_t opcode)
{
code.push_back((opcode >> 0) & 0xffu);
code.push_back((opcode >> 8) & 0xffu);
code.push_back((opcode >> 16) & 0xffu);
code.push_back((opcode >> 24) & 0xffu);
}
}