瀏覽代碼

+ inline trunc() support for the LLVM backend when using -Oofastmath (because
the behaviour of LLVM's fptosi instruction is undefined in case of
overflow)

git-svn-id: trunk@36275 -

Jonas Maebe 8 年之前
父節點
當前提交
e4dbd24a49
共有 1 個文件被更改,包括 62 次插入3 次删除
  1. 62 3
      compiler/llvm/nllvminl.pas

+ 62 - 3
compiler/llvm/nllvminl.pas

@@ -32,27 +32,56 @@ interface
     type
     type
       tllvminlinenode = class(tcginlinenode)
       tllvminlinenode = class(tcginlinenode)
        protected
        protected
+        procedure maybe_remove_round_trunc_typeconv;
+
         function first_get_frame: tnode; override;
         function first_get_frame: tnode; override;
         function first_abs_real: tnode; override;
         function first_abs_real: tnode; override;
         function first_sqr_real: tnode; override;
         function first_sqr_real: tnode; override;
+        function first_trunc_real: tnode; override;
        public
        public
         procedure second_length; override;
         procedure second_length; override;
         procedure second_sqr_real; override;
         procedure second_sqr_real; override;
+        procedure second_trunc_real; override;
       end;
       end;
 
 
 
 
 implementation
 implementation
 
 
      uses
      uses
-       verbose,globtype,constexp,
+       verbose,globals,globtype,constexp,
        aasmbase, aasmdata,
        aasmbase, aasmdata,
-       symtype,symdef,defutil,
-       nutils,nadd,nbas,ncal,ncon,nflw,ninl,nld,nmat,
+       symconst,symtype,symdef,defutil,
+       nutils,nadd,nbas,ncal,ncnv,ncon,nflw,ninl,nld,nmat,
        pass_2,
        pass_2,
        cgbase,cgutils,tgobj,hlcgobj,
        cgbase,cgutils,tgobj,hlcgobj,
        cpubase,
        cpubase,
        llvmbase,aasmllvm;
        llvmbase,aasmllvm;
 
 
+     procedure tllvminlinenode.maybe_remove_round_trunc_typeconv;
+       var
+         temp: tnode;
+       begin
+         { the prototype of trunc()/round() in the system unit is declared
+           with valreal as parameter type, so the argument will always be
+           extended -> remove the typeconversion to extended if any; not done
+           in ninl, because there are other code generators that assume that
+           the parameter to trunc has been converted to valreal (e.g. PowerPC).
+
+           (copy from code in nx64inl, should be refactored)
+         }
+         if (left.nodetype=typeconvn) and
+            not(nf_explicit in left.flags) and
+            (ttypeconvnode(left).left.resultdef.typ=floatdef) then
+           begin
+             { get rid of the type conversion, so the use_vectorfpu will be
+               applied to the original type }
+             temp:=ttypeconvnode(left).left;
+             ttypeconvnode(left).left:=nil;
+             left.free;
+             left:=temp;
+           end;
+       end;
+
 
 
      function tllvminlinenode.first_get_frame: tnode;
      function tllvminlinenode.first_get_frame: tnode;
        begin
        begin
@@ -127,6 +156,21 @@ implementation
       end;
       end;
 
 
 
 
+    function tllvminlinenode.first_trunc_real: tnode;
+      begin
+        { fptosi is undefined if the value is out of range -> only generate
+          in cast of fastmath }
+        if cs_opt_fastmath in current_settings.optimizerswitches then
+          begin
+            maybe_remove_round_trunc_typeconv;
+            expectloc:=LOC_REGISTER;
+            result:=nil;
+          end
+        else
+          result:=inherited;
+      end;
+
+
     procedure tllvminlinenode.second_length;
     procedure tllvminlinenode.second_length;
       var
       var
         lengthlab, nillab: tasmlabel;
         lengthlab, nillab: tasmlabel;
@@ -208,6 +252,21 @@ implementation
         );
         );
       end;
       end;
 
 
+
+    procedure tllvminlinenode.second_trunc_real;
+      begin
+        secondpass(left);
+        if use_vectorfpu(left.resultdef) then
+          hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true)
+        else
+          hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+        location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+        location.register:=hlcg.getregisterfordef(current_asmdata.CurrAsmList,resultdef);
+        current_asmdata.CurrAsmList.concat(
+          taillvm.op_reg_size_reg_size(la_fptosi,location.register,left.resultdef,left.location.register,resultdef)
+        );
+      end;
+
 begin
 begin
   cinlinenode:=tllvminlinenode;
   cinlinenode:=tllvminlinenode;
 end.
 end.