AMDGPU: Add core backend files for R600/SI codegen v6
[oota-llvm.git] / lib / Target / AMDGPU / R600GenRegisterInfo.pl
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
16 use strict;
17 use warnings;
18
19 use constant CONST_REG_COUNT => 100;
20 use constant TEMP_REG_COUNT => 128;
21
22 my $CREG_MAX = CONST_REG_COUNT - 1;
23 my $TREG_MAX = TEMP_REG_COUNT - 1;
24
25 print <<STRING;
26
27 class R600Reg <string name, bits<16> encoding> : Register<name> {
28   let Namespace = "AMDGPU";
29   let HWEncoding = encoding;
30 }
31
32 class R600Reg_128<string n, list<Register> subregs, bits<16> encoding> :
33     RegisterWithSubRegs<n, subregs> {
34   let Namespace = "AMDGPU";
35   let SubRegIndices = [sel_x, sel_y, sel_z, sel_w];
36   let HWEncoding = encoding;
37 }
38
39 STRING
40
41 my $i;
42
43 ### REG DEFS ###
44
45 my @creg_list = print_reg_defs(CONST_REG_COUNT * 4, "C");
46 my @treg_list = print_reg_defs(TEMP_REG_COUNT * 4, "T");
47
48 my @t128reg;
49 my @treg_x;
50 for (my $i = 0; $i < TEMP_REG_COUNT; $i++) {
51   my $name = "T$i\_XYZW";
52   print qq{def $name : R600Reg_128 <"T$i.XYZW", [T$i\_X, T$i\_Y, T$i\_Z, T$i\_W], $i >;\n};
53   $t128reg[$i] = $name;
54   $treg_x[$i] = "T$i\_X";
55   if ($i % 10 == 0) {
56     $t128reg[$i] .= "\n";
57     $treg_x[$i] .= "\n";
58   }
59 }
60
61 my $treg_string = join(",", @treg_list);
62 my $creg_list = join(",", @creg_list);
63 my $t128_string = join(",", @t128reg);
64 my $treg_x_string = join(",", @treg_x);
65 print <<STRING;
66
67 class RegSet <dag s> {
68   dag set = s;
69 }
70
71 def ZERO : R600Reg<"0.0", 248>;
72 def ONE : R600Reg<"1.0", 249>;
73 def NEG_ONE : R600Reg<"-1.0", 249>;
74 def ONE_INT : R600Reg<"1", 250>;
75 def HALF : R600Reg<"0.5", 252>;
76 def NEG_HALF : R600Reg<"-0.5", 252>;
77 def PV_X : R600Reg<"pv.x", 254>;
78 def ALU_LITERAL_X : R600Reg<"literal.x", 253>;
79
80 def R600_CReg32 : RegisterClass <"AMDGPU", [f32, i32], 32, (add
81     $creg_list)>;
82
83 def R600_TReg32 : RegisterClass <"AMDGPU", [f32, i32], 32, (add
84     $treg_string)>;
85
86 def R600_TReg32_X : RegisterClass <"AMDGPU", [f32, i32], 32, (add
87     $treg_x_string)>;
88     
89 def R600_Reg32 : RegisterClass <"AMDGPU", [f32, i32], 32, (add
90     R600_TReg32,
91     R600_CReg32,
92     ZERO, HALF, ONE, ONE_INT, PV_X, ALU_LITERAL_X, NEG_ONE, NEG_HALF)>;
93
94 def R600_Reg128 : RegisterClass<"AMDGPU", [v4f32, v4i32], 128, (add
95     $t128_string)>
96 {
97   let CopyCost = -1;
98 }
99
100 STRING
101
102 my %index_map;
103 my %chan_map;
104
105 for ($i = 0; $i <= $#creg_list; $i++) {
106   push(@{$index_map{get_hw_index($i)}}, $creg_list[$i]);
107   push(@{$chan_map{get_chan_str($i)}}, $creg_list[$i]);
108 }
109
110 for ($i = 0; $i <= $#treg_list; $i++) {
111   push(@{$index_map{get_hw_index($i)}}, $treg_list[$i]);
112   push(@{$chan_map{get_chan_str($i)}}, $treg_list[$i]);
113 }
114
115 for ($i = 0; $i <= $#t128reg; $i++) {
116   push(@{$index_map{$i}}, $t128reg[$i]);
117   push(@{$chan_map{'X'}}, $t128reg[$i]);
118 }
119
120 open(OUTFILE, ">", "R600HwRegInfo.include");
121
122 print OUTFILE <<STRING;
123
124 unsigned R600RegisterInfo::getHWRegChanGen(unsigned reg) const
125 {
126   switch(reg) {
127   default: assert(!"Unknown register"); return 0;
128 STRING
129
130 foreach my $key (keys(%chan_map)) {
131   foreach my $reg (@{$chan_map{$key}}) {
132     chomp($reg);
133     print OUTFILE " case AMDGPU::$reg:\n";
134   }
135   my $val;
136   if ($key eq 'X') {
137     $val = 0;
138   } elsif ($key eq 'Y') {
139     $val = 1;
140   } elsif ($key eq 'Z') {
141     $val = 2;
142   } elsif ($key eq 'W') {
143     $val = 3;
144   } else {
145     die("Unknown chan value; $key");
146   }
147   print OUTFILE "    return $val;\n\n";
148 }
149
150 print OUTFILE "  }\n}\n\n";
151
152 sub print_reg_defs {
153   my ($count, $prefix) = @_;
154
155   my @reg_list;
156
157   for ($i = 0; $i < $count; $i++) {
158     my $hw_index = get_hw_index($i);
159     my $chan= get_chan_str($i);
160     my $name = "$prefix$hw_index\_$chan";
161     print qq{def $name : R600Reg <"$prefix$hw_index.$chan", $hw_index>;\n};
162     $reg_list[$i] = $name;
163     if ($i % 10 == 0) {
164         $reg_list[$i] .= "\n";
165     }
166   }
167   return @reg_list;
168 }
169
170 #Helper functions
171 sub get_hw_index {
172   my ($index) = @_;
173   return int($index / 4);
174 }
175
176 sub get_chan_str {
177   my ($index) = @_;
178   my $chan = $index % 4;
179   if ($chan == 0 )  {
180     return 'X';
181   } elsif ($chan == 1) {
182     return 'Y';
183   } elsif ($chan == 2) {
184     return 'Z';
185   } elsif ($chan == 3) {
186     return 'W';
187   } else {
188     die("Unknown chan value: $chan");
189   }
190 }