From 803acb3ff2bb1fe322b530d3bf2db73a5c3eb305 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Thu, 22 Dec 2011 03:51:45 +0000 Subject: [PATCH] Add support for bitcasts to vector type in Evaluate. llvm-svn: 147137 --- clang/include/clang/Basic/TargetInfo.h | 3 + clang/lib/AST/ExprConstant.cpp | 85 ++++++++++++++++++++++++++ clang/lib/Basic/TargetInfo.cpp | 1 + clang/lib/Basic/Targets.cpp | 11 +++- clang/test/CodeGen/altivec.c | 8 +-- clang/test/CodeGen/const-init.c | 12 ++++ 6 files changed, 115 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index e9b9d14daf6b..280597817917 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -64,6 +64,7 @@ class TargetInfo : public llvm::RefCountedBase { protected: // Target values set by the ctor of the actual target implementation. Default // values are specified by the TargetInfo constructor. + bool BigEndian; bool TLSSupported; bool NoAsmVariants; // True if {|} are normal characters. unsigned char PointerWidth, PointerAlign; @@ -621,6 +622,8 @@ public: /// which the program should be compiled. VersionTuple getPlatformMinVersion() const { return PlatformMinVersion; } + bool isBigEndian() const { return BigEndian; } + protected: virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return PointerWidth; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index c58a5688760d..96a1785e142a 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -913,6 +913,53 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E, return true; } +static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, + llvm::APInt &Res) { + CCValue SVal; + if (!Evaluate(SVal, Info, E)) + return false; + if (SVal.isInt()) { + Res = SVal.getInt(); + return true; + } + if (SVal.isFloat()) { + Res = SVal.getFloat().bitcastToAPInt(); + return true; + } + if (SVal.isVector()) { + QualType VecTy = E->getType(); + unsigned VecSize = Info.Ctx.getTypeSize(VecTy); + QualType EltTy = VecTy->castAs()->getElementType(); + unsigned EltSize = Info.Ctx.getTypeSize(EltTy); + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + Res = llvm::APInt::getNullValue(VecSize); + for (unsigned i = 0; i < SVal.getVectorLength(); i++) { + APValue &Elt = SVal.getVectorElt(i); + llvm::APInt EltAsInt; + if (Elt.isInt()) { + EltAsInt = Elt.getInt(); + } else if (Elt.isFloat()) { + EltAsInt = Elt.getFloat().bitcastToAPInt(); + } else { + // Don't try to handle vectors of anything other than int or float + // (not sure if it's possible to hit this case). + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + return false; + } + unsigned BaseEltSize = EltAsInt.getBitWidth(); + if (BigEndian) + Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i*EltSize+BaseEltSize); + else + Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i*EltSize); + } + return true; + } + // Give up if the input isn't an int, float, or vector. For example, we + // reject "(v4i16)(intptr_t)&a". + Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + return false; +} + static bool FindMostDerivedObject(EvalInfo &Info, const LValue &LVal, const CXXRecordDecl *&MostDerivedType, unsigned &MostDerivedPathLength, @@ -2977,6 +3024,44 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { SmallVector Elts(NElts, Val); return Success(Elts, E); } + case CK_BitCast: { + // Evaluate the operand into an APInt we can extract from. + llvm::APInt SValInt; + if (!EvalAndBitcastToAPInt(Info, SE, SValInt)) + return false; + // Extract the elements + QualType EltTy = VTy->getElementType(); + unsigned EltSize = Info.Ctx.getTypeSize(EltTy); + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + SmallVector Elts; + if (EltTy->isRealFloatingType()) { + const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(EltTy); + bool isIEESem = &Sem != &APFloat::PPCDoubleDouble; + unsigned FloatEltSize = EltSize; + if (&Sem == &APFloat::x87DoubleExtended) + FloatEltSize = 80; + for (unsigned i = 0; i < NElts; i++) { + llvm::APInt Elt; + if (BigEndian) + Elt = SValInt.rotl(i*EltSize+FloatEltSize).trunc(FloatEltSize); + else + Elt = SValInt.rotr(i*EltSize).trunc(FloatEltSize); + Elts.push_back(APValue(APFloat(Elt, isIEESem))); + } + } else if (EltTy->isIntegerType()) { + for (unsigned i = 0; i < NElts; i++) { + llvm::APInt Elt; + if (BigEndian) + Elt = SValInt.rotl(i*EltSize+EltSize).zextOrTrunc(EltSize); + else + Elt = SValInt.rotr(i*EltSize).zextOrTrunc(EltSize); + Elts.push_back(APValue(APSInt(Elt, EltTy->isSignedIntegerType()))); + } + } else { + return Error(E); + } + return Success(Elts, E); + } default: return ExprEvaluatorBaseTy::VisitCastExpr(E); } diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 66274f11fc14..f938b5a6045d 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -27,6 +27,7 @@ static const LangAS::Map DefaultAddrSpaceMap = { 0 }; TargetInfo::TargetInfo(const std::string &T) : Triple(T) { // Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or // SPARC. These should be overridden by concrete targets as needed. + BigEndian = true; TLSSupported = true; NoAsmVariants = false; PointerWidth = PointerAlign = 32; diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index b9f505c86bbb..d61d3cd7cf3b 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -910,6 +910,7 @@ namespace { std::vector AvailableFeatures; public: PTXTargetInfo(const std::string& triple) : TargetInfo(triple) { + BigEndian = false; TLSSupported = false; LongWidth = LongAlign = 64; AddrSpaceMap = &PTXAddrSpaceMap; @@ -1331,6 +1332,7 @@ public: X86TargetInfo(const std::string& triple) : TargetInfo(triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow), HasAES(false), HasAVX(false), HasAVX2(false), CPU(CK_Generic) { + BigEndian = false; LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; } virtual void getTargetBuiltins(const Builtin::Info *&Records, @@ -2482,6 +2484,7 @@ public: ARMTargetInfo(const std::string &TripleStr) : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s") { + BigEndian = false; SizeType = UnsignedInt; PtrDiffType = SignedInt; // AAPCS 7.1.1, ARM-Linux ABI 2.4: type of wchar_t is unsigned int. @@ -2847,6 +2850,7 @@ class HexagonTargetInfo : public TargetInfo { std::string CPU; public: HexagonTargetInfo(const std::string& triple) : TargetInfo(triple) { + BigEndian = false; DescriptionString = ("e-p:32:32:32-" "i64:64:64-i32:32:32-" "i16:16:16-i1:32:32-a:0:0"); @@ -2976,6 +2980,7 @@ class SparcV8TargetInfo : public TargetInfo { public: SparcV8TargetInfo(const std::string& triple) : TargetInfo(triple) { // FIXME: Support Sparc quad-precision long double? + BigEndian = false; DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; } @@ -3105,6 +3110,7 @@ namespace { static const char * const GCCRegNames[]; public: MSP430TargetInfo(const std::string& triple) : TargetInfo(triple) { + BigEndian = false; TLSSupported = false; IntWidth = 16; IntAlign = 16; LongWidth = 32; LongLongWidth = 64; @@ -3399,6 +3405,7 @@ public: class Mips32ELTargetInfo : public Mips32TargetInfoBase { public: Mips32ELTargetInfo(const std::string& triple) : Mips32TargetInfoBase(triple) { + BigEndian = false; DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; } @@ -3530,7 +3537,8 @@ class Mips64ELTargetInfo : public Mips64TargetInfoBase { } public: Mips64ELTargetInfo(const std::string& triple) : Mips64TargetInfoBase(triple) { - // Default ABI is n64. + // Default ABI is n64. + BigEndian = false; DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-f128:128:128-" "v64:64:64-n32"; @@ -3551,6 +3559,7 @@ namespace { class PNaClTargetInfo : public TargetInfo { public: PNaClTargetInfo(const std::string& triple) : TargetInfo(triple) { + BigEndian = false; this->UserLabelPrefix = ""; this->LongAlign = 32; this->LongWidth = 32; diff --git a/clang/test/CodeGen/altivec.c b/clang/test/CodeGen/altivec.c index bd694a6a56de..29823031b56a 100644 --- a/clang/test/CodeGen/altivec.c +++ b/clang/test/CodeGen/altivec.c @@ -5,13 +5,13 @@ vector int test0 = (vector int)(1); // CHECK: @test0 = global <4 x i32> vector float test1 = (vector float)(1.0); // CHECK: @test1 = global <4 x float> -// CHECK: @v1 = global <16 x i8> bitcast (<4 x i32> to <16 x i8>) +// CHECK: @v1 = global <16 x i8> vector char v1 = (vector char)((vector int)(1, 2, 3, 4)); -// CHECK: @v2 = global <16 x i8> bitcast (<4 x float> to <16 x i8>) +// CHECK: @v2 = global <16 x i8> vector char v2 = (vector char)((vector float)(1.0f, 2.0f, 3.0f, 4.0f)); -// CHECK: @v3 = global <16 x i8> bitcast (<4 x i32> to <16 x i8>) +// CHECK: @v3 = global <16 x i8> vector char v3 = (vector char)((vector int)('a', 'b', 'c', 'd')); -// CHECK: @v4 = global <4 x i32> bitcast (<16 x i8> to <4 x i32>) +// CHECK: @v4 = global <4 x i32> vector int v4 = (vector char){1, 2, 3, 4}; void test2() diff --git a/clang/test/CodeGen/const-init.c b/clang/test/CodeGen/const-init.c index 9bc3bbafdeff..4f3f7ab55330 100644 --- a/clang/test/CodeGen/const-init.c +++ b/clang/test/CodeGen/const-init.c @@ -132,3 +132,15 @@ int g25() { void g27() { // PR8073 static void *x = &x; } + +void g28() { + typedef long long v1i64 __attribute((vector_size(8))); + typedef short v12i16 __attribute((vector_size(24))); + typedef long double v2f80 __attribute((vector_size(24))); + // CHECK: @g28.a = internal global <1 x i64> + // CHECK: @g28.b = internal global <12 x i16> + // CHECK: @g28.c = internal global <2 x x86_fp80> , align 32 + static v1i64 a = (v1i64)10LL; + static v12i16 b = (v2f80){1,2}; + static v2f80 c = (v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0}; +}