✨
This commit is contained in:
162
Fasto/CodeGen.fs
162
Fasto/CodeGen.fs
@ -613,8 +613,59 @@ let rec compileExp (e : TypedExp)
|
||||
If `n` is less than `0` then remember to terminate the program with
|
||||
an error -- see implementation of `iota`.
|
||||
*)
|
||||
| Replicate (_, _, _, _) ->
|
||||
failwith "Unimplemented code generation of replicate"
|
||||
| Replicate (n_exp, a_exp, a_type, (line, _)) ->
|
||||
let a_size = getElemSize a_type
|
||||
|
||||
let size_reg = newReg "size_reg"
|
||||
let n_code = compileExp n_exp vtable size_reg
|
||||
(* size_reg is now the integer n. *)
|
||||
|
||||
let a_reg = newReg "a_reg"
|
||||
let a_code = compileExp a_exp vtable a_reg
|
||||
|
||||
(* Check that array size N >= 0:
|
||||
if N >= 0 then jumpto safe_lab
|
||||
jumpto "_IllegalArrSizeError_"
|
||||
safe_lab: ...
|
||||
*)
|
||||
let safe_lab = newLab "safe_lab"
|
||||
let checksize = [ Mips.BGEZ (size_reg, safe_lab)
|
||||
; Mips.LI (RN5, line)
|
||||
; Mips.LA (RN6, "_Msg_IllegalArraySize_")
|
||||
; Mips.J "_RuntimeError_"
|
||||
; Mips.LABEL (safe_lab)
|
||||
]
|
||||
|
||||
let addr_reg = newReg "addr_reg"
|
||||
let i_reg = newReg "i_reg"
|
||||
let init_regs = [ Mips.ADDI (addr_reg, place, 4)
|
||||
; Mips.MOVE (i_reg, RZ) ]
|
||||
(* addr_reg is now the position of the first array element. *)
|
||||
|
||||
(* Run a loop. Keep jumping back to loop_beg until it is not the
|
||||
case that i_reg < size_reg, and then jump to loop_end. *)
|
||||
let loop_beg = newLab "loop_beg"
|
||||
let loop_end = newLab "loop_end"
|
||||
let tmp_reg = newReg "tmp_reg"
|
||||
let loop_header = [ Mips.LABEL (loop_beg)
|
||||
; Mips.SUB (tmp_reg, i_reg, size_reg)
|
||||
; Mips.BGEZ (tmp_reg, loop_end)
|
||||
]
|
||||
(* 'arr[i] = a' *)
|
||||
let loop_replicate = [ mipsStore a_size (a_reg, addr_reg, 0) ]
|
||||
let loop_footer = [ Mips.ADDI (addr_reg, addr_reg, 4)
|
||||
; Mips.ADDI (i_reg, i_reg, 1)
|
||||
; Mips.J loop_beg
|
||||
; Mips.LABEL loop_end
|
||||
]
|
||||
n_code
|
||||
@ a_code
|
||||
@ checksize
|
||||
@ dynalloc (size_reg, place, Int)
|
||||
@ init_regs
|
||||
@ loop_header
|
||||
@ loop_replicate
|
||||
@ loop_footer
|
||||
|
||||
(* TODO project task 2: see also the comment to replicate.
|
||||
(a) `filter(f, arr)`: has some similarity with the implementation of map.
|
||||
@ -631,8 +682,59 @@ let rec compileExp (e : TypedExp)
|
||||
counter computed in step (c). You do this of course with a
|
||||
`Mips.SW(counter_reg, place, 0)` instruction.
|
||||
*)
|
||||
| Filter (_, _, _, _) ->
|
||||
failwith "Unimplemented code generation of filter"
|
||||
| Filter (farg, arr_exp, a_type, pos) ->
|
||||
let size_reg = newReg "size_reg" (* size of input/output array *)
|
||||
let arr_reg = newReg "arr_reg" (* address of array *)
|
||||
let elem_reg = newReg "elem_reg" (* address of single element *)
|
||||
let res_reg = newReg "res_reg"
|
||||
let bool_reg = newReg "bool_reg"
|
||||
let arr_code = compileExp arr_exp vtable arr_reg
|
||||
|
||||
let get_size = [ Mips.LW (size_reg, arr_reg, 0) ]
|
||||
|
||||
let addr_reg = newReg "addr_reg" (* address of element in new array *)
|
||||
let i_reg = newReg "i_reg"
|
||||
let j_reg = newReg "j_reg"
|
||||
let init_regs = [ Mips.ADDI (addr_reg, place, 4)
|
||||
; Mips.MOVE (i_reg, RZ)
|
||||
; Mips.MOVE (j_reg, RZ)
|
||||
; Mips.ADDI (elem_reg, arr_reg, 4)
|
||||
]
|
||||
let loop_beg = newLab "loop_beg"
|
||||
let loop_end = newLab "loop_end"
|
||||
let not_true = newLab "not_true"
|
||||
let tmp_reg = newReg "tmp_reg"
|
||||
let loop_header = [ Mips.LABEL (loop_beg)
|
||||
; Mips.SUB (tmp_reg, i_reg, size_reg)
|
||||
; Mips.BGEZ (tmp_reg, loop_end) ]
|
||||
(* map is 'arr[i] = f(old_arr[i])'. *)
|
||||
let a_size = getElemSize a_type
|
||||
let loop_map =
|
||||
[ mipsLoad a_size (res_reg, elem_reg, 0)
|
||||
; Mips.ADDI(elem_reg, elem_reg, elemSizeToInt a_size)
|
||||
]
|
||||
@ applyFunArg(farg, [res_reg], vtable, bool_reg, pos)
|
||||
@
|
||||
[ Mips.BEQ (bool_reg, RZ, not_true)
|
||||
; mipsStore a_size (res_reg, addr_reg, 0)
|
||||
; Mips.ADDI (j_reg, j_reg, 1)
|
||||
; Mips.ADDI (addr_reg, addr_reg, elemSizeToInt a_size)
|
||||
]
|
||||
|
||||
let loop_footer =
|
||||
[ Mips.LABEL not_true
|
||||
; Mips.ADDI (i_reg, i_reg, 1)
|
||||
; Mips.J loop_beg
|
||||
; Mips.LABEL loop_end
|
||||
; Mips.SW (j_reg,place,0)
|
||||
]
|
||||
arr_code
|
||||
@ get_size
|
||||
@ dynalloc (size_reg, place, a_type)
|
||||
@ init_regs
|
||||
@ loop_header
|
||||
@ loop_map
|
||||
@ loop_footer
|
||||
|
||||
(* TODO project task 2: see also the comment to replicate.
|
||||
`scan(f, ne, arr)`: you can inspire yourself from the implementation of
|
||||
@ -641,8 +743,56 @@ let rec compileExp (e : TypedExp)
|
||||
the current location of the result iterator at every iteration of
|
||||
the loop.
|
||||
*)
|
||||
| Scan (_, _, _, _, _) ->
|
||||
failwith "Unimplemented code generation of scan"
|
||||
| Scan (farg, e_exp, arr_exp, a_type, pos) ->
|
||||
let size_reg = newReg "size_reg" (* size of input/output array *)
|
||||
let arr_reg = newReg "arr_reg" (* address of array *)
|
||||
let elem_reg = newReg "elem_reg" (* address of single element *)
|
||||
let res_reg = newReg "res_reg"
|
||||
let nelem_reg = newReg "nelem_reg"
|
||||
|
||||
let arr_code = compileExp arr_exp vtable arr_reg
|
||||
|
||||
let e_code = compileExp e_exp vtable nelem_reg
|
||||
|
||||
let get_size = [ Mips.LW (size_reg, arr_reg, 0) ]
|
||||
|
||||
let addr_reg = newReg "addr_reg" (* address of element in new array *)
|
||||
let i_reg = newReg "i_reg"
|
||||
let init_regs = [ Mips.ADDI (addr_reg, place, 4)
|
||||
; Mips.MOVE (i_reg, RZ)
|
||||
; Mips.ADDI (elem_reg, arr_reg, 4)
|
||||
]
|
||||
let loop_beg = newLab "loop_beg"
|
||||
let loop_end = newLab "loop_end"
|
||||
let tmp_reg = newReg "tmp_reg"
|
||||
let loop_header = [ Mips.LABEL (loop_beg)
|
||||
; Mips.SUB (tmp_reg, i_reg, size_reg)
|
||||
; Mips.BGEZ (tmp_reg, loop_end) ]
|
||||
(* map is 'arr[i] = f(old_arr[i])'. *)
|
||||
let a_size = getElemSize a_type
|
||||
let loop_map =
|
||||
[ mipsLoad a_size (res_reg, elem_reg, 0)
|
||||
; Mips.ADDI(elem_reg, elem_reg, elemSizeToInt a_size)
|
||||
]
|
||||
@ applyFunArg(farg, [nelem_reg ; res_reg], vtable, nelem_reg, pos)
|
||||
@
|
||||
[ mipsStore a_size (nelem_reg, addr_reg, 0)
|
||||
; Mips.ADDI (addr_reg, addr_reg, elemSizeToInt a_size)
|
||||
]
|
||||
|
||||
let loop_footer =
|
||||
[ Mips.ADDI (i_reg, i_reg, 1)
|
||||
; Mips.J loop_beg
|
||||
; Mips.LABEL loop_end
|
||||
]
|
||||
arr_code
|
||||
@ e_code
|
||||
@ get_size
|
||||
@ dynalloc (size_reg, place, a_type)
|
||||
@ init_regs
|
||||
@ loop_header
|
||||
@ loop_map
|
||||
@ loop_footer
|
||||
|
||||
and applyFunArg ( ff : TypedFunArg
|
||||
, args : Mips.reg list
|
||||
|
Reference in New Issue
Block a user