Selaa lähdekoodia

+ implementation of shifting operations for avr
* handle shl/shr operand size correctly

git-svn-id: branches/avr@17109 -

florian 14 vuotta sitten
vanhempi
commit
8d960cb608
5 muutettua tiedostoa jossa 113 lisäystä ja 4 poistoa
  1. 65 1
      compiler/avr/cgcpu.pas
  2. 18 1
      compiler/avr/cpubase.pas
  3. 1 1
      compiler/avr/itcpugas.pas
  4. 5 0
      compiler/ncgmat.pas
  5. 24 1
      compiler/nmat.pas

+ 65 - 1
compiler/avr/cgcpu.pas

@@ -378,10 +378,12 @@ unit cgcpu;
 
      procedure tcgavr.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
        var
+         countreg,
          tmpreg: tregister;
          i : integer;
          instr : taicpu;
          paraloc1,paraloc2,paraloc3 : TCGPara;
+         l1,l2 : tasmlabel;
       begin
          case op of
            OP_ADD:
@@ -488,7 +490,69 @@ unit cgcpu;
 
            OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
              begin
-               { TODO : Shift operators }
+               current_asmdata.getjumplabel(l1);
+               current_asmdata.getjumplabel(l2);
+               countreg:=getintregister(list,OS_8);
+               a_load_reg_reg(list,size,OS_8,src,countreg);
+               list.concat(taicpu.op_reg_const(A_CP,countreg,0));
+               a_jmp_flags(list,F_EQ,l2);
+               cg.a_label(list,l1);
+               case op of
+                 OP_SHR:
+                   list.concat(taicpu.op_reg(A_LSR,GetOffsetReg(dst,tcgsize2size[size]-1)));
+                 OP_SHL:
+                   list.concat(taicpu.op_reg(A_LSL,dst));
+                 OP_SAR:
+                   list.concat(taicpu.op_reg(A_ASR,GetOffsetReg(dst,tcgsize2size[size]-1)));
+                 OP_ROR:
+                   begin
+                     { load carry? }
+                     if not(size in [OS_8,OS_S8]) then
+                       begin
+                         list.concat(taicpu.op_none(A_CLC));
+                         list.concat(taicpu.op_reg_const(A_SBRC,src,0));
+                         list.concat(taicpu.op_none(A_SEC));
+                       end;
+                     list.concat(taicpu.op_reg(A_ROR,GetOffsetReg(dst,tcgsize2size[size]-1)));
+                   end;
+                 OP_ROL:
+                   begin
+                     { load carry? }
+                     if not(size in [OS_8,OS_S8]) then
+                       begin
+                         list.concat(taicpu.op_none(A_CLC));
+                         list.concat(taicpu.op_reg_const(A_SBRC,GetOffsetReg(dst,tcgsize2size[size]-1),7));
+                         list.concat(taicpu.op_none(A_SEC));
+                       end;
+                     list.concat(taicpu.op_reg(A_ROL,dst))
+                   end;
+                 else
+                   internalerror(2011030901);
+               end;
+               if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
+                 begin
+                   for i:=2 to tcgsize2size[size] do
+                     begin
+                       case op of
+                         OP_ROR,
+                         OP_SHR:
+                           list.concat(taicpu.op_reg(A_ROR,GetOffsetReg(dst,tcgsize2size[size]-i)));
+                         OP_ROL,
+                         OP_SHL:
+                           list.concat(taicpu.op_reg(A_ROL,GetOffsetReg(dst,i-1)));
+                         OP_SAR:
+                           list.concat(taicpu.op_reg(A_ROR,GetOffsetReg(dst,tcgsize2size[size]-i)));
+                         else
+                           internalerror(2011030902);
+                       end;
+                   end;
+                 end;
+
+               a_op_const_reg(list,OP_SUB,OS_8,1,countreg);
+               a_jmp_flags(list,F_NE,l1);
+               // keep registers alive
+               list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
+               cg.a_label(list,l2);
              end;
 
            OP_AND,OP_OR,OP_XOR:

+ 18 - 1
compiler/avr/cpubase.pas

