summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlaksen <laksen@3ad0048d-3df7-0310-abae-a5850022a9f2>2018-09-01 19:48:44 +0000
committerlaksen <laksen@3ad0048d-3df7-0310-abae-a5850022a9f2>2018-09-01 19:48:44 +0000
commit43c92a70383d7f8b71ae3ce87b59112ee8c390f7 (patch)
tree17a563bb768369f048d0990bb51fe1f9c1bae0f8
parentd4aa1d617723940296de20fa1e2a386fcb45d5f0 (diff)
downloadfpc-43c92a70383d7f8b71ae3ce87b59112ee8c390f7.tar.gz
Add rounding mode operands.
Add support for trunc and round methods. git-svn-id: https://svn.freepascal.org/svn/fpc/branches/laksen@39698 3ad0048d-3df7-0310-abae-a5850022a9f2
-rw-r--r--riscv_new/compiler/aasmtai.pas2
-rw-r--r--riscv_new/compiler/riscv/aasmcpu.pas28
-rw-r--r--riscv_new/compiler/riscv/agrvgas.pas4
-rw-r--r--riscv_new/compiler/riscv/nrvinl.pas88
-rw-r--r--riscv_new/compiler/riscv64/cpubase.pas11
5 files changed, 132 insertions, 1 deletions
diff --git a/riscv_new/compiler/aasmtai.pas b/riscv_new/compiler/aasmtai.pas
index 0a8af76bfe..99057b8696 100644
--- a/riscv_new/compiler/aasmtai.pas
+++ b/riscv_new/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;
diff --git a/riscv_new/compiler/riscv/aasmcpu.pas b/riscv_new/compiler/riscv/aasmcpu.pas
index c110dc1690..e6937a7cab 100644
--- a/riscv_new/compiler/riscv/aasmcpu.pas
+++ b/riscv_new/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);
diff --git a/riscv_new/compiler/riscv/agrvgas.pas b/riscv_new/compiler/riscv/agrvgas.pas
index 45ee41247d..a047c7c6a6 100644
--- a/riscv_new/compiler/riscv/agrvgas.pas
+++ b/riscv_new/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;
diff --git a/riscv_new/compiler/riscv/nrvinl.pas b/riscv_new/compiler/riscv/nrvinl.pas
index 4d29506dc6..9da7a05c1d 100644
--- a/riscv_new/compiler/riscv/nrvinl.pas
+++ b/riscv_new/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 =
diff --git a/riscv_new/compiler/riscv64/cpubase.pas b/riscv_new/compiler/riscv64/cpubase.pas
index c673c6a4d3..fb94973a13 100644
--- a/riscv_new/compiler/riscv64/cpubase.pas
+++ b/riscv_new/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
*****************************************************************************}