From: Rafael Espindola Date: Sat, 24 Mar 2012 16:50:34 +0000 (+0000) Subject: Add back r153360 with a fix for enums that cover all the 32 bit values. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c3f8955d7da1019dbe16b0bdf3e49d2e08d988e9;p=clang Add back r153360 with a fix for enums that cover all the 32 bit values. Thanks to NAKAMURA Takumi for finding it! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153383 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 30e3e7ad2c..a9f87e67d4 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -860,6 +860,62 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue) { lvalue.getType(), lvalue.getTBAAInfo()); } +static bool hasBooleanRepresentation(QualType Ty) { + if (Ty->isBooleanType()) + return true; + + if (const EnumType *ET = Ty->getAs()) + return ET->getDecl()->getIntegerType()->isBooleanType(); + + return false; +} + +llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) { + const EnumType *ET = Ty->getAs(); + bool IsRegularCPlusPlusEnum = getLangOpts().CPlusPlus && ET && + !ET->getDecl()->isFixed(); + bool IsBool = hasBooleanRepresentation(Ty); + llvm::Type *LTy; + if (!IsBool && !IsRegularCPlusPlusEnum) + return NULL; + + llvm::APInt Min; + llvm::APInt End; + if (IsBool) { + Min = llvm::APInt(8, 0); + End = llvm::APInt(8, 2); + LTy = Int8Ty; + } else { + const EnumDecl *ED = ET->getDecl(); + LTy = ConvertTypeForMem(ED->getIntegerType()); + unsigned Bitwidth = LTy->getScalarSizeInBits(); + unsigned NumNegativeBits = ED->getNumNegativeBits(); + unsigned NumPositiveBits = ED->getNumPositiveBits(); + + if (NumNegativeBits) { + unsigned NumBits = std::max(NumNegativeBits, NumPositiveBits + 1); + assert(NumBits <= Bitwidth); + End = llvm::APInt(Bitwidth, 1) << (NumBits - 1); + Min = -End; + } else { + assert(NumPositiveBits <= Bitwidth); + End = llvm::APInt(Bitwidth, 1) << NumPositiveBits; + Min = llvm::APInt(Bitwidth, 0); + } + } + + if (End == Min) + return NULL; + + llvm::Value *LowAndHigh[2]; + LowAndHigh[0] = llvm::ConstantInt::get(LTy, Min); + LowAndHigh[1] = llvm::ConstantInt::get(LTy, End); + + llvm::LLVMContext &C = getLLVMContext(); + llvm::MDNode *Range = llvm::MDNode::get(C, LowAndHigh); + return Range; +} + llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, unsigned Alignment, QualType Ty, llvm::MDNode *TBAAInfo) { @@ -874,18 +930,16 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, if (Ty->isAtomicType()) Load->setAtomic(llvm::SequentiallyConsistent); - return EmitFromMemory(Load, Ty); -} + if (CGM.getCodeGenOpts().OptimizationLevel > 0) + if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty)) + Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo); -static bool isBooleanUnderlyingType(QualType Ty) { - if (const EnumType *ET = dyn_cast(Ty)) - return ET->getDecl()->getIntegerType()->isBooleanType(); - return false; + return EmitFromMemory(Load, Ty); } llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) { // Bool has a different representation in memory than in registers. - if (Ty->isBooleanType() || isBooleanUnderlyingType(Ty)) { + if (hasBooleanRepresentation(Ty)) { // This should really always be an i1, but sometimes it's already // an i8, and it's awkward to track those cases down. if (Value->getType()->isIntegerTy(1)) @@ -898,7 +952,7 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) { llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) { // Bool has a different representation in memory than in registers. - if (Ty->isBooleanType() || isBooleanUnderlyingType(Ty)) { + if (hasBooleanRepresentation(Ty)) { assert(Value->getType()->isIntegerTy(8) && "memory rep of bool not i8"); return Builder.CreateTrunc(Value, Builder.getInt1Ty(), "tobool"); } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index e0e6501b19..85cbd143d8 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2522,6 +2522,7 @@ public: unsigned AccuracyD = 1); private: + llvm::MDNode *getRangeForLoadFromType(QualType Ty); void EmitReturnOfRValue(RValue RV, QualType Ty); /// ExpandTypeFromArgs - Reconstruct a structure of type \arg Ty diff --git a/test/CodeGen/pr12251.c b/test/CodeGen/pr12251.c new file mode 100644 index 0000000000..a644bb79da --- /dev/null +++ b/test/CodeGen/pr12251.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 %s -emit-llvm -O1 -relaxed-aliasing -o - | FileCheck %s + +enum e1 {e1_a = -1 }; +enum e1 g1(enum e1 *x) { + return *x; +} + +// CHECK: define i32 @g1 +// CHECK: load i32* %x, align 4 +// CHECK-NOT: range +// CHECK: ret diff --git a/test/CodeGenCXX/pr12251.cpp b/test/CodeGenCXX/pr12251.cpp new file mode 100644 index 0000000000..7aca8ddccf --- /dev/null +++ b/test/CodeGenCXX/pr12251.cpp @@ -0,0 +1,139 @@ +// RUN: %clang_cc1 %s -emit-llvm -O1 -relaxed-aliasing -std=c++11 -o - | FileCheck %s + +bool f(bool *x) { + return *x; +} +// CHECK: define zeroext i1 @_Z1fPb +// CHECK: load i8* %{{.*}}, align 1, !range !0 + +enum e1 { }; +e1 g1(e1 *x) { + return *x; +} +// CHECK: define i32 @_Z2g1P2e1 +// CHECK: load i32* %x, align 4, !range !1 + +enum e2 { e2_a = 0 }; +e2 g2(e2 *x) { + return *x; +} +// CHECK: define i32 @_Z2g2P2e2 +// CHECK: load i32* %x, align 4, !range !1 + +enum e3 { e3_a = 16 }; +e3 g3(e3 *x) { + return *x; +} +// CHECK: define i32 @_Z2g3P2e3 +// CHECK: load i32* %x, align 4, !range !2 + +enum e4 { e4_a = -16}; +e4 g4(e4 *x) { + return *x; +} +// CHECK: define i32 @_Z2g4P2e4 +// CHECK: load i32* %x, align 4, !range !3 + +enum e5 { e5_a = -16, e5_b = 16}; +e5 g5(e5 *x) { + return *x; +} +// CHECK: define i32 @_Z2g5P2e5 +// CHECK: load i32* %x, align 4, !range !4 + +enum e6 { e6_a = -1 }; +e6 g6(e6 *x) { + return *x; +} +// CHECK: define i32 @_Z2g6P2e6 +// CHECK: load i32* %x, align 4, !range !5 + +enum e7 { e7_a = -16, e7_b = 2}; +e7 g7(e7 *x) { + return *x; +} +// CHECK: define i32 @_Z2g7P2e7 +// CHECK: load i32* %x, align 4, !range !3 + +enum e8 { e8_a = -17}; +e8 g8(e8 *x) { + return *x; +} +// CHECK: define i32 @_Z2g8P2e8 +// CHECK: load i32* %x, align 4, !range !4 + +enum e9 { e9_a = 17}; +e9 g9(e9 *x) { + return *x; +} +// CHECK: define i32 @_Z2g9P2e9 +// CHECK: load i32* %x, align 4, !range !2 + +enum e10 { e10_a = -16, e10_b = 32}; +e10 g10(e10 *x) { + return *x; +} +// CHECK: define i32 @_Z3g10P3e10 +// CHECK: load i32* %x, align 4, !range !6 + +enum e11 {e11_a = 4294967296 }; +enum e11 g11(enum e11 *x) { + return *x; +} +// CHECK: define i64 @_Z3g11P3e11 +// CHECK: load i64* %x, align {{[84]}}, !range !7 + +enum e12 {e12_a = 9223372036854775808U }; +enum e12 g12(enum e12 *x) { + return *x; +} +// CHECK: define i64 @_Z3g12P3e12 +// CHECK: load i64* %x, align {{[84]}} +// CHECK-NOT: range +// CHECK: ret + +enum e13 : char {e13_a = -1 }; +e13 g13(e13 *x) { + return *x; +} +// CHECK: define signext i8 @_Z3g13P3e13 +// CHECK: load i8* %x, align 1 +// CHECK-NOT: range +// CHECK: ret + +enum class e14 {e14_a = 1}; +e14 g14(e14 *x) { + return *x; +} +// CHECK: define i32 @_Z3g14P3e14 +// CHECK: load i32* %x, align 4 +// CHECK-NOT: range +// CHECK: ret + +enum e15 { e15_a = 2147483648 }; +e15 g15(e15 *x) { + return *x; +} +// CHECK: define i32 @_Z3g15P3e15 +// CHECK: load i32* %x, align 4 +// CHECK-NOT: range +// CHECK: ret + +enum e16 { e16_a = -2147483648 }; +e16 g16(e16 *x) { + return *x; +} +// CHECK: define i32 @_Z3g16P3e16q +// CHECK: load i32* %x, align 4 +// CHECK-NOT: range +// CHECK: ret + + +// CHECK: !0 = metadata !{i8 0, i8 2} +// CHECK: !1 = metadata !{i32 0, i32 1} +// CHECK: !2 = metadata !{i32 0, i32 32} +// CHECK: !3 = metadata !{i32 -16, i32 16} +// CHECK: !4 = metadata !{i32 -32, i32 32} +// CHECK: !5 = metadata !{i32 -1, i32 1} +// CHECK: !6 = metadata !{i32 -64, i32 64} +// CHECK: !7 = metadata !{i64 0, i64 8589934592}