Imported Upstream version 6.0.0
[platform/upstream/gmp.git] / mpn / x86 / k6 / cross.pl
1 #! /usr/bin/perl
2
3 # Copyright 2000, 2001 Free Software Foundation, Inc.
4 #
5 #  This file is part of the GNU MP Library.
6 #
7 #  The GNU MP Library is free software; you can redistribute it and/or modify
8 #  it under the terms of either:
9 #
10 #    * the GNU Lesser General Public License as published by the Free
11 #      Software Foundation; either version 3 of the License, or (at your
12 #      option) any later version.
13 #
14 #  or
15 #
16 #    * the GNU General Public License as published by the Free Software
17 #      Foundation; either version 2 of the License, or (at your option) any
18 #      later version.
19 #
20 #  or both in parallel, as here.
21 #
22 #  The GNU MP Library is distributed in the hope that it will be useful, but
23 #  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 #  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25 #  for more details.
26 #
27 #  You should have received copies of the GNU General Public License and the
28 #  GNU Lesser General Public License along with the GNU MP Library.  If not,
29 #  see https://www.gnu.org/licenses/.
30
31
32 # Usage: cross.pl [filename.o]...
33 #
34 # Produce an annotated disassembly of the given object files, indicating
35 # certain code alignment and addressing mode problems afflicting K6 chips.
36 # "ZZ" is used on all annotations, so this can be searched for.
37 #
38 # With no arguments, all .o files corresponding to .asm files are processed.
39 # This is good in the mpn object directory of a k6*-*-* build.
40 #
41 # Code alignments of 8 bytes or more are handled.  When 32 is used, cache
42 # line boundaries will fall in at offsets 0x20,0x40,etc and problems are
43 # flagged at those locations.  When 16 is used, the line boundaries can also
44 # fall at offsets 0x10,0x30,0x50,etc, depending where the file is loaded, so
45 # problems are identified there too.  Likewise when 8 byte alignment is used
46 # problems are flagged additionally at 0x08,0x18,0x28,etc.
47 #
48 # Usually 32 byte alignment is used for k6 routines, but less is certainly
49 # possible if through good luck, or a little tweaking, cache line crossing
50 # problems can be avoided at the extra locations.
51 #
52 # Bugs:
53 #
54 # Instructions without mod/rm bytes or which are already vector decoded are
55 # unaffected by cache line boundary crossing, but not all of these have yet
56 # been put in as exceptions.  All that occur in practice in GMP are present
57 # though.
58 #
59 # There's no messages for using the vector decoded addressing mode (%esi),
60 # but that's easy to avoid when coding.
61 #
62 # Future:
63 #
64 # Warn about jump targets that are poorly aligned (less than 2 instructions
65 # before a cache line boundary).
66
67 use strict;
68
69 sub disassemble {
70     my ($file) = @_;
71     my ($addr,$b1,$b2,$b3, $prefix,$opcode,$modrm);
72     my $align;
73
74     open (IN, "objdump -Srfh $file |")
75         || die "Cannot open pipe from objdump\n";
76     while (<IN>) {
77         print;
78
79         if (/^[ \t]*[0-9]+[ \t]+\.text[ \t]/ && /2\*\*([0-9]+)$/) {
80             $align = 1 << $1;
81             if ($align < 8) {
82                 print "ZZ cross.pl cannot handle alignment < 2**3\n";
83                 $align = 8
84             }
85         }
86
87         if (/^[ \t]*([0-9a-f]*):[ \t]*([0-9a-f]+)[ \t]+([0-9a-f]+)[ \t]+([0-9a-f]+)/) {
88             ($addr,$b1,$b2,$b3) = ($1,$2,$3,$4);
89
90         } elsif (/^[ \t]*([0-9a-f]*):[ \t]*([0-9a-f]+)[ \t]+([0-9a-f]+)/) {
91             ($addr,$b1,$b2,$b3) = ($1,$2,$3,'');
92
93         } elsif (/^[ \t]*([0-9a-f]*):[ \t]*([0-9a-f]+)/) {
94             ($addr,$b1,$b2,$b3) = ($1,$2,'','');
95
96         } else {
97             next;
98         }
99
100         if ($b1 =~ /0f/) {
101             $prefix = $b1;
102             $opcode = $b2;
103             $modrm = $b3;
104         } else {
105             $prefix = '';
106             $opcode = $b1;
107             $modrm = $b2;
108         }
109
110         # modrm of the form 00-xxx-100 with an 0F prefix is the problem case
111         # for K6 and pre-CXT K6-2
112         if ($prefix =~ /0f/
113             && $opcode !~ /^8/         # jcond disp32
114             && $modrm =~ /^[0-3][4c]/) {
115             print "ZZ ($file) >3 bytes to determine instruction length [K6]\n";
116         }
117
118         # with just an opcode, starting 1f mod 20h
119         if (($align==32 && $addr =~ /[13579bdf]f$/
120              || $align==16 && $addr =~ /f$/
121              || $align==8 && $addr =~ /[7f]$/)
122             && $prefix !~ /0f/
123             && $opcode !~ /1[012345]/ # adc
124             && $opcode !~ /1[89abcd]/ # sbb
125             && $opcode !~ /^4/        # inc/dec reg
126             && $opcode !~ /^5/        # push/pop reg
127             && $opcode !~ /68/        # push $imm32
128             && $opcode !~ /^7/        # jcond disp8
129             && $opcode !~ /a[89]/     # test+imm
130             && $opcode !~ /a[a-f]/    # stos/lods/scas
131             && $opcode !~ /b8/        # movl $imm32,%eax
132             && $opcode !~ /d[0123]/   # rcl
133             && $opcode !~ /e[0123]/   # loop/loopz/loopnz/jcxz
134             && $opcode !~ /e8/        # call disp32
135             && $opcode !~ /e[9b]/     # jmp disp32/disp8
136             && $opcode !~ /f[89abcd]/ # clc,stc,cli,sti,cld,std
137             && !($opcode =~ /f[67]/          # grp 1
138                  && $modrm =~ /^[2367abef]/) # mul, imul, div, idiv
139             && $modrm !~ /^$/) {
140             print "ZZ ($file) opcode/modrm cross 32-byte boundary\n";
141         }
142
143         # with an 0F prefix, anything starting at 1f mod 20h
144         if (($align==32 && $addr =~ /[13579bdf][f]$/
145              || $align==16 && $addr =~ /f$/
146              || $align==8 && $addr =~ /[7f]$/)
147             && $prefix =~ /0f/
148             && $opcode !~ /af/        # imul
149             && $opcode !~ /a[45]/     # shldl
150             && $opcode !~ /a[cd]/     # shrdl
151             ) {
152             print "ZZ ($file) prefix/opcode cross 32-byte boundary\n";
153         }
154
155         # with an 0F prefix, anything with mod/rm starting at 1e mod 20h
156         if (($align==32 && $addr =~ /[13579bdf][e]$/
157              || $align==16 && $addr =~ /[e]$/
158              || $align==8 && $addr =~ /[6e]$/)
159             && $prefix =~ /0f/
160              && $opcode !~ /^8/        # jcond disp32
161              && $opcode !~ /af/        # imull reg,reg
162              && $opcode !~ /a[45]/     # shldl
163              && $opcode !~ /a[cd]/     # shrdl
164             && $modrm !~ /^$/) {
165             print "ZZ ($file) prefix/opcode/modrm cross 32-byte boundary\n";
166         }
167     }
168     close IN || die "Error from objdump (or objdump not available)\n";
169 }
170
171
172 my @files;
173 if ($#ARGV >= 0) {
174     @files = @ARGV;
175 } else {
176     @files = glob "*.asm";
177     map {s/.asm/.o/} @files;
178 }
179
180 foreach (@files)  {
181     disassemble($_);
182 }