2
0
Эх сурвалжийг харах

Add rounding mode operands.
Add support for trunc and round methods.

git-svn-id: branches/laksen/riscv_new@39698 -

Jeppe Johansen 7 жил өмнө
parent
commit
29ea4ed07d

+ 2 - 0
compiler/aasmtai.pas

@@ -264,6 +264,7 @@ interface
 {$endif llvm}
 {$if defined(riscv32) or defined(riscv64)}
        ,top_fenceflags
+       ,top_roundingmode
 {$endif defined(riscv32) or defined(riscv64)}
        );
 
@@ -468,6 +469,7 @@ interface
         {$endif llvm}
         {$if defined(riscv32) or defined(riscv64)}
             top_fenceflags : (fenceflags : TFenceFlags);
+            top_roundingmode : (roundingmode : TRoundingMode);
         {$endif defined(riscv32) or defined(riscv64)}
         end;
         poper=^toper;

+ 28 - 0
compiler/riscv/aasmcpu.pas

@@ -38,6 +38,9 @@ uses
 
 
     type
+
+      { taicpu }
+
       taicpu = class(tai_cpu_abstract_sym)
          memoryordering: TMemoryOrdering;
          constructor op_none(op : tasmop);
@@ -54,6 +57,7 @@ uses
 
          constructor op_reg_reg_const_const(op: tasmop; _op1, _op2: tregister; _op3, _op4: aint);
 
+         constructor op_reg_reg_roundingmode(op : tasmop;_op1,_op2 : tregister; _op3: TRoundingMode);
          constructor op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister);
          constructor op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: aint);
          constructor op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: aint);
@@ -82,6 +86,7 @@ uses
          constructor op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : aint);
          constructor op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:aint;const _op2 : treference);
 
+         procedure loadroundingmode(opidx:aint;_roundmode:TRoundingMode);
          procedure loadfenceflags(opidx:aint;_flags:TFenceFlags);
          procedure loadbool(opidx:aint;_b:boolean);
 
@@ -201,6 +206,16 @@ uses cutils, cclasses;
       end;
 
 
+    constructor taicpu.op_reg_reg_roundingmode(op: tasmop; _op1, _op2: tregister; _op3: TRoundingMode);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadroundingmode(2,_op3);
+      end;
+
+
     constructor taicpu.op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister);
       begin
          inherited create(op);
@@ -388,6 +403,19 @@ uses cutils, cclasses;
       end;
 
 
+    procedure taicpu.loadroundingmode(opidx: aint; _roundmode: TRoundingMode);
+      begin
+        allocate_oper(opidx+1);
+        with oper[opidx]^ do
+         begin
+           if typ<>top_roundingmode then
+             clearop(opidx);
+           roundingmode:=_roundmode;
+           typ:=top_roundingmode;
+         end;
+      end;
+
+
     procedure taicpu.loadfenceflags(opidx: aint; _flags: TFenceFlags);
       begin
         allocate_oper(opidx+1);

+ 3 - 1
compiler/riscv/agrvgas.pas

@@ -174,7 +174,9 @@ unit agrvgas;
             if ffO in o.fenceflags then getopstr:=getopstr+'o';
             if ffR in o.fenceflags then getopstr:=getopstr+'r';
             if ffW in o.fenceflags then getopstr:=getopstr+'w';
-          end
+          end;
+        top_roundingmode:
+          getopstr:=roundingmode2str[o.roundingmode];
         else
           internalerror(2002070604);
       end;

+ 88 - 0
compiler/riscv/nrvinl.pas

@@ -30,6 +30,9 @@ interface
        node,ninl,ncginl;
 
     type
+
+       { trvinlinenode }
+
        trvinlinenode = class(tcginlinenode)
           { first pass override
             so that the code generator will actually generate
@@ -38,12 +41,16 @@ interface
           function first_sqrt_real: tnode; override;
           function first_abs_real: tnode; override;
           function first_sqr_real: tnode; override;
+          function first_round_real: tnode; override;
+          function first_trunc_real: tnode; override;
 
           function first_fma: tnode; override;
 
           procedure second_sqrt_real; override;
           procedure second_abs_real; override;
           procedure second_sqr_real; override;
+          procedure second_round_real; override;
+          procedure second_trunc_real; override;
 
           procedure second_fma; override;
        protected
@@ -102,6 +109,31 @@ implementation
            result:=inherited first_sqr_real;
        end;
 
+
+     function trvinlinenode.first_round_real: tnode;
+       begin
+         if (current_settings.fputype >= fpu_fd) then
+           begin
+             expectloc:=LOC_FPUREGISTER;
+             first_round_real := nil;
+           end
+         else
+           result:=inherited first_round_real;
+       end;
+
+
+     function trvinlinenode.first_trunc_real: tnode;
+       begin
+         if (current_settings.fputype >= fpu_fd) then
+           begin
+             expectloc:=LOC_FPUREGISTER;
+             first_trunc_real := nil;
+           end
+         else
+           result:=inherited first_trunc_real;
+       end;
+
+
      function trvinlinenode.first_fma: tnode;
        begin
          Result:=nil;
@@ -171,6 +203,62 @@ implementation
        end;
 
 
+     procedure trvinlinenode.second_round_real;
+       var
+         op: TAsmOp;
+       begin
+         secondpass(left);
+         hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+         location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+         location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
+         { convert to signed integer rounding towards zero (there's no "round to
+           integer using current rounding mode") }
+
+{$ifdef RISCV32}
+         if (left.location.size = OS_F32) then
+           op := A_FCVT_W_S
+         else
+           op := A_FCVT_W_D;
+{$else}
+         if (left.location.size = OS_F32) then
+           op := A_FCVT_L_S
+         else
+           op := A_FCVT_L_D;
+{$endif}
+
+         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,location.register,left.location.register));
+         cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+       end;
+
+
+     procedure trvinlinenode.second_trunc_real;
+       var
+         op: TAsmOp;
+       begin
+         secondpass(left);
+         hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+         location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+         location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
+         { convert to signed integer rounding towards zero (there's no "round to
+           integer using current rounding mode") }
+
+{$ifdef RISCV32}
+         if (left.location.size = OS_F32) then
+           op := A_FCVT_W_S
+         else
+           op := A_FCVT_W_D;
+{$else}
+         if (left.location.size = OS_F32) then
+           op := A_FCVT_L_S
+         else
+           op := A_FCVT_L_D;
+{$endif}
+
+         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_roundingmode(op,location.register,left.location.register,RM_RTZ));
+         cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+       end;
+
+
      procedure trvinlinenode.second_fma;
        const
          op : array[os_f32..os_f64,false..true,false..true] of TAsmOp =

+ 11 - 0
compiler/riscv64/cpubase.pas

@@ -170,6 +170,17 @@ type
       TFenceFlag = (ffI, ffO, ffR, ffW);
       TFenceFlags = set of TFenceFlag;
 
+      TRoundingMode = (RM_Default,
+                       RM_RNE,
+                       RM_RTZ,
+                       RM_RDN,
+                       RM_RUP,
+                       RM_RMM);
+
+    const
+      roundingmode2str : array[TRoundingMode] of string[3] = ('',
+        'rne','rtz','rdn','rup','rmm');
+
 {*****************************************************************************
                                 Conditions
 *****************************************************************************}