📄 hipe_x86_x87.erl
字号:
case ?HIPE_X86_REGISTERS:is_precoloured(Reg) of true -> Temp = hipe_x86:mk_new_temp('untagged'), {[hipe_x86:mk_move(Src,Temp)], Temp}; _ -> {[], Src} end, {PushOp, [_|NewMap0]} = push(NewSrc, Map), %% We want Dst in the map rather than NewSrc. NewMap = [Dst|NewMap0], case length(PushOp) of 1 -> %% No popping of memory object on fpstack {Move++[hipe_x86:mk_fp_unop(fild, NewSrc)], NewMap}; _ -> %% H contains pop instructions. Must be kept! Head = butlast(PushOp), {Move ++ Head ++ [hipe_x86:mk_fp_unop(fild, NewSrc)], NewMap} end.do_fp_unop(I = #fp_unop{arg=Arg, op=fchs}, Liveout, Map) -> %% This is fchs, the only operation without a %% popping version. Needs special handling. case is_liveOut(Arg, Liveout) of true -> {SwitchIns, NewMap} = switch_first(Arg, Map), {SwitchIns ++ [I#fp_unop{arg=[]}], NewMap}; false -> %% Don't need to keep this instruction! %% However, we may need to pop Src from the stack. case in_map(Arg, Map) of true -> {SwitchInsn, NewMap0} = switch_first(Arg, Map), NewMap = pop(NewMap0), {SwitchInsn ++ pop_insn(), NewMap}; _ -> {[],Map} end end.do_fp_binop(#fp_binop{src=Src, dst=Dst, op=Op}, LiveOut, Map) -> case {is_liveOut(Src, LiveOut), is_liveOut(Dst, LiveOut)} of {true, true} -> keep_both(Op, Src, Dst, Map); {true, false} -> keep_src(Op, Src, Dst, Map); {false, true} -> keep_dst(Op, Src, Dst, Map); {false, false} -> %% Both Dst and Src are popped. keep_none(Op, Src, Dst, Map) end.keep_both(Op, Src, Dst, Map) -> %% Keep both Dst and Src if it is there. {SwitchInsn, NewMap} = switch_first(Dst, Map), NewSrc = get_new_opnd(Src, NewMap), Insn = format_fp_binop(Op, NewSrc, mk_st(0)), {SwitchInsn++Insn, NewMap}.keep_src(Op, Src, Dst, Map) -> %% Pop Dst but keep Src in stack if it is there. {SwitchInsn, NewMap0} = switch_first(Dst, Map), NewSrc = get_new_opnd(Src, NewMap0), NewMap = pop(NewMap0), Insn = format_fp_binop(Op, NewSrc, mk_st(0)), {SwitchInsn ++ Insn ++ pop_insn(), NewMap}.keep_dst(Op, Src, Dst, Map) -> %% Keep Dst but pop Src. %% Dst must be in stack. DstInMap = in_map(Dst, Map), SrcInMap = in_map(Src, Map), case SrcInMap of true -> case DstInMap of true -> %% Src must be popped. If Dst is on top of the stack we can %% alter the operation rather than shuffle the stack. {SwitchInsn, Insn, NewMap} = if hd(Map) =:= Dst -> NewOp = mk_op_pop(reverse_op(Op)), NewDst = get_new_opnd(Src, Map), TmpMap = lists:map(fun(X) -> if X =:= Src -> Dst; true -> X end end, Map), {[], format_fp_binop(NewOp, mk_st(0), NewDst), pop(TmpMap)}; true -> {SwitchInsn1, NewMap0} = switch_first(Src, Map), NewDst = get_new_opnd(Dst,NewMap0), NewOp = mk_op_pop(Op), {SwitchInsn1,format_fp_binop(NewOp, mk_st(0), NewDst), pop(NewMap0)} end, {SwitchInsn ++ Insn, NewMap}; _ -> %% Src is on the stack, but Dst isn't. Use memory command to avoid %% unnecessary loading instructions. {SwitchInsn, NewMap0} = switch_first(Src, Map), NewOp = reverse_op(Op), NewMap = [Dst] ++ tl(NewMap0), Insn = format_fp_binop(NewOp, Dst, mk_st(0)), {SwitchInsn ++ Insn, NewMap} end; _ -> %% Src isn't in the map so it doesn't have to be popped. {SwitchInsn, NewMap} = switch_first(Dst, Map), {SwitchInsn ++ [#fp_unop{arg=Src,op=Op}], NewMap} end.keep_none(Op, Src, Dst, Map) -> %% Dst must be on stack. {PushInsn, NewMap0} = case in_map(Dst, Map) of true -> {[], Map}; _ -> push(Dst, Map) end, case in_map(Src, NewMap0) of true -> %% Src must be popped. {SwitchInsn1, NewMap1} = switch_first(Src, NewMap0), NewOp = mk_op_pop(Op), NewDst = get_new_opnd(Dst,NewMap1), NewMap2 = pop(NewMap1), %% Then Dst has to be popped. {PopInsn,NewMap} = pop_member(Dst,NewMap2), Insn = format_fp_binop(NewOp, mk_st(0), NewDst), {PushInsn ++ SwitchInsn1 ++ Insn ++ PopInsn, NewMap}; _ -> %% Src isn't in the map so it doesn't have to be popped. {SwitchInsn, NewMap1} = switch_first(Dst, NewMap0), NewMap = pop(NewMap1), {SwitchInsn ++ [#fp_unop{arg=Src,op=Op}] ++ pop_insn(), NewMap} end.format_fp_binop(Op, Src=#x86_temp{}, Dst=#x86_fpreg{reg=Reg}) -> %% Handle that st(0) is sometimes implicit. if Reg =:= 0 -> [hipe_x86:mk_fp_unop(Op, Src)]; true -> [hipe_x86:mk_fp_binop(Op, Src, Dst)] end;format_fp_binop(Op, Src, Dst) -> [hipe_x86:mk_fp_binop(Op, Src, Dst)].in_map(X, Map) -> lists:member(X, Map).push_list(L, Map) -> push_list(L, Map, []).push_list([H|T], Map, Acc) -> {Insn, NewMap} = push(H,Map), push_list(T, NewMap, Acc++Insn);push_list([], Map, Acc) -> {Acc, Map}.push(X, Map0) -> {PopInsn, Map} = if length(Map0) > 7 -> pop_a_temp(Map0); true -> {[], Map0} end, NewX = get_new_opnd(X,Map), NewMap = [X | Map], PushOp = [hipe_x86:mk_fp_unop(fld, NewX)], {PopInsn ++ PushOp, NewMap}.pop([_|Map]) -> Map.pop_insn() -> [hipe_x86:mk_fp_unop('fstp',mk_st(0))].pop_dead(Dead, Map) -> Dead0 = [X || X <- Map, lists:member(X,Dead)], pop_dead(Dead0, Map, []).pop_dead([D|Dead], Map, Code) -> {I, NewMap0} = switch_first(D, Map), NewMap = pop(NewMap0), Store = case D of #x86_temp{} -> [hipe_x86:mk_fp_unop('fstp', D)]; _ -> pop_insn() end, pop_dead(Dead, NewMap, Code++I++Store);pop_dead([], Map, Code) -> {Code,Map}.pop_all(Map) -> {Code, _} = pop_dead(Map, Map), Code.pop_member(Member, Map) -> {Head,[_|T]} = lists:splitwith(fun(X)->X/=Member end,Map), {[hipe_x86:mk_fp_unop('fstp', mk_st(get_pos(Member, Map, 0)))], Head++T}.pop_a_temp(Map) -> Temp = find_a_temp(Map), {SwitchInsn, NewMap0} = switch_first(Temp, Map), NewMap = pop(NewMap0), {SwitchInsn ++ [hipe_x86:mk_fp_unop('fstp', Temp)], NewMap}.find_a_temp([H = #x86_temp{}|_]) -> H;find_a_temp([_|T]) -> find_a_temp(T);find_a_temp([]) -> ?EXIT({noTempOnFPStack,{}}).switch_first(X, Map = [H|_]) -> Pos = get_pos(X, Map, 0), case Pos of 0 -> {[], Map}; notFound -> push(X, Map); _ -> {[_|Head], [_|Tail]} = lists:splitwith(fun(Y)->Y/=X end, Map), NewMap = [X|Head] ++ [H|Tail], Ins = hipe_x86:mk_fp_unop(fxch, mk_st(Pos)), {[Ins], NewMap} end;switch_first(X, Map) -> push(X, Map).get_pos(X, [H|T], Pos) -> if X =:= H -> Pos; true -> get_pos(X, T, Pos+1) end;get_pos(_, [], _) -> notFound.get_new_opnd(X, Map) -> I = get_pos(X, Map, 0), case I of notFound -> %% The operand is probably a spilled float. X; _ -> mk_st(I) end.is_fp(#x86_fpreg{}) -> true;is_fp(#x86_mem{type=Type}) -> Type =:= 'double';is_fp(#x86_temp{type=Type}) -> Type =:= 'double'.handle_insn(I) -> case I of #fmove{} -> true; #fp_unop{} -> true; #fp_binop{} -> true; #pseudo_call{}->true;%% #ret{}-> true; _ -> false end.is_liveOut(X, LiveOut) -> ordsets:is_element(X, LiveOut).mk_st(X) -> hipe_x86:mk_fpreg(X, false).reverse_op(Op) -> case Op of 'fsub' -> 'fsubr'; 'fdiv' -> 'fdivr'; 'fsubr'-> 'fsub'; 'fdivr' -> 'fdiv'; _ -> Op end.mk_op_pop(Op) -> case Op of 'fadd'-> 'faddp'; 'fdiv' -> 'fdivp'; 'fdivr' -> 'fdivrp'; 'fmul' -> 'fmulp'; 'fsub' -> 'fsubp'; 'fsubr' -> 'fsubrp'; _ -> ?EXIT({operandHasNoPopVariant,{Op}}) end.butlast([X|Xs]) -> butlast(Xs,X).butlast([],_) -> [];butlast([X|Xs],Y) -> [Y|butlast(Xs,X)].%%pp_insn(Op, Src, Dst) ->%% pp([hipe_x86:mk_fp_binop(Op, Src, Dst)]).%%pp([I|Ins]) ->%% hipe_x86_pp:pp_insn(I),%% pp(Ins);%%pp([]) ->%% [].pseudo_pop(Map) when length(Map) > 0 -> Dst = hipe_x86:mk_new_temp('double'), pseudo_pop(Dst, length(Map), []);pseudo_pop(_) -> [].pseudo_pop(Dst, St, Acc) when St > 1 ->%% Store all members of the stack to a single temporary to force %% any floating point overflow exceptions to occur even though we%% don't have overflow for the extended double precision in the x87. pseudo_pop(Dst, St-1, [hipe_x86:mk_fp_unop('fxch', mk_st(St-1)), hipe_x86:mk_fp_unop('fst', Dst), hipe_x86:mk_fp_unop('fxch', mk_st(St-1)) |Acc]);pseudo_pop(Dst, _St, Acc) -> [hipe_x86:mk_fp_unop('fst', Dst)|Acc].
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -