summaryrefslogtreecommitdiff
path: root/src/lem_interp/interp_inter_imp.lem
diff options
context:
space:
mode:
Diffstat (limited to 'src/lem_interp/interp_inter_imp.lem')
-rw-r--r--src/lem_interp/interp_inter_imp.lem313
1 files changed, 261 insertions, 52 deletions
diff --git a/src/lem_interp/interp_inter_imp.lem b/src/lem_interp/interp_inter_imp.lem
index dbc8e0e6..cbd56240 100644
--- a/src/lem_interp/interp_inter_imp.lem
+++ b/src/lem_interp/interp_inter_imp.lem
@@ -833,58 +833,6 @@ let rec interp_to_outcome mode context thunk =
end )
end
-let interp mode (IState interp_state context) =
- match interp_to_outcome mode context (fun _ -> Interp.resume mode.internal_mode interp_state Nothing) with
- | (o,_) -> o
-end
-
-val state_to_outcome_s : (instruction_state -> unit -> (string * string)) -> interp_mode -> instruction_state -> Sail_impl_base.outcome_s unit
-val outcome_to_outcome : (instruction_state -> unit -> (string * string)) -> interp_mode -> Interp_interface.outcome -> Sail_impl_base.outcome unit
-
-let rec outcome_to_outcome pp_instruction_state mode =
- let state_to_outcome_s = state_to_outcome_s pp_instruction_state in
- function
- | Interp_interface.Read_mem rk addr size _ k ->
- Sail_impl_base.Read_mem (rk,addr,size) (fun v -> state_to_outcome_s mode (k v))
- | Interp_interface.Write_mem rk addr size _ mv _ k ->
- failwith "Write_mem not supported anymore"
- | Interp_interface.Write_ea wk addr size _ state ->
- Sail_impl_base.Write_ea (wk,addr,size) (state_to_outcome_s mode state)
- | Interp_interface.Write_memv _ mv _ k ->
- Sail_impl_base.Write_memv mv (fun v -> state_to_outcome_s mode (k v))
- | Interp_interface.Barrier bk state ->
- Sail_impl_base.Barrier bk (state_to_outcome_s mode state)
- | Interp_interface.Footprint state ->
- Sail_impl_base.Footprint (state_to_outcome_s mode state)
- | Interp_interface.Read_reg r k ->
- Sail_impl_base.Read_reg r (fun v -> state_to_outcome_s mode (k v))
- | Interp_interface.Write_reg r rv state ->
- Sail_impl_base.Write_reg (r,rv) (state_to_outcome_s mode state)
- | Interp_interface.Nondet_choice _ _ ->
- failwith "Nondet_choice not supported yet"
- | Interp_interface.Escape _ _ ->
- Sail_impl_base.Escape Nothing
- | Interp_interface.Fail maybestring ->
- Sail_impl_base.Fail maybestring
- | Interp_interface.Internal maybestring maybeprint state ->
- Sail_impl_base.Internal (maybestring,maybeprint) (state_to_outcome_s mode state)
- | Interp_interface.Analysis_non_det _ _ ->
- failwith "Analysis_non_det outcome returned"
- | Interp_interface.Done ->
- Sail_impl_base.Done ()
- | Interp_interface.Error message ->
- failwith ("Interpreter error: " ^ message)
-end
-
-and state_to_outcome_s pp_instruction_state mode state =
- let next_outcome' = interp mode state in
- let next_outcome = outcome_to_outcome pp_instruction_state mode next_outcome' in
- (next_outcome, Just (pp_instruction_state state))
-
-val initial_outcome_s_of_instruction : (instruction_state -> unit -> (string * string)) -> context -> interp_mode -> instruction -> Sail_impl_base.outcome_s unit
-let initial_outcome_s_of_instruction pp_instruction_state context mode instruction =
- let state = instruction_to_istate context instruction in
- state_to_outcome_s pp_instruction_state mode state
(*Update slice potentially here*)
@@ -895,6 +843,13 @@ let reg_size = function
| Reg_f_slice i _ _ f _ (p1,p2) -> if p1 < p2 then p2-p1 +1 else p1-p2+1
end
+
+let interp mode (IState interp_state context) =
+ match interp_to_outcome mode context (fun _ -> Interp.resume mode.internal_mode interp_state Nothing) with
+ | (o,_) -> o
+end
+
+
(*ie_loop returns a tuple of event list, and a tuple ofinternal interpreter memory, bool to indicate normal or exceptional termination*)
let rec ie_loop mode register_values (IState interp_state context) =
let (Context _ direction externs reads writes write_eas write_vals barriers) = context in
@@ -968,12 +923,71 @@ let rec ie_loop mode register_values (IState interp_state context) =
| _ -> Assert_extra.failwith "interp_to_outcome may have produced a nondet action"
end ;;
+val interp_exhaustive : maybe (list (reg_name * register_value)) -> instruction_state -> list event
let interp_exhaustive register_values i_state =
let mode = make_mode_exhaustive E_big_endian in
match ie_loop mode register_values i_state with
| (events,_) -> events
end
+
+val state_to_outcome_s :
+ (instruction_state -> unit -> (string * string)) ->
+ interp_mode -> instruction_state -> Sail_impl_base.outcome_s unit
+val outcome_to_outcome :
+ (instruction_state -> unit -> (string * string)) ->
+ interp_mode -> Interp_interface.outcome -> Sail_impl_base.outcome unit
+
+let rec outcome_to_outcome pp_instruction_state mode =
+ let state_to_outcome_s =
+ state_to_outcome_s pp_instruction_state in
+ function
+ | Interp_interface.Read_mem rk addr size _ k ->
+ Sail_impl_base.Read_mem (rk,addr,size) (fun v -> state_to_outcome_s mode (k v))
+ | Interp_interface.Write_mem rk addr size _ mv _ k ->
+ failwith "Write_mem not supported anymore"
+ | Interp_interface.Write_ea wk addr size _ state ->
+ Sail_impl_base.Write_ea (wk,addr,size) (state_to_outcome_s mode state)
+ | Interp_interface.Write_memv _ mv _ k ->
+ Sail_impl_base.Write_memv mv (fun v -> state_to_outcome_s mode (k v))
+ | Interp_interface.Barrier bk state ->
+ Sail_impl_base.Barrier bk (state_to_outcome_s mode state)
+ | Interp_interface.Footprint state ->
+ Sail_impl_base.Footprint (state_to_outcome_s mode state)
+ | Interp_interface.Read_reg r k ->
+ Sail_impl_base.Read_reg r (fun v -> state_to_outcome_s mode (k v))
+ | Interp_interface.Write_reg r rv state ->
+ Sail_impl_base.Write_reg (r,rv) (state_to_outcome_s mode state)
+ | Interp_interface.Nondet_choice _ _ ->
+ failwith "Nondet_choice not supported yet"
+ | Interp_interface.Escape _ _ ->
+ Sail_impl_base.Escape Nothing
+ | Interp_interface.Fail maybestring ->
+ Sail_impl_base.Fail maybestring
+ | Interp_interface.Internal maybestring maybeprint state ->
+ Sail_impl_base.Internal (maybestring,maybeprint) (state_to_outcome_s mode state)
+ | Interp_interface.Analysis_non_det _ _ ->
+ failwith "Analysis_non_det outcome returned"
+ | Interp_interface.Done ->
+ Sail_impl_base.Done ()
+ | Interp_interface.Error message ->
+ failwith ("Interpreter error: " ^ message)
+end
+
+and state_to_outcome_s pp_instruction_state mode state =
+ let next_outcome' = interp mode state in
+ let next_outcome = outcome_to_outcome pp_instruction_state mode next_outcome' in
+ (next_outcome,
+ Just ((pp_instruction_state state),
+ (fun env -> interp_exhaustive (Just env) state))
+ )
+
+val initial_outcome_s_of_instruction : (instruction_state -> unit -> (string * string)) -> context -> interp_mode -> instruction -> Sail_impl_base.outcome_s unit
+let initial_outcome_s_of_instruction pp_instruction_state context mode instruction =
+ let state = instruction_to_istate context instruction in
+ state_to_outcome_s pp_instruction_state mode state
+
+
(*This code is no longer uptodate. If no one is using it, then we don't need to fix it
If someone is using it, this will let me know*)
(*let rec rr_ie_loop mode i_state =
@@ -1006,3 +1020,198 @@ If someone is using it, this will let me know*)
let rr_interp_exhaustive mode i_state events =
let (events',outcome) = rr_ie_loop mode i_state in ((events ++ events'),outcome)
*)
+
+
+let instruction_kind_of_event : event -> maybe instruction_kind = function
+ | E_read_mem rk _ _ _ -> Just (IK_mem_read rk)
+ | E_write_mem wk _ _ _ _ _ -> Just (IK_mem_write wk)
+ | E_write_ea wk _ _ _ -> Just (IK_mem_write wk)
+ | E_write_memv _ _ _ -> Nothing
+ | E_barrier bk -> Just (IK_barrier bk)
+ | E_footprint -> Nothing
+ | E_read_reg _ -> Nothing
+ | E_write_reg _ _ -> Nothing
+ | E_error s -> failwith ("instruction_kind_of_event error: "^s)
+ | E_escape -> Nothing (*failwith ("instruction_kind_of_event escape")*)
+ end
+(* TODO: how can we decide, looking only at the output of interp_exhaustive,
+ that an instruction is a conditional branch? *)
+
+let regs_in_of_event : event -> list reg_name = function
+ | E_read_mem _ _ _ _ -> []
+ | E_write_mem _ _ _ _ _ _ -> []
+ | E_write_ea _ _ _ _ -> []
+ | E_write_memv _ _ _ -> []
+ | E_barrier _ -> []
+ | E_footprint -> []
+ | E_read_reg r -> [r]
+ | E_write_reg _ _ -> []
+ | E_error s -> failwith ("regs_in_of_event "^s)
+ | E_escape -> [] (*failwith ("regs_in_of_event escape")*)
+ end
+
+let regs_out_of_event : event -> list reg_name = function
+ | E_read_mem _ _ _ _ -> []
+ | E_write_mem _ _ _ _ _ _ -> []
+ | E_write_ea _ _ _ _ -> []
+ | E_write_memv _ _ _ -> []
+ | E_barrier _ -> []
+ | E_footprint -> []
+ | E_read_reg _ -> []
+ | E_write_reg r _ -> [r]
+ | E_error s -> failwith ("regs_out_of_event "^s)
+ | E_escape -> [] (*failwith ("regs_out_of_event escape")*)
+ end
+
+
+let regs_feeding_memory_access_address_of_event : event -> list reg_name = function
+ | E_read_mem _ _ _ (Just rs) -> rs
+ | E_read_mem _ _ _ None -> []
+ | E_write_mem _ _ _ (Just rs) _ _ -> rs
+ | E_write_mem _ _ _ None _ _ -> []
+ | E_write_ea wk _ _ (Just rs) -> rs
+ | E_write_ea wk _ _ None -> []
+ | E_write_memv _ _ _ -> []
+ | E_barrier bk -> []
+ | E_footprint -> []
+ | E_read_reg _ -> []
+ | E_write_reg _ _ -> []
+ | E_error s -> failwith ("regs_feeding_memory_access_address_of_event " ^ s)
+ | E_escape -> [] (*failwith ("regs_feeding_memory_access_address_of_event escape")*)
+end
+
+let nia_address_of_event nia_reg (event: event) : maybe (maybe address) =
+ (* return Nothing for unknown/undef *)
+ match event with
+ | E_write_reg reg reg_value ->
+ if register_base_name reg = register_base_name nia_reg then
+ let al = match address_lifted_of_register_value reg_value with
+ | Just al -> al
+ | Nothing -> failwith "nia_register_of_event: NIA read not 64 bits"
+ end in
+ Just (address_of_address_lifted al)
+ else Nothing
+ | _ -> Nothing
+ end
+
+let nias_of_instruction
+ thread_ism
+ (nia_address: list (maybe address)) (* Nothing for unknown/undef*)
+ (regs_in: list reg_name)
+ (instruction: instruction)
+ : list nia
+ =
+ let (instruction_name, instruction_fields) = instruction in
+
+ let unknown_nia_address = List.elem Nothing nia_address in
+
+ let nias = [NIA_concrete_address addr | forall (addr MEM (List.mapMaybe id nia_address)) | true] in
+
+ (* it's a fact of the Power2.06B instruction pseudocode that in the B and Bc
+ cases there should be no Unknown values in nia_values, while in the Bclr
+ and Bcctr cases nia_values will just be Unknown and the semantics should
+ match the comments in the machineDefTypes definition of nia *)
+ (* All our other analysis is on the pseudocode directly, which is arguably
+ pleasingly robust. We could replace the nias pattern match on
+ instruction_name with something in that style if the exhaustive interpreter
+ announced register dependencies to register writes (easy) and if it could
+ check the form of the register writes to LR and CTR matches the
+ machineDefTypes nia definition *)
+ match (thread_ism, instruction_name) with
+ | ("PPCGEN_ism", "B") ->
+ let () = ensure (not unknown_nia_address)
+ "unexpected unknown/undefined address in nia_values" in
+ nias
+ | ("PPCGEN_ism", "Bc") ->
+ let () = ensure (not unknown_nia_address)
+ "unexpected unknown/undefined address in nia_values" in
+ NIA_successor :: nias
+ | ("PPCGEN_ism", "Bclr") -> [ NIA_successor; NIA_LR ]
+ | ("PPCGEN_ism", "Bcctr") -> [ NIA_successor; NIA_CTR ]
+ | ("PPCGEN_ism", "Sc") ->
+ let () = ensure (not unknown_nia_address)
+ "unexpected unknown/undefined address in nia_values" in
+ match instruction_fields with
+ | [(_, _, lev)] ->
+ (* LEV field is 7 bits long, pad it with false at beginning *)
+ if lev = [Bitc_zero;Bitc_one;Bitc_one;Bitc_one;Bitc_one;Bitc_one;Bitc_one]
+ (* (Interp_inter_imp.integer_of_byte_list (Interp_inter_imp.to_bytes (false :: bl))) = 63 *)
+ then []
+ else [NIA_successor]
+ | _ -> [ NIA_successor ]
+ end
+
+ (* AARch64 label branch (i.e. address must be known) although
+ these instructions take the address as an offset from PC, in here
+ we see the absolute address as it was extracted from the micro ops
+ just before write to PC *)
+ | ("AArch64HandSail", "BranchImmediate") -> nias
+ | ("AArch64HandSail", "BranchConditional") -> NIA_successor :: nias
+ | ("AArch64HandSail", "CompareAndBranch") -> NIA_successor :: nias
+ | ("AArch64HandSail", "TestBitAndBranch") -> NIA_successor :: nias
+
+ (* AArch64 calculated address branch *)
+ | ("AArch64HandSail", "BranchRegister") ->
+ (* do some parsing of the ast fields to figure out which register holds
+ the branching address i.e. find n in "BR <Xn>". The ast constructor
+ from armV8.sail: (reg_index,BranchType) BranchRegister; *)
+ let n_integer =
+ match instruction_fields with
+ | [(_, _, n); _] -> integer_of_bit_list n
+ | _ -> fail
+ end
+ in
+ let () = ensure (0 <= n_integer && n_integer <= 31)
+ "expected register number from 0 to 31"
+ in
+ if n_integer = 31 then
+ nias (* BR XZR *)
+ else
+ (* look for Xn (which we actually call Rn) in regs_in *)
+ let n_reg = "R" ^ (String_extra.stringFromInteger n_integer) in
+ [NIA_register r | forall (r MEM regs_in)
+ | match r with
+ | (Reg name _ _ _) -> name = n_reg
+ | _ -> false
+ end]
+
+ | ("AArch64LitmusSail", "CtrlDep") -> NIA_successor :: nias
+
+ | ("MIPS_ism", "B") -> fail
+
+ | _ ->
+ let () = ensure (not unknown_nia_address)
+ "unexpected unknown/undefined address in nia_values" in
+ [ NIA_successor ]
+ end
+
+let interp_instruction_analysis
+ (interp_exhaustive : ((list (reg_name * register_value)) -> list event))
+ instruction nia_reg ism environment =
+
+ let es = interp_exhaustive environment in
+
+ let regs_in = List.concatMap regs_in_of_event es in
+ let regs_out = List.concatMap regs_out_of_event es in
+
+ let regs_feeding_address = List.concatMap regs_feeding_memory_access_address_of_event es in
+
+ let nia_address = List.mapMaybe (nia_address_of_event nia_reg) es in
+
+ let nias = nias_of_instruction ism nia_address regs_in instruction in
+
+ let dia = DIA_none in (* FIX THIS! *)
+
+
+ let inst_kind =
+ match List.mapMaybe instruction_kind_of_event es with
+ | [] -> if List.length nias > 1 then IK_cond_branch else IK_simple
+ | inst_kind :: inst_kinds ->
+ let () = ensure (forall (inst_kind' MEM inst_kinds). inst_kind' = inst_kind)
+ "multiple instruction kinds" in
+ let () = ensure (List.length nias > 1 --> inst_kind = IK_cond_branch)
+ "multiple NIAs must be IK_cond_branch" in
+ inst_kind
+ end in
+
+ (regs_in, regs_out, regs_feeding_address, nias, dia, inst_kind)