@@ -692,8 +692,7 @@ let string_of_quad (f:hreg_formatter) (q:quad) : string =
692
692
type emitter = { mutable emit_pc : int ;
693
693
mutable emit_next_vreg : int option ;
694
694
mutable emit_next_spill : int ;
695
- emit_preallocator : (quad ' -> quad ');
696
- emit_is_2addr : bool ;
695
+ emit_target_specific : (emitter -> quad -> unit );
697
696
mutable emit_quads : quads ;
698
697
emit_annotations : (int ,string ) Hashtbl .t ;
699
698
emit_size_cache : ((size ,operand) Hashtbl .t ) Stack .t ;
@@ -712,17 +711,15 @@ let deadq = { quad_fixup = None;
712
711
713
712
714
713
let new_emitter
715
- (preallocator :quad' -> quad' )
716
- (is_2addr :bool )
714
+ (emit_target_specific :emitter -> quad -> unit )
717
715
(vregs_ok :bool )
718
716
(node :node_id option )
719
717
: emitter =
720
718
{
721
719
emit_pc = 0 ;
722
720
emit_next_vreg = (if vregs_ok then Some 0 else None );
723
721
emit_next_spill = 0 ;
724
- emit_preallocator = preallocator;
725
- emit_is_2addr = is_2addr;
722
+ emit_target_specific = emit_target_specific;
726
723
emit_quads = Array. create 4 badq;
727
724
emit_annotations = Hashtbl. create 0 ;
728
725
emit_size_cache = Stack. create () ;
@@ -837,218 +834,30 @@ let append_quad
837
834
e.emit_pc < - e.emit_pc + 1
838
835
;;
839
836
837
+ let default_mov q' =
838
+ match q' with
839
+ Binary b ->
840
+ begin
841
+ match b.binary_op with
842
+ IDIV | IMUL | IMOD -> IMOV
843
+ | _ -> UMOV
844
+ end
845
+ | Unary u ->
846
+ begin
847
+ match u.unary_op with
848
+ IMOV -> IMOV
849
+ | _ -> UMOV
850
+ end
851
+ | _ -> UMOV
852
+ ;;
840
853
841
854
let emit_full
842
855
(e :emitter )
843
856
(fix :fixup option )
844
857
(q' :quad' )
845
858
: unit =
846
- let fixup = ref fix in
847
- let emit_quad_bottom q' =
848
- append_quad e { quad_body = q';
849
- quad_fixup = (! fixup) };
850
- fixup := None ;
851
- in
852
-
853
- let emit_quad (q' :quad' ) : unit =
854
- (* re-decay any freshly generated mem-mem movs. *)
855
- match q' with
856
- Unary { unary_dst = Mem (dst_mem , ScalarTy src_st );
857
- unary_src = Cell (Mem (src_mem , ScalarTy dst_st ));
858
- unary_op = op }
859
- when is_mov op ->
860
- let v = next_vreg_cell e dst_st in
861
- emit_quad_bottom
862
- (unary op v (Cell (Mem (src_mem, ScalarTy src_st))));
863
- emit_quad_bottom
864
- (unary op (Mem (dst_mem, ScalarTy dst_st)) (Cell v))
865
- | _ -> emit_quad_bottom q'
866
- in
867
-
868
- let default_mov =
869
- match q' with
870
- Binary b ->
871
- begin
872
- match b.binary_op with
873
- IDIV | IMUL | IMOD -> IMOV
874
- | _ -> UMOV
875
- end
876
- | Unary u ->
877
- begin
878
- match u.unary_op with
879
- IMOV -> IMOV
880
- | _ -> UMOV
881
- end
882
- | _ -> UMOV
883
- in
884
-
885
- let emit_mov (dst :cell ) (src :operand ) : unit =
886
- emit_quad (unary default_mov dst src)
887
- in
888
-
889
- let mov_if_operands_differ
890
- (old_op :operand ) (new_op :operand )
891
- : unit =
892
- if (new_op <> old_op)
893
- then
894
- match new_op with
895
- (Cell new_cell ) ->
896
- emit_mov new_cell old_op
897
- | _ -> ()
898
- in
899
-
900
- let mov_if_two_operands_differ
901
- (old_lhs_op :operand ) (new_lhs_op :operand )
902
- (old_rhs_op :operand ) (new_rhs_op :operand )
903
- : unit =
904
- (*
905
- * This is sufficiently obscure that it deserves an explanation.
906
- *
907
- * The main idea here is to do two "mov_if_operands_differ" calls,
908
- * such as one might have when setting up a binary quad.
909
- *
910
- * The problem comes when you happen to hit a case like X86 div,
911
- * which preallocates *both* operands. Preallocating both means we
912
- * have to potentially issue two movs into the preallocated regs,
913
- * and the second of those movs might be a problem. Specifically:
914
- * the second mov-to-prealloc might make be moving from a
915
- * register-indirect mem cell based on a vreg, and that vreg may
916
- * wind up being assigned to an hreg that we just loaded with the
917
- * first mov. In other words, the second mov may retask the
918
- * preallocated hreg we set up in the first mov.
919
- *
920
- * You laugh, but of course this actually happens.
921
- *
922
- * So here we do a conservative thing and check to see if either
923
- * operand is memory-indirect at all. If either is, then for either
924
- * of the 'old' operands we're *about* to mov into a prealloc reg,
925
- * we first bounce them off a spill slot. Spill slots, thankfully,
926
- * we can always count on being able to address irrespective of the
927
- * opinions of the RA, as they are all just fp-relative.
928
- *
929
- * A slightly more aggressive version of this would only bounce
930
- * cases that are not fp-relative already, though doing so would
931
- * require threading the notion of what fp *is* through to
932
- * here. Possibly tighten this up in the future (or just
933
- * ... destroy this backend ASAP).
934
- *
935
- *)
936
- let has_reg_indirect op =
937
- match op with
938
- Cell (Mem _ ) -> true
939
- | _ -> false
940
- in
941
- let either_old_op_has_reg_indirect =
942
- (has_reg_indirect old_lhs_op) || (has_reg_indirect old_rhs_op)
943
- in
944
- let old_lhs_op =
945
- if either_old_op_has_reg_indirect && (new_lhs_op <> old_lhs_op)
946
- then
947
- let tmp =
948
- Mem (next_spill_slot e
949
- (ScalarTy (operand_scalar_ty old_lhs_op)))
950
- in
951
- emit_mov tmp old_lhs_op;
952
- Cell tmp
953
- else
954
- old_lhs_op
955
- in
956
- let old_rhs_op =
957
- if either_old_op_has_reg_indirect && (new_rhs_op <> old_rhs_op)
958
- then
959
- let tmp =
960
- Mem (next_spill_slot e
961
- (ScalarTy (operand_scalar_ty old_rhs_op)))
962
- in
963
- emit_mov tmp old_rhs_op;
964
- Cell tmp
965
- else
966
- old_rhs_op
967
- in
968
- mov_if_operands_differ old_lhs_op new_lhs_op;
969
- mov_if_operands_differ old_rhs_op new_rhs_op;
970
- in
971
-
972
- let mov_if_cells_differ (old_cell :cell ) (new_cell :cell ) : unit =
973
- if not (new_cell = old_cell)
974
- then
975
- emit_mov old_cell (Cell new_cell)
976
- in
977
-
978
- let emit_decayed_quad q' =
979
- match (q', e.emit_preallocator q') with
980
- (Binary b , Binary b' ) ->
981
- begin
982
- mov_if_two_operands_differ
983
- b.binary_lhs b'.binary_lhs
984
- b.binary_rhs b'.binary_rhs;
985
- if e.emit_is_2addr &&
986
- (not (b'.binary_lhs = (Cell b'.binary_dst)))
987
- then
988
- begin
989
- emit_mov b'.binary_dst b'.binary_lhs;
990
- emit_quad (Binary { b' with
991
- binary_lhs = (Cell b'.binary_dst) })
992
- end
993
- else
994
- emit_quad (Binary b');
995
- mov_if_cells_differ b.binary_dst b'.binary_dst
996
- end
997
-
998
- | (Unary u , Unary u' ) ->
999
- mov_if_operands_differ u.unary_src u'.unary_src;
1000
- (* Assume '2addr' means '1addr' for unary ops. *)
1001
- if e.emit_is_2addr &&
1002
- (u'.unary_op = NEG || u'.unary_op = NOT ) &&
1003
- (not (u'.unary_src = (Cell u'.unary_dst)))
1004
- then
1005
- begin
1006
- emit_mov u'.unary_dst u'.unary_src;
1007
- emit_quad (Unary { u' with unary_src = (Cell u'.unary_dst) })
1008
- end
1009
- else
1010
- emit_quad (Unary u');
1011
- mov_if_cells_differ u.unary_dst u'.unary_dst
1012
-
1013
- | (Cmp c , Cmp c' ) ->
1014
- mov_if_two_operands_differ
1015
- c.cmp_lhs c'.cmp_lhs
1016
- c.cmp_rhs c'.cmp_rhs;
1017
- emit_quad (Cmp c');
1018
-
1019
- | (Push op , Push op' ) ->
1020
- mov_if_operands_differ op op';
1021
- emit_quad (Push op');
1022
-
1023
- | (Pop c , Pop c' ) ->
1024
- emit_quad (Pop c');
1025
- mov_if_cells_differ c c'
1026
-
1027
- | (Call c , Call c' ) ->
1028
- emit_quad (Call c');
1029
- mov_if_cells_differ c.call_dst c'.call_dst
1030
-
1031
- | (Lea lea , Lea lea' ) ->
1032
- emit_quad (Lea lea');
1033
- mov_if_cells_differ lea.lea_dst lea'.lea_dst
1034
-
1035
- | (x , y ) ->
1036
- assert (x = y);
1037
- emit_quad x
1038
- in
1039
-
1040
- (* pre-decay mem-mem movs. *)
1041
- match q' with
1042
- Unary { unary_dst = Mem (dst_mem , ScalarTy src_st );
1043
- unary_src = Cell (Mem (src_mem , ScalarTy dst_st ));
1044
- unary_op = op }
1045
- when is_mov op ->
1046
- let v = next_vreg_cell e dst_st in
1047
- emit_decayed_quad
1048
- (unary op v (Cell (Mem (src_mem, ScalarTy src_st))));
1049
- emit_decayed_quad
1050
- (unary op (Mem (dst_mem, ScalarTy dst_st)) (Cell v))
1051
- | _ -> emit_decayed_quad q'
859
+ e.emit_target_specific e { quad_body = q';
860
+ quad_fixup = fix }
1052
861
;;
1053
862
1054
863
let emit (e :emitter ) (q' :quad' ) : unit =
0 commit comments