Browse Source

tcginnode.pass_generate_code: use tlhcgobj.g_undefined_ok

Also override the code that uses this for LLVM with a variant that does not
need it for LLVM versions that do not support the freeze instruction.
Jonas Maebe 2 years ago
parent
commit
29bae2297f
2 changed files with 86 additions and 24 deletions
  1. 45 1
      compiler/llvm/nllvmset.pas
  2. 41 23
      compiler/ncgset.pas

+ 45 - 1
compiler/llvm/nllvmset.pas

@@ -26,9 +26,16 @@ unit nllvmset;
 interface
 interface
 
 
   uses
   uses
-    nset, ncgset;
+    nset, ncgset,
+    symtype,
+    cgbase;
 
 
   type
   type
+    tllvminnode = class(tcginnode)
+     protected
+      procedure in_reg_const(uopdef: tdef; opsize: tcgsize); override;
+    end;
+
     tllvmcasenode = class(tcgcasenode)
     tllvmcasenode = class(tcgcasenode)
      protected
      protected
       procedure genlinearlist(hp: pcaselabel); override;
       procedure genlinearlist(hp: pcaselabel); override;
@@ -37,6 +44,42 @@ interface
 
 
 implementation
 implementation
 
 
+    uses
+      globals,
+      aasmbase, aasmdata,
+      hlcgobj,
+      llvminfo;
+
+    procedure tllvminnode.in_reg_const(uopdef: tdef; opsize: tcgsize);
+      var
+        hl,hlend: TAsmLabel;
+      begin
+        if not(llvmflag_no_freeze in llvmversion_properties[current_settings.llvmversion]) then
+          begin
+            { if we have the freeze instruction, we can mark the poison value
+              potentially generated by the shift as "replace with a fixed value
+              if it's poison, we don't care since we'll mask it anyway" }
+            inherited;
+            exit;
+          end;
+        { don't perform the bit test if the register's value can be >=
+          "number of bits in right.location", because that generates a poison
+          value in LLVM (and even anding it will 0 will keep it a poison value),
+          and calculations using poison as input result in undefined behaviour }
+        current_asmdata.getjumplabel(hl);
+        current_asmdata.getjumplabel(hlend);
+        hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,uopdef,OC_AE,
+          right.resultdef.packedbitsize,left.location.register,hl);
+        hlcg.a_bit_test_reg_loc_reg(current_asmdata.CurrAsmList,
+          uopdef,right.resultdef,uopdef,
+          left.location.register,right.location,location.register);
+        hlcg.a_jmp_always(current_asmdata.CurrAsmList,hlend);
+        hlcg.a_label(current_asmdata.CurrAsmList,hl);
+        hlcg.a_load_const_reg(current_asmdata.CurrAsmList,uopdef,0,location.register);
+        hlcg.a_label(current_asmdata.CurrAsmList,hlend);
+      end;
+
+
   procedure tllvmcasenode.genlinearlist(hp: pcaselabel);
   procedure tllvmcasenode.genlinearlist(hp: pcaselabel);
     begin
     begin
       { genlinearlist constantly updates the case value in the register,
       { genlinearlist constantly updates the case value in the register,
@@ -48,6 +91,7 @@ implementation
     end;
     end;
 
 
 begin
 begin
+  cinnode:=tllvminnode;
   ccasenode:=tllvmcasenode;
   ccasenode:=tllvmcasenode;
 end.
 end.
 
 

+ 41 - 23
compiler/ncgset.pas

@@ -51,6 +51,7 @@ interface
        protected
        protected
          function checkgenjumps(out setparts: Tsetparts; out numparts: byte; out use_small: boolean): boolean; virtual;
          function checkgenjumps(out setparts: Tsetparts; out numparts: byte; out use_small: boolean): boolean; virtual;
          function analizeset(const Aset:Tconstset;out setparts: Tsetparts; out numparts: byte;is_small:boolean):boolean;virtual;
          function analizeset(const Aset:Tconstset;out setparts: Tsetparts; out numparts: byte;is_small:boolean):boolean;virtual;
+         procedure in_reg_const(uopdef: tdef; opsize: tcgsize);virtual;
        end;
        end;
 
 
        tcgcasenode = class(tcasenode)
        tcgcasenode = class(tcasenode)
@@ -183,6 +184,45 @@ implementation
     end;
     end;
 
 
 
 
+    procedure tcginnode.in_reg_const(uopdef: tdef; opsize: tcgsize);
+      var
+        hr: tregister;
+      begin
+        { emit bit test operation -- warning: do not use
+          location_force_reg() to force a set into a register, except
+          to a register of the same size as the set. The reason is
+          that on big endian systems, this would require moving the
+          set to the most significant part of the new register,
+          and location_force_register can't do that (it does not
+          know the type).
+
+         a_bit_test_reg_loc_reg() properly takes into account the
+         size of the set to adjust the register index to test }
+        hlcg.a_bit_test_reg_loc_reg(current_asmdata.CurrAsmList,
+          uopdef, right.resultdef, uopdef,
+          left.location.register, right.location, location.register);
+
+        { this may have resulted in an undefined value if left.location.register
+          was >= size of right.location, but we'll mask the value to zero below
+          in that case -> okay }
+        hlcg.g_undefined_ok(current_asmdata.CurrAsmList,uopdef,location.register);
+
+        { now zero the result if left > nr_of_bits_in_right_register }
+        hr := hlcg.getintregister(current_asmdata.CurrAsmList, uopdef);
+        { if left > tcgsize2size[opsize]*8 then hr := 0 else hr := $ffffffff }
+        { (left.location.size = location.size at this point) }
+        hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SUB, uopdef,
+          tcgsize2size[opsize]*8, left.location.register, hr);
+        hlcg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SAR, uopdef, (tcgsize2size
+          [opsize]*8)-1, hr);
+
+
+          { if left > tcgsize2size[opsize]*8-1, then result := 0 else result := result of bit test }
+        hlcg.a_op_reg_reg(current_asmdata.CurrAsmList, OP_AND, uopdef, hr,
+          location.register);
+      end;
+
+
     procedure tcginnode.in_smallset(opdef: tdef; setbase: aint);
     procedure tcginnode.in_smallset(opdef: tdef; setbase: aint);
       begin
       begin
         { location is always LOC_REGISTER }
         { location is always LOC_REGISTER }
