2 * Copyright © 2014 Broadcom
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
26 #include "vc4_context.h"
31 * Returns a mapping from QFILE_TEMP indices to struct qpu_regs.
33 * The return value should be freed by the caller.
36 vc4_register_allocate(struct vc4_compile
*c
)
38 struct simple_node
*node
;
39 struct qpu_reg allocate_to_qpu_reg
[4 + 32 + 32];
40 bool reg_in_use
[ARRAY_SIZE(allocate_to_qpu_reg
)];
41 int *reg_allocated
= calloc(c
->num_temps
, sizeof(*reg_allocated
));
42 int *reg_uses_remaining
=
43 calloc(c
->num_temps
, sizeof(*reg_uses_remaining
));
44 struct qpu_reg
*temp_registers
= calloc(c
->num_temps
,
45 sizeof(*temp_registers
));
47 for (int i
= 0; i
< ARRAY_SIZE(reg_in_use
); i
++)
48 reg_in_use
[i
] = false;
49 for (int i
= 0; i
< c
->num_temps
; i
++)
50 reg_allocated
[i
] = -1;
52 /* If things aren't ever written (undefined values), just read from
55 for (int i
= 0; i
< c
->num_temps
; i
++)
56 temp_registers
[i
] = qpu_rn(0);
58 uint32_t next_reg
= 0;
59 for (int i
= 0; i
< 4; i
++)
60 allocate_to_qpu_reg
[next_reg
++] = qpu_rn(i
== 3 ? 4 : i
);
61 for (int i
= 0; i
< 32; i
++)
62 allocate_to_qpu_reg
[next_reg
++] = qpu_ra(i
);
63 for (int i
= 0; i
< 32; i
++)
64 allocate_to_qpu_reg
[next_reg
++] = qpu_rb(i
);
65 assert(next_reg
== ARRAY_SIZE(allocate_to_qpu_reg
));
67 foreach(node
, &c
->instructions
) {
68 struct qinst
*qinst
= (struct qinst
*)node
;
70 if (qinst
->dst
.file
== QFILE_TEMP
)
71 reg_uses_remaining
[qinst
->dst
.index
]++;
72 for (int i
= 0; i
< qir_get_op_nsrc(qinst
->op
); i
++) {
73 if (qinst
->src
[i
].file
== QFILE_TEMP
)
74 reg_uses_remaining
[qinst
->src
[i
].index
]++;
76 if (qinst
->op
== QOP_FRAG_Z
)
77 reg_in_use
[3 + 32 + QPU_R_FRAG_PAYLOAD_ZW
] = true;
80 foreach(node
, &c
->instructions
) {
81 struct qinst
*qinst
= (struct qinst
*)node
;
83 for (int i
= 0; i
< qir_get_op_nsrc(qinst
->op
); i
++) {
84 int index
= qinst
->src
[i
].index
;
86 if (qinst
->src
[i
].file
!= QFILE_TEMP
)
89 if (reg_allocated
[index
] == -1) {
90 fprintf(stderr
, "undefined reg use: ");
92 fprintf(stderr
, "\n");
94 reg_uses_remaining
[index
]--;
95 if (reg_uses_remaining
[index
] == 0)
96 reg_in_use
[reg_allocated
[index
]] = false;
100 if (qinst
->dst
.file
== QFILE_TEMP
) {
101 if (reg_allocated
[qinst
->dst
.index
] == -1) {
104 alloc
< ARRAY_SIZE(reg_in_use
);
106 struct qpu_reg reg
= allocate_to_qpu_reg
[alloc
];
109 case QOP_PACK_SCALED
:
110 /* The pack flags require an
113 if (reg
.mux
!= QPU_MUX_A
)
117 case QOP_TLB_COLOR_READ
:
118 /* Only R4-generating
119 * instructions get to store
120 * values in R4 for now, until
121 * we figure out how to do
124 if (reg
.mux
!= QPU_MUX_R4
)
128 if (reg
.mux
!= QPU_MUX_B
||
129 reg
.addr
!= QPU_R_FRAG_PAYLOAD_ZW
) {
134 if (reg
.mux
== QPU_MUX_R4
)
139 if (!reg_in_use
[alloc
])
142 assert(alloc
!= ARRAY_SIZE(reg_in_use
) && "need better reg alloc");
143 reg_in_use
[alloc
] = true;
144 reg_allocated
[qinst
->dst
.index
] = alloc
;
145 temp_registers
[qinst
->dst
.index
] = allocate_to_qpu_reg
[alloc
];
148 reg_uses_remaining
[qinst
->dst
.index
]--;
149 if (reg_uses_remaining
[qinst
->dst
.index
] == 0) {
150 reg_in_use
[reg_allocated
[qinst
->dst
.index
]] =
157 free(reg_uses_remaining
);
159 return temp_registers
;