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 .
diff --git a/src/DartARM32/assembler_arm.h b/src/DartARM32/assembler_arm.h
index 6d7432a..9bc4e2d 100644
--- a/src/DartARM32/assembler_arm.h
+++ b/src/DartARM32/assembler_arm.h
@@ -1410,6 +1410,7 @@
// ARM32::AssemblerARM32::vld1qr()
// ARM32::AssemblerARM32::vst1qr()
// ARM32::AssemblerARM32::vmorqi()
+ // ARM32::AssemblerARM32::vmovqc()
#endif
DISALLOW_ALLOCATION();
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
index bba8e16..ebc95a4 100644
--- a/src/IceAssemblerARM32.cpp
+++ b/src/IceAssemblerARM32.cpp
@@ -215,6 +215,28 @@
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,
// possibly modified by an immediate value.
enum EncodedImmAddress {
@@ -2710,6 +2732,36 @@
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,
const OperandARM32FlexFpImm *OpFpImm,
CondARM32::Cond Cond) {
diff --git a/src/IceAssemblerARM32.h b/src/IceAssemblerARM32.h
index e3f9b4c..694113e 100644
--- a/src/IceAssemblerARM32.h
+++ b/src/IceAssemblerARM32.h
@@ -419,6 +419,10 @@
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
void vmovd(const Operand *OpDn, const OperandARM32FlexFpImm *OpFpImm,
CondARM32::Cond Cond);
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index 718360f..e2d8a14 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -1616,12 +1616,18 @@
case IceType_v4i32:
case IceType_v4f32:
assert(CondARM32::isUnconditional(Cond) &&
- "Moves on <4 x f32> must be unconditional!");
- // Mov between different Src and Dest types is used for bitcasting vectors.
- // We still want to make sure SrcTy is a vector type.
- assert(isVectorType(SrcTy) && "Mov between vector and scalar.");
- Asm->vorrq(Dest, Src0, Src0);
- return;
+ "Moves on vector must be unconditional!");
+ if (isVectorType(SrcTy)) {
+ // Mov between different Src and Dest types is used for bitcasting
+ // vectors. We still want to make sure SrcTy is a vector type.
+ Asm->vorrq(Dest, Src0, Src0);
+ 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 " +
typeStdString(SrcTy) + " to " +