OSDN Git Service

Subzero. Implements the scalar bitcast operations for ARM32.
authorJohn Porto <jpp@chromium.org>
Mon, 14 Sep 2015 23:28:33 +0000 (16:28 -0700)
committerJohn Porto <jpp@chromium.org>
Mon, 14 Sep 2015 23:28:33 +0000 (16:28 -0700)
BUG= https://code.google.com/p/nativeclient/issues/detail?id=4076
R=stichnot@chromium.org

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

src/IceInstARM32.cpp
src/IceInstARM32.h
src/IceTargetLoweringARM32.cpp
src/IceTargetLoweringARM32.h
tests_lit/llvm2ice_tests/bitcast.ll
tests_lit/llvm2ice_tests/fp.convert.ll

index 375132b..9a68115 100644 (file)
@@ -403,7 +403,6 @@ template <> const char *InstARM32Ldr::Opcode = "ldr";
 template <> const char *InstARM32Mov::Opcode = "mov";
 // FP
 template <> const char *InstARM32Vldr::Opcode = "vldr";
-template <> const char *InstARM32Vmov::Opcode = "vmov";
 // Three-addr ops
 template <> const char *InstARM32Adc::Opcode = "adc";
 template <> const char *InstARM32Add::Opcode = "add";
@@ -498,15 +497,56 @@ template <> void InstARM32Vldr::emitIAS(const Cfg *Func) const {
   llvm_unreachable("Not yet implemented");
 }
 
