Browse Source

* on i8086 with regvars on, do not notify the register allocator of moves to BX.
This fixes compilation of unit math (and the whole RTL) with regvars enabled.

git-svn-id: trunk@26282 -

nickysn 11 years ago
parent
commit
fdd36b4603
1 changed files with 68 additions and 0 deletions
  1. 68 0
      compiler/i8086/cgcpu.pas

+ 68 - 0
compiler/i8086/cgcpu.pas

@@ -89,6 +89,8 @@ unit cgcpu;
         procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
         procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
 
 
         procedure get_32bit_ops(op: TOpCG; out op1,op2: TAsmOp);
         procedure get_32bit_ops(op: TOpCG; out op1,op2: TAsmOp);
+
+        procedure add_move_instruction(instr:Taicpu);override;
      end;
      end;
 
 
       tcg64f8086 = class(tcg64f32)
       tcg64f8086 = class(tcg64f32)
@@ -1630,6 +1632,72 @@ unit cgcpu;
       end;
       end;
 
 
 
 
+    procedure tcg8086.add_move_instruction(instr: Taicpu);
+      begin
+        { HACK: when regvars are on, don't notify the register allocator of any
+          direct moves to BX, so it doesn't try to coalesce them. Currently,
+          direct moves to BX are only used when returning an int64 value in
+          AX:BX:CX:DX. This hack fixes a common issue with functions, returning
+          int64, for example:
+
+        function RandomFrom(const AValues: array of Int64): Int64;
+          begin
+            result:=AValues[random(High(AValues)+1)];
+          end;
+
+    	push	bp
+    	mov	bp,sp
+; Var AValues located in register ireg20w
+; Var $highAVALUES located in register ireg21w
+; Var $result located in register ireg33w:ireg32w:ireg31w:ireg30w
+    	mov	ireg20w,word [bp+6]
+    	mov	ireg21w,word [bp+4]
+; [3] result:=AValues[random(High(AValues)+1)];
+    	mov	ireg22w,ireg21w
+    	inc	ireg22w
+    	mov	ax,ireg22w
+    	cwd
+    	mov	ireg23w,ax
+    	mov	ireg24w,dx
+    	push	ireg24w
+    	push	ireg23w
+    	call	SYSTEM_$$_RANDOM$LONGINT$$LONGINT
+    	mov	ireg25w,ax
+    	mov	ireg26w,dx
+    	mov	ireg27w,ireg25w
+    	mov	ireg28w,ireg27w
+    	mov	ireg29w,ireg28w
+    	mov	cl,3
+    	shl	ireg29w,cl
+; Var $result located in register ireg32w:ireg30w
+    	mov	ireg30w,word [ireg20w+ireg29w]
+    	mov	ireg31w,word [ireg20w+ireg29w+2]
+    	mov	ireg32w,word [ireg20w+ireg29w+4]  ; problematic section start
+    	mov	ireg33w,word [ireg20w+ireg29w+6]
+; [4] end;
+    	mov	bx,ireg32w  ; problematic section end
+    	mov	ax,ireg33w
+    	mov	dx,ireg30w
+    	mov	cx,ireg31w
+    	mov	sp,bp
+    	pop	bp
+    	ret	4
+
+        the problem arises, because the register allocator tries to coalesce
+          mov bx,ireg32w
+        however, in the references [ireg20w+ireg29w+const], due to the
+        constraints of i8086, ireg20w can only be BX (or BP, which isn't available
+        to the register allocator, because it's used as a base pointer) }
+
+        if (cs_opt_regvar in current_settings.optimizerswitches) and
+           (instr.opcode=A_MOV) and (instr.ops=2) and
+           (instr.oper[1]^.typ=top_reg) and (getsupreg(instr.oper[1]^.reg)=RS_BX) then
+          exit
+        else
+          inherited add_move_instruction(instr);
+      end;
+
+
     procedure tcg8086.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
     procedure tcg8086.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
       var
       var
         hsym : tsym;
         hsym : tsym;