blob: 969f562dbf0799624027a8f22543f0b78bf78457 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BERBERIS_LITE_TRANSLATOR_RISCV64_TO_X86_64_H_
#define BERBERIS_LITE_TRANSLATOR_RISCV64_TO_X86_64_H_
#include <cstdint>
#include "berberis/assembler/common.h"
#include "berberis/assembler/x86_64.h"
#include "berberis/base/checks.h"
#include "berberis/base/macros.h"
#include "berberis/decoder/riscv64/decoder.h"
#include "berberis/decoder/riscv64/semantics_player.h"
#include "berberis/guest_state/guest_addr.h"
#include "berberis/guest_state/guest_state_riscv64.h"
#include "berberis/lite_translator/lite_translate_region.h"
namespace berberis {
class MachindeCode;
class LiteTranslator {
public:
using Decoder = Decoder<SemanticsPlayer<LiteTranslator>>;
using Register = x86_64::Assembler::Register;
using FpRegister = x86_64::Assembler::XMMRegister;
using Condition = x86_64::Assembler::Condition;
explicit LiteTranslator(MachineCode* machine_code, GuestAddr pc, LiteTranslateParams& params)
: as_(machine_code), success_(true), next_gp_reg_for_alloc_(0), pc_(pc), params_(params){};
//
// Instruction implementations.
//
Register Op(Decoder::OpOpcode opcode, Register arg1, Register arg2);
Register Op32(Decoder::Op32Opcode opcode, Register arg1, Register arg2);
Register OpImm(Decoder::OpImmOpcode opcode, Register arg, int16_t imm);
Register OpImm32(Decoder::OpImm32Opcode opcode, Register arg, int16_t imm);
Register ShiftImm(Decoder::ShiftImmOpcode opcode, Register arg, uint16_t imm);
Register ShiftImm32(Decoder::ShiftImm32Opcode opcode, Register arg, uint16_t imm);
Register Lui(int32_t imm);
Register Auipc(int32_t imm);
void CompareAndBranch(Decoder::BranchOpcode opcode, Register arg1, Register arg2, int16_t offset);
void Branch(int32_t offset);
void BranchRegister(Register base, int16_t offset);
void ExitRegion(GuestAddr target);
void ExitRegionIndirect(Register target);
Register Load(Decoder::LoadOperandType operand_type, Register arg, int16_t offset) {
UNUSED(operand_type, arg, offset);
Unimplemented();
return {};
}
void Store(Decoder::StoreOperandType operand_type, Register arg, int16_t offset, Register data) {
UNUSED(operand_type, arg, offset, data);
Unimplemented();
}
Register Amo(Decoder::AmoOpcode opcode, Register arg1, Register arg2, bool aq, bool rl) {
UNUSED(opcode, arg1, arg2, aq, rl);
Unimplemented();
return {};
}
Register Ecall(Register syscall_nr,
Register arg0,
Register arg1,
Register arg2,
Register arg3,
Register arg4,
Register arg5) {
UNUSED(syscall_nr, arg0, arg1, arg2, arg3, arg4, arg5);
Unimplemented();
return {};
}
void Fence(Decoder::FenceOpcode /*opcode*/,
Register /*src*/,
bool sw,
bool sr,
bool /*so*/,
bool /*si*/,
bool pw,
bool pr,
bool /*po*/,
bool /*pi*/) {
UNUSED(sw, sr, pw, pr);
Unimplemented();
}
void FenceI(Register /*arg*/, int16_t /*imm*/) { Unimplemented(); }
void Nop() {}
//
// F and D extensions.
//
FpRegister OpFp(Decoder::OpFpOpcode opcode,
Decoder::FloatOperandType float_size,
uint8_t rm,
FpRegister arg1,
FpRegister arg2) {
UNUSED(opcode, float_size, rm, arg1, arg2);
Unimplemented();
return {};
}
FpRegister OpFpNoRounding(Decoder::OpFpNoRoundingOpcode opcode,
Decoder::FloatOperandType float_size,
FpRegister arg1,
FpRegister arg2) {
UNUSED(opcode, float_size, arg1, arg2);
Unimplemented();
return {};
}
Register OpFpGpRegisterTargetNoRounding(Decoder::OpFpGpRegisterTargetNoRoundingOpcode opcode,
Decoder::FloatOperandType float_size,
FpRegister arg1,
FpRegister arg2) {
UNUSED(opcode, float_size, arg1, arg2);
Unimplemented();
return {};
}
Register OpFpGpRegisterTargetSingleInputNoRounding(
Decoder::OpFpGpRegisterTargetSingleInputNoRoundingOpcode opcode,
Decoder::FloatOperandType float_size,
FpRegister arg) {
UNUSED(opcode, float_size, arg);
Unimplemented();
return {};
}
FpRegister OpFpSingleInput(Decoder::OpFpSingleInputOpcode opcode,
Decoder::FloatOperandType float_size,
uint8_t rm,
FpRegister arg) {
UNUSED(opcode, float_size, rm, arg);
Unimplemented();
return {};
}
FpRegister Fmv(Register arg) {
UNUSED(arg);
Unimplemented();
return {};
}
Register Fmv(Decoder::FloatOperandType float_size, FpRegister arg) {
UNUSED(float_size, arg);
Unimplemented();
return {};
}
FpRegister Fcvt(Decoder::FloatOperandType target_operand_size,
Decoder::FloatOperandType source_operand_size,
uint8_t rm,
FpRegister arg) {
UNUSED(target_operand_size, source_operand_size, rm, arg);
Unimplemented();
return {};
}
Register Fcvt(Decoder::FcvtOperandType target_operand_size,
Decoder::FloatOperandType source_operand_size,
uint8_t rm,
FpRegister arg) {
UNUSED(target_operand_size, source_operand_size, rm, arg);
Unimplemented();
return {};
}
FpRegister Fcvt(Decoder::FloatOperandType target_operand_size,
Decoder::FcvtOperandType source_operand_size,
uint8_t rm,
Register arg) {
UNUSED(target_operand_size, source_operand_size, rm, arg);
Unimplemented();
return {};
}
FpRegister Fma(Decoder::FmaOpcode opcode,
Decoder::FloatOperandType float_size,
uint8_t rm,
FpRegister arg1,
FpRegister arg2,
FpRegister arg3) {
UNUSED(opcode, float_size, rm, arg1, arg2, arg3);
Unimplemented();
return {};
}
FpRegister LoadFp(Decoder::FloatOperandType opcode, Register arg, int16_t offset) {
UNUSED(opcode, arg, offset);
Unimplemented();
return {};
}
void StoreFp(Decoder::FloatOperandType opcode, Register arg, int16_t offset, FpRegister data) {
UNUSED(opcode, arg, offset, data);
Unimplemented();
}
Register Csr(Decoder::CsrOpcode opcode, Register arg, Decoder::CsrRegister csr) {
UNUSED(opcode, arg, csr);
Unimplemented();
return {};
}
Register Csr(Decoder::CsrImmOpcode opcode, uint8_t imm, Decoder::CsrRegister csr) {
UNUSED(opcode, imm, csr);
Unimplemented();
return {};
}
//
// Guest state getters/setters.
//
GuestAddr GetInsnAddr() const { return pc_; }
Register GetReg(uint8_t reg) {
CHECK_GT(reg, 0);
CHECK_LT(reg, arraysize(ThreadState::cpu.x));
Register result = AllocTempReg();
int32_t offset = offsetof(ThreadState, cpu.x[0]) + reg * 8;
as_.Movq(result, {.base = as_.rbp, .disp = offset});
return result;
}
void SetReg(uint8_t reg, Register value) {
CHECK_GT(reg, 0);
CHECK_LT(reg, arraysize(ThreadState::cpu.x));
int32_t offset = offsetof(ThreadState, cpu.x[0]) + reg * 8;
as_.Movq({.base = as_.rbp, .disp = offset}, value);
}
FpRegister GetFpReg(uint8_t reg) {
UNUSED(reg);
Unimplemented();
return {};
}
FpRegister GetFRegAndUnboxNaN(uint8_t reg, Decoder::FloatOperandType operand_type) {
UNUSED(reg, operand_type);
Unimplemented();
return {};
}
FpRegister CanonicalizeNans(FpRegister value, Decoder::FloatOperandType operand_type) {
UNUSED(value, operand_type);
Unimplemented();
return {};
}
Register CanonicalizeGpNans(Register value, Decoder::FloatOperandType operand_type) {
UNUSED(value, operand_type);
Unimplemented();
return {};
}
void NanBoxAndSetFpReg(uint8_t reg, FpRegister value, Decoder::FloatOperandType operand_type) {
UNUSED(reg, value, operand_type);
Unimplemented();
}
//
// Various helper methods.
//
Register GetImm(uint64_t imm) {
Register imm_reg = AllocTempReg();
as_.Movq(imm_reg, imm);
return imm_reg;
}
void Unimplemented() { success_ = false; }
x86_64::Assembler* as() { return &as_; }
bool success() const { return success_; }
private:
Register AllocTempReg() {
// TODO(286261771): Add rdx to registers, push it on stack in all instances that are clobbering
// it.
static constexpr x86_64::Assembler::Register kRegs[] = {x86_64::Assembler::rbx,
x86_64::Assembler::rsi,
x86_64::Assembler::rdi,
x86_64::Assembler::r8,
x86_64::Assembler::r9,
x86_64::Assembler::r10,
x86_64::Assembler::r11,
x86_64::Assembler::r12,
x86_64::Assembler::r13,
x86_64::Assembler::r14,
x86_64::Assembler::r15};
CHECK_LT(next_gp_reg_for_alloc_, arraysize(kRegs));
return kRegs[next_gp_reg_for_alloc_++];
}
x86_64::Assembler as_;
bool success_;
uint8_t next_gp_reg_for_alloc_;
GuestAddr pc_;
const LiteTranslateParams& params_;
};
} // namespace berberis
#endif // BERBERIS_LITE_TRANSLATOR_RISCV64_TO_X86_64_H_