diff options
Diffstat (limited to 'compiler/m68k/cgcpu.pas')
-rw-r--r-- | compiler/m68k/cgcpu.pas | 232 |
1 files changed, 173 insertions, 59 deletions
diff --git a/compiler/m68k/cgcpu.pas b/compiler/m68k/cgcpu.pas index 39b38ceaf0..2d0220c16a 100644 --- a/compiler/m68k/cgcpu.pas +++ b/compiler/m68k/cgcpu.pas @@ -108,6 +108,7 @@ unit cgcpu; tcg64f68k = class(tcg64f32) procedure a_op64_reg_reg(list : TAsmList;op:TOpCG; size: tcgsize; regsrc,regdst : tregister64);override; procedure a_op64_const_reg(list : TAsmList;op:TOpCG; size: tcgsize; value : int64;regdst : tregister64);override; + procedure a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64);override; end; { This function returns true if the reference+offset is valid. @@ -377,8 +378,9 @@ unit cgcpu; if use_push(cgpara) then begin { Record copy? } - if (cgpara.size in [OS_NO,OS_F64]) or (size=OS_NO) then + if (cgpara.size in [OS_NO,OS_F64]) or (size in [OS_NO,OS_F64]) then begin + //list.concat(tai_comment.create(strpnew('a_load_ref_cgpara: g_concatcopy'))); cgpara.check_simple_location; len:=align(cgpara.intsize,cgpara.alignment); g_stackpointer_alloc(list,len); @@ -751,7 +753,11 @@ unit cgcpu; list.concat(taicpu.op_reg(A_CLR,S_L,register)) else begin - if (longint(a) >= low(shortint)) and (longint(a) <= high(shortint)) then + { Prefer MOV3Q if applicable, it allows replacement spilling for register } + if (current_settings.cputype in [cpu_isa_b,cpu_isa_c]) and + ((longint(a)=-1) or ((longint(a)>0) and (longint(a)<8))) then + list.concat(taicpu.op_const_reg(A_MOV3Q,S_L,longint(a),register)) + else if (longint(a) >= low(shortint)) and (longint(a) <= high(shortint)) then list.concat(taicpu.op_const_reg(A_MOVEQ,S_L,longint(a),register)) else begin @@ -786,11 +792,18 @@ unit cgcpu; hreg : tregister; href : treference; begin + a:=longint(a); href:=ref; fixref(list,href); + if (a=0) and not (current_settings.cputype = cpu_mc68000) then + list.concat(taicpu.op_ref(A_CLR,tcgsize2opsize[tosize],href)) + else if (tcgsize2opsize[tosize]=S_L) and + (current_settings.cputype in [cpu_isa_b,cpu_isa_c]) and + ((a=-1) or ((a>0) and (a<8))) then + list.concat(taicpu.op_const_ref(A_MOV3Q,S_L,a,href)) { for coldfire we need to go through a temporary register if we have a offset, index or symbol given } - if (current_settings.cputype in cpu_coldfire) and + else if (current_settings.cputype in cpu_coldfire) and ( (href.offset<>0) or { TODO : check whether we really need this second condition } @@ -902,10 +915,13 @@ unit cgcpu; var instr : taicpu; begin - { move to destination register } - instr:=taicpu.op_reg_reg(A_MOVE,TCGSize2OpSize[fromsize],reg1,reg2); - add_move_instruction(instr); - list.concat(instr); + { move to destination register } + if (reg1<>reg2) then + begin + instr:=taicpu.op_reg_reg(A_MOVE,TCGSize2OpSize[fromsize],reg1,reg2); + add_move_instruction(instr); + list.concat(instr); + end; sign_extend(list, fromsize, reg2); end; @@ -923,17 +939,25 @@ unit cgcpu; size:=tosize; list.concat(taicpu.op_ref_reg(A_MOVE,TCGSize2OpSize[size],href,register)); { extend the value in the register } - sign_extend(list, fromsize, register); + sign_extend(list, size, register); end; procedure tcg68k.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister); var href : treference; + hreg : tregister; begin href:=ref; fixref(list, href); - list.concat(taicpu.op_ref_reg(A_LEA,S_L,href,r)); + if not isaddressregister(r) then + begin + hreg:=getaddressregister(list); + list.concat(taicpu.op_ref_reg(A_LEA,S_L,href,hreg)); + a_load_reg_reg(list, OS_ADDR, OS_ADDR, hreg, r); + end + else + list.concat(taicpu.op_ref_reg(A_LEA,S_L,href,r)); end; @@ -941,20 +965,16 @@ unit cgcpu; var instr : taicpu; begin - { in emulation mode, only 32-bit single is supported } - if (cs_fp_emulation in current_settings.moduleswitches) or (current_settings.fputype=fpu_soft) then - instr:=taicpu.op_reg_reg(A_MOVE,S_L,reg1,reg2) - else - instr:=taicpu.op_reg_reg(A_FMOVE,tcgsize2opsize[tosize],reg1,reg2); - add_move_instruction(instr); - list.concat(instr); + instr:=taicpu.op_reg_reg(A_FMOVE,S_FX,reg1,reg2); + add_move_instruction(instr); + list.concat(instr); end; procedure tcg68k.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); - var - opsize : topsize; - href : treference; + var + opsize : topsize; + href : treference; begin opsize := tcgsize2opsize[fromsize]; { extended is not supported, since it is not available on Coldfire } @@ -962,50 +982,44 @@ unit cgcpu; internalerror(20020729); href := ref; fixref(list,href); - { in emulation mode, only 32-bit single is supported } - if (cs_fp_emulation in current_settings.moduleswitches) or (current_settings.fputype=fpu_soft) then - list.concat(taicpu.op_ref_reg(A_MOVE,S_L,href,reg)) - else - begin - list.concat(taicpu.op_ref_reg(A_FMOVE,opsize,href,reg)); - if (tosize < fromsize) then - a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg); - end; + list.concat(taicpu.op_ref_reg(A_FMOVE,opsize,href,reg)); end; procedure tcg68k.a_loadfpu_reg_ref(list: TAsmList; fromsize,tosize: tcgsize; reg: tregister; const ref: treference); var - opsize : topsize; + opsize : topsize; + href : treference; begin opsize := tcgsize2opsize[tosize]; { extended is not supported, since it is not available on Coldfire } if opsize = S_FX then internalerror(20020729); - { in emulation mode, only 32-bit single is supported } - if (cs_fp_emulation in current_settings.moduleswitches) or (current_settings.fputype=fpu_soft) then - list.concat(taicpu.op_reg_ref(A_MOVE,S_L,reg, ref)) - else - list.concat(taicpu.op_reg_ref(A_FMOVE,opsize,reg, ref)); + href := ref; + fixref(list,href); + list.concat(taicpu.op_reg_ref(A_FMOVE,opsize,reg,href)); end; procedure tcg68k.a_loadfpu_ref_cgpara(list : TAsmList; size : tcgsize;const ref : treference;const cgpara : TCGPara); begin - case cgpara.location^.loc of - LOC_REFERENCE,LOC_CREFERENCE: - begin - case size of - OS_F64: - cg64.a_load64_ref_cgpara(list,ref,cgpara); - OS_F32: - a_load_ref_cgpara(list,size,ref,cgpara); - else - internalerror(2013021201); + if current_settings.fputype = fpu_soft then + case cgpara.location^.loc of + LOC_REFERENCE,LOC_CREFERENCE: + begin + case size of + OS_F64: + cg64.a_load64_ref_cgpara(list,ref,cgpara); + OS_F32: + a_load_ref_cgpara(list,size,ref,cgpara); + else + internalerror(2013021201); + end; end; - end; - else - inherited a_loadfpu_ref_cgpara(list,size,ref,cgpara); - end; + else + inherited a_loadfpu_ref_cgpara(list,size,ref,cgpara); + end + else + inherited a_loadfpu_ref_cgpara(list,size,ref,cgpara); end; @@ -1100,10 +1114,41 @@ unit cgcpu; begin scratch_reg := force_to_dataregister(list, size, reg); sign_extend(list, size, scratch_reg); - if (a >= 1) and (a <= 8) then + + { some special cases which can generate smarter code + using the SWAP instruction } + if (a = 16) then + begin + if (op = OP_SHL) then + begin + list.concat(taicpu.op_reg(A_SWAP,S_NO,scratch_reg)); + list.concat(taicpu.op_reg(A_CLR,S_W,scratch_reg)); + end + else if (op = OP_SHR) then + begin + list.concat(taicpu.op_reg(A_CLR,S_W,scratch_reg)); + list.concat(taicpu.op_reg(A_SWAP,S_NO,scratch_reg)); + end + else if (op = OP_SAR) then + begin + list.concat(taicpu.op_reg(A_SWAP,S_NO,scratch_reg)); + list.concat(taicpu.op_reg(A_EXT,S_L,scratch_reg)); + end + else if (op = OP_ROR) or (op = OP_ROL) then + list.concat(taicpu.op_reg(A_SWAP,S_NO,scratch_reg)) + end + else if (a >= 1) and (a <= 8) then begin list.concat(taicpu.op_const_reg(opcode, S_L, a, scratch_reg)); end + else if (a >= 9) and (a < 16) then + begin + { Use two ops instead of const -> reg + shift with reg, because + this way is the same in length and speed but has less register + pressure } + list.concat(taicpu.op_const_reg(opcode, S_L, 8, scratch_reg)); + list.concat(taicpu.op_const_reg(opcode, S_L, a-8, scratch_reg)); + end else begin { move const to a register first } @@ -1398,6 +1443,13 @@ unit cgcpu; procedure tcg68k.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); begin + if (current_settings.cputype in cpu_coldfire-[cpu_isa_b,cpu_isa_c]) then + begin + sign_extend(list,size,reg1); + sign_extend(list,size,reg2); + size:=OS_INT; + end; + list.concat(taicpu.op_reg_reg(A_CMP,tcgsize2opsize[size],reg1,reg2)); { emit the actual jump to the label } a_jmp_cond(list,cmp_op,l); @@ -1473,10 +1525,8 @@ unit cgcpu; hp2 : treference; hl : tasmlabel; srcref,dstref : treference; - orglen : tcgint; begin hregister := getintregister(list,OS_INT); - orglen:=len; { from 12 bytes movs is being used } if ((len<=8) or (not(cs_opt_size in current_settings.optimizerswitches) and (len<=12))) then @@ -1568,7 +1618,28 @@ unit cgcpu; end; procedure tcg68k.g_overflowcheck(list: TAsmList; const l:tlocation; def:tdef); + var + hl : tasmlabel; + ai : taicpu; + cond : TAsmCond; begin + if not(cs_check_overflow in current_settings.localswitches) then + exit; + current_asmdata.getjumplabel(hl); + if not ((def.typ=pointerdef) or + ((def.typ=orddef) and + (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar, + pasbool8,pasbool16,pasbool32,pasbool64]))) then + cond:=C_VC + else + cond:=C_CC; + ai:=Taicpu.Op_Sym(A_Bxx,S_NO,hl); + ai.SetCondition(cond); + ai.is_jmp:=true; + list.concat(ai); + + a_call_name(list,'FPC_OVERFLOW',false); + a_label(list,hl); end; procedure tcg68k.g_proc_entry(list: TAsmList; localsize: longint; nostackframe:boolean); @@ -1582,13 +1653,13 @@ unit cgcpu; if (localsize < 0) then internalerror(2006122601); - { Not to complicate the code generator too much, and since some } - { of the systems only support this format, the localsize cannot } - { exceed 32K in size. } if (localsize > high(smallint)) then - CGMessage(cg_e_localsize_too_big); - - list.concat(taicpu.op_reg_const(A_LINK,S_W,NR_FRAME_POINTER_REG,-localsize)); + begin + list.concat(taicpu.op_reg_const(A_LINK,S_W,NR_FRAME_POINTER_REG,0)); + list.concat(taicpu.op_const_reg(A_SUBA,S_L,localsize,NR_STACK_POINTER_REG)); + end + else + list.concat(taicpu.op_reg_const(A_LINK,S_W,NR_FRAME_POINTER_REG,-localsize)); end; end; @@ -1698,6 +1769,7 @@ unit cgcpu; { calculate temp. size } size:=0; + hreg:=NR_NO; for r:=low(saved_standard_registers) to high(saved_standard_registers) do if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then begin @@ -1724,9 +1796,16 @@ unit cgcpu; include(current_procinfo.flags,pi_has_saved_regs); { Copy registers to temp } + { NOTE: virtual registers allocated here won't be translated --> no higher-level stuff. } href:=current_procinfo.save_regs_ref; + if (href.offset<low(smallint)) and (current_settings.cputype in cpu_coldfire) then + begin + list.concat(taicpu.op_reg_reg(A_MOVE,S_L,href.base,NR_A0)); + list.concat(taicpu.op_const_reg(A_ADDA,S_L,href.offset,NR_A0)); + reference_reset_base(href,NR_A0,0,sizeof(pint)); + end; if size = sizeof(aint) then - a_load_reg_ref(list, OS_32, OS_32, hreg, href) + list.concat(taicpu.op_reg_ref(A_MOVE,S_L,hreg,href)) else list.concat(taicpu.op_regset_ref(A_MOVEM,S_L,dataregs,addrregs,href)); end; @@ -1750,6 +1829,7 @@ unit cgcpu; exit; { Copy registers from temp } size:=0; + hreg:=NR_NO; for r:=low(saved_standard_registers) to high(saved_standard_registers) do if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then begin @@ -1777,8 +1857,14 @@ unit cgcpu; { Restore registers from temp } href:=current_procinfo.save_regs_ref; + if (href.offset<low(smallint)) and (current_settings.cputype in cpu_coldfire) then + begin + list.concat(taicpu.op_reg_reg(A_MOVE,S_L,href.base,NR_A0)); + list.concat(taicpu.op_const_reg(A_ADDA,S_L,href.offset,NR_A0)); + reference_reset_base(href,NR_A0,0,sizeof(pint)); + end; if size = sizeof(aint) then - a_load_ref_reg(list, OS_32, OS_32, href, hreg) + list.concat(taicpu.op_ref_reg(A_MOVE,S_L,href,hreg)) else list.concat(taicpu.op_ref_regset(A_MOVEM,S_L,href,dataregs,addrregs)); @@ -2097,6 +2183,34 @@ unit cgcpu; end; + procedure tcg64f68k.a_op64_ref_reg(list : TAsmList;op:TOpCG;size : tcgsize;const ref : treference;reg : tregister64); + var + tempref : treference; + begin + case op of + OP_NEG,OP_NOT: + begin + a_load64_ref_reg(list,ref,reg); + a_op64_reg_reg(list,op,size,reg,reg); + end; + + OP_AND,OP_OR: + begin + tempref:=ref; + tcg68k(cg).fixref(list,tempref); + inc(tempref.offset,4); + list.concat(taicpu.op_ref_reg(topcg2tasmop[op],S_L,tempref,reg.reglo)); + dec(tempref.offset,4); + list.concat(taicpu.op_ref_reg(topcg2tasmop[op],S_L,tempref,reg.reghi)); + end; + else + { XOR does not allow reference for source; ADD/SUB do not allow reference for + high dword, although low dword can still be handled directly. } + inherited a_op64_ref_reg(list,op,size,ref,reg); + end; + end; + + procedure tcg64f68k.a_op64_const_reg(list : TAsmList;op:TOpCG;size: tcgsize; value : int64;regdst : tregister64); var lowvalue : cardinal; |