mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-31 07:31:49 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			308 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			308 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|     Copyright (c) 1998-2002 by Florian Klaempfl
 | |
| 
 | |
|     This unit implements the code generator for the SPARC
 | |
| 
 | |
|     This program is free software; you can redistribute it and/or modify
 | |
|     it under the terms of the GNU General Public License as published by
 | |
|     the Free Software Foundation; either version 2 of the License, or
 | |
|     (at your option) any later version.
 | |
| 
 | |
|     This program is distributed in the hope that it will be useful,
 | |
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|     GNU General Public License for more details.
 | |
| 
 | |
|     You should have received a copy of the GNU General Public License
 | |
|     along with this program; if not, write to the Free Software
 | |
|     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | |
| 
 | |
|  ****************************************************************************
 | |
| }
 | |
| unit cgcpu;
 | |
| 
 | |
| {$i fpcdefs.inc}
 | |
| 
 | |
| interface
 | |
| 
 | |
|     uses
 | |
|        globtype,parabase,
 | |
|        cgbase,cgutils,cgobj,
 | |
|        cg64f32,
 | |
|        aasmbase,aasmtai,aasmdata,aasmcpu,
 | |
|        cpubase,cpuinfo,
 | |
|        node,symconst,SymType,symdef,
 | |
|        rgcpu,
 | |
|        cgsparc;
 | |
| 
 | |
|     type
 | |
|       TCGSparc=class(TCGSparcGen)
 | |
|         procedure a_load_reg_reg(list : TAsmList; fromsize,tosize : tcgsize; reg1,reg2 : tregister);override;
 | |
|         procedure a_load_const_reg(list : TAsmList; size : TCGSize; a : tcgint; reg : TRegister);override;
 | |
|       end;
 | |
| 
 | |
|       TCg64Sparc=class(tcg64f32)
 | |
|       private
 | |
|         procedure get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp;checkoverflow : boolean);
 | |
|       public
 | |
|         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;
 | |
|         procedure a_load64_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);override;
 | |
|         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_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
 | |
|         procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
 | |
|         procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
 | |
|         procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
 | |
|       end;
 | |
| 
 | |
|     procedure create_codegen;
 | |
| 
 | |
|   implementation
 | |
| 
 | |
|     uses
 | |
|       verbose,
 | |
|       systems;
 | |
| 
 | |
|     procedure TCGSparc.a_load_reg_reg(list:TAsmList;fromsize,tosize:tcgsize;reg1,reg2:tregister);
 | |
|       var
 | |
|         instr : taicpu;
 | |
|       begin
 | |
|          if (tcgsize2size[fromsize] > tcgsize2size[tosize]) or
 | |
|             ((tcgsize2size[fromsize] = tcgsize2size[tosize]) and
 | |
|              (fromsize <> tosize)) or
 | |
|             { needs to mask out the sign in the top 16 bits }
 | |
|             ((fromsize = OS_S8) and
 | |
|              (tosize = OS_16)) then
 | |
|            case tosize of
 | |
|              OS_8 :
 | |
|                list.concat(taicpu.op_reg_const_reg(A_AND,reg1,$ff,reg2));
 | |
|              OS_16 :
 | |
|                begin
 | |
|                  list.concat(taicpu.op_reg_const_reg(A_SLL,reg1,16,reg2));
 | |
|                  list.concat(taicpu.op_reg_const_reg(A_SRL,reg2,16,reg2));
 | |
|                end;
 | |
|              OS_32,
 | |
|              OS_S32 :
 | |
|                begin
 | |
|                  instr:=taicpu.op_reg_reg(A_MOV,reg1,reg2);
 | |
|                  list.Concat(instr);
 | |
|                  { Notify the register allocator that we have written a move instruction so
 | |
|                   it can try to eliminate it. }
 | |
|                  add_move_instruction(instr);
 | |
|                end;
 | |
|              OS_S8 :
 | |
|                begin
 | |
|                  list.concat(taicpu.op_reg_const_reg(A_SLL,reg1,24,reg2));
 | |
