Handle "inplace" ops and unary ops w/ assembler Extend the bswap test to have a case which will exhibit a bit of register pressure to test register encoding more (at first wasn't sure if it was 0xC8 + reg or 0xC8 | reg... but it should be the same since there's only 0-7 for regs). BUG=none R=stichnot@chromium.org Review URL: https://codereview.chromium.org/595093002
diff --git a/crosstest/test_bitmanip.cpp b/crosstest/test_bitmanip.cpp index 7106767..181286e 100644 --- a/crosstest/test_bitmanip.cpp +++ b/crosstest/test_bitmanip.cpp
@@ -40,6 +40,18 @@ #undef X #define X(type, builtin_name) \ - type test_bswap(type a) { return builtin_name(a); } + type test_bswap(type a) { return builtin_name(a); } \ + type test_bswap_alloca(type a) { \ + const size_t buf_size = 8; \ + type buf[buf_size]; \ + for (size_t i = 0; i < buf_size; ++i) { \ + buf[i] = builtin_name(a * i) + builtin_name(a + i); \ + } \ + type sum = 0; \ + for (size_t i = 0; i < buf_size; ++i) { \ + sum += buf[i]; \ + } \ + return sum; \ + } BSWAP_TABLE #undef X
diff --git a/crosstest/test_bitmanip.h b/crosstest/test_bitmanip.h index d283d7f..c24c679 100644 --- a/crosstest/test_bitmanip.h +++ b/crosstest/test_bitmanip.h
@@ -23,6 +23,8 @@ FOR_ALL_BMI_OP_TYPES(X) #undef X -#define X(type, builtin_name) type test_bswap(type); +#define X(type, builtin_name) \ + type test_bswap(type); \ + type test_bswap_alloca(type); BSWAP_TABLE #undef X
diff --git a/crosstest/test_bitmanip_main.cpp b/crosstest/test_bitmanip_main.cpp index 89dc8ba..592ad7e 100644 --- a/crosstest/test_bitmanip_main.cpp +++ b/crosstest/test_bitmanip_main.cpp
@@ -102,19 +102,30 @@ template <typename Type> void testByteSwap(size_t &TotalTests, size_t &Passes, size_t &Failures) { - for (size_t i = 0; i < NumValues; ++i) { - Type Value = static_cast<Type>(Values[i]); - ++TotalTests; - Type ResultSz = test_bswap(Value); - Type ResultLlc = Subzero_::test_bswap(Value); - if (ResultSz == ResultLlc) { - ++Passes; - } else { - ++Failures; - std::cout << "test_bswap" << (CHAR_BIT * sizeof(Type)) << "(" - << static_cast<uint64_t>(Value) - << "): sz=" << static_cast<uint64_t>(ResultSz) - << " llc=" << static_cast<uint64_t>(ResultLlc) << "\n"; + typedef Type (*FuncType)(Type); + static struct { + const char *Name; + FuncType FuncLlc; + FuncType FuncSz; + } Funcs[] = { + {"bswap", test_bswap, Subzero_::test_bswap}, + {"bswap_alloca", test_bswap_alloca, Subzero_::test_bswap_alloca}}; + const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs); + for (size_t f = 0; f < NumFuncs; ++f) { + for (size_t i = 0; i < NumValues; ++i) { + Type Value = static_cast<Type>(Values[i]); + ++TotalTests; + Type ResultSz = Funcs[f].FuncSz(Value); + Type ResultLlc = Funcs[f].FuncLlc(Value); + if (ResultSz == ResultLlc) { + ++Passes; + } else { + ++Failures; + std::cout << "test_" << Funcs[f].Name << (CHAR_BIT * sizeof(Type)) + << "(" << static_cast<uint64_t>(Value) + << "): sz=" << static_cast<uint64_t>(ResultSz) + << " llc=" << static_cast<uint64_t>(ResultLlc) << "\n"; + } } } }
diff --git a/src/IceInstX8632.cpp b/src/IceInstX8632.cpp index 3fd74f9..72d7545 100644 --- a/src/IceInstX8632.cpp +++ b/src/IceInstX8632.cpp
@@ -478,10 +478,66 @@ Str << "\n"; } +void emitIASVarTyGPR(const Cfg *Func, Type Ty, const Variable *Var, + const x86::AssemblerX86::GPREmitterOneOp &Emitter) { + x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); + intptr_t StartPosition = Asm->GetPosition(); + if (Var->hasReg()) { + // We cheat a little and use GPRRegister even for byte operations. + RegX8632::GPRRegister VarReg = + RegX8632::getEncodedByteRegOrGPR(Ty, Var->getRegNum()); + (Asm->*(Emitter.Reg))(Ty, VarReg); + } else { + x86::Address StackAddr(static_cast<TargetX8632 *>(Func->getTarget()) + ->stackVarToAsmOperand(Var)); + (Asm->*(Emitter.Addr))(Ty, StackAddr); + } + Ostream &Str = Func->getContext()->getStrEmit(); + emitIASBytes(Str, Asm, StartPosition); +} + +void emitIASRegOpTyGPR(const Cfg *Func, Type Ty, const Variable *Var, + const Operand *Src, + const x86::AssemblerX86::GPREmitterRegOp &Emitter) { + x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); + intptr_t StartPosition = Asm->GetPosition(); + assert(Var->hasReg()); + // We cheat a little and use GPRRegister even for byte operations. + RegX8632::GPRRegister VarReg = + RegX8632::getEncodedByteRegOrGPR(Ty, Var->getRegNum()); + if (const Variable *SrcVar = llvm::dyn_cast<Variable>(Src)) { + if (SrcVar->hasReg()) { + RegX8632::GPRRegister SrcReg; + if (Ty == IceType_i8 || Ty == IceType_i1) { + SrcReg = static_cast<RegX8632::GPRRegister>( + RegX8632::getEncodedByteReg(SrcVar->getRegNum())); + } else { + SrcReg = RegX8632::getEncodedGPR(SrcVar->getRegNum()); + } + (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg); + } else { + x86::Address SrcStackAddr = static_cast<TargetX8632 *>(Func->getTarget()) + ->stackVarToAsmOperand(SrcVar); + (Asm->*(Emitter.GPRAddr))(Ty, VarReg, SrcStackAddr); + } + } else if (const OperandX8632Mem *Mem = + llvm::dyn_cast<OperandX8632Mem>(Src)) { + x86::Address SrcAddr = Mem->toAsmAddress(Asm); + (Asm->*(Emitter.GPRAddr))(Ty, VarReg, SrcAddr); + } else if (const ConstantInteger32 *Imm = + llvm::dyn_cast<ConstantInteger32>(Src)) { + (Asm->*(Emitter.GPRImm))(Ty, VarReg, x86::Immediate(Imm->getValue())); + } else { + llvm_unreachable("Unexpected operand type"); + } + Ostream &Str = Func->getContext()->getStrEmit(); + emitIASBytes(Str, Asm, StartPosition); +} + void emitIASVarOperandTyXMM(const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, - const x86::AssemblerX86::TypedXmmEmitters &Emitter) { + const x86::AssemblerX86::XmmEmitterTwoOps &Emitter) { x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); intptr_t StartPosition = Asm->GetPosition(); assert(Var->hasReg()); @@ -586,54 +642,75 @@ template <> const char *InstX8632Pextr::Opcode = "pextr"; template <> const char *InstX8632Pshufd::Opcode = "pshufd"; +// Inplace GPR ops +template <> +const x86::AssemblerX86::GPREmitterOneOp InstX8632Bswap::Emitter = { + &x86::AssemblerX86::bswap, NULL /* only a reg form exists */}; +template <> +const x86::AssemblerX86::GPREmitterOneOp InstX8632Neg::Emitter = { + &x86::AssemblerX86::neg, &x86::AssemblerX86::neg}; + +// Unary GPR ops +template <> +const x86::AssemblerX86::GPREmitterRegOp InstX8632Bsf::Emitter = { + &x86::AssemblerX86::bsf, &x86::AssemblerX86::bsf, NULL}; +template <> +const x86::AssemblerX86::GPREmitterRegOp InstX8632Bsr::Emitter = { + &x86::AssemblerX86::bsr, &x86::AssemblerX86::bsr, NULL}; +template <> +const x86::AssemblerX86::GPREmitterRegOp InstX8632Lea::Emitter = { + /* reg/reg and reg/imm are illegal */ NULL, &x86::AssemblerX86::lea, NULL}; + +// Unary XMM ops +template <> +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Sqrtss::Emitter = { + &x86::AssemblerX86::sqrtss, &x86::AssemblerX86::sqrtss, NULL}; + // Binary XMM ops template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Addss::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Addss::Emitter = { &x86::AssemblerX86::addss, &x86::AssemblerX86::addss, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Addps::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Addps::Emitter = { &x86::AssemblerX86::addps, &x86::AssemblerX86::addps, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Divss::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Divss::Emitter = { &x86::AssemblerX86::divss, &x86::AssemblerX86::divss, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Divps::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Divps::Emitter = { &x86::AssemblerX86::divps, &x86::AssemblerX86::divps, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Mulss::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Mulss::Emitter = { &x86::AssemblerX86::mulss, &x86::AssemblerX86::mulss, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Mulps::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Mulps::Emitter = { &x86::AssemblerX86::mulps, &x86::AssemblerX86::mulps, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Padd::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Padd::Emitter = { &x86::AssemblerX86::padd, &x86::AssemblerX86::padd, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Pand::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Pand::Emitter = { &x86::AssemblerX86::pand, &x86::AssemblerX86::pand, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Pandn::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Pandn::Emitter = { &x86::AssemblerX86::pandn, &x86::AssemblerX86::pandn, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Pmuludq::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Pmuludq::Emitter = { &x86::AssemblerX86::pmuludq, &x86::AssemblerX86::pmuludq, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Por::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Por::Emitter = { &x86::AssemblerX86::por, &x86::AssemblerX86::por, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Psub::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Psub::Emitter = { &x86::AssemblerX86::psub, &x86::AssemblerX86::psub, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Pxor::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Pxor::Emitter = { &x86::AssemblerX86::pxor, &x86::AssemblerX86::pxor, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Sqrtss::Emitter = { - &x86::AssemblerX86::sqrtss, &x86::AssemblerX86::sqrtss, NULL}; -template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Subss::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Subss::Emitter = { &x86::AssemblerX86::subss, &x86::AssemblerX86::subss, NULL}; template <> -const x86::AssemblerX86::TypedXmmEmitters InstX8632Subps::Emitter = { +const x86::AssemblerX86::XmmEmitterTwoOps InstX8632Subps::Emitter = { &x86::AssemblerX86::subps, &x86::AssemblerX86::subps, NULL}; template <> void InstX8632Sqrtss::emit(const Cfg *Func) const { @@ -1125,7 +1202,7 @@ assert(llvm::isa<Variable>(getSrc(0))); const Variable *Src0 = llvm::cast<Variable>(getSrc(0)); Type Ty = Src0->getType(); - const static x86::AssemblerX86::TypedXmmEmitters Emitter = { + const static x86::AssemblerX86::XmmEmitterTwoOps Emitter = { &x86::AssemblerX86::ucomiss, &x86::AssemblerX86::ucomiss, NULL}; emitIASVarOperandTyXMM(Func, Ty, Src0, getSrc(1), Emitter); } @@ -1300,6 +1377,42 @@ } } +template <> void InstX8632Movd::emitIAS(const Cfg *Func) const { + x86::AssemblerX86 *Asm = Func->getAssembler<x86::AssemblerX86>(); + intptr_t StartPosition = Asm->GetPosition(); + assert(getSrcSize() == 1); + const Variable *Dest = getDest(); + const Variable *Src = llvm::cast<Variable>(getSrc(0)); + // For insert/extract element (one of Src/Dest is an Xmm vector and + // the other is an int type). + if (Src->getType() == IceType_i32) { + assert(isVectorType(Dest->getType())); + assert(Dest->hasReg()); + RegX8632::XmmRegister DestReg = RegX8632::getEncodedXmm(Dest->getRegNum()); + if (Src->hasReg()) { + Asm->movd(DestReg, RegX8632::getEncodedGPR(Src->getRegNum())); + } else { + x86::Address StackAddr(static_cast<TargetX8632 *>(Func->getTarget()) + ->stackVarToAsmOperand(Src)); + Asm->movd(DestReg, StackAddr); + } + } else { + assert(isVectorType(Src->getType())); + assert(Src->hasReg()); + assert(Dest->getType() == IceType_i32); + RegX8632::XmmRegister SrcReg = RegX8632::getEncodedXmm(Src->getRegNum()); + if (Dest->hasReg()) { + Asm->movd(RegX8632::getEncodedGPR(Dest->getRegNum()), SrcReg); + } else { + x86::Address StackAddr(static_cast<TargetX8632 *>(Func->getTarget()) + ->stackVarToAsmOperand(Dest)); + Asm->movd(StackAddr, SrcReg); + } + } + Ostream &Str = Func->getContext()->getStrEmit(); + emitIASBytes(Str, Asm, StartPosition); +} + template <> void InstX8632Movp::emit(const Cfg *Func) const { // TODO(wala,stichnot): movups works with all vector operands, but // there exist other instructions (movaps, movdqa, movdqu) that may
diff --git a/src/IceInstX8632.h b/src/IceInstX8632.h index facd4f4..ac30870 100644 --- a/src/IceInstX8632.h +++ b/src/IceInstX8632.h
@@ -429,13 +429,17 @@ virtual ~InstX8632Call() {} }; +// Emit a one-operand (GPR) instruction. +void emitIASVarTyGPR(const Cfg *Func, Type Ty, const Variable *Var, + const x86::AssemblerX86::GPREmitterOneOp &Emitter); + // Instructions of the form x := op(x). template <InstX8632::InstKindX8632 K> -class InstX8632Inplaceop : public InstX8632 { +class InstX8632InplaceopGPR : public InstX8632 { public: - static InstX8632Inplaceop *create(Cfg *Func, Operand *SrcDest) { - return new (Func->allocate<InstX8632Inplaceop>()) - InstX8632Inplaceop(Func, SrcDest); + static InstX8632InplaceopGPR *create(Cfg *Func, Operand *SrcDest) { + return new (Func->allocate<InstX8632InplaceopGPR>()) + InstX8632InplaceopGPR(Func, SrcDest); } virtual void emit(const Cfg *Func) const { Ostream &Str = Func->getContext()->getStrEmit(); @@ -444,6 +448,12 @@ getSrc(0)->emit(Func); Str << "\n"; } + virtual void emitIAS(const Cfg *Func) const { + assert(getSrcSize() == 1); + const Variable *Var = getDest(); + Type Ty = Var->getType(); + emitIASVarTyGPR(Func, Ty, Var, Emitter); + } virtual void dump(const Cfg *Func) const { Ostream &Str = Func->getContext()->getStrDump(); dumpDest(Func); @@ -453,24 +463,31 @@ static bool classof(const Inst *Inst) { return isClassof(Inst, K); } private: - InstX8632Inplaceop(Cfg *Func, Operand *SrcDest) + InstX8632InplaceopGPR(Cfg *Func, Operand *SrcDest) : InstX8632(Func, K, 1, llvm::dyn_cast<Variable>(SrcDest)) { addSource(SrcDest); } - InstX8632Inplaceop(const InstX8632Inplaceop &) LLVM_DELETED_FUNCTION; - InstX8632Inplaceop & - operator=(const InstX8632Inplaceop &) LLVM_DELETED_FUNCTION; - virtual ~InstX8632Inplaceop() {} + InstX8632InplaceopGPR(const InstX8632InplaceopGPR &) LLVM_DELETED_FUNCTION; + InstX8632InplaceopGPR & + operator=(const InstX8632InplaceopGPR &) LLVM_DELETED_FUNCTION; + virtual ~InstX8632InplaceopGPR() {} static const char *Opcode; + static const x86::AssemblerX86::GPREmitterOneOp Emitter; }; +// Emit a two-operand (GPR) instruction, where the dest operand is a +// Variable that's guaranteed to be a register. +void emitIASRegOpTyGPR(const Cfg *Func, Type Ty, const Variable *Dst, + const Operand *Src, + const x86::AssemblerX86::GPREmitterRegOp &Emitter); + // Instructions of the form x := op(y) template <InstX8632::InstKindX8632 K> -class InstX8632Unaryop : public InstX8632 { +class InstX8632UnaryopGPR : public InstX8632 { public: - static InstX8632Unaryop *create(Cfg *Func, Variable *Dest, Operand *Src) { - return new (Func->allocate<InstX8632Unaryop>()) - InstX8632Unaryop(Func, Dest, Src); + static InstX8632UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src) { + return new (Func->allocate<InstX8632UnaryopGPR>()) + InstX8632UnaryopGPR(Func, Dest, Src); } virtual void emit(const Cfg *Func) const { Ostream &Str = Func->getContext()->getStrEmit(); @@ -481,7 +498,13 @@ getSrc(0)->emit(Func); Str << "\n"; } - virtual void emitIAS(const Cfg *Func) const { emit(Func); } + virtual void emitIAS(const Cfg *Func) const { + assert(getSrcSize() == 1); + const Variable *Var = getDest(); + Type Ty = Var->getType(); + const Operand *Src = getSrc(0); + emitIASRegOpTyGPR(Func, Ty, Var, Src, Emitter); + } virtual void dump(const Cfg *Func) const { Ostream &Str = Func->getContext()->getStrDump(); dumpDest(Func); @@ -491,19 +514,21 @@ static bool classof(const Inst *Inst) { return isClassof(Inst, K); } private: - InstX8632Unaryop(Cfg *Func, Variable *Dest, Operand *Src) + InstX8632UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src) : InstX8632(Func, K, 1, Dest) { addSource(Src); } - InstX8632Unaryop(const InstX8632Unaryop &) LLVM_DELETED_FUNCTION; - InstX8632Unaryop &operator=(const InstX8632Unaryop &) LLVM_DELETED_FUNCTION; - virtual ~InstX8632Unaryop() {} + InstX8632UnaryopGPR(const InstX8632UnaryopGPR &) LLVM_DELETED_FUNCTION; + InstX8632UnaryopGPR & + operator=(const InstX8632UnaryopGPR &) LLVM_DELETED_FUNCTION; + virtual ~InstX8632UnaryopGPR() {} static const char *Opcode; + static const x86::AssemblerX86::GPREmitterRegOp Emitter; }; void emitIASVarOperandTyXMM(const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src, - const x86::AssemblerX86::TypedXmmEmitters &Emitter); + const x86::AssemblerX86::XmmEmitterTwoOps &Emitter); template <InstX8632::InstKindX8632 K> class InstX8632UnaryopXmm : public InstX8632 { @@ -544,7 +569,7 @@ operator=(const InstX8632UnaryopXmm &) LLVM_DELETED_FUNCTION; virtual ~InstX8632UnaryopXmm() {} static const char *Opcode; - static const x86::AssemblerX86::TypedXmmEmitters Emitter; + static const x86::AssemblerX86::XmmEmitterTwoOps Emitter; }; // See the definition of emitTwoAddress() for a description of @@ -620,7 +645,7 @@ InstX8632BinopXmm &operator=(const InstX8632BinopXmm &) LLVM_DELETED_FUNCTION; virtual ~InstX8632BinopXmm() {} static const char *Opcode; - static const x86::AssemblerX86::TypedXmmEmitters Emitter; + static const x86::AssemblerX86::XmmEmitterTwoOps Emitter; }; template <InstX8632::InstKindX8632 K> class InstX8632Ternop : public InstX8632 { @@ -741,15 +766,15 @@ static const char *Opcode; }; -typedef InstX8632Inplaceop<InstX8632::Bswap> InstX8632Bswap; -typedef InstX8632Inplaceop<InstX8632::Neg> InstX8632Neg; -typedef InstX8632Unaryop<InstX8632::Bsf> InstX8632Bsf; -typedef InstX8632Unaryop<InstX8632::Bsr> InstX8632Bsr; -typedef InstX8632Unaryop<InstX8632::Lea> InstX8632Lea; -typedef InstX8632Unaryop<InstX8632::Movd> InstX8632Movd; -typedef InstX8632UnaryopXmm<InstX8632::Sqrtss> InstX8632Sqrtss; +typedef InstX8632InplaceopGPR<InstX8632::Bswap> InstX8632Bswap; +typedef InstX8632InplaceopGPR<InstX8632::Neg> InstX8632Neg; +typedef InstX8632UnaryopGPR<InstX8632::Bsf> InstX8632Bsf; +typedef InstX8632UnaryopGPR<InstX8632::Bsr> InstX8632Bsr; +typedef InstX8632UnaryopGPR<InstX8632::Lea> InstX8632Lea; // Cbwdq instruction - wrapper for cbw, cwd, and cdq -typedef InstX8632Unaryop<InstX8632::Cbwdq> InstX8632Cbwdq; +typedef InstX8632UnaryopGPR<InstX8632::Cbwdq> InstX8632Cbwdq; +typedef InstX8632UnaryopXmm<InstX8632::Movd> InstX8632Movd; +typedef InstX8632UnaryopXmm<InstX8632::Sqrtss> InstX8632Sqrtss; // Move/assignment instruction - wrapper for mov/movss/movsd. typedef InstX8632Movlike<InstX8632::Mov> InstX8632Mov; // Move packed - copy 128 bit values between XMM registers, or mem128 @@ -1384,6 +1409,7 @@ template <> void InstX8632Subss::emit(const Cfg *Func) const; template <> void InstX8632Cbwdq::emitIAS(const Cfg *Func) const; +template <> void InstX8632Movd::emitIAS(const Cfg *Func) const; } // end of namespace Ice
diff --git a/src/IceRegistersX8632.h b/src/IceRegistersX8632.h index 3aa8178..cbbcfc9 100644 --- a/src/IceRegistersX8632.h +++ b/src/IceRegistersX8632.h
@@ -16,6 +16,7 @@ #include "IceDefs.h" #include "IceInstX8632.def" +#include "IceTypes.h" namespace Ice { @@ -83,6 +84,13 @@ return ByteRegister(RegNum - Reg_GPR_First); } +static inline GPRRegister getEncodedByteRegOrGPR(Type Ty, int32_t RegNum) { + if (Ty == IceType_i8 || Ty == IceType_i1) + return GPRRegister(getEncodedByteReg(RegNum)); + else + return getEncodedGPR(RegNum); +} + } // end of namespace RegX8632 } // end of namespace Ice
diff --git a/src/assembler_ia32.cpp b/src/assembler_ia32.cpp index 3cf9e25..4347f46 100644 --- a/src/assembler_ia32.cpp +++ b/src/assembler_ia32.cpp
@@ -258,8 +258,11 @@ EmitOperand(src, dst); } -void AssemblerX86::leal(GPRRegister dst, const Address &src) { +void AssemblerX86::lea(Type Ty, GPRRegister dst, const Address &src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); + assert(Ty == IceType_i16 || Ty == IceType_i32); + if (Ty == IceType_i16) + EmitOperandSizeOverride(); EmitUint8(0x8D); EmitOperand(dst, src); } @@ -307,7 +310,15 @@ EmitUint8(0x66); EmitUint8(0x0F); EmitUint8(0x6E); - EmitOperand(dst, Operand(src)); + EmitRegisterOperand(dst, src); +} + +void AssemblerX86::movd(XmmRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x6E); + EmitOperand(dst, src); } void AssemblerX86::movd(GPRRegister dst, XmmRegister src) { @@ -315,7 +326,15 @@ EmitUint8(0x66); EmitUint8(0x0F); EmitUint8(0x7E); - EmitOperand(src, Operand(dst)); + EmitRegisterOperand(src, dst); +} + +void AssemblerX86::movd(const Address &dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x7E); + EmitOperand(src, dst); } void AssemblerX86::movq(const Address &dst, XmmRegister src) { @@ -1494,10 +1513,26 @@ EmitOperand(src, Operand(dst)); } -void AssemblerX86::negl(GPRRegister reg) { +void AssemblerX86::neg(Type Ty, GPRRegister reg) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); - EmitUint8(0xF7); - EmitOperand(3, Operand(reg)); + if (Ty == IceType_i16) + EmitOperandSizeOverride(); + if (Ty == IceType_i8 || Ty == IceType_i1) + EmitUint8(0xF6); + else + EmitUint8(0xF7); + EmitRegisterOperand(3, reg); +} + +void AssemblerX86::neg(Type Ty, const Address &addr) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (Ty == IceType_i16) + EmitOperandSizeOverride(); + if (Ty == IceType_i8 || Ty == IceType_i1) + EmitUint8(0xF6); + else + EmitUint8(0xF7); + EmitOperand(3, addr); } void AssemblerX86::notl(GPRRegister reg) { @@ -1506,13 +1541,53 @@ EmitUint8(0xD0 | reg); } -void AssemblerX86::bsrl(GPRRegister dst, GPRRegister src) { +void AssemblerX86::bswap(Type Ty, GPRRegister reg) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); + assert(Ty == IceType_i32); + EmitUint8(0x0F); + EmitUint8(0xC8 | reg); +} + +void AssemblerX86::bsf(Type Ty, GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + assert(Ty == IceType_i16 || Ty == IceType_i32); + if (Ty == IceType_i16) + EmitOperandSizeOverride(); + EmitUint8(0x0F); + EmitUint8(0xBC); + EmitRegisterOperand(dst, src); +} + +void AssemblerX86::bsf(Type Ty, GPRRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + assert(Ty == IceType_i16 || Ty == IceType_i32); + if (Ty == IceType_i16) + EmitOperandSizeOverride(); + EmitUint8(0x0F); + EmitUint8(0xBC); + EmitOperand(dst, src); +} + +void AssemblerX86::bsr(Type Ty, GPRRegister dst, GPRRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + assert(Ty == IceType_i16 || Ty == IceType_i32); + if (Ty == IceType_i16) + EmitOperandSizeOverride(); EmitUint8(0x0F); EmitUint8(0xBD); EmitRegisterOperand(dst, src); } +void AssemblerX86::bsr(Type Ty, GPRRegister dst, const Address &src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + assert(Ty == IceType_i16 || Ty == IceType_i32); + if (Ty == IceType_i16) + EmitOperandSizeOverride(); + EmitUint8(0x0F); + EmitUint8(0xBD); + EmitOperand(dst, src); +} + void AssemblerX86::bt(GPRRegister base, GPRRegister offset) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x0F);
diff --git a/src/assembler_ia32.h b/src/assembler_ia32.h index 6192e91..b5c9a16 100644 --- a/src/assembler_ia32.h +++ b/src/assembler_ia32.h
@@ -336,13 +336,32 @@ static const bool kNearJump = true; static const bool kFarJump = false; + // Operations to emit GPR instructions (and dispatch on operand type). + typedef void (AssemblerX86::*TypedEmitGPR)(Type, GPRRegister); + typedef void (AssemblerX86::*TypedEmitAddr)(Type, const Address &); + struct GPREmitterOneOp { + TypedEmitGPR Reg; + TypedEmitAddr Addr; + }; + + typedef void (AssemblerX86::*TypedEmitGPRGPR)(Type, GPRRegister, GPRRegister); + typedef void (AssemblerX86::*TypedEmitGPRAddr)(Type, GPRRegister, + const Address &); + typedef void (AssemblerX86::*TypedEmitGPRImm)(Type, GPRRegister, + const Immediate &); + struct GPREmitterRegOp { + TypedEmitGPRGPR GPRGPR; + TypedEmitGPRAddr GPRAddr; + TypedEmitGPRImm GPRImm; + }; + // Operations to emit XMM instructions (and dispatch on operand type). typedef void (AssemblerX86::*TypedEmitXmmXmm)(Type, XmmRegister, XmmRegister); typedef void (AssemblerX86::*TypedEmitXmmAddr)(Type, XmmRegister, const Address &); typedef void (AssemblerX86::*TypedEmitAddrXmm)(Type, const Address &, XmmRegister); - struct TypedXmmEmitters { + struct XmmEmitterTwoOps { TypedEmitXmmXmm XmmXmm; TypedEmitXmmAddr XmmAddr; TypedEmitAddrXmm AddrXmm; @@ -393,7 +412,7 @@ void movw(GPRRegister dst, const Address &src); void movw(const Address &dst, GPRRegister src); - void leal(GPRRegister dst, const Address &src); + void lea(Type Ty, GPRRegister dst, const Address &src); void cmov(CondX86::BrCond cond, GPRRegister dst, GPRRegister src); @@ -404,7 +423,9 @@ void movss(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(const Address &dst, XmmRegister src); void movq(XmmRegister dst, const Address &src); @@ -622,10 +643,16 @@ void shrd(GPRRegister dst, GPRRegister src, const Immediate &imm); void shrd(const Address &dst, GPRRegister src); - void negl(GPRRegister reg); + void neg(Type Ty, GPRRegister reg); + void neg(Type Ty, const Address &addr); void notl(GPRRegister reg); - void bsrl(GPRRegister dst, GPRRegister src); + 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);
diff --git a/tests_lit/llvm2ice_tests/vector-ops.ll b/tests_lit/llvm2ice_tests/vector-ops.ll index 1866e62..a5dadde 100644 --- a/tests_lit/llvm2ice_tests/vector-ops.ll +++ b/tests_lit/llvm2ice_tests/vector-ops.ll
@@ -37,6 +37,7 @@ %res = insertelement <4 x i32> %vec, i32 %elt, i32 0 ret <4 x i32> %res ; CHECK-LABEL: insertelement_v4i32_0: +; CHECK: movd xmm{{.*}}, ; CHECK: movss ; SSE41-LABEL: insertelement_v4i32_0: @@ -164,6 +165,7 @@ ret i32 %res ; CHECK-LABEL: extractelement_v4i32: ; CHECK: pshufd +; CHECK: movd {{.*}}, xmm ; SSE41-LABEL: extractelement_v4i32: ; SSE41: pextrd