blob: b505e486e1385686d546a6a47d9f43f5be773a07 [file] [log] [blame]
Jim Cownie5e8470a2013-09-27 10:38:44 +00001#!/usr/bin/perl
2
3#
4#//===----------------------------------------------------------------------===//
5#//
6#// The LLVM Compiler Infrastructure
7#//
8#// This file is dual licensed under the MIT and the University of Illinois Open
9#// Source Licenses. See LICENSE.txt for details.
10#//
11#//===----------------------------------------------------------------------===//
12#
13
14use strict;
15use warnings;
16
17use FindBin;
18use lib "$FindBin::Bin/lib";
19
Jim Cownie5e8470a2013-09-27 10:38:44 +000020use tools;
21
22our $VERSION = "0.004";
Jonathan Peyton4c91ad12016-01-26 19:44:31 +000023my $target_os;
24my $target_arch;
25my $target_mic_arch;
Jim Cownie5e8470a2013-09-27 10:38:44 +000026
27my $hex = qr{[0-9a-f]}i; # hex digit.
28
Andrey Churbanovd315cea2015-01-16 12:54:51 +000029# mic-specific details.
Jim Cownie5e8470a2013-09-27 10:38:44 +000030
Andrey Churbanovd315cea2015-01-16 12:54:51 +000031sub bad_mic_fmt($) {
Jim Cownie5e8470a2013-09-27 10:38:44 +000032 # Before we allowed both elf64-x86-64-freebsd and elf-l1om-freebsd.
33 # Now the first one is obsolete, only elf64-l1om-freebsd is allowed.
34 my ( $fmt ) = @_;
35 if ( 0 ) {
Andrey Churbanovd315cea2015-01-16 12:54:51 +000036 } elsif ( "$target_mic_arch" eq "knf" ) {
Jim Cownie5e8470a2013-09-27 10:38:44 +000037 return $fmt !~ m{\Aelf64-l1om?\z};
Andrey Churbanovd315cea2015-01-16 12:54:51 +000038 } elsif ( "$target_mic_arch" eq "knc" ) {
Jim Cownie5e8470a2013-09-27 10:38:44 +000039 return $fmt !~ m{\Aelf64-k1om?\z};
40 } else {
41 return 1;
42 };
Andrey Churbanovd315cea2015-01-16 12:54:51 +000043}; # sub bad_mic_fmt
Jim Cownie5e8470a2013-09-27 10:38:44 +000044
Andrey Churbanovd315cea2015-01-16 12:54:51 +000045# Undesired instructions for mic: all x87 and some other.
Jim Cownie5e8470a2013-09-27 10:38:44 +000046# AC: Since compiler 2010-06-30 x87 instructions are supported, removed the check of x87.
Andrey Churbanovd315cea2015-01-16 12:54:51 +000047my $mic_bad_re;
48sub bad_mic_instr($$) {
Jim Cownie5e8470a2013-09-27 10:38:44 +000049 my ( $instr, $args ) = @_;
Andrey Churbanovd315cea2015-01-16 12:54:51 +000050 if ( "$target_mic_arch" eq "knc" ) {
Jim Cownie5e8470a2013-09-27 10:38:44 +000051 # workaround of bad code generation on KNF Linux* OS:
Andrey Churbanovd315cea2015-01-16 12:54:51 +000052 return ( defined( $instr ) and $instr =~ $mic_bad_re );
Jim Cownie5e8470a2013-09-27 10:38:44 +000053 } else {
Andrey Churbanovd315cea2015-01-16 12:54:51 +000054 return ( defined( $instr ) and $instr =~ $mic_bad_re or defined( $args ) and $args =~ m{xmm}i );
Jim Cownie5e8470a2013-09-27 10:38:44 +000055 }
Andrey Churbanovd315cea2015-01-16 12:54:51 +000056}; # sub bad_mic_instr
Jim Cownie5e8470a2013-09-27 10:38:44 +000057
58# lin_32-specific details.
59
60sub bad_ia32_fmt($) {
61 my ( $fmt ) = @_;
62 return $fmt !~ m{\Aelf32-i386\z};
63}; # sub bad_ia32_fmt
64
65my @sse2 =
66 qw{
67 movapd movupd movhpd movlpd movmskpd movsd
68 addpd addsd subpd subsd mulpd mulsd divpd divsd sqrtpd sqrtsd maxpd maxsd minpd minsd
69 andpd andnpd orpd xorpd
70 cmppd cmpsd comisd ucomisd
71 shufpd unpckhpd unpcklpd
72 cvtpd2pi cvttpd2pi cvtpi2pd cvtpd2dq cvttpd2dq cvtdq2pd cvtps2pd cvtpd2ps cvtss2sd cvtsd2ss
73 cvtsd2si cvttsd2si cvtsi2sd cvtdq2ps cvtps2dq cvttps2dq movdqa movdqu movq2dq movdq2q
74 pmuludq paddq psubq pshuflw pshufhw pshufd pslldq psrldq punpckhqdq punpcklqdq clflush
75 lfence mfence maskmovdqu movntpd movntdq movnti
76 };
77my @sse3 =
78 qw{
79 fisttp lddqu addsubps addsubpd haddps hsubps haddpd hsubpd movshdup movsldup movddup monitor
80 mwait
81 };
82my @ssse3 =
83 qw{
84 phaddw phaddsw phaddd phsubw phsubsw phsubd pabsb pabsw pabsd pmaddubsw pmulhrsw pshufb
85 psignb psignw psignd palignr
86 };
87my @sse4 =
88 (
89 # SSE4.1
90 qw{
91 pmulld pmuldq dppd dpps movntdqa blendpd blendps blendvpd blendvps pblendvb pblendw pminuw
92 pminud pminsb pminsd pmaxuw pmaxud pmaxsb pmaxsd roundps roundpd roundss roundsd extractps
93 insertps pinsrb pinsrd pinsrq pextrb pextrw pextrd pextrq pmovsxbw pmovzxbw pmovsxbd
94 pmovzxbd pmovsxwd pmovzxwd pmovsxbq pmovzxbq pmovsxwq pmovzxwq pmovsxdq pmovzxdq mpsadbw
95 phminposuw ptest pcmpeqq packusdw
96 },
97 # SSE4.2
98 qw{
99 pcmpestri pcmpestrm pcmpistri pcmpistrm pcmpgtq crc32 popcnt
100 }
101 );
102
103# Undesired instructions for IA-32 architecture: Pentium 4 (SSE2) and newer.
104# TODO: It would be much more reliable to list *allowed* instructions rather than list undesired
105# instructions. In such a case the list will be stable and not require update when SSE5 is released.
106my @ia32_bad_list = ( @sse2, @sse3, @ssse3, @sse4 );
107
108my $ia32_bad_re = qr{@{[ "^(?:" . join( "|", @ia32_bad_list ) . ")" ]}}i;
109
110sub bad_ia32_instr($$) {
111 my ( $instr, $args ) = @_;
112 return ( defined( $instr ) and $instr =~ $ia32_bad_re );
113}; # sub bad_ia32_instr
114
115sub check_file($;$$) {
116
117 my ( $file, $show_instructions, $max_instructions ) = @_;
118 my @bulk;
119
120 if ( not defined( $max_instructions ) ) {
121 $max_instructions = 100;
122 }; # if
123
Andrey Churbanovd315cea2015-01-16 12:54:51 +0000124 execute( [ "x86_64-k1om-linux-objdump", "-d", $file ], -stdout => \@bulk );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000125
126 my $n = 0;
127 my $errors = 0;
128 my $current_func = ""; # Name of current fuction.
129 my $reported_func = ""; # name of last reported function.
130 foreach my $line ( @bulk ) {
131 ++ $n;
132 if ( 0 ) {
133 } elsif ( $line =~ m{^\s*$} ) {
134 # Empty line.
135 # Ignore.
136 } elsif ( $line =~ m{^In archive (.*?):\s*$} ) {
Jonathan Peytonf0efbb52015-06-01 02:41:44 +0000137 # In archive libomp.a:
Jim Cownie5e8470a2013-09-27 10:38:44 +0000138 } elsif ( $line =~ m{^(?:.*?):\s*file format (.*?)\s*$} ) {
Jonathan Peytonf0efbb52015-06-01 02:41:44 +0000139 # libomp.so: file format elf64-x86-64-freebsd
Jim Cownie5e8470a2013-09-27 10:38:44 +0000140 # kmp_ftn_cdecl.o: file format elf64-x86-64
141 my $fmt = $1;
142 if ( bad_fmt( $fmt ) ) {
143 runtime_error( "Invalid file format: $fmt." );
144 }; # if
145 } elsif ( $line =~ m{^Disassembly of section (.*?):\s*$} ) {
146 # Disassembly of section .plt:
147 } elsif ( $line =~ m{^$hex+ <([^>]+)>:\s*$} ) {
148 # 0000000000017e98 <__kmp_str_format@plt-0x10>:
149 $current_func = $1;
150 } elsif ( $line =~ m{^\s*\.{3}\s*$} ) {
151 } elsif ( $line =~ m{^\s*($hex+):\s+($hex$hex(?: $hex$hex)*)\s+(?:lock\s+|rex[.a-z]*\s+)?([^ ]+)(?:\s+([^#]+?))?\s*(?:#|$)} ) {
152 # 17e98: ff 35 fa 7d 26 00 pushq 0x267dfa(%rip) # 27fc98 <_GLOBAL_OFFSET_TABLE>
153 my ( $addr, $dump, $instr, $args ) = ( $1, $2, $3, $4 );
154 # Check this is not a bad instruction and xmm registers are not used.
155 if ( bad_instr( $instr, $args ) ) {
156 if ( $errors == 0 ) {
157 warning( "Invalid instructions found in `$file':" );
158 }; # if
159 if ( $current_func ne $reported_func ) {
160 warning( " $current_func" );
161 $reported_func = $current_func;
162 }; # if
163 ++ $errors;
164 if ( $show_instructions ) {
165 warning( " $line" );
166 }; # if
167 if ( $errors >= $max_instructions ) {
168 info( "$errors invalid instructions found; scanning stopped." );
169 last;
170 }; # if
171 }; # if
172 } else {
173 runtime_error( "Error parsing objdump output line $n:\n>>>> $line\n" );
174 }; # if
175 }; # foreach $line
176
177 return $errors;
178
179}; # sub check_file
180
181# --------------------------------------------------------------------------------------------------
182
183# Parse command line.
184my $max_instructions;
185my $show_instructions;
186get_options(
Jonathan Peyton4c91ad12016-01-26 19:44:31 +0000187 "os=s" => \$target_os,
188 "arch=s" => \$target_arch,
189 "mic-arch=s" => \$target_mic_arch,
Jim Cownie5e8470a2013-09-27 10:38:44 +0000190 "max-instructions=i" => \$max_instructions,
191 "show-instructions!" => \$show_instructions,
Jim Cownie5e8470a2013-09-27 10:38:44 +0000192);
Jonathan Peyton4c91ad12016-01-26 19:44:31 +0000193my $target_platform = $target_os . "_" . $target_arch;
Andrey Churbanovd315cea2015-01-16 12:54:51 +0000194if ( "$target_os" eq "lin" and "$target_mic_arch" eq "knf" ) {
195 $mic_bad_re = qr{^(?:pause|[slm]fence|scatter|gather|cmpxchg16b|clevict[12])}i;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000196} else {
Andrey Churbanovd315cea2015-01-16 12:54:51 +0000197 $mic_bad_re = qr{^(?:pause|[slm]fence|scatter|gather|cmov|cmpxchg16b|clevict[12])}i;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000198};
199if ( 0 ) {
Jonathan Peyton4c91ad12016-01-26 19:44:31 +0000200} elsif ( $target_platform eq "lin_mic" ) {
Andrey Churbanovd315cea2015-01-16 12:54:51 +0000201 *bad_instr = \*bad_mic_instr;
202 *bad_fmt = \*bad_mic_fmt;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000203} elsif ( $target_platform eq "lin_32" ) {
204 *bad_instr = \*bad_ia32_instr;
205 *bad_fmt = \*bad_ia32_fmt;
206} else {
Andrey Churbanovd315cea2015-01-16 12:54:51 +0000207 runtime_error( "Only works on lin_32 and lin_mic platforms." );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000208}; # if
209
210# Do the work.
211my $rc = 0;
212if ( not @ARGV ) {
213 info( "No arguments specified -- nothing to do." );
214} else {
215 foreach my $arg ( @ARGV ) {
216 my $errs = check_file( $arg, $show_instructions, $max_instructions );
217 if ( $errs > 0 ) {
218 $rc = 3;
219 }; # if
220 }; # foreach $arg
221}; # if
222
223exit( $rc );
224
225__END__
226
227=pod
228
229=head1 NAME
230
231B<check-instruction-set.pl> -- Make sure binary file does not contain undesired instructions.
232
233=head1 SYNOPSIS
234
235B<check-instructions.pl> I<option>... I<file>...
236
237=head1 OPTIONS
238
239=over
240
241=item B<--architecture=>I<arch>
242
243Specify target architecture.
244
245=item B<--max-instructions=>I<number>
246
247Stop scanning if I<number> invalid instructions found. 100 by default.
248
249=item B<--os=>I<os>
250
251Specify target OS.
252
253=item B<-->[B<no->]B<show-instructions>
254
255Show invalid instructions found in the file. Bu default, instructions are not shown.
256
257=item Standard Options
258
259=over
260
261=item B<--doc>
262
263=item B<--manual>
264
265Print full help message and exit.
266
267=item B<--help>
268
269Print short help message and exit.
270
271=item B<--usage>
272
273Print very short usage message and exit.
274
275=item B<--verbose>
276
277Do print informational messages.
278
279=item B<--version>
280
281Print program version and exit.
282
283=item B<--quiet>
284
285Work quiet, do not print informational messages.
286
287=back
288
289=back
290
291=head1 ARGUMENTS
292
293=over
294
295=item I<file>
296
297File (object file or library, either static or dynamic) to check.
298
299=back
300
301=head1 DESCRIPTION
302
303The script runs F<objdump> utility to get disassembler listing and checks the file does not contain
304unwanted instructions.
305
306Currently the script works only for:
307
308=over
309
Andrey Churbanovd315cea2015-01-16 12:54:51 +0000310=item C<lin_mic>
Jim Cownie5e8470a2013-09-27 10:38:44 +0000311
312Intel(R) Many Integrated Core Architecture target OS. Undesired unstructions are: all x87 instructions and some others.
313
314=item C<lin_32>
315
316Undesired instructions are instructions not valid for Pentium 3 processor (SSE2 and newer).
317
318=back
319
320=cut
321