-template <> void InstARM32Vmov::emit(const Cfg *Func) const {
+void InstARM32Vmov::emitMultiDestSingleSource(const Cfg *Func) const {
+  if (!BuildDefs::dump())
+    return;
+  Ostream &Str = Func->getContext()->getStrEmit();
+  Variable *Dest0 = getDest();
+  Operand *Src0 = getSrc(0);
+
+  assert(Dest0->hasReg());
+  assert(Dest1->hasReg());
+  assert(!llvm::isa<OperandARM32Mem>(Src0));
+
+  Str << "\t"
+      << "vmov"
+      << "\t";
+  Dest0->emit(Func);
+  Str << ", ";
+  Dest1->emit(Func);
+  Str << ", ";
+  Src0->emit(Func);
+}
+
+void InstARM32Vmov::emitSingleDestMultiSource(const Cfg *Func) const {
+  if (!BuildDefs::dump())
+    return;
+  Ostream &Str = Func->getContext()->getStrEmit();
+  Variable *Dest0 = getDest();
+  Operand *Src0 = getSrc(0);
+  Operand *Src1 = getSrc(1);
+
+  assert(Dest0->hasReg());
+  assert(!llvm::isa<OperandARM32Mem>(Src0));
+  assert(!llvm::isa<OperandARM32Mem>(Src1));
+
+  Str << "\t"
+      << "vmov"
+      << "\t";
+  Dest0->emit(Func);
+  Str << ", ";
+  Src0->emit(Func);
+  Str << ", ";
+  Src1->emit(Func);
+}
+
+void InstARM32Vmov::emitSingleDestSingleSource(const Cfg *Func) const {
   if (!BuildDefs::dump())
     return;
-  assert(CondARM32::AL == getPredicate());
   Ostream &Str = Func->getContext()->getStrEmit();
-  assert(getSrcSize() == 1);
   Variable *Dest = getDest();
   if (Dest->hasReg()) {
-    IceString ActualOpcode = Opcode;
+    IceString ActualOpcode = "vmov";
     Operand *Src0 = getSrc(0);
     if (const auto *Src0V = llvm::dyn_cast<Variable>(Src0)) {
       if (!Src0V->hasReg()) {
@@ -532,12 +572,41 @@ template <> void InstARM32Vmov::emit(const Cfg *Func) const {
   }
 }
 
-template <> void InstARM32Vmov::emitIAS(const Cfg *Func) const {
+void InstARM32Vmov::emit(const Cfg *Func) const {
+  if (!BuildDefs::dump())
+    return;
+  assert(CondARM32::AL == getPredicate());
+  assert(isMultiDest() + isMultiSource() <= 1 && "Invalid vmov type.");
+  if (isMultiDest()) {
+    emitMultiDestSingleSource(Func);
+    return;
+  }
+
+  if (isMultiSource()) {
+    emitSingleDestMultiSource(Func);
+    return;
+  }
+
+  emitSingleDestSingleSource(Func);
+}
+
+void InstARM32Vmov::emitIAS(const Cfg *Func) const {
   assert(getSrcSize() == 1);
   (void)Func;
   llvm_unreachable("Not yet implemented");
 }
 
+void InstARM32Vmov::dump(const Cfg *Func) const {
+  if (!BuildDefs::dump())
+    return;
+  Ostream &Str = Func->getContext()->getStrDump();
+  dumpOpcodePred(Str, "vmov", getDest()->getType());
+  Str << " ";
+  dumpDest(Func);
+  Str << ", ";
+  dumpSources(Func);
+}
+
 void InstARM32Br::emit(const Cfg *Func) const {
   if (!BuildDefs::dump())
     return;
index 56bf8cd..8c2ea6f 100644 (file)
@@ -785,7 +785,6 @@ using InstARM32Ldr = InstARM32Movlike<InstARM32::Ldr>;
 using InstARM32Mov = InstARM32Movlike<InstARM32::Mov>;
 /// Represents various vector mov instruction forms (simple single source,
 /// single dest forms only, not the 2 GPR <-> 1 D reg forms, etc.).
-using InstARM32Vmov = InstARM32Movlike<InstARM32::Vmov>;
 using InstARM32Vldr = InstARM32Movlike<InstARM32::Vldr>;
 /// MovT leaves the bottom bits alone so dest is also a source.
 /// This helps indicate that a previous MovW setting dest is not dead code.
@@ -1119,6 +1118,93 @@ private:
   const VcvtVariant Variant;
 };
 
+/// Handles (some of) vmov's various formats.
+class InstARM32Vmov final : public InstARM32Pred {
+  InstARM32Vmov() = delete;
+  InstARM32Vmov(const InstARM32Vmov &) = delete;
+  InstARM32Vmov &operator=(const InstARM32Vmov &) = delete;
+
+public:
+  /// RegisterPair is used to group registers in
+  ///
+  /// vmov D, (R, R)
+  ///
+  /// and
+  ///
+  /// vmov (R, R), D
+  struct RegisterPair {
+    explicit RegisterPair(Variable *V0, Variable *V1) : _0(V0), _1(V1) {
+      assert(V0->getType() == IceType_i32);
+      assert(V1->getType() == IceType_i32);
+    }
+    Variable *_0;
+    Variable *_1;
+  };
+
+  static InstARM32Vmov *create(Cfg *Func, Variable *Dest, Operand *Src,
+                               CondARM32::Cond Predicate) {
+    return new (Func->allocate<InstARM32Vmov>())
+        InstARM32Vmov(Func, Dest, Src, Predicate);
+  }
+  static InstARM32Vmov *create(Cfg *Func, const RegisterPair &Dests,
+                               Variable *Src, CondARM32::Cond Predicate) {
+    return new (Func->allocate<InstARM32Vmov>())
+        InstARM32Vmov(Func, Dests, Src, Predicate);
+  }
+  static InstARM32Vmov *create(Cfg *Func, Variable *Dest,
+                               const RegisterPair &Srcs,
+                               CondARM32::Cond Predicate) {
+    return new (Func->allocate<InstARM32Vmov>())
+        InstARM32Vmov(Func, Dest, Srcs, Predicate);
+  }
+  bool isRedundantAssign() const override {
+    return Dest1 == nullptr && getSrcSize() == 1 &&
+           checkForRedundantAssign(getDest(), getSrc(0));
+  }
+  bool isSimpleAssign() const override { return true; }
+  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, Vmov); }
+
+private:
+  InstARM32Vmov(Cfg *Func, Variable *Dest, Operand *Src,
+                CondARM32::Cond Predicate)
+      : InstARM32Pred(Func, InstARM32::Vmov, 1, Dest, Predicate) {
+    addSource(Src);
+  }
+
+  InstARM32Vmov(Cfg *Func, const RegisterPair &Dests, Variable *Src,
+                CondARM32::Cond Predicate)
+      : InstARM32Pred(Func, InstARM32::Vmov, 1, Dests._0, Predicate),
+        Dest1(Dests._1) {
+    addSource(Src);
+  }
+
+  InstARM32Vmov(Cfg *Func, Variable *Dest, const RegisterPair &Srcs,
+                CondARM32::Cond Predicate)
+      : InstARM32Pred(Func, InstARM32::Vmov, 2, Dest, Predicate) {
+    addSource(Srcs._0);
+    addSource(Srcs._1);
+  }
+
+  bool isMultiDest() const {
+    assert(getDest() != nullptr);
+    return Dest1 != nullptr;
+  }
+
+  bool isMultiSource() const {
+    assert(getSrcSize() >= 1);
+    return getSrcSize() > 1;
+  }
+
+  void emitMultiDestSingleSource(const Cfg *Func) const;
+  void emitSingleDestMultiSource(const Cfg *Func) const;
+  void emitSingleDestSingleSource(const Cfg *Func) const;
+
+  Variable *Dest1 = nullptr;
+};
+
 // Declare partial template specializations of emit() methods that
 // already have default implementations.  Without this, there is the
 // possibility of ODR violations and link errors.
@@ -1128,7 +1214,6 @@ template <> void InstARM32Mov::emit(const Cfg *Func) const;
 template <> void InstARM32Movw::emit(const Cfg *Func) const;
 template <> void InstARM32Movt::emit(const Cfg *Func) const;
 template <> void InstARM32Vldr::emit(const Cfg *Func) const;
-template <> void InstARM32Vmov::emit(const Cfg *Func) const;
 
 } // end of namespace Ice
 
index 3e92637..0634e45 100644 (file)
@@ -2108,6 +2108,9 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
       UnimplementedError(Func->getContext()->getFlags());
       break;
     } else if (Dest->getType() == IceType_i64) {
+      split64(Dest);
+      Context.insert(InstFakeDef::create(Func, Dest->getLo()));
+      Context.insert(InstFakeDef::create(Func, Dest->getHi()));
       UnimplementedError(Func->getContext()->getFlags());
       break;
     }
@@ -2144,7 +2147,10 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
     if (isVectorType(Dest->getType())) {
       UnimplementedError(Func->getContext()->getFlags());
       break;
-    } else if (Src0->getType() == IceType_i64) {
+    }
+    if (Src0->getType() == IceType_i64) {
+      // avoid cryptic liveness errors
+      Context.insert(InstFakeDef::create(Func, Dest));
       UnimplementedError(Func->getContext()->getFlags());
       break;
     }
@@ -2178,7 +2184,77 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
       lowerAssign(Assign);
       return;
     }
