зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
88a569a978
Коммит
c3f8955d7d
|
@ -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<EnumType>())
|
||||
return ET->getDecl()->getIntegerType()->isBooleanType();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
|
||||
const EnumType *ET = Ty->getAs<EnumType>();
|
||||
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<EnumType>(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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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}
|
Загрузка…
Ссылка в новой задаче