Emit(encoding);
}
-
+#if 0
+// Moved to ARM32::AssemblerARM32::vmovdrr().
void Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
Condition cond) {
ASSERT(TargetCPUFeatures::vfp_supported());
Emit(encoding);
}
-
+// Moved to ARM32::AssemblerARM32::vmovrrd().
void Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
Condition cond) {
ASSERT(TargetCPUFeatures::vfp_supported());
Emit(encoding);
}
-#if 0
// Moved to ARM32::AssemblerARM32::vldrs()
void Assembler::vldrs(SRegister sd, Address ad, Condition cond) {
ASSERT(TargetCPUFeatures::vfp_supported());
#endif
void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL);
void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL);
+#if 0
+ // Moved to ARM32::AssemblerARM32::vmovdrr().
void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL);
+ // Moved to ARM32::AssemblerARM32::vmovrrd().
void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL);
+#endif
void vmovdr(DRegister dd, int i, Register rt, Condition cond = AL);
#if 0
// Moved to ARM32::AssemblerARM32::vmovss().
emitVFPddd(Cond, VmovddOpcode, Dd, D0, Dm);
}
+void AssemblerARM32::vmovdrr(const Operand *OpDm, const Operand *OpRt,
+ const Operand *OpRt2, CondARM32::Cond Cond) {
+ // VMOV (between two ARM core registers and a doubleword extension register).
+ // ARM section A8.8.345, encoding A1:
+ // vmov<c> <Dm>, <Rt>, <Rt2>
+ //
+ // cccc11000100xxxxyyyy101100M1mmmm where cccc=Cond, xxxx=Rt, yyyy=Rt2, and
+ // Mmmmm=Dm.
+ constexpr const char *Vmovdrr = "vmovdrr";
+ IValueT Dm = encodeDRegister(OpDm, "Dm", Vmovdrr);
+ IValueT Rt = encodeGPRegister(OpRt, "Rt", Vmovdrr);
+ IValueT Rt2 = encodeGPRegister(OpRt2, "Rt", Vmovdrr);
+ assert(Rt != RegARM32::Encoded_Reg_sp);
+ assert(Rt != RegARM32::Encoded_Reg_pc);
+ assert(Rt2 != RegARM32::Encoded_Reg_sp);
+ assert(Rt2 != RegARM32::Encoded_Reg_pc);
+ assert(Rt != Rt2);
+ assert(CondARM32::isDefined(Cond));
+ IValueT Encoding = B27 | B26 | B22 | B11 | B9 | B8 | B4 |
+ (encodeCondition(Cond) << kConditionShift) | (Rt2 << 16) |
+ (Rt << 12) | (getYInRegYXXXX(Dm) << 5) |
+ getXXXXInRegYXXXX(Dm);
+ emitInst(Encoding);
+}
+
+void AssemblerARM32::vmovrrd(const Operand *OpRt, const Operand *OpRt2,
+ const Operand *OpDm, CondARM32::Cond Cond) {
+ // VMOV (between two ARM core registers and a doubleword extension register).
+ // ARM section A8.8.345, encoding A1:
+ // vmov<c> <Rt>, <Rt2>, <Dm>
+ //
+ // cccc11000101xxxxyyyy101100M1mmmm where cccc=Cond, xxxx=Rt, yyyy=Rt2, and
+ // Mmmmm=Dm.
+ constexpr const char *Vmovrrd = "vmovrrd";
+ IValueT Rt = encodeGPRegister(OpRt, "Rt", Vmovrrd);
+ IValueT Rt2 = encodeGPRegister(OpRt2, "Rt", Vmovrrd);
+ IValueT Dm = encodeDRegister(OpDm, "Dm", Vmovrrd);
+ assert(Rt != RegARM32::Encoded_Reg_sp);
+ assert(Rt != RegARM32::Encoded_Reg_pc);
+ assert(Rt2 != RegARM32::Encoded_Reg_sp);
+ assert(Rt2 != RegARM32::Encoded_Reg_pc);
+ assert(Rt != Rt2);
+ assert(CondARM32::isDefined(Cond));
+ IValueT Encoding = B27 | B26 | B22 | B20 | B11 | B9 | B8 | B4 |
+ (encodeCondition(Cond) << kConditionShift) | (Rt2 << 16) |
+ (Rt << 12) | (getYInRegYXXXX(Dm) << 5) |
+ getXXXXInRegYXXXX(Dm);
+ emitInst(Encoding);
+}
+
void AssemblerARM32::vmovrs(const Operand *OpRt, const Operand *OpSn,
CondARM32::Cond Cond) {
// VMOV (between ARM core register and single-precision register)
void vmovdd(const Operand *OpDd, const Variable *OpDm, CondARM32::Cond Cond);
+ void vmovdrr(const Operand *OpDm, const Operand *OpRt, const Operand *OpRt2,
+ CondARM32::Cond Cond);
+
+ void vmovrrd(const Operand *OpRt, const Operand *OpRt2, const Operand *OpDm,
+ CondARM32::Cond Cond);
+
void vmovrs(const Operand *OpRt, const Operand *OpSn, CondARM32::Cond Cond);
void vmovs(const Operand *OpSn, const OperandARM32FlexFpImm *OpFpImm,
}
void InstARM32Mov::emitIAS(const Cfg *Func) const {
- assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type.");
+ // TODO(kschimpf) Flatten this to a switch statement of dest type. That is,
+ // combine code of emitIASSingleDestSingleSource, emitIASCoreVFPMove,
+ // emitIASScalarVFPMove, emitDoubleToI64Move, and emitI64ToDoubleMove.
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
- if (!(isMultiDest() || isMultiSource()))
- // Must be single source/dest.
- emitIASSingleDestSingleSource(Func);
+ assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type.");
+ if (isMultiDest())
+ Asm->vmovrrd(getDest(), getDestHi(), getSrc(0), getPredicate());
+ else if (isMultiSource())
+ Asm->vmovdrr(getDest(), getSrc(0), getSrc(1), getPredicate());
else
- Asm->setNeedsTextFixup();
+ emitIASSingleDestSingleSource(Func);
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
--- /dev/null
+; Show that we can generate vmov for bitcasts between i64 and double.
+
+; REQUIRES: allow_dump
+
+; Compile using standalone assembler.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -Om1 \
+; RUN: -allow-extern -reg-use r5,r10,d20 \
+; RUN: | FileCheck %s --check-prefix=ASM
+
+; Show bytes in assembled standalone code.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
+; RUN: --args -Om1 \
+; RUN: -allow-extern -reg-use r5,r10,d20 \
+; RUN: | FileCheck %s --check-prefix=DIS
+
+; Compile using integrated assembler.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -Om1 \
+; RUN: -allow-extern -reg-use r5,r10,d20 \
+; RUN: | FileCheck %s --check-prefix=IASM
+
+; Show bytes in assembled integrated code.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
+; RUN: --args -Om1 \
+; RUN: -allow-extern -reg-use r5,r10,d20 \
+; RUN: | FileCheck %s --check-prefix=DIS
+
+define internal i64 @convertDoubleToI64(double %d) {
+; ASM-LABEL: convertDoubleToI64:
+; DIS-LABEL: {{.+}} <convertDoubleToI64>:
+
+ %v = bitcast double %d to i64
+
+; ASM: vmov r5, r10, d20
+; DIS: {{.+}}: ec5a5b34
+; IASM-NOT: vmov
+
+ ret i64 %v
+}
+
+define internal double @convertI64ToDouble(i64 %i) {
+; ASM-LABEL: convertI64ToDouble:
+; DIS-LABEL: {{.+}} <convertI64ToDouble>:
+
+ %v = bitcast i64 %i to double
+
+; ASM: vmov d20, r5, r10
+; DIS: {{.+}}: ec4a5b34
+; IASM-NOT: vmov
+
+ ; Note: This call is added to allow %v to be put into d20 (instead of
+ ; return register d0).
+ call void @ignore(double %v)
+
+ ret double %v
+}
+
+declare external void @ignore(double)