-    UnimplementedError(Func->getContext()->getFlags());
+    Type DestType = Dest->getType();
+    switch (DestType) {
+    case IceType_NUM:
+    case IceType_void:
+      llvm::report_fatal_error("Unexpected bitcast.");
+    case IceType_i1:
+      UnimplementedError(Func->getContext()->getFlags());
+      break;
+    case IceType_v4i1:
+      UnimplementedError(Func->getContext()->getFlags());
+      break;
+    case IceType_i8:
+      UnimplementedError(Func->getContext()->getFlags());
+      break;
+    case IceType_i16:
+      UnimplementedError(Func->getContext()->getFlags());
+      break;
+    case IceType_i32:
+    case IceType_f32: {
+      Variable *Src0R = legalizeToReg(Src0);
+      Variable *T = makeReg(DestType);
+      _vmov(T, Src0R);
+      lowerAssign(InstAssign::create(Func, Dest, T));
+      break;
+    }
+    case IceType_i64: {
+      // t0, t1 <- src0
+      // dest[31..0]  = t0
+      // dest[63..32] = t1
+      assert(Src0->getType() == IceType_f64);
+      Variable *T0 = makeReg(IceType_i32);
+      Variable *T1 = makeReg(IceType_i32);
+      Variable *Src0R = legalizeToReg(Src0);
+      split64(Dest);
+      _vmov(InstARM32Vmov::RegisterPair(T0, T1), Src0R);
+      lowerAssign(InstAssign::create(Func, Dest->getLo(), T0));
+      lowerAssign(InstAssign::create(Func, Dest->getHi(), T1));
+      break;
+    }
+    case IceType_f64: {
+      // T0 <- lo(src)
+      // T1 <- hi(src)
+      // vmov T2, T0, T1
+      // Dest <- T2
+      assert(Src0->getType() == IceType_i64);
+      Variable *SrcLo = legalizeToReg(loOperand(Src0));
+      Variable *SrcHi = legalizeToReg(hiOperand(Src0));
+      Variable *T = makeReg(IceType_f64);
+      _vmov(T, InstARM32Vmov::RegisterPair(SrcLo, SrcHi));
+      lowerAssign(InstAssign::create(Func, Dest, T));
+      break;
+    }
+    case IceType_v8i1:
+      UnimplementedError(Func->getContext()->getFlags());
+      break;
+    case IceType_v16i1:
+      UnimplementedError(Func->getContext()->getFlags());
+      break;
+    case IceType_v8i16:
+      UnimplementedError(Func->getContext()->getFlags());
+      break;
+    case IceType_v16i8:
+      UnimplementedError(Func->getContext()->getFlags());
+      break;
+    case IceType_v4i32:
+      UnimplementedError(Func->getContext()->getFlags());
+      break;
+    case IceType_v4f32:
+      UnimplementedError(Func->getContext()->getFlags());
+      break;
+    }
     break;
   }
   }