|                  list.concat(taicpu.op_reg_const_reg(A_SRA,reg2,24,reg2));
 | |
|                end;
 | |
|              OS_S16 :
 | |
|                begin
 | |
|                  list.concat(taicpu.op_reg_const_reg(A_SLL,reg1,16,reg2));
 | |
|                  list.concat(taicpu.op_reg_const_reg(A_SRA,reg2,16,reg2));
 | |
|                end;
 | |
|              else
 | |
|                internalerror(2002090901);
 | |
|            end
 | |
|          else
 | |
|            begin
 | |
|              instr:=taicpu.op_reg_reg(A_MOV,reg1,reg2);
 | |
|              list.Concat(instr);
 | |
|              { Notify the register allocator that we have written a move instruction so
 | |
|               it can try to eliminate it. }
 | |
|              add_move_instruction(instr);
 | |
|            end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TCGSparc.a_load_const_reg(list : TAsmList;size : TCGSize;a : tcgint;reg : TRegister);
 | |
|       begin
 | |
|         { we don't use the set instruction here because it could be evalutated to two
 | |
|           instructions which would cause problems with the delay slot (FK) }
 | |
|         if (a=0) then
 | |
|           list.concat(taicpu.op_reg(A_CLR,reg))
 | |
|         else if (a>=simm13lo) and (a<=simm13hi) then
 | |
|           list.concat(taicpu.op_const_reg(A_MOV,a,reg))
 | |
|         else
 | |
|           begin
 | |
|             list.concat(taicpu.op_const_reg(A_SETHI,aint(a) shr 10,reg));
 | |
|             if (aint(a) and aint($3ff))<>0 then
 | |
|               list.concat(taicpu.op_reg_const_reg(A_OR,reg,aint(a) and aint($3ff),reg));
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {****************************************************************************
 | |
|                                TCG64Sparc
 | |
| ****************************************************************************}
 | |
| 
 | |
|     procedure tcg64sparc.a_load64_reg_ref(list : TAsmList;reg : tregister64;const ref : treference);
 | |
|       var
 | |
|         tmpref: treference;
 | |
|       begin
 | |
|         { Override this function to prevent loading the reference twice }
 | |
|         tmpref:=ref;
 | |
|         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 tcg64sparc.a_load64_ref_reg(list : TAsmList;const ref : treference;reg : tregister64);
 | |
|       var
 | |
|         tmpref: treference;
 | |
|       begin
 | |
|         { Override this function to prevent loading the reference twice }
 | |
|         tmpref:=ref;
 | |
|         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 tcg64sparc.a_load64_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);
 | |
|       var
 | |
|         hreg64 : tregister64;
 | |
|       begin
 | |
|         { Override this function to prevent loading the reference twice.
 | |
|           Use here some extra registers, but those are optimized away by the RA }
 | |
|         hreg64.reglo:=cg.GetIntRegister(list,OS_32);
 | |
|         hreg64.reghi:=cg.GetIntRegister(list,OS_32);
 | |
|         a_load64_ref_reg(list,r,hreg64);
 | |
|         a_load64_reg_cgpara(list,hreg64,paraloc);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TCg64Sparc.get_64bit_ops(op:TOpCG;var op1,op2:TAsmOp;checkoverflow : boolean);
 | |
|       begin
 | |
|         case op of
 | |
|           OP_ADD :
 | |
|             begin
 | |
|               op1:=A_ADDCC;
 | |
|               if checkoverflow then
 | |
|                 op2:=A_ADDXCC
 | |
|               else
 | |
|                 op2:=A_ADDX;
 | |
|             end;
 | |
|           OP_SUB :
 | |
|             begin
 | |
|               op1:=A_SUBCC;
 | |
|               if checkoverflow then
 | |
|                 op2:=A_SUBXCC
 | |
|               else
 | |
|                 op2:=A_SUBX;
 | |
|             end;
 | |
|           OP_XOR :
 | |
|             begin
 | |
|               op1:=A_XOR;
 | |
|               op2:=A_XOR;
 | |
|             end;
 | |
|           OP_OR :
 | |
|             begin
 | |
|               op1:=A_OR;
 | |
