OSDN Git Service

Add VMOV(immediate) instructions to the ARM assembler.
authorKarl Schimpf <kschimpf@google.com>
Tue, 26 Jan 2016 19:12:29 +0000 (11:12 -0800)
committerKarl Schimpf <kschimpf@google.com>
Tue, 26 Jan 2016 19:12:29 +0000 (11:12 -0800)
Adds the vmovs/vmovd instructions to the integerated ARM assembler.

BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/1624383004 .

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

index 0eef894..26983f9 100644 (file)
@@ -928,7 +928,8 @@ void Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) {
   EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm);
 }
 
-
+#if 0
+// Moved to Arm32::AssemblerARM32::vmovs()
 bool Assembler::vmovs(SRegister sd, float s_imm, Condition cond) {
   if (TargetCPUFeatures::arm_version() != ARMv7) {
     return false;
@@ -946,7 +947,7 @@ bool Assembler::vmovs(SRegister sd, float s_imm, Condition cond) {
   return false;
 }
 
-
+// Moved to Arm32::AssemblerARM32::vmovd()
 bool Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
   if (TargetCPUFeatures::arm_version() != ARMv7) {
     return false;
@@ -964,7 +965,6 @@ bool Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
   return false;
 }
 
-#if 0
 // Moved to Arm32::AssemblerARM32::vadds()
 void Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
                       Condition cond) {
index c50fe4d..db9ae94 100644 (file)
@@ -631,11 +631,13 @@ class Assembler : public ValueObject {
   void vmovd(DRegister dd, DRegister dm, Condition cond = AL);
   void vmovq(QRegister qd, QRegister qm);
 
+#if 0
   // Returns false if the immediate cannot be encoded.
+  // Moved to ARM32::AssemblerARM32::vmovs();
   bool vmovs(SRegister sd, float s_imm, Condition cond = AL);
+  // Moved to ARM32::AssemblerARM32::vmovs();
   bool vmovd(DRegister dd, double d_imm, Condition cond = AL);
 
-#if 0
   // Moved to ARM32::AssemblerARM32::vldrs()
   void vldrs(SRegister sd, Address ad, Condition cond = AL);
   // Moved to Arm32::AssemblerARM32::vstrs()
index 001458d..abd4716 100644 (file)
@@ -2390,6 +2390,40 @@ void AssemblerARM32::vldrs(const Operand *OpSd, const Operand *OpAddress,
   emitInst(Encoding);
 }
 
+void AssemblerARM32::vmovd(const Operand *OpDd,
+                           const OperandARM32FlexFpImm *OpFpImm,
+                           CondARM32::Cond Cond) {
+  // VMOV (immediate) - ARM section A8.8.339, encoding A2:
+  //   vmov<c>.f64 <Dd>, #<imm>
+  //
+  // cccc11101D11xxxxdddd10110000yyyy where cccc=Cond, ddddD=Sn, xxxxyyyy=imm.
+  constexpr const char *Vmovd = "vmovd";
+  IValueT Dd = encodeSRegister(OpDd, "Dd", Vmovd);
+  IValueT Imm8 = OpFpImm->getModifiedImm();
+  assert(Imm8 < (1 << 8));
+  constexpr IValueT VmovsOpcode = B23 | B21 | B20 | B8;
+  IValueT OpcodePlusImm8 = VmovsOpcode | ((Imm8 >> 4) << 16) | (Imm8 & 0xf);
+  constexpr IValueT D0 = 0;
+  emitVFPddd(Cond, OpcodePlusImm8, Dd, D0, D0);
+}
+
+void AssemblerARM32::vmovs(const Operand *OpSd,
+                           const OperandARM32FlexFpImm *OpFpImm,
+                           CondARM32::Cond Cond) {
+  // VMOV (immediate) - ARM section A8.8.339, encoding A2:
+  //   vmov<c>.f32 <Sd>, #<imm>
+  //
+  // cccc11101D11xxxxdddd10100000yyyy where cccc=Cond, ddddD=Sn, xxxxyyyy=imm.
+  constexpr const char *Vmovs = "vmovs";
+  IValueT Sd = encodeSRegister(OpSd, "Sd", Vmovs);
+  IValueT Imm8 = OpFpImm->getModifiedImm();
+  assert(Imm8 < (1 << 8));
+  constexpr IValueT VmovsOpcode = B23 | B21 | B20;
+  IValueT OpcodePlusImm8 = VmovsOpcode | ((Imm8 >> 4) << 16) | (Imm8 & 0xf);
+  constexpr IValueT S0 = 0;
+  emitVFPsss(Cond, OpcodePlusImm8, Sd, S0, S0);
+}
+
 void AssemblerARM32::vmovsr(const Operand *OpSn, const Operand *OpRt,
                             CondARM32::Cond Cond) {
   // VMOV (between ARM core register and single-precision register)
index bec4510..8290dc7 100644 (file)
@@ -382,6 +382,12 @@ public:
     vldrs(OpSd, OpAddress, Cond, TInfo);
   }
 
+  void vmovd(const Operand *OpDn, const OperandARM32FlexFpImm *OpFpImm,
+             CondARM32::Cond Cond);
+
+  void vmovs(const Operand *OpSn, const OperandARM32FlexFpImm *OpFpImm,
+             CondARM32::Cond Cond);
+
   void vmovsr(const Operand *OpSn, const Operand *OpRt, CondARM32::Cond Cond);
 
   // Uses APSR_nzcv as register
index 03b65dd..f6e4ae5 100644 (file)
@@ -1125,6 +1125,32 @@ void InstARM32Mov::emitSingleDestSingleSource(const Cfg *Func) const {
   Src0->emit(Func);
 }
 
+void InstARM32Mov::emitIASScalarVFPMove(const Cfg *Func) const {
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  Operand *Src0 = getSrc(0);
+  Variable *Dest = getDest();
+  switch (Dest->getType()) {
+  default:
+    assert(false && "Do not know how to emit scalar FP move for type.");
+    return;
+  case IceType_f32:
+    if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) {
+      Asm->vmovs(Dest, FpImm, getPredicate());
+      return;
+    }
+    break;
+  case IceType_f64:
+    if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) {
+      Asm->vmovd(Dest, FpImm, getPredicate());
+      return;
+    }
+    break;
+  }
+  // TODO(kschimpf) Handle register to register move.
+  Asm->setNeedsTextFixup();
+  return;
+}
+
 void InstARM32Mov::emitIASCoreVFPMove(const Cfg *Func) const {
   auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
   Operand *Src0 = getSrc(0);
@@ -1150,7 +1176,6 @@ void InstARM32Mov::emitIASCoreVFPMove(const Cfg *Func) const {
 }
 
 void InstARM32Mov::emitIASSingleDestSingleSource(const Cfg *Func) const {
-  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
   Variable *Dest = getDest();
   Operand *Src0 = getSrc(0);
 
@@ -1167,8 +1192,9 @@ void InstARM32Mov::emitIASSingleDestSingleSource(const Cfg *Func) const {
 
   const Type DestTy = Dest->getType();
   if (isScalarFloatingType(DestTy))
-    return Asm->setNeedsTextFixup();
+    return emitIASScalarVFPMove(Func);
 
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
   if (isVectorType(DestTy))
     return Asm->setNeedsTextFixup();
 
index 6dba05f..eda1fe4 100644 (file)
@@ -266,10 +266,12 @@ public:
 
   static bool canHoldImm(Operand *C, uint32_t *ModifiedImm);
 
+  uint32_t getModifiedImm() const { return ModifiedImm; }
+
 private:
   OperandARM32FlexFpImm(Cfg *Func, Type Ty, uint32_t ModifiedImm);
 
-  uint32_t ModifiedImm;
+  const uint32_t ModifiedImm;
 };
 
 /// An operand for representing the 0.0 immediate in vcmp.
@@ -1340,6 +1342,7 @@ private:
   void emitSingleDestSingleSource(const Cfg *Func) const;
 
   void emitIASSingleDestSingleSource(const Cfg *Func) const;
+  void emitIASScalarVFPMove(const Cfg *Func) const;
   void emitIASCoreVFPMove(const Cfg *Func) const;
 
   Variable *DestHi = nullptr;
diff --git a/tests_lit/assembler/arm32/vmov-imm.ll b/tests_lit/assembler/arm32/vmov-imm.ll
new file mode 100644 (file)
index 0000000..9e3c80e
--- /dev/null
@@ -0,0 +1,50 @@
+; Test moving constants into VPF registers.
+
+; REQUIRES: allow_dump
+
+; Compile using standalone assembler.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -Om1 -reg-use=d21,s20 \
+; 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 -reg-use=d21,s20 \
+; RUN:   | FileCheck %s --check-prefix=DIS
+
+; Compile using integrated assembler.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -Om1 -reg-use=d21,s20 \
+; 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 -reg-use=d21,s20 \
+; RUN:   | FileCheck %s --check-prefix=DIS
+
+define internal void @testMoveDouble() {
+; ASM-LABEL: testMoveDouble:
+; DIS-LABEL: 00000000 <testMoveDouble>:
+
+entry:
+  store double 1.5, double* undef, align 8
+
+; ASM:  vmov.f64        d21, #1.500000e+00
+; DIS:    4:    eef75b08
+; IASM-NOT: vmov.f64
+
+  ret void
+}
+
+define internal void @testMoveFloat() {
+; ASM-LABEL: testMoveFloat:
+; DIS-LABEL: 00000010 <testMoveFloat>:
+
+entry:
+  %addr = inttoptr i32 0 to float*
+  store float 1.5, float* %addr, align 4
+
+; ASM:  vmov.f32        s20, #1.500000e+00
+; DIS:   18:    eeb7aa08
+; IASM-NOT: vmov.f32
+
+  ret void
+}