index 1370368..57e0b5a 100644 (file)
@@ -415,6 +415,19 @@ protected:
     constexpr CondARM32::Cond Pred = CondARM32::AL;
     Context.insert(InstARM32Vmov::create(Func, Dest, Src0, Pred));
   }
+  // This represents the single source, multi dest variant.
+  void _vmov(InstARM32Vmov::RegisterPair Dests, Variable *Src0) {
+    constexpr CondARM32::Cond Pred = CondARM32::AL;
+    Context.insert(InstARM32Vmov::create(Func, Dests, Src0, Pred));
+    // The Vmov instruction created above does not define Dests._1. Therefore
+    // we add a Dest._1 = FakeDef pseudo instruction.
+    Context.insert(InstFakeDef::create(Func, Dests._1));
+  }
+  // This represents the multi source, single dest variant.
+  void _vmov(Variable *Dest, InstARM32Vmov::RegisterPair Srcs) {
+    constexpr CondARM32::Cond Pred = CondARM32::AL;
+    Context.insert(InstARM32Vmov::create(Func, Dest, Srcs, Pred));
+  }
   void _vmul(Variable *Dest, Variable *Src0, Variable *Src1) {
     Context.insert(InstARM32Vmul::create(Func, Dest, Src0, Src1));
   }
index 40a654c..388afb1 100644 (file)
@@ -3,6 +3,16 @@
 ; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 | FileCheck %s
 ; RUN: %p2i --filetype=obj --disassemble -i %s --args -Om1 | FileCheck %s
 
+; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \
+; RUN:   --target arm32 -i %s --args -O2 --skip-unimplemented \
+; RUN:   | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \
+; RUN:   --check-prefix=ARM32
+
+; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \
+; RUN:   --target arm32 -i %s --args -Om1 --skip-unimplemented \
+; RUN:   | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \
+; RUN:   --check-prefix=ARM32
+
 define internal i32 @cast_f2i(float %f) {
 entry:
   %v0 = bitcast float %f to i32
@@ -10,6 +20,8 @@ entry:
 }
 ; CHECK-LABEL: cast_f2i
 ; CHECK: mov eax
+; ARM32-LABEL: cast_f2i
+; ARM32: vmov r{{[0-9]+}}, s{{[0-9]+}}
 
 define internal float @cast_i2f(i32 %i) {
 entry:
@@ -18,6 +30,8 @@ entry:
 }
 ; CHECK-LABEL: cast_i2f
 ; CHECK: fld DWORD PTR
+; ARM32-LABEL: cast_i2f
+; ARM32: vmov s{{[0-9]+}}, r{{[0-9]+}}
 
 define internal i64 @cast_d2ll(double %d) {
 entry:
@@ -26,6 +40,8 @@ entry:
 }
 ; CHECK-LABEL: cast_d2ll
 ; CHECK: mov edx
