-
Notifications
You must be signed in to change notification settings - Fork 1
/
checkasm.pl
executable file
·135 lines (110 loc) · 3.5 KB
/
checkasm.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/perl
use warnings;
use strict;
# Verification tool for checking vecgen-avx register assignments.
# Pass it the --dump-asm output from a single test.
# FIXME: this missed the case of a register whose reset at the end of
# a loop was missed. Augment test.
my $logname = shift || "<stdin>";
my %inmem; # vr's in memory
my %physr; # vr to pr
my %virtr; # pr to vr
my %scratch; # vr to RBP offset
my $exitcode = 0;
my $line=0;
while(<>) {
$line++;
next if /^ /;
chomp;
if(/^FILL (.*) -> (.*)/) {
my ($reg, $ymm) = ($1, $2);
#print "FILL $ymm from $reg\n"; #DEBUG
if(!$inmem{$reg} and $reg !~ /\/[A-Z]/) {
err("ERROR: filling unspilled register $reg to $ymm");
}
$physr{$reg} = $ymm;
$virtr{$ymm} = $reg;
#checkscratch("FILL", $reg);
} elsif(/^SPILL (.*) <- (.*)/) {
my ($reg, $ymm) = ($1, $2);
#print "SPILL $ymm to $reg\n"; #DEBUG
err("ERROR: spill of unfilled register $reg from $ymm")
if !defined $physr{$reg} or $physr{$reg} ne $ymm or $virtr{$ymm} ne $reg;
$inmem{$reg}++;
#checkscratch("SPILL", $reg);
} elsif(/(.*) = ([A-Z]+)(.*)/) {
my ($dst, $op, $args) = ($1, $2, $3);
#print "$op dst: $dst\n"; #DEBUG
for(my $argn=0; $args =~ /(R[0-9]+(?:\/[A-Z0-9]+)?)@(ymm[0-9]+)/g; $argn++) {
my ($reg, $ymm) = ($1, $2);
#print " $reg @ $ymm (n $argn)\n"; #DEBUG
if((($op eq "LOAD" or $op eq "STORE") and $argn != 0) or
(($op eq "CULL" or $op eq "CULL_FLD") and $argn != 1 )) {
if(!$inmem{$reg}) {
if($reg !~ /\//) {
# Only scratch (no slash) registers must be spilled
err("ERROR: LOAD/STORE/CULL arg $reg not spilled");
}
}
} else {
# Everything else must be in registers
if(!defined $virtr{$ymm} or $virtr{$ymm} ne $reg or
!defined $physr{$reg} or $physr{$reg} ne $ymm) {
err("ERROR: $op arg $reg not filled into $ymm");
}
}
}
if($dst !~ /(R[0-9]+(?:\/[A-Z0-9]+)?)(?:@(ymm[0-9]+))?/) {
err("ERROR: unparsable dst: $dst");
} else {
my ($reg, $ymm) = ($1, $2);
if($op eq "LOAD") {
# LOADS deposit their results in memory
delete $physr{$reg};
$inmem{$dst}++;
} else {
# All other destinations are registers, the in-memory
# version is now stale
delete $inmem{$dst};
$virtr{$ymm} = $reg;
$physr{$reg} = $ymm;
}
}
} elsif(/^LOOP/) {
#print "LOOP\n"; #DEBUG
# Mark register state for checking at POOL
} elsif(/^POOLTEST (R[0-9]+(?:\/[A-Z0-9]+)?)@(ymm[0-9]+)/) {
my ($reg, $ymm) = ($1, $2);
#print "POOLTEST $reg in $ymm"; #DEBUG
if(!defined $virtr{$ymm} or $virtr{$ymm} ne $reg or
!defined $physr{$reg} or $physr{$reg} ne $ymm) {
err("ERROR: POOLTEST arg $reg not filled into $ymm");
}
} elsif(/^POOL\(/) {
#print "POOL\n"; #DEBUG
# Check register state vs. the matching LOOP.
}
}
# Note that this assumes the mapping of scratch location to vr is 1:1,
# that may change with future optimization.
#
# FIXME: disabled for now, not LOAD-cognizant (LOAD acts like a spill)
sub checkscratch {
my ($mode, $r) = @_;
return if $r =~ /\//; # not scratch
my $s = $1 if <> =~ /(-0x[0-9a-f]+)\(%rbp\)/;
$line++;
if(!defined $s) {
err("cannot find scratch offset for $r");
return;
}
if(!defined $scratch{$r} && $mode eq "SPILL") {
$scratch{$r} = $s; # first spill, not notable
} elsif(!defined $scratch{$s}) {
err("Attempt to $mode $r before first spill");
} elsif($s != $scratch{$s}) {
err("Multiple scratch offsets for $r: $s vs. $scratch{$s}");
}
}
exit $exitcode;
sub err { print "$logname:$line: @_\n"; $exitcode = 1; }