agx: Augment if/else/while_cmp with a target
Add an optional pointer to a target block for these instructions. This does NOT act like a logical branch, and does NOT get added to the logical control flow. It is ignored wholesale until after RA, when physical edges may be inserted by a pass we add later in this series. Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
This commit is contained in:
@@ -131,7 +131,7 @@ agx_fmov_to(agx_builder *b, agx_index dst0, agx_index src0)
|
|||||||
static inline agx_instr *
|
static inline agx_instr *
|
||||||
agx_push_exec(agx_builder *b, unsigned n)
|
agx_push_exec(agx_builder *b, unsigned n)
|
||||||
{
|
{
|
||||||
return agx_if_fcmp(b, agx_zero(), agx_zero(), n, AGX_FCOND_EQ, false);
|
return agx_if_fcmp(b, agx_zero(), agx_zero(), n, AGX_FCOND_EQ, false, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline agx_instr *
|
static inline agx_instr *
|
||||||
|
@@ -1788,7 +1788,7 @@ agx_emit_jump(agx_builder *b, nir_jump_instr *instr)
|
|||||||
agx_block_add_successor(ctx->current_block, ctx->break_block);
|
agx_block_add_successor(ctx->current_block, ctx->break_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
agx_break(b, nestings);
|
agx_break(b, nestings, ctx->break_block);
|
||||||
ctx->current_block->unconditional_jumps = true;
|
ctx->current_block->unconditional_jumps = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1941,7 +1941,8 @@ emit_if(agx_context *ctx, nir_if *nif)
|
|||||||
agx_builder _b = agx_init_builder(ctx, agx_after_block(first_block));
|
agx_builder _b = agx_init_builder(ctx, agx_after_block(first_block));
|
||||||
agx_index cond = agx_src_index(&nif->condition);
|
agx_index cond = agx_src_index(&nif->condition);
|
||||||
|
|
||||||
agx_if_icmp(&_b, cond, agx_zero(), 1, AGX_ICOND_UEQ, true);
|
agx_instr *if_ = agx_if_icmp(&_b, cond, agx_zero(), 1, AGX_ICOND_UEQ, true,
|
||||||
|
NULL /* filled in later */);
|
||||||
ctx->loop_nesting++;
|
ctx->loop_nesting++;
|
||||||
ctx->total_nesting++;
|
ctx->total_nesting++;
|
||||||
|
|
||||||
@@ -1954,11 +1955,16 @@ emit_if(agx_context *ctx, nir_if *nif)
|
|||||||
agx_block *else_block = emit_cf_list(ctx, &nif->else_list);
|
agx_block *else_block = emit_cf_list(ctx, &nif->else_list);
|
||||||
agx_block *end_else = ctx->current_block;
|
agx_block *end_else = ctx->current_block;
|
||||||
|
|
||||||
|
/* If the "if" fails, we fallthrough to the else */
|
||||||
|
if_->target = else_block;
|
||||||
|
|
||||||
/* Insert an else instruction at the beginning of the else block. We use
|
/* Insert an else instruction at the beginning of the else block. We use
|
||||||
* "else_fcmp 0.0, 0.0, eq" as unconditional else, matching the blob.
|
* "else_fcmp 0.0, 0.0, eq" as unconditional else, matching the blob.
|
||||||
|
*
|
||||||
|
* If it fails, we fall through to the logical end of the last else block.
|
||||||
*/
|
*/
|
||||||
_b.cursor = agx_before_block(else_block);
|
_b.cursor = agx_before_block(else_block);
|
||||||
agx_else_fcmp(&_b, agx_zero(), agx_zero(), 1, AGX_FCOND_EQ, false);
|
agx_else_fcmp(&_b, agx_zero(), agx_zero(), 1, AGX_FCOND_EQ, false, end_else);
|
||||||
|
|
||||||
ctx->after_block = agx_create_block(ctx);
|
ctx->after_block = agx_create_block(ctx);
|
||||||
|
|
||||||
@@ -2019,8 +2025,11 @@ emit_loop(agx_context *ctx, nir_loop *nloop)
|
|||||||
*/
|
*/
|
||||||
_b.cursor = agx_after_block(ctx->current_block);
|
_b.cursor = agx_after_block(ctx->current_block);
|
||||||
|
|
||||||
if (ctx->loop_continues)
|
if (ctx->loop_continues) {
|
||||||
agx_while_icmp(&_b, agx_zero(), agx_zero(), 2, AGX_ICOND_UEQ, false);
|
agx_while_icmp(
|
||||||
|
&_b, agx_zero(), agx_zero(), 2, AGX_ICOND_UEQ, false,
|
||||||
|
NULL /* no semantic target, used purely for side effects */);
|
||||||
|
}
|
||||||
|
|
||||||
agx_jmp_exec_any(&_b, start_block);
|
agx_jmp_exec_any(&_b, start_block);
|
||||||
agx_pop_exec(&_b, ctx->loop_continues ? 2 : 1);
|
agx_pop_exec(&_b, ctx->loop_continues ? 2 : 1);
|
||||||
|
@@ -275,6 +275,12 @@ typedef struct {
|
|||||||
uint8_t nr_dests;
|
uint8_t nr_dests;
|
||||||
uint8_t nr_srcs;
|
uint8_t nr_srcs;
|
||||||
|
|
||||||
|
/* TODO: More efficient */
|
||||||
|
union {
|
||||||
|
enum agx_icond icond;
|
||||||
|
enum agx_fcond fcond;
|
||||||
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint64_t imm;
|
uint64_t imm;
|
||||||
uint32_t writeout;
|
uint32_t writeout;
|
||||||
@@ -285,8 +291,6 @@ typedef struct {
|
|||||||
uint16_t pixel_offset;
|
uint16_t pixel_offset;
|
||||||
uint16_t zs;
|
uint16_t zs;
|
||||||
enum agx_sr sr;
|
enum agx_sr sr;
|
||||||
enum agx_icond icond;
|
|
||||||
enum agx_fcond fcond;
|
|
||||||
enum agx_round round;
|
enum agx_round round;
|
||||||
enum agx_atomic_opc atomic_opc;
|
enum agx_atomic_opc atomic_opc;
|
||||||
enum agx_lod_mode lod_mode;
|
enum agx_lod_mode lod_mode;
|
||||||
|
@@ -14,10 +14,10 @@ while_for_break_if(agx_builder *b, agx_instr *I)
|
|||||||
{
|
{
|
||||||
if (I->op == AGX_OPCODE_BREAK_IF_FCMP) {
|
if (I->op == AGX_OPCODE_BREAK_IF_FCMP) {
|
||||||
return agx_while_fcmp(b, I->src[0], I->src[1], I->nest, I->fcond,
|
return agx_while_fcmp(b, I->src[0], I->src[1], I->nest, I->fcond,
|
||||||
!I->invert_cond);
|
!I->invert_cond, NULL);
|
||||||
} else {
|
} else {
|
||||||
return agx_while_icmp(b, I->src[0], I->src[1], I->nest, I->icond,
|
return agx_while_icmp(b, I->src[0], I->src[1], I->nest, I->icond,
|
||||||
!I->invert_cond);
|
!I->invert_cond, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -350,7 +350,7 @@ for is_float in [False, True]:
|
|||||||
name = "{}_{}cmp".format(cf, "f" if is_float else "i")
|
name = "{}_{}cmp".format(cf, "f" if is_float else "i")
|
||||||
exact = 0x42 | (0x0 if is_float else 0x10) | (cf_op << 9)
|
exact = 0x42 | (0x0 if is_float else 0x10) | (cf_op << 9)
|
||||||
mask = 0x7F | (0x3 << 9) | mod_mask | (0x3 << 44)
|
mask = 0x7F | (0x3 << 9) | mod_mask | (0x3 << 44)
|
||||||
imms = [NEST, FCOND if is_float else ICOND, INVERT_COND]
|
imms = [NEST, FCOND if is_float else ICOND, INVERT_COND, TARGET]
|
||||||
|
|
||||||
op(name, (exact, mask, 6, _), dests = 0, srcs = 2, can_eliminate = False,
|
op(name, (exact, mask, 6, _), dests = 0, srcs = 2, can_eliminate = False,
|
||||||
imms = imms, is_float = is_float,
|
imms = imms, is_float = is_float,
|
||||||
@@ -426,10 +426,10 @@ op("preload", _, srcs = 1, schedule_class = "preload")
|
|||||||
|
|
||||||
# Pseudo-instructions to set the nesting counter. Lowers to r0l writes after RA.
|
# Pseudo-instructions to set the nesting counter. Lowers to r0l writes after RA.
|
||||||
op("begin_cf", _, dests = 0, can_eliminate = False)
|
op("begin_cf", _, dests = 0, can_eliminate = False)
|
||||||
op("break", _, dests = 0, imms = [NEST], can_eliminate = False,
|
op("break", _, dests = 0, imms = [NEST, TARGET], can_eliminate = False,
|
||||||
schedule_class = "invalid")
|
schedule_class = "invalid")
|
||||||
|
|
||||||
for (name, is_float) in [("break_if_icmp", False), ("break_if_fcmp", True)]:
|
for (name, is_float) in [("break_if_icmp", False), ("break_if_fcmp", True)]:
|
||||||
op(name, _, dests = 0, srcs = 2,
|
op(name, _, dests = 0, srcs = 2,
|
||||||
imms = [NEST, INVERT_COND, FCOND if is_float else ICOND],
|
imms = [NEST, INVERT_COND, FCOND if is_float else ICOND, TARGET],
|
||||||
can_eliminate = False, schedule_class = "invalid")
|
can_eliminate = False, schedule_class = "invalid")
|
||||||
|
@@ -61,10 +61,10 @@ match_block(agx_context *ctx, agx_block *block)
|
|||||||
|
|
||||||
if (if_->op == AGX_OPCODE_IF_FCMP) {
|
if (if_->op == AGX_OPCODE_IF_FCMP) {
|
||||||
agx_break_if_fcmp(&b, if_->src[0], if_->src[1], new_nest,
|
agx_break_if_fcmp(&b, if_->src[0], if_->src[1], new_nest,
|
||||||
if_->invert_cond, if_->fcond);
|
if_->invert_cond, if_->fcond, break_->target);
|
||||||
} else {
|
} else {
|
||||||
agx_break_if_icmp(&b, if_->src[0], if_->src[1], new_nest,
|
agx_break_if_icmp(&b, if_->src[0], if_->src[1], new_nest,
|
||||||
if_->invert_cond, if_->icond);
|
if_->invert_cond, if_->icond, break_->target);
|
||||||
}
|
}
|
||||||
|
|
||||||
agx_remove_instruction(if_);
|
agx_remove_instruction(if_);
|
||||||
|
@@ -203,16 +203,16 @@ TEST_F(Optimizer, NoConversionsOn16BitALU)
|
|||||||
TEST_F(Optimizer, IfCondition)
|
TEST_F(Optimizer, IfCondition)
|
||||||
{
|
{
|
||||||
CASE_NO_RETURN(agx_if_icmp(b, agx_icmp(b, wx, wy, AGX_ICOND_UEQ, true),
|
CASE_NO_RETURN(agx_if_icmp(b, agx_icmp(b, wx, wy, AGX_ICOND_UEQ, true),
|
||||||
agx_zero(), 1, AGX_ICOND_UEQ, true),
|
agx_zero(), 1, AGX_ICOND_UEQ, true, NULL),
|
||||||
agx_if_icmp(b, wx, wy, 1, AGX_ICOND_UEQ, true));
|
agx_if_icmp(b, wx, wy, 1, AGX_ICOND_UEQ, true, NULL));
|
||||||
|
|
||||||
CASE_NO_RETURN(agx_if_icmp(b, agx_fcmp(b, wx, wy, AGX_FCOND_EQ, true),
|
CASE_NO_RETURN(agx_if_icmp(b, agx_fcmp(b, wx, wy, AGX_FCOND_EQ, true),
|
||||||
agx_zero(), 1, AGX_ICOND_UEQ, true),
|
agx_zero(), 1, AGX_ICOND_UEQ, true, NULL),
|
||||||
agx_if_fcmp(b, wx, wy, 1, AGX_FCOND_EQ, true));
|
agx_if_fcmp(b, wx, wy, 1, AGX_FCOND_EQ, true, NULL));
|
||||||
|
|
||||||
CASE_NO_RETURN(agx_if_icmp(b, agx_fcmp(b, hx, hy, AGX_FCOND_LT, false),
|
CASE_NO_RETURN(agx_if_icmp(b, agx_fcmp(b, hx, hy, AGX_FCOND_LT, false),
|
||||||
agx_zero(), 1, AGX_ICOND_UEQ, true),
|
agx_zero(), 1, AGX_ICOND_UEQ, true, NULL),
|
||||||
agx_if_fcmp(b, hx, hy, 1, AGX_FCOND_LT, false));
|
agx_if_fcmp(b, hx, hy, 1, AGX_FCOND_LT, false, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(Optimizer, SelectCondition)
|
TEST_F(Optimizer, SelectCondition)
|
||||||
|
Reference in New Issue
Block a user