OSDN Git Service

[SubZero] lower float and double constants for MIPS
authorJaydeep Patil <jaydeep.patil@imgtec.com>
Tue, 20 Sep 2016 15:38:11 +0000 (08:38 -0700)
committerJim Stichnoth <stichnot@chromium.org>
Tue, 20 Sep 2016 15:38:11 +0000 (08:38 -0700)
The patch emits constant pool for float and double constants.

R=stichnot@chromium.org

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

Patch from Jaydeep Patil <jaydeep.patil@imgtec.com>.

src/IceTargetLoweringMIPS32.cpp
src/IceTargetLoweringMIPS32.h
tests_lit/llvm2ice_tests/fp_const_pool.ll

index 952aac8..fe1c42d 100644 (file)
@@ -1420,12 +1420,19 @@ void TargetMIPS32::PostLoweringLegalizer::legalizeMov(InstMIPS32Mov *MovInstr) {
         }
       } else {
         // Dest is FPR and SrcR is GPR. Use mtc1.
-        if (typeWidthInBytes(SrcR->getType()) == 8) {
-          // Split it into two mtc1 instructions
-          Variable *SrcGPRHi = Target->makeReg(
-              IceType_i32, RegMIPS32::get64PairFirstRegNum(SRegNum));
-          Variable *SrcGPRLo = Target->makeReg(
-              IceType_i32, RegMIPS32::get64PairSecondRegNum(SRegNum));
+        if (typeWidthInBytes(Dest->getType()) == 8) {
+          Variable *SrcGPRHi, *SrcGPRLo;
+          // SrcR could be $zero which is i32
+          if (SRegNum == RegMIPS32::Reg_ZERO) {
+            SrcGPRHi = Target->makeReg(IceType_i32, SRegNum);
+            SrcGPRLo = SrcGPRHi;
+          } else {
+            // Split it into two mtc1 instructions
+            SrcGPRHi = Target->makeReg(
+                IceType_i32, RegMIPS32::get64PairFirstRegNum(SRegNum));
+            SrcGPRLo = Target->makeReg(
+                IceType_i32, RegMIPS32::get64PairSecondRegNum(SRegNum));
+          }
           Variable *DstFPRHi = Target->makeReg(
               IceType_f32, RegMIPS32::get64PairFirstRegNum(DRegNum));
           Variable *DstFPRLo = Target->makeReg(
@@ -3362,9 +3369,104 @@ void TargetDataMIPS32::lowerGlobals(const VariableDeclarationList &Vars,
   }
 }
 
+namespace {
+template <typename T> struct ConstantPoolEmitterTraits;
+
+static_assert(sizeof(uint64_t) == 8,
+              "uint64_t is supposed to be 8 bytes wide.");
+
+// TODO(jaydeep.patil): implement the following when implementing constant
+// randomization:
+//  * template <> struct ConstantPoolEmitterTraits<uint8_t>
+//  * template <> struct ConstantPoolEmitterTraits<uint16_t>
+//  * template <> struct ConstantPoolEmitterTraits<uint32_t>
+template <> struct ConstantPoolEmitterTraits<float> {
+  using ConstantType = ConstantFloat;
+  static constexpr Type IceType = IceType_f32;
+  // AsmTag and TypeName can't be constexpr because llvm::StringRef is unhappy
+  // about them being constexpr.
+  static const char AsmTag[];
+  static const char TypeName[];
+  static uint64_t bitcastToUint64(float Value) {
+    static_assert(sizeof(Value) == sizeof(uint32_t),
+                  "Float should be 4 bytes.");
+    const uint32_t IntValue = Utils::bitCopy<uint32_t>(Value);
+    return static_cast<uint64_t>(IntValue);
+  }
+};
+const char ConstantPoolEmitterTraits<float>::AsmTag[] = ".word";
+const char ConstantPoolEmitterTraits<float>::TypeName[] = "f32";
+
+template <> struct ConstantPoolEmitterTraits<double> {
+  using ConstantType = ConstantDouble;
+  static constexpr Type IceType = IceType_f64;
+  static const char AsmTag[];
+  static const char TypeName[];
+  static uint64_t bitcastToUint64(double Value) {
+    static_assert(sizeof(double) == sizeof(uint64_t),
+                  "Double should be 8 bytes.");
+    return Utils::bitCopy<uint64_t>(Value);
+  }
+};
+const char ConstantPoolEmitterTraits<double>::AsmTag[] = ".quad";
+const char ConstantPoolEmitterTraits<double>::TypeName[] = "f64";
+
+template <typename T>
+void emitConstant(
+    Ostream &Str,
+    const typename ConstantPoolEmitterTraits<T>::ConstantType *Const) {
+  if (!BuildDefs::dump())
+    return;
+  using Traits = ConstantPoolEmitterTraits<T>;
+  Str << Const->getLabelName();
+  T Value = Const->getValue();
+  Str << ":\n\t" << Traits::AsmTag << "\t0x";
+  Str.write_hex(Traits::bitcastToUint64(Value));
+  Str << "\t/* " << Traits::TypeName << " " << Value << " */\n";
+}
+
+template <typename T> void emitConstantPool(GlobalContext *Ctx) {
+  if (!BuildDefs::dump())
+    return;
+  using Traits = ConstantPoolEmitterTraits<T>;
+  static constexpr size_t MinimumAlignment = 4;
+  SizeT Align = std::max(MinimumAlignment, typeAlignInBytes(Traits::IceType));
+  assert((Align % 4) == 0 && "Constants should be aligned");
+  Ostream &Str = Ctx->getStrEmit();
+  ConstantList Pool = Ctx->getConstantPool(Traits::IceType);
+  Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",%progbits," << Align
+      << "\n"
+      << "\t.align\t" << (Align == 4 ? 2 : 3) << "\n";
+  if (getFlags().getReorderPooledConstants()) {
+    // TODO(jaydeep.patil): add constant pooling.
+    UnimplementedError(getFlags());
+  }
+  for (Constant *C : Pool) {
+    if (!C->getShouldBePooled()) {
+      continue;
+    }
+    emitConstant<T>(Str, llvm::dyn_cast<typename Traits::ConstantType>(C));
+  }
+}
+} // end of anonymous namespace
+
 void TargetDataMIPS32::lowerConstants() {
   if (getFlags().getDisableTranslation())
     return;
+  switch (getFlags().getOutFileType()) {
+  case FT_Elf: {
+    ELFObjectWriter *Writer = Ctx->getObjectWriter();
+    Writer->writeConstantPool<ConstantFloat>(IceType_f32);
+    Writer->writeConstantPool<ConstantDouble>(IceType_f64);
+  } break;
+  case FT_Asm:
+  case FT_Iasm: {
+    OstreamLocker _(Ctx);
+    emitConstantPool<float>(Ctx);
+    emitConstantPool<double>(Ctx);
+    break;
+  }
+  }
 }
 
 void TargetDataMIPS32::lowerJumpTables() {
@@ -3486,21 +3588,25 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed,
       }
       return Reg;
     } else if (isScalarFloatingType(Ty)) {
-      // Load floats/doubles from literal pool.
       auto *CFrom = llvm::cast<Constant>(From);
-      assert(CFrom->getShouldBePooled());
-      Constant *Offset = Ctx->getConstantSym(0, CFrom->getLabelName());
-      Variable *TReg1 = makeReg(getPointerType());
-      Variable *TReg2 = makeReg(Ty);
-      Context.insert<InstFakeDef>(TReg2);
-      _lui(TReg1, Offset, RO_Hi);
-      OperandMIPS32Mem *Addr =
-          OperandMIPS32Mem::create(Func, Ty, TReg1, Offset);
-      if (Ty == IceType_f32)
-        _lwc1(TReg2, Addr, RO_Lo);
-      else
-        _ldc1(TReg2, Addr, RO_Lo);
-      return copyToReg(TReg2, RegNum);
+      Variable *TReg = makeReg(Ty);
+      if (!CFrom->getShouldBePooled()) {
+        // Float/Double constant 0 is not pooled.
+        Context.insert<InstFakeDef>(TReg);
+        _mov(TReg, getZero());
+      } else {
+        // Load floats/doubles from literal pool.
+        Constant *Offset = Ctx->getConstantSym(0, CFrom->getLabelName());
+        Variable *TReg1 = makeReg(getPointerType());
+        _lui(TReg1, Offset, RO_Hi);
+        OperandMIPS32Mem *Addr =
+            OperandMIPS32Mem::create(Func, Ty, TReg1, Offset);
+        if (Ty == IceType_f32)
+          _lwc1(TReg, Addr, RO_Lo);
+        else
+          _ldc1(TReg, Addr, RO_Lo);
+      }
+      return copyToReg(TReg, RegNum);
     }
   }
 
index 338fc85..5f3de51 100644 (file)
@@ -38,8 +38,9 @@ public:
     if (auto *ConstDouble = llvm::dyn_cast<ConstantDouble>(C)) {
       return !Utils::isPositiveZero(ConstDouble->getValue());
     }
-    if (llvm::isa<ConstantFloat>(C))
-      return true;
+    if (auto *ConstFloat = llvm::dyn_cast<ConstantFloat>(C)) {
+      return !Utils::isPositiveZero(ConstFloat->getValue());
+    }
     return false;
   }
   static std::unique_ptr<::Ice::TargetLowering> create(Cfg *Func) {
@@ -828,7 +829,6 @@ protected:
 
 private:
   ~TargetDataMIPS32() override = default;
-  template <typename T> static void emitConstantPool(GlobalContext *Ctx);
 };
 
 class TargetHeaderMIPS32 final : public TargetHeaderLowering {
index 587e967..e291ec1 100644 (file)
@@ -5,6 +5,12 @@
 
 ; REQUIRES: allow_dump
 
+; RUN: %if --need=target_MIPS32 --need=allow_dump \
+; RUN:   --command %p2i --filetype=asm --assemble --disassemble \
+; RUN:   --target mips32 -i %s --args -O2 --skip-unimplemented \
+; RUN:   | %if --need=target_MIPS32 --need=allow_dump \
+; RUN:   --command FileCheck --check-prefix MIPS32 %s
+
 define internal void @consume_float(float %f) {
   ret void
 }
@@ -21,6 +27,18 @@ entry:
   call void @consume_double(double -0.0)
   ret void
 }
