diff options
Diffstat (limited to 'compiler/m68k')
-rw-r--r-- | compiler/m68k/aasmcpu.pas | 28 | ||||
-rw-r--r-- | compiler/m68k/cgcpu.pas | 232 | ||||
-rw-r--r-- | compiler/m68k/cpubase.pas | 9 | ||||
-rw-r--r-- | compiler/m68k/cpuinfo.pas | 35 | ||||
-rw-r--r-- | compiler/m68k/itcpugas.pas | 2 | ||||
-rw-r--r-- | compiler/m68k/n68kadd.pas | 762 | ||||
-rw-r--r-- | compiler/m68k/n68kcnv.pas | 8 | ||||
-rw-r--r-- | compiler/m68k/n68kmat.pas | 9 | ||||
-rw-r--r-- | compiler/m68k/ra68k.pas | 1 | ||||
-rw-r--r-- | compiler/m68k/ra68kmot.pas | 4 | ||||
-rw-r--r-- | compiler/m68k/rgcpu.pas | 140 | ||||
-rw-r--r-- | compiler/m68k/symcpu.pas | 14 |
12 files changed, 660 insertions, 584 deletions
diff --git a/compiler/m68k/aasmcpu.pas b/compiler/m68k/aasmcpu.pas index c9689eea24..f2d0f34104 100644 --- a/compiler/m68k/aasmcpu.pas +++ b/compiler/m68k/aasmcpu.pas @@ -464,6 +464,7 @@ type result:=operand_read; case opcode of + // CPU opcodes A_MOVE, A_MOVEQ, A_MOVEA, A_MVZ, A_MVS, A_MOV3Q, A_LEA: if opnr=1 then result:=operand_write; @@ -479,10 +480,21 @@ type A_CLR, A_SXX, A_SEQ, A_SNE, A_SLT, A_SLE, A_SGT, A_SGE, A_SCS, A_SCC, A_SMI, A_SPL, A_SF, A_ST, A_SVS, A_SVC, A_SHI, A_SLS: result:=operand_write; - A_NEG, A_NEGX, A_EXT, A_EXTB, A_NOT: + A_NEG, A_NEGX, A_EXT, A_EXTB, A_NOT, A_SWAP: result:=operand_readwrite; A_TST,A_CMP,A_CMPI: begin end; { Do nothing, default operand_read is fine here. } + + // FPU opcodes + A_FMOVE: + if opnr=1 then + result:=operand_write; + A_FADD, A_FSUB, A_FMUL, A_FDIV: + if opnr=1 then + result:=operand_readwrite; + A_FCMP: + begin end; { operand_read } + else begin internalerror(2004040903); end; @@ -508,17 +520,17 @@ type function spilling_create_store(r:tregister; const ref:treference):Taicpu; begin - case getregtype(r) of - R_INTREGISTER : - result:=taicpu.op_reg_ref(A_MOVE,S_L,r,ref); - R_ADDRESSREGISTER : - result:=taicpu.op_reg_ref(A_MOVE,S_L,r,ref); - R_FPUREGISTER : + case getregtype(r) of + R_INTREGISTER : + result:=taicpu.op_reg_ref(A_MOVE,S_L,r,ref); + R_ADDRESSREGISTER : + result:=taicpu.op_reg_ref(A_MOVE,S_L,r,ref); + R_FPUREGISTER : // no need to handle sizes here result:=taicpu.op_reg_ref(A_FMOVE,S_FS,r,ref); else internalerror(200602012); - end; + end; end; 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; diff --git a/compiler/m68k/cpubase.pas b/compiler/m68k/cpubase.pas index 0d777f32ea..021e7d32fd 100644 --- a/compiler/m68k/cpubase.pas +++ b/compiler/m68k/cpubase.pas @@ -67,7 +67,7 @@ unit cpubase; { mc64040 instructions } a_move16, { coldfire v4 instructions } - a_mov3q,a_mvz,a_mvs,a_sats, + a_mov3q,a_mvz,a_mvs,a_sats,a_byterev,a_ff1, { fpu processor instructions - directly supported only. } { ieee aware and misc. condition codes not supported } a_fabs,a_fadd, @@ -153,7 +153,7 @@ unit cpubase; { registers which may be destroyed by calls } VOLATILE_INTREGISTERS = [RS_D0,RS_D1]; - VOLATILE_FPUREGISTERS = []; + VOLATILE_FPUREGISTERS = [RS_FP0,RS_FP1]; VOLATILE_ADDRESSREGISTERS = [RS_A0,RS_A1]; type @@ -311,6 +311,7 @@ unit cpubase; } saved_standard_registers : array[0..5] of tsuperregister = (RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7); saved_address_registers : array[0..4] of tsuperregister = (RS_A2,RS_A3,RS_A4,RS_A5,RS_A6); + saved_fpu_registers : array[0..5] of tsuperregister = (RS_FP2,RS_FP3,RS_FP4,RS_FP5,RS_FP6,RS_FP7); { this is only for the generic code which is not used for this architecture } saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID); @@ -471,7 +472,9 @@ implementation R_INTREGISTER : result:=OS_32; R_FPUREGISTER : - result:=OS_F64; + { 68881 & compatibles -> 80 bit } + { CF FPU -> 64 bit, but that's unsupported for now } + result:=OS_F80; else internalerror(200303181); end; diff --git a/compiler/m68k/cpuinfo.pas b/compiler/m68k/cpuinfo.pas index 38f6f79a49..80f09b4f29 100644 --- a/compiler/m68k/cpuinfo.pas +++ b/compiler/m68k/cpuinfo.pas @@ -21,6 +21,9 @@ Interface Type bestreal = double; +{$if FPC_FULLVERSION>20700} + bestrealrec = TDoubleRec; +{$endif FPC_FULLVERSION>20700} ts32real = single; ts64real = double; ts80real = extended; @@ -48,7 +51,25 @@ Type fpu_68881 ); + tcontrollertype = + (ct_none + ); + + Const + { Is there support for dealing with multiple microcontrollers available } + { for this platform? } + ControllerSupport = false; + + { We know that there are fields after sramsize + but we don't care about this warning } + {$PUSH} + {$WARN 3177 OFF} + embedded_controllers : array [tcontrollertype] of tcontrollerdatatype = + ( + (controllertypestr:''; controllerunitstr:''; flashbase:0; flashsize:0; srambase:0; sramsize:0)); + {$POP} + { calling conventions supported by the code generator } supported_calling_conventions : tproccalloptions = [ pocall_internproc, @@ -107,19 +128,21 @@ type (CPUM68K_HAS_DBRA, { CPU supports the DBRA instruction } CPUM68K_HAS_CAS, { CPU supports the CAS instruction } CPUM68K_HAS_TAS, { CPU supports the TAS instruction } - CPUM68K_HAS_BRAL { CPU supports the BRA.L/Bcc.L instructions } + CPUM68K_HAS_BRAL, { CPU supports the BRA.L/Bcc.L instructions } + CPUM68K_HAS_ROLROR, { CPU supports the ROL/ROR and ROXL/ROXR instructions } + CPUM68K_HAS_BYTEREV { CPU supports the BYTEREV instruction } ); const cpu_capabilities : array[tcputype] of set of tcpuflags = ( { cpu_none } [], - { cpu_68000 } [CPUM68K_HAS_DBRA,CPUM68K_HAS_TAS], - { cpu_68020 } [CPUM68K_HAS_DBRA,CPUM68K_HAS_CAS,CPUM68K_HAS_TAS,CPUM68K_HAS_BRAL], - { cpu_68040 } [CPUM68K_HAS_DBRA,CPUM68K_HAS_CAS,CPUM68K_HAS_TAS,CPUM68K_HAS_BRAL], + { cpu_68000 } [CPUM68K_HAS_DBRA,CPUM68K_HAS_TAS,CPUM68K_HAS_ROLROR], + { cpu_68020 } [CPUM68K_HAS_DBRA,CPUM68K_HAS_CAS,CPUM68K_HAS_TAS,CPUM68K_HAS_BRAL,CPUM68K_HAS_ROLROR], + { cpu_68040 } [CPUM68K_HAS_DBRA,CPUM68K_HAS_CAS,CPUM68K_HAS_TAS,CPUM68K_HAS_BRAL,CPUM68K_HAS_ROLROR], { cpu_isaa } [], - { cpu_isaap } [CPUM68K_HAS_BRAL], + { cpu_isaap } [CPUM68K_HAS_BRAL,CPUM68K_HAS_BYTEREV], { cpu_isab } [CPUM68K_HAS_TAS,CPUM68K_HAS_BRAL], - { cpu_isac } [CPUM68K_HAS_TAS] + { cpu_isac } [CPUM68K_HAS_TAS,CPUM68K_HAS_BYTEREV] ); { all CPUs commonly called "coldfire" } diff --git a/compiler/m68k/itcpugas.pas b/compiler/m68k/itcpugas.pas index cfe77aae22..4e134a3e70 100644 --- a/compiler/m68k/itcpugas.pas +++ b/compiler/m68k/itcpugas.pas @@ -61,7 +61,7 @@ interface { mc64040 instructions } 'move16', { coldfire v4 instructions } - 'mov3q','mvz','mvs','sats', + 'mov3q','mvz','mvs','sats','byterev','ff1', { fpu processor instructions - directly supported only. } { ieee aware and misc. condition codes not supported } 'fabs','fadd', diff --git a/compiler/m68k/n68kadd.pas b/compiler/m68k/n68kadd.pas index a812a2ee5e..84c88e3202 100644 --- a/compiler/m68k/n68kadd.pas +++ b/compiler/m68k/n68kadd.pas @@ -32,23 +32,13 @@ interface type t68kaddnode = class(tcgaddnode) private - function cmp64_lt(left_reg,right_reg:tregister64):tregister; - function cmp64_le(left_reg,right_reg:tregister64):tregister; - function cmp64_eq(left_reg,right_reg:tregister64):tregister; - function cmp64_ne(left_reg,right_reg:tregister64):tregister; - function cmp64_ltu(left_reg,right_reg:tregister64):tregister; - function cmp64_leu(left_reg,right_reg:tregister64):tregister; - function getresflags(unsigned: boolean) : tresflags; - function getres64_register(unsigned:boolean;left_reg,right_reg:tregister64):tregister; protected procedure second_addfloat;override; procedure second_cmpfloat;override; procedure second_cmpordinal;override; procedure second_cmpsmallset;override; procedure second_cmp64bit;override; - public - function pass_1:tnode;override; end; @@ -62,198 +52,12 @@ implementation cpuinfo,pass_1,pass_2,regvars, cpupara,cgutils,procinfo, ncon,nset, - ncgutil,tgobj,rgobj,rgcpu,cgobj,hlcgobj,cg64f32; + ncgutil,tgobj,rgobj,rgcpu,cgobj,cgcpu,hlcgobj,cg64f32; {***************************************************************************** Helpers *****************************************************************************} - function t68kaddnode.cmp64_lt(left_reg,right_reg:tregister64):tregister; - var - labelcmp64_1,labelcmp64_2 : tasmlabel; - tmpreg : tregister; - begin - tmpreg:=cg.getintregister(current_asmdata.currasmlist,OS_INT); - - { load the value for "false" } - cg.a_load_const_reg(current_asmdata.currasmlist,OS_INT,0,tmpreg); - - current_asmdata.getjumplabel(labelcmp64_1); - current_asmdata.getjumplabel(labelcmp64_2); - - { check whether left_reg.reghi is less than right_reg.reghi } - current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,right_reg.reghi,left_reg.reghi)); - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_LT,S_NO,labelcmp64_2)); - - { are left_reg.reghi and right_reg.reghi equal? } - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_NO,labelcmp64_1)); - - { is left_reg.reglo less than right_reg.reglo? } - current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,right_reg.reglo,left_reg.reglo)); - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_CS,S_NO,labelcmp64_2)); - - current_asmdata.currasmlist.concat(Taicpu.op_sym(A_BRA,S_NO,labelcmp64_1)); - cg.a_label(current_asmdata.currasmlist,labelcmp64_2); - - { load the value for "true" } - cg.a_load_const_reg(current_asmdata.currasmlist,OS_INT,1,tmpreg); - - cg.a_label(current_asmdata.currasmlist,labelcmp64_1); - result:=tmpreg; - end; - - function t68kaddnode.cmp64_le(left_reg,right_reg:tregister64):tregister; - var - labelcmp64_1,labelcmp64_2 : tasmlabel; - tmpreg : tregister; - begin - tmpreg:=cg.getintregister(current_asmdata.currasmlist,OS_INT); - - { load the value for "false" } - cg.a_load_const_reg(current_asmdata.currasmlist,OS_INT,0,tmpreg); - - current_asmdata.getjumplabel(labelcmp64_1); - current_asmdata.getjumplabel(labelcmp64_2); - - { check whether right_reg.reghi is less than left_reg.reghi } - current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reghi,right_reg.reghi)); - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_LT,S_NO,labelcmp64_1)); - - { are left_reg.reghi and right_reg.reghi equal? } - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_NO,labelcmp64_2)); - - { is right_reg.reglo less than left_reg.reglo? } - current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reglo,right_reg.reglo)); - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_CS,S_NO,labelcmp64_1)); - - cg.a_label(current_asmdata.currasmlist,labelcmp64_2); - - { load the value for "true" } - cg.a_load_const_reg(current_asmdata.currasmlist,OS_INT,1,tmpreg); - - cg.a_label(current_asmdata.currasmlist,labelcmp64_1); - result:=tmpreg; - end; - - function t68kaddnode.cmp64_eq(left_reg,right_reg:tregister64):tregister; - var - labelcmp64 : tasmlabel; - tmpreg : tregister; - begin - tmpreg:=cg.getintregister(current_asmdata.currasmlist,OS_INT); - current_asmdata.getjumplabel(labelcmp64); - - { load the value for "false" } - cg.a_load_const_reg(current_asmdata.currasmlist,OS_INT,0,tmpreg); - - { is the high order longword equal? } - current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reghi,right_reg.reghi)); - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_NO,labelcmp64)); - - { is the low order longword equal? } - current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reglo,right_reg.reglo)); - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_NO,labelcmp64)); - - { load the value for "true" } - cg.a_load_const_reg(current_asmdata.currasmlist,OS_INT,1,tmpreg); - - cg.a_label(current_asmdata.currasmlist,labelcmp64); - result:=tmpreg; - end; - - function t68kaddnode.cmp64_ne(left_reg,right_reg:tregister64):tregister; - var - labelcmp64 : tasmlabel; - tmpreg : tregister; - begin - tmpreg:=cg.getintregister(current_asmdata.currasmlist,OS_INT); - current_asmdata.getjumplabel(labelcmp64); - - { load the value for "true" } - cg.a_load_const_reg(current_asmdata.currasmlist,OS_INT,1,tmpreg); - - { is the high order longword equal? } - current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reghi,right_reg.reghi)); - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_NO,labelcmp64)); - - { is the low order longword equal? } - current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reglo,right_reg.reglo)); - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_NO,labelcmp64)); - - { load the value for "false" } - cg.a_load_const_reg(current_asmdata.currasmlist,OS_INT,0,tmpreg); - - cg.a_label(current_asmdata.currasmlist,labelcmp64); - result:=tmpreg; - end; - - function t68kaddnode.cmp64_ltu(left_reg,right_reg:tregister64):tregister; - var - labelcmp64_1,labelcmp64_2 : tasmlabel; - tmpreg : tregister; - begin - tmpreg:=cg.getintregister(current_asmdata.currasmlist,OS_INT); - - { load the value for "false" } - cg.a_load_const_reg(current_asmdata.currasmlist,OS_INT,0,tmpreg); - - current_asmdata.getjumplabel(labelcmp64_1); - current_asmdata.getjumplabel(labelcmp64_2); - - { check whether left_reg.reghi is less than right_reg.reghi } - current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,right_reg.reghi,left_reg.reghi)); - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_CS,S_NO,labelcmp64_2)); - - { are left_reg.reghi and right_reg.reghi equal? } - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_NO,labelcmp64_1)); - - { is left_reg.reglo less than right_reg.reglo? } - current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,right_reg.reglo,left_reg.reglo)); - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_CS,S_NO,labelcmp64_2)); - - current_asmdata.currasmlist.concat(Taicpu.op_sym(A_BRA,S_NO,labelcmp64_1)); - cg.a_label(current_asmdata.currasmlist,labelcmp64_2); - - { load the value for "true" } - cg.a_load_const_reg(current_asmdata.currasmlist,OS_INT,1,tmpreg); - - cg.a_label(current_asmdata.currasmlist,labelcmp64_1); - result:=tmpreg; - end; - - function t68kaddnode.cmp64_leu(left_reg,right_reg:tregister64):tregister; - var - labelcmp64_1,labelcmp64_2 : tasmlabel; - tmpreg : tregister; - begin - tmpreg:=cg.getintregister(current_asmdata.currasmlist,OS_INT); - - { load the value for "false" } - cg.a_load_const_reg(current_asmdata.currasmlist,OS_INT,0,tmpreg); - - current_asmdata.getjumplabel(labelcmp64_1); - current_asmdata.getjumplabel(labelcmp64_2); - - { check whether right_reg.reghi is less than left_reg.reghi } - current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reghi,right_reg.reghi)); - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_CS,S_NO,labelcmp64_1)); - - { are left_reg.reghi and right_reg.reghi equal? } - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_NE,S_NO,labelcmp64_2)); - - { is right_reg.reglo less than left_reg.reglo? } - current_asmdata.currasmlist.concat(taicpu.op_reg_reg(A_CMP,S_L,left_reg.reglo,right_reg.reglo)); - current_asmdata.currasmlist.concat(taicpu.op_cond_sym(A_BXX,C_CS,S_NO,labelcmp64_1)); - - cg.a_label(current_asmdata.currasmlist,labelcmp64_2); - - { load the value for "true" } - cg.a_load_const_reg(current_asmdata.currasmlist,OS_INT,1,tmpreg); - - cg.a_label(current_asmdata.currasmlist,labelcmp64_1); - result:=tmpreg; - end; - function t68kaddnode.getresflags(unsigned : boolean) : tresflags; begin case nodetype of @@ -268,6 +72,8 @@ implementation lten : getresflags:=F_GE; gtn : getresflags:=F_L; gten : getresflags:=F_LE; + else + internalerror(2014082030); end else case nodetype of @@ -275,6 +81,8 @@ implementation lten : getresflags:=F_LE; gtn : getresflags:=F_G; gten : getresflags:=F_GE; + else + internalerror(2014082031); end; end else @@ -285,6 +93,8 @@ implementation lten : getresflags:=F_AE; gtn : getresflags:=F_B; gten : getresflags:=F_BE; + else + internalerror(2014082032); end else case nodetype of @@ -292,71 +102,13 @@ implementation lten : getresflags:=F_BE; gtn : getresflags:=F_A; gten : getresflags:=F_AE; + else + internalerror(2014082033); end; end; end; end; - function t68kaddnode.getres64_register(unsigned:boolean;left_reg,right_reg:tregister64):tregister; - begin - case nodetype of - equaln: - result:=cmp64_eq(left_reg,right_reg); - unequaln: - result:=cmp64_ne(left_reg,right_reg); - else - if not unsigned then - begin - if nf_swapped in flags then - case nodetype of - ltn: - result:=cmp64_lt(right_reg,left_reg); - lten: - result:=cmp64_le(right_reg,left_reg); - gtn: - result:=cmp64_lt(left_reg,right_reg); - gten: - result:=cmp64_le(left_reg,right_reg); - end - else - case nodetype of - ltn: - result:=cmp64_lt(left_reg,right_reg); - lten: - result:=cmp64_le(left_reg,right_reg); - gtn: - result:=cmp64_lt(right_reg,left_reg); - gten: - result:=cmp64_le(right_reg,left_reg); - end; - end - else - begin - if nf_swapped in Flags then - case nodetype of - ltn: - result:=cmp64_ltu(right_reg,left_reg); - lten: - result:=cmp64_leu(right_reg,left_reg); - gtn: - result:=cmp64_ltu(left_reg,right_reg); - gten: - result:=cmp64_leu(left_reg,right_reg); - end - else - case nodetype of - ltn: - result:=cmp64_ltu(left_reg,right_reg); - lten: - result:=cmp64_leu(left_reg,right_reg); - gtn: - result:=cmp64_ltu(right_reg,left_reg); - gten: - result:=cmp64_leu(right_reg,left_reg); - end; - end; - end; - end; {***************************************************************************** AddFloat @@ -386,56 +138,53 @@ implementation if nf_swapped in flags then swapleftright; - // put both operands in a register - hlcg.location_force_fpureg(current_asmdata.CurrAsmList,right.location,right.resultdef,true); - hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true); + case current_settings.fputype of + fpu_68881: + begin + // put both operands in a register + hlcg.location_force_fpureg(current_asmdata.CurrAsmList,right.location,right.resultdef,true); + hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true); - // initialize de result - location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef)); - if left.location.loc = LOC_FPUREGISTER then - location.register := left.location.register - else if right.location.loc = LOC_FPUREGISTER then - location.register := right.location.register - else - location.register := cg.getfpuregister(current_asmdata.CurrAsmList,location.size); - - // emit the actual operation - { - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op, - location.register,left.location.register, - right.location.register)) - } + // initialize the result + location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef)); + location.register := cg.getfpuregister(current_asmdata.CurrAsmList,location.size); + + // emit the actual operation + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FMOVE,S_FX,left.location.register,location.register)); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,S_FX,right.location.register,location.register)); + end; + else + // softfpu should be handled in pass1, others are not yet supported... + internalerror(2015010201); + end; end; procedure t68kaddnode.second_cmpfloat; begin pass_left_right; - -{ if (nf_swapped in flags) then swapleftright; -} - { force fpureg as location, left right doesn't matter - as both will be in a fpureg } - hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true); - hlcg.location_force_fpureg(current_asmdata.CurrAsmList,right.location,right.resultdef,true); - location_reset(location,LOC_FLAGS,OS_NO); - location.resflags:=getresflags(true); -{ - if nodetype in [equaln,unequaln] then - current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_CMF, - left.location.register,right.location.register), - cgsize2fpuoppostfix[def_cgsize(resultdef)])) - else - current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_CMFE, - left.location.register,right.location.register), - cgsize2fpuoppostfix[def_cgsize(resultdef)])); + case current_settings.fputype of + fpu_68881: + begin + location_reset(location,LOC_FLAGS,OS_NO); - location_reset(location,LOC_FLAGS,OS_NO); - location.resflags:=getresflags(false); -} + { force fpureg as location, left right doesn't matter + as both will be in a fpureg } + hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true); + hlcg.location_force_fpureg(current_asmdata.CurrAsmList,right.location,right.resultdef,true); + + // emit compare + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FCMP,S_FX,right.location.register,left.location.register)); + + location.resflags:=getresflags(false); + end; + else + // softfpu should be handled in pass1, others are not yet supported... + internalerror(2015010201); + end; end; @@ -500,111 +249,92 @@ implementation procedure t68kaddnode.second_cmpordinal; var unsigned : boolean; - useconst : boolean; tmpreg : tregister; opsize : topsize; cmpsize : tcgsize; + href: treference; begin - pass_left_right; - { set result location } - location_reset(location,LOC_JUMP,OS_NO); - - { ToDo : set "allowconstants" to True, but this seems to upset Coldfire - a bit for the CMP instruction => check manual and implement - exception accordingly below } - { load values into registers (except constants) } - force_reg_left_right(true, false); - { determine if the comparison will be unsigned } unsigned:=not(is_signed(left.resultdef)) or not(is_signed(right.resultdef)); + { this puts constant operand (if any) to the right } + pass_left_right; + { tentatively assume left size (correct for possible TST, will fix later) } + cmpsize:=def_cgsize(left.resultdef); + opsize:=tcgsize2opsize[cmpsize]; - // get the constant on the right if there is one - if (left.location.loc = LOC_CONSTANT) then - swapleftright; - // can we use an immediate, or do we have to load the - // constant in a register first? - if (right.location.loc = LOC_CONSTANT) then - begin -{$ifdef extdebug} - if (right.location.size in [OS_64,OS_S64]) and (hi(right.location.value64)<>0) and ((hi(right.location.value64)<>-1) or unsigned) then - internalerror(2002080301); -{$endif extdebug} - if (nodetype in [equaln,unequaln]) then - if (unsigned and - (right.location.value > high(word))) or - (not unsigned and - (longint(right.location.value) < low(smallint)) or - (longint(right.location.value) > high(smallint))) then - { we can then maybe use a constant in the 'othersigned' case - (the sign doesn't matter for // equal/unequal)} - unsigned := not unsigned; - - if (unsigned and - ((right.location.value) <= high(word))) or - (not(unsigned) and - (longint(right.location.value) >= low(smallint)) and - (longint(right.location.value) <= high(smallint))) then - useconst := true - else - begin - useconst := false; - tmpreg := cg.getintregister(current_asmdata.CurrAsmList,OS_INT); - cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT, - aword(right.location.value),tmpreg); - end - end - else - useconst := false; - location.loc := LOC_FLAGS; - location.resflags := getresflags(unsigned); - if tcgsize2size[right.location.size]=tcgsize2size[left.location.size] then - cmpsize:=left.location.size - else - { ToDo : zero/sign extend??? } - if tcgsize2size[right.location.size]<tcgsize2size[left.location.size] then - cmpsize:=left.location.size - else - cmpsize:=right.location.size; - opsize:=tcgsize2opsize[cmpsize]; - if opsize=S_NO then - internalerror(2013090301); - { Attention: The RIGHT(!) operand is substracted from and must be a - register! } - if (right.location.loc = LOC_CONSTANT) then - if useconst then - current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,opsize, - longint(right.location.value),left.location.register)) - else - begin - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,opsize, - tmpreg,left.location.register)); - end - else - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,opsize, - right.location.register,left.location.register)); - end; + { set result location } + location_reset(location,LOC_FLAGS,OS_NO); + { see if we can optimize into TST } + if (right.location.loc=LOC_CONSTANT) and (right.location.value=0) then + begin + { Unsigned <0 or >=0 should not reach pass2, most likely } + case left.location.loc of + LOC_REFERENCE, + LOC_CREFERENCE: + begin + href:=left.location.reference; + tcg68k(cg).fixref(current_asmdata.CurrAsmList,href); + current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_TST,opsize,href)); + location_freetemp(current_asmdata.CurrAsmList,left.location); + end; + else + hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true); + current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_TST,opsize,left.location.register)); + end; + location.resflags := getresflags(unsigned); + exit; + end; - function t68kaddnode.pass_1:tnode; - var - ld,rd : tdef; - begin - result:=inherited pass_1; + { Coldfire supports byte/word compares only starting with ISA_B, + !!see remark about Qemu weirdness in tcg68k.a_cmp_const_reg_label } + if (opsize<>S_L) and (current_settings.cputype in cpu_coldfire{-[cpu_isa_b,cpu_isa_c]}) then + begin + { 1) Extension is needed for LOC_REFERENCE, but what about LOC_REGISTER ? Perhaps after fixing cg we can assume + that high bits of registers are correct. + 2) Assuming that extension depends only on source signedness --> destination OS_32 is acceptable. } + hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,cgsize_orddef(OS_32),false); + if (right.location.loc<>LOC_CONSTANT) then + hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,cgsize_orddef(OS_32),false); + opsize:=S_L; + end + else if not (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then + begin + if not (right.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then + hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true) + else + begin + location_swap(left.location,right.location); + toggleflag(nf_swapped); + end; + end; + { left is now in register } + case right.location.loc of + LOC_CONSTANT: + current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,opsize, + longint(right.location.value),left.location.register)); + LOC_REFERENCE, + LOC_CREFERENCE: + begin + href:=right.location.reference; + tcg68k(cg).fixref(current_asmdata.CurrAsmList,href); + current_asmdata.CurrAsmList.concat(taicpu.op_ref_reg(A_CMP,opsize,href, + left.location.register)); + end; + LOC_REGISTER, + LOC_CREGISTER: + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,opsize, + right.location.register,left.location.register)); + else + hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,opsize, + right.location.register,left.location.register)); + end; - { for 64 bit operations we return the resulting value in a register } - if not assigned(result) then - begin - rd:=right.resultdef; - ld:=left.resultdef; - if (nodetype in [ltn,lten,gtn,gten,equaln,unequaln]) and - ( - ((ld.typ=orddef) and (torddef(ld).ordtype in [u64bit,s64bit,scurrency])) or - ((rd.typ=orddef) and (torddef(rd).ordtype in [u64bit,s64bit,scurrency])) - ) then - expectloc:=LOC_REGISTER; - end; - end; + { update location because sides could have been swapped } + location.resflags:=getresflags(unsigned); + end; {***************************************************************************** @@ -613,123 +343,167 @@ implementation procedure t68kaddnode.second_cmp64bit; var + hlab: tasmlabel; unsigned : boolean; - tmp_left_reg : tregister; + href: treference; + + procedure firstjmp64bitcmp; + var + oldnodetype : tnodetype; + begin + case nodetype of + ltn,gtn: + begin + if (hlab<>current_procinfo.CurrTrueLabel) then + cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrTrueLabel); + { cheat a little bit for the negative test } + toggleflag(nf_swapped); + if (hlab<>current_procinfo.CurrFalseLabel) then + cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrFalseLabel); + toggleflag(nf_swapped); + end; + lten,gten: + begin + oldnodetype:=nodetype; + if nodetype=lten then + nodetype:=ltn + else + nodetype:=gtn; + if (hlab<>current_procinfo.CurrTrueLabel) then + cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrTrueLabel); + { cheat for the negative test } + if nodetype=ltn then + nodetype:=gtn + else + nodetype:=ltn; + if (hlab<>current_procinfo.CurrFalseLabel) then + cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrFalseLabel); + nodetype:=oldnodetype; + end; + equaln: + cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrFalseLabel); + unequaln: + cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrTrueLabel); + end; + end; + + procedure secondjmp64bitcmp; + begin + case nodetype of + ltn,gtn,lten,gten: + begin + cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),current_procinfo.CurrTrueLabel); + cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel); + end; + equaln: + begin + cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrFalseLabel); + cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrTrueLabel); + end; + unequaln: + begin + cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrTrueLabel); + cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel); + end; + end; + end; + begin + { This puts constant operand (if any) to the right } pass_left_right; - force_reg_left_right(false,false); unsigned:=not(is_signed(left.resultdef)) or not(is_signed(right.resultdef)); - location_reset(location,LOC_REGISTER,OS_INT); - location.register:=getres64_register(unsigned,left.location.register64,right.location.register64); - - { keep the below code for now, as we could optimize the =/<> code later - on based on it } - - // writeln('second_cmp64bit'); -// pass_left_right; + location_reset(location,LOC_JUMP,OS_NO); + { Relational compares against constants having low dword=0 can omit the + second compare based on the fact that any unsigned value is >=0 } + hlab:=nil; + if (right.location.loc=LOC_CONSTANT) and + (lo(right.location.value64)=0) then + begin + case getresflags(true) of + F_AE: hlab:=current_procinfo.CurrTrueLabel; + F_B: hlab:=current_procinfo.CurrFalseLabel; + end; + end; -// load_left_right(true,false); -(* - case nodetype of - ltn,lten, - gtn,gten: - begin - emit_cmp64_hi; - firstjmp64bitcmp; - emit_cmp64_lo; - secondjmp64bitcmp; - end; - equaln,unequaln: - begin - // instead of doing a complicated compare, do - // (left.hi xor right.hi) or (left.lo xor right.lo) - // (somewhate optimized so that no superfluous 'mr's are - // generated) - if (left.location.loc = LOC_CONSTANT) then - swapleftright; - if (right.location.loc = LOC_CONSTANT) then - begin - if left.location.loc = LOC_REGISTER then - begin - tempreg64.reglo := left.location.register64.reglo; - tempreg64.reghi := left.location.register64.reghi; - end - else - begin - if (aword(right.location.valueqword) <> 0) then - tempreg64.reglo := cg.getintregister(current_asmdata.CurrAsmList) - else - tempreg64.reglo := left.location.register64.reglo; - if ((right.location.valueqword shr 32) <> 0) then - tempreg64.reghi := cg.getintregister(current_asmdata.CurrAsmList) - else - tempreg64.reghi := left.location.register64.reghi; - end; - - if (aword(right.location.valueqword) <> 0) then - { negative values can be handled using SUB, } - { positive values < 65535 using XOR. } - if (longint(right.location.valueqword) >= -32767) and - (longint(right.location.valueqword) < 0) then - cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT, - aword(right.location.valueqword), - left.location.register64.reglo,tempreg64.reglo) - else - cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_INT, - aword(right.location.valueqword), - left.location.register64.reglo,tempreg64.reglo); - - if ((right.location.valueqword shr 32) <> 0) then - if (longint(right.location.valueqword shr 32) >= -32767) and - (longint(right.location.valueqword shr 32) < 0) then - cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT, - aword(right.location.valueqword shr 32), - left.location.register64.reghi,tempreg64.reghi) - else - cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,OS_INT, - aword(right.location.valueqword shr 32), - left.location.register64.reghi,tempreg64.reghi); - end - else - begin - tempreg64.reglo := cg.getintregister(current_asmdata.CurrAsmList); - tempreg64.reghi := cg.getintregister(current_asmdata.CurrAsmList); - cg64.a_op64_reg_reg_reg(current_asmdata.CurrAsmList,OP_XOR, - left.location.register64,right.location.register64, - tempreg64); - end; - - cg.a_reg_alloc(current_asmdata.CurrAsmList,R_0); - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_OR_,R_0, - tempreg64.reglo,tempreg64.reghi)); - cg.a_reg_dealloc(current_asmdata.CurrAsmList,R_0); - if (tempreg64.reglo <> left.location.register64.reglo) then - cg.ungetregister(current_asmdata.CurrAsmList,tempreg64.reglo); - if (tempreg64.reghi <> left.location.register64.reghi) then - cg.ungetregister(current_asmdata.CurrAsmList,tempreg64.reghi); - - location_reset(location,LOC_FLAGS,OS_NO); - location.resflags := getresflags; + if (right.location.loc=LOC_CONSTANT) and (right.location.value64=0) and + (nodetype in [equaln,unequaln]) then + begin + case left.location.loc of + LOC_REFERENCE, + LOC_CREFERENCE: + begin + href:=left.location.reference; + tcg68k(cg).fixref(current_asmdata.CurrAsmList,href); + current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_TST,S_L,href)); + firstjmp64bitcmp; + inc(href.offset,4); + current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_TST,S_L,href)); + secondjmp64bitcmp; + location_freetemp(current_asmdata.CurrAsmList,left.location); end; - else - internalerror(2002072803); + else + hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true); + current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_TST,S_L,left.location.register64.reglo)); + firstjmp64bitcmp; + current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_TST,S_L,left.location.register64.reghi)); + secondjmp64bitcmp; end; + exit; + end; + { left and right no register? } + { then one must be demanded } + if not (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then + begin + if not (right.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then + hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true) + else + begin + location_swap(left.location,right.location); + toggleflag(nf_swapped); + end; + end; - { set result location } - { (emit_compare sets it to LOC_FLAGS for compares, so set the } - { real location only now) (JM) } - if cmpop and - not(nodetype in [equaln,unequaln]) then - location_reset(location,LOC_JUMP,OS_NO); -*) - // location_reset(location,LOC_JUMP,OS_NO); - // writeln('second_cmp64_exit'); - end; + { left is now in register } + case right.location.loc of + LOC_REGISTER,LOC_CREGISTER: + begin + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,S_L,right.location.register64.reghi,left.location.register64.reghi)); + firstjmp64bitcmp; + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,S_L,right.location.register64.reglo,left.location.register64.reglo)); + secondjmp64bitcmp; + end; + LOC_REFERENCE,LOC_CREFERENCE: + begin + href:=right.location.reference; + tcg68k(cg).fixref(current_asmdata.CurrAsmList,href); + current_asmdata.CurrAsmList.concat(taicpu.op_ref_reg(A_CMP,S_L,href,left.location.register64.reghi)); + firstjmp64bitcmp; + inc(href.offset,4); + current_asmdata.CurrAsmList.concat(taicpu.op_ref_reg(A_CMP,S_L,href,left.location.register64.reglo)); + secondjmp64bitcmp; + location_freetemp(current_asmdata.CurrAsmList,right.location); + end; + LOC_CONSTANT: + begin + current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_L,aint(hi(right.location.value64)),left.location.register64.reghi)); + firstjmp64bitcmp; + if assigned(hlab) then + cg.a_jmp_always(current_asmdata.CurrAsmList,hlab) + else + begin + current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_L,aint(lo(right.location.value64)),left.location.register64.reglo)); + secondjmp64bitcmp; + end; + end; + else + InternalError(2014072501); + end; + end; begin diff --git a/compiler/m68k/n68kcnv.pas b/compiler/m68k/n68kcnv.pas index f49769e169..0158536efe 100644 --- a/compiler/m68k/n68kcnv.pas +++ b/compiler/m68k/n68kcnv.pas @@ -68,8 +68,14 @@ implementation end else { converting a 64bit integer to a float requires a helper } - if is_64bitint(left.resultdef) then + if is_64bitint(left.resultdef) or + is_currency(left.resultdef) then begin + { hack to avoid double division by 10000, as it's + already done by typecheckpass.resultdef_int_to_real } + if is_currency(left.resultdef) then + left.resultdef := s64inttype; + if is_signed(left.resultdef) then fname := 'fpc_int64_to_double' else diff --git a/compiler/m68k/n68kmat.pas b/compiler/m68k/n68kmat.pas index 8314498f9b..623e5f18a6 100644 --- a/compiler/m68k/n68kmat.pas +++ b/compiler/m68k/n68kmat.pas @@ -70,8 +70,7 @@ implementation procedure tm68knotnode.second_boolean; var hreg: tregister; - opsize : tcgsize; - loc : tcgloc; + opsize : tcgsize; begin if not handle_locjump then begin @@ -154,10 +153,8 @@ implementation procedure tm68kmoddivnode.emit_mod_reg_reg(signed: boolean;denum,num : tregister); - var tmpreg : tregister; - continuelabel : tasmlabel; - signlabel : tasmlabel; - reg_d0,reg_d1 : tregister; + var + tmpreg : tregister; begin if current_settings.cputype=cpu_MC68020 then begin diff --git a/compiler/m68k/ra68k.pas b/compiler/m68k/ra68k.pas index 7dff294853..a28cf942af 100644 --- a/compiler/m68k/ra68k.pas +++ b/compiler/m68k/ra68k.pas @@ -328,6 +328,7 @@ unit ra68k; function TM68kInstruction.ConcatLabeledInstr(p : TAsmList):tai; begin + result:=nil; if ((opcode >= A_BCC) and (opcode <= A_BVS)) or (opcode = A_BRA) or (opcode = A_BSR) or (opcode = A_JMP) or (opcode = A_JSR) or diff --git a/compiler/m68k/ra68kmot.pas b/compiler/m68k/ra68kmot.pas index 01d775ca7a..aedfed306a 100644 --- a/compiler/m68k/ra68kmot.pas +++ b/compiler/m68k/ra68kmot.pas @@ -616,6 +616,7 @@ const l : longint; errorflag: boolean; begin + BuildExpression:=0; errorflag := FALSE; expr := ''; tempstr := ''; @@ -986,6 +987,7 @@ const l: longint; code: integer; begin + str:=''; Consume(AS_STAR); if (oper.opr.ref.scalefactor <> 0) and (oper.opr.ref.scalefactor <> 1) then @@ -1180,6 +1182,7 @@ const code: integer; str: string; begin + str:=''; Consume(AS_LPAREN); case actasmtoken of { // (reg ... // } @@ -1309,6 +1312,7 @@ const dataregset := []; addrregset := []; tempstr := ''; + r:=NR_NO; case actasmtoken of { // Memory reference // } AS_LPAREN: diff --git a/compiler/m68k/rgcpu.pas b/compiler/m68k/rgcpu.pas index a981d73a75..0c0ab7957c 100644 --- a/compiler/m68k/rgcpu.pas +++ b/compiler/m68k/rgcpu.pas @@ -27,14 +27,150 @@ unit rgcpu; interface uses - aasmbase,aasmtai,aasmdata, - cpubase, + aasmbase,aasmtai,aasmdata,aasmcpu, + cgbase,cgutils,cpubase, rgobj; type trgcpu = class(trgobj) + procedure do_spill_read(list:tasmlist;pos:tai;const spilltemp:treference;tempreg:tregister);override; + procedure do_spill_written(list:tasmlist;pos:tai;const spilltemp:treference;tempreg:tregister);override; + function do_spill_replace(list:TAsmList;instr:taicpu;orgreg:tsuperregister;const spilltemp:treference):boolean;override; end; implementation + uses + cutils,cgobj,verbose,globtype,globals,cpuinfo; + + { returns True if source operand of MOVE can be replaced with spilltemp when its destination is ref^. } + function isvalidmovedest(ref: preference): boolean; inline; + begin + { The following is for Coldfire, for other CPUs it maybe can be relaxed. } + result:=(ref^.symbol=nil) and (ref^.scalefactor<=1) and + (ref^.index=NR_NO) and (ref^.base<>NR_NO) and (ref^.offset>=low(smallint)) and + (ref^.offset<=high(smallint)); + end; + + + procedure trgcpu.do_spill_read(list:tasmlist;pos:tai;const spilltemp:treference;tempreg:tregister); + var + helpins : tai; + tmpref : treference; + helplist : tasmlist; + hreg : tregister; + begin + if (abs(spilltemp.offset)>32767) and (current_settings.cputype in (cpu_coldfire + [cpu_mc68000])) then + begin + helplist:=tasmlist.create; + + if getregtype(tempreg)=R_INTREGISTER then + hreg:=tempreg + else + hreg:=cg.getintregister(helplist,OS_ADDR); +{$ifdef DEBUG_SPILLING} + helplist.concat(tai_comment.Create(strpnew('Spilling: Read, large offset'))); +{$endif} + + helplist.concat(taicpu.op_const_reg(A_MOVE,S_L,spilltemp.offset,hreg)); + reference_reset_base(tmpref,spilltemp.base,0,sizeof(aint)); + tmpref.index:=hreg; + + helpins:=spilling_create_load(tmpref,tempreg); + helplist.concat(helpins); + list.insertlistafter(pos,helplist); + helplist.free; + end + else + inherited do_spill_read(list,pos,spilltemp,tempreg); + end; + + + procedure trgcpu.do_spill_written(list:tasmlist;pos:tai;const spilltemp:treference;tempreg:tregister); + var + tmpref : treference; + helplist : tasmlist; + hreg : tregister; + begin + if (abs(spilltemp.offset)>32767) and (current_settings.cputype in (cpu_coldfire + [cpu_mc68000])) then + begin + helplist:=tasmlist.create; + + if getregtype(tempreg)=R_INTREGISTER then + hreg:=getregisterinline(helplist,[R_SUBWHOLE]) + else + hreg:=cg.getintregister(helplist,OS_ADDR); +{$ifdef DEBUG_SPILLING} + helplist.concat(tai_comment.Create(strpnew('Spilling: Write, large offset'))); +{$endif} + + helplist.concat(taicpu.op_const_reg(A_MOVE,S_L,spilltemp.offset,hreg)); + reference_reset_base(tmpref,spilltemp.base,0,sizeof(aint)); + tmpref.index:=hreg; + + helplist.concat(spilling_create_store(tempreg,tmpref)); + if getregtype(tempreg)=R_INTREGISTER then + ungetregisterinline(helplist,hreg); + + list.insertlistafter(pos,helplist); + helplist.free; + end + else + inherited do_spill_written(list,pos,spilltemp,tempreg); + end; + + + function trgcpu.do_spill_replace(list:TAsmList;instr:taicpu;orgreg:tsuperregister;const spilltemp:treference):boolean; + var + opidx: longint; + begin + result:=false; + opidx:=-1; + if (abs(spilltemp.offset)>32767) and (current_settings.cputype in cpu_coldfire) then + exit; + case instr.ops of + 1: + begin + if (instr.oper[0]^.typ=top_reg) and (getregtype(instr.oper[0]^.reg)=regtype) and + ((instr.opcode=A_TST) or (instr.opcode=A_CLR)) then + begin + if get_alias(getsupreg(instr.oper[0]^.reg))<>orgreg then + InternalError(2014080101); + opidx:=0; + end; + end; + 2: + begin + if (instr.oper[0]^.typ=top_reg) and (getregtype(instr.oper[0]^.reg)=regtype) and + (get_alias(getsupreg(instr.oper[0]^.reg))=orgreg) then + begin + { source can be replaced if dest is register... } + if ((instr.oper[1]^.typ=top_reg) and (instr.opcode in [A_MOVE,A_ADD,A_SUB,A_AND,A_OR,A_CMP])) or + {... or a "simple" reference in case of MOVE } + ((instr.opcode=A_MOVE) and (instr.oper[1]^.typ=top_ref) and isvalidmovedest(instr.oper[1]^.ref)) then + opidx:=0; + end + else if (instr.oper[1]^.typ=top_reg) and (getregtype(instr.oper[1]^.reg)=regtype) and + (get_alias(getsupreg(instr.oper[1]^.reg))=orgreg) and + ( + (instr.opcode in [A_MOVE,A_ADD,A_SUB,A_AND,A_OR]) and + (instr.oper[0]^.typ=top_reg) + ) or + (instr.opcode in [A_ADDQ,A_SUBQ,A_MOV3Q]) then + opidx:=1; + end; + end; + + if (opidx<0) then + exit; + instr.oper[opidx]^.typ:=top_ref; + new(instr.oper[opidx]^.ref); + instr.oper[opidx]^.ref^:=spilltemp; + case instr.opsize of + S_B: inc(instr.oper[opidx]^.ref^.offset,3); + S_W: inc(instr.oper[opidx]^.ref^.offset,2); + end; + result:=true; + end; + end. diff --git a/compiler/m68k/symcpu.pas b/compiler/m68k/symcpu.pas index 93702598cb..cb467ba937 100644 --- a/compiler/m68k/symcpu.pas +++ b/compiler/m68k/symcpu.pas @@ -186,14 +186,16 @@ implementation procedure tcpuprocdef.ppuload_platform(ppufile: tcompilerppufile); begin inherited; - ppufile.getderef(libsymderef); + if po_syscall_has_libsym in procoptions then + ppufile.getderef(libsymderef); end; procedure tcpuprocdef.ppuwrite_platform(ppufile: tcompilerppufile); begin inherited; - ppufile.putderef(libsymderef); + if po_syscall_has_libsym in procoptions then + ppufile.putderef(libsymderef); end; @@ -208,14 +210,18 @@ implementation procedure tcpuprocdef.buildderef; begin inherited; - libsymderef.build(libsym); + if po_syscall_has_libsym in procoptions then + libsymderef.build(libsym); end; procedure tcpuprocdef.deref; begin inherited; - libsym:=tsym(libsymderef.resolve); + if po_syscall_has_libsym in procoptions then + libsym:=tsym(libsymderef.resolve) + else + libsym:=nil; end; begin |