OSDN Git Service

Add multi-source/dest VMOV to the integrated ARM assembler.
authorKarl Schimpf <kschimpf@google.com>
Fri, 29 Jan 2016 15:28:05 +0000 (07:28 -0800)
committerKarl Schimpf <kschimpf@google.com>
Fri, 29 Jan 2016 15:28:05 +0000 (07:28 -0800)
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 .

src/DartARM32/assembler_arm.cc
src/DartARM32/assembler_arm.h
src/IceAssemblerARM32.cpp
src/IceAssemblerARM32.h
src/IceInstARM32.cpp
tests_lit/assembler/arm32/vmov-dbl.ll [new file with mode: 0644]

index 260967b..3abd47b 100644 (file)
@@ -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());
index 0269842..bc667ab 100644 (file)
@@ -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().
index 0d41c34..a7e229d 100644 (file)
@@ -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)
index 574d6de..543503a 100644 (file)
@@ -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,
index 64a535c..f104803 100644 (file)
@@ -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);
 }
diff --git a/tests_lit/assembler/arm32/vmov-dbl.ll b/tests_lit/assembler/arm32/vmov-dbl.ll
new file mode 100644 (file)
index 0000000..4e86af9
--- /dev/null
@@ -0,0 +1,57 @@
+; 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)