Skip to content

Commit

Permalink
Use set operations instead of plain lists to enumerate register classes.
Browse files Browse the repository at this point in the history
This simplifies many of the target description files since it is common
for register classes to be related or contain sequences of numbered
registers.

I have verified that this doesn't change the files generated by TableGen
for ARM and X86. It alters the allocation order of MBlaze GPR and Mips
FGR32 registers, but I believe the change is benign.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@133105 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
stoklund committed Jun 15, 2011
1 parent f14bacc commit f28987b
Show file tree
Hide file tree
Showing 15 changed files with 255 additions and 547 deletions.
80 changes: 33 additions & 47 deletions docs/WritingAnLLVMBackend.html
Expand Up @@ -706,8 +706,7 @@ <h3>
<div class="doc_code">
<pre>
class RegisterClass&lt;string namespace,
list&lt;ValueType&gt; regTypes, int alignment,
list&lt;Register&gt; regList&gt; {
list&lt;ValueType&gt; regTypes, int alignment, dag regList&gt; {
string Namespace = namespace;
list&lt;ValueType&gt; RegTypes = regTypes;
int Size = 0; // spill size, in bits; zero lets tblgen pick the size
Expand All @@ -717,7 +716,7 @@ <h3>
// default value 1 means a single instruction
// A negative value means copying is extremely expensive or impossible
int CopyCost = 1;
list&lt;Register&gt; MemberList = regList;
dag MemberList = regList;

// for register classes that are subregisters of this class
list&lt;RegisterClass&gt; SubRegClassList = [];
Expand Down Expand Up @@ -749,9 +748,11 @@ <h3>
memory.</li>

<li>The final argument, <tt>regList</tt>, specifies which registers are in this
class. If an <tt>allocation_order_*</tt> method is not specified,
then <tt>regList</tt> also defines the order of allocation used by the
register allocator.</li>
class. If an alternative allocation order method is not specified, then
<tt>regList</tt> also defines the order of allocation used by the register
allocator. Besides simply listing registers with <tt>(add R0, R1, ...)</tt>,
more advanced set operators are available. See
<tt>include/llvm/Target/Target.td</tt> for more information.</li>
</ul>

<p>
Expand All @@ -761,44 +762,31 @@ <h3>
'<tt>SP</tt>'. <tt>FPRegs</tt> defines a group of 32 single-precision
floating-point registers (<tt>F0</tt> to <tt>F31</tt>); <tt>DFPRegs</tt> defines
a group of 16 double-precision registers
(<tt>D0-D15</tt>). For <tt>IntRegs</tt>, the <tt>MethodProtos</tt>
and <tt>MethodBodies</tt> methods are used by TableGen to insert the specified
code into generated output.
(<tt>D0-D15</tt>).
</p>

<div class="doc_code">
<pre>
def FPRegs : RegisterClass&lt;"SP", [f32], 32,
[F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15,
F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31]&gt;;
// F0, F1, F2, ..., F31
def FPRegs : RegisterClass&lt;"SP", [f32], 32, (sequence "F%u", 0, 31)&gt;;

def DFPRegs : RegisterClass&lt;"SP", [f64], 64,
[D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15]&gt;;
(add D0, D1, D2, D3, D4, D5, D6, D7, D8,
D9, D10, D11, D12, D13, D14, D15)&gt;;
&nbsp;
def IntRegs : RegisterClass&lt;"SP", [i32], 32,
[L0, L1, L2, L3, L4, L5, L6, L7,
I0, I1, I2, I3, I4, I5,
O0, O1, O2, O3, O4, O5, O7,
G1,
// Non-allocatable regs:
G2, G3, G4,
O6, // stack ptr
I6, // frame ptr
I7, // return address
G0, // constant zero
G5, G6, G7 // reserved for kernel
]&gt; {
let MethodProtos = [{
iterator allocation_order_end(const MachineFunction &amp;MF) const;
}];
let MethodBodies = [{
IntRegsClass::iterator
IntRegsClass::allocation_order_end(const MachineFunction &amp;MF) const {
return end() - 10 // Don't allocate special registers
-1;
}
}];
}
(add L0, L1, L2, L3, L4, L5, L6, L7,
I0, I1, I2, I3, I4, I5,
O0, O1, O2, O3, O4, O5, O7,
G1,
// Non-allocatable regs:
G2, G3, G4,
O6, // stack ptr
I6, // frame ptr
I7, // return address
G0, // constant zero
G5, G6, G7 // reserved for kernel
)&gt;;
</pre>
</div>

Expand All @@ -820,10 +808,7 @@ <h3>
register implementation. The code below shows only the generated integer
registers and associated register classes. The order of registers
in <tt>IntRegs</tt> reflects the order in the definition of <tt>IntRegs</tt> in
the target description file. Take special note of the use
of <tt>MethodBodies</tt> in <tt>SparcRegisterInfo.td</tt> to create code in
<tt>SparcGenRegisterInfo.inc</tt>. <tt>MethodProtos</tt> generates similar code
in <tt>SparcGenRegisterInfo.h.inc</tt>.
the target description file.
</p>

<div class="doc_code">
Expand Down Expand Up @@ -866,20 +851,21 @@ <h3>
static const TargetRegisterClass* const IntRegsSuperclasses [] = {
NULL
};
...
IntRegsClass::iterator
IntRegsClass::allocation_order_end(const MachineFunction &amp;MF) const {
return end()-10 // Don't allocate special registers
-1;
}


IntRegsClass::IntRegsClass() : TargetRegisterClass(IntRegsRegClassID,
IntRegsVTs, IntRegsSubclasses, IntRegsSuperclasses, IntRegsSubRegClasses,
IntRegsSuperRegClasses, 4, 4, 1, IntRegs, IntRegs + 32) {}
}
</pre>
</div>

<p>
The register allocators will avoid using reserved registers, and callee saved
registers are not used until all the volatile registers have been used. That
is usually good enough, but in some cases it may be necessary to provide custom
allocation orders.
</p>

</div>

<!-- ======================================================================= -->
Expand Down
37 changes: 35 additions & 2 deletions include/llvm/Target/Target.td
Expand Up @@ -92,7 +92,7 @@ class RegisterWithSubRegs<string n, list<Register> subregs> : Register<n> {
// registers by register allocators.
//
class RegisterClass<string namespace, list<ValueType> regTypes, int alignment,
list<Register> regList> {
dag regList> {
string Namespace = namespace;

// RegType - Specify the list ValueType of the registers in this register
Expand Down Expand Up @@ -122,7 +122,7 @@ class RegisterClass<string namespace, list<ValueType> regTypes, int alignment,
// allocation_order_* method are not specified, this also defines the order of
// allocation used by the register allocator.
//
list<Register> MemberList = regList;
dag MemberList = regList;

// SubRegClasses - Specify the register class of subregisters as a list of
// dags: (RegClass SubRegIndex, SubRegindex, ...)
Expand All @@ -140,6 +140,39 @@ class RegisterClass<string namespace, list<ValueType> regTypes, int alignment,
code MethodBodies = [{}];
}

// The memberList in a RegisterClass is a dag of set operations. TableGen
// evaluates these set operations and expand them into register lists. These
// are the most common operation, see test/TableGen/SetTheory.td for more
// examples of what is possible:
//
// (add R0, R1, R2) - Set Union. Each argument can be an individual register, a
// register class, or a sub-expression. This is also the way to simply list
// registers.
//
// (sub GPR, SP) - Set difference. Subtract the last arguments from the first.
//
// (and GPR, CSR) - Set intersection. All registers from the first set that are
// also in the second set.
//
// (sequence "R%u", 0, 15) -> [R0, R1, ..., R15]. Generate a sequence of
// numbered registers.
//
// (shl GPR, 4) - Remove the first N elements.
//
// (trunc GPR, 4) - Truncate after the first N elements.
//
// (rotl GPR, 1) - Rotate N places to the left.
//
// (rotr GPR, 1) - Rotate N places to the right.
//
// (decimate GPR, 2) - Pick every N'th element, starting with the first.
//
// All of these operators work on ordered sets, not lists. That means
// duplicates are removed from sub-expressions.

// Set operators. The rest is defined in TargetSelectionDAG.td.
def sequence;
def decimate;

//===----------------------------------------------------------------------===//
// DwarfRegNum - This class provides a mapping of the llvm register enumeration
Expand Down
53 changes: 17 additions & 36 deletions lib/Target/ARM/ARMRegisterInfo.td
Expand Up @@ -200,9 +200,8 @@ def FPEXC : ARMReg<8, "fpexc">;
// r11 == Frame Pointer (arm-style backtraces)
// r10 == Stack Limit
//
def GPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6,
R7, R8, R9, R10, R11, R12,
SP, LR, PC]> {
def GPR : RegisterClass<"ARM", [i32], 32, (add (sequence "R%u", 0, 12),
SP, LR, PC)> {
let MethodProtos = [{
iterator allocation_order_begin(const MachineFunction &MF) const;
iterator allocation_order_end(const MachineFunction &MF) const;
Expand Down Expand Up @@ -246,8 +245,7 @@ def GPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6,
// register range for operands, but have undefined behaviours when PC
// or SP (R13 or R15) are used. The ARM ISA refers to these operands
// via the BadReg() pseudo-code description.
def rGPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6,
R7, R8, R9, R10, R11, R12, LR]> {
def rGPR : RegisterClass<"ARM", [i32], 32, (sub GPR, SP, PC)> {
let MethodProtos = [{
iterator allocation_order_begin(const MachineFunction &MF) const;
iterator allocation_order_end(const MachineFunction &MF) const;
Expand Down Expand Up @@ -291,13 +289,13 @@ def rGPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6,

// Thumb registers are R0-R7 normally. Some instructions can still use
// the general GPR register class above (MOV, e.g.)
def tGPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6, R7]> {}
def tGPR : RegisterClass<"ARM", [i32], 32, (trunc GPR, 8)>;

// For tail calls, we can't use callee-saved registers, as they are restored
// to the saved value before the tail call, which would clobber a call address.
// Note, getMinimalPhysRegClass(R0) returns tGPR because of the names of
// this class and the preceding one(!) This is what we want.
def tcGPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R9, R12]> {
def tcGPR : RegisterClass<"ARM", [i32], 32, (add R0, R1, R2, R3, R9, R12)> {
let MethodProtos = [{
iterator allocation_order_begin(const MachineFunction &MF) const;
iterator allocation_order_end(const MachineFunction &MF) const;
Expand Down Expand Up @@ -345,25 +343,18 @@ def tcGPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R9, R12]> {


// Scalar single precision floating point register class..
def SPR : RegisterClass<"ARM", [f32], 32, [S0, S1, S2, S3, S4, S5, S6, S7, S8,
S9, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20, S21, S22,
S23, S24, S25, S26, S27, S28, S29, S30, S31]>;
def SPR : RegisterClass<"ARM", [f32], 32, (sequence "S%u", 0, 31)>;

// Subset of SPR which can be used as a source of NEON scalars for 16-bit
// operations
def SPR_8 : RegisterClass<"ARM", [f32], 32,
[S0, S1, S2, S3, S4, S5, S6, S7,
S8, S9, S10, S11, S12, S13, S14, S15]>;
def SPR_8 : RegisterClass<"ARM", [f32], 32, (trunc SPR, 16)>;

// Scalar double precision floating point / generic 64-bit vector register
// class.
// ARM requires only word alignment for double. It's more performant if it
// is double-word alignment though.
def DPR : RegisterClass<"ARM", [f64, v8i8, v4i16, v2i32, v1i64, v2f32], 64,
[D0, D1, D2, D3, D4, D5, D6, D7,
D8, D9, D10, D11, D12, D13, D14, D15,
D16, D17, D18, D19, D20, D21, D22, D23,
D24, D25, D26, D27, D28, D29, D30, D31]> {
(sequence "D%u", 0, 31)> {
let MethodProtos = [{
iterator allocation_order_begin(const MachineFunction &MF) const;
iterator allocation_order_end(const MachineFunction &MF) const;
Expand Down Expand Up @@ -411,22 +402,20 @@ def DPR : RegisterClass<"ARM", [f64, v8i8, v4i16, v2i32, v1i64, v2f32], 64,
// Subset of DPR that are accessible with VFP2 (and so that also have
// 32-bit SPR subregs).
def DPR_VFP2 : RegisterClass<"ARM", [f64, v8i8, v4i16, v2i32, v1i64, v2f32], 64,
[D0, D1, D2, D3, D4, D5, D6, D7,
D8, D9, D10, D11, D12, D13, D14, D15]> {
(trunc DPR, 16)> {
let SubRegClasses = [(SPR ssub_0, ssub_1)];
}

// Subset of DPR which can be used as a source of NEON scalars for 16-bit
// operations
def DPR_8 : RegisterClass<"ARM", [f64, v8i8, v4i16, v2i32, v1i64, v2f32], 64,
[D0, D1, D2, D3, D4, D5, D6, D7]> {
(trunc DPR, 8)> {
let SubRegClasses = [(SPR_8 ssub_0, ssub_1)];
}

// Generic 128-bit vector register class.
def QPR : RegisterClass<"ARM", [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], 128,
[Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7,
Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15]> {
(sequence "Q%u", 0, 15)> {
let SubRegClasses = [(DPR dsub_0, dsub_1)];
let MethodProtos = [{
iterator allocation_order_begin(const MachineFunction &MF) const;
Expand Down Expand Up @@ -455,25 +444,21 @@ def QPR : RegisterClass<"ARM", [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], 128,

// Subset of QPR that have 32-bit SPR subregs.
def QPR_VFP2 : RegisterClass<"ARM", [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
128,
[Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7]> {
128, (trunc QPR, 8)> {
let SubRegClasses = [(SPR ssub_0, ssub_1, ssub_2, ssub_3),
(DPR_VFP2 dsub_0, dsub_1)];
}

// Subset of QPR that have DPR_8 and SPR_8 subregs.
def QPR_8 : RegisterClass<"ARM", [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
128,
[Q0, Q1, Q2, Q3]> {
128, (trunc QPR, 4)> {
let SubRegClasses = [(SPR_8 ssub_0, ssub_1, ssub_2, ssub_3),
(DPR_8 dsub_0, dsub_1)];
}

// Pseudo 256-bit vector register class to model pairs of Q registers
// (4 consecutive D registers).
def QQPR : RegisterClass<"ARM", [v4i64],
256,
[QQ0, QQ1, QQ2, QQ3, QQ4, QQ5, QQ6, QQ7]> {
def QQPR : RegisterClass<"ARM", [v4i64], 256, (sequence "QQ%u", 0, 7)> {
let SubRegClasses = [(DPR dsub_0, dsub_1, dsub_2, dsub_3),
(QPR qsub_0, qsub_1)];
let MethodProtos = [{
Expand All @@ -500,9 +485,7 @@ def QQPR : RegisterClass<"ARM", [v4i64],
}

// Subset of QQPR that have 32-bit SPR subregs.
def QQPR_VFP2 : RegisterClass<"ARM", [v4i64],
256,
[QQ0, QQ1, QQ2, QQ3]> {
def QQPR_VFP2 : RegisterClass<"ARM", [v4i64], 256, (trunc QQPR, 4)> {
let SubRegClasses = [(SPR ssub_0, ssub_1, ssub_2, ssub_3),
(DPR_VFP2 dsub_0, dsub_1, dsub_2, dsub_3),
(QPR_VFP2 qsub_0, qsub_1)];
Expand All @@ -511,9 +494,7 @@ def QQPR_VFP2 : RegisterClass<"ARM", [v4i64],

// Pseudo 512-bit vector register class to model 4 consecutive Q registers
// (8 consecutive D registers).
def QQQQPR : RegisterClass<"ARM", [v8i64],
256,
[QQQQ0, QQQQ1, QQQQ2, QQQQ3]> {
def QQQQPR : RegisterClass<"ARM", [v8i64], 256, (sequence "QQQQ%u", 0, 3)> {
let SubRegClasses = [(DPR dsub_0, dsub_1, dsub_2, dsub_3,
dsub_4, dsub_5, dsub_6, dsub_7),
(QPR qsub_0, qsub_1, qsub_2, qsub_3)];
Expand All @@ -540,6 +521,6 @@ def QQQQPR : RegisterClass<"ARM", [v8i64],
}

// Condition code registers.
def CCR : RegisterClass<"ARM", [i32], 32, [CPSR]> {
def CCR : RegisterClass<"ARM", [i32], 32, (add CPSR)> {
let isAllocatable = 0;
}
19 changes: 7 additions & 12 deletions lib/Target/Alpha/AlphaRegisterInfo.td
Expand Up @@ -110,29 +110,24 @@ def F31 : FPR<31, "$f31">, DwarfRegNum<[64]>;
// $28 is undefined after any and all calls

/// Register classes
def GPRC : RegisterClass<"Alpha", [i64], 64,
def GPRC : RegisterClass<"Alpha", [i64], 64, (add
// Volatile
[R0, R1, R2, R3, R4, R5, R6, R7, R8, R16, R17, R18, R19, R20, R21, R22,
R23, R24, R25, R28,
R0, R1, R2, R3, R4, R5, R6, R7, R8, R16, R17, R18, R19, R20, R21, R22,
R23, R24, R25, R28,
//Special meaning, but volatile
R27, //procedure address
R26, //return address
R29, //global offset table address
// Non-volatile
R9, R10, R11, R12, R13, R14,
// Don't allocate 15, 30, 31
R15, R30, R31 ]>; //zero
R15, R30, R31)>; //zero

def F4RC : RegisterClass<"Alpha", [f32], 64, [F0, F1,
def F4RC : RegisterClass<"Alpha", [f32], 64, (add F0, F1,
F10, F11, F12, F13, F14, F15, F16, F17, F18, F19,
F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30,
// Saved:
F2, F3, F4, F5, F6, F7, F8, F9,
F31 ]>; //zero
F31)>; //zero

def F8RC : RegisterClass<"Alpha", [f64], 64, [F0, F1,
F10, F11, F12, F13, F14, F15, F16, F17, F18, F19,
F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30,
// Saved:
F2, F3, F4, F5, F6, F7, F8, F9,
F31 ]>; //zero
def F8RC : RegisterClass<"Alpha", [f64], 64, (add F4RC)>;

0 comments on commit f28987b

Please sign in to comment.