@@ -44,7 +44,7 @@ unit cpubase;
 
     type
       TAsmOp=(A_None,
-        A_ADD,A_ADC,A_ADIW,A_SUB,A_SUBI,A_SBC,A_SBCI,A_SBRC,A_SBRS,A_SBIW,A_AND,A_ANDI,
+        A_ADD,A_ADC,A_ADIW,A_SUB,A_SUBI,A_SBC,A_SBCI,A_SBRC,A_SBRS,A_CLC,A_SEC,A_SBIW,A_AND,A_ANDI,
         A_OR,A_ORI,A_EOR,A_COM,A_NEG,A_SBR,A_CBR,A_INC,A_DEC,A_TST,A_CLR,
         A_SER,A_MUL,A_MULS,A_FMUL,A_FMULS,A_FMULSU,A_RJMP,A_IJMP,
         A_EIJMP,A_JMP,A_RCALL,A_ICALL,R_EICALL,A_CALL,A_RET,A_RETI,A_CPSE,
@@ -343,6 +343,11 @@ unit cpubase;
     { returns the next virtual register }
     function GetNextReg(const r : TRegister) : TRegister;
 
+    { returns the last virtual register }
+    function GetLastReg(const r : TRegister) : TRegister;
+
+    function GetOffsetReg(const r : TRegister;ofs : shortint) : TRegister;
+
   implementation
 
     uses
@@ -471,4 +476,16 @@ unit cpubase;
         result:=TRegister(longint(r)+1);
       end;
 
+
+    function GetLastReg(const r: TRegister): TRegister;
+      begin
+        result:=TRegister(longint(r)-1);
+      end;
+
+
+    function GetOffsetReg(const r: TRegister;ofs : shortint): TRegister;
+      begin
+        result:=TRegister(longint(r)+ofs);
+      end;
+
 end.

+ 1 - 1
compiler/avr/itcpugas.pas

@@ -35,7 +35,7 @@ interface
       processor manufacturer.
     }
     gas_op2str : op2strtable = ('',
-        'add','adc','adiw','sub','subi','sbc','sbci','sbrc','sbrs','sbiw','and','andi',
+        'add','adc','adiw','sub','subi','sbc','sbci','sbrc','sbrs','clc','sec','sbiw','and','andi',
         'or','ori','eor','com','neg','sbr','cbr','inc','dec','tst','clr',
         'ser','mul','muls','fmul','fmuls','fmulsu','rjmp','ijmp',
         'eijmp','jmp','rcall','icall','eicall','call','ret','reti','cpse',

+ 5 - 0
compiler/ncgmat.pas

@@ -410,11 +410,16 @@ implementation
            shln: op:=OP_SHL;
            shrn: op:=OP_SHR;
          end;
+{$ifdef cpunodefaultint}
+        opsize:=left.location.size;
+{$else cpunodefaultint}
          { load left operators in a register }
          if is_signed(left.resultdef) then
            opsize:=OS_SINT
          else
            opsize:=OS_INT;
+{$endif cpunodefaultint}
+
          location_force_reg(current_asmdata.CurrAsmList,left.location,opsize,true);
          location_reset(location,LOC_REGISTER,opsize);
          location.register:=cg.getintregister(current_asmdata.CurrAsmList,opsize);

+ 24 - 1
compiler/nmat.pas

@@ -483,6 +483,7 @@ implementation
     function tshlshrnode.pass_typecheck:tnode;
       var
          t : tnode;
+         nd : tdef;
       begin
          result:=nil;
          typecheckpass(left);
@@ -508,6 +509,14 @@ implementation
               exit;
            end;
 
+{$ifdef cpunodefaultint}
+         { for small cpus we use the smallest common type }
+         if (left.resultdef.typ=orddef) and (right.resultdef.typ=orddef) then
+           nd:=get_common_intdef(torddef(left.resultdef),torddef(right.resultdef),false)
+         else
+           nd:=s32inttype;
+{$endif cpunodefaultint}
+
          { calculations for ordinals < 32 bit have to be done in
            32 bit for backwards compatibility. That way 'shl 33' is
            the same as 'shl 1'. It's ugly but compatible with delphi/tp/gcc }
@@ -516,12 +525,26 @@ implementation
            begin
              { keep singness of orignal type }
              if is_signed(left.resultdef) then
+{$ifdef cpunodefaultint}
+               inserttypeconv(left,nd)
+{$else cpunodefaultint}
                inserttypeconv(left,s32inttype)
+{$endif cpunodefaultint}
              else
-               inserttypeconv(left,u32inttype);
+               begin
+{$ifdef cpunodefaultint}
+                 inserttypeconv(left,nd)
+{$else cpunodefaultint}
+                 inserttypeconv(left,u32inttype);
+{$endif cpunodefaultint}
+               end
            end;
 
+{$ifdef cpunodefaultint}
+         inserttypeconv(right,nd);
+{$else cpunodefaultint}
          inserttypeconv(right,sinttype);
+{$endif cpunodefaultint}
 
          resultdef:=left.resultdef;
       end;