+
+; MIPS32-LABEL: test_zeros
+; MIPS32: mtc1 zero,[[REG:.*]]
+; MIPS32: mov.s {{.*}},[[REG]]
+; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$float$80000000
+; MIPS32: lwc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$float$80000000
+; MIPS32: mtc1 zero,[[REGLo:.*]]
+; MIPS32: mtc1 zero,[[REGHi:.*]]
+; MIPS32: mov.d {{.*}},[[REGLo]]
+; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$double$8000000000000000
+; MIPS32: ldc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$double$8000000000000000
+
 ; Parse the function, dump the bitcode back out, and stop without translating.
 ; This tests that +0.0 and -0.0 aren't accidentally merged into a single
 ; zero-valued constant pool entry.
@@ -46,6 +64,26 @@ entry:
   call void @consume_double(double 0xFFF8000000000000)
   ret void
 }
+
+; MIPS32-LABEL: test_nans
+; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$float$7fc00000
+; MIPS32: lwc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$float$7fc00000
+; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$float$7fc00000
+; MIPS32: lwc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$float$7fc00000
+; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$float$ffc00000
+; MIPS32: lwc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$float$ffc00000
+; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$float$ffc00000
+; MIPS32: lwc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$float$ffc00000
+; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$double$7ff8000000000000
+; MIPS32: ldc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$double$7ff8000000000000
+; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$double$7ff8000000000000
+; MIPS32: ldc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$double$7ff8000000000000
+; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$double$fff8000000000000
+; MIPS32: ldc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$double$fff8000000000000
+; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$double$fff8000000000000
+; MIPS32: ldc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$double$fff8000000000000
+; MIPS32: jr ra
+
 ; The following tests check the emitted constant pool entries and make sure
 ; there is at most one entry for each NaN value.  We have to run a separate test
 ; for each NaN because the constant pool entries may be emitted in any order.
