1#===-- R600GenRegisterInfo.pl - Script for generating register info files --===#
2#
3#                     The LLVM Compiler Infrastructure
4#
5# This file is distributed under the University of Illinois Open Source
6# License. See LICENSE.TXT for details.
7#
8#===------------------------------------------------------------------------===#
9#
10# This perl script prints to stdout .td code to be used as R600RegisterInfo.td
11# it also generates a file called R600HwRegInfo.include, which contains helper
12# functions for determining the hw encoding of registers.
13#
14#===------------------------------------------------------------------------===#
15
16use strict;
17use warnings;
18
19use constant CONST_REG_COUNT => 1024;
20use constant TEMP_REG_COUNT => 128;
21
22my $CREG_MAX = CONST_REG_COUNT - 1;
23my $TREG_MAX = TEMP_REG_COUNT - 1;
24
25print <<STRING;
26
27class R600Reg <string name> : Register<name> {
28  let Namespace = "AMDGPU";
29}
30
31class R600Reg_128<string n, list<Register> subregs> : RegisterWithSubRegs<n, subregs> {
32  let Namespace = "AMDGPU";
33  let SubRegIndices = [sel_x, sel_y, sel_z, sel_w];
34}
35
36STRING
37
38my $i;
39
40### REG DEFS ###
41
42my @creg_list = print_reg_defs(CONST_REG_COUNT * 4, "C");
43my @treg_list = print_reg_defs(TEMP_REG_COUNT * 4, "T");
44
45my @t128reg;
46my @treg_x;
47for (my $i = 0; $i < TEMP_REG_COUNT; $i++) {
48  my $name = "T$i\_XYZW";
49  print qq{def $name : R600Reg_128 <"T$i.XYZW", [T$i\_X, T$i\_Y, T$i\_Z, T$i\_W] >;\n};
50  $t128reg[$i] = $name;
51  $treg_x[$i] = "T$i\_X";
52}
53
54my $treg_string = join(",", @treg_list);
55my $creg_list = join(",", @creg_list);
56my $t128_string = join(",", @t128reg);
57my $treg_x_string = join(",", @treg_x);
58print <<STRING;
59
60class RegSet <dag s> {
61  dag set = s;
62}
63
64def ZERO : R600Reg<"0.0">;
65def HALF : R600Reg<"0.5">;
66def ONE : R600Reg<"1.0">;
67def ONE_INT : R600Reg<"1">;
68def NEG_HALF : R600Reg<"-0.5">;
69def NEG_ONE : R600Reg<"-1.0">;
70def PV_X : R600Reg<"pv.x">;
71def ALU_LITERAL_X : R600Reg<"literal.x">;
72def PREDICATE_BIT : R600Reg<"PredicateBit">;
73def PRED_SEL_OFF: R600Reg<"Pred_sel_off">;
74def PRED_SEL_ZERO : R600Reg<"Pred_sel_zero">;
75def PRED_SEL_ONE : R600Reg<"Pred_sel_one">;
76
77def R600_CReg32 : RegisterClass <"AMDGPU", [f32, i32], 32, (add
78    $creg_list)>;
79
80def R600_TReg32 : RegisterClass <"AMDGPU", [f32, i32], 32, (add
81    $treg_string)>;
82
83def R600_TReg32_X : RegisterClass <"AMDGPU", [f32, i32], 32, (add
84    $treg_x_string)>;
85
86def R600_Reg32 : RegisterClass <"AMDGPU", [f32, i32], 32, (add
87    R600_TReg32,
88    R600_CReg32,
89    ZERO, HALF, ONE, ONE_INT, PV_X, ALU_LITERAL_X, NEG_ONE, NEG_HALF)>;
90
91def R600_Predicate : RegisterClass <"AMDGPU", [i32], 32, (add
92    PRED_SEL_OFF, PRED_SEL_ZERO, PRED_SEL_ONE)>;
93
94def R600_Predicate_Bit: RegisterClass <"AMDGPU", [i32], 32, (add
95    PREDICATE_BIT)>;
96
97def R600_Reg128 : RegisterClass<"AMDGPU", [v4f32, v4i32], 128, (add
98    $t128_string)>
99{
100  let SubRegClasses = [(R600_TReg32 sel_x, sel_y, sel_z, sel_w)];
101  let CopyCost = -1;
102}
103
104STRING
105
106my %index_map;
107my %chan_map;
108
109for ($i = 0; $i <= $#creg_list; $i++) {
110  push(@{$index_map{get_hw_index($i)}}, $creg_list[$i]);
111  push(@{$chan_map{get_chan_str($i)}}, $creg_list[$i]);
112}
113
114for ($i = 0; $i <= $#treg_list; $i++) {
115  push(@{$index_map{get_hw_index($i)}}, $treg_list[$i]);
116  push(@{$chan_map{get_chan_str($i)}}, $treg_list[$i]);
117}
118
119for ($i = 0; $i <= $#t128reg; $i++) {
120  push(@{$index_map{$i}}, $t128reg[$i]);
121  push(@{$chan_map{'X'}}, $t128reg[$i]);
122}
123
124open(OUTFILE, ">", "R600HwRegInfo.include");
125
126print OUTFILE <<STRING;
127
128unsigned R600RegisterInfo::getHWRegIndexGen(unsigned reg) const
129{
130  switch(reg) {
131  default: assert(!"Unknown register"); return 0;
132STRING
133foreach my $key (keys(%index_map)) {
134  foreach my $reg (@{$index_map{$key}}) {
135    print OUTFILE "  case AMDGPU::$reg:\n";
136  }
137  print OUTFILE "    return $key;\n\n";
138}
139
140print OUTFILE "  }\n}\n\n";
141
142print OUTFILE <<STRING;
143
144unsigned R600RegisterInfo::getHWRegChanGen(unsigned reg) const
145{
146  switch(reg) {
147  default: assert(!"Unknown register"); return 0;
148STRING
149
150foreach my $key (keys(%chan_map)) {
151  foreach my $reg (@{$chan_map{$key}}) {
152    print OUTFILE " case AMDGPU::$reg:\n";
153  }
154  my $val;
155  if ($key eq 'X') {
156    $val = 0;
157  } elsif ($key eq 'Y') {
158    $val = 1;
159  } elsif ($key eq 'Z') {
160    $val = 2;
161  } elsif ($key eq 'W') {
162    $val = 3;
163  } else {
164    die("Unknown chan value; $key");
165  }
166  print OUTFILE "    return $val;\n\n";
167}
168
169print OUTFILE "  }\n}\n\n";
170
171sub print_reg_defs {
172  my ($count, $prefix) = @_;
173
174  my @reg_list;
175
176  for ($i = 0; $i < $count; $i++) {
177    my $hw_index = get_hw_index($i);
178    my $chan= get_chan_str($i);
179    my $name = "$prefix$hw_index\_$chan";
180    print qq{def $name : R600Reg <"$prefix$hw_index.$chan">;\n};
181    $reg_list[$i] = $name;
182  }
183  return @reg_list;
184}
185
186#Helper functions
187sub get_hw_index {
188  my ($index) = @_;
189  return int($index / 4);
190}
191
192sub get_chan_str {
193  my ($index) = @_;
194  my $chan = $index % 4;
195  if ($chan == 0 )  {
196    return 'X';
197  } elsif ($chan == 1) {
198    return 'Y';
199  } elsif ($chan == 2) {
200    return 'Z';
201  } elsif ($chan == 3) {
202    return 'W';
203  } else {
204    die("Unknown chan value: $chan");
205  }
206}
207