summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/freedreno/ir3/ir3.h
diff options
context:
space:
mode:
authorRob Clark <[email protected]>2015-06-09 17:17:06 -0400
committerRob Clark <[email protected]>2015-06-21 07:54:38 -0400
commit457f7c2a2a93b45396ac66e0d4b3896d2db8fdf3 (patch)
tree1286493bc6b7fd01738125b6fc91db78c3dc805f /src/gallium/drivers/freedreno/ir3/ir3.h
parent660d5c1646f5d63f9626b24beabc9cfc318849d4 (diff)
freedreno/ir3: block reshuffling and loops!
This shuffles things around to allow the shader to have multiple basic blocks. We drop the entire CFG structure from nir and just preserve the blocks. At scheduling we know whether to schedule conditional branches or unconditional jumps at the end of the block based on the # of block successors. (Dropping jumps to the following instruction, etc.) One slight complication is that variables (load_var/store_var, ie. arrays) are not in SSA form, so we have to figure out where to put the phi's ourself. For this, we use the predecessor set information from nir_block. (We could perhaps use NIR's dominance frontier information to help with this?) Signed-off-by: Rob Clark <[email protected]>
Diffstat (limited to 'src/gallium/drivers/freedreno/ir3/ir3.h')
-rw-r--r--src/gallium/drivers/freedreno/ir3/ir3.h92
1 files changed, 68 insertions, 24 deletions
diff --git a/src/gallium/drivers/freedreno/ir3/ir3.h b/src/gallium/drivers/freedreno/ir3/ir3.h
index 95b866988b8..9c35a763d58 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3.h
+++ b/src/gallium/drivers/freedreno/ir3/ir3.h
@@ -83,7 +83,8 @@ struct ir3_register {
* before register assignment is done:
*/
IR3_REG_SSA = 0x2000, /* 'instr' is ptr to assigning instr */
- IR3_REG_IA = 0x4000, /* meta-input dst is "assigned" */
+ IR3_REG_PHI_SRC= 0x4000, /* phi src, regs[0]->instr points to phi */
+
} flags;
union {
/* normal registers:
@@ -187,6 +188,7 @@ struct ir3_instruction {
char inv;
char comp;
int immed;
+ struct ir3_block *target;
} cat0;
struct {
type_t src_type, dst_type;
@@ -220,14 +222,14 @@ struct ir3_instruction {
int aid;
} fi;
struct {
- struct ir3_block *if_block, *else_block;
- } flow;
+ /* used to temporarily hold reference to nir_phi_instr
+ * until we resolve the phi srcs
+ */
+ void *nphi;
+ } phi;
struct {
struct ir3_block *block;
} inout;
-
- /* XXX keep this as big as all other union members! */
- uint32_t info[3];
};
/* transient values used during various algorithms: */
@@ -363,16 +365,40 @@ struct ir3 {
unsigned predicates_count, predicates_sz;
struct ir3_instruction **predicates;
- struct ir3_block *block;
+ /* List of blocks: */
+ struct list_head block_list;
+
unsigned heap_idx;
struct ir3_heap_chunk *chunk;
};
+typedef struct nir_block nir_block;
+
struct ir3_block {
+ struct list_head node;
struct ir3 *shader;
- /* only a single address register: */
- struct ir3_instruction *address;
- struct list_head instr_list;
+
+ nir_block *nblock;
+
+ struct list_head instr_list; /* list of ir3_instruction */
+
+ /* each block has either one or two successors.. in case of
+ * two successors, 'condition' decides which one to follow.
+ * A block preceding an if/else has two successors.
+ */
+ struct ir3_instruction *condition;
+ struct ir3_block *successors[2];
+
+ uint16_t start_ip, end_ip;
+
+ /* used for per-pass extra block data. Mainly used right
+ * now in RA step to track livein/liveout.
+ */
+ void *bd;
+
+#ifdef DEBUG
+ uint32_t serialno;
+#endif
};
struct ir3 * ir3_create(struct ir3_compiler *compiler,
@@ -394,7 +420,6 @@ const char *ir3_instr_name(struct ir3_instruction *instr);
struct ir3_register * ir3_reg_create(struct ir3_instruction *instr,
int num, int flags);
-
static inline bool ir3_instr_check_mark(struct ir3_instruction *instr)
{
if (instr->flags & IR3_INSTR_MARK)
@@ -403,19 +428,10 @@ static inline bool ir3_instr_check_mark(struct ir3_instruction *instr)
return false;
}
-static inline void ir3_clear_mark(struct ir3 *shader)
-{
- /* TODO would be nice to drop the instruction array.. for
- * new compiler, _clear_mark() is all we use it for, and
- * we could probably manage a linked list instead..
- *
- * Also, we'll probably want to mark instructions within
- * a block, so tracking the list of instrs globally is
- * unlikely to be what we want.
- */
- list_for_each_entry (struct ir3_instruction, instr, &shader->block->instr_list, node)
- instr->flags &= ~IR3_INSTR_MARK;
-}
+void ir3_block_clear_mark(struct ir3_block *block);
+void ir3_clear_mark(struct ir3 *shader);
+
+void ir3_count_instructions(struct ir3 *ir);
static inline int ir3_instr_regno(struct ir3_instruction *instr,
struct ir3_register *reg)
@@ -593,6 +609,22 @@ static inline bool reg_gpr(struct ir3_register *r)
return true;
}
+static inline type_t half_type(type_t type)
+{
+ switch (type) {
+ case TYPE_F32: return TYPE_F16;
+ case TYPE_U32: return TYPE_U16;
+ case TYPE_S32: return TYPE_S16;
+ case TYPE_F16:
+ case TYPE_U16:
+ case TYPE_S16:
+ return type;
+ default:
+ assert(0);
+ return ~0;
+ }
+}
+
/* some cat2 instructions (ie. those which are not float) can embed an
* immediate:
*/
@@ -837,6 +869,15 @@ ir3_NOP(struct ir3_block *block)
return ir3_instr_create(block, 0, OPC_NOP);
}
+#define INSTR0(CAT, name) \
+static inline struct ir3_instruction * \
+ir3_##name(struct ir3_block *block) \
+{ \
+ struct ir3_instruction *instr = \
+ ir3_instr_create(block, CAT, OPC_##name); \
+ return instr; \
+}
+
#define INSTR1(CAT, name) \
static inline struct ir3_instruction * \
ir3_##name(struct ir3_block *block, \
@@ -880,7 +921,10 @@ ir3_##name(struct ir3_block *block, \
}
/* cat0 instructions: */
+INSTR0(0, BR);
+INSTR0(0, JUMP);
INSTR1(0, KILL);
+INSTR0(0, END);
/* cat2 instructions, most 2 src but some 1 src: */
INSTR2(2, ADD_F)