@@ -36,6 +36,7 @@ open CHTraceResult
3636
3737(* xprlib *)
3838open XprTypes
39+ open XprUtil
3940open Xsimplify
4041
4142(* bchlib *)
@@ -255,6 +256,43 @@ object (self)
255256 linenumber
256257 [(p2s floc#l#toPretty) ^ " : " ^ (btype_to_string ty)] in
257258
259+ let operand_is_zero (op : arm_operand_int ): bool =
260+ (* Returns true if the value of the operand is known to be zero at
261+ this location. This result is primarily intended to avoid spurious
262+ typing relationships in cases where the compiler 'knows' that the value
263+ is zero, and may use it as an alternate for the the immediate value zero
264+ in certain instructions, like ADD, MOV, or SUB. *)
265+ TR. tfold_default
266+ (fun v ->
267+ match v with
268+ | XConst (IntConst n ) -> n#equal numerical_zero
269+ | _ -> false )
270+ false
271+ (TR. tmap rewrite_expr (op#to_expr floc)) in
272+
273+ let operand_is_zero_in_cc_context
274+ (cc : arm_opcode_cc_t ) (op : arm_operand_int ): bool =
275+ match cc with
276+ | ACCAlways -> operand_is_zero op
277+ | _ when instr#is_condition_covered -> operand_is_zero op
278+ | _ when is_cond_conditional cc && floc#has_test_expr ->
279+ TR. tfold_default
280+ (fun xx ->
281+ let txpr = floc#get_test_expr in
282+ let tcond = rewrite_expr txpr in
283+ (match tcond with
284+ | XOp (XEq, [XVar vr ; XConst (IntConst n )]) ->
285+ let subst v =
286+ if v#equal vr then XConst (IntConst n) else XVar vr in
287+ let result = simplify_xpr (substitute_expr subst xx) in
288+ (match result with
289+ | XConst (IntConst n ) -> n#equal numerical_zero
290+ | _ -> operand_is_zero op)
291+ | _ -> operand_is_zero op))
292+ (operand_is_zero op)
293+ (TR. tmap rewrite_expr (op#to_expr floc))
294+ | _ -> operand_is_zero op in
295+
258296 match instr#get_opcode with
259297
260298 | Add (_ , _ , rd , rn , rm , _ ) ->
@@ -275,7 +313,26 @@ object (self)
275313 | _ -> () )
276314 | _ -> () );
277315
278- (if rm#is_immediate && (rm#to_numerical#toInt < 256 ) then
316+ (* Heuristic: if a small number (taken here as < 256) is added to
317+ a register value it is assumed that the value in the destination
318+ register has the same type as the value in the source register.
319+
320+ The case where the value of the source register is known to be zero
321+ is excluded, because this construct, rd = rn (=0) + imm, is often
322+ used as an alternate for MOV rd, #imm, in which case the type of
323+ the source value may be entirely related to the type of the type of
324+ the destination value (giving rise to very hard to diagnose typing
325+ errors)
326+
327+ This heuristic also fails when applied to pointers to access
328+ different fields in a struct. Although this case is not so common,
329+ (ARM allows offsets to be specified as part of memory accesses),
330+ it does happen (it has been observed), and hence this heuristic
331+ is disabled for now, until we have a way to explicitly exclude
332+ this case.
333+ (if rm#is_immediate
334+ && (rm#to_numerical#toInt < 256)
335+ && (not (operand_is_zero rn)) then
279336 let rdreg = rd#to_register in
280337 let lhstypevar = mk_reglhs_typevar rdreg faddr iaddr in
281338 let rndefs = get_variable_rdefs_r (rn#to_variable floc) in
@@ -288,7 +345,7 @@ object (self)
288345 begin
289346 log_subtype_constraint __LINE__ "ADD-imm" rntypeterm lhstypeterm;
290347 store#add_subtype_constraint rntypeterm lhstypeterm
291- end ) rndefs);
348+ end) rndefs); *)
292349
293350 (match getopt_global_address_r (rn#to_expr floc) with
294351 | Some gaddr ->
@@ -389,7 +446,19 @@ object (self)
389446 begin
390447 log_subtype_constraint __LINE__ " MVN" tctypeterm lhstypeterm;
391448 store#add_subtype_constraint tctypeterm lhstypeterm
392- end )
449+ end );
450+
451+ (* propagate function return type *)
452+ (if rd#get_register = AR0 && (has_exit_use_r (rd#to_variable floc)) then
453+ let regvar = mk_reglhs_typevar rdreg faddr iaddr in
454+ let fvar = mk_function_typevar faddr in
455+ let fvar = add_return_capability fvar in
456+ let regterm = mk_vty_term regvar in
457+ let fterm = mk_vty_term fvar in
458+ begin
459+ log_subtype_constraint __LINE__ " MVN-freturn" regterm fterm;
460+ store#add_subtype_constraint regterm fterm
461+ end );
393462
394463 end
395464
@@ -399,15 +468,28 @@ object (self)
399468 let rmdefs = get_variable_rdefs_r (rm#to_variable floc) in
400469 let rmreg = rm#to_register in
401470 begin
402- List. iter (fun rmsym ->
403- let rmaddr = rmsym#getBaseName in
404- let rmtypevar = mk_reglhs_typevar rmreg faddr rmaddr in
405- let rmtypeterm = mk_vty_term rmtypevar in
406- let lhstypeterm = mk_vty_term lhstypevar in
407- begin
408- log_subtype_constraint __LINE__ " MVN-rdef" rmtypeterm lhstypeterm;
409- store#add_subtype_constraint rmtypeterm lhstypeterm
410- end ) rmdefs
471+ (List. iter (fun rmsym ->
472+ let rmaddr = rmsym#getBaseName in
473+ let rmtypevar = mk_reglhs_typevar rmreg faddr rmaddr in
474+ let rmtypeterm = mk_vty_term rmtypevar in
475+ let lhstypeterm = mk_vty_term lhstypevar in
476+ begin
477+ log_subtype_constraint __LINE__ " MVN-rdef" rmtypeterm lhstypeterm;
478+ store#add_subtype_constraint rmtypeterm lhstypeterm
479+ end ) rmdefs);
480+
481+ (* propagate function return type *)
482+ (if rd#get_register = AR0 && (has_exit_use_r (rd#to_variable floc)) then
483+ let regvar = mk_reglhs_typevar rdreg faddr iaddr in
484+ let fvar = mk_function_typevar faddr in
485+ let fvar = add_return_capability fvar in
486+ let regterm = mk_vty_term regvar in
487+ let fterm = mk_vty_term fvar in
488+ begin
489+ log_subtype_constraint __LINE__ " MVN-freturn" regterm fterm;
490+ store#add_subtype_constraint regterm fterm
491+ end );
492+
411493 end
412494
413495 | BitwiseOr (_ , _ , rd , rn , _ , _ ) ->
@@ -962,6 +1044,7 @@ object (self)
9621044 store#add_subtype_constraint tctypeterm rntypeterm
9631045 end ) rndefs)
9641046
1047+ (*
9651048 | LogicalShiftRight (_, _, rd, rn, rm, _) when rm#is_immediate ->
9661049 let rdreg = rd#to_register in
9671050 let lhstypevar = mk_reglhs_typevar rdreg faddr iaddr in
@@ -988,29 +1071,45 @@ object (self)
9881071 log_subtype_constraint __LINE__ "LSR-rhs" tctypeterm rntypeterm;
9891072 store#add_subtype_constraint tctypeterm rntypeterm
9901073 end) rndefs)
991-
1074+ *)
9921075 | Move (_ , _ , rd , rm , _ , _ ) when rm#is_immediate ->
993- let rmval = rm#to_numerical#toInt in
994- (* 0 provides no information about the type *)
995- if rmval = 0 then
996- ()
997- else
998- let rdreg = rd#to_register in
999- let lhstypevar = mk_reglhs_typevar rdreg faddr iaddr in
1000- let tyc = get_intvalue_type_constant rmval in
1001- let lhstypeterm = mk_vty_term lhstypevar in
1002- let tctypeterm = mk_cty_term tyc in
1003- begin
1004- log_subtype_constraint __LINE__ " MOV-imm" tctypeterm lhstypeterm;
1005- store#add_subtype_constraint tctypeterm lhstypeterm
1006- end
1076+ let rdreg = rd#to_register in
1077+ let lhstypevar = mk_reglhs_typevar rdreg faddr iaddr in
1078+ begin
1079+
1080+ (* variable introduction for lhs with type *)
1081+ (match get_regvar_type_annotation () with
1082+ | Some t ->
1083+ let opttc = mk_btype_constraint lhstypevar t in
1084+ (match opttc with
1085+ | Some tc ->
1086+ begin
1087+ log_type_constraint __LINE__ " MOV-rvintro" tc;
1088+ store#add_constraint tc
1089+ end
1090+ | _ -> () )
1091+ | _ -> () );
1092+
1093+ (let rmval = rm#to_numerical#toInt in
1094+ (* 0 provides no information about the type *)
1095+ if rmval = 0 then
1096+ ()
1097+ else
1098+ let tyc = get_intvalue_type_constant rmval in
1099+ let lhstypeterm = mk_vty_term lhstypevar in
1100+ let tctypeterm = mk_cty_term tyc in
1101+ begin
1102+ log_subtype_constraint __LINE__ " MOV-imm" tctypeterm lhstypeterm;
1103+ store#add_subtype_constraint tctypeterm lhstypeterm
1104+ end )
1105+ end
10071106
10081107 | Move (_ , _ , rd , rm , _ , _ ) when rd#get_register = rm#get_register ->
10091108 (* exclude to avoid spurious rdefs to get involved *)
10101109 ()
10111110
10121111 (* Move x, y --- x := y --- Y <: X *)
1013- | Move (_ , _ , rd , rm , _ , _ ) when rm#is_register ->
1112+ | Move (_ , c , rd , rm , _ , _ ) when rm#is_register ->
10141113 let xrm_r = rm#to_expr floc in
10151114 let rdreg = rd#to_register in
10161115 let rdtypevar = mk_reglhs_typevar rdreg faddr iaddr in
@@ -1058,19 +1157,28 @@ object (self)
10581157
10591158 (* use reaching defs *)
10601159 (let rmreg = rm#to_register in
1061- let rmvar_r = rm#to_variable floc in
1062- let rmrdefs = get_variable_rdefs_r rmvar_r in
1063- let lhstypevar = mk_reglhs_typevar rdreg faddr iaddr in
1064- List. iter (fun rmrdef ->
1065- let rmaddr = rmrdef#getBaseName in
1066- if rmaddr != " init" then
1067- let rmtypevar = mk_reglhs_typevar rmreg faddr rmaddr in
1068- let rmtypeterm = mk_vty_term rmtypevar in
1069- let lhstypeterm = mk_vty_term lhstypevar in
1070- begin
1071- log_subtype_constraint __LINE__ " MOV-reg" rmtypeterm lhstypeterm;
1072- store#add_subtype_constraint rmtypeterm lhstypeterm
1073- end ) rmrdefs)
1160+ if operand_is_zero_in_cc_context c rm then
1161+ (* This case is excluded, because the move from a register
1162+ that contains zero can be done as a substitute for the
1163+ move of an immediate value, without any relationships in
1164+ types between the source and destination register. It is
1165+ often used by compilers as a convenience, if the register
1166+ is known to have the value zero at this point. *)
1167+ ()
1168+ else
1169+ let rmvar_r = rm#to_variable floc in
1170+ let rmrdefs = get_variable_rdefs_r rmvar_r in
1171+ let lhstypevar = mk_reglhs_typevar rdreg faddr iaddr in
1172+ List. iter (fun rmrdef ->
1173+ let rmaddr = rmrdef#getBaseName in
1174+ if rmaddr != " init" then
1175+ let rmtypevar = mk_reglhs_typevar rmreg faddr rmaddr in
1176+ let rmtypeterm = mk_vty_term rmtypevar in
1177+ let lhstypeterm = mk_vty_term lhstypevar in
1178+ begin
1179+ log_subtype_constraint __LINE__ " MOV-reg" rmtypeterm lhstypeterm;
1180+ store#add_subtype_constraint rmtypeterm lhstypeterm
1181+ end ) rmrdefs)
10741182 end
10751183
10761184 | Pop (_ , _ , rl , _ ) when rl#includes_pc ->
@@ -1283,7 +1391,7 @@ object (self)
12831391
12841392 end
12851393
1286- | Subtract (_ , _ , rd , rn , _ , _ , _ ) ->
1394+ | Subtract (_ , _ , rd , rn , rm , _ , _ ) ->
12871395 let rdreg = rd#to_register in
12881396 let lhstypevar = mk_reglhs_typevar rdreg faddr iaddr in
12891397 let rndefs = get_variable_rdefs_r (rn#to_variable floc) in
@@ -1292,15 +1400,19 @@ object (self)
12921400
12931401 (* Note: Does not take into consideration the possibility of the
12941402 subtraction of two pointers *)
1295- List. iter (fun rnsym ->
1296- let rnaddr = rnsym#getBaseName in
1297- let rntypevar = mk_reglhs_typevar rnreg faddr rnaddr in
1298- let rntypeterm = mk_vty_term rntypevar in
1299- let lhstypeterm = mk_vty_term lhstypevar in
1300- begin
1301- log_subtype_constraint __LINE__ " SUB-rdef-1" rntypeterm lhstypeterm;
1302- store#add_subtype_constraint rntypeterm lhstypeterm
1303- end ) rndefs;
1403+ (if rm#is_immediate && (rm#to_numerical#toInt = 0 ) then
1404+ ()
1405+ else
1406+ List. iter (fun rnsym ->
1407+ let rnaddr = rnsym#getBaseName in
1408+ let rntypevar = mk_reglhs_typevar rnreg faddr rnaddr in
1409+ let rntypeterm = mk_vty_term rntypevar in
1410+ let lhstypeterm = mk_vty_term lhstypevar in
1411+ begin
1412+ log_subtype_constraint
1413+ __LINE__ " SUB-rdef-1" rntypeterm lhstypeterm;
1414+ store#add_subtype_constraint rntypeterm lhstypeterm
1415+ end ) rndefs);
13041416
13051417 (* propagate function return type *)
13061418 (if rd#get_register = AR0 && (has_exit_use_r (rd#to_variable floc)) then
0 commit comments