@@ -445,29 +485,7 @@ implementation
                      { load left in register }
                      { load left in register }
                      hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,uopdef,true);
                      hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,uopdef,true);
                      register_maybe_adjust_setbase(current_asmdata.CurrAsmList,uopdef,left.location,setbase);
                      register_maybe_adjust_setbase(current_asmdata.CurrAsmList,uopdef,left.location,setbase);
-                     { emit bit test operation -- warning: do not use
-                       location_force_reg() to force a set into a register, except
-                       to a register of the same size as the set. The reason is
-                       that on big endian systems, this would require moving the
-                       set to the most significant part of the new register,
-                       and location_force_register can't do that (it does not
-                       know the type).
-
-                      a_bit_test_reg_loc_reg() properly takes into account the
-                      size of the set to adjust the register index to test }
-                     hlcg.a_bit_test_reg_loc_reg(current_asmdata.CurrAsmList,
-                       uopdef,right.resultdef,uopdef,
-                       left.location.register,right.location,location.register);
-
-                     { now zero the result if left > nr_of_bits_in_right_register }
-                     hr := hlcg.getintregister(current_asmdata.CurrAsmList,uopdef);
-                     { if left > tcgsize2size[opsize]*8 then hr := 0 else hr := $ffffffff }
-                     { (left.location.size = location.size at this point) }
-                     hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList, OP_SUB, uopdef, tcgsize2size[opsize]*8, left.location.register, hr);
-                     hlcg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SAR, uopdef, (tcgsize2size[opsize]*8)-1, hr);
-
-                     { if left > tcgsize2size[opsize]*8-1, then result := 0 else result := result of bit test }
-                     hlcg.a_op_reg_reg(current_asmdata.CurrAsmList, OP_AND, uopdef, hr, location.register);
+                     in_reg_const(uopdef, opsize);
                    end { of right.location.loc=LOC_CONSTANT }
                    end { of right.location.loc=LOC_CONSTANT }
                  { do search in a normal set which could have >32 elements
                  { do search in a normal set which could have >32 elements
                    but also used if the left side contains higher values > 32 }
                    but also used if the left side contains higher values > 32 }