diff --git a/compiler/llvm/aasmllvmmetadata.pas b/compiler/llvm/aasmllvmmetadata.pas index 6418b0f42e..b0710d19e8 100644 --- a/compiler/llvm/aasmllvmmetadata.pas +++ b/compiler/llvm/aasmllvmmetadata.pas @@ -129,11 +129,12 @@ interface function llvm_getmetadatareftypedconst(metadata: tai_llvmbasemetadatanode): tai_simpletypedconst; + function llvm_constrainedexceptmodestring: ansistring; implementation uses - verbose, + verbose,globals, fmodule, symdef; @@ -142,6 +143,14 @@ implementation result:=tai_simpletypedconst.create(llvm_metadatatype, tai_llvmmetadatareftypedconst.create(metadata)); end; + function llvm_constrainedexceptmodestring: ansistring; + begin + if not(cs_opt_fastmath in current_settings.optimizerswitches) then + result:='fpexcept.strict' + else + result:='fpexcept.ignore' + end; + procedure tai_llvmbasemetadatanode.addvalue(val: tai_abstracttypedconst); begin { bypass string merging attempts, as we add tai_strings directly here } diff --git a/compiler/llvm/llvminfo.pas b/compiler/llvm/llvminfo.pas index 05b82c1031..0dfa8b8e88 100644 --- a/compiler/llvm/llvminfo.pas +++ b/compiler/llvm/llvminfo.pas @@ -41,14 +41,16 @@ Type llvmver_7_0, llvmver_7_1, llvmver_8_0, - llvmver_9_0 + llvmver_9_0, + llvmver_10_0 ); type tllvmversionflag = ( - llvmflag_memcpy_indiv_align, { memcpy intrinsic supports separate alignment for source and dest } - llvmflag_null_pointer_valid, { supports "llvmflag_null_pointer_valid" attribute, which indicates access to nil should not be optimized as undefined behaviour } - llvmflag_constrained_fptrunc_fpext { supports constrained fptrunc and fpext intrinsics } + llvmflag_memcpy_indiv_align, { memcpy intrinsic supports separate alignment for source and dest } + llvmflag_null_pointer_valid, { supports "llvmflag_null_pointer_valid" attribute, which indicates access to nil should not be optimized as undefined behaviour } + llvmflag_constrained_fptrunc_fpext, { supports constrained fptrunc and fpext intrinsics } + llvmflag_constrained_fptoi_itofp { supports constrained fptosi/fptoui/uitofp/sitofp instrinsics } ); tllvmversionflags = set of tllvmversionflag; @@ -60,7 +62,8 @@ Const '7.0', '7.1', '8.0', - '9.0' + '9.0', + '10.0' ); llvmversion_properties: array[tllvmversion] of tllvmversionflags = @@ -71,7 +74,8 @@ Const { llvmver_7_0 } [llvmflag_memcpy_indiv_align,llvmflag_null_pointer_valid], { llvmver_7_1 } [llvmflag_memcpy_indiv_align,llvmflag_null_pointer_valid], { llvmver_8_0 } [llvmflag_memcpy_indiv_align,llvmflag_null_pointer_valid], - { llvmver_9_0 } [llvmflag_memcpy_indiv_align,llvmflag_null_pointer_valid,llvmflag_constrained_fptrunc_fpext] + { llvmver_9_0 } [llvmflag_memcpy_indiv_align,llvmflag_null_pointer_valid,llvmflag_constrained_fptrunc_fpext], + { llvmver_10_0 } [llvmflag_memcpy_indiv_align,llvmflag_null_pointer_valid,llvmflag_constrained_fptrunc_fpext,llvmflag_constrained_fptoi_itofp] ); { Supported optimizations, only used for information } diff --git a/compiler/llvm/nllvmcnv.pas b/compiler/llvm/nllvmcnv.pas index f31e12d2e6..4f8405a551 100644 --- a/compiler/llvm/nllvmcnv.pas +++ b/compiler/llvm/nllvmcnv.pas @@ -64,11 +64,11 @@ interface implementation uses - globtype,globals,verbose, + globtype,globals,cutils,verbose, aasmbase,aasmdata, - llvmbase,aasmllvm, + llvmbase,llvminfo,aasmllvm,aasmllvmmetadata,llvmdef, procinfo, - ncal, + ncal,ncon, symconst,symdef,defutil, cgbase,cgutils,tgobj,hlcgobj,pass_2; @@ -104,9 +104,37 @@ class function tllvmtypeconvnode.target_specific_need_equal_typeconv(fromdef, to function tllvmtypeconvnode.first_int_to_real: tnode; +{$push}{$j+} + const + intrinfix: array[boolean] of string[7] = + ('uitofp','sitofp'); +{$pop} + var + exceptmode: ansistring; begin - expectloc:=LOC_FPUREGISTER; - result:=nil; + if (llvmflag_constrained_fptoi_itofp in llvmversion_properties[current_settings.llvmversion]) and + { these are converted to 80 bits first in any case } + not(tfloatdef(resultdef).floattype in [s64currency,s64comp]) and + ((left.resultdef.size>=resultdef.size) or + ((torddef(left.resultdef).ordtype=u64bit) and + (tfloatdef(resultdef).floattype=s80real))) then + begin + { in case rounding may have to be applied, use the intrinsic } + exceptmode:=llvm_constrainedexceptmodestring; + result:=ccallnode.createintern('llvm_experimental_constrained_'+intrinfix[is_signed(left.resultdef)]+llvmfloatintrinsicsuffix(tfloatdef(resultdef))+'_i'+tostr(left.resultdef.size*8), + ccallparanode.create(cstringconstnode.createpchar(ansistring2pchar(exceptmode),length(exceptmode),llvm_metadatatype), + ccallparanode.create(cstringconstnode.createpchar(ansistring2pchar('round.dynamic'),length('round.dynamic'),llvm_metadatatype), + ccallparanode.create(left,nil) + ) + ) + ); + left:=nil; + end + else + begin + expectloc:=LOC_FPUREGISTER; + result:=nil; + end; end; diff --git a/rtl/inc/llvmintr.inc b/rtl/inc/llvmintr.inc index 3819102f0d..6e7063629c 100644 --- a/rtl/inc/llvmintr.inc +++ b/rtl/inc/llvmintr.inc @@ -105,3 +105,14 @@ function llvm_experimental_constrained_fptrunc_f64_f128(a: float128; rounding, e function llvm_experimental_constrained_fpext_f128_f32(a: single; exceptions: LLVMMetadata): float128; compilerproc; external name 'llvm.experimental.constrained.fpext.f128.f32'; function llvm_experimental_constrained_fpext_f128_f64(a: double; exceptions: LLVMMetadata): float128; compilerproc; external name 'llvm.experimental.constrained.fpext.f128.f64'; {$endif} + +{ only include the cases that may trigger rounding } +function llvm_experimental_constrained_sitofp_f32_i32(val: longint; rounding, exceptions: LLVMMetadata): single; compilerproc; external name 'llvm.experimental.constrained.sitofp.f32.i32'; +function llvm_experimental_constrained_sitofp_f32_i64(val: int64; rounding, exceptions: LLVMMetadata): single; compilerproc; external name 'llvm.experimental.constrained.sitofp.f32.i64'; +function llvm_experimental_constrained_sitofp_f64_i64(val: int64; rounding, exceptions: LLVMMetadata): double; compilerproc; external name 'llvm.experimental.constrained.sitofp.f64.i64'; +function llvm_experimental_constrained_uitofp_f32_i32(val: cardinal; rounding, exceptions: LLVMMetadata): single; compilerproc; external name 'llvm.experimental.constrained.uitofp.f32.i32'; +function llvm_experimental_constrained_uitofp_f32_i64(val: qword; rounding, exceptions: LLVMMetadata): single; compilerproc; external name 'llvm.experimental.constrained.uitofp.f32.i64'; +function llvm_experimental_constrained_uitofp_f64_i64(val: qword; rounding, exceptions: LLVMMetadata): double; compilerproc; external name 'llvm.experimental.constrained.uitofp.f64.i64'; +{$ifdef SUPPORT_EXTENDED} +function llvm_experimental_constrained_uitofp_f80_i64(val: qword; rounding, exceptions: LLVMMetadata): extended; compilerproc; external name 'llvm.experimental.constrained.uitofp.x86_fp80.i64'; +{$endif}