Commit af2780c2 by Jan Voung

Handle add, adc, etc., mfence, div, idiv, mul in the assembler.

Add a test to check that the encodings are efficient for immediates (chooses the i8, and eax encodings when appropriate). The .byte syntax breaks NaCl bundle straddle checking in llvm-mc, so I had to change one of the tests which noted that a nop appeared (no longer does). This also assumes that _add(), etc. are usually done with _add(T, ...) and then _mov(dst, T) so that the dest is always register. BUG=none R=stichnot@chromium.org Review URL: https://codereview.chromium.org/604873003
parent be22e146
...@@ -345,20 +345,20 @@ void emitIASBytes(Ostream &Str, const x86::AssemblerX86 *Asm, ...@@ -345,20 +345,20 @@ void emitIASBytes(Ostream &Str, const x86::AssemblerX86 *Asm,
} }
if (LastFixupLoc < StartPosition) { if (LastFixupLoc < StartPosition) {
// The fixup doesn't apply to this current block. // The fixup doesn't apply to this current block.
for (intptr_t i = 0; i < EndPosition - StartPosition; ++i) { for (intptr_t i = StartPosition; i < EndPosition; ++i) {
Str << "\t.byte " Str << "\t.byte 0x";
<< static_cast<uint32_t>(Asm->LoadBuffer<uint8_t>(StartPosition + i)) Str.write_hex(Asm->LoadBuffer<uint8_t>(i));
<< "\n"; Str << "\n";
} }
return; return;
} }
const intptr_t FixupSize = 4; const intptr_t FixupSize = 4;
assert(LastFixupLoc + FixupSize <= EndPosition); assert(LastFixupLoc + FixupSize <= EndPosition);
// The fixup does apply to this current block. // The fixup does apply to this current block.
for (intptr_t i = 0; i < LastFixupLoc - StartPosition; ++i) { for (intptr_t i = StartPosition; i < LastFixupLoc; ++i) {
Str << "\t.byte " Str << "\t.byte 0x";
<< static_cast<uint32_t>(Asm->LoadBuffer<uint8_t>(StartPosition + i)) Str.write_hex(Asm->LoadBuffer<uint8_t>(i));
<< "\n"; Str << "\n";
} }
Str << "\t.long " << LastFixup->value()->getName(); Str << "\t.long " << LastFixup->value()->getName();
if (LastFixup->value()->getOffset()) { if (LastFixup->value()->getOffset()) {
...@@ -366,8 +366,9 @@ void emitIASBytes(Ostream &Str, const x86::AssemblerX86 *Asm, ...@@ -366,8 +366,9 @@ void emitIASBytes(Ostream &Str, const x86::AssemblerX86 *Asm,
} }
Str << "\n"; Str << "\n";
for (intptr_t i = LastFixupLoc + FixupSize; i < EndPosition; ++i) { for (intptr_t i = LastFixupLoc + FixupSize; i < EndPosition; ++i) {
Str << "\t.byte " << static_cast<uint32_t>(Asm->LoadBuffer<uint8_t>(i)) Str << "\t.byte 0x";
<< "\n"; Str.write_hex(Asm->LoadBuffer<uint8_t>(i));
Str << "\n";
} }
} }
...@@ -478,10 +479,11 @@ void emitTwoAddress(const char *Opcode, const Inst *Inst, const Cfg *Func, ...@@ -478,10 +479,11 @@ void emitTwoAddress(const char *Opcode, const Inst *Inst, const Cfg *Func,
Str << "\n"; Str << "\n";
} }
void emitIASVarTyGPR(const Cfg *Func, Type Ty, const Variable *Var, void emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Op,
const x86::AssemblerX86::GPREmitterOneOp &Emitter) { const x86::AssemblerX86::GPREmitterOneOp &Emitter) {
x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>();
intptr_t StartPosition = Asm->GetPosition(); intptr_t StartPosition = Asm->GetPosition();
if (const Variable *Var = llvm::dyn_cast<Variable>(Op)) {
if (Var->hasReg()) { if (Var->hasReg()) {
// We cheat a little and use GPRRegister even for byte operations. // We cheat a little and use GPRRegister even for byte operations.
RegX8632::GPRRegister VarReg = RegX8632::GPRRegister VarReg =
...@@ -492,6 +494,11 @@ void emitIASVarTyGPR(const Cfg *Func, Type Ty, const Variable *Var, ...@@ -492,6 +494,11 @@ void emitIASVarTyGPR(const Cfg *Func, Type Ty, const Variable *Var,
->stackVarToAsmOperand(Var)); ->stackVarToAsmOperand(Var));
(Asm->*(Emitter.Addr))(Ty, StackAddr); (Asm->*(Emitter.Addr))(Ty, StackAddr);
} }
} else if (const OperandX8632Mem *Mem = llvm::dyn_cast<OperandX8632Mem>(Op)) {
(Asm->*(Emitter.Addr))(Ty, Mem->toAsmAddress(Asm));
} else {
llvm_unreachable("Unexpected operand type");
}
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
emitIASBytes(Str, Asm, StartPosition); emitIASBytes(Str, Asm, StartPosition);
} }
...@@ -666,6 +673,29 @@ template <> ...@@ -666,6 +673,29 @@ template <>
const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Sqrtss::Emitter = { const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Sqrtss::Emitter = {
&x86::AssemblerX86::sqrtss, &x86::AssemblerX86::sqrtss, NULL}; &x86::AssemblerX86::sqrtss, &x86::AssemblerX86::sqrtss, NULL};
// Binary GPR ops
template <>
const x86::AssemblerX86::GPREmitterRegOp InstX8632Add::Emitter = {
&x86::AssemblerX86::add, &x86::AssemblerX86::add, &x86::AssemblerX86::add};
template <>
const x86::AssemblerX86::GPREmitterRegOp InstX8632Adc::Emitter = {
&x86::AssemblerX86::adc, &x86::AssemblerX86::adc, &x86::AssemblerX86::adc};
template <>
const x86::AssemblerX86::GPREmitterRegOp InstX8632And::Emitter = {
&x86::AssemblerX86::And, &x86::AssemblerX86::And, &x86::AssemblerX86::And};
template <>
const x86::AssemblerX86::GPREmitterRegOp InstX8632Or::Emitter = {
&x86::AssemblerX86::Or, &x86::AssemblerX86::Or, &x86::AssemblerX86::Or};
template <>
const x86::AssemblerX86::GPREmitterRegOp InstX8632Sbb::Emitter = {
&x86::AssemblerX86::sbb, &x86::AssemblerX86::sbb, &x86::AssemblerX86::sbb};
template <>
const x86::AssemblerX86::GPREmitterRegOp InstX8632Sub::Emitter = {
&x86::AssemblerX86::sub, &x86::AssemblerX86::sub, &x86::AssemblerX86::sub};
template <>
const x86::AssemblerX86::GPREmitterRegOp InstX8632Xor::Emitter = {
&x86::AssemblerX86::Xor, &x86::AssemblerX86::Xor, &x86::AssemblerX86::Xor};
// Binary XMM ops // Binary XMM ops
template <> template <>
const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Addss::Emitter = { const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Addss::Emitter = {
...@@ -798,6 +828,15 @@ template <> void InstX8632Div::emit(const Cfg *Func) const { ...@@ -798,6 +828,15 @@ template <> void InstX8632Div::emit(const Cfg *Func) const {
Str << "\n"; Str << "\n";
} }
template <> void InstX8632Div::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 3);
const Operand *Src = getSrc(1);
Type Ty = Src->getType();
const static x86::AssemblerX86::GPREmitterOneOp Emitter = {
&x86::AssemblerX86::div, &x86::AssemblerX86::div};
emitIASOpTyGPR(Func, Ty, Src, Emitter);
}
template <> void InstX8632Idiv::emit(const Cfg *Func) const { template <> void InstX8632Idiv::emit(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 3); assert(getSrcSize() == 3);
...@@ -806,6 +845,14 @@ template <> void InstX8632Idiv::emit(const Cfg *Func) const { ...@@ -806,6 +845,14 @@ template <> void InstX8632Idiv::emit(const Cfg *Func) const {
Str << "\n"; Str << "\n";
} }
template <> void InstX8632Idiv::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 3);
const Operand *Src = getSrc(1);
Type Ty = Src->getType();
const static x86::AssemblerX86::GPREmitterOneOp Emitter = {
&x86::AssemblerX86::idiv, &x86::AssemblerX86::idiv};
emitIASOpTyGPR(Func, Ty, Src, Emitter);
}
namespace { namespace {
...@@ -926,6 +973,18 @@ void InstX8632Mul::emit(const Cfg *Func) const { ...@@ -926,6 +973,18 @@ void InstX8632Mul::emit(const Cfg *Func) const {
Str << "\n"; Str << "\n";
} }
void InstX8632Mul::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 2);
assert(llvm::isa<Variable>(getSrc(0)));
assert(llvm::dyn_cast<Variable>(getSrc(0))->getRegNum() == RegX8632::Reg_eax);
assert(getDest()->getRegNum() == RegX8632::Reg_eax); // TODO: allow edx?
const Operand *Src = getSrc(1);
Type Ty = Src->getType();
const static x86::AssemblerX86::GPREmitterOneOp Emitter = {
&x86::AssemblerX86::mul, &x86::AssemblerX86::mul};
emitIASOpTyGPR(Func, Ty, Src, Emitter);
}
void InstX8632Mul::dump(const Cfg *Func) const { void InstX8632Mul::dump(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrDump(); Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func); dumpDest(Func);
...@@ -1246,6 +1305,14 @@ void InstX8632Mfence::emit(const Cfg *Func) const { ...@@ -1246,6 +1305,14 @@ void InstX8632Mfence::emit(const Cfg *Func) const {
Str << "\tmfence\n"; Str << "\tmfence\n";
} }
void InstX8632Mfence::emitIAS(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrEmit();
x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>();
intptr_t StartPosition = Asm->GetPosition();
Asm->mfence();
emitIASBytes(Str, Asm, StartPosition);
}
void InstX8632Mfence::dump(const Cfg *Func) const { void InstX8632Mfence::dump(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrDump(); Ostream &Str = Func->getContext()->getStrDump();
Str << "mfence\n"; Str << "mfence\n";
...@@ -1661,7 +1728,7 @@ void InstX8632AdjustStack::emitIAS(const Cfg *Func) const { ...@@ -1661,7 +1728,7 @@ void InstX8632AdjustStack::emitIAS(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>();
intptr_t StartPosition = Asm->GetPosition(); intptr_t StartPosition = Asm->GetPosition();
Asm->subl(RegX8632::Encoded_Reg_esp, x86::Immediate(Amount)); Asm->sub(IceType_i32, RegX8632::Encoded_Reg_esp, x86::Immediate(Amount));
emitIASBytes(Str, Asm, StartPosition); emitIASBytes(Str, Asm, StartPosition);
Func->getTarget()->updateStackAdjustment(Amount); Func->getTarget()->updateStackAdjustment(Amount);
} }
......
...@@ -428,7 +428,7 @@ private: ...@@ -428,7 +428,7 @@ private:
}; };
// Emit a one-operand (GPR) instruction. // Emit a one-operand (GPR) instruction.
void emitIASVarTyGPR(const Cfg *Func, Type Ty, const Variable *Var, void emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Var,
const x86::AssemblerX86::GPREmitterOneOp &Emitter); const x86::AssemblerX86::GPREmitterOneOp &Emitter);
// Instructions of the form x := op(x). // Instructions of the form x := op(x).
...@@ -450,7 +450,7 @@ public: ...@@ -450,7 +450,7 @@ public:
assert(getSrcSize() == 1); assert(getSrcSize() == 1);
const Variable *Var = getDest(); const Variable *Var = getDest();
Type Ty = Var->getType(); Type Ty = Var->getType();
emitIASVarTyGPR(Func, Ty, Var, Emitter); emitIASOpTyGPR(Func, Ty, Var, Emitter);
} }
void dump(const Cfg *Func) const override { void dump(const Cfg *Func) const override {
Ostream &Str = Func->getContext()->getStrDump(); Ostream &Str = Func->getContext()->getStrDump();
...@@ -578,7 +578,7 @@ void emitTwoAddress(const char *Opcode, const Inst *Inst, const Cfg *Func, ...@@ -578,7 +578,7 @@ void emitTwoAddress(const char *Opcode, const Inst *Inst, const Cfg *Func,
template <InstX8632::InstKindX8632 K, bool ShiftHack = false> template <InstX8632::InstKindX8632 K, bool ShiftHack = false>
class InstX8632Binop : public InstX8632 { class InstX8632Binop : public InstX8632 {
public: public:
// Create an ordinary binary-op instruction like add or sub. // Create a binary-op instruction like shifts.
static InstX8632Binop *create(Cfg *Func, Variable *Dest, Operand *Source) { static InstX8632Binop *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX8632Binop>()) return new (Func->allocate<InstX8632Binop>())
InstX8632Binop(Func, Dest, Source); InstX8632Binop(Func, Dest, Source);
...@@ -606,6 +606,44 @@ private: ...@@ -606,6 +606,44 @@ private:
static const char *Opcode; static const char *Opcode;
}; };
template <InstX8632::InstKindX8632 K>
class InstX8632BinopGPR : public InstX8632 {
public:
// Create an ordinary binary-op instruction like add or sub.
static InstX8632BinopGPR *create(Cfg *Func, Variable *Dest, Operand *Source) {
return new (Func->allocate<InstX8632BinopGPR>())
InstX8632BinopGPR(Func, Dest, Source);
}
void emit(const Cfg *Func) const override {
const bool ShiftHack = false;
emitTwoAddress(Opcode, this, Func, ShiftHack);
}
void emitIAS(const Cfg *Func) const override {
Type Ty = getDest()->getType();
assert(getSrcSize() == 2);
emitIASRegOpTyGPR(Func, Ty, getDest(), getSrc(1), Emitter);
}
void dump(const Cfg *Func) const override {
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = " << Opcode << "." << getDest()->getType() << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstX8632BinopGPR(Cfg *Func, Variable *Dest, Operand *Source)
: InstX8632(Func, K, 2, Dest) {
addSource(Dest);
addSource(Source);
}
InstX8632BinopGPR(const InstX8632BinopGPR &) LLVM_DELETED_FUNCTION;
InstX8632BinopGPR &operator=(const InstX8632BinopGPR &) LLVM_DELETED_FUNCTION;
~InstX8632BinopGPR() override {}
static const char *Opcode;
static const x86::AssemblerX86::GPREmitterRegOp Emitter;
};
template <InstX8632::InstKindX8632 K, bool NeedsElementType> template <InstX8632::InstKindX8632 K, bool NeedsElementType>
class InstX8632BinopXmm : public InstX8632 { class InstX8632BinopXmm : public InstX8632 {
public: public:
...@@ -665,6 +703,7 @@ public: ...@@ -665,6 +703,7 @@ public:
getSrc(2)->emit(Func); getSrc(2)->emit(Func);
Str << "\n"; Str << "\n";
} }
void emitIAS(const Cfg *Func) const override { emit(Func); }
void dump(const Cfg *Func) const override { void dump(const Cfg *Func) const override {
Ostream &Str = Func->getContext()->getStrDump(); Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func); dumpDest(Func);
...@@ -781,22 +820,22 @@ typedef InstX8632Movlike<InstX8632::Mov> InstX8632Mov; ...@@ -781,22 +820,22 @@ typedef InstX8632Movlike<InstX8632::Mov> InstX8632Mov;
typedef InstX8632Movlike<InstX8632::Movp> InstX8632Movp; typedef InstX8632Movlike<InstX8632::Movp> InstX8632Movp;
// Movq - copy between XMM registers, or mem64 and XMM registers. // Movq - copy between XMM registers, or mem64 and XMM registers.
typedef InstX8632Movlike<InstX8632::Movq> InstX8632Movq; typedef InstX8632Movlike<InstX8632::Movq> InstX8632Movq;
typedef InstX8632Binop<InstX8632::Add> InstX8632Add; typedef InstX8632BinopGPR<InstX8632::Add> InstX8632Add;
typedef InstX8632BinopXmm<InstX8632::Addps, true> InstX8632Addps; typedef InstX8632BinopXmm<InstX8632::Addps, true> InstX8632Addps;
typedef InstX8632Binop<InstX8632::Adc> InstX8632Adc; typedef InstX8632BinopGPR<InstX8632::Adc> InstX8632Adc;
typedef InstX8632BinopXmm<InstX8632::Addss, false> InstX8632Addss; typedef InstX8632BinopXmm<InstX8632::Addss, false> InstX8632Addss;
typedef InstX8632BinopXmm<InstX8632::Padd, true> InstX8632Padd; typedef InstX8632BinopXmm<InstX8632::Padd, true> InstX8632Padd;
typedef InstX8632Binop<InstX8632::Sub> InstX8632Sub; typedef InstX8632BinopGPR<InstX8632::Sub> InstX8632Sub;
typedef InstX8632BinopXmm<InstX8632::Subps, true> InstX8632Subps; typedef InstX8632BinopXmm<InstX8632::Subps, true> InstX8632Subps;
typedef InstX8632BinopXmm<InstX8632::Subss, false> InstX8632Subss; typedef InstX8632BinopXmm<InstX8632::Subss, false> InstX8632Subss;
typedef InstX8632Binop<InstX8632::Sbb> InstX8632Sbb; typedef InstX8632BinopGPR<InstX8632::Sbb> InstX8632Sbb;
typedef InstX8632BinopXmm<InstX8632::Psub, true> InstX8632Psub; typedef InstX8632BinopXmm<InstX8632::Psub, true> InstX8632Psub;
typedef InstX8632Binop<InstX8632::And> InstX8632And; typedef InstX8632BinopGPR<InstX8632::And> InstX8632And;
typedef InstX8632BinopXmm<InstX8632::Pand, false> InstX8632Pand; typedef InstX8632BinopXmm<InstX8632::Pand, false> InstX8632Pand;
typedef InstX8632BinopXmm<InstX8632::Pandn, false> InstX8632Pandn; typedef InstX8632BinopXmm<InstX8632::Pandn, false> InstX8632Pandn;
typedef InstX8632Binop<InstX8632::Or> InstX8632Or; typedef InstX8632BinopGPR<InstX8632::Or> InstX8632Or;
typedef InstX8632BinopXmm<InstX8632::Por, false> InstX8632Por; typedef InstX8632BinopXmm<InstX8632::Por, false> InstX8632Por;
typedef InstX8632Binop<InstX8632::Xor> InstX8632Xor; typedef InstX8632BinopGPR<InstX8632::Xor> InstX8632Xor;
typedef InstX8632BinopXmm<InstX8632::Pxor, false> InstX8632Pxor; typedef InstX8632BinopXmm<InstX8632::Pxor, false> InstX8632Pxor;
typedef InstX8632Binop<InstX8632::Imul> InstX8632Imul; typedef InstX8632Binop<InstX8632::Imul> InstX8632Imul;
typedef InstX8632BinopXmm<InstX8632::Mulps, true> InstX8632Mulps; typedef InstX8632BinopXmm<InstX8632::Mulps, true> InstX8632Mulps;
...@@ -858,6 +897,7 @@ public: ...@@ -858,6 +897,7 @@ public:
InstX8632Mul(Func, Dest, Source1, Source2); InstX8632Mul(Func, Dest, Source1, Source2);
} }
void emit(const Cfg *Func) const override; void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override; void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) { return isClassof(Inst, Mul); } static bool classof(const Inst *Inst) { return isClassof(Inst, Mul); }
...@@ -1112,6 +1152,7 @@ public: ...@@ -1112,6 +1152,7 @@ public:
return new (Func->allocate<InstX8632Mfence>()) InstX8632Mfence(Func); return new (Func->allocate<InstX8632Mfence>()) InstX8632Mfence(Func);
} }
void emit(const Cfg *Func) const override; void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override; void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) { return isClassof(Inst, Mfence); } static bool classof(const Inst *Inst) { return isClassof(Inst, Mfence); }
...@@ -1407,6 +1448,8 @@ template <> void InstX8632Psub::emit(const Cfg *Func) const; ...@@ -1407,6 +1448,8 @@ template <> void InstX8632Psub::emit(const Cfg *Func) const;
template <> void InstX8632Sqrtss::emit(const Cfg *Func) const; template <> void InstX8632Sqrtss::emit(const Cfg *Func) const;
template <> void InstX8632Subss::emit(const Cfg *Func) const; template <> void InstX8632Subss::emit(const Cfg *Func) const;
template <> void InstX8632Div::emitIAS(const Cfg *Func) const;
template <> void InstX8632Idiv::emitIAS(const Cfg *Func) const;
template <> void InstX8632Cbwdq::emitIAS(const Cfg *Func) const; template <> void InstX8632Cbwdq::emitIAS(const Cfg *Func) const;
template <> void InstX8632Movd::emitIAS(const Cfg *Func) const; template <> void InstX8632Movd::emitIAS(const Cfg *Func) const;
......
...@@ -571,40 +571,43 @@ public: ...@@ -571,40 +571,43 @@ public:
void testl(GPRRegister reg1, GPRRegister reg2); void testl(GPRRegister reg1, GPRRegister reg2);
void testl(GPRRegister reg, const Immediate &imm); void testl(GPRRegister reg, const Immediate &imm);
void andl(GPRRegister dst, const Immediate &imm); void And(Type Ty, GPRRegister dst, GPRRegister src);
void andl(GPRRegister dst, GPRRegister src); void And(Type Ty, GPRRegister dst, const Address &address);
void andl(GPRRegister dst, const Address &address); void And(Type Ty, GPRRegister dst, const Immediate &imm);
void orl(GPRRegister dst, const Immediate &imm); void Or(Type Ty, GPRRegister dst, GPRRegister src);
void orl(GPRRegister dst, GPRRegister src); void Or(Type Ty, GPRRegister dst, const Address &address);
void orl(GPRRegister dst, const Address &address); void Or(Type Ty, GPRRegister dst, const Immediate &imm);
void xorl(GPRRegister dst, const Immediate &imm); void Xor(Type Ty, GPRRegister dst, GPRRegister src);
void xorl(GPRRegister dst, GPRRegister src); void Xor(Type Ty, GPRRegister dst, const Address &address);
void xorl(GPRRegister dst, const Address &address); void Xor(Type Ty, GPRRegister dst, const Immediate &imm);
void addl(GPRRegister dst, GPRRegister src); void add(Type Ty, GPRRegister dst, GPRRegister src);
void addl(GPRRegister reg, const Immediate &imm); void add(Type Ty, GPRRegister reg, const Address &address);
void addl(GPRRegister reg, const Address &address); void add(Type Ty, GPRRegister reg, const Immediate &imm);
void addl(const Address &address, GPRRegister reg); void adc(Type Ty, GPRRegister dst, GPRRegister src);
void addl(const Address &address, const Immediate &imm); void adc(Type Ty, GPRRegister dst, const Address &address);
void adc(Type Ty, GPRRegister reg, const Immediate &imm);
void adcl(GPRRegister dst, GPRRegister src); void sub(Type Ty, GPRRegister dst, GPRRegister src);
void adcl(GPRRegister reg, const Immediate &imm); void sub(Type Ty, GPRRegister reg, const Address &address);
void adcl(GPRRegister dst, const Address &address); void sub(Type Ty, GPRRegister reg, const Immediate &imm);
void adcl(const Address &dst, GPRRegister src);
void subl(GPRRegister dst, GPRRegister src); void sbb(Type Ty, GPRRegister dst, GPRRegister src);
void subl(GPRRegister reg, const Immediate &imm); void sbb(Type Ty, GPRRegister reg, const Address &address);
void subl(GPRRegister reg, const Address &address); void sbb(Type Ty, GPRRegister reg, const Immediate &imm);
void subl(const Address &address, GPRRegister reg);
void cbw(); void cbw();
void cwd(); void cwd();
void cdq(); void cdq();
void idivl(GPRRegister reg); 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 imull(GPRRegister dst, GPRRegister src); void imull(GPRRegister dst, GPRRegister src);
void imull(GPRRegister reg, const Immediate &imm); void imull(GPRRegister reg, const Immediate &imm);
...@@ -613,13 +616,8 @@ public: ...@@ -613,13 +616,8 @@ public:
void imull(GPRRegister reg); void imull(GPRRegister reg);
void imull(const Address &address); void imull(const Address &address);
void mull(GPRRegister reg); void mul(Type Ty, GPRRegister reg);
void mull(const Address &address); void mul(Type Ty, const Address &address);
void sbbl(GPRRegister dst, GPRRegister src);
void sbbl(GPRRegister reg, const Immediate &imm);
void sbbl(GPRRegister reg, const Address &address);
void sbbl(const Address &address, GPRRegister reg);
void incl(GPRRegister reg); void incl(GPRRegister reg);
void incl(const Address &address); void incl(const Address &address);
...@@ -670,6 +668,8 @@ public: ...@@ -670,6 +668,8 @@ public:
void jmp(Label *label, bool near = kFarJump); void jmp(Label *label, bool near = kFarJump);
void jmp(const ConstantRelocatable *label); void jmp(const ConstantRelocatable *label);
void mfence();
void lock(); void lock();
void cmpxchg(Type Ty, const Address &address, GPRRegister reg); void cmpxchg(Type Ty, const Address &address, GPRRegister reg);
void cmpxchg8b(const Address &address); void cmpxchg8b(const Address &address);
......
; Tests various aspects of x86 immediate encoding. Some encodings are shorter.
; For example, the encoding is shorter for 8-bit immediates or when using EAX.
; This assumes that EAX is chosen as the first free register in O2 mode.
; RUN: %p2i -i %s --args -O2 --verbose none \
; RUN: | llvm-mc -triple=i686-none-nacl -x86-asm-syntax=intel -filetype=obj \
; RUN: | llvm-objdump -d --symbolize -x86-asm-syntax=intel - | FileCheck %s
; RUN: %p2i -i %s --args --verbose none | FileCheck --check-prefix=ERRORS %s
; RUN: %p2i -i %s --insts | %szdiff %s | FileCheck --check-prefix=DUMP %s
define internal i32 @testXor8Imm8(i32 %arg) {
entry:
%arg_i8 = trunc i32 %arg to i8
%result_i8 = xor i8 %arg_i8, 127
%result = zext i8 %result_i8 to i32
ret i32 %result
}
; CHECK-LABEL: testXor8Imm8
; CHECK: 34 7f xor al, 127
define internal i32 @testXor8Imm8Neg(i32 %arg) {
entry:
%arg_i8 = trunc i32 %arg to i8
%result_i8 = xor i8 %arg_i8, -128
%result = zext i8 %result_i8 to i32
ret i32 %result
}
; CHECK-LABEL: testXor8Imm8Neg
; CHECK: 34 80 xor al, -128
define internal i32 @testXor8Imm8NotEAX(i32 %arg, i32 %arg2, i32 %arg3) {
entry:
%arg_i8 = trunc i32 %arg to i8
%arg2_i8 = trunc i32 %arg2 to i8
%arg3_i8 = trunc i32 %arg3 to i8
%x1 = xor i8 %arg_i8, 127
%x2 = xor i8 %arg2_i8, 127
%x3 = xor i8 %arg3_i8, 127
%x4 = add i8 %x1, %x2
%x5 = add i8 %x4, %x3
%result = zext i8 %x5 to i32
ret i32 %result
}
; CHECK-LABEL: testXor8Imm8NotEAX
; CHECK: 80 f{{[1-3]}} 7f xor {{[^a]}}l, 127
define internal i32 @testXor32Imm8(i32 %arg) {
entry:
%result = xor i32 %arg, 127
ret i32 %result
}
; CHECK-LABEL: testXor32Imm8
; CHECK: 83 f0 7f xor eax, 127
define internal i32 @testXor32Imm8Neg(i32 %arg) {
entry:
%result = xor i32 %arg, -128
ret i32 %result
}
; CHECK-LABEL: testXor32Imm8Neg
; CHECK: 83 f0 80 xor eax, -128
define internal i32 @testXor32Imm32Eax(i32 %arg) {
entry:
%result = xor i32 %arg, 16777216
ret i32 %result
}
; CHECK-LABEL: testXor32Imm32Eax
; CHECK: 35 00 00 00 01 xor eax, 16777216
define internal i32 @testXor32Imm32NegEax(i32 %arg) {
entry:
%result = xor i32 %arg, -256
ret i32 %result
}
; CHECK-LABEL: testXor32Imm32NegEax
; CHECK: 35 00 ff ff ff xor eax, 4294967040
define internal i32 @testXor32Imm32NotEAX(i32 %arg, i32 %arg2, i32 %arg3) {
entry:
%x = xor i32 %arg, 32767
%x2 = xor i32 %arg2, 32767
%x3 = xor i32 %arg3, 32767
%add1 = add i32 %x, %x2
%add2 = add i32 %add1, %x3
ret i32 %add2
}
; CHECK-LABEL: testXor32Imm32NotEAX
; CHECK: 81 f{{[1-3]}} ff 7f 00 00 xor e{{[^a]}}x, 32767
; Should be similar for add, sub, etc., so sample a few.
define internal i32 @testAdd8Imm8(i32 %arg) {
entry:
%arg_i8 = trunc i32 %arg to i8
%result_i8 = add i8 %arg_i8, 126
%result = zext i8 %result_i8 to i32
ret i32 %result
}
; CHECK-LABEL: testAdd8Imm8
; CHECK: 04 7e add al, 126
define internal i32 @testSub8Imm8(i32 %arg) {
entry:
%arg_i8 = trunc i32 %arg to i8
%result_i8 = sub i8 %arg_i8, 125
%result = zext i8 %result_i8 to i32
ret i32 %result
}
; CHECK-LABEL: testSub8Imm8
; CHECK: 2c 7d sub al, 125
; ERRORS-NOT: ICE translation error
; DUMP-NOT: SZ
...@@ -36,8 +36,6 @@ for.end: ...@@ -36,8 +36,6 @@ for.end:
; CHECK: mov ecx, dword ptr [esp{{.*}}+{{.*}}{{[0-9]+}}] ; CHECK: mov ecx, dword ptr [esp{{.*}}+{{.*}}{{[0-9]+}}]
; CHECK: cmp ecx, 0 ; CHECK: cmp ecx, 0
; CHECK-NEXT: jle {{[0-9]}} ; CHECK-NEXT: jle {{[0-9]}}
; NaCl bundle padding
; CHECK-NEXT: nop
; TODO: the mov from ebx to esi seems redundant here - so this may need to be ; TODO: the mov from ebx to esi seems redundant here - so this may need to be
; modified later ; modified later
......
...@@ -9,6 +9,28 @@ ...@@ -9,6 +9,28 @@
; RUN: %p2i -i %s -a --verbose none | FileCheck --check-prefix=ERRORS %s ; RUN: %p2i -i %s -a --verbose none | FileCheck --check-prefix=ERRORS %s
; RUN: %p2i -i %s --insts | %szdiff %s | FileCheck --check-prefix=DUMP %s ; RUN: %p2i -i %s --insts | %szdiff %s | FileCheck --check-prefix=DUMP %s
; Test that and with true uses immediate 1, not -1.
define internal i32 @testAndTrue(i32 %arg) {
entry:
%arg_i1 = trunc i32 %arg to i1
%result_i1 = and i1 %arg_i1, true
%result = zext i1 %result_i1 to i32
ret i32 %result
}
; CHECK-LABEL: testAndTrue
; CHECK: and {{.*}}, 1
; Test that or with true uses immediate 1, not -1.
define internal i32 @testOrTrue(i32 %arg) {
entry:
%arg_i1 = trunc i32 %arg to i1
%result_i1 = or i1 %arg_i1, true
%result = zext i1 %result_i1 to i32
ret i32 %result
}
; CHECK-LABEL: testOrTrue
; CHECK: or {{.*}}, 1
; Test that xor with true uses immediate 1, not -1. ; Test that xor with true uses immediate 1, not -1.
define internal i32 @testXorTrue(i32 %arg) { define internal i32 @testXorTrue(i32 %arg) {
entry: entry:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment