Index: lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- lib/Target/ARM/ARMISelLowering.cpp +++ lib/Target/ARM/ARMISelLowering.cpp @@ -2962,10 +2962,16 @@ llvm_unreachable("bogus TLS model"); } -/// Return true if all users of V are within function F, looking through -/// ConstantExprs. -static bool allUsersAreInFunction(const Value *V, const Function *F) { - SmallVector Worklist; +// Tells if users of V do not prevent it from being promoted to constant pool, +// looking through ConstantExprs. +// This means: +// - all users of V are within function F; +// - all users of V are within some (any) function but it no larger than a pointer; +// - if V is constant array, it only has one use. +static bool usersAllowConstantPromotion(const Value *V, const Function *F, + bool IsCDAInit, unsigned InitSize) { + unsigned UsersCount = 0; + SmallVector Worklist; for (auto *U : V->users()) Worklist.push_back(U); while (!Worklist.empty()) { @@ -2976,28 +2982,15 @@ continue; } - auto *I = dyn_cast(U); - if (!I || I->getParent()->getParent() != F) - return false; - } - return true; -} - -/// Return true if all users of V are within some (any) function, looking through -/// ConstantExprs. In other words, are there any global constant users? -static bool allUsersAreInFunctions(const Value *V) { - SmallVector Worklist; - for (auto *U : V->users()) - Worklist.push_back(U); - while (!Worklist.empty()) { - auto *U = Worklist.pop_back_val(); - if (isa(U)) { - for (auto *UU : U->users()) - Worklist.push_back(UU); - continue; + if (isa(U)) { + auto *I = cast(U); + if (I->getParent()->getParent() != F && InitSize > 4) + return false; + ++UsersCount; + if (IsCDAInit && UsersCount > 1) + return false; } - - if (!isa(U)) + else return false; } return true; @@ -3081,11 +3074,14 @@ return SDValue(); // This is only valid if all users are in a single function OR it has users - // in multiple functions but it no larger than a pointer. We also check if - // GVar has constant (non-ConstantExpr) users. If so, it essentially has its - // address taken. - if (!allUsersAreInFunction(GVar, F) && - !(Size <= 4 && allUsersAreInFunctions(GVar))) + // in multiple functions but it no larger than a pointer. + // Constant arrays has an extra check to restrict promotion to arrays that + // only have one use. This prevents possible pointer accesses to different + // CP copies of the same promoted array, which may result in misbehaving + // code when such pointers are compared, substructed, etc. + // We also check if GVar has constant (non-ConstantExpr) users. If so, it + // essentially has its address taken. + if (!usersAllowConstantPromotion(GVar, F, CDAInit != nullptr, Size)) return SDValue(); // We're going to inline this global. Pad it out if needed. Index: test/CodeGen/ARM/constantpool-promote-dbg.ll =================================================================== --- test/CodeGen/ARM/constantpool-promote-dbg.ll +++ test/CodeGen/ARM/constantpool-promote-dbg.ll @@ -3,20 +3,20 @@ target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" target triple = "thumbv7m--linux-gnu" -@.str = private unnamed_addr constant [4 x i8] c"abc\00", align 1 +@.int = private unnamed_addr constant i32 777, align 4 ; CHECK-LABEL: fn1 -; CHECK: .str: +; CHECK: .int: define arm_aapcscc i8* @fn1() local_unnamed_addr #0 !dbg !8 { entry: - ret i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), !dbg !14 + ret i8* bitcast (i32* @.int to i8*), !dbg !14 } ; CHECK-LABEL: fn2 -; CHECK-NOT: .str: -define arm_aapcscc i8* @fn2() local_unnamed_addr #0 !dbg !15 { +; CHECK-NOT: .int: +define arm_aapcscc i16* @fn2() local_unnamed_addr #0 !dbg !15 { entry: - ret i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 1), !dbg !16 + ret i16* bitcast (i32* @.int to i16*), !dbg !16 } attributes #0 = { minsize norecurse nounwind optsize readnone "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="cortex-m3" "target-features"="+hwdiv,+soft-float,-crypto,-neon" "unsafe-fp-math"="false" "use-soft-float"="true" } Index: test/CodeGen/ARM/constantpool-promote.ll =================================================================== --- test/CodeGen/ARM/constantpool-promote.ll +++ test/CodeGen/ARM/constantpool-promote.ll @@ -1,5 +1,5 @@ -; RUN: llc -mtriple armv7--linux-gnueabihf -relocation-model=static < %s | FileCheck %s --check-prefixes=CHECK,CHECK-V7,CHECK-V7ARM -; RUN: llc -mtriple armv7--linux-gnueabihf -relocation-model=pic < %s | FileCheck %s --check-prefixes=CHECK,CHECK-V7,CHECK-V7ARM +; RUN: llc -mtriple armv7--linux-gnueabihf -relocation-model=static < %s | FileCheck %s --check-prefixes=CHECK,CHECK-V7,CHECK-V7ARM,CHECK-STATIC +; RUN: llc -mtriple armv7--linux-gnueabihf -relocation-model=pic < %s | FileCheck %s --check-prefixes=CHECK,CHECK-V7,CHECK-V7ARM,CHECK-PIC ; RUN: llc -mtriple armv7--linux-gnueabihf -relocation-model=ropi < %s | FileCheck %s --check-prefixes=CHECK,CHECK-V7,CHECK-V7ARM ; RUN: llc -mtriple armv7--linux-gnueabihf -relocation-model=rwpi < %s | FileCheck %s --check-prefixes=CHECK,CHECK-V7,CHECK-V7ARM ; RUN: llc -mtriple thumbv7--linux-gnueabihf -relocation-model=static < %s | FileCheck %s --check-prefixes=CHECK,CHECK-V7,CHECK-V7THUMB @@ -16,11 +16,14 @@ @.str2 = private unnamed_addr constant [27 x i8] c"this string is just right!\00", align 1 @.str3 = private unnamed_addr constant [26 x i8] c"this string is used twice\00", align 1 @.str4 = private unnamed_addr constant [29 x i8] c"same string in two functions\00", align 1 +@.str5 = private unnamed_addr constant [2 x i8] c"s\00", align 1 @.arr1 = private unnamed_addr constant [2 x i16] [i16 3, i16 4], align 2 @.arr2 = private unnamed_addr constant [2 x i16] [i16 7, i16 8], align 2 @.arr3 = private unnamed_addr constant [2 x i16*] [i16* null, i16* null], align 4 @.ptr = private unnamed_addr constant [2 x i16*] [i16* getelementptr inbounds ([2 x i16], [2 x i16]* @.arr2, i32 0, i32 0), i16* null], align 2 @.arr4 = private unnamed_addr constant [2 x i16] [i16 3, i16 4], align 16 +@.arr5 = private unnamed_addr constant [2 x i16] [i16 3, i16 4], align 2 +@.arr6 = private unnamed_addr constant [2 x i16] [i16 3, i16 4], align 2 @.zerosize = private unnamed_addr constant [0 x i16] zeroinitializer, align 4 ; CHECK-LABEL: @test1 @@ -53,9 +56,14 @@ ; CHECK-LABEL: @test4 -; CHECK: adr r{{.*}}, [[x:.*]] -; CHECK: [[x]]: -; CHECK: .asciz "this string is used twice\000\000" +; CHECK-STATIC: movw [[r:.*]], :lower16:[[x:.*]] +; CHECK-STATIC: movt [[r]], :upper16:[[x]] +; CHECK-PIC: ldr [[r1:.*]], [[x:.*]] +; CHECK-PIC: add [[r2:.*]], pc, [[r1]] +; CHECK-PIC: [[x]]: +; CHECK-NOT: adr r{{.*}}, [[x:.*]] +; CHECK-NOT: [[x]]: +; CHECK-NOT: .asciz "this string is used twice\000\000" define void @test4() #0 { tail call void @a(i8* getelementptr inbounds ([26 x i8], [26 x i8]* @.str3, i32 0, i32 0)) #2 tail call void @a(i8* getelementptr inbounds ([26 x i8], [26 x i8]* @.str3, i32 0, i32 0)) #2 @@ -90,7 +98,7 @@ ; CHECK: .short 3 ; CHECK: .short 4 define void @test6b() #0 { - tail call void @c(i16* getelementptr inbounds ([2 x i16], [2 x i16]* @.arr1, i32 0, i32 0)) #2 + tail call void @c(i16* getelementptr inbounds ([2 x i16], [2 x i16]* @.arr6, i32 0, i32 0)) #2 ret void } @@ -156,7 +164,7 @@ ; CHECK-V7: [[x]]: ; CHECK-V7: .asciz "s\000\000" define void @test10(i8* %a) local_unnamed_addr #0 { - call void @llvm.memmove.p0i8.p0i8.i32(i8* %a, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str, i32 0, i32 0), i32 1, i32 1, i1 false) + call void @llvm.memmove.p0i8.p0i8.i32(i8* %a, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str5, i32 0, i32 0), i32 1, i32 1, i1 false) ret void } @@ -174,7 +182,7 @@ ; CHECK-V7ARM: .short 3 ; CHECK-V7ARM: .short 4 define void @test11(i16* %a) local_unnamed_addr #0 { - call void @llvm.memmove.p0i16.p0i16.i32(i16* %a, i16* getelementptr inbounds ([2 x i16], [2 x i16]* @.arr1, i32 0, i32 0), i32 2, i32 2, i1 false) + call void @llvm.memmove.p0i16.p0i16.i32(i16* %a, i16* getelementptr inbounds ([2 x i16], [2 x i16]* @.arr5, i32 0, i32 0), i32 2, i32 2, i1 false) ret void }