B25 | B24 | B21 | (0xf << 12);
Emit(encoding);
}
-#endif
-
+// Moved to ARM32::AssemblerARM32::vmovsr().
void Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
ASSERT(TargetCPUFeatures::vfp_supported());
ASSERT(sn != kNoSRegister);
((static_cast<int32_t>(sn) & 1)*B7) | B4;
Emit(encoding);
}
-
+#endif
void Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
ASSERT(TargetCPUFeatures::vfp_supported());
}
// Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles).
+#if 0
+ // Moved to ARM32::AssemblerARM32::vmovsr().
void vmovsr(SRegister sn, Register rt, Condition cond = AL);
+#endif
void vmovrs(Register rt, SRegister sn, Condition cond = AL);
void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL);
void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL);
}
IValueT getEncodedSRegNum(const Variable *Var) {
+ assert(Var->hasReg());
return RegARM32::getEncodedSReg(Var->getRegNum());
}
emitInst(Encoding);
}
+void AssemblerARM32::vmovsr(const Operand *OpSn, const Operand *OpRt,
+ CondARM32::Cond Cond) {
+ // VMOV (between ARM core register and single-precision register)
+ // ARM seciont A8.8.343, encoding A1.
+ //
+ // vmov<c> <Sn>, <Rt>
+ //
+ // cccc1110000onnnntttt1010N0010000 where cccc=Cond, nnnnN = Sn, and tttt=Rt.
+ constexpr const char *Vmovsr = "vmovsr";
+ IValueT Sn = encodeSRegister(OpSn, "Sn", Vmovsr);
+ IValueT Rt = encodeGPRegister(OpRt, "Rt", Vmovsr);
+ assert(Sn < RegARM32::getNumSRegs());
+ assert(Rt < RegARM32::getNumGPRegs());
+ assert(CondARM32::isDefined(Cond));
+ AssemblerBuffer::EnsureCapacity ensured(&Buffer);
+ IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | B27 | B26 |
+ B25 | B11 | B9 | B4 | (getXXXXInRegXXXXY(Sn) << 16) |
+ (Rt << kRdShift) | (getYInRegXXXXY(Sn) << 7);
+ emitInst(Encoding);
+}
+
void AssemblerARM32::vmuls(const Operand *OpSd, const Operand *OpSn,
const Operand *OpSm, CondARM32::Cond Cond) {
// VMUL (floating-point) - ARM section A8.8.351, encoding A2:
vldrs(OpSd, OpAddress, Cond, TInfo);
}
+ void vmovsr(const Operand *OpSn, const Operand *OpRt, CondARM32::Cond Cond);
+
void vmuld(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm,
CondARM32::Cond Cond);
Src0->emit(Func);
}
+void InstARM32Mov::emitIASCoreVFPMove(const Cfg *Func) const {
+ auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+ Operand *Src0 = getSrc(0);
+ if (!llvm::isa<Variable>(Src0))
+ // TODO(kschimpf) Handle moving constants into registers.
+ return Asm->setNeedsTextFixup();
+
+ // Move register to register.
+ Variable *Dest = getDest();
+ switch (Dest->getType()) {
+ default:
+ // TODO(kschimpf): Fill this out more.
+ return Asm->setNeedsTextFixup();
+ case IceType_f32:
+ switch (Src0->getType()) {
+ default:
+ // TODO(kschimpf): Fill this out more?
+ return Asm->setNeedsTextFixup();
+ case IceType_i32:
+ return Asm->vmovsr(Dest, Src0, getPredicate());
+ }
+ }
+}
+
void InstARM32Mov::emitIASSingleDestSingleSource(const Cfg *Func) const {
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Variable *Dest = getDest();
llvm::report_fatal_error("mov can't load.");
}
+ if (isMoveBetweenCoreAndVFPRegisters(Dest, Src0))
+ return emitIASCoreVFPMove(Func);
+
const Type DestTy = Dest->getType();
- const bool DestIsVector = isVectorType(DestTy);
- const bool DestIsScalarFP = isScalarFloatingType(DestTy);
- const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
- if (DestIsVector || DestIsScalarFP || CoreVFPMove)
+ if (isScalarFloatingType(DestTy))
+ return Asm->setNeedsTextFixup();
+
+ if (isVectorType(DestTy))
return Asm->setNeedsTextFixup();
+
return Asm->mov(Dest, Src0, getPredicate());
}
void emitSingleDestSingleSource(const Cfg *Func) const;
void emitIASSingleDestSingleSource(const Cfg *Func) const;
+ void emitIASCoreVFPMove(const Cfg *Func) const;
Variable *DestHi = nullptr;
};
--- /dev/null
+; Show that we know how to translate vmov for casts.
+
+; NOTE: Restricts S register to one that will better test S register encodings.
+
+; REQUIRES: allow_dump
+
+; Compile using standalone assembler.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -Om1 \
+; RUN: -reg-use s20,s22,d20,d22 \
+; 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: -reg-use s20,s22,d20,d22 \
+; RUN: | FileCheck %s --check-prefix=DIS
+
+; Compile using integrated assembler.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -Om1 \
+; RUN: -reg-use s20,s22,d20,d22 \
+; 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: -reg-use s20,s22,d20,d22 \
+; RUN: | FileCheck %s --check-prefix=DIS
+
+define internal float @castToFloat(i32 %a) {
+; ASM-LABEL: castToFloat:
+; DIS-LABEL: 00000000 <castToFloat>:
+; IASM-LABEL: castToFloat:
+
+entry:
+; ASM: .LcastToFloat$entry:
+; IASM: .LcastToFloat$entry:
+
+ %0 = bitcast i32 %a to float
+
+; ASM: vmov s20, r0
+; DIS: 10: ee0a0a10
+; IASM-NOT: vmov
+
+ ret float %0
+}