summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGExprScalar.cpp
diff options
context:
space:
mode:
authorAkira Hatanaka <ahatanaka@apple.com>2017-09-23 05:02:02 +0000
committerAkira Hatanaka <ahatanaka@apple.com>2017-09-23 05:02:02 +0000
commit34b5dbca0a449d96daa782a884418669b6d7736d (patch)
tree2528cf8192a189b1f6e84062eb0ca394101fd777 /clang/lib/CodeGen/CGExprScalar.cpp
parent41c4a109d893604fe2570598ee62fceff6e1aee8 (diff)
downloadbcm5719-llvm-34b5dbca0a449d96daa782a884418669b6d7736d.tar.gz
bcm5719-llvm-34b5dbca0a449d96daa782a884418669b6d7736d.zip
Promote storage-only __fp16 vector operands to float vectors.
This commit fixes a bug in the handling of storage-only __fp16 vectors where clang didn't promote __fp16 vector operands to float vectors. Conceptually, it performs the following transformation on the AST in CreateBuiltinBinOp and CreateBuiltinUnaryOp: (Before) typedef __fp16 half4 __attribute__ ((vector_size (8))); typedef float float4 __attribute__ ((vector_size (16))); half4 hv0, hv1, hv2, hv3; hv0 = hv1 + hv2 + hv3; (After) float4 t0 = (float4)hv1 + (float4)hv2; float4 t1 = t0 + (float4)hv3; hv0 = (half4)t1; Note that this commit fixes the bug for targets that set HalfArgsAndReturns to true (ARM and ARM64). Targets using intrinsics such as llvm.convert.to.fp16 to handle __fp16 are still broken. rdar://problem/20625184 Differential Revision: https://reviews.llvm.org/D32520 llvm-svn: 314056
Diffstat (limited to 'clang/lib/CodeGen/CGExprScalar.cpp')
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp39
1 files changed, 35 insertions, 4 deletions
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index a488c80979f..d9d619e802b 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -1014,10 +1014,41 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
return Builder.CreateVectorSplat(NumElements, Src, "splat");
}
- // Allow bitcast from vector to integer/fp of the same size.
- if (isa<llvm::VectorType>(SrcTy) ||
- isa<llvm::VectorType>(DstTy))
- return Builder.CreateBitCast(Src, DstTy, "conv");
+ if (isa<llvm::VectorType>(SrcTy) || isa<llvm::VectorType>(DstTy)) {
+ // Allow bitcast from vector to integer/fp of the same size.
+ unsigned SrcSize = SrcTy->getPrimitiveSizeInBits();
+ unsigned DstSize = DstTy->getPrimitiveSizeInBits();
+ if (SrcSize == DstSize)
+ return Builder.CreateBitCast(Src, DstTy, "conv");
+
+ // Conversions between vectors of different sizes are not allowed except
+ // when vectors of half are involved. Operations on storage-only half
+ // vectors require promoting half vector operands to float vectors and
+ // truncating the result, which is either an int or float vector, to a
+ // short or half vector.
+
+ // Source and destination are both expected to be vectors.
+ llvm::Type *SrcElementTy = SrcTy->getVectorElementType();
+ llvm::Type *DstElementTy = DstTy->getVectorElementType();
+
+ assert(((SrcElementTy->isIntegerTy() &&
+ DstElementTy->isIntegerTy()) ||
+ (SrcElementTy->isFloatingPointTy() &&
+ DstElementTy->isFloatingPointTy())) &&
+ "unexpected conversion between a floating-point vector and an "
+ "integer vector");
+
+ // Truncate an i32 vector to an i16 vector.
+ if (SrcElementTy->isIntegerTy())
+ return Builder.CreateIntCast(Src, DstTy, false, "conv");
+
+ // Truncate a float vector to a half vector.
+ if (SrcSize > DstSize)
+ return Builder.CreateFPTrunc(Src, DstTy, "conv");
+
+ // Promote a half vector to a float vector.
+ return Builder.CreateFPExt(Src, DstTy, "conv");
+ }
// Finally, we have the arithmetic types: real int/float.
Value *Res = nullptr;
OpenPOWER on IntegriCloud