summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/radeon/R600GenRegisterInfo.pl
blob: 9e7cf61428bb8a90c9b8617c2f36417c95fa609a (plain)
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#===-- R600GenRegisterInfo.pl - Script for generating register info files --===#
#
#                     The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
#
# This perl script prints to stdout .td code to be used as R600RegisterInfo.td
# it also generates a file called R600HwRegInfo.include, which contains helper
# functions for determining the hw encoding of registers.
#
#===------------------------------------------------------------------------===#

use strict;
use warnings;

use constant CONST_REG_COUNT => 1024;
use constant TEMP_REG_COUNT => 128;

my $CREG_MAX = CONST_REG_COUNT - 1;
my $TREG_MAX = TEMP_REG_COUNT - 1;

print <<STRING;

class R600Reg <string name> : Register<name> {
  let Namespace = "AMDIL";
}

class R600Reg_128<string n, list<Register> subregs> : RegisterWithSubRegs<n, subregs> {
  let Namespace = "AMDIL";
  let SubRegIndices = [sel_x, sel_y, sel_z, sel_w];
}

STRING

my $i;

### REG DEFS ###

my @creg_list = print_reg_defs(CONST_REG_COUNT * 4, "C");
my @treg_list = print_reg_defs(TEMP_REG_COUNT * 4, "T");

my @t128reg;
my @treg_x;
for (my $i = 0; $i < TEMP_REG_COUNT; $i++) {
  my $name = "T$i\_XYZW";
  print qq{def $name : R600Reg_128 <"T$i.XYZW", [T$i\_X, T$i\_Y, T$i\_Z, T$i\_W] >;\n};
  $t128reg[$i] = $name;
  $treg_x[$i] = "T$i\_X";
}

my $treg_string = join(",", @treg_list);
my $creg_list = join(",", @creg_list);
my $t128_string = join(",", @t128reg);
my $treg_x_string = join(",", @treg_x);
print <<STRING;

class RegSet <dag s> {
  dag set = s;
}

def ZERO : R600Reg<"0.0">;
def HALF : R600Reg<"0.5">;
def ONE : R600Reg<"1.0">;
def ONE_INT : R600Reg<"1">;
def NEG_HALF : R600Reg<"-0.5">;
def NEG_ONE : R600Reg<"-1.0">;
def PV_X : R600Reg<"pv.x">;
def ALU_LITERAL_X : R600Reg<"literal.x">;

def R600_CReg32 : RegisterClass <"AMDIL", [f32, i32], 32, (add
    $creg_list)>;

def R600_TReg32 : RegisterClass <"AMDIL", [f32, i32], 32, (add
    $treg_string)>;

def R600_TReg32_X : RegisterClass <"AMDIL", [f32, i32], 32, (add
    $treg_x_string)>;
    
def R600_Reg32 : RegisterClass <"AMDIL", [f32, i32], 32, (add
    R600_TReg32,
    R600_CReg32,
    ZERO, HALF, ONE, ONE_INT, PV_X, ALU_LITERAL_X, NEG_ONE, NEG_HALF)>;

def R600_Reg128 : RegisterClass<"AMDIL", [v4f32, v4i32], 128, (add
    $t128_string)>
{
  let SubRegClasses = [(R600_TReg32 sel_x, sel_y, sel_z, sel_w)];
  let CopyCost = -1;
}

STRING

my %index_map;
my %chan_map;

for ($i = 0; $i <= $#creg_list; $i++) {
  push(@{$index_map{get_hw_index($i)}}, $creg_list[$i]);
  push(@{$chan_map{get_chan_str($i)}}, $creg_list[$i]);
}

for ($i = 0; $i <= $#treg_list; $i++) {
  push(@{$index_map{get_hw_index($i)}}, $treg_list[$i]);
  push(@{$chan_map{get_chan_str($i)}}, $treg_list[$i]);
}

for ($i = 0; $i <= $#t128reg; $i++) {
  push(@{$index_map{$i}}, $t128reg[$i]);
  push(@{$chan_map{'X'}}, $t128reg[$i]);
}

open(OUTFILE, ">", "R600HwRegInfo.include");

print OUTFILE <<STRING;

unsigned R600RegisterInfo::getHWRegIndexGen(unsigned reg) const
{
  switch(reg) {
  default: assert(!"Unknown register"); return 0;
STRING
foreach my $key (keys(%index_map)) {
  foreach my $reg (@{$index_map{$key}}) {
    print OUTFILE "  case AMDIL::$reg:\n";
  }
  print OUTFILE "    return $key;\n\n";
}

print OUTFILE "  }\n}\n\n";

print OUTFILE <<STRING;

unsigned R600RegisterInfo::getHWRegChanGen(unsigned reg) const
{
  switch(reg) {
  default: assert(!"Unknown register"); return 0;
STRING

foreach my $key (keys(%chan_map)) {
  foreach my $reg (@{$chan_map{$key}}) {
    print OUTFILE " case AMDIL::$reg:\n";
  }
  my $val;
  if ($key eq 'X') {
    $val = 0;
  } elsif ($key eq 'Y') {
    $val = 1;
  } elsif ($key eq 'Z') {
    $val = 2;
  } elsif ($key eq 'W') {
    $val = 3;
  } else {
    die("Unknown chan value; $key");
  }
  print OUTFILE "    return $val;\n\n";
}

print OUTFILE "  }\n}\n\n";

sub print_reg_defs {
  my ($count, $prefix) = @_;

  my @reg_list;

  for ($i = 0; $i < $count; $i++) {
    my $hw_index = get_hw_index($i);
    my $chan= get_chan_str($i);
    my $name = "$prefix$hw_index\_$chan";
    print qq{def $name : R600Reg <"$prefix$hw_index.$chan">;\n};
    $reg_list[$i] = $name;
  }
  return @reg_list;
}

#Helper functions
sub get_hw_index {
  my ($index) = @_;
  return int($index / 4);
}

sub get_chan_str {
  my ($index) = @_;
  my $chan = $index % 4;
  if ($chan == 0 )  {
    return 'X';
  } elsif ($chan == 1) {
    return 'Y';
  } elsif ($chan == 2) {
    return 'Z';
  } elsif ($chan == 3) {
    return 'W';
  } else {
    die("Unknown chan value: $chan");
  }
}