diff --git a/compiler/x86/aoptx86.pas b/compiler/x86/aoptx86.pas index 062d01cc2e..dc2f6c2e48 100644 --- a/compiler/x86/aoptx86.pas +++ b/compiler/x86/aoptx86.pas @@ -7937,6 +7937,9 @@ unit aoptx86; function TX86AsmOptimizer.OptPass2Movx(var p : tai) : boolean; + label + { This label permits the case block for MOVSX/D to pass into the MOVZX block } + movzx_cascade; var ThisReg: TRegister; MinSize, MaxSize, TrySmaller, TargetSize: TOpSize; @@ -8436,6 +8439,46 @@ unit aoptx86; Break; end; *) + A_MOVSX{$ifdef x86_64}, A_MOVSXD{$endif x86_64}: + begin + { If there are no instructions in between, then we might be able to make a saving } + if (InstrMax <> -1) or (taicpu(hp1).oper[0]^.typ <> top_reg) or (taicpu(hp1).oper[0]^.reg <> ThisReg) then + Break; + + { We have something like: + movzbw %dl,%dx + ... + movswl %dx,%edx + + Change the latter to a zero-extension then enter the + A_MOVZX case branch. + } + +{$ifdef x86_64} + if taicpu(hp1).opcode = A_MOVSXD then + begin + { this becomes a zero extension from 32-bit to 64-bit, but + the upper 32 bits are already zero, so just delete the + instruction } + + DebugMsg(SPeepholeOptimization + 'MovzMovsxd2MovzNop', hp1); + RemoveInstruction(hp1); + + Result := True; + Exit; + end + else +{$endif x86_64} + begin + DebugMsg(SPeepholeOptimization + 'MovzMovs2MovzMovz', hp1); + taicpu(hp1).opcode := A_MOVZX; + Result := True; + + { Enter the A_MOVZX block below } + goto movzx_cascade; + end; + end; + A_MOVZX: begin if not MatchOpType(taicpu(hp1), top_reg, top_reg) then @@ -8460,6 +8503,7 @@ unit aoptx86; Break; end; +movzx_cascade: { The objective here is to try to find a combination that removes one of the MOV/Z instructions. } case taicpu(hp1).opsize of