+; ARM32-LABEL: cast_d2ll
+; ARM32: vmov r{{[0-9]+}}, r{{[0-9]+}}, d{{[0-9]+}}
 
 define internal i64 @cast_d2ll_const() {
 entry:
@@ -35,6 +51,11 @@ entry:
 ; CHECK-LABEL: cast_d2ll_const
 ; CHECK: mov e{{..}},DWORD PTR ds:0x0 {{.*}} .L$double$0
 ; CHECK: mov e{{..}},DWORD PTR ds:0x4 {{.*}} .L$double$0
+; ARM32-LABEL: cast_d2ll_const
+; ARM32-DAG: movw [[ADDR:r[0-9]+]], #:lower16:.L$
+; ARM32-DAG: movt [[ADDR]], #:upper16:.L$
+; ARM32-DAG: vldr [[DREG:d[0-9]+]], {{\[}}[[ADDR]], #0{{\]}}
+; ARM32: vmov r{{[0-9]+}}, r{{[0-9]+}}, [[DREG]]
 
 define internal double @cast_ll2d(i64 %ll) {
 entry:
@@ -43,6 +64,8 @@ entry:
 }
 ; CHECK-LABEL: cast_ll2d
 ; CHECK: fld QWORD PTR
+; ARM32-LABEL: cast_ll2d
+; ARM32: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
 
 define internal double @cast_ll2d_const() {
 entry:
@@ -53,3 +76,8 @@ entry:
 ; CHECK: mov {{.*}},0x73ce2ff2
 ; CHECK: mov {{.*}},0xb3a
 ; CHECK: fld QWORD PTR
+; ARM32-LABEL: cast_ll2d_const
+; ARM32-DAG: movw [[REG0:r[0-9]+]], #12274
+; ARM32-DAG: movt [[REG0:r[0-9]+]], #29646
+; ARM32-DAG: movw [[REG1:r[0-9]+]], #2874
+; ARM32: vmov d{{[0-9]+}}, [[REG0]], [[REG1]]
index 1efe0d7..18c0951 100644 (file)
@@ -7,8 +7,14 @@
 ; RUN: %p2i --filetype=obj --disassemble -i %s --args -Om1 | FileCheck %s
 
 ; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \
+; RUN:   --target arm32 -i %s --args -O2 --skip-unimplemented \
+; RUN:   | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \
+; RUN:   --check-prefix=ARM32
+
+; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \
 ; RUN:   --target arm32 -i %s --args -Om1 --skip-unimplemented \
-; RUN:   | %if --need=target_ARM32 --command FileCheck %s --check-prefix=ARM32
+; RUN:   | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \
+; RUN:   --check-prefix=ARM32
 
 define internal float @fptrunc(double %a) {
 entry:
@@ -554,8 +560,7 @@ entry:
 ; CHECK-LABEL: int32BitcastToFloat
 ; CHECK: mov
 ; ARM32-LABEL: int32BitcastToFloat
-; TODO(jpp): implement this test.
-
+; ARM32: vmov s{{[0-9]+}}, r{{[0-9]+}}
 define internal float @int32BitcastToFloatConst() {
 entry:
   %conv = bitcast i32 8675309 to float
@@ -564,7 +569,9 @@ entry:
 ; CHECK-LABEL: int32BitcastToFloatConst
 ; CHECK: mov
 ; ARM32-LABEL: int32BitcastToFloatConst
-; TODO(jpp): implement this test.
+; ARM32-DAG: movw [[REG:r[0-9]+]], #24557
+; ARM32-DAG: movt [[REG]], #132
+; ARM32: vmov s{{[0-9]+}}, [[REG]]
 
 define internal double @int64BitcastToDouble(i64 %a) {
 entry:
@@ -574,7 +581,7 @@ entry:
 ; CHECK-LABEL: int64BitcastToDouble
 ; CHECK: mov
 ; ARM32-LABEL: int64BitcastToDouble
-; TODO(jpp): implement this test.
+; ARM32: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
 
 define internal double @int64BitcastToDoubleConst() {
 entry:
@@ -584,5 +591,7 @@ entry:
 ; CHECK-LABEL: int64BitcastToDoubleConst
 ; CHECK: mov
 ; ARM32-LABEL: int64BitcastToDoubleConst
-; TODO(jpp): implement this test.
-
+; ARM32-DAG: movw [[REG0:r[0-9]+]], #57336
+; ARM32-DAG: movt [[REG0]], #137
+; ARM32-DAG: movw [[REG1:r[0-9]+]], #0
+; ARM32-DAG: vmov d{{[0-9]+}}, [[REG0]], [[REG1]]