@@ -69,3 +107,22 @@ entry:
 ; RUN:   | FileCheck --check-prefix=NANS4 %s
 ; NANS4: double -nan
 ; NANS4-NOT: double -nan
+
+; MIPS32 constant pool
+; RUN: %if --need=target_MIPS32 --command %p2i \
+; RUN:   --target mips32 -i %s --filetype=asm --llvm-source \
+; RUN:   --args -O2 --skip-unimplemented \
+; RUN:   | %if --need=target_MIPS32 --command FileCheck \
+; RUN:   --check-prefix=MIPS32CP %s
+; MIPS32CP-LABEL: .L$float$7fc00000:
+; MIPS32CP: .word 0x7fc00000 /* f32 nan */
+; MIPS32CP-LABEL: .L$float$80000000
+; MIPS32CP: .word 0x80000000 /* f32 -0.000000e+00 */
+; MIPS32CP-LABEL: .L$float$ffc00000
+; MIPS32CP: .word 0xffc00000 /* f32 -nan */
+; MIPS32CP-LABEL: .L$double$7ff8000000000000
+; MIPS32CP: .quad 0x7ff8000000000000 /* f64 nan */
+; MIPS32CP-LABEL: .L$double$8000000000000000
+; MIPS32CP: .quad 0x8000000000000000 /* f64 -0.000000e+00 */
+; MIPS32CP-LABEL: .L$double$fff8000000000000
+; MIPS32CP: .quad 0xfff8000000000000 /* f64 -nan */