aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Anderson <resistor@mac.com>2011-01-16 04:33:33 +0000
committerOwen Anderson <resistor@mac.com>2011-01-16 04:33:33 +0000
commit66f708f7e5f207d7a7ab259b70b5fd94795fb74c (patch)
tree613afbfede21288f10945502fa281c5ce80c2adf
parent156eb0a569a1ebac86ad8438645f690d8a3894c4 (diff)
Improve the safety of my globalopt enhancement by ensuring that the bitcast
of the stored value to the new store type is always. Also, add a testcase. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@123563 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Transforms/IPO/GlobalOpt.cpp34
-rw-r--r--test/Transforms/GlobalOpt/static-ctor-bitcast.ll59
2 files changed, 81 insertions, 12 deletions
diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp
index 8519fce7a3..bf04594344 100644
--- a/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/lib/Transforms/IPO/GlobalOpt.cpp
@@ -2358,21 +2358,31 @@ static bool EvaluateFunction(Function *F, Constant *&RetVal,
const Type *NewTy=cast<PointerType>(Ptr->getType())->getElementType();
- // A bitcast'd pointer implicitly points to the first field of a
- // struct. Insert implicity "gep @x, 0, 0, ..." until we get down
- // to the first concrete member.
- // FIXME: This could be extended to work for arrays as well.
- while (const StructType *STy = dyn_cast<StructType>(NewTy)) {
- NewTy = STy->getTypeAtIndex(0U);
+ // In order to push the bitcast onto the stored value, a bitcast
+ // from NewTy to Val's type must be legal. If it's not, we can try
+ // introspecting NewTy to find a legal conversion.
+ while (!Val->getType()->canLosslesslyBitCastTo(NewTy)) {
+ // If NewTy is a struct, we can convert the pointer to the struct
+ // into a pointer to its first member.
+ // FIXME: This could be extended to support arrays as well.
+ if (const StructType *STy = dyn_cast<StructType>(NewTy)) {
+ NewTy = STy->getTypeAtIndex(0U);
+
+ const IntegerType *IdxTy =IntegerType::get(NewTy->getContext(), 32);
+ Constant *IdxZero = ConstantInt::get(IdxTy, 0, false);
+ Constant * const IdxList[] = {IdxZero, IdxZero};
+
+ Ptr = ConstantExpr::getGetElementPtr(Ptr, IdxList, 2);
- const IntegerType *IdxTy =IntegerType::get(NewTy->getContext(), 32);
- Constant *IdxZero = ConstantInt::get(IdxTy, 0, false);
- Constant * const IdxList[] = {IdxZero, IdxZero};
-
- Ptr = ConstantExpr::getGetElementPtr(Ptr, IdxList, 2);
+ // If we can't improve the situation by introspecting NewTy,
+ // we have to give up.
+ } else {
+ return 0;
+ }
}
- if (!isa<PointerType>(NewTy)) return false;
+ // If we found compatible types, go ahead and push the bitcast
+ // onto the stored value.
Val = ConstantExpr::getBitCast(Val, NewTy);
}
diff --git a/test/Transforms/GlobalOpt/static-ctor-bitcast.ll b/test/Transforms/GlobalOpt/static-ctor-bitcast.ll
new file mode 100644
index 0000000000..c988eea8a3
--- /dev/null
+++ b/test/Transforms/GlobalOpt/static-ctor-bitcast.ll
@@ -0,0 +1,59 @@
+; RUN: opt -S -globalopt < %s | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
+target triple = "x86_64-apple-darwin10.0.0"
+
+%0 = type { i8*, i8* }
+%1 = type { i8*, i8*, i32, i32, i8*, i64 }
+%2 = type { i32, void ()* }
+%struct.A = type { i32 }
+%struct.B = type { i32 (...)**, i8*, [4 x i8] }
+
+@y = global i8 0, align 1
+@x = global %struct.B zeroinitializer, align 8
+@_ZTV1B = weak_odr unnamed_addr constant [3 x i8*] [i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast (%1* @_ZTI1B to i8*)]
+@_ZTVN10__cxxabiv121__vmi_class_type_infoE = external global i8*
+@_ZTS1B = weak_odr constant [3 x i8] c"1B\00"
+@_ZTVN10__cxxabiv117__class_type_infoE = external global i8*
+@_ZTS1A = weak_odr constant [3 x i8] c"1A\00"
+@_ZTI1A = weak_odr unnamed_addr constant %0 { i8* bitcast (i8** getelementptr inbounds (i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8]* @_ZTS1A, i32 0, i32 0) }
+@_ZTI1B = weak_odr unnamed_addr constant %1 { i8* bitcast (i8** getelementptr inbounds (i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8]* @_ZTS1B, i32 0, i32 0), i32 0, i32 1, i8* bitcast (%0* @_ZTI1A to i8*), i64 -6141 }
+@_ZTT1B = weak_odr unnamed_addr constant [1 x i8*] [i8* bitcast (i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 1, i64 0) to i8*)]
+@llvm.global_ctors = appending global [1 x %2] [%2 { i32 65535, void ()* @_GLOBAL__I_a }]
+
+; CHECK-NOT: __cxx_global_var_init
+define internal void @__cxx_global_var_init() section "__TEXT,__StaticInit,regular,pure_instructions" {
+entry:
+ call void @_ZN1BC1Ev(%struct.B* @x)
+ ret void
+}
+
+; CHECK-NOT: _ZN1BC1Ev
+define linkonce_odr unnamed_addr void @_ZN1BC1Ev(%struct.B* %this) inlinehint ssp align 2 {
+entry:
+ %0 = bitcast %struct.B* %this to i8*
+ %1 = getelementptr inbounds i8* %0, i64 16
+ %2 = bitcast i8* %1 to %struct.A*
+ call void @_ZN1AC2Ev(%struct.A* %2)
+ %3 = bitcast %struct.B* %this to i8***
+ store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 1, i64 0), i8*** %3
+ ret void
+}
+
+; CHECK-NOT: _ZN1AC2Ev
+define linkonce_odr unnamed_addr void @_ZN1AC2Ev(%struct.A* %this) nounwind ssp align 2 {
+entry:
+ %0 = ptrtoint %struct.A* %this to i64
+ %sub = sub i64 %0, ptrtoint (%struct.B* @x to i64)
+ %div = udiv i64 %sub, 8
+ %conv = trunc i64 %div to i8
+ store i8 %conv, i8* @y, align 1
+ ret void
+}
+
+; CHECK-NOT: _GLOBAL__I_a
+define internal void @_GLOBAL__I_a() section "__TEXT,__StaticInit,regular,pure_instructions" {
+entry:
+ call void @__cxx_global_var_init()
+ ret void
+}