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.

+ +

TYPE_CODE_HALF Record

+ +
+ +

[HALF]

+ +

The HALF record (code 10) adds a half (16-bit +floating point) type to the type table. +

+
+

TYPE_CODE_FLOAT Record

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 +}