@@ -24,6 +24,13 @@ type sideEffectResult struct {
24
24
// returns whether this function has side effects and if it does, which globals
25
25
// it mentions anywhere in this function or any called functions.
26
26
func (e * Eval ) hasSideEffects (fn llvm.Value ) * sideEffectResult {
27
+ switch fn .Name () {
28
+ case "runtime.alloc" :
29
+ // Cannot be scanned but can be interpreted.
30
+ return & sideEffectResult {severity : sideEffectNone }
31
+ case "runtime._panic" :
32
+ return & sideEffectResult {severity : sideEffectLimited }
33
+ }
27
34
if e .sideEffectFuncs == nil {
28
35
e .sideEffectFuncs = make (map [llvm.Value ]* sideEffectResult )
29
36
}
@@ -73,25 +80,32 @@ func (e *Eval) hasSideEffects(fn llvm.Value) *sideEffectResult {
73
80
result .updateSeverity (sideEffectAll )
74
81
continue
75
82
}
76
- name := child .Name ()
77
83
if child .IsDeclaration () {
78
- if name == "runtime.makeInterface" {
84
+ switch child .Name () {
85
+ case "runtime.makeInterface" :
79
86
// Can be interpreted so does not have side effects.
80
87
continue
81
88
}
82
89
// External function call. Assume only limited side effects
83
90
// (no affected globals, etc.).
84
- if result .hasLocalSideEffects (dirtyLocals , inst ) {
91
+ if e .hasLocalSideEffects (dirtyLocals , inst ) {
85
92
result .updateSeverity (sideEffectLimited )
86
93
}
87
94
continue
88
95
}
89
- childSideEffects := e .hasSideEffects (fn )
96
+ childSideEffects := e .hasSideEffects (child )
90
97
switch childSideEffects .severity {
91
98
case sideEffectInProgress , sideEffectNone :
92
99
// no side effects or recursive function - continue scanning
100
+ case sideEffectLimited :
101
+ // The return value may be problematic.
102
+ if e .hasLocalSideEffects (dirtyLocals , inst ) {
103
+ result .updateSeverity (sideEffectLimited )
104
+ }
105
+ case sideEffectAll :
106
+ result .updateSeverity (sideEffectAll )
93
107
default :
94
- result . update ( childSideEffects )
108
+ panic ( "unreachable" )
95
109
}
96
110
case llvm .Load , llvm .Store :
97
111
if inst .IsVolatile () {
@@ -118,7 +132,7 @@ func (e *Eval) hasSideEffects(fn llvm.Value) *sideEffectResult {
118
132
// hasLocalSideEffects checks whether the given instruction flows into a branch
119
133
// or return instruction, in which case the whole function must be marked as
120
134
// having side effects and be called at runtime.
121
- func (r * sideEffectResult ) hasLocalSideEffects (dirtyLocals map [llvm.Value ]struct {}, inst llvm.Value ) bool {
135
+ func (e * Eval ) hasLocalSideEffects (dirtyLocals map [llvm.Value ]struct {}, inst llvm.Value ) bool {
122
136
if _ , ok := dirtyLocals [inst ]; ok {
123
137
// It is already known that this local is dirty.
124
138
return true
@@ -156,7 +170,7 @@ func (r *sideEffectResult) hasLocalSideEffects(dirtyLocals map[llvm.Value]struct
156
170
// For a list:
157
171
// https://godoc.org/github.com/llvm-mirror/llvm/bindings/go/llvm#Opcode
158
172
dirtyLocals [user ] = struct {}{}
159
- if r .hasLocalSideEffects (dirtyLocals , user ) {
173
+ if e .hasLocalSideEffects (dirtyLocals , user ) {
160
174
return true
161
175
}
162
176
}
0 commit comments