EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm);
}
-
+#if 0
+// Moved to ARM32::AssemblerARM32::emitVFPsd
void Assembler::EmitVFPsd(Condition cond, int32_t opcode,
SRegister sd, DRegister dm) {
ASSERT(TargetCPUFeatures::vfp_supported());
Emit(encoding);
}
-
+// Moved to ARM32::AssemblerARM32::emitVFPds
void Assembler::EmitVFPds(Condition cond, int32_t opcode,
DRegister dd, SRegister sm) {
ASSERT(TargetCPUFeatures::vfp_supported());
Emit(encoding);
}
-
+// Moved to ARM32::AssemblerARM32::vcvtsd().
void Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) {
EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm);
}
-
+// Moved to ARM32::AssemblerARM32::vcvtds().
void Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) {
EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm);
}
+#endif
void Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) {
void vsqrts(SRegister sd, SRegister sm, Condition cond = AL);
void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL);
+#if 0
+ // Moved to ARM32::AssemblerARM32::vcvtsd
void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL);
+ // Moved to ARM32::AssemblerARM32:vcvtds
void vcvtds(DRegister dd, SRegister sm, Condition cond = AL);
+#endif
void vcvtis(SRegister sd, SRegister sm, Condition cond = AL);
void vcvtid(SRegister sd, DRegister dm, Condition cond = AL);
void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL);
DRegister dd,
DRegister dn,
DRegister dm);
-#endif
+ // Moved to ARM32::AssemblerARM32::emitVFPsd
void EmitVFPsd(Condition cond,
int32_t opcode,
SRegister sd,
DRegister dm);
+ // Moved to ARM32::AssemblerARM32::emitVFPds
void EmitVFPds(Condition cond,
int32_t opcode,
DRegister dd,
SRegister sm);
+#endif
void EmitSIMDqqq(int32_t opcode, OperandSize sz,
QRegister qd, QRegister qn, QRegister qm);
emitVFPddd(Cond, VadddOpcode, Dd, Dn, Dm);
}
+void AssemblerARM32::emitVFPsd(CondARM32::Cond Cond, IValueT Opcode, IValueT Sd,
+ IValueT Dm) {
+ assert(Sd < RegARM32::getNumSRegs());
+ assert(Dm < RegARM32::getNumDRegs());
+ assert(CondARM32::isDefined(Cond));
+ AssemblerBuffer::EnsureCapacity ensured(&Buffer);
+ constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9;
+ const IValueT Encoding =
+ Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) |
+ (getYInRegXXXXY(Sd) << 22) | (getXXXXInRegXXXXY(Sd) << 12) |
+ (getYInRegYXXXX(Dm) << 5) | getXXXXInRegYXXXX(Dm);
+ emitInst(Encoding);
+}
+
+void AssemblerARM32::vcvtsd(const Operand *OpSd, const Operand *OpDm,
+ CondARM32::Cond Cond) {
+ constexpr const char *Vcvtsd = "vctsd";
+ IValueT Sd = encodeSRegister(OpSd, "Sd", Vcvtsd);
+ IValueT Dm = encodeDRegister(OpDm, "Dm", Vcvtsd);
+ constexpr IValueT VcvtsdOpcode =
+ B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6;
+ emitVFPsd(Cond, VcvtsdOpcode, Sd, Dm);
+}
+
+void AssemblerARM32::emitVFPds(CondARM32::Cond Cond, IValueT Opcode, IValueT Dd,
+ IValueT Sm) {
+ assert(Dd < RegARM32::getNumDRegs());
+ assert(Sm < RegARM32::getNumSRegs());
+ assert(CondARM32::isDefined(Cond));
+ AssemblerBuffer::EnsureCapacity ensured(&Buffer);
+ constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9;
+ const IValueT Encoding =
+ Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) |
+ (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dd) << 12) |
+ (getYInRegXXXXY(Sm) << 5) | getXXXXInRegXXXXY(Sm);
+ emitInst(Encoding);
+}
+
+void AssemblerARM32::vcvtds(const Operand *OpDd, const Operand *OpSm,
+ CondARM32::Cond Cond) {
+ constexpr const char *Vcvtds = "Vctds";
+ IValueT Dd = encodeDRegister(OpDd, "Dd", Vcvtds);
+ IValueT Sm = encodeSRegister(OpSm, "Sm", Vcvtds);
+ constexpr IValueT VcvtdsOpcode = B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6;
+ emitVFPds(Cond, VcvtdsOpcode, Dd, Sm);
+}
+
void AssemblerARM32::vdivs(const Operand *OpSd, const Operand *OpSn,
const Operand *OpSm, CondARM32::Cond Cond) {
// VDIV (floating-point) - ARM section A8.8.283, encoding A2:
void vadds(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm,
CondARM32::Cond Cond);
+ void vcvtsd(const Operand *OpSd, const Operand *OpDm, CondARM32::Cond Cond);
+
+ void vcvtds(const Operand *OpDd, const Operand *OpSm, CondARM32::Cond Cond);
+
void vdivd(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm,
CondARM32::Cond Cond);
void emitVStackOp(CondARM32::Cond Cond, IValueT Opcode,
const Variable *OpBaseReg, SizeT NumConsecRegs);
+ // Pattern cccc111xxDxxxxxxdddd101xxxMxmmmm where cccc=Cond, ddddD=Sd,
+ // Mmmmm=Dm, and xx0xxxxxxdddd000xxx0x0000=Opcode.
+ void emitVFPsd(CondARM32::Cond Cond, IValueT Opcode, IValueT Sd, IValueT Dm);
+
+ // Pattern cccc111xxDxxxxxxdddd101xxxMxmmmm where cccc=Cond, Ddddd=Dd,
+ // mmmmM=Sm, and xx0xxxxxxdddd000xxx0x0000=Opcode.
+ void emitVFPds(CondARM32::Cond Cond, IValueT Opcode, IValueT Dd, IValueT Sm);
+
// Pattern cccc011100x1dddd1111mmmm0001nnn where cccc=Cond,
// x=Opcode, dddd=Rd, nnnn=Rn, mmmm=Rm.
void emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
getSrc(0)->emit(Func);
}
+void InstARM32Vcvt::emitIAS(const Cfg *Func) const {
+ auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+ switch (Variant) {
+ case S2d:
+ Asm->vcvtds(getDest(), getSrc(0), getPredicate());
+ break;
+ case D2s:
+ Asm->vcvtsd(getDest(), getSrc(0), getPredicate());
+ break;
+ default:
+ // TODO(kschimpf): Fill in other variants.
+ Asm->setNeedsTextFixup();
+ break;
+ }
+ if (Asm->needsTextFixup())
+ emitUsingTextFixup(Func);
+}
+
void InstARM32Vcvt::dump(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
InstARM32Vcvt(Func, Dest, Src, Variant, Predicate);
}
void emit(const Cfg *Func) const override;
+ void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) { return isClassof(Inst, Vcvt); }
--- /dev/null
+; Show that we know how to translate vcvt between float and double.
+
+; NOTE: We use -O2 to get rid of memory stores.
+
+; REQUIRES: allow_dump
+
+; Compile using standalone assembler.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \
+; RUN: | FileCheck %s --check-prefix=ASM
+
+; Show bytes in assembled standalone code.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
+; RUN: --args -O2 | FileCheck %s --check-prefix=DIS
+
+; Compile using integrated assembler.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 \
+; RUN: | FileCheck %s --check-prefix=IASM
+
+; Show bytes in assembled integrated code.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
+; RUN: --args -O2 | FileCheck %s --check-prefix=DIS
+
+define internal double @testVcvtFloatToDouble(float %v) {
+; ASM-LABEL: testVcvtFloatToDouble:
+; DIS-LABEL: 00000000 <testVcvtFloatToDouble>:
+; IASM-LABEL: testVcvtFloatToDouble:
+
+entry:
+; ASM-NEXT: .LtestVcvtFloatToDouble$entry:
+; IASM-NEXT: .LtestVcvtFloatToDouble$entry:
+
+ %res = fpext float %v to double
+
+; ASM-NEXT: vcvt.f64.f32 d0, s0
+; DIS-NEXT: 0: eeb70ac0
+; IASM-NEXT: .byte 0xc0
+; IASM-NEXT: .byte 0xa
+; IASM-NEXT: .byte 0xb7
+; IASM-NEXT: .byte 0xee
+
+ ret double %res
+}
+
+define internal float @testVcvtDoubleToFloat(double %v) {
+; ASM-LABEL: testVcvtDoubleToFloat:
+; DIS-LABEL: 00000010 <testVcvtDoubleToFloat>:
+; IASM-LABEL: testVcvtDoubleToFloat:
+
+entry:
+; ASM-NEXT: .LtestVcvtDoubleToFloat$entry:
+; IASM-NEXT: .LtestVcvtDoubleToFloat$entry:
+
+ %res = fptrunc double %v to float
+; ASM-NEXT: vcvt.f32.f64 s0, d0
+; DIS-NEXT: 10: eeb70bc0
+; IASM-NEXT: .byte 0xc0
+; IASM-NEXT: .byte 0xb
+; IASM-NEXT: .byte 0xb7
+; IASM-NEXT: .byte 0xee
+
+ ret float %res
+}