Add half support to LLVM (for OpenCL)
authorTobias Grosser <grosser@fim.uni-passau.de>
Thu, 24 May 2012 15:59:06 +0000 (15:59 +0000)
committerTobias Grosser <grosser@fim.uni-passau.de>
Thu, 24 May 2012 15:59:06 +0000 (15:59 +0000)
Submitted by: Anton Lokhmotov  <Anton.Lokhmotov@arm.com>

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
docs/LangRef.html
lib/AsmParser/LLLexer.cpp
lib/VMCore/AsmWriter.cpp
test/Assembler/half-constprop.ll [new file with mode: 0644]
test/Assembler/half-conv.ll [new file with mode: 0644]
test/Assembler/half.ll [new file with mode: 0644]

index a8777ee772b7d8a46c90abe95d1e323c1ad7f56d..30145de5811537f34cbf57a973289b7150614927 100644 (file)
@@ -1144,6 +1144,18 @@ type table.
 </p>
 </div>
 
+<!-- _______________________________________________________________________ -->
+<h4><a name="TYPE_CODE_HALF">TYPE_CODE_HALF Record</a></h4>
+
+<div>
+
+<p><tt>[HALF]</tt></p>
+
+<p>The <tt>HALF</tt> record (code 10) adds a <tt>half</tt> (16-bit
+floating point) type to the type table.
+</p>
+</div>
+
 <!-- _______________________________________________________________________ -->
 <h4><a name="TYPE_CODE_FLOAT">TYPE_CODE_FLOAT Record</a></h4>
 
index 8f7a17c748cb83b7699973ad0fe80e44174935a2..a781992f89826c027120e325a3d3ad6ac8e9a799 100644 (file)
@@ -2289,8 +2289,9 @@ in signal handlers).</p>
    by <tt>0xM</tt> followed by 32 hexadecimal digits.  The IEEE 128-bit format
    is represented by <tt>0xL</tt> 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).</p>
+   they match the long double format on your target. The IEEE 16-bit format
+   (half precision) is represented by <tt>0xH</tt> followed by 4 hexadecimal
+   digits. All hexadecimal formats are big-endian (sign bit at the left).</p>
 
 <p>There are no constants of type x86mmx.</p>
 </div>
@@ -7947,7 +7948,8 @@ LLVM</a>.</p>
 
 <div>
 
-<p>Half precision floating point is a storage-only format. This means that it is
+<p>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.</p>
    
index 8818168f643d11ad652a7f440d9ae73407e9c918..e718069db2927aeaed3d9a2263917eb73477e98a 100644 (file)
@@ -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;
   }
 }
 
index 7b39efb7c7a0fd878ffa9f36b46c5c23b83f6036..4a7fde190553312aaeb7b452e7cac769e3226a56 100644 (file)
@@ -708,8 +708,7 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV,
   }
 
   if (const ConstantFP *CFP = dyn_cast<ConstantFP>(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<width; j+=4, shiftcount-=4) {
         unsigned int nibble = (word>>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<width; j+=4, shiftcount-=4) {
       unsigned int nibble = (word>>shiftcount) & 15;
diff --git a/test/Assembler/half-constprop.ll b/test/Assembler/half-constprop.ll
new file mode 100644 (file)
index 0000000..03ccdda
--- /dev/null
@@ -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 (file)
index 0000000..bf9ae57
--- /dev/null
@@ -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 (file)
index 0000000..63ad392
--- /dev/null
@@ -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
+}