Commit b627f094 by Karl Schimpf

Add "vmov.<dt> <Qd>, #<imm>" to integrated ARM assembler.

Adds the VMOV instruction to the integrated assembler. Because #<imm> is complex, and we don't currently have a special ARM class to encode constants defined by ARM method AdvSIMDExpandImm(), it currently only accepts (nonnegative) integer32 constants that can fit into 8 bits. There are no tests for this instruction, since there currently no callers to this instruction. However, John will be checking in a CL shortly that will use this instruction. Add example generator for vector add. BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334 R=jpp@chromium.org Review URL: https://codereview.chromium.org/1879463003 .
parent 79568d27
...@@ -1410,6 +1410,7 @@ class Assembler : public ValueObject { ...@@ -1410,6 +1410,7 @@ class Assembler : public ValueObject {
// ARM32::AssemblerARM32::vld1qr() // ARM32::AssemblerARM32::vld1qr()
// ARM32::AssemblerARM32::vst1qr() // ARM32::AssemblerARM32::vst1qr()
// ARM32::AssemblerARM32::vmorqi() // ARM32::AssemblerARM32::vmorqi()
// ARM32::AssemblerARM32::vmovqc()
#endif #endif
DISALLOW_ALLOCATION(); DISALLOW_ALLOCATION();
......
...@@ -215,6 +215,28 @@ IValueT getYInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX >> 4; } ...@@ -215,6 +215,28 @@ IValueT getYInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX >> 4; }
IValueT getXXXXInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX & 0x0f; } IValueT getXXXXInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX & 0x0f; }
// Figures out Op/Cmode values for given Value. Returns true if able to encode.
bool encodeAdvSIMDExpandImm(IValueT Value, Type ElmtTy, IValueT &Op,
IValueT &Cmode, IValueT &Imm8) {
// TODO(kschimpf): Handle other shifted 8-bit values.
constexpr IValueT Imm8Mask = 0xFF;
if ((Value & IValueT(~Imm8Mask)) != 0)
return false;
Imm8 = Value;
switch (ElmtTy) {
case IceType_i16:
Op = 0;
Cmode = 8; // 100:0
return true;
case IceType_i32:
Op = 0;
Cmode = 0; // 000:0
return true;
default:
return false;
}
}
// Defines layouts of an operand representing a (register) memory address, // Defines layouts of an operand representing a (register) memory address,
// possibly modified by an immediate value. // possibly modified by an immediate value.
enum EncodedImmAddress { enum EncodedImmAddress {
...@@ -2710,6 +2732,36 @@ void AssemblerARM32::vld1qr(size_t ElmtSize, const Operand *OpQd, ...@@ -2710,6 +2732,36 @@ void AssemblerARM32::vld1qr(size_t ElmtSize, const Operand *OpQd,
emitVMem1Op(Opcode, Dd, Rn, Rm, DRegListSize2, ElmtSize, Align, Vld1qr); emitVMem1Op(Opcode, Dd, Rn, Rm, DRegListSize2, ElmtSize, Align, Vld1qr);
} }
bool AssemblerARM32::vmovqc(const Operand *OpQd, const ConstantInteger32 *Imm) {
// VMOV (immediate) - ARM section A8.8.320, encoding A1:
// VMOV.<dt> <Qd>, #<Imm>
// 1111001x1D000yyyddddcccc01p1zzzz where Qd=Ddddd, Imm=xyyyzzzz, cmode=cccc,
// and Op=p.
constexpr const char *Vmovc = "vmovc";
const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vmovc));
IValueT Value = Imm->getValue();
const Type VecTy = OpQd->getType();
if (!isVectorType(VecTy))
return false;
IValueT Op;
IValueT Cmode;
IValueT Imm8;
if (!encodeAdvSIMDExpandImm(Value, typeElementType(VecTy), Op, Cmode, Imm8))
return false;
if (Op == 0 && mask(Cmode, 0, 1) == 1)
return false;
if (Op == 1 && Cmode != 13)
return false;
const IValueT Encoding =
(0xF << kConditionShift) | B25 | B23 | B6 | B4 |
(mask(Imm8, 7, 1) << 24) | (getYInRegYXXXX(Dd) << 22) |
(mask(Imm8, 4, 3) << 16) | (getXXXXInRegYXXXX(Dd) << 12) | (Cmode << 8) |
(Op << 5) | mask(Imm8, 0, 4);
emitInst(Encoding);
return true;
}
void AssemblerARM32::vmovd(const Operand *OpDd, void AssemblerARM32::vmovd(const Operand *OpDd,
const OperandARM32FlexFpImm *OpFpImm, const OperandARM32FlexFpImm *OpFpImm,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
......
...@@ -419,6 +419,10 @@ public: ...@@ -419,6 +419,10 @@ public:
vld1qr(ElmtSize, OpQd, OpRn, TInfo); vld1qr(ElmtSize, OpQd, OpRn, TInfo);
} }
// Qn[i] = Imm for all i in vector. Returns true iff Imm can be defined as an
// Imm8 using AdvSIMDExpandImm().
bool vmovqc(const Operand *OpQd, const ConstantInteger32 *Imm);
// Dn = FpImm // Dn = FpImm
void vmovd(const Operand *OpDn, const OperandARM32FlexFpImm *OpFpImm, void vmovd(const Operand *OpDn, const OperandARM32FlexFpImm *OpFpImm,
CondARM32::Cond Cond); CondARM32::Cond Cond);
......
...@@ -1616,12 +1616,18 @@ void InstARM32Mov::emitIAS(const Cfg *Func) const { ...@@ -1616,12 +1616,18 @@ void InstARM32Mov::emitIAS(const Cfg *Func) const {
case IceType_v4i32: case IceType_v4i32:
case IceType_v4f32: case IceType_v4f32:
assert(CondARM32::isUnconditional(Cond) && assert(CondARM32::isUnconditional(Cond) &&
"Moves on <4 x f32> must be unconditional!"); "Moves on vector must be unconditional!");
// Mov between different Src and Dest types is used for bitcasting vectors. if (isVectorType(SrcTy)) {
// We still want to make sure SrcTy is a vector type. // Mov between different Src and Dest types is used for bitcasting
assert(isVectorType(SrcTy) && "Mov between vector and scalar."); // vectors. We still want to make sure SrcTy is a vector type.
Asm->vorrq(Dest, Src0, Src0); Asm->vorrq(Dest, Src0, Src0);
return; return;
} else if (const auto *C = llvm::dyn_cast<ConstantInteger32>(Src0)) {
// Mov with constant argument, allowing the initializing all elements of
// the vector.
if (Asm->vmovqc(Dest, C))
return;
}
} }
llvm::report_fatal_error("Mov: don't know how to move " + llvm::report_fatal_error("Mov: don't know how to move " +
typeStdString(SrcTy) + " to " + typeStdString(SrcTy) + " to " +
......
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