|               op2:=A_OR;
 | |
|             end;
 | |
|           OP_AND :
 | |
|             begin
 | |
|               op1:=A_AND;
 | |
|               op2:=A_AND;
 | |
|             end;
 | |
|           else
 | |
|             internalerror(200203241);
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TCg64Sparc.a_op64_reg_reg(list:TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst:TRegister64);
 | |
|       begin
 | |
|         case op of
 | |
|           OP_NEG :
 | |
|             begin
 | |
|               { Use the simple code: y=0-z }
 | |
|               list.concat(taicpu.op_reg_reg_reg(A_SUBcc,NR_G0,regsrc.reglo,regdst.reglo));
 | |
|               list.concat(taicpu.op_reg_reg_reg(A_SUBX,NR_G0,regsrc.reghi,regdst.reghi));
 | |
|             end;
 | |
|           OP_NOT :
 | |
|             begin
 | |
|               list.concat(taicpu.op_reg_reg_reg(A_XNOR,regsrc.reglo,NR_G0,regdst.reglo));
 | |
|               list.concat(taicpu.op_reg_reg_reg(A_XNOR,regsrc.reghi,NR_G0,regdst.reghi));
 | |
|             end;
 | |
|         else
 | |
|           a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure TCg64Sparc.a_op64_const_reg(list:TAsmList;op:TOpCG;size : tcgsize;value:int64;regdst:TRegister64);
 | |
|       begin
 | |
|         a_op64_const_reg_reg(list,op,size,value,regdst,regdst);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tcg64sparc.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64; regsrc,regdst : tregister64);
 | |
|       var
 | |
|         l : tlocation;
 | |
|       begin
 | |
|         a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,l);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tcg64sparc.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
 | |
|       var
 | |
|         l : tlocation;
 | |
|       begin
 | |
|         a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,l);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tcg64sparc.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
 | |
|       var
 | |
|         op1,op2:TAsmOp;
 | |
|       begin
 | |
|         case op of
 | |
|           OP_NEG,
 | |
|           OP_NOT :
 | |
|             internalerror(200306017);
 | |
|           OP_AND,OP_OR,OP_XOR:
 | |
|             begin
 | |
|               cg.a_op_const_reg_reg(list,op,OS_INT,tcgint(lo(value)),regsrc.reglo,regdst.reglo);
 | |
|               cg.a_op_const_reg_reg(list,op,OS_INT,tcgint(hi(value)),regsrc.reghi,regdst.reghi);
 | |
|             end;
 | |
|         else
 | |
|           get_64bit_ops(op,op1,op2,setflags);
 | |
|           tcgsparc(cg).handle_reg_const_reg(list,op1,regsrc.reglo,tcgint(lo(value)),regdst.reglo);
 | |
|           tcgsparc(cg).handle_reg_const_reg(list,op2,regsrc.reghi,tcgint(hi(value)),regdst.reghi);
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tcg64sparc.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
 | |
|       var
 | |
|         op1,op2:TAsmOp;
 | |
|       begin
 | |
|         case op of
 | |
|           OP_NEG,
 | |
|           OP_NOT :
 | |
|             internalerror(200306017);
 | |
|           else
 | |
|             ;
 | |
|         end;
 | |
|         get_64bit_ops(op,op1,op2,setflags);
 | |
|         list.concat(taicpu.op_reg_reg_reg(op1,regsrc2.reglo,regsrc1.reglo,regdst.reglo));
 | |
|         list.concat(taicpu.op_reg_reg_reg(op2,regsrc2.reghi,regsrc1.reghi,regdst.reghi));
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure create_codegen;
 | |
|       begin
 | |
|         cg:=TCgSparc.Create;
 | |
|         if target_info.system=system_sparc_linux then
 | |
|           TCgSparc(cg).use_unlimited_pic_mode:=true
 | |
|         else
 | |
|           TCgSparc(cg).use_unlimited_pic_mode:=false;
 | |
|         cg64:=TCg64Sparc.Create;
 | |
|       end;
 | |
| 
 | |
| end.
 | |
| 
 | 
