Skip to content

Commit de24d08

Browse files
[FuncSpec] Fix inconsistent treatment of global variables
There are a few inaccuracies with how FuncSpec handles global variables. When specialisation on non-const global variables is disabled (the default) the pass could nevertheless perform some specializations, e.g. on a constant GEP expression, or on a SSA variable, for which the Solver has determined it has the value of a global variable. When specialisation on non-const global variables is enabled, the pass would skip non-scalars, e.g. a global array, but this should be completely inconsequential, a pointer is a pointer. Reviewed By: SjoerdMeijer Differential Revision: https://reviews.llvm.org/D149476 Change-Id: Ic73051b2f8602587306760bf2ec552e5860f8d39
1 parent ef13308 commit de24d08

File tree

3 files changed

+88
-12
lines changed

3 files changed

+88
-12
lines changed

llvm/lib/Transforms/IPO/FunctionSpecialization.cpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#include "llvm/Analysis/TargetTransformInfo.h"
5454
#include "llvm/Analysis/ValueLattice.h"
5555
#include "llvm/Analysis/ValueLatticeUtils.h"
56+
#include "llvm/Analysis/ValueTracking.h"
5657
#include "llvm/IR/IntrinsicInst.h"
5758
#include "llvm/Transforms/Scalar/SCCP.h"
5859
#include "llvm/Transforms/Utils/Cloning.h"
@@ -732,22 +733,19 @@ Constant *FunctionSpecializer::getCandidateConstant(Value *V) {
732733
if (isa<PoisonValue>(V))
733734
return nullptr;
734735

735-
// TrackValueOfGlobalVariable only tracks scalar global variables.
736-
if (auto *GV = dyn_cast<GlobalVariable>(V)) {
737-
// Check if we want to specialize on the address of non-constant
738-
// global values.
739-
if (!GV->isConstant() && !SpecializeOnAddress)
740-
return nullptr;
741-
742-
if (!GV->getValueType()->isSingleValueType())
743-
return nullptr;
744-
}
745-
746736
// Select for possible specialisation values that are constants or
747737
// are deduced to be constants or constant ranges with a single element.
748738
Constant *C = dyn_cast<Constant>(V);
749739
if (!C)
750740
C = Solver.getConstantOrNull(V);
741+
742+
// Don't specialize on (anything derived from) the address of a non-constant
743+
// global variable, unless explicitly enabled.
744+
if (C && C->getType()->isPointerTy() && !C->isNullValue())
745+
if (auto *GV = dyn_cast<GlobalVariable>(getUnderlyingObject(C));
746+
GV && !(GV->isConstant() || SpecializeOnAddress))
747+
return nullptr;
748+
751749
return C;
752750
}
753751

llvm/test/Transforms/FunctionSpecialization/compiler-crash-promote-alloca.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
; while attempting to promote the alloca in `entry`.
55
; CHECK: bar.1
66

7-
@block = internal global [8 x i8] zeroinitializer, align 1
7+
@block = internal constant [8 x i8] zeroinitializer, align 1
88

99
define dso_local void @entry() {
1010
%1 = alloca i32, align 4
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
; RUN: opt -S --passes=ipsccp,deadargelim --force-specialization < %s | FileCheck %s --check-prefix=NO-GLOBALS
2+
; RUN: opt -S --passes=ipsccp,deadargelim --force-specialization --funcspec-on-address < %s | FileCheck %s --check-prefix=GLOBALS
3+
@G = global [10 x i32] zeroinitializer, align 4
4+
5+
define internal i32 @f(ptr %p) noinline {
6+
entry:
7+
%0 = load i32, ptr %p, align 4
8+
store i32 0, ptr %p, align 4
9+
ret i32 %0
10+
}
11+
12+
define internal i32 @g(i32 %x, i32 %y, ptr %p) noinline {
13+
entry:
14+
%cmp = icmp sgt i32 %x, %y
15+
br i1 %cmp, label %if.then, label %if.else
16+
17+
if.then:
18+
br label %if.end
19+
20+
if.else:
21+
br label %if.end
22+
23+
if.end:
24+
%x.addr.0 = phi i32 [ %x, %if.then ], [ 11, %if.else ]
25+
%p.addr.0 = phi ptr [ @G, %if.then ], [ %p, %if.else ]
26+
%call = call i32 @f(ptr %p.addr.0)
27+
%add = add nsw i32 %call, %x.addr.0
28+
ret i32 %add
29+
}
30+
31+
define i32 @h0(ptr %p) {
32+
entry:
33+
%call = call i32 @g(i32 2, i32 1, ptr %p)
34+
ret i32 %call
35+
}
36+
37+
define i32 @h1() {
38+
entry:
39+
%call = call i32 @f(ptr @G)
40+
ret i32 %call
41+
}
42+
43+
define i32 @h2() {
44+
entry:
45+
%call = call i32 @f(ptr getelementptr inbounds (i32, ptr @G, i64 1))
46+
ret i32 %call
47+
}
48+
49+
; Check if specialisation on the address of a non-const global variable
50+
; is not allowed, then it is not performed.
51+
52+
; NO-GLOBALS-LABEL: define internal i32 @g()
53+
; NO-GLOBALS: call i32 @f(ptr @G)
54+
55+
; NO-GLOBALS-LABEL: define i32 @h0(ptr %p)
56+
; NO-GLOBALS:call i32 @g()
57+
58+
; NO-GLOBALS-LABEL: define i32 @h1()
59+
; NO-GLOBALS: call i32 @f(ptr @G)
60+
61+
; NO-GLOBALS-LABEL: define i32 @h2()
62+
; NO-GLOBALS: call i32 @f(ptr getelementptr inbounds (i32, ptr @G, i64 1))
63+
64+
; Check if specialisation on the address of a non-const global variable
65+
; is allowed, then it is performed where possible.
66+
67+
; GLOBALS-LABEL: define internal i32 @g()
68+
; GLOBALS: call i32 @f.2()
69+
70+
; GLOBALS-LABEL: define i32 @h0(ptr %p)
71+
; GLOBALS: call i32 @g()
72+
73+
; GLOBALS-LABEL: define i32 @h1()
74+
; GLOBALS: call i32 @f.2()
75+
76+
; GLOBALS-LABEL: define i32 @h2()
77+
; GLOBALS: call i32 @f.1()
78+

0 commit comments

Comments
 (0)