diff options
author | laksen <laksen@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2018-09-01 19:48:44 +0000 |
---|---|---|
committer | laksen <laksen@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2018-09-01 19:48:44 +0000 |
commit | 43c92a70383d7f8b71ae3ce87b59112ee8c390f7 (patch) | |
tree | 17a563bb768369f048d0990bb51fe1f9c1bae0f8 | |
parent | d4aa1d617723940296de20fa1e2a386fcb45d5f0 (diff) | |
download | fpc-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.pas | 2 | ||||
-rw-r--r-- | riscv_new/compiler/riscv/aasmcpu.pas | 28 | ||||
-rw-r--r-- | riscv_new/compiler/riscv/agrvgas.pas | 4 | ||||
-rw-r--r-- | riscv_new/compiler/riscv/nrvinl.pas | 88 | ||||
-rw-r--r-- | riscv_new/compiler/riscv64/cpubase.pas | 11 |
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 *****************************************************************************} |