[Beignet] [PATCH 1/8] Backend: Add half float as a new type.

junyan.he at inbox.com junyan.he at inbox.com
Thu May 21 01:25:23 PDT 2015


From: Junyan He <junyan.he at linux.intel.com>

Because the CPU of X86 does not support half float
instructions, there is no support for half float operations.
So we introduce the half class to handle the operations for
half float using llvm's APFloat utility.

Signed-off-by: Junyan He <junyan.he at linux.intel.com>
---
 backend/src/CMakeLists.txt |   2 +
 backend/src/ir/half.cpp    | 220 +++++++++++++++++++++++++++++++++++++++++++++
 backend/src/ir/half.hpp    |  64 +++++++++++++
 3 files changed, 286 insertions(+)
 create mode 100644 backend/src/ir/half.cpp
 create mode 100644 backend/src/ir/half.hpp

diff --git a/backend/src/CMakeLists.txt b/backend/src/CMakeLists.txt
index 8f574d4..73fc6e5 100644
--- a/backend/src/CMakeLists.txt
+++ b/backend/src/CMakeLists.txt
@@ -53,6 +53,8 @@ set (GBE_SRC
     ir/sampler.hpp
     ir/image.cpp
     ir/image.hpp
+    ir/half.cpp
+    ir/half.hpp
     ir/instruction.cpp
     ir/instruction.hpp
     ir/liveness.cpp
diff --git a/backend/src/ir/half.cpp b/backend/src/ir/half.cpp
new file mode 100644
index 0000000..1c0d7eb
--- /dev/null
+++ b/backend/src/ir/half.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * \file half.cpp
+ *
+ */
+#include "llvm/ADT/APSInt.h"
+#include "half.hpp"
+
+namespace gbe {
+namespace ir {
+  static llvm::APFloat convU16ToAPFloat(const uint16_t v)
+  {
+    uint64_t v64 = static_cast<uint64_t>(v);
+    llvm::APInt apInt(16, v64, false);
+    return llvm::APFloat(llvm::APFloat::IEEEhalf, apInt);
+  }
+
+  static uint16_t convAPFloatToU16(const llvm::APFloat& apf)
+  {
+    llvm::APInt api = apf.bitcastToAPInt();
+    uint64_t v64 = api.getZExtValue();
+    return static_cast<uint16_t>(v64);
+  }
+
+  half::operator float(void) const {
+    bool loseInfo;
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    apf_self.convert(llvm::APFloat::IEEEsingle, llvm::APFloat::rmNearestTiesToEven, &loseInfo);
+    return apf_self.convertToFloat();
+  }
+
+  half::operator double(void) const {
+    bool loseInfo;
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    apf_self.convert(llvm::APFloat::IEEEdouble, llvm::APFloat::rmNearestTiesToEven, &loseInfo);
+    return apf_self.convertToDouble();
+  }
+
+  half::operator uint16_t(void) const {
+    llvm::APSInt apsInt(16, false);
+    bool isExact;
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    apf_self.convertToInteger(apsInt, llvm::APFloat::rmNearestTiesToEven, &isExact);
+    return static_cast<uint16_t>(apsInt.getZExtValue());
+  }
+
+  half::operator int16_t(void) const {
+    llvm::APSInt apsInt(16, true);
+    bool isExact;
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    apf_self.convertToInteger(apsInt, llvm::APFloat::rmNearestTiesToEven, &isExact);
+    return static_cast<int16_t>(apsInt.getZExtValue());
+  }
+
+  half half::convToHalf(uint16_t u16) {
+    llvm::APFloat res(llvm::APFloat::IEEEhalf, llvm::APInt(16, 0, false));
+    uint64_t u64 = static_cast<uint64_t>(u16);
+    llvm::APInt apInt(16, u64, false);
+    res.convertFromAPInt(apInt, false, llvm::APFloat::rmNearestTiesToEven);
+    return half(convAPFloatToU16(res));
+  }
+
+  half half::convToHalf(int16_t v16) {
+    llvm::APFloat res(llvm::APFloat::IEEEhalf, llvm::APInt(16, 0, true));
+    uint64_t u64 = static_cast<uint64_t>(v16);
+    llvm::APInt apInt(16, u64, true);
+    res.convertFromAPInt(apInt, true, llvm::APFloat::rmNearestTiesToEven);
+    return half(convAPFloatToU16(res));
+  }
+
+  half half::operator +(const half& other) const
+  {
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    llvm::APFloat apf_other = convU16ToAPFloat(other.val);
+    apf_self.add(apf_other, llvm::APFloat::rmNearestTiesToEven);
+    uint16_t ret = convAPFloatToU16(apf_self);
+    return half(ret);
+  }
+
+  half half::operator -(const half& other) const
+  {
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    llvm::APFloat apf_other = convU16ToAPFloat(other.val);
+    apf_self.subtract(apf_other, llvm::APFloat::rmNearestTiesToEven);
+    uint16_t ret = convAPFloatToU16(apf_self);
+    return half(ret);
+  }
+
+  half half::operator *(const half& other) const
+  {
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    llvm::APFloat apf_other = convU16ToAPFloat(other.val);
+    apf_self.multiply(apf_other, llvm::APFloat::rmNearestTiesToEven);
+    uint16_t ret = convAPFloatToU16(apf_self);
+    return half(ret);
+  }
+
+  half half::operator /(const half& other) const
+  {
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    llvm::APFloat apf_other = convU16ToAPFloat(other.val);
+    apf_self.divide(apf_other, llvm::APFloat::rmNearestTiesToEven);
+    uint16_t ret = convAPFloatToU16(apf_self);
+    return half(ret);
+  }
+
+  half half::operator %(const half& other) const
+  {
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    llvm::APFloat apf_other = convU16ToAPFloat(other.val);
+    apf_self.remainder(apf_other);
+    uint16_t ret = convAPFloatToU16(apf_self);
+    return half(ret);
+  }
+
+  bool half::operator ==(const half& other) const
+  {
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    llvm::APFloat apf_other = convU16ToAPFloat(other.val);
+    llvm::APFloat::cmpResult res = apf_self.compare(apf_other);
+    if (res == llvm::APFloat::cmpEqual)
+      return true;
+
+    return false;
+  }
+
+  bool half::operator !=(const half& other) const
+  {
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    llvm::APFloat apf_other = convU16ToAPFloat(other.val);
+    llvm::APFloat::cmpResult res = apf_self.compare(apf_other);
+    if (res == llvm::APFloat::cmpEqual)
+      return false;
+
+    return true;
+  }
+
+  bool half::operator <(const half& other) const
+  {
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    llvm::APFloat apf_other = convU16ToAPFloat(other.val);
+    llvm::APFloat::cmpResult res = apf_self.compare(apf_other);
+    if (res == llvm::APFloat::cmpLessThan)
+      return true;
+
+    return false;
+  }
+
+  bool half::operator >(const half& other) const
+  {
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    llvm::APFloat apf_other = convU16ToAPFloat(other.val);
+    llvm::APFloat::cmpResult res = apf_self.compare(apf_other);
+    if (res == llvm::APFloat::cmpGreaterThan)
+      return true;
+
+    return false;
+  }
+
+  bool half::operator <=(const half& other) const
+  {
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    llvm::APFloat apf_other = convU16ToAPFloat(other.val);
+    llvm::APFloat::cmpResult res = apf_self.compare(apf_other);
+    if (res == llvm::APFloat::cmpLessThan || res == llvm::APFloat::cmpEqual)
+      return true;
+
+    return false;
+  }
+
+  bool half::operator >=(const half& other) const
+  {
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    llvm::APFloat apf_other = convU16ToAPFloat(other.val);
+    llvm::APFloat::cmpResult res = apf_self.compare(apf_other);
+    if (res == llvm::APFloat::cmpGreaterThan || res == llvm::APFloat::cmpEqual)
+      return true;
+
+    return false;
+  }
+
+  bool half::operator &&(const half& other) const
+  {
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    llvm::APFloat apf_other = convU16ToAPFloat(other.val);
+    if (apf_self.isZero() || apf_other.isZero())
+      return false;
+
+    return true;
+  }
+
+  bool half::operator ||(const half& other) const
+  {
+    llvm::APFloat apf_self = convU16ToAPFloat(this->val);
+    llvm::APFloat apf_other = convU16ToAPFloat(other.val);
+    if (apf_self.isZero() && apf_other.isZero())
+      return false;
+
+    return true;
+  }
+
+} /* namespace ir */
+} /* namespace gbe */
diff --git a/backend/src/ir/half.hpp b/backend/src/ir/half.hpp
new file mode 100644
index 0000000..6d2e207
--- /dev/null
+++ b/backend/src/ir/half.hpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * \file half.hpp
+ *
+ */
+
+#ifndef __GBE_IR_HALF_HPP__
+#define __GBE_IR_HALF_HPP__
+
+#include "llvm/ADT/APFloat.h"
+
+namespace gbe {
+namespace ir {
+  /* Because there is no builtin half float data type for GCC on X86 platform,
+     we need to generate a half class to implement all the OP and CONV for half
+     float using LLVM's APFloat ADT. */
+  class half
+  {
+    private:
+      uint16_t val;
+    public:
+      half(uint16_t v) : val(v) {};
+      static half convToHalf(uint16_t u16);
+      static half convToHalf(int16_t v16);
+      half(const half& other) { this->val = other.val; };
+      uint16_t getVal(void) { return val; };
+      operator float (void) const;
+      operator double (void) const;
+      operator uint16_t (void) const;
+      operator int16_t (void) const;
+      half operator+ (const half &) const;
+      half operator- (const half &) const;
+      half operator* (const half &) const;
+      half operator/ (const half &) const;
+      half operator% (const half &) const;
+      bool operator> (const half &) const;
+      bool operator< (const half &) const;
+      bool operator== (const half &) const;
+      bool operator!= (const half &) const;
+      bool operator>= (const half &) const;
+      bool operator<= (const half &) const;
+      bool operator&& (const half &) const;
+      bool operator|| (const half &) const;
+  };
+} /* namespace ir */
+} /* namespace gbe */
+#endif /* End of __GBE_IR_HALF_HPP__ */
-- 
1.9.1



More information about the Beignet mailing list