Răsfoiți Sursa

* fix #40390: implement support for handling parameter names (including __SELF and __HIGH(<identifier>)) that resolve directly to registers
+ added tests

Sven/Sarah Barth 1 an în urmă
părinte
comite
3b455c1cf2
4 a modificat fișierele cu 207 adăugiri și 30 ștergeri
  1. 145 30
      compiler/x86/rax86att.pas
  2. 17 0
      tests/test/tasm28.pp
  3. 22 0
      tests/test/tasm29.pp
  4. 23 0
      tests/webtbs/tw40390.pp

+ 145 - 30
compiler/x86/rax86att.pas

@@ -207,7 +207,105 @@ Implementation
            end;
         end;
 
+      procedure Consume_Index;
 
+        procedure Check_Scaling;
+          begin
+            { check for scaling ... }
+            case actasmtoken of
+              AS_RPAREN:
+                Begin
+                  Consume_RParen;
+                  exit;
+                end;
+              AS_COMMA:
+                Begin
+                  Consume(AS_COMMA);
+                  Consume_Scale;
+                  Consume_RParen;
+                end;
+            else
+              Begin
+                Message(asmr_e_invalid_reference_syntax);
+                RecoverConsume(false);
+              end;
+            end; { end case }
+          end;
+
+        var
+          tmp : tx86operand;
+          expr : string;
+        begin
+          if actasmtoken=AS_REGISTER then
+           Begin
+             oper.opr.ref.index:=actasmregister;
+             Consume(AS_REGISTER);
+             Check_Scaling;
+           end
+          else if actasmtoken=AS_ID then
+            begin
+              expr:=actasmpattern;
+              Consume(AS_ID);
+              tmp:=Tx86Operand.create;
+              if not tmp.SetupVar(expr,false) then
+                begin
+                  { look for special symbols ... }
+                  if expr= '__HIGH' then
+                    begin
+                      consume(AS_LPAREN);
+                      if not tmp.setupvar('high'+actasmpattern,false) then
+                        Message1(sym_e_unknown_id,'high'+actasmpattern);
+                      consume(AS_ID);
+                      consume(AS_RPAREN);
+                    end
+                  else
+                    if expr = '__SELF' then
+                      tmp.SetupSelf
+                  else
+                    begin
+                      message1(sym_e_unknown_id,expr);
+                      RecoverConsume(false);
+                      tmp.free;
+                      Exit;
+                    end;
+                end;
+              { convert OPR_LOCAL register para into a reference base }
+              if (tmp.opr.typ=OPR_LOCAL) and
+                 AsmRegisterPara(tmp.opr.localsym) then
+                begin
+                  tmp.InitRefConvertLocal;
+                  if (tmp.opr.ref.index<>NR_NO) or
+                      (tmp.opr.ref.offset<>0) or
+                      (tmp.opr.ref.scalefactor<>0) or
+                      (tmp.opr.ref.segment<>NR_NO) or
+                      (tmp.opr.ref.base=NR_NO) then
+                    begin
+                      message(asmr_e_invalid_reference_syntax);
+                      RecoverConsume(false);
+                      tmp.free;
+                      Exit;
+                    end;
+                  oper.opr.ref.index:=tmp.opr.ref.base;
+                  tmp.free;
+                  Check_Scaling;
+                end
+              else
+                begin
+                  message(asmr_e_invalid_reference_syntax);
+                  RecoverConsume(false);
+                  tmp.free;
+                  Exit;
+                end;
+            end
+          else
+           Begin
+             Message(asmr_e_invalid_reference_syntax);
+             RecoverConsume(false);
+           end;
+        end;
+
+      var
+        expr : string;
       begin
         oper.InitRef;
         Consume(AS_LPAREN);
@@ -244,7 +342,7 @@ Implementation
                 oper.opr.ref.refaddr:=addr_pic_no_got;
 {$endif x86_64}
               Consume(AS_REGISTER);
-              { can either be a register or a right parenthesis }
+              { can either be a register, an identifier or a right parenthesis }
               { (reg)        }
               if actasmtoken=AS_RPAREN then
                Begin
