1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2018-2020. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20%% This pass infers types from expressions and attempts to simplify or remove 21%% subsequent instructions based on that information. 22%% 23%% This is divided into two subpasses; the first figures out function type 24%% signatures for the whole module without optimizing anything, and the second 25%% optimizes based on that information, further refining the type signatures as 26%% it goes. 27%% 28 29-module(beam_ssa_type). 30-export([opt_start/2, opt_continue/4, opt_finish/3]). 31 32-include("beam_ssa_opt.hrl"). 33-include("beam_types.hrl"). 34 35-import(lists, [all/2,any/2,duplicate/2,foldl/3,member/2, 36 keyfind/3,reverse/1,split/2,zip/2]). 37 38%% The maximum number of #b_ret{} terminators a function can have before 39%% collapsing success types into a single entry. Consider the following code: 40%% 41%% f(0) -> 1; 42%% f(...) -> ...; 43%% f(500000) -> 500000. 44%% 45%% Since success types are grouped by return type and each clause returns a 46%% distinct type (singleton #t_integer{}s), we'll add 500000 entries which 47%% makes progress glacial since every call needs to examine them all to 48%% determine the return type. 49%% 50%% The entries are collapsed unconditionally if the number of returns in a 51%% function exceeds this threshold. This is necessary because collapsing as we 52%% go might widen a type; if we're at (?RETURN_LIMIT - 1) entries and suddenly 53%% narrow a type down, it could push us over the edge and collapse all entries, 54%% possibly widening the return type and breaking optimizations that were based 55%% on the earlier (narrower) types. 56-define(RETURN_LIMIT, 30). 57 58%% Constants common to all subpasses. 59-record(metadata, 60 { func_id :: func_id(), 61 limit_return :: boolean(), 62 params :: [beam_ssa:b_var()], 63 used_once :: cerl_sets:set(beam_ssa:b_var()) }). 64 65-type type_db() :: #{ beam_ssa:var_name() := type() }. 66 67%% 68 69-spec opt_start(term(), term()) -> term(). 70opt_start(StMap, FuncDb0) when FuncDb0 =/= #{} -> 71 {ArgDb, FuncDb} = signatures(StMap, FuncDb0), 72 73 opt_start_1(maps:keys(StMap), ArgDb, StMap, FuncDb); 74opt_start(StMap, FuncDb) -> 75 %% Module-level analysis is disabled, likely because of a call to 76 %% load_nif/2 or similar. opt_continue/4 will assume that all arguments and 77 %% return types are 'any'. 78 {StMap, FuncDb}. 79 80opt_start_1([Id | Ids], ArgDb, StMap0, FuncDb0) -> 81 case ArgDb of 82 #{ Id := ArgTypes } -> 83 #opt_st{ssa=Linear0,args=Args} = St0 = map_get(Id, StMap0), 84 85 Ts = maps:from_list(zip(Args, ArgTypes)), 86 {Linear, FuncDb} = opt_function(Linear0, Args, Id, Ts, FuncDb0), 87 88 St = St0#opt_st{ssa=Linear}, 89 StMap = StMap0#{ Id := St }, 90 91 opt_start_1(Ids, ArgDb, StMap, FuncDb); 92 #{} -> 93 %% Unreachable functions must be removed so that opt_continue/4 94 %% won't process them and potentially taint the argument types of 95 %% other functions. 96 StMap = maps:remove(Id, StMap0), 97 FuncDb = maps:remove(Id, FuncDb0), 98 99 opt_start_1(Ids, ArgDb, StMap, FuncDb) 100 end; 101opt_start_1([], _CommittedArgs, StMap, FuncDb) -> 102 {StMap, FuncDb}. 103 104%% 105%% The initial signature analysis is based on the paper "Practical Type 106%% Inference Based on Success Typings" [1] by `Tobias Lindahl` and 107%% `Konstantinos Sagonas`, mainly section 6.1 and onwards. 108%% 109%% The general idea is to start out at the module's entry points and propagate 110%% types to the functions we call. The argument types of all exported functions 111%% start out a 'any', whereas local functions start at 'none'. Every time a 112%% function call widens the argument types, we analyze the callee again and 113%% propagate its return types to the callers, analyzing them again, and 114%% continuing this process until all arguments and return types have been 115%% widened as far as they can be. 116%% 117%% Note that we do not "jump-start the analysis" by first determining success 118%% types as in the paper because we need to know all possible inputs including 119%% those that will not return. 120%% 121%% [1] http://www.it.uu.se/research/group/hipe/papers/succ_types.pdf 122%% 123 124-record(sig_st, 125 { wl = wl_new() :: worklist(), 126 committed = #{} :: #{ func_id() => [type()] }, 127 updates = #{} :: #{ func_id() => [type()] }}). 128 129signatures(StMap, FuncDb0) -> 130 State0 = init_sig_st(StMap, FuncDb0), 131 {State, FuncDb} = signatures_1(StMap, FuncDb0, State0), 132 {State#sig_st.committed, FuncDb}. 133 134signatures_1(StMap, FuncDb0, State0) -> 135 case wl_next(State0#sig_st.wl) of 136 {ok, FuncId} -> 137 {State, FuncDb} = sig_function(FuncId, StMap, State0, FuncDb0), 138 signatures_1(StMap, FuncDb, State); 139 empty -> 140 %% No more work to do, assert that we don't have any outstanding 141 %% updates. 142 #sig_st{updates=Same,committed=Same} = State0, %Assertion. 143 144 {State0, FuncDb0} 145 end. 146 147sig_function(Id, StMap, State0, FuncDb0) -> 148 case sig_function_1(Id, StMap, State0, FuncDb0) of 149 {false, false, State, FuncDb} -> 150 %% No added work and the types are identical. Pop ourselves from 151 %% the work list and move on to the next function. 152 Wl = wl_pop(Id, State#sig_st.wl), 153 {State#sig_st{wl=Wl}, FuncDb}; 154 {false, true, State, FuncDb} -> 155 %% We've added some work and our return type is unchanged. Keep 156 %% following the work list without popping ourselves; we're very 157 %% likely to need to return here later and can avoid a lot of 158 %% redundant work by keeping our place in line. 159 {State, FuncDb}; 160 {true, WlChanged, State, FuncDb} -> 161 %% Our return type has changed so all of our (previously analyzed) 162 %% callers need to be analyzed again. 163 %% 164 %% If our worklist is unchanged we'll pop ourselves since our 165 %% callers will add us back if we need to analyzed again, and 166 %% it's wasteful to stay in the worklist when we don't. 167 Wl0 = case WlChanged of 168 true -> State#sig_st.wl; 169 false -> wl_pop(Id, State#sig_st.wl) 170 end, 171 172 #func_info{in=Cs0} = map_get(Id, FuncDb0), 173 Callers = [C || C <- Cs0, is_map_key(C, State#sig_st.updates)], 174 Wl = wl_defer_list(Callers, Wl0), 175 176 {State#sig_st{wl=Wl}, FuncDb} 177 end. 178 179sig_function_1(Id, StMap, State0, FuncDb) -> 180 #opt_st{ssa=Linear,args=Args} = map_get(Id, StMap), 181 182 {ArgTypes, State1} = sig_commit_args(Id, State0), 183 Ts = maps:from_list(zip(Args, ArgTypes)), 184 185 FakeCall = #b_set{op=call,args=[#b_remote{mod=#b_literal{val=unknown}, 186 name=#b_literal{val=unknown}, 187 arity=0}]}, 188 189 Ds = maps:from_list([{Var, FakeCall#b_set{dst=Var}} || 190 #b_var{}=Var <- Args]), 191 192 Ls = #{ ?EXCEPTION_BLOCK => {incoming, Ts}, 193 0 => {incoming, Ts} }, 194 195 Meta = init_metadata(Id, Linear, Args), 196 197 Wl0 = State1#sig_st.wl, 198 199 {State, SuccTypes} = sig_bs(Linear, Ds, Ls, FuncDb, #{}, [], Meta, State1), 200 201 WlChanged = wl_changed(Wl0, State#sig_st.wl), 202 #{ Id := #func_info{succ_types=SuccTypes0}=Entry0 } = FuncDb, 203 204 if 205 SuccTypes0 =:= SuccTypes -> 206 {false, WlChanged, State, FuncDb}; 207 SuccTypes0 =/= SuccTypes -> 208 Entry = Entry0#func_info{succ_types=SuccTypes}, 209 {true, WlChanged, State, FuncDb#{ Id := Entry }} 210 end. 211 212sig_bs([{L, #b_blk{is=Is,last=Last0}} | Bs], 213 Ds0, Ls0, Fdb, Sub0, SuccTypes0, Meta, State0) -> 214 case Ls0 of 215 #{ L := Incoming } -> 216 {incoming, Ts0} = Incoming, %Assertion. 217 218 {Ts, Ds, Sub, State} = 219 sig_is(Is, Ts0, Ds0, Ls0, Fdb, Sub0, State0), 220 221 Last = simplify_terminator(Last0, Ts, Ds, Sub), 222 SuccTypes = update_success_types(Last, Ts, Ds, Meta, SuccTypes0), 223 224 UsedOnce = Meta#metadata.used_once, 225 {_, Ls1} = update_successors(Last, Ts, Ds, Ls0, UsedOnce), 226 227 %% In the future there may be a point to storing outgoing types on 228 %% a per-edge basis as it would give us more precision in phi 229 %% nodes, but there's nothing to gain from that at the moment so 230 %% we'll store the current Ts to save memory. 231 Ls = Ls1#{ L := {outgoing, Ts} }, 232 sig_bs(Bs, Ds, Ls, Fdb, Sub, SuccTypes, Meta, State); 233 #{} -> 234 %% This block is never reached. Ignore it. 235 sig_bs(Bs, Ds0, Ls0, Fdb, Sub0, SuccTypes0, Meta, State0) 236 end; 237sig_bs([], _Ds, _Ls, _Fdb, _Sub, SuccTypes, _Meta, State) -> 238 {State, SuccTypes}. 239 240sig_is([#b_set{op=call, 241 args=[#b_local{}=Callee | _]=Args0, 242 dst=Dst}=I0 | Is], 243 Ts0, Ds0, Ls, Fdb, Sub, State0) -> 244 Args = simplify_args(Args0, Ts0, Sub), 245 I1 = beam_ssa:normalize(I0#b_set{args=Args}), 246 247 [_ | CallArgs] = Args, 248 {I, State} = sig_local_call(I1, Callee, CallArgs, Ts0, Fdb, State0), 249 250 Ts = update_types(I, Ts0, Ds0), 251 Ds = Ds0#{ Dst => I }, 252 sig_is(Is, Ts, Ds, Ls, Fdb, Sub, State); 253sig_is([#b_set{op=call, 254 args=[#b_var{} | _]=Args0, 255 dst=Dst}=I0 | Is], 256 Ts0, Ds0, Ls, Fdb, Sub, State) -> 257 Args = simplify_args(Args0, Ts0, Sub), 258 I1 = beam_ssa:normalize(I0#b_set{args=Args}), 259 260 [Fun | _] = Args, 261 I = case normalized_type(Fun, Ts0) of 262 #t_fun{type=Type} -> beam_ssa:add_anno(result_type, Type, I1); 263 _ -> I1 264 end, 265 266 Ts = update_types(I, Ts0, Ds0), 267 Ds = Ds0#{ Dst => I }, 268 sig_is(Is, Ts, Ds, Ls, Fdb, Sub, State); 269sig_is([#b_set{op=make_fun,args=Args0,dst=Dst}=I0|Is], 270 Ts0, Ds0, Ls, Fdb, Sub0, State0) -> 271 Args = simplify_args(Args0, Ts0, Sub0), 272 I1 = beam_ssa:normalize(I0#b_set{args=Args}), 273 274 {I, State} = sig_make_fun(I1, Ts0, Fdb, State0), 275 276 Ts = update_types(I, Ts0, Ds0), 277 Ds = Ds0#{ Dst => I }, 278 sig_is(Is, Ts, Ds, Ls, Fdb, Sub0, State); 279sig_is([I0 | Is], Ts0, Ds0, Ls, Fdb, Sub0, State) -> 280 case simplify(I0, Ts0, Ds0, Ls, Sub0) of 281 {#b_set{}, Ts, Ds} -> 282 sig_is(Is, Ts, Ds, Ls, Fdb, Sub0, State); 283 Sub when is_map(Sub) -> 284 sig_is(Is, Ts0, Ds0, Ls, Fdb, Sub, State) 285 end; 286sig_is([], Ts, Ds, _Ls, _Fdb, Sub, State) -> 287 {Ts, Ds, Sub, State}. 288 289sig_local_call(I0, Callee, Args, Ts, Fdb, State) -> 290 ArgTypes = argument_types(Args, Ts), 291 I = sig_local_return(I0, Callee, ArgTypes, Fdb), 292 {I, sig_update_args(Callee, ArgTypes, State)}. 293 294%% While it's impossible to tell which arguments a fun will be called with 295%% (someone could steal it through tracing and call it), we do know its free 296%% variables and can update their types as if this were a local call. 297sig_make_fun(#b_set{op=make_fun, 298 args=[#b_local{}=Callee | FreeVars]}=I0, 299 Ts, Fdb, State) -> 300 ArgCount = Callee#b_local.arity - length(FreeVars), 301 302 FVTypes = [raw_type(FreeVar, Ts) || FreeVar <- FreeVars], 303 ArgTypes = duplicate(ArgCount, any) ++ FVTypes, 304 305 I = sig_local_return(I0, Callee, ArgTypes, Fdb), 306 {I, sig_update_args(Callee, ArgTypes, State)}. 307 308sig_local_return(I, Callee, ArgTypes, Fdb) -> 309 #func_info{succ_types=SuccTypes} = map_get(Callee, Fdb), 310 case return_type(SuccTypes, ArgTypes) of 311 any -> I; 312 Type -> beam_ssa:add_anno(result_type, Type, I) 313 end. 314 315init_sig_st(StMap, FuncDb) -> 316 %% Start out as if all the roots have been called with 'any' for all 317 %% arguments. 318 Roots = init_sig_roots(FuncDb), 319 #sig_st{ committed=#{}, 320 updates=init_sig_args(Roots, StMap, #{}), 321 wl=wl_defer_list(Roots, wl_new()) }. 322 323init_sig_roots(FuncDb) -> 324 maps:fold(fun(Id, #func_info{exported=true}, Acc) -> 325 [Id | Acc]; 326 (_, _, Acc) -> 327 Acc 328 end, [], FuncDb). 329 330init_sig_args([Root | Roots], StMap, Acc) -> 331 #opt_st{args=Args0} = map_get(Root, StMap), 332 ArgTypes = lists:duplicate(length(Args0), any), 333 init_sig_args(Roots, StMap, Acc#{ Root => ArgTypes }); 334init_sig_args([], _StMap, Acc) -> 335 Acc. 336 337sig_commit_args(Id, #sig_st{updates=Us,committed=Committed0}=State0) -> 338 Types = map_get(Id, Us), 339 Committed = Committed0#{ Id => Types }, 340 State = State0#sig_st{committed=Committed}, 341 {Types, State}. 342 343sig_update_args(Callee, Types, #sig_st{committed=Committed}=State) -> 344 case Committed of 345 #{ Callee := Current } -> 346 case parallel_join(Current, Types) of 347 Current -> 348 %% We've already processed this function with these 349 %% arguments, so there's no need to visit it again. 350 State; 351 Widened -> 352 sig_update_args_1(Callee, Widened, State) 353 end; 354 #{} -> 355 sig_update_args_1(Callee, Types, State) 356 end. 357 358sig_update_args_1(Callee, Types, #sig_st{updates=Us0,wl=Wl0}=State) -> 359 Us = case Us0 of 360 #{ Callee := Current } -> 361 Us0#{ Callee => parallel_join(Current, Types) }; 362 #{} -> 363 Us0#{ Callee => Types } 364 end, 365 State#sig_st{updates=Us,wl=wl_add(Callee, Wl0)}. 366 367-spec opt_continue(Linear, Args, Anno, FuncDb) -> {Linear, FuncDb} when 368 Linear :: [{non_neg_integer(), beam_ssa:b_blk()}], 369 Args :: [beam_ssa:b_var()], 370 Anno :: beam_ssa:anno(), 371 FuncDb :: func_info_db(). 372opt_continue(Linear0, Args, Anno, FuncDb) when FuncDb =/= #{} -> 373 Id = get_func_id(Anno), 374 case FuncDb of 375 #{ Id := #func_info{exported=false,arg_types=ArgTypes} } -> 376 %% This is a local function and we're guaranteed to have visited 377 %% every call site at least once, so we know that the parameter 378 %% types are at least as narrow as the join of all argument types. 379 Ts = join_arg_types(Args, ArgTypes, #{}), 380 opt_function(Linear0, Args, Id, Ts, FuncDb); 381 #{ Id := #func_info{exported=true} } -> 382 %% We can't infer the parameter types of exported functions, but 383 %% running the pass again could still help other functions. 384 Ts = maps:from_list([{V,any} || #b_var{}=V <- Args]), 385 opt_function(Linear0, Args, Id, Ts, FuncDb) 386 end; 387opt_continue(Linear0, Args, Anno, _FuncDb) -> 388 %% Module-level optimization is disabled, pass an empty function database 389 %% so we only perform local optimizations. 390 Id = get_func_id(Anno), 391 Ts = maps:from_list([{V,any} || #b_var{}=V <- Args]), 392 {Linear, _} = opt_function(Linear0, Args, Id, Ts, #{}), 393 {Linear, #{}}. 394 395join_arg_types([Arg | Args], [TypeMap | TMs], Ts) -> 396 Type = beam_types:join(maps:values(TypeMap)), 397 join_arg_types(Args, TMs, Ts#{ Arg => Type }); 398join_arg_types([], [], Ts) -> 399 Ts. 400 401%% 402%% Optimizes a function based on the type information inferred by signatures/2 403%% and earlier runs of opt_function/5. 404%% 405%% This is pretty straightforward as it only walks through each function once, 406%% and because it only makes types narrower it's safe to optimize the functions 407%% in any order or not at all. 408%% 409 410-spec opt_function(Linear, Args, Id, Ts, FuncDb) -> Result when 411 Linear :: [{non_neg_integer(), beam_ssa:b_blk()}], 412 Args :: [beam_ssa:b_var()], 413 Id :: func_id(), 414 Ts :: type_db(), 415 FuncDb :: func_info_db(), 416 Result :: {Linear, FuncDb}. 417opt_function(Linear0, Args, Id, Ts, FuncDb0) -> 418 FakeCall = #b_set{op=call,args=[#b_remote{mod=#b_literal{val=unknown}, 419 name=#b_literal{val=unknown}, 420 arity=0}]}, 421 422 Ds = maps:from_list([{Var, FakeCall#b_set{dst=Var}} || 423 #b_var{}=Var <- Args]), 424 425 Ls = #{ ?EXCEPTION_BLOCK => {incoming, Ts}, 426 0 => {incoming, Ts} }, 427 428 Meta = init_metadata(Id, Linear0, Args), 429 430 {Linear, FuncDb, SuccTypes} = 431 opt_bs(Linear0, Ds, Ls, FuncDb0, #{}, [], Meta, []), 432 433 case FuncDb of 434 #{ Id := Entry0 } -> 435 Entry = Entry0#func_info{succ_types=SuccTypes}, 436 {Linear, FuncDb#{ Id := Entry }}; 437 #{} -> 438 %% Module-level optimizations have been turned off. 439 {Linear, FuncDb} 440 end. 441 442get_func_id(Anno) -> 443 #{func_info:={_Mod, Name, Arity}} = Anno, 444 #b_local{name=#b_literal{val=Name}, arity=Arity}. 445 446opt_bs([{L, #b_blk{is=Is0,last=Last0}=Blk0} | Bs], 447 Ds0, Ls0, Fdb0, Sub0, SuccTypes0, Meta, Acc) -> 448 case Ls0 of 449 #{ L := Incoming } -> 450 {incoming, Ts0} = Incoming, %Assertion. 451 452 {Is, Ts, Ds, Fdb, Sub} = 453 opt_is(Is0, Ts0, Ds0, Ls0, Fdb0, Sub0, Meta, []), 454 455 Last1 = simplify_terminator(Last0, Ts, Ds, Sub), 456 SuccTypes = update_success_types(Last1, Ts, Ds, Meta, SuccTypes0), 457 458 UsedOnce = Meta#metadata.used_once, 459 {Last, Ls1} = update_successors(Last1, Ts, Ds, Ls0, UsedOnce), 460 461 Ls = Ls1#{ L := {outgoing, Ts} }, %Assertion. 462 463 Blk = Blk0#b_blk{is=Is,last=Last}, 464 opt_bs(Bs, Ds, Ls, Fdb, Sub, SuccTypes, Meta, [{L,Blk} | Acc]); 465 #{} -> 466 %% This block is never reached. Discard it. 467 opt_bs(Bs, Ds0, Ls0, Fdb0, Sub0, SuccTypes0, Meta, Acc) 468 end; 469opt_bs([], _Ds, _Ls, Fdb, _Sub, SuccTypes, _Meta, Acc) -> 470 {reverse(Acc), Fdb, SuccTypes}. 471 472opt_is([#b_set{op=call, 473 args=[#b_local{}=Callee | _]=Args0, 474 dst=Dst}=I0 | Is], 475 Ts0, Ds0, Ls, Fdb0, Sub, Meta, Acc) -> 476 Args = simplify_args(Args0, Ts0, Sub), 477 I1 = beam_ssa:normalize(I0#b_set{args=Args}), 478 479 [_ | CallArgs] = Args, 480 {I, Fdb} = opt_local_call(I1, Callee, CallArgs, Dst, Ts0, Fdb0, Meta), 481 482 Ts = update_types(I, Ts0, Ds0), 483 Ds = Ds0#{ Dst => I }, 484 opt_is(Is, Ts, Ds, Ls, Fdb, Sub, Meta, [I | Acc]); 485opt_is([#b_set{op=call, 486 args=[#b_var{} | _]=Args0, 487 dst=Dst}=I0 | Is], 488 Ts0, Ds0, Ls, Fdb, Sub, Meta, Acc) -> 489 Args = simplify_args(Args0, Ts0, Sub), 490 I1 = beam_ssa:normalize(I0#b_set{args=Args}), 491 492 [Fun | _] = Args, 493 I = case normalized_type(Fun, Ts0) of 494 #t_fun{type=Type} when Type =/= any -> 495 beam_ssa:add_anno(result_type, Type, I1); 496 _ -> 497 I1 498 end, 499 500 Ts = update_types(I, Ts0, Ds0), 501 Ds = Ds0#{ Dst => I }, 502 opt_is(Is, Ts, Ds, Ls, Fdb, Sub, Meta, [I | Acc]); 503opt_is([#b_set{op=make_fun,args=Args0,dst=Dst}=I0|Is], 504 Ts0, Ds0, Ls, Fdb0, Sub0, Meta, Acc) -> 505 Args = simplify_args(Args0, Ts0, Sub0), 506 I1 = beam_ssa:normalize(I0#b_set{args=Args}), 507 508 {I, Fdb} = opt_make_fun(I1, Ts0, Fdb0, Meta), 509 510 Ts = update_types(I, Ts0, Ds0), 511 Ds = Ds0#{ Dst => I }, 512 opt_is(Is, Ts, Ds, Ls, Fdb, Sub0, Meta, [I|Acc]); 513opt_is([I0 | Is], Ts0, Ds0, Ls, Fdb, Sub0, Meta, Acc) -> 514 case simplify(I0, Ts0, Ds0, Ls, Sub0) of 515 {#b_set{}=I, Ts, Ds} -> 516 opt_is(Is, Ts, Ds, Ls, Fdb, Sub0, Meta, [I | Acc]); 517 Sub when is_map(Sub) -> 518 opt_is(Is, Ts0, Ds0, Ls, Fdb, Sub, Meta, Acc) 519 end; 520opt_is([], Ts, Ds, _Ls, Fdb, Sub, _Meta, Acc) -> 521 {reverse(Acc), Ts, Ds, Fdb, Sub}. 522 523opt_local_call(I0, Callee, Args, Dst, Ts, Fdb, Meta) -> 524 ArgTypes = argument_types(Args, Ts), 525 I = opt_local_return(I0, Callee, ArgTypes, Fdb), 526 case Fdb of 527 #{ Callee := #func_info{exported=false,arg_types=AT0}=Info0 } -> 528 %% Update the argument types of *this exact call*, the types 529 %% will be joined later when the callee is optimized. 530 CallId = {Meta#metadata.func_id, Dst}, 531 532 AT = update_arg_types(ArgTypes, AT0, CallId), 533 Info = Info0#func_info{arg_types=AT}, 534 535 {I, Fdb#{ Callee := Info }}; 536 #{} -> 537 %% We can't narrow the argument types of exported functions as they 538 %% can receive anything as part of an external call. We can still 539 %% rely on their return types however. 540 {I, Fdb} 541 end. 542 543%% See sig_make_fun/4 544opt_make_fun(#b_set{op=make_fun, 545 dst=Dst, 546 args=[#b_local{}=Callee | FreeVars]}=I0, 547 Ts, Fdb, Meta) -> 548 ArgCount = Callee#b_local.arity - length(FreeVars), 549 FVTypes = [raw_type(FreeVar, Ts) || FreeVar <- FreeVars], 550 ArgTypes = duplicate(ArgCount, any) ++ FVTypes, 551 552 I = opt_local_return(I0, Callee, ArgTypes, Fdb), 553 554 case Fdb of 555 #{ Callee := #func_info{exported=false,arg_types=AT0}=Info0 } -> 556 CallId = {Meta#metadata.func_id, Dst}, 557 558 AT = update_arg_types(ArgTypes, AT0, CallId), 559 Info = Info0#func_info{arg_types=AT}, 560 561 {I, Fdb#{ Callee := Info }}; 562 #{} -> 563 %% We can't narrow the argument types of exported functions as they 564 %% can receive anything as part of an external call. 565 {I, Fdb} 566 end. 567 568opt_local_return(I, Callee, ArgTypes, Fdb) when Fdb =/= #{} -> 569 #func_info{succ_types=SuccTypes} = map_get(Callee, Fdb), 570 case return_type(SuccTypes, ArgTypes) of 571 any -> I; 572 Type -> beam_ssa:add_anno(result_type, Type, I) 573 end; 574opt_local_return(I, _Callee, _ArgTyps, _Fdb) -> 575 %% Module-level optimization is disabled, assume it returns anything. 576 I. 577 578update_arg_types([ArgType | ArgTypes], [TypeMap0 | TypeMaps], CallId) -> 579 TypeMap = TypeMap0#{ CallId => ArgType }, 580 [TypeMap | update_arg_types(ArgTypes, TypeMaps, CallId)]; 581update_arg_types([], [], _CallId) -> 582 []. 583 584%% 585 586-spec opt_finish(Args, Anno, FuncDb) -> {Anno, FuncDb} when 587 Args :: [beam_ssa:b_var()], 588 Anno :: beam_ssa:anno(), 589 FuncDb :: func_info_db(). 590opt_finish(Args, Anno, FuncDb) -> 591 Id = get_func_id(Anno), 592 case FuncDb of 593 #{ Id := #func_info{exported=false,arg_types=ArgTypes} } -> 594 ParamInfo0 = maps:get(parameter_info, Anno, #{}), 595 ParamInfo = opt_finish_1(Args, ArgTypes, ParamInfo0), 596 {Anno#{ parameter_info => ParamInfo }, FuncDb}; 597 #{} -> 598 {Anno, FuncDb} 599 end. 600 601opt_finish_1([Arg | Args], [TypeMap | TypeMaps], Acc0) -> 602 case beam_types:join(maps:values(TypeMap)) of 603 any -> 604 opt_finish_1(Args, TypeMaps, Acc0); 605 JoinedType -> 606 Info = maps:get(Arg, Acc0, []), 607 Acc = Acc0#{ Arg => [{type, JoinedType} | Info] }, 608 opt_finish_1(Args, TypeMaps, Acc) 609 end; 610opt_finish_1([], [], Acc) -> 611 Acc. 612 613%%% 614%%% Optimization helpers 615%%% 616 617simplify_terminator(#b_br{bool=Bool}=Br0, Ts, Ds, Sub) -> 618 Br = beam_ssa:normalize(Br0#b_br{bool=simplify_arg(Bool, Ts, Sub)}), 619 simplify_not(Br, Ts, Ds, Sub); 620simplify_terminator(#b_switch{arg=Arg0,fail=Fail,list=List0}=Sw0, 621 Ts, Ds, Sub) -> 622 Arg = simplify_arg(Arg0, Ts, Sub), 623 %% Ensure that no label in the switch list is the same as the 624 %% failure label. 625 List = [{Val,Lbl} || {Val,Lbl} <- List0, Lbl =/= Fail], 626 case beam_ssa:normalize(Sw0#b_switch{arg=Arg,list=List}) of 627 #b_switch{}=Sw -> 628 case beam_types:is_boolean_type(raw_type(Arg, Ts)) of 629 true -> simplify_switch_bool(Sw, Ts, Ds, Sub); 630 false -> Sw 631 end; 632 #b_br{}=Br -> 633 simplify_terminator(Br, Ts, Ds, Sub) 634 end; 635simplify_terminator(#b_ret{arg=Arg}=Ret, Ts, Ds, Sub) -> 636 %% Reducing the result of a call to a literal (fairly common for 'ok') 637 %% breaks tail call optimization. 638 case Ds of 639 #{ Arg := #b_set{op=call}} -> Ret; 640 #{} -> Ret#b_ret{arg=simplify_arg(Arg, Ts, Sub)} 641 end. 642 643%% 644%% Simplifies an instruction, returning either a new instruction (with updated 645%% type and definition maps), or an updated substitution map if the instruction 646%% was redundant. 647%% 648 649simplify(#b_set{op=phi,dst=Dst,args=Args0}=I0, Ts0, Ds0, Ls, Sub) -> 650 %% Simplify the phi node by removing all predecessor blocks that no 651 %% longer exists or no longer branches to this block. 652 {Type, Args} = simplify_phi_args(Args0, Ls, Sub, none, []), 653 case phi_all_same(Args) of 654 true -> 655 %% Eliminate the phi node if there is just one source 656 %% value or if the values are identical. 657 [{Val, _} | _] = Args, 658 Sub#{ Dst => Val }; 659 false -> 660 I = I0#b_set{args=Args}, 661 662 Ts = Ts0#{ Dst => Type }, 663 Ds = Ds0#{ Dst => I }, 664 {I, Ts, Ds} 665 end; 666simplify(#b_set{op={succeeded,Kind},args=[Arg],dst=Dst}=I0, 667 Ts0, Ds0, _Ls, Sub) -> 668 Type = case will_succeed(I0, Ts0, Ds0, Sub) of 669 yes -> beam_types:make_atom(true); 670 no -> beam_types:make_atom(false); 671 maybe -> beam_types:make_boolean() 672 end, 673 case Type of 674 #t_atom{elements=[true]} -> 675 %% The checked operation always succeeds, so it's safe to remove 676 %% this instruction regardless of whether we're in a guard or not. 677 Lit = #b_literal{val=true}, 678 Sub#{ Dst => Lit }; 679 #t_atom{elements=[false]} when Kind =:= guard -> 680 %% Failing operations are only safe to remove in guards. 681 Lit = #b_literal{val=false}, 682 Sub#{ Dst => Lit }; 683 _ -> 684 true = is_map_key(Arg, Ds0), %Assertion. 685 686 %% Note that we never simplify args; this instruction is specific 687 %% to the operation being checked, and simplifying could break that 688 %% connection. 689 I = beam_ssa:normalize(I0), 690 Ts = Ts0#{ Dst => Type }, 691 Ds = Ds0#{ Dst => I }, 692 {I, Ts, Ds} 693 end; 694simplify(#b_set{op=bs_match,dst=Dst,args=Args0}=I0, Ts0, Ds0, _Ls, Sub) -> 695 Args = simplify_args(Args0, Ts0, Sub), 696 I1 = beam_ssa:normalize(I0#b_set{args=Args}), 697 I2 = case {Args0,Args} of 698 {[_,_,_,#b_var{},_],[Type,Val,Flags,#b_literal{val=all},Unit]} -> 699 %% The size `all` is used for the size of the final binary 700 %% segment in a pattern. Using `all` explicitly is not allowed, 701 %% so we convert it to an obvious invalid size. 702 I1#b_set{args=[Type,Val,Flags,#b_literal{val=bad_size},Unit]}; 703 {_,_} -> 704 I1 705 end, 706 %% We KNOW that simplify/2 will return a #b_set{} record when called with 707 %% a bs_match instruction. 708 #b_set{} = I3 = simplify(I2, Ts0), 709 I = beam_ssa:normalize(I3), 710 Ts = update_types(I, Ts0, Ds0), 711 Ds = Ds0#{ Dst => I }, 712 {I, Ts, Ds}; 713simplify(#b_set{dst=Dst,args=Args0}=I0, Ts0, Ds0, _Ls, Sub) -> 714 Args = simplify_args(Args0, Ts0, Sub), 715 I1 = beam_ssa:normalize(I0#b_set{args=Args}), 716 case simplify(I1, Ts0) of 717 #b_set{}=I2 -> 718 I = beam_ssa:normalize(I2), 719 Ts = update_types(I, Ts0, Ds0), 720 Ds = Ds0#{ Dst => I }, 721 {I, Ts, Ds}; 722 #b_literal{}=Lit -> 723 Sub#{ Dst => Lit }; 724 #b_var{}=Var -> 725 Sub#{ Dst => Var } 726 end. 727 728simplify(#b_set{op={bif,'and'},args=Args}=I, Ts) -> 729 case is_safe_bool_op(Args, Ts) of 730 true -> 731 case Args of 732 [_,#b_literal{val=false}=Res] -> Res; 733 [Res,#b_literal{val=true}] -> Res; 734 _ -> eval_bif(I, Ts) 735 end; 736 false -> 737 I 738 end; 739simplify(#b_set{op={bif,'or'},args=Args}=I, Ts) -> 740 case is_safe_bool_op(Args, Ts) of 741 true -> 742 case Args of 743 [Res,#b_literal{val=false}] -> Res; 744 [_,#b_literal{val=true}=Res] -> Res; 745 _ -> eval_bif(I, Ts) 746 end; 747 false -> 748 I 749 end; 750simplify(#b_set{op={bif,element},args=[#b_literal{val=Index},Tuple]}=I0, Ts) -> 751 case normalized_type(Tuple, Ts) of 752 #t_tuple{size=Size} when is_integer(Index), 753 1 =< Index, 754 Index =< Size -> 755 I = I0#b_set{op=get_tuple_element, 756 args=[Tuple,#b_literal{val=Index-1}]}, 757 simplify(I, Ts); 758 _ -> 759 eval_bif(I0, Ts) 760 end; 761simplify(#b_set{op={bif,hd},args=[List]}=I, Ts) -> 762 case normalized_type(List, Ts) of 763 #t_cons{} -> 764 I#b_set{op=get_hd}; 765 _ -> 766 eval_bif(I, Ts) 767 end; 768simplify(#b_set{op={bif,tl},args=[List]}=I, Ts) -> 769 case normalized_type(List, Ts) of 770 #t_cons{} -> 771 I#b_set{op=get_tl}; 772 _ -> 773 eval_bif(I, Ts) 774 end; 775simplify(#b_set{op={bif,size},args=[Term]}=I, Ts) -> 776 case normalized_type(Term, Ts) of 777 #t_tuple{} -> 778 simplify(I#b_set{op={bif,tuple_size}}, Ts); 779 #t_bitstring{size_unit=U} when U rem 8 =:= 0 -> 780 %% If the bitstring is a binary (the size in bits is 781 %% evenly divisibly by 8), byte_size/1 gives 782 %% the same result as size/1. 783 simplify(I#b_set{op={bif,byte_size}}, Ts); 784 _ -> 785 eval_bif(I, Ts) 786 end; 787simplify(#b_set{op={bif,tuple_size},args=[Term]}=I, Ts) -> 788 case normalized_type(Term, Ts) of 789 #t_tuple{size=Size,exact=true} -> 790 #b_literal{val=Size}; 791 _ -> 792 I 793 end; 794simplify(#b_set{op={bif,is_function},args=[Fun,#b_literal{val=Arity}]}=I, Ts) 795 when is_integer(Arity), Arity >= 0 -> 796 case normalized_type(Fun, Ts) of 797 #t_fun{arity=any} -> 798 I; 799 #t_fun{arity=Arity} -> 800 #b_literal{val=true}; 801 any -> 802 I; 803 _ -> 804 #b_literal{val=false} 805 end; 806simplify(#b_set{op={bif,is_map_key},args=[Key,Map]}=I, Ts) -> 807 case normalized_type(Map, Ts) of 808 #t_map{} -> 809 I#b_set{op=has_map_field,args=[Map,Key]}; 810 _ -> 811 I 812 end; 813simplify(#b_set{op={bif,Op0},args=Args}=I, Ts) when Op0 =:= '=='; 814 Op0 =:= '/=' -> 815 Types = normalized_types(Args, Ts), 816 EqEq0 = case {beam_types:meet(Types),beam_types:join(Types)} of 817 {none,any} -> true; 818 {#t_integer{},#t_integer{}} -> true; 819 {#t_float{},#t_float{}} -> true; 820 {#t_bitstring{},_} -> true; 821 {#t_atom{},_} -> true; 822 {_,_} -> false 823 end, 824 EqEq = EqEq0 orelse any_non_numeric_argument(Args, Ts), 825 case EqEq of 826 true -> 827 Op = case Op0 of 828 '==' -> '=:='; 829 '/=' -> '=/=' 830 end, 831 simplify(I#b_set{op={bif,Op}}, Ts); 832 false -> 833 eval_bif(I, Ts) 834 end; 835simplify(#b_set{op={bif,'=:='},args=[Same,Same]}, _Ts) -> 836 #b_literal{val=true}; 837simplify(#b_set{op={bif,'=:='},args=[LHS,RHS]}=I, Ts) -> 838 LType = raw_type(LHS, Ts), 839 RType = raw_type(RHS, Ts), 840 case beam_types:meet(LType, RType) of 841 none -> 842 #b_literal{val=false}; 843 _ -> 844 case {beam_types:is_boolean_type(LType), 845 beam_types:normalize(RType)} of 846 {true,#t_atom{elements=[true]}} -> 847 %% Bool =:= true ==> Bool 848 LHS; 849 {true,#t_atom{elements=[false]}} -> 850 %% Bool =:= false ==> not Bool 851 %% 852 %% This will be further optimized to eliminate the 853 %% 'not', swapping the success and failure 854 %% branches in the br instruction. If LHS comes 855 %% from a type test (such as is_atom/1) or a 856 %% comparison operator (such as >=) that can be 857 %% translated to test instruction, this 858 %% optimization will eliminate one instruction. 859 simplify(I#b_set{op={bif,'not'},args=[LHS]}, Ts); 860 {_,_} -> 861 eval_bif(I, Ts) 862 end 863 end; 864simplify(#b_set{op={bif,Op},args=Args}=I, Ts) -> 865 Types = normalized_types(Args, Ts), 866 case is_float_op(Op, Types) of 867 false -> 868 eval_bif(I, Ts); 869 true -> 870 AnnoArgs = [anno_float_arg(A) || A <- Types], 871 eval_bif(beam_ssa:add_anno(float_op, AnnoArgs, I), Ts) 872 end; 873simplify(#b_set{op=bs_extract,args=[Ctx]}=I, Ts) -> 874 case raw_type(Ctx, Ts) of 875 #t_bitstring{} -> 876 %% This is a bs_match that has been rewritten as a bs_get_tail; 877 %% just return the input as-is. 878 Ctx; 879 #t_bs_context{} -> 880 I 881 end; 882simplify(#b_set{op=bs_match, 883 args=[#b_literal{val=binary}, Ctx, _Flags, 884 #b_literal{val=all}, 885 #b_literal{val=OpUnit}]}=I, Ts) -> 886 %% <<..., Foo/binary>> can be rewritten as <<..., Foo/bits>> if we know the 887 %% unit is correct. 888 #t_bs_context{tail_unit=CtxUnit} = raw_type(Ctx, Ts), 889 if 890 CtxUnit rem OpUnit =:= 0 -> 891 I#b_set{op=bs_get_tail,args=[Ctx]}; 892 CtxUnit rem OpUnit =/= 0 -> 893 I 894 end; 895simplify(#b_set{op=bs_start_match,args=[#b_literal{val=new}, Src]}=I, Ts) -> 896 case raw_type(Src, Ts) of 897 #t_bs_context{} -> 898 I#b_set{op=bs_start_match,args=[#b_literal{val=resume}, Src]}; 899 _ -> 900 I 901 end; 902simplify(#b_set{op=get_tuple_element,args=[Tuple,#b_literal{val=N}]}=I, Ts) -> 903 #t_tuple{size=Size,elements=Es} = normalized_type(Tuple, Ts), 904 true = Size > N, %Assertion. 905 ElemType = beam_types:get_tuple_element(N + 1, Es), 906 case beam_types:get_singleton_value(ElemType) of 907 {ok, Val} -> #b_literal{val=Val}; 908 error -> I 909 end; 910simplify(#b_set{op=is_nonempty_list,args=[Src]}=I, Ts) -> 911 case normalized_type(Src, Ts) of 912 any -> 913 I; 914 #t_list{} -> 915 I; 916 #t_cons{} -> 917 #b_literal{val=true}; 918 _ -> 919 #b_literal{val=false} 920 end; 921simplify(#b_set{op=is_tagged_tuple, 922 args=[Src,#b_literal{val=Size},#b_literal{}=Tag]}=I, Ts) -> 923 simplify_is_record(I, normalized_type(Src, Ts), Size, Tag, Ts); 924simplify(#b_set{op=put_list,args=[#b_literal{val=H}, 925 #b_literal{val=T}]}, _Ts) -> 926 #b_literal{val=[H|T]}; 927simplify(#b_set{op=put_tuple,args=Args}=I, _Ts) -> 928 case make_literal_list(Args) of 929 none -> I; 930 List -> #b_literal{val=list_to_tuple(List)} 931 end; 932simplify(#b_set{op=wait_timeout,args=[#b_literal{val=0}]}, _Ts) -> 933 #b_literal{val=true}; 934simplify(#b_set{op=call,args=[#b_remote{}=Rem|Args]}=I, _Ts) -> 935 case Rem of 936 #b_remote{mod=#b_literal{val=Mod}, 937 name=#b_literal{val=Name}} -> 938 case erl_bifs:is_pure(Mod, Name, length(Args)) of 939 true -> 940 simplify_remote_call(Mod, Name, Args, I); 941 false -> 942 I 943 end; 944 #b_remote{} -> 945 I 946 end; 947simplify(#b_set{op=call,args=[#b_literal{val=Fun}|Args]}=I, _Ts) 948 when is_function(Fun, length(Args)) -> 949 FI = erlang:fun_info(Fun), 950 {module,M} = keyfind(module, 1, FI), 951 {name,F} = keyfind(name, 1, FI), 952 {arity,A} = keyfind(arity, 1, FI), 953 Rem = #b_remote{mod=#b_literal{val=M}, 954 name=#b_literal{val=F}, 955 arity=A}, 956 I#b_set{args=[Rem|Args]}; 957simplify(I, _Ts) -> I. 958 959will_succeed(#b_set{args=[Src]}, Ts, Ds, Sub) -> 960 case {Ds, Ts} of 961 {#{}, #{ Src := none }} -> 962 %% Checked operation never returns. 963 no; 964 {#{ Src := I }, #{}} -> 965 will_succeed_1(I, Src, Ts, Sub); 966 {#{}, #{}} -> 967 %% The checked instruction has been removed and substituted, so we 968 %% can assume it always succeeds. 969 true = is_map_key(Src, Sub), %Assertion. 970 yes 971 end. 972 973will_succeed_1(#b_set{op=bs_get_tail}, _Src, _Ts, _Sub) -> 974 yes; 975will_succeed_1(#b_set{op=bs_start_match,args=[_, Arg]}, _Src, Ts, _Sub) -> 976 ArgType = raw_type(Arg, Ts), 977 case beam_types:is_bs_matchable_type(ArgType) of 978 true -> 979 %% In the future we may be able to remove this instruction 980 %% altogether when we have a #t_bs_context{}, but for now we need 981 %% to keep it for compatibility with older releases of OTP. 982 yes; 983 false -> 984 %% Is it at all possible to match? 985 case beam_types:meet(ArgType, #t_bs_matchable{}) of 986 none -> no; 987 _ -> maybe 988 end 989 end; 990 991will_succeed_1(#b_set{op={bif,Bif},args=BifArgs}, _Src, Ts, _Sub) -> 992 ArgTypes = normalized_types(BifArgs, Ts), 993 beam_call_types:will_succeed(erlang, Bif, ArgTypes); 994will_succeed_1(#b_set{op=call, 995 args=[#b_remote{mod=#b_literal{val=Mod}, 996 name=#b_literal{val=Func}} | 997 CallArgs]}, 998 _Src, Ts, _Sub) -> 999 ArgTypes = normalized_types(CallArgs, Ts), 1000 beam_call_types:will_succeed(Mod, Func, ArgTypes); 1001 1002will_succeed_1(#b_set{op=get_hd}, _Src, _Ts, _Sub) -> 1003 yes; 1004will_succeed_1(#b_set{op=get_tl}, _Src, _Ts, _Sub) -> 1005 yes; 1006will_succeed_1(#b_set{op=has_map_field}, _Src, _Ts, _Sub) -> 1007 yes; 1008will_succeed_1(#b_set{op=get_tuple_element}, _Src, _Ts, _Sub) -> 1009 yes; 1010will_succeed_1(#b_set{op=put_tuple}, _Src, _Ts, _Sub) -> 1011 yes; 1012 1013%% Remove the success branch from binary operations with invalid 1014%% sizes. That will remove subsequent bs_put and bs_match instructions, 1015%% which are probably not loadable. 1016will_succeed_1(#b_set{op=bs_add,args=[Arg1,Arg2,_]}, 1017 _Src, _Ts, _Sub) -> 1018 case all(fun(#b_literal{val=Size}) -> is_integer(Size) andalso Size >= 0; 1019 (#b_var{}) -> true 1020 end, [Arg1,Arg2]) of 1021 true -> maybe; 1022 false -> no 1023 end; 1024will_succeed_1(#b_set{op=bs_init, 1025 args=[#b_literal{val=new},#b_literal{val=Size},_Unit]}, 1026 _Src, _Ts, _Sub) -> 1027 if 1028 is_integer(Size), Size >= 0 -> 1029 maybe; 1030 true -> 1031 no 1032 end; 1033will_succeed_1(#b_set{op=bs_init, 1034 args=[#b_literal{},_,#b_literal{val=Size},_Unit]}, 1035 _Src, _Ts, _Sub) -> 1036 if 1037 is_integer(Size), Size >= 0 -> 1038 maybe; 1039 true -> 1040 no 1041 end; 1042will_succeed_1(#b_set{op=bs_match, 1043 args=[#b_literal{val=Type},_,_,#b_literal{val=Size},_]}, 1044 _Src, _Ts, _Sub) -> 1045 if 1046 is_integer(Size), Size >= 0 -> 1047 maybe; 1048 Type =:= binary, Size =:= all -> 1049 %% `all` is a legal size for binary segments at the end of 1050 %% a binary pattern. 1051 maybe; 1052 true -> 1053 %% Invalid size. Matching will fail. 1054 no 1055 end; 1056 1057%% These operations may fail even though we know their return value on success. 1058will_succeed_1(#b_set{op=call}, _Src, _Ts, _Sub) -> 1059 maybe; 1060will_succeed_1(#b_set{op=get_map_element}, _Src, _Ts, _Sub) -> 1061 maybe; 1062 1063will_succeed_1(#b_set{op=wait}, _Src, _Ts, _Sub) -> 1064 no; 1065 1066will_succeed_1(#b_set{}, Src, Ts, Sub) -> 1067 case simplify_arg(Src, Ts, Sub) of 1068 #b_var{}=Src -> 1069 %% No substitution; might fail at runtime. 1070 maybe; 1071 _ -> 1072 %% Substituted with literal or other variable; always succeeds. 1073 yes 1074 end. 1075 1076simplify_is_record(I, #t_tuple{exact=Exact, 1077 size=Size, 1078 elements=Es}, 1079 RecSize, #b_literal{val=TagVal}=RecTag, Ts) -> 1080 TagType = maps:get(1, Es, any), 1081 TagMatch = case beam_types:get_singleton_value(TagType) of 1082 {ok, TagVal} -> yes; 1083 {ok, _} -> no; 1084 error -> 1085 %% Is it at all possible for the tag to match? 1086 case beam_types:meet(raw_type(RecTag, Ts), TagType) of 1087 none -> no; 1088 _ -> maybe 1089 end 1090 end, 1091 if 1092 Size =/= RecSize, Exact; Size > RecSize; TagMatch =:= no -> 1093 #b_literal{val=false}; 1094 Size =:= RecSize, Exact, TagMatch =:= yes -> 1095 #b_literal{val=true}; 1096 true -> 1097 I 1098 end; 1099simplify_is_record(I, any, _Size, _Tag, _Ts) -> 1100 I; 1101simplify_is_record(_I, _Type, _Size, _Tag, _Ts) -> 1102 #b_literal{val=false}. 1103 1104simplify_switch_bool(#b_switch{arg=B,fail=Fail,list=List0}, Ts, Ds, Sub) -> 1105 FalseVal = #b_literal{val=false}, 1106 TrueVal = #b_literal{val=true}, 1107 List1 = List0 ++ [{FalseVal,Fail},{TrueVal,Fail}], 1108 {_,FalseLbl} = keyfind(FalseVal, 1, List1), 1109 {_,TrueLbl} = keyfind(TrueVal, 1, List1), 1110 Br = #b_br{bool=B,succ=TrueLbl,fail=FalseLbl}, 1111 simplify_terminator(Br, Ts, Ds, Sub). 1112 1113simplify_not(#b_br{bool=#b_var{}=V,succ=Succ,fail=Fail}=Br0, Ts, Ds, Sub) -> 1114 case Ds of 1115 #{V:=#b_set{op={bif,'not'},args=[Bool]}} -> 1116 case beam_types:is_boolean_type(raw_type(Bool, Ts)) of 1117 true -> 1118 Br = Br0#b_br{bool=Bool,succ=Fail,fail=Succ}, 1119 simplify_terminator(Br, Ts, Ds, Sub); 1120 false -> 1121 Br0 1122 end; 1123 #{} -> 1124 Br0 1125 end; 1126simplify_not(#b_br{bool=#b_literal{}}=Br, _Sub, _Ts, _Ds) -> 1127 Br. 1128 1129simplify_phi_args([{Arg0, From} | Rest], Ls, Sub, Type0, Args) -> 1130 case Ls of 1131 #{ From := Outgoing } -> 1132 {outgoing, Ts} = Outgoing, %Assertion. 1133 1134 Arg = simplify_arg(Arg0, Ts, Sub), 1135 Type = beam_types:join(raw_type(Arg, Ts), Type0), 1136 Phi = {Arg, From}, 1137 1138 simplify_phi_args(Rest, Ls, Sub, Type, [Phi | Args]); 1139 #{} -> 1140 simplify_phi_args(Rest, Ls, Sub, Type0, Args) 1141 end; 1142simplify_phi_args([], _Ls, _Sub, Type, Args) -> 1143 %% We return the arguments in their incoming order so that they won't 1144 %% change back and forth and ruin fixpoint iteration in beam_ssa_opt. 1145 {Type, reverse(Args)}. 1146 1147phi_all_same([{Arg, _From} | Phis]) -> 1148 phi_all_same_1(Phis, Arg). 1149 1150phi_all_same_1([{Arg, _From} | Phis], Arg) -> 1151 phi_all_same_1(Phis, Arg); 1152phi_all_same_1([], _Arg) -> 1153 true; 1154phi_all_same_1(_Phis, _Arg) -> 1155 false. 1156 1157%% Simplify a remote call to a pure BIF. 1158simplify_remote_call(erlang, '++', [#b_literal{val=[]},Tl], _I) -> 1159 Tl; 1160simplify_remote_call(erlang, setelement, 1161 [#b_literal{val=Pos}, 1162 #b_literal{val=Tuple}, 1163 #b_var{}=Value], I) 1164 when is_integer(Pos), 1 =< Pos, Pos =< tuple_size(Tuple) -> 1165 %% Position is a literal integer and the shape of the 1166 %% tuple is known. 1167 Els0 = [#b_literal{val=El} || El <- tuple_to_list(Tuple)], 1168 {Bef,[_|Aft]} = split(Pos - 1, Els0), 1169 Els = Bef ++ [Value|Aft], 1170 I#b_set{op=put_tuple,args=Els}; 1171simplify_remote_call(Mod, Name, Args0, I) -> 1172 case make_literal_list(Args0) of 1173 none -> 1174 I; 1175 Args -> 1176 %% The arguments are literals. Try to evaluate the BIF. 1177 try apply(Mod, Name, Args) of 1178 Val -> 1179 case cerl:is_literal_term(Val) of 1180 true -> 1181 #b_literal{val=Val}; 1182 false -> 1183 %% The value can't be expressed as a literal 1184 %% (e.g. a pid). 1185 I 1186 end 1187 catch 1188 _:_ -> 1189 %% Failed. Don't bother trying to optimize 1190 %% the call. 1191 I 1192 end 1193 end. 1194 1195any_non_numeric_argument([#b_literal{val=Lit}|_], _Ts) -> 1196 is_non_numeric(Lit); 1197any_non_numeric_argument([#b_var{}=V|T], Ts) -> 1198 is_non_numeric_type(raw_type(V, Ts)) orelse any_non_numeric_argument(T, Ts); 1199any_non_numeric_argument([], _Ts) -> false. 1200 1201is_non_numeric([H|T]) -> 1202 is_non_numeric(H) andalso is_non_numeric(T); 1203is_non_numeric(Tuple) when is_tuple(Tuple) -> 1204 is_non_numeric_tuple(Tuple, tuple_size(Tuple)); 1205is_non_numeric(Map) when is_map(Map) -> 1206 %% Starting from OTP 18, map keys are compared using `=:=`. 1207 %% Therefore, we only need to check that the values in the map are 1208 %% non-numeric. (Support for compiling BEAM files for OTP releases 1209 %% older than OTP 18 has been dropped.) 1210 is_non_numeric(maps:values(Map)); 1211is_non_numeric(Num) when is_number(Num) -> 1212 false; 1213is_non_numeric(_) -> true. 1214 1215is_non_numeric_tuple(Tuple, El) when El >= 1 -> 1216 is_non_numeric(element(El, Tuple)) andalso 1217 is_non_numeric_tuple(Tuple, El-1); 1218is_non_numeric_tuple(_Tuple, 0) -> true. 1219 1220is_non_numeric_type(#t_atom{}) -> true; 1221is_non_numeric_type(#t_bitstring{}) -> true; 1222is_non_numeric_type(#t_cons{type=Type,terminator=Terminator}) -> 1223 is_non_numeric_type(Type) andalso is_non_numeric_type(Terminator); 1224is_non_numeric_type(#t_list{type=Type,terminator=Terminator}) -> 1225 is_non_numeric_type(Type) andalso is_non_numeric_type(Terminator); 1226is_non_numeric_type(#t_map{super_value=Value}) -> 1227 is_non_numeric_type(Value); 1228is_non_numeric_type(nil) -> true; 1229is_non_numeric_type(#t_tuple{size=Size,exact=true,elements=Types}) 1230 when map_size(Types) =:= Size -> 1231 is_non_numeric_tuple_type(Size, Types); 1232is_non_numeric_type(_) -> false. 1233 1234is_non_numeric_tuple_type(0, _Types) -> 1235 true; 1236is_non_numeric_tuple_type(Pos, Types) -> 1237 is_non_numeric_type(map_get(Pos, Types)) andalso 1238 is_non_numeric_tuple_type(Pos - 1, Types). 1239 1240make_literal_list(Args) -> 1241 make_literal_list(Args, []). 1242 1243make_literal_list([#b_literal{val=H}|T], Acc) -> 1244 make_literal_list(T, [H|Acc]); 1245make_literal_list([_|_], _) -> 1246 none; 1247make_literal_list([], Acc) -> 1248 reverse(Acc). 1249 1250is_safe_bool_op([LHS, RHS], Ts) -> 1251 LType = raw_type(LHS, Ts), 1252 RType = raw_type(RHS, Ts), 1253 beam_types:is_boolean_type(LType) andalso 1254 beam_types:is_boolean_type(RType). 1255 1256eval_bif(#b_set{op={bif,Bif},args=Args}=I, Ts) -> 1257 Arity = length(Args), 1258 case erl_bifs:is_pure(erlang, Bif, Arity) of 1259 false -> 1260 I; 1261 true -> 1262 case make_literal_list(Args) of 1263 none -> 1264 eval_type_test_bif(I, Bif, raw_types(Args, Ts)); 1265 LitArgs -> 1266 try apply(erlang, Bif, LitArgs) of 1267 Val -> #b_literal{val=Val} 1268 catch 1269 error:_ -> I 1270 end 1271 1272 end 1273 end. 1274 1275eval_type_test_bif(I, is_atom, [Type]) -> 1276 eval_type_test_bif_1(I, Type, #t_atom{}); 1277eval_type_test_bif(I, is_binary, [Type]) -> 1278 eval_type_test_bif_1(I, Type, #t_bs_matchable{tail_unit=8}); 1279eval_type_test_bif(I, is_bitstring, [Type]) -> 1280 eval_type_test_bif_1(I, Type, #t_bs_matchable{}); 1281eval_type_test_bif(I, is_boolean, [Type]) -> 1282 case beam_types:is_boolean_type(Type) of 1283 true -> 1284 #b_literal{val=true}; 1285 false -> 1286 case beam_types:meet(Type, #t_atom{}) of 1287 #t_atom{elements=[_|_]=Es} -> 1288 case any(fun is_boolean/1, Es) of 1289 true -> I; 1290 false -> #b_literal{val=false} 1291 end; 1292 #t_atom{} -> 1293 I; 1294 none -> 1295 #b_literal{val=false} 1296 end 1297 end; 1298eval_type_test_bif(I, is_float, [Type]) -> 1299 eval_type_test_bif_1(I, Type, #t_float{}); 1300eval_type_test_bif(I, is_function, [Type]) -> 1301 eval_type_test_bif_1(I, Type, #t_fun{}); 1302eval_type_test_bif(I, is_integer, [Type]) -> 1303 eval_type_test_bif_1(I, Type, #t_integer{}); 1304eval_type_test_bif(I, is_list, [Type]) -> 1305 eval_type_test_bif_1(I, Type, #t_list{}); 1306eval_type_test_bif(I, is_map, [Type]) -> 1307 eval_type_test_bif_1(I, Type, #t_map{}); 1308eval_type_test_bif(I, is_number, [Type]) -> 1309 eval_type_test_bif_1(I, Type, number); 1310eval_type_test_bif(I, is_tuple, [Type]) -> 1311 eval_type_test_bif_1(I, Type, #t_tuple{}); 1312eval_type_test_bif(I, Op, Types) -> 1313 case Types of 1314 [#t_integer{},#t_integer{elements={0,0}}] 1315 when Op =:= '+'; Op =:= '-'; Op =:= 'bor'; Op =:= 'bxor' -> 1316 #b_set{args=[Result,_]} = I, 1317 Result; 1318 [#t_integer{},#t_integer{elements={0,0}}] when Op =:= '*'; Op =:= 'band' -> 1319 #b_literal{val=0}; 1320 [#t_integer{},#t_integer{elements={1,1}}] when Op =:= '*'; Op =:= 'div' -> 1321 #b_set{args=[Result,_]} = I, 1322 Result; 1323 [#t_integer{elements={LMin,LMax}},#t_integer{elements={RMin,RMax}}] -> 1324 case is_inequality_op(Op) of 1325 true -> 1326 case {erlang:Op(LMin, RMin),erlang:Op(LMax, RMin), 1327 erlang:Op(LMin, RMax),erlang:Op(LMax, RMax)} of 1328 {Bool,Bool,Bool,Bool} -> 1329 #b_literal{val=Bool}; 1330 _ -> 1331 I 1332 end; 1333 false -> 1334 I 1335 end; 1336 _ -> 1337 I 1338 end. 1339 1340is_inequality_op('<') -> true; 1341is_inequality_op('=<') -> true; 1342is_inequality_op('>') -> true; 1343is_inequality_op('>=') -> true; 1344is_inequality_op(_) -> false. 1345 1346eval_type_test_bif_1(I, ArgType, Required) -> 1347 case beam_types:meet(ArgType, Required) of 1348 ArgType -> #b_literal{val=true}; 1349 none -> #b_literal{val=false}; 1350 _ -> I 1351 end. 1352 1353simplify_args(Args, Ts, Sub) -> 1354 [simplify_arg(Arg, Ts, Sub) || Arg <- Args]. 1355 1356simplify_arg(#b_var{}=Arg0, Ts, Sub) -> 1357 case sub_arg(Arg0, Sub) of 1358 #b_literal{}=LitArg -> 1359 LitArg; 1360 #b_var{}=Arg -> 1361 case beam_types:get_singleton_value(raw_type(Arg, Ts)) of 1362 {ok, Val} -> #b_literal{val=Val}; 1363 error -> Arg 1364 end 1365 end; 1366simplify_arg(#b_remote{mod=Mod,name=Name}=Rem, Ts, Sub) -> 1367 Rem#b_remote{mod=simplify_arg(Mod, Ts, Sub), 1368 name=simplify_arg(Name, Ts, Sub)}; 1369simplify_arg(Arg, _Ts, _Sub) -> Arg. 1370 1371sub_arg(#b_var{}=Old, Sub) -> 1372 case Sub of 1373 #{Old:=New} -> New; 1374 #{} -> Old 1375 end. 1376 1377is_float_op('-', [#t_float{}]) -> 1378 true; 1379is_float_op('/', [_,_]) -> 1380 true; 1381is_float_op(Op, [#t_float{},_Other]) -> 1382 is_float_op_1(Op); 1383is_float_op(Op, [_Other,#t_float{}]) -> 1384 is_float_op_1(Op); 1385is_float_op(_, _) -> false. 1386 1387is_float_op_1('+') -> true; 1388is_float_op_1('-') -> true; 1389is_float_op_1('*') -> true; 1390is_float_op_1(_) -> false. 1391 1392anno_float_arg(#t_float{}) -> float; 1393anno_float_arg(_) -> convert. 1394 1395%%% 1396%%% Type helpers 1397%%% 1398 1399%% Returns the narrowest possible return type for the given success types and 1400%% arguments. 1401return_type(SuccTypes0, CallArgs0) -> 1402 SuccTypes = st_filter_reachable(SuccTypes0, CallArgs0, [], []), 1403 st_join_return_types(SuccTypes, none). 1404 1405st_filter_reachable([{SuccArgs, {call_self, SelfArgs}}=SuccType | Rest], 1406 CallArgs0, Deferred, Acc) -> 1407 case st_is_reachable(SuccArgs, CallArgs0) of 1408 true -> 1409 %% If we return a call to ourselves, we need to join our current 1410 %% argument types with that of the call to ensure all possible 1411 %% return paths are covered. 1412 CallArgs = parallel_join(SelfArgs, CallArgs0), 1413 st_filter_reachable(Rest, CallArgs, Deferred, Acc); 1414 false -> 1415 %% This may be reachable after we've joined another self-call, so 1416 %% we defer it until we've gone through all other self-calls. 1417 st_filter_reachable(Rest, CallArgs0, [SuccType | Deferred], Acc) 1418 end; 1419st_filter_reachable([SuccType | Rest], CallArgs, Deferred, Acc) -> 1420 st_filter_reachable(Rest, CallArgs, Deferred, [SuccType | Acc]); 1421st_filter_reachable([], CallArgs, Deferred, Acc) -> 1422 case st_any_reachable(Deferred, CallArgs) of 1423 true -> 1424 %% Handle all deferred self calls that may be reachable now that 1425 %% we've expanded our argument types. 1426 st_filter_reachable(Deferred, CallArgs, [], Acc); 1427 false -> 1428 %% We have no reachable self calls, so we know our argument types 1429 %% can't expand any further. Filter out our reachable sites and 1430 %% return. 1431 [ST || {SuccArgs, _}=ST <- Acc, st_is_reachable(SuccArgs, CallArgs)] 1432 end. 1433 1434st_join_return_types([{_SuccArgs, SuccRet} | Rest], Acc0) -> 1435 st_join_return_types(Rest, beam_types:join(SuccRet, Acc0)); 1436st_join_return_types([], Acc) -> 1437 Acc. 1438 1439st_any_reachable([{SuccArgs, _} | SuccType], CallArgs) -> 1440 case st_is_reachable(SuccArgs, CallArgs) of 1441 true -> true; 1442 false -> st_any_reachable(SuccType, CallArgs) 1443 end; 1444st_any_reachable([], _CallArgs) -> 1445 false. 1446 1447st_is_reachable([A | SuccArgs], [B | CallArgs]) -> 1448 case beam_types:meet(A, B) of 1449 none -> false; 1450 _Other -> st_is_reachable(SuccArgs, CallArgs) 1451 end; 1452st_is_reachable([], []) -> 1453 true. 1454 1455update_success_types(#b_ret{arg=Arg}, Ts, Ds, Meta, SuccTypes) -> 1456 #metadata{ func_id=FuncId, 1457 limit_return=Limited, 1458 params=Params } = Meta, 1459 1460 RetType = case Ds of 1461 #{ Arg := #b_set{op=call,args=[FuncId | Args]} } -> 1462 {call_self, argument_types(Args, Ts)}; 1463 #{} -> 1464 argument_type(Arg, Ts) 1465 end, 1466 ArgTypes = argument_types(Params, Ts), 1467 1468 case Limited of 1469 true -> ust_limited(SuccTypes, ArgTypes, RetType); 1470 false -> ust_unlimited(SuccTypes, ArgTypes, RetType) 1471 end; 1472update_success_types(_Last, _Ts, _Ds, _Meta, SuccTypes) -> 1473 SuccTypes. 1474 1475%% See ?RETURN_LIMIT for details. 1476ust_limited(SuccTypes, CallArgs, {call_self, SelfArgs}) -> 1477 NewArgs = parallel_join(CallArgs, SelfArgs), 1478 ust_limited_1(SuccTypes, NewArgs, none); 1479ust_limited(SuccTypes, CallArgs, CallRet) -> 1480 ust_limited_1(SuccTypes, CallArgs, CallRet). 1481 1482ust_limited_1([], ArgTypes, RetType) -> 1483 [{ArgTypes, RetType}]; 1484ust_limited_1([{SuccArgs, SuccRet}], CallArgs, CallRet) -> 1485 NewTypes = parallel_join(SuccArgs, CallArgs), 1486 NewType = beam_types:join(SuccRet, CallRet), 1487 [{NewTypes, NewType}]. 1488 1489%% Adds a new success type. Note that we no longer try to keep the list short 1490%% by combining entries with the same return type, as that can make effective 1491%% return types less specific as analysis goes on, which may cause endless 1492%% loops or render previous optimizations unsafe. 1493%% 1494%% See beam_type_SUITE:success_type_oscillation/1 for more details. 1495ust_unlimited(SuccTypes, _CallArgs, none) -> 1496 %% 'none' is implied since functions can always fail. 1497 SuccTypes; 1498ust_unlimited([{SameArgs, SameType} | _]=SuccTypes, SameArgs, SameType) -> 1499 %% Already covered, return as-is. 1500 SuccTypes; 1501ust_unlimited([SuccType | SuccTypes], CallArgs, CallRet) -> 1502 [SuccType | ust_unlimited(SuccTypes, CallArgs, CallRet)]; 1503ust_unlimited([], CallArgs, CallRet) -> 1504 [{CallArgs, CallRet}]. 1505 1506update_successors(#b_br{bool=#b_literal{val=true},succ=Succ}=Last, 1507 Ts, _Ds, Ls, _UsedOnce) -> 1508 {Last, update_successor(Succ, Ts, Ls)}; 1509update_successors(#b_br{bool=#b_var{}=Bool,succ=Succ,fail=Fail}=Last0, 1510 Ts, Ds, Ls0, UsedOnce) -> 1511 IsTempVar = cerl_sets:is_element(Bool, UsedOnce), 1512 case infer_types_br(Bool, Ts, IsTempVar, Ds) of 1513 {#{}=SuccTs, #{}=FailTs} -> 1514 Ls1 = update_successor(Succ, SuccTs, Ls0), 1515 Ls = update_successor(Fail, FailTs, Ls1), 1516 {Last0, Ls}; 1517 {#{}=SuccTs, none} -> 1518 Last = Last0#b_br{bool=#b_literal{val=true},fail=Succ}, 1519 {Last, update_successor(Succ, SuccTs, Ls0)}; 1520 {none, #{}=FailTs} -> 1521 Last = Last0#b_br{bool=#b_literal{val=true},succ=Fail}, 1522 {Last, update_successor(Fail, FailTs, Ls0)} 1523 end; 1524update_successors(#b_switch{arg=#b_var{}=V,fail=Fail0,list=List0}=Last0, 1525 Ts, Ds, Ls0, UsedOnce) -> 1526 IsTempVar = cerl_sets:is_element(V, UsedOnce), 1527 1528 {List1, FailTs, Ls1} = 1529 update_switch(List0, V, raw_type(V, Ts), Ts, Ds, Ls0, IsTempVar, []), 1530 1531 case FailTs of 1532 none -> 1533 %% The fail block is unreachable; swap it with one of the choices. 1534 case List1 of 1535 [{#b_literal{val=0},_}|_] -> 1536 %% Swap with the last choice in order to keep the zero the 1537 %% first choice. If the loader can substitute a jump table 1538 %% instruction, then a shorter version of the jump table 1539 %% instruction can be used if the first value is zero. 1540 {List, [{_,Fail}]} = split(length(List1)-1, List1), 1541 Last = Last0#b_switch{fail=Fail,list=List}, 1542 {Last, Ls1}; 1543 [{_,Fail}|List] -> 1544 %% Swap with the first choice in the list. 1545 Last = Last0#b_switch{fail=Fail,list=List}, 1546 {Last, Ls1} 1547 end; 1548 #{} -> 1549 Ls = update_successor(Fail0, FailTs, Ls1), 1550 Last = Last0#b_switch{list=List1}, 1551 {Last, Ls} 1552 end; 1553update_successors(#b_ret{}=Last, _Ts, _Ds, Ls, _UsedOnce) -> 1554 {Last, Ls}. 1555 1556update_switch([{Val, Lbl}=Sw | List], 1557 V, FailType0, Ts, Ds, Ls0, IsTempVar, Acc) -> 1558 FailType = beam_types:subtract(FailType0, raw_type(Val, Ts)), 1559 case infer_types_switch(V, Val, Ts, IsTempVar, Ds) of 1560 none -> 1561 update_switch(List, V, FailType, Ts, Ds, Ls0, IsTempVar, Acc); 1562 SwTs -> 1563 Ls = update_successor(Lbl, SwTs, Ls0), 1564 update_switch(List, V, FailType, Ts, Ds, Ls, IsTempVar, [Sw | Acc]) 1565 end; 1566update_switch([], _V, none, _Ts, _Ds, Ls, _IsTempVar, Acc) -> 1567 %% Fail label is unreachable. 1568 {reverse(Acc), none, Ls}; 1569update_switch([], V, FailType, Ts, Ds, Ls, IsTempVar, Acc) -> 1570 %% Fail label is reachable, see if we can narrow the type down further. 1571 FailTs = case beam_types:get_singleton_value(FailType) of 1572 {ok, Value} -> 1573 %% This is the only possible value at the fail label, so 1574 %% we can infer types as if we matched it directly. 1575 Lit = #b_literal{val=Value}, 1576 infer_types_switch(V, Lit, Ts, IsTempVar, Ds); 1577 error when IsTempVar -> 1578 ts_remove_var(V, Ts); 1579 error -> 1580 Ts#{ V := FailType } 1581 end, 1582 {reverse(Acc), FailTs, Ls}. 1583 1584update_successor(?EXCEPTION_BLOCK, _Ts, Ls) -> 1585 %% We KNOW that no variables are used in the ?EXCEPTION_BLOCK, 1586 %% so there is no need to update the type information. That 1587 %% can be a huge timesaver for huge functions. 1588 Ls; 1589update_successor(S, Ts0, Ls) -> 1590 case Ls of 1591 #{ S := {outgoing, _} } -> 1592 %% We're in a receive loop or similar; the target block will not be 1593 %% revisited. 1594 Ls; 1595 #{ S := {incoming, InTs} } -> 1596 Ts = join_types(Ts0, InTs), 1597 Ls#{ S := {incoming, Ts} }; 1598 #{} -> 1599 Ls#{ S => {incoming, Ts0} } 1600 end. 1601 1602update_types(#b_set{op=Op,dst=Dst,anno=Anno,args=Args}, Ts, Ds) -> 1603 T = type(Op, Args, Anno, Ts, Ds), 1604 Ts#{Dst=>T}. 1605 1606type({bif,Bif}, Args, _Anno, Ts, _Ds) -> 1607 ArgTypes = normalized_types(Args, Ts), 1608 {RetType, _, _} = beam_call_types:types(erlang, Bif, ArgTypes), 1609 RetType; 1610type(bs_init, _Args, _Anno, _Ts, _Ds) -> 1611 #t_bitstring{}; 1612type(bs_extract, [Ctx], _Anno, _Ts, Ds) -> 1613 #b_set{op=bs_match,args=Args} = map_get(Ctx, Ds), 1614 bs_match_type(Args); 1615type(bs_start_match, [_, Src], _Anno, Ts, _Ds) -> 1616 case beam_types:meet(#t_bs_matchable{}, raw_type(Src, Ts)) of 1617 none -> 1618 none; 1619 T -> 1620 Unit = beam_types:get_bs_matchable_unit(T), 1621 #t_bs_context{tail_unit=Unit} 1622 end; 1623type(bs_match, [#b_literal{val=binary}, Ctx, _Flags, 1624 #b_literal{val=all}, #b_literal{val=OpUnit}], 1625 _Anno, Ts, _Ds) -> 1626 1627 %% This is an explicit tail unit test which does not advance the match 1628 %% position. 1629 CtxType = raw_type(Ctx, Ts), 1630 OpType = #t_bs_context{tail_unit=OpUnit}, 1631 1632 beam_types:meet(CtxType, OpType); 1633type(bs_match, Args, _Anno, Ts, _Ds) -> 1634 [_, Ctx | _] = Args, 1635 1636 %% Matches advance the current position without testing the tail unit. We 1637 %% try to retain unit information by taking the GCD of our current unit and 1638 %% the increments we know the match will advance by. 1639 #t_bs_context{tail_unit=CtxUnit} = raw_type(Ctx, Ts), 1640 OpUnit = bs_match_stride(Args, Ts), 1641 1642 #t_bs_context{tail_unit=gcd(OpUnit, CtxUnit)}; 1643type(bs_get_tail, [Ctx], _Anno, Ts, _Ds) -> 1644 #t_bs_context{tail_unit=Unit} = raw_type(Ctx, Ts), 1645 #t_bitstring{size_unit=Unit}; 1646type(call, [#b_remote{mod=#b_literal{val=Mod}, 1647 name=#b_literal{val=Name}}|Args], _Anno, Ts, _Ds) -> 1648 ArgTypes = normalized_types(Args, Ts), 1649 {RetType, _, _} = beam_call_types:types(Mod, Name, ArgTypes), 1650 RetType; 1651type(call, [#b_remote{} | _Args], _Anno, _Ts, _Ds) -> 1652 %% Remote call with variable Module and/or Function. 1653 any; 1654type(call, [#b_local{} | _Args], Anno, _Ts, _Ds) -> 1655 case Anno of 1656 #{ result_type := Type } -> Type; 1657 #{} -> any 1658 end; 1659type(call, [#b_var{} | _Args], Anno, _Ts, _Ds) -> 1660 case Anno of 1661 #{ result_type := Type } -> Type; 1662 #{} -> any 1663 end; 1664type(call, [#b_literal{val=Fun} | Args], _Anno, _Ts, _Ds) -> 1665 case is_function(Fun, length(Args)) of 1666 true -> 1667 %% This is an external fun literal (fun M:F/A). 1668 any; 1669 false -> 1670 %% This is either not a fun literal or the number of 1671 %% arguments is wrong. 1672 none 1673 end; 1674type(get_hd, [Src], _Anno, Ts, _Ds) -> 1675 SrcType = #t_cons{} = normalized_type(Src, Ts), %Assertion. 1676 {RetType, _, _} = beam_call_types:types(erlang, hd, [SrcType]), 1677 RetType; 1678type(get_tl, [Src], _Anno, Ts, _Ds) -> 1679 SrcType = #t_cons{} = normalized_type(Src, Ts), %Assertion. 1680 {RetType, _, _} = beam_call_types:types(erlang, tl, [SrcType]), 1681 RetType; 1682type(get_map_element, [_, _]=Args0, _Anno, Ts, _Ds) -> 1683 [#t_map{}=Map, Key] = normalized_types(Args0, Ts), %Assertion. 1684 {RetType, _, _} = beam_call_types:types(erlang, map_get, [Key, Map]), 1685 RetType; 1686type(get_tuple_element, [Tuple, Offset], _Anno, Ts, _Ds) -> 1687 #t_tuple{size=Size,elements=Es} = normalized_type(Tuple, Ts), 1688 #b_literal{val=N} = Offset, 1689 true = Size > N, %Assertion. 1690 beam_types:get_tuple_element(N + 1, Es); 1691type(has_map_field, [_, _]=Args0, _Anno, Ts, _Ds) -> 1692 [#t_map{}=Map, Key] = normalized_types(Args0, Ts), %Assertion. 1693 {RetType, _, _} = beam_call_types:types(erlang, is_map_key, [Key, Map]), 1694 RetType; 1695type(is_nonempty_list, [_], _Anno, _Ts, _Ds) -> 1696 beam_types:make_boolean(); 1697type(is_tagged_tuple, [_,#b_literal{},#b_literal{}], _Anno, _Ts, _Ds) -> 1698 beam_types:make_boolean(); 1699type(make_fun, [#b_local{arity=TotalArity} | Env], Anno, _Ts, _Ds) -> 1700 RetType = case Anno of 1701 #{ result_type := Type } -> Type; 1702 #{} -> any 1703 end, 1704 #t_fun{arity=TotalArity - length(Env), type=RetType}; 1705type(put_map, [_Kind, Map | Ss], _Anno, Ts, _Ds) -> 1706 put_map_type(Map, Ss, Ts); 1707type(put_list, [Head, Tail], _Anno, Ts, _Ds) -> 1708 HeadType = raw_type(Head, Ts), 1709 TailType = raw_type(Tail, Ts), 1710 beam_types:make_cons(HeadType, TailType); 1711type(put_tuple, Args, _Anno, Ts, _Ds) -> 1712 {Es, _} = foldl(fun(Arg, {Es0, Index}) -> 1713 Type = raw_type(Arg, Ts), 1714 Es = beam_types:set_tuple_element(Index, Type, Es0), 1715 {Es, Index + 1} 1716 end, {#{}, 1}, Args), 1717 #t_tuple{exact=true,size=length(Args),elements=Es}; 1718type(resume, [_, _], _Anno, _Ts, _Ds) -> 1719 none; 1720type(_, _, _, _, _) -> any. 1721 1722put_map_type(Map, Ss, Ts) -> 1723 pmt_1(Ss, Ts, normalized_type(Map, Ts)). 1724 1725pmt_1([Key0, Value0 | Ss], Ts, Acc0) -> 1726 Key = normalized_type(Key0, Ts), 1727 Value = normalized_type(Value0, Ts), 1728 {Acc, _, _} = beam_call_types:types(maps, put, [Key, Value, Acc0]), 1729 pmt_1(Ss, Ts, Acc); 1730pmt_1([], _Ts, Acc) -> 1731 Acc. 1732 1733%% We seldom know how far a match operation may advance, but we can often tell 1734%% which increment it will advance by. 1735bs_match_stride([#b_literal{val=Type} | Args], Ts) -> 1736 bs_match_stride(Type, Args, Ts). 1737 1738bs_match_stride(_, [_,_,Size,#b_literal{val=Unit}], Ts) -> 1739 case raw_type(Size, Ts) of 1740 #t_integer{elements={Sz, Sz}} when is_integer(Sz) -> 1741 Sz * Unit; 1742 _ -> 1743 Unit 1744 end; 1745bs_match_stride(string, [_,#b_literal{val=String}], _) -> 1746 bit_size(String); 1747bs_match_stride(utf8, _, _) -> 1748 8; 1749bs_match_stride(utf16, _, _) -> 1750 16; 1751bs_match_stride(utf32, _, _) -> 1752 32; 1753bs_match_stride(_, _, _) -> 1754 1. 1755 1756-define(UNICODE_MAX, (16#10FFFF)). 1757 1758bs_match_type([#b_literal{val=Type}|Args]) -> 1759 bs_match_type(Type, Args). 1760 1761bs_match_type(binary, Args) -> 1762 [_,_,_,#b_literal{val=U}] = Args, 1763 #t_bitstring{size_unit=U}; 1764bs_match_type(float, _) -> 1765 #t_float{}; 1766bs_match_type(integer, Args) -> 1767 case Args of 1768 [_, 1769 #b_literal{val=Flags}, 1770 #b_literal{val=Size}, 1771 #b_literal{val=Unit}] when Size * Unit < 64 -> 1772 NumBits = Size * Unit, 1773 case member(unsigned, Flags) of 1774 true -> 1775 beam_types:make_integer(0, (1 bsl NumBits)-1); 1776 false -> 1777 %% Signed integer. Don't bother. 1778 #t_integer{} 1779 end; 1780 [_|_] -> 1781 #t_integer{} 1782 end; 1783bs_match_type(skip, _) -> 1784 any; 1785bs_match_type(string, _) -> 1786 any; 1787bs_match_type(utf8, _) -> 1788 beam_types:make_integer(0, ?UNICODE_MAX); 1789bs_match_type(utf16, _) -> 1790 beam_types:make_integer(0, ?UNICODE_MAX); 1791bs_match_type(utf32, _) -> 1792 beam_types:make_integer(0, ?UNICODE_MAX). 1793 1794normalized_types(Values, Ts) -> 1795 [normalized_type(Val, Ts) || Val <- Values]. 1796 1797normalized_type(V, Ts) -> 1798 beam_types:normalize(raw_type(V, Ts)). 1799 1800argument_types(Values, Ts) -> 1801 [argument_type(Val, Ts) || Val <- Values]. 1802 1803-spec argument_type(beam_ssa:value(), type_db()) -> type(). 1804 1805argument_type(V, Ts) -> 1806 beam_types:limit_depth(raw_type(V, Ts)). 1807 1808raw_types(Values, Ts) -> 1809 [raw_type(Val, Ts) || Val <- Values]. 1810 1811-spec raw_type(beam_ssa:value(), type_db()) -> type(). 1812 1813raw_type(#b_literal{val=Value}, _Ts) -> 1814 beam_types:make_type_from_value(Value); 1815raw_type(V, Ts) -> 1816 map_get(V, Ts). 1817 1818%% infer_types(Var, Types, #d{}) -> {SuccTypes,FailTypes} 1819%% Looking at the expression that defines the variable Var, infer 1820%% the types for the variables in the arguments. Return the updated 1821%% type database for the case that the expression evaluates to 1822%% true, and and for the case that it evaluates to false. 1823%% 1824%% Here is an example. The variable being asked about is 1825%% the variable Bool, which is defined like this: 1826%% 1827%% Bool = is_nonempty_list L 1828%% 1829%% If 'is_nonempty_list L' evaluates to 'true', L must 1830%% must be cons. The meet of the previously known type of L and 'cons' 1831%% will be added to SuccTypes. 1832%% 1833%% On the other hand, if 'is_nonempty_list L' evaluates to false, L 1834%% is not cons and cons can be subtracted from the previously known 1835%% type for L. For example, if L was known to be 'list', subtracting 1836%% 'cons' would give 'nil' as the only possible type. The result of the 1837%% subtraction for L will be added to FailTypes. 1838 1839infer_types_br(#b_var{}=V, Ts, IsTempVar, Ds) -> 1840 #{V:=#b_set{op=Op,args=Args}} = Ds, 1841 1842 {PosTypes, NegTypes} = infer_type(Op, Args, Ts, Ds), 1843 1844 SuccTs0 = meet_types(PosTypes, Ts), 1845 FailTs0 = subtract_types(NegTypes, Ts), 1846 1847 case IsTempVar of 1848 true -> 1849 %% The branch variable is defined in this block and is only 1850 %% referenced by this terminator. Therefore, there is no need to 1851 %% include it in the type database passed on to the successors of 1852 %% of this block. 1853 SuccTs = ts_remove_var(V, SuccTs0), 1854 FailTs = ts_remove_var(V, FailTs0), 1855 {SuccTs, FailTs}; 1856 false -> 1857 SuccTs = infer_br_value(V, true, SuccTs0), 1858 FailTs = infer_br_value(V, false, FailTs0), 1859 {SuccTs, FailTs} 1860 end. 1861 1862infer_br_value(_V, _Bool, none) -> 1863 none; 1864infer_br_value(V, Bool, NewTs) -> 1865 #{ V := T } = NewTs, 1866 case beam_types:is_boolean_type(T) of 1867 true -> 1868 NewTs#{ V := beam_types:make_atom(Bool) }; 1869 false -> 1870 %% V is a try/catch tag or similar, leave it alone. 1871 NewTs 1872 end. 1873 1874infer_types_switch(V, Lit, Ts0, IsTempVar, Ds) -> 1875 {PosTypes, _} = infer_type({bif,'=:='}, [V, Lit], Ts0, Ds), 1876 Ts = meet_types(PosTypes, Ts0), 1877 case IsTempVar of 1878 true -> ts_remove_var(V, Ts); 1879 false -> Ts 1880 end. 1881 1882ts_remove_var(_V, none) -> none; 1883ts_remove_var(V, Ts) -> maps:remove(V, Ts). 1884 1885infer_type({succeeded,_}, [#b_var{}=Src], Ts, Ds) -> 1886 #b_set{op=Op,args=Args} = maps:get(Src, Ds), 1887 infer_success_type(Op, Args, Ts, Ds); 1888 1889%% Type tests are handled separately from other BIFs as we're inferring types 1890%% based on their result, so we know that subtraction is safe even if we're 1891%% not branching on 'succeeded'. 1892infer_type(is_tagged_tuple, [#b_var{}=Src,#b_literal{val=Size}, 1893 #b_literal{}=Tag], _Ts, _Ds) -> 1894 Es = beam_types:set_tuple_element(1, raw_type(Tag, #{}), #{}), 1895 T = {Src,#t_tuple{exact=true,size=Size,elements=Es}}, 1896 {[T], [T]}; 1897infer_type(is_nonempty_list, [#b_var{}=Src], _Ts, _Ds) -> 1898 T = {Src,#t_cons{}}, 1899 {[T], [T]}; 1900infer_type({bif,is_atom}, [Arg], _Ts, _Ds) -> 1901 T = {Arg, #t_atom{}}, 1902 {[T], [T]}; 1903infer_type({bif,is_binary}, [Arg], _Ts, _Ds) -> 1904 T = {Arg, #t_bitstring{size_unit=8}}, 1905 {[T], [T]}; 1906infer_type({bif,is_bitstring}, [Arg], _Ts, _Ds) -> 1907 T = {Arg, #t_bitstring{}}, 1908 {[T], [T]}; 1909infer_type({bif,is_boolean}, [Arg], _Ts, _Ds) -> 1910 T = {Arg, beam_types:make_boolean()}, 1911 {[T], [T]}; 1912infer_type({bif,is_float}, [Arg], _Ts, _Ds) -> 1913 T = {Arg, #t_float{}}, 1914 {[T], [T]}; 1915infer_type({bif,is_integer}, [Arg], _Ts, _Ds) -> 1916 T = {Arg, #t_integer{}}, 1917 {[T], [T]}; 1918infer_type({bif,is_list}, [Arg], _Ts, _Ds) -> 1919 T = {Arg, #t_list{}}, 1920 {[T], [T]}; 1921infer_type({bif,is_map}, [Arg], _Ts, _Ds) -> 1922 T = {Arg, #t_map{}}, 1923 {[T], [T]}; 1924infer_type({bif,is_number}, [Arg], _Ts, _Ds) -> 1925 T = {Arg, number}, 1926 {[T], [T]}; 1927infer_type({bif,is_tuple}, [Arg], _Ts, _Ds) -> 1928 T = {Arg, #t_tuple{}}, 1929 {[T], [T]}; 1930infer_type({bif,'=:='}, [#b_var{}=LHS,#b_var{}=RHS], Ts, _Ds) -> 1931 %% As an example, assume that L1 is known to be 'list', and L2 is 1932 %% known to be 'cons'. Then if 'L1 =:= L2' evaluates to 'true', it can 1933 %% be inferred that L1 is 'cons' (the meet of 'cons' and 'list'). 1934 LType = raw_type(LHS, Ts), 1935 RType = raw_type(RHS, Ts), 1936 Type = beam_types:meet(LType, RType), 1937 1938 PosTypes = [{V,Type} || {V, OrigType} <- [{LHS, LType}, {RHS, RType}], 1939 OrigType =/= Type], 1940 1941 %% We must be careful with types inferred from '=:='. 1942 %% 1943 %% If we have seen L =:= [a], we know that L is 'cons' if the 1944 %% comparison succeeds. However, if the comparison fails, L could 1945 %% still be 'cons'. Therefore, we must not subtract 'cons' from the 1946 %% previous type of L. 1947 %% 1948 %% However, it is safe to subtract a type inferred from '=:=' if 1949 %% it is single-valued, e.g. if it is [] or the atom 'true'. 1950 %% 1951 %% Note that we subtract the left-hand type from the right-hand 1952 %% value and vice versa. We must not subtract the meet of the two 1953 %% as it may be too specific. See beam_type_SUITE:type_subtraction/1 1954 %% for details. 1955 NegTypes = [T || {_, OtherType}=T <- [{RHS, LType}, {LHS, RType}], 1956 beam_types:is_singleton_type(OtherType)], 1957 1958 {PosTypes, NegTypes}; 1959infer_type({bif,'=:='}, [#b_var{}=Src,#b_literal{}=Lit], Ts, Ds) -> 1960 Def = maps:get(Src, Ds), 1961 LitType = raw_type(Lit, Ts), 1962 PosTypes = [{Src, LitType} | infer_eq_lit(Def, LitType)], 1963 1964 %% Subtraction is only safe if LitType is single-valued. 1965 NegTypes = case beam_types:is_singleton_type(LitType) of 1966 true -> PosTypes; 1967 false -> [] 1968 end, 1969 1970 {PosTypes, NegTypes}; 1971infer_type(_Op, _Args, _Ts, _Ds) -> 1972 {[], []}. 1973 1974infer_success_type({bif,Op}, Args, Ts, _Ds) -> 1975 ArgTypes = normalized_types(Args, Ts), 1976 1977 {_, PosTypes0, CanSubtract} = beam_call_types:types(erlang, Op, ArgTypes), 1978 PosTypes = [T || {#b_var{},_}=T <- zip(Args, PosTypes0)], 1979 1980 case CanSubtract of 1981 true -> {PosTypes, PosTypes}; 1982 false -> {PosTypes, []} 1983 end; 1984infer_success_type(call, [#b_var{}=Fun|Args], _Ts, _Ds) -> 1985 T = {Fun, #t_fun{arity=length(Args)}}, 1986 {[T], []}; 1987infer_success_type(bs_start_match, [_, #b_var{}=Src], _Ts, _Ds) -> 1988 T = {Src,#t_bs_matchable{}}, 1989 {[T], [T]}; 1990infer_success_type(bs_match, [#b_literal{val=binary}, 1991 Ctx, _Flags, 1992 #b_literal{val=all}, 1993 #b_literal{val=OpUnit}], 1994 _Ts, _Ds) -> 1995 %% This is an explicit tail unit test which does not advance the match 1996 %% position, so we know that Ctx has the same unit. 1997 T = {Ctx, #t_bs_context{tail_unit=OpUnit}}, 1998 {[T], [T]}; 1999infer_success_type(_Op, _Args, _Ts, _Ds) -> 2000 {[], []}. 2001 2002infer_eq_lit(#b_set{op={bif,tuple_size},args=[#b_var{}=Tuple]}, 2003 #t_integer{elements={Size,Size}}) -> 2004 [{Tuple,#t_tuple{exact=true,size=Size}}]; 2005infer_eq_lit(#b_set{op=get_tuple_element, 2006 args=[#b_var{}=Tuple,#b_literal{val=N}]}, 2007 LitType) -> 2008 Index = N + 1, 2009 case beam_types:set_tuple_element(Index, LitType, #{}) of 2010 #{ Index := _ }=Es -> 2011 [{Tuple,#t_tuple{size=Index,elements=Es}}]; 2012 #{} -> 2013 %% Index was above the element limit; subtraction is not safe. 2014 [] 2015 end; 2016infer_eq_lit(_, _) -> 2017 []. 2018 2019join_types(Ts, Ts) -> 2020 Ts; 2021join_types(LHS, RHS) -> 2022 if 2023 map_size(LHS) < map_size(RHS) -> 2024 join_types_1(maps:keys(LHS), RHS, LHS); 2025 true -> 2026 join_types_1(maps:keys(RHS), LHS, RHS) 2027 end. 2028 2029%% Joins two type maps, keeping the variables that are common to both maps. 2030join_types_1([V | Vs], Bigger, Smaller) -> 2031 case {Bigger, Smaller} of 2032 {#{ V := Same }, #{ V := Same }} -> 2033 join_types_1(Vs, Bigger, Smaller); 2034 {#{ V := LHS }, #{ V := RHS }} -> 2035 T = beam_types:join(LHS, RHS), 2036 join_types_1(Vs, Bigger, Smaller#{ V := T }); 2037 {#{}, #{ V := _ }} -> 2038 join_types_1(Vs, Bigger, maps:remove(V, Smaller)) 2039 end; 2040join_types_1([], _Bigger, Smaller) -> 2041 Smaller. 2042 2043meet_types([{V,T0}|Vs], Ts) -> 2044 #{V:=T1} = Ts, 2045 case beam_types:meet(T0, T1) of 2046 none -> none; 2047 T1 -> meet_types(Vs, Ts); 2048 T -> meet_types(Vs, Ts#{V:=T}) 2049 end; 2050meet_types([], Ts) -> Ts. 2051 2052subtract_types([{V,T0}|Vs], Ts) -> 2053 #{V:=T1} = Ts, 2054 case beam_types:subtract(T1, T0) of 2055 none -> none; 2056 T1 -> subtract_types(Vs, Ts); 2057 T -> subtract_types(Vs, Ts#{V:=T}) 2058 end; 2059subtract_types([], Ts) -> Ts. 2060 2061parallel_join([A | As], [B | Bs]) -> 2062 [beam_types:join(A, B) | parallel_join(As, Bs)]; 2063parallel_join([], []) -> 2064 []. 2065 2066gcd(A, B) -> 2067 case A rem B of 2068 0 -> B; 2069 X -> gcd(B, X) 2070 end. 2071 2072%%% 2073%%% Helpers 2074%%% 2075 2076init_metadata(FuncId, Linear, Params) -> 2077 {RetCounter, Map0} = init_metadata_1(reverse(Linear), 0, #{}), 2078 Map = maps:without(Params, Map0), 2079 UsedOnce = cerl_sets:from_list(maps:keys(Map)), 2080 2081 #metadata{ func_id = FuncId, 2082 limit_return = (RetCounter >= ?RETURN_LIMIT), 2083 params = Params, 2084 used_once = UsedOnce }. 2085 2086init_metadata_1([{L,#b_blk{is=Is,last=Last}} | Bs], RetCounter0, Uses0) -> 2087 %% Track the number of return terminators in use. See ?RETURN_LIMIT for 2088 %% details. 2089 RetCounter = case Last of 2090 #b_ret{} -> RetCounter0 + 1; 2091 _ -> RetCounter0 2092 end, 2093 2094 %% Calculate the set of variables that are only used once in the terminator 2095 %% of the block that defines them. That will allow us to discard type 2096 %% information discard type information for variables that will never be 2097 %% referenced by the successor blocks, potentially improving compilation 2098 %% times. 2099 2100 Uses1 = used_once_last_uses(beam_ssa:used(Last), L, Uses0), 2101 Uses = used_once_2(reverse(Is), L, Uses1), 2102 init_metadata_1(Bs, RetCounter, Uses); 2103init_metadata_1([], RetCounter, Uses) -> 2104 {RetCounter, Uses}. 2105 2106used_once_2([#b_set{dst=Dst}=I|Is], L, Uses0) -> 2107 Uses = used_once_uses(beam_ssa:used(I), L, Uses0), 2108 case Uses of 2109 #{Dst:=[L]} -> 2110 used_once_2(Is, L, Uses); 2111 #{} -> 2112 %% Used more than once or used once in 2113 %% in another block. 2114 used_once_2(Is, L, maps:remove(Dst, Uses)) 2115 end; 2116used_once_2([], _, Uses) -> Uses. 2117 2118used_once_uses([V|Vs], L, Uses) -> 2119 case Uses of 2120 #{V:=more_than_once} -> 2121 used_once_uses(Vs, L, Uses); 2122 #{} -> 2123 %% Already used or first use is not in 2124 %% a terminator. 2125 used_once_uses(Vs, L, Uses#{V=>more_than_once}) 2126 end; 2127used_once_uses([], _, Uses) -> Uses. 2128 2129used_once_last_uses([V|Vs], L, Uses) -> 2130 case Uses of 2131 #{V:=[_]} -> 2132 %% Second time this variable is used. 2133 used_once_last_uses(Vs, L, Uses#{V:=more_than_once}); 2134 #{V:=more_than_once} -> 2135 %% Used at least twice before. 2136 used_once_last_uses(Vs, L, Uses); 2137 #{} -> 2138 %% First time this variable is used. 2139 used_once_last_uses(Vs, L, Uses#{V=>[L]}) 2140 end; 2141used_once_last_uses([], _, Uses) -> Uses. 2142 2143%% 2144%% Ordered worklist used in signatures/2. 2145%% 2146%% This is equivalent to consing (wl_add) and appending (wl_defer_list) 2147%% to a regular list, but avoids uneccessary work by reordering elements. 2148%% 2149%% We can do this since a function only needs to be visited *once* for all 2150%% prior updates to take effect, so if an element is added to the front, then 2151%% all earlier instances of the same element are redundant. 2152%% 2153 2154-record(worklist, 2155 { counter = 0 :: integer(), 2156 elements = gb_trees:empty() :: gb_trees:tree(integer(), term()), 2157 indexes = #{} :: #{ term() => integer() } }). 2158 2159-type worklist() :: #worklist{}. 2160 2161wl_new() -> #worklist{}. 2162 2163%% Adds an element to the worklist, or moves it to the front if it's already 2164%% present. 2165wl_add(Element, #worklist{counter=Counter,elements=Es,indexes=Is}) -> 2166 case Is of 2167 #{ Element := Index } -> 2168 wl_add_1(Element, Counter, gb_trees:delete(Index, Es), Is); 2169 #{} -> 2170 wl_add_1(Element, Counter, Es, Is) 2171 end. 2172 2173wl_add_1(Element, Counter0, Es0, Is0) -> 2174 Counter = Counter0 + 1, 2175 Es = gb_trees:insert(Counter, Element, Es0), 2176 Is = Is0#{ Element => Counter }, 2177 #worklist{counter=Counter,elements=Es,indexes=Is}. 2178 2179%% All mutations bump the counter, so we can check for changes without a deep 2180%% comparison. 2181wl_changed(#worklist{counter=Same}, #worklist{counter=Same}) -> false; 2182wl_changed(#worklist{}, #worklist{}) -> true. 2183 2184%% Adds the given elements to the back of the worklist, skipping the elements 2185%% that are already present. This lets us append elements arbitrarly after the 2186%% current front without changing the work order. 2187wl_defer_list(Elements, #worklist{counter=Counter,elements=Es,indexes=Is}) -> 2188 wl_defer_list_1(Elements, Counter, Es, Is). 2189 2190wl_defer_list_1([Element | Elements], Counter0, Es0, Is0) -> 2191 case Is0 of 2192 #{ Element := _ } -> 2193 wl_defer_list_1(Elements, Counter0, Es0, Is0); 2194 #{} -> 2195 Counter = Counter0 + 1, 2196 Es = gb_trees:insert(-Counter, Element, Es0), 2197 Is = Is0#{ Element => -Counter }, 2198 wl_defer_list_1(Elements, Counter, Es, Is) 2199 end; 2200wl_defer_list_1([], Counter, Es, Is) -> 2201 #worklist{counter=Counter,elements=Es,indexes=Is}. 2202 2203wl_next(#worklist{indexes=Is}) when Is =:= #{} -> 2204 empty; 2205wl_next(#worklist{elements=Es,indexes=Is}) when Is =/= #{} -> 2206 {_Key, Element} = gb_trees:largest(Es), 2207 {ok, Element}. 2208 2209%% Removes the front of the worklist. 2210wl_pop(Element, #worklist{counter=Counter0,elements=Es0,indexes=Is0}=Wl) -> 2211 Counter = Counter0 + 1, 2212 {_Key, Element, Es} = gb_trees:take_largest(Es0), %Assertion. 2213 Is = maps:remove(Element, Is0), 2214 Wl#worklist{counter=Counter,elements=Es,indexes=Is}. 2215