From 057beb8d4fe8d5dad98ad80a49a649730c3a3eb0 Mon Sep 17 00:00:00 2001
From: Tobias Grosser
Date: Thu, 24 May 2012 15:59:06 +0000
Subject: [PATCH] Add half support to LLVM (for OpenCL)
Submitted by: Anton Lokhmotov
Approved by: o Anton Korobeynikov
o Micah Villmow
o David Neto
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@157393 91177308-0d34-0410-b5e6-96231b3b80d8
---
docs/BitCodeFormat.html | 12 ++++++++++++
docs/LangRef.html | 8 +++++---
lib/AsmParser/LLLexer.cpp | 6 +++++-
lib/VMCore/AsmWriter.cpp | 25 ++++++++++++++++---------
test/Assembler/half-constprop.ll | 17 +++++++++++++++++
test/Assembler/half-conv.ll | 13 +++++++++++++
test/Assembler/half.ll | 8 ++++++++
7 files changed, 76 insertions(+), 13 deletions(-)
create mode 100644 test/Assembler/half-constprop.ll
create mode 100644 test/Assembler/half-conv.ll
create mode 100644 test/Assembler/half.ll
diff --git a/docs/BitCodeFormat.html b/docs/BitCodeFormat.html
index a8777ee772b..30145de5811 100644
--- a/docs/BitCodeFormat.html
+++ b/docs/BitCodeFormat.html
@@ -1144,6 +1144,18 @@ type table.
+
+
+
+
+
+
[HALF]
+
+
The HALF record (code 10) adds a half (16-bit
+floating point) type to the type table.
+
+
+
diff --git a/docs/LangRef.html b/docs/LangRef.html
index 8f7a17c748c..a781992f898 100644
--- a/docs/LangRef.html
+++ b/docs/LangRef.html
@@ -2289,8 +2289,9 @@ in signal handlers).
by 0xM followed by 32 hexadecimal digits. The IEEE 128-bit format
is represented by 0xL followed by 32 hexadecimal digits; no
currently supported target uses this format. Long doubles will only work if
- they match the long double format on your target. All hexadecimal formats
- are big-endian (sign bit at the left).
+ they match the long double format on your target. The IEEE 16-bit format
+ (half precision) is represented by 0xH followed by 4 hexadecimal
+ digits. All hexadecimal formats are big-endian (sign bit at the left).
There are no constants of type x86mmx.
@@ -7947,7 +7948,8 @@ LLVM.
-
Half precision floating point is a storage-only format. This means that it is
+
For most target platforms, half precision floating point is a storage-only
+ format. This means that it is
a dense encoding (in memory) but does not support computation in the
format.
diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp
index 8818168f643..e718069db29 100644
--- a/lib/AsmParser/LLLexer.cpp
+++ b/lib/AsmParser/LLLexer.cpp
@@ -673,11 +673,12 @@ lltok::Kind LLLexer::LexIdentifier() {
/// HexFP80Constant 0xK[0-9A-Fa-f]+
/// HexFP128Constant 0xL[0-9A-Fa-f]+
/// HexPPC128Constant 0xM[0-9A-Fa-f]+
+/// HexHalfConstant 0xH[0-9A-Fa-f]+
lltok::Kind LLLexer::Lex0x() {
CurPtr = TokStart + 2;
char Kind;
- if (CurPtr[0] >= 'K' && CurPtr[0] <= 'M') {
+ if (CurPtr[0] >= 'K' && CurPtr[0] <= 'M' || CurPtr[0] == 'H') {
Kind = *CurPtr++;
} else {
Kind = 'J';
@@ -718,6 +719,9 @@ lltok::Kind LLLexer::Lex0x() {
HexToIntPair(TokStart+3, CurPtr, Pair);
APFloatVal = APFloat(APInt(128, Pair));
return lltok::APFloat;
+ case 'H':
+ APFloatVal = APFloat(APInt(16,HexIntToVal(TokStart+3, CurPtr)));
+ return lltok::APFloat;
}
}
diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp
index 7b39efb7c7a..4a7fde19055 100644
--- a/lib/VMCore/AsmWriter.cpp
+++ b/lib/VMCore/AsmWriter.cpp
@@ -708,8 +708,7 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV,
}
if (const ConstantFP *CFP = dyn_cast
(CV)) {
- if (&CFP->getValueAPF().getSemantics() == &APFloat::IEEEhalf ||
- &CFP->getValueAPF().getSemantics() == &APFloat::IEEEsingle ||
+ if (&CFP->getValueAPF().getSemantics() == &APFloat::IEEEsingle ||
&CFP->getValueAPF().getSemantics() == &APFloat::IEEEdouble) {
// We would like to output the FP constant value in exponential notation,
// but we cannot do this if doing so will lose precision. Check here to
@@ -759,16 +758,20 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV,
return;
}
- // Some form of long double. These appear as a magic letter identifying
- // the type, then a fixed number of hex digits.
+ // Either half, or some form of long double.
+ // These appear as a magic letter identifying the type, then a
+ // fixed number of hex digits.
Out << "0x";
+ // Bit position, in the current word, of the next nibble to print.
+ int shiftcount;
+
if (&CFP->getValueAPF().getSemantics() == &APFloat::x87DoubleExtended) {
Out << 'K';
// api needed to prevent premature destruction
APInt api = CFP->getValueAPF().bitcastToAPInt();
const uint64_t* p = api.getRawData();
uint64_t word = p[1];
- int shiftcount=12;
+ shiftcount = 12;
int width = api.getBitWidth();
for (int j=0; j>shiftcount) & 15;
@@ -784,17 +787,21 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV,
}
}
return;
- } else if (&CFP->getValueAPF().getSemantics() == &APFloat::IEEEquad)
+ } else if (&CFP->getValueAPF().getSemantics() == &APFloat::IEEEquad) {
+ shiftcount = 60;
Out << 'L';
- else if (&CFP->getValueAPF().getSemantics() == &APFloat::PPCDoubleDouble)
+ } else if (&CFP->getValueAPF().getSemantics() == &APFloat::PPCDoubleDouble) {
+ shiftcount = 60;
Out << 'M';
- else
+ } else if (&CFP->getValueAPF().getSemantics() == &APFloat::IEEEhalf) {
+ shiftcount = 12;
+ Out << 'H';
+ } else
llvm_unreachable("Unsupported floating point type");
// api needed to prevent premature destruction
APInt api = CFP->getValueAPF().bitcastToAPInt();
const uint64_t* p = api.getRawData();
uint64_t word = *p;
- int shiftcount=60;
int width = api.getBitWidth();
for (int j=0; j>shiftcount) & 15;
diff --git a/test/Assembler/half-constprop.ll b/test/Assembler/half-constprop.ll
new file mode 100644
index 00000000000..03ccdda97e0
--- /dev/null
+++ b/test/Assembler/half-constprop.ll
@@ -0,0 +1,17 @@
+; RUN: llvm-as < %s | opt -O3 | llvm-dis | FileCheck %s
+; Testing half constant propagation.
+
+define half @abc() nounwind {
+entry:
+ %a = alloca half, align 2
+ %b = alloca half, align 2
+ %.compoundliteral = alloca float, align 4
+ store half 0xH4200, half* %a, align 2
+ store half 0xH4B9A, half* %b, align 2
+ %tmp = load half* %a, align 2
+ %tmp1 = load half* %b, align 2
+ %add = fadd half %tmp, %tmp1
+; CHECK: 0xH4C8D
+ ret half %add
+}
+
diff --git a/test/Assembler/half-conv.ll b/test/Assembler/half-conv.ll
new file mode 100644
index 00000000000..bf9ae571397
--- /dev/null
+++ b/test/Assembler/half-conv.ll
@@ -0,0 +1,13 @@
+; RUN: llvm-as < %s | opt -O3 | llvm-dis | FileCheck %s
+; Testing half to float conversion.
+
+define float @abc() nounwind {
+entry:
+ %a = alloca half, align 2
+ %.compoundliteral = alloca float, align 4
+ store half 0xH4C8D, half* %a, align 2
+ %tmp = load half* %a, align 2
+ %conv = fpext half %tmp to float
+; CHECK: 0x4032340000000000
+ ret float %conv
+}
diff --git a/test/Assembler/half.ll b/test/Assembler/half.ll
new file mode 100644
index 00000000000..63ad39235d1
--- /dev/null
+++ b/test/Assembler/half.ll
@@ -0,0 +1,8 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+; Basic smoke test for half type.
+
+; CHECK: define half @halftest
+define half @halftest(half %A0) {
+; CHECK: ret half %A0
+ ret half %A0
+}