blob: 48a5f0a2f6e8c7f56e158ebe33df30c7efec2eb0 [file] [log] [blame]
//===- subzero/src/assembler_ia32.h - Assembler for x86-32 ------*- C++ -*-===//
//
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// Modified by the Subzero authors.
//
//===----------------------------------------------------------------------===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Assembler class for x86-32.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICEASSEMBLERX8632_H
#define SUBZERO_SRC_ICEASSEMBLERX8632_H
#include "IceAssembler.h"
#include "IceConditionCodesX8632.h"
#include "IceDefs.h"
#include "IceOperand.h"
#include "IceRegistersX8632.h"
#include "IceTypes.h"
#include "IceUtils.h"
namespace Ice {
using RegX8632::GPRRegister;
using RegX8632::XmmRegister;
using RegX8632::ByteRegister;
using RegX8632::X87STRegister;
namespace X8632 {
const int MAX_NOP_SIZE = 8;
enum ScaleFactor { TIMES_1 = 0, TIMES_2 = 1, TIMES_4 = 2, TIMES_8 = 3 };
class Immediate {
Immediate(const Immediate &) = delete;
Immediate &operator=(const Immediate &) = delete;
public:
explicit Immediate(int32_t value) : value_(value) {}
Immediate(RelocOffsetT offset, AssemblerFixup *fixup)
: value_(offset), fixup_(fixup) {
// Use the Offset in the "value" for now. If we decide to process fixups,
// we'll need to patch that offset with the true value.
}
int32_t value() const { return value_; }
AssemblerFixup *fixup() const { return fixup_; }
bool is_int8() const {
// We currently only allow 32-bit fixups, and they usually have value = 0,
// so if fixup_ != nullptr, it shouldn't be classified as int8/16.
return fixup_ == nullptr && Utils::IsInt(8, value_);
}
bool is_uint8() const {
return fixup_ == nullptr && Utils::IsUint(8, value_);
}
bool is_uint16() const {
return fixup_ == nullptr && Utils::IsUint(16, value_);
}
private:
const int32_t value_;
AssemblerFixup *fixup_ = nullptr;
};
class Operand {
public:
Operand(const Operand &other) : length_(other.length_), fixup_(other.fixup_) {
memmove(&encoding_[0], &other.encoding_[0], other.length_);
}
Operand &operator=(const Operand &other) {
length_ = other.length_;
fixup_ = other.fixup_;
memmove(&encoding_[0], &other.encoding_[0], other.length_);
return *this;
}
uint8_t mod() const { return (encoding_at(0) >> 6) & 3; }
GPRRegister rm() const {
return static_cast<GPRRegister>(encoding_at(0) & 7);
}
ScaleFactor scale() const {
return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3);
}
GPRRegister index() const {
return static_cast<GPRRegister>((encoding_at(1) >> 3) & 7);
}
GPRRegister base() const {
return static_cast<GPRRegister>(encoding_at(1) & 7);
}
int8_t disp8() const {
assert(length_ >= 2);
return static_cast<int8_t>(encoding_[length_ - 1]);
}
int32_t disp32() const {
assert(length_ >= 5);
return bit_copy<int32_t>(encoding_[length_ - 4]);
}
AssemblerFixup *fixup() const { return fixup_; }
protected:
Operand() : length_(0), fixup_(nullptr) {} // Needed by subclass Address.
void SetModRM(int mod, GPRRegister rm) {
assert((mod & ~3) == 0);
encoding_[0] = (mod << 6) | rm;
length_ = 1;
}
void SetSIB(ScaleFactor scale, GPRRegister index, GPRRegister base) {
assert(length_ == 1);
assert((scale & ~3) == 0);
encoding_[1] = (scale << 6) | (index << 3) | base;
length_ = 2;
}
void SetDisp8(int8_t disp) {
assert(length_ == 1 || length_ == 2);
encoding_[length_++] = static_cast<uint8_t>(disp);
}
void SetDisp32(int32_t disp) {
assert(length_ == 1 || length_ == 2);
intptr_t disp_size = sizeof(disp);
memmove(&encoding_[length_], &disp, disp_size);
length_ += disp_size;
}
void SetFixup(AssemblerFixup *fixup) { fixup_ = fixup; }
private:
uint8_t length_;
uint8_t encoding_[6];
AssemblerFixup *fixup_;
explicit Operand(GPRRegister reg) : fixup_(nullptr) { SetModRM(3, reg); }
// Get the operand encoding byte at the given index.
uint8_t encoding_at(intptr_t index) const {
assert(index >= 0 && index < length_);
return encoding_[index];
}
// Returns whether or not this operand is really the given register in
// disguise. Used from the assembler to generate better encodings.
bool IsRegister(GPRRegister reg) const {
return ((encoding_[0] & 0xF8) == 0xC0) // Addressing mode is register only.
&& ((encoding_[0] & 0x07) == reg); // Register codes match.
}
friend class AssemblerX8632;
};
class Address : public Operand {
public:
Address(const Address &other) : Operand(other) {}
Address &operator=(const Address &other) {
Operand::operator=(other);
return *this;
}
Address(GPRRegister base, int32_t disp) {
if (disp == 0 && base != RegX8632::Encoded_Reg_ebp) {
SetModRM(0, base);
if (base == RegX8632::Encoded_Reg_esp)
SetSIB(TIMES_1, RegX8632::Encoded_Reg_esp, base);
} else if (Utils::IsInt(8, disp)) {
SetModRM(1, base);
if (base == RegX8632::Encoded_Reg_esp)
SetSIB(TIMES_1, RegX8632::Encoded_Reg_esp, base);
SetDisp8(disp);
} else {
SetModRM(2, base);
if (base == RegX8632::Encoded_Reg_esp)
SetSIB(TIMES_1, RegX8632::Encoded_Reg_esp, base);
SetDisp32(disp);
}
}
Address(GPRRegister index, ScaleFactor scale, int32_t disp) {
assert(index != RegX8632::Encoded_Reg_esp); // Illegal addressing mode.
SetModRM(0, RegX8632::Encoded_Reg_esp);
SetSIB(scale, index, RegX8632::Encoded_Reg_ebp);
SetDisp32(disp);
}
Address(GPRRegister base, GPRRegister index, ScaleFactor scale,
int32_t disp) {
assert(index != RegX8632::Encoded_Reg_esp); // Illegal addressing mode.
if (disp == 0 && base != RegX8632::Encoded_Reg_ebp) {
SetModRM(0, RegX8632::Encoded_Reg_esp);
SetSIB(scale, index, base);
} else if (Utils::IsInt(8, disp)) {
SetModRM(1, RegX8632::Encoded_Reg_esp);
SetSIB(scale, index, base);
SetDisp8(disp);
} else {
SetModRM(2, RegX8632::Encoded_Reg_esp);
SetSIB(scale, index, base);
SetDisp32(disp);
}
}
static Address Absolute(const uintptr_t addr) {
Address result;
result.SetModRM(0, RegX8632::Encoded_Reg_ebp);
result.SetDisp32(addr);
return result;
}
static Address Absolute(RelocOffsetT Offset, AssemblerFixup *fixup) {
Address result;
result.SetModRM(0, RegX8632::Encoded_Reg_ebp);
// Use the Offset in the displacement for now. If we decide to process
// fixups later, we'll need to patch up the emitted displacement.
result.SetDisp32(Offset);
result.SetFixup(fixup);
return result;
}
static Address ofConstPool(Assembler *Asm, const Constant *Imm);
private:
Address() = default; // Needed by Address::Absolute.
};
class Label {
Label(const Label &) = delete;
Label &operator=(const Label &) = delete;
public:
Label() {
#ifndef NDEBUG
for (int i = 0; i < kMaxUnresolvedBranches; i++) {
unresolved_near_positions_[i] = -1;
}
#endif // !NDEBUG
}
~Label() = default;
void FinalCheck() const {
// Assert if label is being destroyed with unresolved branches pending.
assert(!IsLinked());
assert(!HasNear());
}
// TODO(jvoung): why are labels offset by this?
static const uint32_t kWordSize = sizeof(uint32_t);
// Returns the position for bound labels (branches that come after this
// are considered backward branches). Cannot be used for unused or linked
// labels.
intptr_t Position() const {
assert(IsBound());
return -position_ - kWordSize;
}
// Returns the position of an earlier branch instruction that was linked
// to this label (branches that use this are considered forward branches).
// The linked instructions form a linked list, of sorts, using the
// instruction's displacement field for the location of the next
// instruction that is also linked to this label.
intptr_t LinkPosition() const {
assert(IsLinked());
return position_ - kWordSize;
}
// Returns the position of an earlier branch instruction which
// assumes that this label is "near", and bumps iterator to the
// next near position.
intptr_t NearPosition() {
assert(HasNear());
return unresolved_near_positions_[--num_unresolved_];
}
bool IsBound() const { return position_ < 0; }
bool IsLinked() const { return position_ > 0; }
bool IsUnused() const { return (position_ == 0) && (num_unresolved_ == 0); }
bool HasNear() const { return num_unresolved_ != 0; }
private:
void BindTo(intptr_t position) {
assert(!IsBound());
assert(!HasNear());
position_ = -position - kWordSize;
assert(IsBound());
}
void LinkTo(intptr_t position) {
assert(!IsBound());
position_ = position + kWordSize;
assert(IsLinked());
}
void NearLinkTo(intptr_t position) {
assert(!IsBound());
assert(num_unresolved_ < kMaxUnresolvedBranches);
unresolved_near_positions_[num_unresolved_++] = position;
}
static const int kMaxUnresolvedBranches = 20;
intptr_t position_ = 0;
intptr_t num_unresolved_ = 0;
// TODO(stichnot,jvoung): Can this instead be
// llvm::SmallVector<intptr_t, kMaxUnresolvedBranches> ?
intptr_t unresolved_near_positions_[kMaxUnresolvedBranches];
friend class AssemblerX8632;
};
class AssemblerX8632 : public Assembler {
AssemblerX8632(const AssemblerX8632 &) = delete;
AssemblerX8632 &operator=(const AssemblerX8632 &) = delete;
public:
explicit AssemblerX8632(bool use_far_branches = false) : Assembler() {
// This mode is only needed and implemented for MIPS and ARM.
assert(!use_far_branches);
(void)use_far_branches;
}
~AssemblerX8632() override;
static const bool kNearJump = true;
static const bool kFarJump = false;
void alignFunction() override;
SizeT getBundleAlignLog2Bytes() const override { return 5; }
const char *getNonExecPadDirective() const override { return ".p2align"; }
llvm::ArrayRef<uint8_t> getNonExecBundlePadding() const override {
static const uint8_t Padding[] = {0xF4};
return llvm::ArrayRef<uint8_t>(Padding, 1);
}
void padWithNop(intptr_t Padding) override {
while (Padding > MAX_NOP_SIZE) {
nop(MAX_NOP_SIZE);
Padding -= MAX_NOP_SIZE;
}
if (Padding)
nop(Padding);
}
Label *GetOrCreateCfgNodeLabel(SizeT NodeNumber);
void bindCfgNodeLabel(SizeT NodeNumber) override;
Label *GetOrCreateLocalLabel(SizeT Number);
void BindLocalLabel(SizeT Number);
bool fixupIsPCRel(FixupKind Kind) const override {
// Currently assuming this is the only PC-rel relocation type used.
return Kind == llvm::ELF::R_386_PC32;
}
// Operations to emit GPR instructions (and dispatch on operand type).
typedef void (AssemblerX8632::*TypedEmitGPR)(Type, GPRRegister);
typedef void (AssemblerX8632::*TypedEmitAddr)(Type, const Address &);
struct GPREmitterOneOp {
TypedEmitGPR Reg;
TypedEmitAddr Addr;
};
typedef void (AssemblerX8632::*TypedEmitGPRGPR)(Type, GPRRegister,
GPRRegister);
typedef void (AssemblerX8632::*TypedEmitGPRAddr)(Type, GPRRegister,
const Address &);
typedef void (AssemblerX8632::*TypedEmitGPRImm)(Type, GPRRegister,
const Immediate &);
struct GPREmitterRegOp {
TypedEmitGPRGPR GPRGPR;
TypedEmitGPRAddr GPRAddr;
TypedEmitGPRImm GPRImm;
};
struct GPREmitterShiftOp {
// Technically, Addr/GPR and Addr/Imm are also allowed, but */Addr are not.
// In practice, we always normalize the Dest to a Register first.
TypedEmitGPRGPR GPRGPR;
TypedEmitGPRImm GPRImm;
};
typedef void (AssemblerX8632::*TypedEmitGPRGPRImm)(Type, GPRRegister,
GPRRegister,
const Immediate &);
struct GPREmitterShiftD {
// Technically AddrGPR and AddrGPRImm are also allowed, but in practice
// we always normalize Dest to a Register first.
TypedEmitGPRGPR GPRGPR;
TypedEmitGPRGPRImm GPRGPRImm;
};
typedef void (AssemblerX8632::*TypedEmitAddrGPR)(Type, const Address &,
GPRRegister);
typedef void (AssemblerX8632::*TypedEmitAddrImm)(Type, const Address &,
const Immediate &);
struct GPREmitterAddrOp {
TypedEmitAddrGPR AddrGPR;
TypedEmitAddrImm AddrImm;
};
// Operations to emit XMM instructions (and dispatch on operand type).
typedef void (AssemblerX8632::*TypedEmitXmmXmm)(Type, XmmRegister,
XmmRegister);
typedef void (AssemblerX8632::*TypedEmitXmmAddr)(Type, XmmRegister,
const Address &);
struct XmmEmitterRegOp {
TypedEmitXmmXmm XmmXmm;
TypedEmitXmmAddr XmmAddr;
};
typedef void (AssemblerX8632::*EmitXmmXmm)(XmmRegister, XmmRegister);
typedef void (AssemblerX8632::*EmitXmmAddr)(XmmRegister, const Address &);
typedef void (AssemblerX8632::*EmitAddrXmm)(const Address &, XmmRegister);
struct XmmEmitterMovOps {
EmitXmmXmm XmmXmm;
EmitXmmAddr XmmAddr;
EmitAddrXmm AddrXmm;
};
typedef void (AssemblerX8632::*TypedEmitXmmImm)(Type, XmmRegister,
const Immediate &);
struct XmmEmitterShiftOp {
TypedEmitXmmXmm XmmXmm;
TypedEmitXmmAddr XmmAddr;
TypedEmitXmmImm XmmImm;
};
// Cross Xmm/GPR cast instructions.
template <typename DReg_t, typename SReg_t> struct CastEmitterRegOp {
typedef void (AssemblerX8632::*TypedEmitRegs)(Type, DReg_t, SReg_t);
typedef void (AssemblerX8632::*TypedEmitAddr)(Type, DReg_t,
const Address &);
TypedEmitRegs RegReg;
TypedEmitAddr RegAddr;
};
// Three operand (potentially) cross Xmm/GPR instructions.
// The last operand must be an immediate.
template <typename DReg_t, typename SReg_t> struct ThreeOpImmEmitter {
typedef void (AssemblerX8632::*TypedEmitRegRegImm)(Type, DReg_t, SReg_t,
const Immediate &);
typedef void (AssemblerX8632::*TypedEmitRegAddrImm)(Type, DReg_t,
const Address &,
const Immediate &);
TypedEmitRegRegImm RegRegImm;
TypedEmitRegAddrImm RegAddrImm;
};
/*
* Emit Machine Instructions.
*/
void call(GPRRegister reg);
void call(const Address &address);
void call(const ConstantRelocatable *label);
void call(const Immediate &abs_address);
static const intptr_t kCallExternalLabelSize = 5;
void pushl(GPRRegister reg);
void popl(GPRRegister reg);
void popl(const Address &address);
void pushal();
void popal();
void setcc(CondX86::BrCond condition, ByteRegister dst);
void setcc(CondX86::BrCond condition, const Address &address);
void mov(Type Ty, GPRRegister dst, const Immediate &src);
void mov(Type Ty, GPRRegister dst, GPRRegister src);
void mov(Type Ty, GPRRegister dst, const Address &src);
void mov(Type Ty, const Address &dst, GPRRegister src);
void mov(Type Ty, const Address &dst, const Immediate &imm);
void movzx(Type Ty, GPRRegister dst, GPRRegister src);
void movzx(Type Ty, GPRRegister dst, const Address &src);
void movsx(Type Ty, GPRRegister dst, GPRRegister src);
void movsx(Type Ty, GPRRegister dst, const Address &src);
void lea(Type Ty, GPRRegister dst, const Address &src);
void cmov(Type Ty, CondX86::BrCond cond, GPRRegister dst, GPRRegister src);
void cmov(Type Ty, CondX86::BrCond cond, GPRRegister dst, const Address &src);
void rep_movsb();
void movss(Type Ty, XmmRegister dst, const Address &src);
void movss(Type Ty, const Address &dst, XmmRegister src);
void movss(Type Ty, XmmRegister dst, XmmRegister src);
void movd(XmmRegister dst, GPRRegister src);
void movd(XmmRegister dst, const Address &src);
void movd(GPRRegister dst, XmmRegister src);
void movd(const Address &dst, XmmRegister src);
void movq(XmmRegister dst, XmmRegister src);
void movq(const Address &dst, XmmRegister src);
void movq(XmmRegister dst, const Address &src);
void addss(Type Ty, XmmRegister dst, XmmRegister src);
void addss(Type Ty, XmmRegister dst, const Address &src);
void subss(Type Ty, XmmRegister dst, XmmRegister src);
void subss(Type Ty, XmmRegister dst, const Address &src);
void mulss(Type Ty, XmmRegister dst, XmmRegister src);
void mulss(Type Ty, XmmRegister dst, const Address &src);
void divss(Type Ty, XmmRegister dst, XmmRegister src);
void divss(Type Ty, XmmRegister dst, const Address &src);
void movaps(XmmRegister dst, XmmRegister src);
void movups(XmmRegister dst, XmmRegister src);
void movups(XmmRegister dst, const Address &src);
void movups(const Address &dst, XmmRegister src);
void padd(Type Ty, XmmRegister dst, XmmRegister src);
void padd(Type Ty, XmmRegister dst, const Address &src);
void pand(Type Ty, XmmRegister dst, XmmRegister src);
void pand(Type Ty, XmmRegister dst, const Address &src);
void pandn(Type Ty, XmmRegister dst, XmmRegister src);
void pandn(Type Ty, XmmRegister dst, const Address &src);
void pmull(Type Ty, XmmRegister dst, XmmRegister src);
void pmull(Type Ty, XmmRegister dst, const Address &src);
void pmuludq(Type Ty, XmmRegister dst, XmmRegister src);
void pmuludq(Type Ty, XmmRegister dst, const Address &src);
void por(Type Ty, XmmRegister dst, XmmRegister src);
void por(Type Ty, XmmRegister dst, const Address &src);
void psub(Type Ty, XmmRegister dst, XmmRegister src);
void psub(Type Ty, XmmRegister dst, const Address &src);
void pxor(Type Ty, XmmRegister dst, XmmRegister src);
void pxor(Type Ty, XmmRegister dst, const Address &src);
void psll(Type Ty, XmmRegister dst, XmmRegister src);
void psll(Type Ty, XmmRegister dst, const Address &src);
void psll(Type Ty, XmmRegister dst, const Immediate &src);
void psra(Type Ty, XmmRegister dst, XmmRegister src);
void psra(Type Ty, XmmRegister dst, const Address &src);
void psra(Type Ty, XmmRegister dst, const Immediate &src);
void psrl(Type Ty, XmmRegister dst, XmmRegister src);
void psrl(Type Ty, XmmRegister dst, const Address &src);
void psrl(Type Ty, XmmRegister dst, const Immediate &src);
void addps(Type Ty, XmmRegister dst, XmmRegister src);
void addps(Type Ty, XmmRegister dst, const Address &src);
void subps(Type Ty, XmmRegister dst, XmmRegister src);
void subps(Type Ty, XmmRegister dst, const Address &src);
void divps(Type Ty, XmmRegister dst, XmmRegister src);
void divps(Type Ty, XmmRegister dst, const Address &src);
void mulps(Type Ty, XmmRegister dst, XmmRegister src);
void mulps(Type Ty, XmmRegister dst, const Address &src);
void minps(XmmRegister dst, XmmRegister src);
void maxps(XmmRegister dst, XmmRegister src);
void andps(XmmRegister dst, XmmRegister src);
void andps(XmmRegister dst, const Address &src);
void orps(XmmRegister dst, XmmRegister src);
void blendvps(Type Ty, XmmRegister dst, XmmRegister src);
void blendvps(Type Ty, XmmRegister dst, const Address &src);
void pblendvb(Type Ty, XmmRegister dst, XmmRegister src);
void pblendvb(Type Ty, XmmRegister dst, const Address &src);
void cmpps(XmmRegister dst, XmmRegister src, CondX86::CmppsCond CmpCondition);
void cmpps(XmmRegister dst, const Address &src,
CondX86::CmppsCond CmpCondition);
void sqrtps(XmmRegister dst);
void rsqrtps(XmmRegister dst);
void reciprocalps(XmmRegister dst);
void movhlps(XmmRegister dst, XmmRegister src);
void movlhps(XmmRegister dst, XmmRegister src);
void unpcklps(XmmRegister dst, XmmRegister src);
void unpckhps(XmmRegister dst, XmmRegister src);
void unpcklpd(XmmRegister dst, XmmRegister src);
void unpckhpd(XmmRegister dst, XmmRegister src);
void set1ps(XmmRegister dst, GPRRegister tmp, const Immediate &imm);
void shufps(XmmRegister dst, XmmRegister src, const Immediate &mask);
void minpd(XmmRegister dst, XmmRegister src);
void maxpd(XmmRegister dst, XmmRegister src);
void sqrtpd(XmmRegister dst);
void shufpd(XmmRegister dst, XmmRegister src, const Immediate &mask);
void pshufd(Type Ty, XmmRegister dst, XmmRegister src, const Immediate &mask);
void pshufd(Type Ty, XmmRegister dst, const Address &src,
const Immediate &mask);
void shufps(Type Ty, XmmRegister dst, XmmRegister src, const Immediate &mask);
void shufps(Type Ty, XmmRegister dst, const Address &src,
const Immediate &mask);
void cvtdq2ps(Type, XmmRegister dst, XmmRegister src);
void cvtdq2ps(Type, XmmRegister dst, const Address &src);
void cvttps2dq(Type, XmmRegister dst, XmmRegister src);
void cvttps2dq(Type, XmmRegister dst, const Address &src);
void cvtsi2ss(Type DestTy, XmmRegister dst, GPRRegister src);
void cvtsi2ss(Type DestTy, XmmRegister dst, const Address &src);
void cvtfloat2float(Type SrcTy, XmmRegister dst, XmmRegister src);
void cvtfloat2float(Type SrcTy, XmmRegister dst, const Address &src);
void cvttss2si(Type SrcTy, GPRRegister dst, XmmRegister src);
void cvttss2si(Type SrcTy, GPRRegister dst, const Address &src);
void ucomiss(Type Ty, XmmRegister a, XmmRegister b);
void ucomiss(Type Ty, XmmRegister a, const Address &b);
void movmskpd(GPRRegister dst, XmmRegister src);
void movmskps(GPRRegister dst, XmmRegister src);
void sqrtss(Type Ty, XmmRegister dst, const Address &src);
void sqrtss(Type Ty, XmmRegister dst, XmmRegister src);
void xorpd(XmmRegister dst, const Address &src);
void xorpd(XmmRegister dst, XmmRegister src);
void xorps(XmmRegister dst, const Address &src);
void xorps(XmmRegister dst, XmmRegister src);
void andpd(XmmRegister dst, const Address &src);
void andpd(XmmRegister dst, XmmRegister src);
void orpd(XmmRegister dst, XmmRegister src);
void insertps(Type Ty, XmmRegister dst, XmmRegister src,
const Immediate &imm);
void insertps(Type Ty, XmmRegister dst, const Address &src,
const Immediate &imm);
void pinsr(Type Ty, XmmRegister dst, GPRRegister src, const Immediate &imm);
void pinsr(Type Ty, XmmRegister dst, const Address &src,
const Immediate &imm);
void pextr(Type Ty, GPRRegister dst, XmmRegister src, const Immediate &imm);
void pextr(Type Ty, GPRRegister dst, const Address &src,
const Immediate &imm);
void pmovsxdq(XmmRegister dst, XmmRegister src);
void pcmpeq(Type Ty, XmmRegister dst, XmmRegister src);
void pcmpeq(Type Ty, XmmRegister dst, const Address &src);
void pcmpgt(Type Ty, XmmRegister dst, XmmRegister src);
void pcmpgt(Type Ty, XmmRegister dst, const Address &src);
enum RoundingMode {
kRoundToNearest = 0x0,
kRoundDown = 0x1,
kRoundUp = 0x2,
kRoundToZero = 0x3
};
void roundsd(XmmRegister dst, XmmRegister src, RoundingMode mode);
void fld(Type Ty, const Address &src);
void fstp(Type Ty, const Address &dst);
void fstp(X87STRegister st);
void fnstcw(const Address &dst);
void fldcw(const Address &src);
void fistpl(const Address &dst);
void fistps(const Address &dst);
void fildl(const Address &src);
void filds(const Address &src);
void fincstp();
void cmp(Type Ty, GPRRegister reg0, GPRRegister reg1);
void cmp(Type Ty, GPRRegister reg, const Address &address);
void cmp(Type Ty, GPRRegister reg, const Immediate &imm);
void cmp(Type Ty, const Address &address, GPRRegister reg);
void cmp(Type Ty, const Address &address, const Immediate &imm);
void test(Type Ty, GPRRegister reg0, GPRRegister reg1);
void test(Type Ty, GPRRegister reg, const Immediate &imm);
void test(Type Ty, const Address &address, GPRRegister reg);
void test(Type Ty, const Address &address, const Immediate &imm);
void And(Type Ty, GPRRegister dst, GPRRegister src);
void And(Type Ty, GPRRegister dst, const Address &address);
void And(Type Ty, GPRRegister dst, const Immediate &imm);
void And(Type Ty, const Address &address, GPRRegister reg);
void And(Type Ty, const Address &address, const Immediate &imm);
void Or(Type Ty, GPRRegister dst, GPRRegister src);
void Or(Type Ty, GPRRegister dst, const Address &address);
void Or(Type Ty, GPRRegister dst, const Immediate &imm);
void Or(Type Ty, const Address &address, GPRRegister reg);
void Or(Type Ty, const Address &address, const Immediate &imm);
void Xor(Type Ty, GPRRegister dst, GPRRegister src);
void Xor(Type Ty, GPRRegister dst, const Address &address);
void Xor(Type Ty, GPRRegister dst, const Immediate &imm);
void Xor(Type Ty, const Address &address, GPRRegister reg);
void Xor(Type Ty, const Address &address, const Immediate &imm);
void add(Type Ty, GPRRegister dst, GPRRegister src);
void add(Type Ty, GPRRegister reg, const Address &address);
void add(Type Ty, GPRRegister reg, const Immediate &imm);
void add(Type Ty, const Address &address, GPRRegister reg);
void add(Type Ty, const Address &address, const Immediate &imm);
void adc(Type Ty, GPRRegister dst, GPRRegister src);
void adc(Type Ty, GPRRegister dst, const Address &address);
void adc(Type Ty, GPRRegister reg, const Immediate &imm);
void adc(Type Ty, const Address &address, GPRRegister reg);
void adc(Type Ty, const Address &address, const Immediate &imm);
void sub(Type Ty, GPRRegister dst, GPRRegister src);
void sub(Type Ty, GPRRegister reg, const Address &address);
void sub(Type Ty, GPRRegister reg, const Immediate &imm);
void sub(Type Ty, const Address &address, GPRRegister reg);
void sub(Type Ty, const Address &address, const Immediate &imm);
void sbb(Type Ty, GPRRegister dst, GPRRegister src);
void sbb(Type Ty, GPRRegister reg, const Address &address);
void sbb(Type Ty, GPRRegister reg, const Immediate &imm);
void sbb(Type Ty, const Address &address, GPRRegister reg);
void sbb(Type Ty, const Address &address, const Immediate &imm);
void cbw();
void cwd();
void cdq();
void div(Type Ty, GPRRegister reg);
void div(Type Ty, const Address &address);
void idiv(Type Ty, GPRRegister reg);
void idiv(Type Ty, const Address &address);
void imul(Type Ty, GPRRegister dst, GPRRegister src);
void imul(Type Ty, GPRRegister reg, const Immediate &imm);
void imul(Type Ty, GPRRegister reg, const Address &address);
void imul(Type Ty, GPRRegister reg);
void imul(Type Ty, const Address &address);
void mul(Type Ty, GPRRegister reg);
void mul(Type Ty, const Address &address);
void incl(GPRRegister reg);
void incl(const Address &address);
void decl(GPRRegister reg);
void decl(const Address &address);
void rol(Type Ty, GPRRegister reg, const Immediate &imm);
void rol(Type Ty, GPRRegister operand, GPRRegister shifter);
void rol(Type Ty, const Address &operand, GPRRegister shifter);
void shl(Type Ty, GPRRegister reg, const Immediate &imm);
void shl(Type Ty, GPRRegister operand, GPRRegister shifter);
void shl(Type Ty, const Address &operand, GPRRegister shifter);
void shr(Type Ty, GPRRegister reg, const Immediate &imm);
void shr(Type Ty, GPRRegister operand, GPRRegister shifter);
void shr(Type Ty, const Address &operand, GPRRegister shifter);
void sar(Type Ty, GPRRegister reg, const Immediate &imm);
void sar(Type Ty, GPRRegister operand, GPRRegister shifter);
void sar(Type Ty, const Address &address, GPRRegister shifter);
void shld(Type Ty, GPRRegister dst, GPRRegister src);
void shld(Type Ty, GPRRegister dst, GPRRegister src, const Immediate &imm);
void shld(Type Ty, const Address &operand, GPRRegister src);
void shrd(Type Ty, GPRRegister dst, GPRRegister src);
void shrd(Type Ty, GPRRegister dst, GPRRegister src, const Immediate &imm);
void shrd(Type Ty, const Address &dst, GPRRegister src);
void neg(Type Ty, GPRRegister reg);
void neg(Type Ty, const Address &addr);
void notl(GPRRegister reg);
void bsf(Type Ty, GPRRegister dst, GPRRegister src);
void bsf(Type Ty, GPRRegister dst, const Address &src);
void bsr(Type Ty, GPRRegister dst, GPRRegister src);
void bsr(Type Ty, GPRRegister dst, const Address &src);
void bswap(Type Ty, GPRRegister reg);
void bt(GPRRegister base, GPRRegister offset);
void ret();
void ret(const Immediate &imm);
// 'size' indicates size in bytes and must be in the range 1..8.
void nop(int size = 1);
void int3();
void hlt();
void ud2();
void j(CondX86::BrCond condition, Label *label, bool near = kFarJump);
void j(CondX86::BrCond condition, const ConstantRelocatable *label);
void jmp(GPRRegister reg);
void jmp(Label *label, bool near = kFarJump);
void jmp(const ConstantRelocatable *label);
void mfence();
void lock();
void cmpxchg(Type Ty, const Address &address, GPRRegister reg, bool Locked);
void cmpxchg8b(const Address &address, bool Locked);
void xadd(Type Ty, const Address &address, GPRRegister reg, bool Locked);
void xchg(Type Ty, const Address &address, GPRRegister reg);
void emitSegmentOverride(uint8_t prefix);
intptr_t preferredLoopAlignment() { return 16; }
void align(intptr_t alignment, intptr_t offset);
void bind(Label *label);
intptr_t CodeSize() const { return Buffer.size(); }
private:
inline void emitUint8(uint8_t value);
inline void emitInt16(int16_t value);
inline void emitInt32(int32_t value);
inline void emitRegisterOperand(int rm, int reg);
inline void emitXmmRegisterOperand(int rm, XmmRegister reg);
inline void emitFixup(AssemblerFixup *fixup);
inline void emitOperandSizeOverride();
void emitOperand(int rm, const Operand &operand);
void emitImmediate(Type ty, const Immediate &imm);
void emitComplexI8(int rm, const Operand &operand,
const Immediate &immediate);
void emitComplex(Type Ty, int rm, const Operand &operand,
const Immediate &immediate);
void emitLabel(Label *label, intptr_t instruction_size);
void emitLabelLink(Label *label);
void emitNearLabelLink(Label *label);
void emitGenericShift(int rm, Type Ty, GPRRegister reg, const Immediate &imm);
void emitGenericShift(int rm, Type Ty, const Operand &operand,
GPRRegister shifter);
typedef std::vector<Label *> LabelVector;
// A vector of pool-allocated x86 labels for CFG nodes.
LabelVector CfgNodeLabels;
// A vector of pool-allocated x86 labels for Local labels.
LabelVector LocalLabels;
Label *GetOrCreateLabel(SizeT Number, LabelVector &Labels);
// The arith_int() methods factor out the commonality between the encodings of
// add(), Or(), adc(), sbb(), And(), sub(), Xor(), and cmp(). The Tag
// parameter is statically asserted to be less than 8.
template <uint32_t Tag>
void arith_int(Type Ty, GPRRegister reg, const Immediate &imm);
template <uint32_t Tag>
void arith_int(Type Ty, GPRRegister reg0, GPRRegister reg1);
template <uint32_t Tag>
void arith_int(Type Ty, GPRRegister reg, const Address &address);
template <uint32_t Tag>
void arith_int(Type Ty, const Address &address, GPRRegister reg);
template <uint32_t Tag>
void arith_int(Type Ty, const Address &address, const Immediate &imm);
};
inline void AssemblerX8632::emitUint8(uint8_t value) {
Buffer.emit<uint8_t>(value);
}
inline void AssemblerX8632::emitInt16(int16_t value) {
Buffer.emit<int16_t>(value);
}
inline void AssemblerX8632::emitInt32(int32_t value) {
Buffer.emit<int32_t>(value);
}
inline void AssemblerX8632::emitRegisterOperand(int rm, int reg) {
assert(rm >= 0 && rm < 8);
Buffer.emit<uint8_t>(0xC0 + (rm << 3) + reg);
}
inline void AssemblerX8632::emitXmmRegisterOperand(int rm, XmmRegister reg) {
emitRegisterOperand(rm, static_cast<GPRRegister>(reg));
}
inline void AssemblerX8632::emitFixup(AssemblerFixup *fixup) {
Buffer.emitFixup(fixup);
}
inline void AssemblerX8632::emitOperandSizeOverride() { emitUint8(0x66); }
} // end of namespace X8632
} // end of namespace Ice
#endif // SUBZERO_SRC_ICEASSEMBLERX8632_H