@@ -253,36 +351,53 @@ Implementation
                end;
               { (reg,reg ..  }
               Consume(AS_COMMA);
-              if actasmtoken=AS_REGISTER then
-               Begin
-                 oper.opr.ref.index:=actasmregister;
-                 Consume(AS_REGISTER);
-                 { check for scaling ... }
-                 case actasmtoken of
-                   AS_RPAREN:
-                     Begin
-                       Consume_RParen;
-                       exit;
-                     end;
-                   AS_COMMA:
-                     Begin
-                       Consume(AS_COMMA);
-                       Consume_Scale;
-                       Consume_RParen;
-                     end;
-                 else
-                   Begin
-                     Message(asmr_e_invalid_reference_syntax);
-                     RecoverConsume(false);
-                   end;
-                 end; { end case }
-               end
-              else
-               Begin
-                 Message(asmr_e_invalid_reference_syntax);
-                 RecoverConsume(false);
-               end;
+              Consume_Index;
             end; {end case }
+          AS_ID: { identifier (parameter, variable, ...), but only those that might be in a register }
+            begin
+              expr:=actasmpattern;
+              Consume(AS_ID);
+              if not oper.SetupVar(expr,false) then
+                begin
+                  { look for special symbols ... }
+                  if expr= '__HIGH' then
+                    begin
+                      consume(AS_LPAREN);
+                      if not oper.setupvar('high'+actasmpattern,false) then
+                        Message1(sym_e_unknown_id,'high'+actasmpattern);
+                      consume(AS_ID);
+                      consume(AS_RPAREN);
+                    end
+                  else
+                    if expr = '__SELF' then
+                      oper.SetupSelf
+                  else
+                    begin
+                      message1(sym_e_unknown_id,expr);
+                      RecoverConsume(false);
+                      Exit;
+                    end;
+                end;
+              { convert OPR_LOCAL register para into a reference base }
+              if (oper.opr.typ=OPR_LOCAL) and
+                 AsmRegisterPara(oper.opr.localsym) then
+                oper.InitRefConvertLocal
+              else
+                begin
+                  message(asmr_e_invalid_reference_syntax);
+                  RecoverConsume(false);
+                  Exit;
+                end;
+              { can either be a register, an identifier or a right parenthesis }
+              { (reg)        }
+              if actasmtoken=AS_RPAREN then
+                begin
+                  Consume_RParen;
+                  exit;
+                end;
+              Consume(AS_COMMA);
+              Consume_Index;
+            end;
           AS_COMMA: { (, ...  can either be scaling, or index }
             Begin
               Consume(AS_COMMA);

+ 17 - 0
tests/test/tasm28.pp

@@ -0,0 +1,17 @@
+{ %NORUN }
+{ %CPU=i386,x86_64 }
+
+program tasm28;
+
+{$mode objfpc}
+
+{$asmmode att}
+procedure Test(aArr: array of LongInt); {$ifdef cpu386}register;{$endif} assembler; nostackframe;
+asm
+  movb $5, (aArr, __HIGH(aArr))
+  movb $5, (__HIGH(aArr), aArr)
+end;
+
+begin
+
+end.

+ 22 - 0
tests/test/tasm29.pp

@@ -0,0 +1,22 @@
+{ %NORUN }
+{ %CPU=i386,x86_64 }
+
+program tasm29;
+
+{$mode objfpc}
+
+type
+
+  TTest = class
+    procedure Test(aArg: Pointer); {$ifdef cpu386}register;{$endif} assembler; nostackframe;
+  end;
+
+procedure TTest.Test(aArg: Pointer); {$ifdef cpu386}register;{$endif} assembler; nostackframe;
+asm
+  movb $5, (__SELF, aArg)
+  movb $5, (aArg, __SELF)
+end;
+
+begin
+
+end.

+ 23 - 0
tests/webtbs/tw40390.pp

@@ -0,0 +1,23 @@
+{ %NORUN }
+{ %CPU=i386,x86_64 }
+
+program tw40390;
+
+{$asmmode att}
+procedure SetMiddleTo5(p: pointer; n: SizeUint); {$ifdef cpu386}register;{$endif} assembler; nostackframe;
+asm
+{$ifdef cpu386}
+    shrl $1, n     // becomes “shrq $1, %rdx” (Win64) or “shrq $1, %rsi” (System V)
+    movb $5, (p,n) // Invalid reference syntax.
+    movb $5, (%edx,n)
+    movb $5, (p,%edx)
+{$elseif defined(cpux86_64)}
+    shrq $1, n     // becomes “shrq $1, %rdx” (Win64) or “shrq $1, %rsi” (System V)
+    movb $5, (p,n) // Invalid reference syntax.
+    movb $5, (%rdx,n)
+    movb $5, (p,%rdx)
+{$endif}
+end;
+
+begin
+end.