diff options
Diffstat (limited to 'compiler/m68k/cgcpu.pas')
-rw-r--r-- | compiler/m68k/cgcpu.pas | 297 |
1 files changed, 260 insertions, 37 deletions
diff --git a/compiler/m68k/cgcpu.pas b/compiler/m68k/cgcpu.pas index 95547958bf..3a3ab84c0f 100644 --- a/compiler/m68k/cgcpu.pas +++ b/compiler/m68k/cgcpu.pas @@ -50,8 +50,10 @@ unit cgcpu; procedure a_load_const_ref(list : TAsmList; tosize: tcgsize; a : tcgint;const ref : treference);override; procedure a_load_reg_ref(list : TAsmList;fromsize,tosize : tcgsize;register : tregister;const ref : treference);override; + procedure a_load_reg_ref_unaligned(list : TAsmList;fromsize,tosize : tcgsize;register : tregister;const ref : treference);override; procedure a_load_reg_reg(list : TAsmList;fromsize,tosize : tcgsize;reg1,reg2 : tregister);override; procedure a_load_ref_reg(list : TAsmList;fromsize,tosize : tcgsize;const ref : treference;register : tregister);override; + procedure a_load_ref_reg_unaligned(list : TAsmList;fromsize,tosize : tcgsize;const ref : treference;register : tregister);override; procedure a_load_ref_ref(list : TAsmList;fromsize,tosize : tcgsize;const sref : treference;const dref : treference);override; procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override; @@ -65,6 +67,7 @@ unit cgcpu; procedure a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference); override; procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override; procedure a_op_reg_ref(list : TAsmList; Op: TOpCG; size: TCGSize; reg: TRegister; const ref: TReference); override; + procedure a_op_ref_reg(list : TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); override; procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister; l : tasmlabel);override; procedure a_cmp_const_ref_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;const ref : treference; l : tasmlabel); override; @@ -108,6 +111,8 @@ unit cgcpu; 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; + procedure a_load64_reg_ref(list : TAsmList;reg : tregister64;const ref : treference); override; + procedure a_load64_ref_reg(list : TAsmList;const ref : treference;reg : tregister64); override; end; { This function returns true if the reference+offset is valid. @@ -359,14 +364,7 @@ unit cgcpu; reference_reset_base(ref, NR_STACK_POINTER_REG, 0, tcgsize2size[pushsize]); ref.direction := dir_dec; - if tcgsize2size[paraloc^.size]<cgpara.alignment then - begin - tmpreg:=getintregister(list,pushsize); - a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg); - list.concat(taicpu.op_reg_ref(A_MOVE,tcgsize2opsize[pushsize],tmpreg,ref)); - end - else - list.concat(taicpu.op_ref_ref(A_MOVE,tcgsize2opsize[pushsize],href,ref)); + a_load_ref_ref(list,int_cgsize(tcgsize2size[paraloc^.size]),pushsize,href,ref); end; var @@ -391,7 +389,7 @@ unit cgcpu; if tcgsize2size[cgpara.size]<>tcgsize2size[size] then internalerror(200501161); { We need to push the data in reverse order, - therefor we use a recursive algorithm } + therefore we use a recursive algorithm } pushdata(cgpara.location,0); end end @@ -708,6 +706,12 @@ unit cgcpu; hreg : tregister; href : treference; begin + if needs_unaligned(ref.alignment,tosize) then + begin + inherited; + exit; + end; + a:=longint(a); href:=ref; fixref(list,href,false); @@ -752,6 +756,13 @@ unit cgcpu; href : treference; hreg : tregister; begin + if needs_unaligned(ref.alignment,tosize) then + begin + //list.concat(tai_comment.create(strpnew('a_load_reg_ref calling unaligned'))); + a_load_reg_ref_unaligned(list,fromsize,tosize,register,ref); + exit; + end; + href := ref; hreg := register; fixref(list,href,false); @@ -765,6 +776,55 @@ unit cgcpu; end; + procedure tcg68k.a_load_reg_ref_unaligned(list : TAsmList;fromsize,tosize : tcgsize;register : tregister;const ref : treference); + var + tmpref : treference; + tmpreg, + tmpreg2 : tregister; + begin + if not needs_unaligned(ref.alignment,tosize) then + begin + a_load_reg_ref(list,fromsize,tosize,register,ref); + exit; + end; + + list.concat(tai_comment.create(strpnew('a_load_reg_ref_unaligned: generating unaligned store'))); + + tmpreg2:=getaddressregister(list); + tmpref:=ref; + inc(tmpref.offset,tcgsize2size[tosize]); + a_loadaddr_ref_reg(list,ref,tmpreg2); + reference_reset_base(tmpref,tmpreg2,0,1); + tmpref.direction:=dir_none; + + tmpreg:=getintregister(list,tosize); + a_load_reg_reg(list,fromsize,tosize,register,tmpreg); + + case tosize of + OS_16,OS_S16: + begin + list.concat(taicpu.op_reg_ref(A_MOVE,S_B,tmpreg,tmpref)); + list.concat(taicpu.op_const_reg(A_LSR,S_W,8,tmpreg)); + tmpref.direction:=dir_dec; + list.concat(taicpu.op_reg_ref(A_MOVE,S_B,tmpreg,tmpref)); + end; + OS_32,OS_S32: + begin + list.concat(taicpu.op_reg_ref(A_MOVE,S_B,tmpreg,tmpref)); + tmpref.direction:=dir_dec; + list.concat(taicpu.op_const_reg(A_LSR,S_W,8,tmpreg)); + list.concat(taicpu.op_reg_ref(A_MOVE,S_B,tmpreg,tmpref)); + list.concat(taicpu.op_reg(A_SWAP,S_L,tmpreg)); + list.concat(taicpu.op_reg_ref(A_MOVE,S_B,tmpreg,tmpref)); + list.concat(taicpu.op_const_reg(A_LSR,S_W,8,tmpreg)); + list.concat(taicpu.op_reg_ref(A_MOVE,S_B,tmpreg,tmpref)); + end + else + internalerror(2016052201); + end; + end; + + procedure tcg68k.a_load_ref_ref(list : TAsmList;fromsize,tosize : tcgsize;const sref : treference;const dref : treference); var aref: treference; @@ -773,24 +833,38 @@ unit cgcpu; hreg: TRegister; begin usetemp:=TCGSize2OpSize[fromsize]<>TCGSize2OpSize[tosize]; + usetemp:=usetemp or (needs_unaligned(sref.alignment,fromsize) or needs_unaligned(dref.alignment,tosize)); aref := sref; bref := dref; - fixref(list,aref,false); if usetemp then begin - { if we will use a temp register, we don't need to fully resolve - the dest ref, not even on coldfire } - fixref(list,bref,false); { if we need to change the size then always use a temporary register } hreg:=getintregister(list,fromsize); - list.concat(taicpu.op_ref_reg(A_MOVE,TCGSize2OpSize[fromsize],aref,hreg)); - sign_extend(list,fromsize,tosize,hreg); - list.concat(taicpu.op_reg_ref(A_MOVE,TCGSize2OpSize[tosize],hreg,bref)); + + if needs_unaligned(sref.alignment,fromsize) then + a_load_ref_reg_unaligned(list,fromsize,tosize,sref,hreg) + else + begin + fixref(list,aref,false); + list.concat(taicpu.op_ref_reg(A_MOVE,TCGSize2OpSize[fromsize],aref,hreg)); + sign_extend(list,fromsize,tosize,hreg); + end; + + if needs_unaligned(dref.alignment,tosize) then + a_load_reg_ref_unaligned(list,tosize,tosize,hreg,dref) + else + begin + { if we use a temp register, we don't need to fully resolve + the dest ref, not even on coldfire } + fixref(list,bref,false); + list.concat(taicpu.op_reg_ref(A_MOVE,TCGSize2OpSize[tosize],hreg,bref)); + end; end else begin + fixref(list,aref,false); fixref(list,bref,current_settings.cputype in cpu_coldfire); list.concat(taicpu.op_ref_ref(A_MOVE,TCGSize2OpSize[fromsize],aref,bref)); end; @@ -822,7 +896,7 @@ unit cgcpu; add_move_instruction(instr); list.concat(instr); end; - sign_extend(list,fromsize,reg2); + sign_extend(list,fromsize,tosize,reg2); end; end; @@ -833,27 +907,98 @@ unit cgcpu; hreg : tregister; size : tcgsize; opsize: topsize; + needsext: boolean; begin + if needs_unaligned(ref.alignment,fromsize) then + begin + //list.concat(tai_comment.create(strpnew('a_load_ref_reg calling unaligned'))); + a_load_ref_reg_unaligned(list,fromsize,tosize,ref,register); + exit; + end; + href:=ref; fixref(list,href,false); - if tcgsize2size[fromsize]<tcgsize2size[tosize] then + + needsext:=tcgsize2size[fromsize]<tcgsize2size[tosize]; + if needsext then size:=fromsize else size:=tosize; opsize:=TCGSize2OpSize[size]; if isaddressregister(register) and not (opsize in [S_L]) then + hreg:=getintregister(list,OS_ADDR) + else + hreg:=register; + + if needsext and (CPUM68K_HAS_MVSMVZ in cpu_capabilities[current_settings.cputype]) and not (opsize in [S_L]) then begin - hreg:=getintregister(list,OS_ADDR); - list.concat(taicpu.op_ref_reg(A_MOVE,opsize,href,hreg)); - sign_extend(list,size,hreg); - a_load_reg_reg(list,OS_ADDR,OS_ADDR,hreg,register); + if fromsize in [OS_S8,OS_S16] then + list.concat(taicpu.op_ref_reg(A_MVS,opsize,href,hreg)) + else if fromsize in [OS_8,OS_16] then + list.concat(taicpu.op_ref_reg(A_MVZ,opsize,href,hreg)) + else + internalerror(2016050502); end - else + else begin - list.concat(taicpu.op_ref_reg(A_MOVE,opsize,href,register)); - { extend the value in the register } - sign_extend(list, size, register); + list.concat(taicpu.op_ref_reg(A_MOVE,opsize,href,hreg)); + sign_extend(list,size,hreg); end; + + if hreg<>register then + a_load_reg_reg(list,OS_ADDR,OS_ADDR,hreg,register); + end; + + + procedure tcg68k.a_load_ref_reg_unaligned(list : TAsmList;fromsize,tosize : tcgsize;const ref : treference;register : tregister); + var + tmpref : treference; + tmpreg, + tmpreg2 : tregister; + begin + if not needs_unaligned(ref.alignment,fromsize) then + begin + a_load_ref_reg(list,fromsize,tosize,ref,register); + exit; + end; + + list.concat(tai_comment.create(strpnew('a_load_ref_reg_unaligned: generating unaligned load'))); + + tmpreg2:=getaddressregister(list); + a_loadaddr_ref_reg(list,ref,tmpreg2); + reference_reset_base(tmpref,tmpreg2,0,1); + tmpref.direction:=dir_inc; + + if isaddressregister(register) then + tmpreg:=getintregister(list,OS_ADDR) + else + tmpreg:=register; + + case fromsize of + OS_16,OS_S16: + begin + list.concat(taicpu.op_ref_reg(A_MOVE,S_B,tmpref,tmpreg)); + list.concat(taicpu.op_const_reg(A_LSL,S_W,8,tmpreg)); + tmpref.direction:=dir_none; + list.concat(taicpu.op_ref_reg(A_MOVE,S_B,tmpref,tmpreg)); + sign_extend(list,fromsize,tmpreg); + end; + OS_32,OS_S32: + begin + list.concat(taicpu.op_ref_reg(A_MOVE,S_B,tmpref,tmpreg)); + list.concat(taicpu.op_const_reg(A_LSL,S_W,8,tmpreg)); + list.concat(taicpu.op_ref_reg(A_MOVE,S_B,tmpref,tmpreg)); + list.concat(taicpu.op_reg(A_SWAP,S_L,tmpreg)); + list.concat(taicpu.op_ref_reg(A_MOVE,S_B,tmpref,tmpreg)); + list.concat(taicpu.op_const_reg(A_LSL,S_W,8,tmpreg)); + tmpref.direction:=dir_none; + list.concat(taicpu.op_ref_reg(A_MOVE,S_B,tmpref,tmpreg)); + end + else + internalerror(2016052103); + end; + if tmpreg<>register then + a_load_reg_reg(list,OS_ADDR,OS_ADDR,tmpreg,register); end; @@ -1118,7 +1263,8 @@ unit cgcpu; opsize := TCGSize2OpSize[size]; { on ColdFire all arithmetic operations are only possible on 32bit } - if ((current_settings.cputype in cpu_coldfire) and (opsize <> S_L) + if needs_unaligned(ref.alignment,size) or + ((current_settings.cputype in cpu_coldfire) and (opsize <> S_L) and not (op in [OP_NONE,OP_MOVE])) then begin inherited; @@ -1284,16 +1430,22 @@ unit cgcpu; { on ColdFire all arithmetic operations are only possible on 32bit and addressing modes are limited } - if ((current_settings.cputype in cpu_coldfire) and (opsize <> S_L)) then + if needs_unaligned(ref.alignment,size) or + ((current_settings.cputype in cpu_coldfire) and (opsize <> S_L)) then begin + //list.concat(tai_comment.create(strpnew('a_op_reg_ref: inherited #1'))); inherited; exit; end; case op of OP_ADD, - OP_SUB : + OP_SUB, + OP_OR, + OP_XOR, + OP_AND: begin + //list.concat(tai_comment.create(strpnew('a_op_reg_ref: normal op'))); href:=ref; fixref(list,href,false); { areg -> ref arithmetic operations are impossible on 68k } @@ -1302,12 +1454,56 @@ unit cgcpu; list.concat(taicpu.op_reg_ref(opcode, opsize, hreg, href)); end; else begin -// list.concat(tai_comment.create(strpnew('a_op_reg_ref inherited'))); + //list.concat(tai_comment.create(strpnew('a_op_reg_ref inherited #2'))); inherited; end; end; end; + + procedure tcg68k.a_op_ref_reg(list : TAsmList; Op: TOpCG; size: TCGSize; const ref: TReference; reg: TRegister); + var + opcode : tasmop; + opsize : topsize; + href : treference; + hreg : tregister; + begin + opcode := topcg2tasmop[op]; + opsize := TCGSize2OpSize[size]; + + { on ColdFire all arithmetic operations are only possible on 32bit + and addressing modes are limited } + if needs_unaligned(ref.alignment,size) or + ((current_settings.cputype in cpu_coldfire) and (opsize <> S_L)) then + begin + //list.concat(tai_comment.create(strpnew('a_op_ref_reg: inherited #1'))); + inherited; + exit; + end; + + case op of + OP_ADD, + OP_SUB, + OP_OR, + OP_AND, + OP_MUL, + OP_IMUL: + begin + //list.concat(tai_comment.create(strpnew('a_op_ref_reg: normal op'))); + href:=ref; + { Coldfire doesn't support d(Ax,Dx) for long MULx... } + fixref(list,href,(op in [OP_MUL,OP_IMUL]) and + (current_settings.cputype in cpu_coldfire)); + list.concat(taicpu.op_ref_reg(opcode, opsize, href, reg)); + end; + else begin + //list.concat(tai_comment.create(strpnew('a_op_ref_reg inherited #2'))); + inherited; + end; + end; + end; + + procedure tcg68k.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister; l : tasmlabel); var @@ -1372,7 +1568,7 @@ unit cgcpu; begin { optimize for usage of TST here, so ref compares against zero, which is the most common case by far in the RTL code at least (KB) } - if (a = 0) then + if not needs_unaligned(ref.alignment,size) and (a = 0) then begin //list.concat(tai_comment.create(strpnew('a_cmp_const_ref_label with TST'))); tmpref:=ref; @@ -1513,7 +1709,7 @@ unit cgcpu; a_loadaddr_ref_reg(list,source,iregister); a_loadaddr_ref_reg(list,dest,jregister); - if (current_settings.cputype <> cpu_mc68000) then + if not (needs_unaligned(source.alignment,OS_INT) or needs_unaligned(dest.alignment,OS_INT)) then begin if not ((len<=8) or (not(cs_opt_size in current_settings.optimizerswitches) and (len<=16))) then begin @@ -1570,7 +1766,7 @@ unit cgcpu; list.concat(taicpu.op_sym(A_BPL,S_NO,hl)); end else - list.concat(taicpu.op_reg_sym(A_DBRA,S_L,hregister,hl)); + list.concat(taicpu.op_reg_sym(A_DBRA,S_NO,hregister,hl)); end; end; @@ -1770,7 +1966,7 @@ unit cgcpu; { 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 + if (href.offset<low(smallint)) and (current_settings.cputype in cpu_coldfire+[cpu_mc68000]) 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)); @@ -1858,7 +2054,7 @@ 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 + if (href.offset<low(smallint)) and (current_settings.cputype in cpu_coldfire+[cpu_mc68000]) 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)); @@ -2144,10 +2340,9 @@ unit cgcpu; begin tempref:=ref; tcg68k(cg).fixref(list,tempref,false); + list.concat(taicpu.op_ref_reg(topcg2tasmop[op],S_L,tempref,reg.reghi)); 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 @@ -2210,6 +2405,34 @@ unit cgcpu; end; + procedure tcg64f68k.a_load64_reg_ref(list : TAsmList;reg : tregister64;const ref : treference); + var + tmpref: treference; + begin + tmpref:=ref; + tcg68k(cg).fixref(list,tmpref,false); + cg.a_load_reg_ref(list,OS_32,OS_32,reg.reghi,tmpref); + inc(tmpref.offset,4); + cg.a_load_reg_ref(list,OS_32,OS_32,reg.reglo,tmpref); + end; + + procedure tcg64f68k.a_load64_ref_reg(list : TAsmList;const ref : treference;reg : tregister64); + var + tmpref: treference; + begin + { do not allow 64bit values to be loaded to address registers } + if isaddressregister(reg.reglo) or + isaddressregister(reg.reghi) then + internalerror(2016050501); + + tmpref:=ref; + tcg68k(cg).fixref(list,tmpref,false); + cg.a_load_ref_reg(list,OS_32,OS_32,tmpref,reg.reghi); + inc(tmpref.offset,4); + cg.a_load_ref_reg(list,OS_32,OS_32,tmpref,reg.reglo); + end; + + procedure create_codegen; begin cg := tcg68k.create; |