Commit a880ac8f by Karl Schimpf

Add multi-source/dest VMOV to the integrated ARM assembler.

Implements moves between double and i64. It also completes the implementation of the IR "move" instruction, except for vectors. BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334 R=eholk@chromium.org, jpp@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/1642253002 .
parent 694cdbd8
......@@ -701,7 +701,8 @@ void Assembler::vmovdr(DRegister dn, int i, Register rt, Condition cond) {
Emit(encoding);
}
#if 0
// Moved to ARM32::AssemblerARM32::vmovdrr().
void Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
Condition cond) {
ASSERT(TargetCPUFeatures::vfp_supported());
......@@ -722,7 +723,7 @@ void Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
Emit(encoding);
}
// Moved to ARM32::AssemblerARM32::vmovrrd().
void Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
Condition cond) {
ASSERT(TargetCPUFeatures::vfp_supported());
......@@ -744,7 +745,6 @@ void Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
Emit(encoding);
}
#if 0
// Moved to ARM32::AssemblerARM32::vldrs()
void Assembler::vldrs(SRegister sd, Address ad, Condition cond) {
ASSERT(TargetCPUFeatures::vfp_supported());
......
......@@ -625,8 +625,12 @@ class Assembler : public ValueObject {
#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().
......
......@@ -2427,6 +2427,56 @@ void AssemblerARM32::vmovdd(const Operand *OpDd, const Variable *OpDm,
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)
......
......@@ -387,6 +387,12 @@ public:
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,
......
......@@ -1311,13 +1311,17 @@ void InstARM32Mov::emit(const Cfg *Func) const {
}
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);
}
......
; 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)
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