Added support for half float in the Blitter
Implemented Float <-> Half conversion. The conversion is copied from
Half.cpp and is the same as the C++ code, converted to Reactor code.
The conversion is NOT optimized. Optimizing this code path will be
done later, this cl only cares about correctness.
Passes all conversion tests to and from half float in the following
patterns:
[dEQP-VK.api.copy_and_blit.core.blit_image]
.all_formats.color.[supported format].r16_sfloat.*
.all_formats.color.[supported format].r16g16_sfloat.*
.all_formats.color.[supported format].r16g16b16a16_sfloat.*
.all_formats.color.r16_sfloat.*
.all_formats.color.r16g16_sfloat.*
.all_formats.color.r16g16b16a16_sfloat.*
Bug b/119620767
Change-Id: Icd725dcd2ddd8c54e6657a2c3210da270210a149
Reviewed-on: https://swiftshader-review.googlesource.com/c/23329
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 6f99e6e..c760081 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -6086,6 +6086,39 @@
return T(llvm::VectorType::get(T(UInt::getType()), 4));
}
+ Half::Half(RValue<Float> cast)
+ {
+ UInt fp32i = As<UInt>(cast);
+ UInt abs = fp32i & 0x7FFFFFFF;
+ UShort fp16i((fp32i & 0x80000000) >> 16); // sign
+
+ If(abs > 0x47FFEFFF) // Infinity
+ {
+ fp16i |= UShort(0x7FFF);
+ }
+ Else
+ {
+ If(abs < 0x38800000) // Denormal
+ {
+ Int mantissa = (abs & 0x007FFFFF) | 0x00800000;
+ Int e = 113 - (abs >> 23);
+ abs = IfThenElse(e < 24, mantissa >> e, Int(0));
+ fp16i |= UShort((abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13);
+ }
+ Else
+ {
+ fp16i |= UShort((abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13);
+ }
+ }
+
+ storeValue(fp16i.loadValue());
+ }
+
+ Type *Half::getType()
+ {
+ return T(llvm::Type::getInt16Ty(*::context));
+ }
+
Float::Float(RValue<Int> cast)
{
Value *integer = Nucleus::createSIToFP(cast.value, Float::getType());
@@ -6101,6 +6134,36 @@
storeValue(result.value);
}
+ Float::Float(RValue<Half> cast)
+ {
+ Int fp16i(As<UShort>(cast));
+
+ Int s = (fp16i >> 15) & 0x00000001;
+ Int e = (fp16i >> 10) & 0x0000001F;
+ Int m = fp16i & 0x000003FF;
+
+ UInt fp32i(s << 31);
+ If(e == 0)
+ {
+ If(m != 0)
+ {
+ While((m & 0x00000400) == 0)
+ {
+ m <<= 1;
+ e -= 1;
+ }
+
+ fp32i |= As<UInt>(((e + (127 - 15) + 1) << 23) | ((m & ~0x00000400) << 13));
+ }
+ }
+ Else
+ {
+ fp32i |= As<UInt>(((e + (127 - 15)) << 23) | (m << 13));
+ }
+
+ storeValue(As<Float>(fp32i).value);
+ }
+
Float::Float(float x)
{
storeValue(Nucleus::createConstantFloat(x));
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index ba67afa..fe4cf1d 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -49,6 +49,7 @@
class Int4;
class UInt4;
class Long;
+ class Half;
class Float;
class Float2;
class Float4;
@@ -1923,11 +1924,20 @@
RValue<UInt4> Min(RValue<UInt4> x, RValue<UInt4> y);
// RValue<UInt4> RoundInt(RValue<Float4> cast);
+ class Half : public LValue<Half>
+ {
+ public:
+ explicit Half(RValue<Float> cast);
+
+ static Type *getType();
+ };
+
class Float : public LValue<Float>
{
public:
explicit Float(RValue<Int> cast);
explicit Float(RValue<UInt> cast);
+ explicit Float(RValue<Half> cast);
Float() = default;
Float(float x);
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index 08fc013..083576e 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -6389,6 +6389,39 @@
return T(Ice::IceType_v4i32);
}
+ Half::Half(RValue<Float> cast)
+ {
+ UInt fp32i = As<UInt>(cast);
+ UInt abs = fp32i & 0x7FFFFFFF;
+ UShort fp16i((fp32i & 0x80000000) >> 16); // sign
+
+ If(abs > 0x47FFEFFF) // Infinity
+ {
+ fp16i |= UShort(0x7FFF);
+ }
+ Else
+ {
+ If(abs < 0x38800000) // Denormal
+ {
+ Int mantissa = (abs & 0x007FFFFF) | 0x00800000;
+ Int e = 113 - (abs >> 23);
+ abs = IfThenElse(e < 24, mantissa >> e, Int(0));
+ fp16i |= UShort((abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13);
+ }
+ Else
+ {
+ fp16i |= UShort((abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13);
+ }
+ }
+
+ storeValue(fp16i.loadValue());
+ }
+
+ Type *Half::getType()
+ {
+ return T(Ice::IceType_i16);
+ }
+
Float::Float(RValue<Int> cast)
{
Value *integer = Nucleus::createSIToFP(cast.value, Float::getType());
@@ -6404,6 +6437,36 @@
storeValue(result.value);
}
+ Float::Float(RValue<Half> cast)
+ {
+ Int fp16i(As<UShort>(cast));
+
+ Int s = (fp16i >> 15) & 0x00000001;
+ Int e = (fp16i >> 10) & 0x0000001F;
+ Int m = fp16i & 0x000003FF;
+
+ UInt fp32i(s << 31);
+ If(e == 0)
+ {
+ If(m != 0)
+ {
+ While((m & 0x00000400) == 0)
+ {
+ m <<= 1;
+ e -= 1;
+ }
+
+ fp32i |= As<UInt>(((e + (127 - 15) + 1) << 23) | ((m & ~0x00000400) << 13));
+ }
+ }
+ Else
+ {
+ fp32i |= As<UInt>(((e + (127 - 15)) << 23) | (m << 13));
+ }
+
+ storeValue(As<Float>(fp32i).value);
+ }
+
Float::Float(float x)
{
storeValue(Nucleus::createConstantFloat(x));