blob: c1e4b12d0f2d91325bbafb0cfe3f3d4d69fc7f89 [file] [log] [blame]
/*
* Copyright 2021 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_X86_INSTS_MICROOP_ARGS_HH__
#define __ARCH_X86_INSTS_MICROOP_ARGS_HH__
#include <cstdint>
#include <sstream>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include "arch/x86/insts/static_inst.hh"
#include "arch/x86/regs/int.hh"
#include "arch/x86/types.hh"
#include "base/compiler.hh"
#include "base/cprintf.hh"
#include "cpu/reg_class.hh"
#include "sim/faults.hh"
namespace gem5
{
namespace X86ISA
{
struct DestOp
{
const RegIndex dest;
const size_t size;
RegIndex opIndex() const { return dest; }
DestOp(RegIndex _dest, size_t _size) : dest(_dest), size(_size) {}
template <class InstType>
DestOp(RegIndex _dest, InstType *inst) : dest(_dest),
size(inst->getDestSize())
{}
};
struct Src1Op
{
const RegIndex src1;
const size_t size;
RegIndex opIndex() const { return src1; }
Src1Op(RegIndex _src1, size_t _size) : src1(_src1), size(_size) {}
template <class InstType>
Src1Op(RegIndex _src1, InstType *inst) : src1(_src1),
size(inst->getSrcSize())
{}
};
struct Src2Op
{
const RegIndex src2;
const size_t size;
RegIndex opIndex() const { return src2; }
Src2Op(RegIndex _src2, size_t _size) : src2(_src2), size(_size) {}
template <class InstType>
Src2Op(RegIndex _src2, InstType *inst) : src2(_src2),
size(inst->getSrcSize())
{}
};
struct DataOp
{
const RegIndex data;
const size_t size;
RegIndex opIndex() const { return data; }
DataOp(RegIndex _data, size_t _size) : data(_data), size(_size) {}
};
struct DataHiOp
{
const RegIndex dataHi;
const size_t size;
RegIndex opIndex() const { return dataHi; }
DataHiOp(RegIndex data_hi, size_t _size) : dataHi(data_hi), size(_size) {}
};
struct DataLowOp
{
const RegIndex dataLow;
const size_t size;
RegIndex opIndex() const { return dataLow; }
DataLowOp(RegIndex data_low, size_t _size) : dataLow(data_low), size(_size)
{}
};
template <class T, class Enabled=void>
struct HasDataSize : public std::false_type {};
template <class T>
struct HasDataSize<T, decltype((void)&T::dataSize)> : public std::true_type {};
template <class T>
constexpr bool HasDataSizeV = HasDataSize<T>::value;
template <class Base>
struct IntOp : public Base
{
using ArgType = GpRegIndex;
template <class Inst>
IntOp(Inst *inst, std::enable_if_t<HasDataSizeV<Inst>, ArgType> idx) :
Base(idx.index, inst->dataSize)
{}
template <class Inst>
IntOp(Inst *inst, std::enable_if_t<!HasDataSizeV<Inst>, ArgType> idx) :
Base(idx.index, inst)
{}
void
print(std::ostream &os) const
{
X86StaticInst::printReg(os, RegId(IntRegClass, this->opIndex()),
this->size);
}
};
template <class Base>
struct FoldedOp : public Base
{
using ArgType = GpRegIndex;
template <class InstType>
FoldedOp(InstType *inst, ArgType idx) :
Base(INTREG_FOLDED(idx.index, inst->foldOBit), inst->dataSize)
{}
void
print(std::ostream &os) const
{
X86StaticInst::printReg(os, RegId(IntRegClass, this->opIndex()),
this->size);
}
};
template <class Base>
struct CrOp : public Base
{
using ArgType = CrRegIndex;
template <class InstType>
CrOp(InstType *inst, ArgType idx) : Base(idx.index, 0) {}
void
print(std::ostream &os) const
{
ccprintf(os, "cr%d", this->opIndex());
}
};
template <class Base>
struct DbgOp : public Base
{
using ArgType = DbgRegIndex;
template <class InstType>
DbgOp(InstType *inst, ArgType idx) : Base(idx.index, 0) {}
void
print(std::ostream &os) const
{
ccprintf(os, "dr%d", this->opIndex());
}
};
template <class Base>
struct SegOp : public Base
{
using ArgType = SegRegIndex;
template <class InstType>
SegOp(InstType *inst, ArgType idx) : Base(idx.index, 0) {}
void
print(std::ostream &os) const
{
X86StaticInst::printSegment(os, this->opIndex());
}
};
template <class Base>
struct MiscOp : public Base
{
using ArgType = CtrlRegIndex;
template <class InstType>
MiscOp(InstType *inst, ArgType idx) : Base(idx.index, inst->dataSize) {}
void
print(std::ostream &os) const
{
X86StaticInst::printReg(os, RegId(MiscRegClass, this->opIndex()),
this->size);
}
};
template <class Base>
struct FloatOp : public Base
{
using ArgType = FpRegIndex;
template <class Inst>
FloatOp(Inst *inst, std::enable_if_t<HasDataSizeV<Inst>, ArgType> idx) :
Base(idx.index, inst->dataSize)
{}
template <class Inst>
FloatOp(Inst *inst, std::enable_if_t<!HasDataSizeV<Inst>, ArgType> idx) :
Base(idx.index, inst)
{}
void
print(std::ostream &os) const
{
X86StaticInst::printReg(os, RegId(FloatRegClass, this->opIndex()),
this->size);
}
};
using FoldedDestOp = FoldedOp<DestOp>;
using DbgDestOp = DbgOp<DestOp>;
using CrDestOp = CrOp<DestOp>;
using SegDestOp = SegOp<DestOp>;
using MiscDestOp = MiscOp<DestOp>;
using FloatDestOp = FloatOp<DestOp>;
using IntDestOp = IntOp<DestOp>;
using FoldedSrc1Op = FoldedOp<Src1Op>;
using DbgSrc1Op = DbgOp<Src1Op>;
using CrSrc1Op = CrOp<Src1Op>;
using SegSrc1Op = SegOp<Src1Op>;
using MiscSrc1Op = MiscOp<Src1Op>;
using FloatSrc1Op = FloatOp<Src1Op>;
using IntSrc1Op = IntOp<Src1Op>;
using FoldedSrc2Op = FoldedOp<Src2Op>;
using FloatSrc2Op = FloatOp<Src2Op>;
using IntSrc2Op = IntOp<Src2Op>;
using FoldedDataOp = FoldedOp<DataOp>;
using FloatDataOp = FloatOp<DataOp>;
using FoldedDataHiOp = FoldedOp<DataHiOp>;
using FoldedDataLowOp = FoldedOp<DataLowOp>;
struct Imm8Op
{
using ArgType = uint8_t;
uint8_t imm8;
template <class InstType>
Imm8Op(InstType *inst, ArgType _imm8) : imm8(_imm8) {}
void
print(std::ostream &os) const
{
ccprintf(os, "%#x", imm8);
}
};
struct Imm64Op
{
using ArgType = uint64_t;
uint64_t imm64;
template <class InstType>
Imm64Op(InstType *inst, ArgType _imm64) : imm64(_imm64) {}
void
print(std::ostream &os) const
{
ccprintf(os, "%#x", imm64);
}
};
struct UpcOp
{
using ArgType = MicroPC;
MicroPC target;
template <class InstType>
UpcOp(InstType *inst, ArgType _target) : target(_target) {}
void
print(std::ostream &os) const
{
ccprintf(os, "%#x", target);
}
};
struct FaultOp
{
using ArgType = Fault;
Fault fault;
template <class InstType>
FaultOp(InstType *inst, ArgType _fault) : fault(_fault) {}
void
print(std::ostream &os) const
{
ccprintf(os, fault ? fault->name() : "NoFault");
}
};
struct AddrOp
{
struct ArgType
{
uint8_t scale;
GpRegIndex index;
GpRegIndex base;
uint64_t disp;
SegRegIndex segment;
};
const uint8_t scale;
const RegIndex index;
const RegIndex base;
const uint64_t disp;
const uint8_t segment;
const size_t size;
template <class InstType>
AddrOp(InstType *inst, const ArgType &args) : scale(args.scale),
index(INTREG_FOLDED(args.index.index, inst->foldABit)),
base(INTREG_FOLDED(args.base.index, inst->foldABit)),
disp(args.disp), segment(args.segment.index),
size(inst->addressSize)
{
assert(segment < NUM_SEGMENTREGS);
}
void
print(std::ostream &os) const
{
X86StaticInst::printMem(
os, segment, scale, index, base, disp, size, false);
}
};
template <typename Base, typename ...Operands>
class InstOperands : public Base, public Operands...
{
private:
using ArgTuple = std::tuple<typename Operands::ArgType...>;
template <std::size_t ...I, typename ...CTorArgs>
InstOperands(std::index_sequence<I...>, ExtMachInst mach_inst,
const char *mnem, const char *inst_mnem, uint64_t set_flags,
OpClass op_class, [[maybe_unused]] ArgTuple args,
CTorArgs... ctor_args) :
Base(mach_inst, mnem, inst_mnem, set_flags, op_class, ctor_args...),
Operands(this, std::get<I>(args))...
{}
protected:
template <typename ...CTorArgs>
InstOperands(ExtMachInst mach_inst, const char *mnem,
const char *inst_mnem, uint64_t set_flags, OpClass op_class,
ArgTuple args, CTorArgs... ctor_args) :
InstOperands(std::make_index_sequence<sizeof...(Operands)>{},
mach_inst, mnem, inst_mnem, set_flags, op_class,
std::move(args), ctor_args...)
{}
std::string
generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const override
{
std::stringstream response;
Base::printMnemonic(response, this->instMnem, this->mnemonic);
int count = 0;
GEM5_FOR_EACH_IN_PACK(ccprintf(response, count++ ? ", " : ""),
Operands::print(response));
return response.str();
}
};
} // namespace X86ISA
} // namespace gem5
#endif //__ARCH_X86_INSTS_MICROOP_ARGS_HH__