pco: define data structures and basic builder implementation with ops

Signed-off-by: Simon Perretta <simon.perretta@imgtec.com>
Acked-by: Frank Binns <frank.binns@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/32258>
This commit is contained in:
Simon Perretta
2024-05-13 02:41:18 +01:00
committed by Marge Bot
parent d47ac545d5
commit f179e5a220
9 changed files with 1112 additions and 6 deletions
+10
View File
@@ -14,6 +14,15 @@ libpowervr_compiler_files = files(
pco_pygen_dep_files = files('pco_pygen_common.py', 'pco_isa.py', 'pco_ops.py')
pco_builder_ops_h = custom_target(
'pco_builder_ops.h',
input : ['pco_builder_ops.h.py'],
output : 'pco_builder_ops.h',
command : [prog_python, '@INPUT@'],
capture : true,
depend_files : pco_pygen_dep_files,
)
pco_common_h = custom_target(
'pco_common.h',
input : ['pco_common.h.py'],
@@ -52,6 +61,7 @@ pco_ops_h = custom_target(
idep_pco_pygen = declare_dependency(
sources : [
pco_builder_ops_h,
pco_common_h,
pco_info_c,
pco_isa_h,
+36
View File
@@ -64,3 +64,39 @@ const nir_shader_compiler_options *pco_nir_options(pco_ctx *ctx)
{
return &ctx->nir_options;
}
/**
* \brief Allocates and sets up a PCO instruction.
*
* \param[in,out] func Parent function.
* \param[in] op Instruction op.
* \param[in] num_dests Number of destinations.
* \param[in] num_srcs Number of sources.
* \return The PCO instruction, or NULL on failure.
*/
pco_instr *pco_instr_create(pco_func *func,
enum pco_op op,
unsigned num_dests,
unsigned num_srcs)
{
pco_instr *instr;
unsigned size = sizeof(*instr);
size += num_dests * sizeof(*instr->dest);
size += num_srcs * sizeof(*instr->src);
instr = rzalloc_size(func, size);
instr->parent_func = func;
instr->op = op;
instr->num_dests = num_dests;
instr->dest = (pco_ref *)(instr + 1);
instr->num_srcs = num_srcs;
instr->src = instr->dest + num_dests;
instr->index = func->next_instr++;
return instr;
}
+1
View File
@@ -12,6 +12,7 @@
#include "pco.h"
#include "pco_internal.h"
#include "pco_isa.h"
#include <stdio.h>
+434
View File
@@ -0,0 +1,434 @@
/*
* Copyright © 2024 Imagination Technologies Ltd.
*
* SPDX-License-Identifier: MIT
*/
#ifndef PCO_BUILDER_H
#define PCO_BUILDER_H
/**
* \\file pco_builder.h
*
* \\brief PCO builder header.
*/
#include "pco.h"
#include "pco_internal.h"
#include "util/list.h"
#include "util/macros.h"
#include <stdbool.h>
/** Cursor pointer. */
enum pco_cursor_option {
PCO_CURSOR_BEFORE_CF_NODE,
PCO_CURSOR_AFTER_CF_NODE,
PCO_CURSOR_BEFORE_INSTR,
PCO_CURSOR_AFTER_INSTR,
PCO_CURSOR_BEFORE_IGRP,
PCO_CURSOR_AFTER_IGRP,
};
/** Cursor for PCO instructions/groups and basic blocks. */
typedef struct pco_cursor {
enum pco_cursor_option option; /** Cursor pointer option. */
union {
pco_cf_node *cf_node;
pco_instr *instr;
pco_igrp *igrp;
};
} pco_cursor;
/** PCO builder context. */
typedef struct pco_builder {
pco_func *func; /** Target function. */
pco_cursor cursor; /** Current position in the function. */
} pco_builder;
/* Cursor position setters. */
/**
* \brief Returns a cursor set to before a cf node.
*
* \param[in] cf_node The cf node.
* \return The cursor.
*/
static inline pco_cursor pco_cursor_before_cf_node(pco_cf_node *cf_node)
{
return (pco_cursor){
.option = PCO_CURSOR_BEFORE_CF_NODE,
.cf_node = cf_node,
};
}
/**
* \brief Returns a cursor set to after a cf node.
*
* \param[in] cf_node The cf node.
* \return The cursor.
*/
static inline pco_cursor pco_cursor_after_cf_node(pco_cf_node *cf_node)
{
return (pco_cursor){
.option = PCO_CURSOR_AFTER_CF_NODE,
.cf_node = cf_node,
};
}
/**
* \brief Returns a cursor set to before a block.
*
* \param[in] block The block.
* \return The cursor.
*/
static inline pco_cursor pco_cursor_before_block(pco_block *block)
{
return pco_cursor_before_cf_node(&block->cf_node);
}
/**
* \brief Returns a cursor set to after a block.
*
* \param[in] block The block.
* \return The cursor.
*/
static inline pco_cursor pco_cursor_after_block(pco_block *block)
{
return pco_cursor_after_cf_node(&block->cf_node);
}
/**
* \brief Returns a cursor set to before an instruction.
*
* \param[in] instr The instruction.
* \return The cursor.
*/
static inline pco_cursor pco_cursor_before_instr(pco_instr *instr)
{
return (pco_cursor){
.option = PCO_CURSOR_BEFORE_INSTR,
.instr = instr,
};
}
/**
* \brief Returns a cursor set to after an instruction.
*
* \param[in] instr The instruction.
* \return The cursor.
*/
static inline pco_cursor pco_cursor_after_instr(pco_instr *instr)
{
return (pco_cursor){
.option = PCO_CURSOR_AFTER_INSTR,
.instr = instr,
};
}
/**
* \brief Returns a cursor set to before an instruction group.
*
* \param[in] igrp The instruction group.
* \return The cursor.
*/
static inline pco_cursor pco_cursor_before_igrp(pco_igrp *igrp)
{
return (pco_cursor){
.option = PCO_CURSOR_BEFORE_IGRP,
.igrp = igrp,
};
}
/**
* \brief Returns a cursor set to after an instruction group.
*
* \param[in] igrp The instruction group.
* \return The cursor.
*/
static inline pco_cursor pco_cursor_after_igrp(pco_igrp *igrp)
{
return (pco_cursor){
.option = PCO_CURSOR_AFTER_IGRP,
.igrp = igrp,
};
}
/**
* \brief Returns whether a cursor is set to before a construct.
*
* \param[in] cursor The cursor.
* \return True if the cursor is set to before a construct.
*/
static inline bool pco_cursor_is_before(pco_cursor cursor)
{
return cursor.option == PCO_CURSOR_BEFORE_CF_NODE ||
cursor.option == PCO_CURSOR_BEFORE_INSTR ||
cursor.option == PCO_CURSOR_BEFORE_IGRP;
}
/* Cursor get functions. */
/**
* \brief Returns the function being pointed to by the cursor.
*
* \param[in] cursor The cursor.
* \return The function being pointed to.
*/
static inline pco_func *pco_cursor_func(pco_cursor cursor)
{
switch (cursor.option) {
case PCO_CURSOR_BEFORE_CF_NODE:
case PCO_CURSOR_AFTER_CF_NODE:
switch (cursor.cf_node->type) {
case PCO_CF_NODE_TYPE_BLOCK:
return pco_cf_node_as_block(cursor.cf_node)->parent_func;
case PCO_CF_NODE_TYPE_IF:
return pco_cf_node_as_if(cursor.cf_node)->parent_func;
case PCO_CF_NODE_TYPE_LOOP:
return pco_cf_node_as_loop(cursor.cf_node)->parent_func;
case PCO_CF_NODE_TYPE_FUNC:
return pco_cf_node_as_func(cursor.cf_node);
default:
break;
}
break;
case PCO_CURSOR_BEFORE_INSTR:
case PCO_CURSOR_AFTER_INSTR:
return cursor.instr->parent_func;
case PCO_CURSOR_BEFORE_IGRP:
case PCO_CURSOR_AFTER_IGRP:
return cursor.igrp->parent_func;
default:
break;
}
unreachable();
}
/**
* \brief Returns the cf node being pointed to by the cursor.
*
* \param[in] cursor The cursor.
* \return The cf node being pointed to.
*/
static inline pco_cf_node *pco_cursor_cf_node(pco_cursor cursor)
{
switch (cursor.option) {
case PCO_CURSOR_BEFORE_CF_NODE:
case PCO_CURSOR_AFTER_CF_NODE:
return cursor.cf_node;
case PCO_CURSOR_BEFORE_INSTR:
case PCO_CURSOR_AFTER_INSTR:
return &cursor.instr->parent_block->cf_node;
case PCO_CURSOR_BEFORE_IGRP:
case PCO_CURSOR_AFTER_IGRP:
return &cursor.igrp->parent_block->cf_node;
default:
break;
}
unreachable();
}
/**
* \brief Returns the block being pointed to by the cursor.
*
* \param[in] cursor The cursor.
* \return The block being pointed to.
*/
static inline pco_block *pco_cursor_block(pco_cursor cursor)
{
switch (cursor.option) {
case PCO_CURSOR_BEFORE_CF_NODE:
case PCO_CURSOR_AFTER_CF_NODE:
switch (cursor.cf_node->type) {
case PCO_CF_NODE_TYPE_BLOCK:
return pco_cf_node_as_block(cursor.cf_node);
/* TODO: other cf node types? */
default:
break;
}
break;
case PCO_CURSOR_BEFORE_INSTR:
case PCO_CURSOR_AFTER_INSTR:
return cursor.instr->parent_block;
case PCO_CURSOR_BEFORE_IGRP:
case PCO_CURSOR_AFTER_IGRP:
return cursor.igrp->parent_block;
default:
break;
}
unreachable();
}
/**
* \brief Returns the instruction being pointed to by the cursor.
*
* \param[in] cursor The cursor.
* \return The instruction being pointed to.
*/
static inline pco_instr *pco_cursor_instr(pco_cursor cursor)
{
bool before = pco_cursor_is_before(cursor);
switch (cursor.option) {
case PCO_CURSOR_BEFORE_CF_NODE:
case PCO_CURSOR_AFTER_CF_NODE: {
pco_block *block = NULL;
switch (cursor.cf_node->type) {
case PCO_CF_NODE_TYPE_BLOCK:
block = pco_cf_node_as_block(cursor.cf_node);
return before ? pco_first_instr(block) : pco_last_instr(block);
/* TODO: other cf node types? */
default:
break;
}
break;
}
case PCO_CURSOR_BEFORE_INSTR:
case PCO_CURSOR_AFTER_INSTR:
return cursor.instr;
default:
break;
}
unreachable();
}
/**
* \brief Returns the instruction group being pointed to by the cursor.
*
* \param[in] cursor The cursor.
* \return The instruction group being pointed to.
*/
static inline pco_igrp *pco_cursor_igrp(pco_cursor cursor)
{
bool before = pco_cursor_is_before(cursor);
switch (cursor.option) {
case PCO_CURSOR_BEFORE_CF_NODE:
case PCO_CURSOR_AFTER_CF_NODE: {
pco_block *block = NULL;
switch (cursor.cf_node->type) {
case PCO_CF_NODE_TYPE_BLOCK:
block = pco_cf_node_as_block(cursor.cf_node);
/* Special case: we're in pco_group_instrs and want to go from
* the start.
*/
if (!block->parent_func->parent_shader->is_grouped)
return NULL;
return before ? pco_first_igrp(block) : pco_last_igrp(block);
/* TODO: other cf node types? */
default:
break;
}
break;
}
case PCO_CURSOR_BEFORE_IGRP:
case PCO_CURSOR_AFTER_IGRP:
return cursor.igrp;
default:
break;
}
unreachable();
}
/* Builder functions. */
/**
* \brief Creates a builder.
*
* \param[in] func The function being targeted.
* \param[in] cursor The cursor.
* \return The builder.
*/
static pco_builder pco_builder_create(pco_func *func, pco_cursor cursor)
{
return (pco_builder){
.func = func,
.cursor = cursor,
};
}
/**
* \brief Inserts a block at a position specified by the builder.
*
* \param[in] b The builder.
* \param[in] block The block.
*/
/* TODO: test with multiple blocks. */
static inline void pco_builder_insert_block(pco_builder *b, pco_block *block)
{
struct list_head *list = &pco_cursor_cf_node(b->cursor)->link;
bool before = pco_cursor_is_before(b->cursor);
list_add(&block->cf_node.link, before ? list->prev : list);
b->cursor = pco_cursor_after_block(block);
}
/**
* \brief Inserts a instruction at a position specified by the builder.
*
* \param[in] b The builder.
* \param[in] instr The instruction.
*/
static inline void pco_builder_insert_instr(pco_builder *b, pco_instr *instr)
{
pco_instr *cursor_instr = pco_cursor_instr(b->cursor);
bool before = pco_cursor_is_before(b->cursor);
pco_block *block = pco_cursor_block(b->cursor);
struct list_head *list = cursor_instr ? &cursor_instr->link : &block->instrs;
instr->parent_block = block;
list_add(&instr->link, (before && cursor_instr) ? list->prev : list);
b->cursor = pco_cursor_after_instr(instr);
}
/**
* \brief Inserts a instruction group at a position specified by the builder.
*
* \param[in] b The builder.
* \param[in] igrp The instruction group.
*/
static inline void pco_builder_insert_igrp(pco_builder *b, pco_igrp *igrp)
{
pco_igrp *cursor_igrp = pco_cursor_igrp(b->cursor);
bool before = pco_cursor_is_before(b->cursor);
pco_block *block = pco_cursor_block(b->cursor);
struct list_head *list = cursor_igrp ? &cursor_igrp->link : &block->instrs;
igrp->parent_block = block;
list_add(&igrp->link, (before && cursor_igrp) ? list->prev : list);
b->cursor = pco_cursor_after_igrp(igrp);
}
/* Generated op building functions. */
#include "pco_builder_ops.h"
#endif /* PCO_BUILDER_H */
+122
View File
@@ -0,0 +1,122 @@
# Copyright © 2024 Imagination Technologies Ltd.
# SPDX-License-Identifier: MIT
from mako.template import Template
from pco_ops import *
template = """/*
* Copyright © 2024 Imagination Technologies Ltd.
*
* SPDX-License-Identifier: MIT
*/
#ifndef PCO_BUILDER_OPS_H
#define PCO_BUILDER_OPS_H
/**
* \\file pco_builder_ops.h
*
* \\brief PCO op building functions.
*/
#include "pco_internal.h"
#include "pco_common.h"
#include "pco_ops.h"
#include "util/macros.h"
#include <assert.h>
#include <stdbool.h>
/** Op mod getting/setting. */
static inline
bool pco_instr_has_mod(const pco_instr *instr, enum pco_op_mod mod)
{
assert(mod < _PCO_OP_MOD_COUNT);
return (pco_op_info[instr->op].mods & (1ULL << mod)) != 0;
}
static inline
void pco_instr_set_mod(pco_instr *instr, enum pco_op_mod mod, uint32_t val)
{
assert(mod < _PCO_OP_MOD_COUNT);
unsigned mod_index = pco_op_info[instr->op].mod_map[mod];
assert(mod_index > 0);
instr->mod[mod_index - 1] = val;
}
static inline
uint32_t pco_instr_get_mod(pco_instr *instr, enum pco_op_mod mod)
{
assert(mod < _PCO_OP_MOD_COUNT);
unsigned mod_index = pco_op_info[instr->op].mod_map[mod];
assert(mod_index > 0);
return instr->mod[mod_index - 1];
}
% for t, cname, ctype in op_mods.values():
static inline
bool pco_instr_has_${t.tname}(const pco_instr *instr)
{
return pco_instr_has_mod(instr, ${cname});
}
static inline
void pco_instr_set_${t.tname}(pco_instr *instr, ${t.name} val)
{
return pco_instr_set_mod(instr, ${cname}, val);
}
static inline
${t.name} pco_instr_get_${t.tname}(pco_instr *instr)
{
return pco_instr_get_mod(instr, ${cname});
}
% endfor
% for op in ops.values():
% if bool(op.op_mods):
struct ${op.bname}_mods {
% for t, *_ in op.op_mods:
${t.name} ${t.tname};
% endfor
};
% endif
#define ${op.bname}(${op.builder_params[1]}${op.builder_params[2]}) _${op.bname}(${op.builder_params[1]}${op.builder_params[3]})
static
pco_instr *_${op.bname}(${op.builder_params[0]})
{
pco_instr *instr = pco_instr_create(pco_cursor_func(b->cursor),
${op.cname.upper()},
${op.num_dests},
${op.num_srcs});
% if op.has_target_cf_node:
instr->target_cf_node = target_cf_node;
% endif
% for d in range(op.num_dests):
instr->dest[${d}] = dest${d};
% endfor
% for s in range(op.num_srcs):
instr->src[${s}] = src${s};
% endfor
% for t, *_ in op.op_mods:
% if t.nzdefault is None:
pco_instr_set_${t.tname}(instr, mods.${t.tname});
% else:
pco_instr_set_${t.tname}(instr, !mods.${t.tname} ? ${t.nzdefault} : mods.${t.tname});
% endif
% endfor
pco_builder_insert_instr(b, instr);
return instr;
}
% endfor
#endif /* PCO_BUILDER_OPS_H */"""
def main():
print(Template(template).render(ops=ops, op_mods=op_mods))
if __name__ == '__main__':
main()
+474
View File
@@ -19,7 +19,10 @@
#include "pco_ops.h"
#include "spirv/nir_spirv.h"
#include "util/macros.h"
#include "util/list.h"
#include "util/u_dynarray.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
@@ -71,6 +74,267 @@ extern const char *pco_skip_passes;
extern bool pco_color;
void pco_debug_init(void);
typedef struct _pco_cf_node pco_cf_node;
typedef struct _pco_func pco_func;
typedef struct _pco_block pco_block;
typedef struct _pco_instr pco_instr;
/** PCO reference index. */
typedef struct PACKED _pco_ref {
/** Reference value. */
union PACKED {
unsigned val : 32;
struct PACKED {
unsigned num : 2; /** Index register number. */
unsigned offset : 8; /** Offset. */
unsigned _pad : 22;
} idx_reg;
};
/** Source/destination modifiers. */
bool oneminus : 1;
bool clamp : 1;
bool abs : 1;
bool neg : 1;
bool flr : 1;
enum pco_elem elem : 4; /** .e0.e1.e2.e3 */
enum pco_dtype dtype : 2; /** Reference data-type. */
unsigned chans : 10; /** Number of channels (1-1024). */
enum pco_bits bits : 3; /** Bit width. */
enum pco_ref_type type : 3; /** Reference type. */
enum pco_reg_class reg_class : 4; /** Register class. */
unsigned _pad : 1;
} pco_ref;
static_assert(sizeof(pco_ref) == 8, "sizeof(pco_ref) != 8");
/** PCO phi source. */
typedef struct _pco_phi_src {
struct list_head link; /** Link in pco_instr::phi_srcs. */
pco_block *pred; /** Predecessor block. */
pco_ref ref; /** Source reference. */
} pco_phi_src;
/** PCO instruction group. */
typedef struct _pco_igrp {
struct list_head link; /** Link in pco_block::instrs. */
pco_block *parent_block; /** Basic block containing the igrp. */
pco_func *parent_func; /** Parent function. */
pco_instr *instrs[_PCO_OP_PHASE_COUNT]; /** Instruction/group list. */
/** Instruction group header. */
struct {
unsigned da;
unsigned length;
union {
enum pco_oporg oporg;
enum pco_opcnt opcnt;
};
bool olchk;
bool w1p;
bool w0p;
enum pco_cc cc;
enum pco_alutype alutype;
union {
struct {
bool end;
bool atom;
unsigned rpt;
};
struct {
unsigned miscctl;
enum pco_ctrlop ctrlop;
};
};
} hdr;
struct {
pco_ref s0;
pco_ref s1;
pco_ref s2;
pco_ref s3;
pco_ref s4;
pco_ref s5;
} srcs;
struct {
pco_ref is0;
pco_ref is1;
pco_ref is2;
pco_ref is3;
pco_ref is4;
pco_ref is5;
} iss;
struct {
pco_ref w0;
pco_ref w1;
} dests;
struct {
enum pco_igrp_hdr_variant igrp_hdr;
union {
enum pco_main_variant main;
enum pco_backend_variant backend;
enum pco_bitwise_variant bitwise;
enum pco_ctrl_variant ctrl;
} instr[_PCO_OP_PHASE_COUNT];
enum pco_src_variant lower_src;
enum pco_src_variant upper_src;
enum pco_iss_variant iss;
enum pco_dst_variant dest;
} variant;
struct {
struct {
unsigned hdr;
unsigned lower_srcs;
unsigned upper_srcs;
unsigned iss;
unsigned dests;
unsigned instrs[_PCO_OP_PHASE_COUNT];
unsigned word_padding;
unsigned align_padding;
unsigned total;
} len;
unsigned offset;
} enc;
unsigned index; /** Igrp index. */
char *comment; /** Comment string. */
} pco_igrp;
/** PCO instruction. */
typedef struct _pco_instr {
union {
struct {
struct list_head link; /** Link in pco_block::instrs. */
pco_block *parent_block; /** Basic block containing the instruction. */
};
pco_igrp *parent_igrp; /** Igrp containing the instruction. */
};
pco_func *parent_func; /** Parent function. */
enum pco_op op;
unsigned num_dests;
pco_ref *dest;
unsigned num_srcs;
pco_ref *src;
union {
struct list_head phi_srcs;
pco_cf_node *target_cf_node;
};
/** Instruction flags/modifiers. */
uint32_t mod[_PCO_OP_MAX_MODS];
unsigned index; /** Instruction index. */
char *comment; /** Comment string. */
} pco_instr;
/** PCO control-flow node type. */
enum pco_cf_node_type {
PCO_CF_NODE_TYPE_BLOCK,
PCO_CF_NODE_TYPE_IF,
PCO_CF_NODE_TYPE_LOOP,
PCO_CF_NODE_TYPE_FUNC,
};
/** PCO control-flow node. */
typedef struct _pco_cf_node {
struct list_head link; /** Link in lists of pco_cf_nodes. */
enum pco_cf_node_type type; /** CF node type. */
struct _pco_cf_node *parent; /** Parent cf node. */
} pco_cf_node;
/** PCO basic block. */
typedef struct _pco_block {
pco_cf_node cf_node; /** Control flow node. */
pco_func *parent_func; /** Parent function. */
struct list_head instrs; /** Instruction/group list. */
unsigned index; /** Block index. */
} pco_block;
/** PCO if cf construct. */
typedef struct _pco_if {
pco_cf_node cf_node; /** CF node. */
pco_func *parent_func; /** Parent function. */
pco_ref cond; /** If condition. */
struct list_head then_body; /** List of pco_cf_nodes for if body. */
struct list_head else_body; /** List of pco_cf_nodes for else body. */
unsigned index; /** If index. */
} pco_if;
/** PCO loop cf construct. */
typedef struct _pco_loop {
pco_cf_node cf_node; /** CF node. */
pco_func *parent_func; /** Parent function. */
struct list_head body; /** List of pco_cf_nodes for loop body. */
unsigned index; /** Loop index. */
} pco_loop;
/** PCO function. */
typedef struct _pco_func {
struct list_head link; /** Link in pco_shader::funcs. */
pco_cf_node cf_node; /** Control flow node. */
pco_shader *parent_shader; /** Shader containing the function. */
bool is_entrypoint;
unsigned index; /** Function index. */
const char *name; /** Function name. */
struct list_head body; /** List of pco_cf_nodes for function body. */
unsigned num_params;
pco_ref *params;
unsigned next_ssa; /** Next SSA node index. */
unsigned next_instr; /** Next instruction index. */
unsigned next_igrp; /** Next igrp index. */
unsigned next_block; /** Next block index. */
unsigned next_if; /** Next if index. */
unsigned next_loop; /** Next loop index. */
unsigned temps; /** Number of temps allocated. */
} pco_func;
/** PCO shader. */
typedef struct _pco_shader {
pco_ctx *ctx; /** Compiler context. */
nir_shader *nir; /** Source NIR shader. */
gl_shader_stage stage; /** Shader stage. */
const char *name; /** Shader name. */
bool is_internal; /** Whether this is an internal shader. */
bool is_grouped; /** Whether the shader uses igrps. */
struct list_head funcs; /** List of functions. */
unsigned next_func; /** Next function index. */
struct {
struct util_dynarray buf; /** Shader binary. */
/** Binary patch info. */
unsigned num_patches;
struct {
unsigned offset;
} * patch;
} binary;
} pco_shader;
/** Op info. */
struct pco_op_info {
const char *str; /** Op name string. */
@@ -108,4 +372,214 @@ struct pco_ref_mod_info {
};
extern const struct pco_ref_mod_info pco_ref_mod_info[_PCO_REF_MOD_COUNT];
pco_instr *pco_instr_create(pco_func *func,
enum pco_op op,
unsigned num_dests,
unsigned num_srcs);
/* Cast helpers. */
/* CF nodes. */
#define PCO_DEFINE_CAST(name, in_type, out_type, field, type_field, type_value) \
static inline out_type *name(const in_type *parent) \
{ \
assert(parent && parent->type_field == type_value); \
return list_entry(parent, out_type, field); \
}
PCO_DEFINE_CAST(pco_cf_node_as_block,
pco_cf_node,
pco_block,
cf_node,
type,
PCO_CF_NODE_TYPE_BLOCK)
PCO_DEFINE_CAST(pco_cf_node_as_if,
pco_cf_node,
pco_if,
cf_node,
type,
PCO_CF_NODE_TYPE_IF)
PCO_DEFINE_CAST(pco_cf_node_as_loop,
pco_cf_node,
pco_loop,
cf_node,
type,
PCO_CF_NODE_TYPE_LOOP)
PCO_DEFINE_CAST(pco_cf_node_as_func,
pco_cf_node,
pco_func,
cf_node,
type,
PCO_CF_NODE_TYPE_FUNC)
/**
* \brief Returns the entrypoint function of a PCO shader.
*
* \param[in] shader The PCO shader.
* \return The entrypoint function, or NULL if the shader has no functions.
*/
static inline pco_func *pco_entrypoint(pco_shader *shader)
{
if (list_is_empty(&shader->funcs))
return NULL;
pco_func *func = list_first_entry(&shader->funcs, pco_func, link);
assert(func->is_entrypoint);
return func;
}
/* Motions. */
/**
* \brief Returns the first block in a function.
*
* \param[in] func The function.
* \return The first block, or NULL if the function body is empty.
*/
static inline pco_block *pco_first_block(pco_func *func)
{
pco_cf_node *cf_node = list_first_entry(&func->body, pco_cf_node, link);
if (list_is_empty(&func->body))
return NULL;
return pco_cf_node_as_block(cf_node);
}
/**
* \brief Returns the last block in a function.
*
* \param[in] func The function.
* \return The last block, or NULL if the function body is empty.
*/
static inline pco_block *pco_last_block(pco_func *func)
{
pco_cf_node *cf_node = list_last_entry(&func->body, pco_cf_node, link);
if (list_is_empty(&func->body))
return NULL;
return pco_cf_node_as_block(cf_node);
}
/**
* \brief Returns the first instruction in a block.
*
* \param[in] block The block.
* \return The first instruction, or NULL if the block is empty.
*/
static inline pco_instr *pco_first_instr(pco_block *block)
{
assert(!block->parent_func->parent_shader->is_grouped);
if (list_is_empty(&block->instrs))
return NULL;
return list_first_entry(&block->instrs, pco_instr, link);
}
/**
* \brief Returns the last instruction in a block.
*
* \param[in] block The block.
* \return The last instruction, or NULL if the block is empty.
*/
static inline pco_instr *pco_last_instr(pco_block *block)
{
assert(!block->parent_func->parent_shader->is_grouped);
if (list_is_empty(&block->instrs))
return NULL;
return list_last_entry(&block->instrs, pco_instr, link);
}
/**
* \brief Returns the next instruction.
*
* \param[in] instr The current instruction.
* \return The next instruction, or NULL if the end of the block has been
* reached.
*/
static inline pco_instr *pco_next_instr(pco_instr *instr)
{
assert(!instr->parent_func->parent_shader->is_grouped);
if (!instr || instr == pco_last_instr(instr->parent_block))
return NULL;
return list_entry(instr->link.next, pco_instr, link);
}
/**
* \brief Returns the previous instruction.
*
* \param[in] instr The current instruction.
* \return The previous instruction, or NULL if the start of the block has been
* reached.
*/
static inline pco_instr *pco_prev_instr(pco_instr *instr)
{
assert(!instr->parent_func->parent_shader->is_grouped);
if (!instr || instr == pco_first_instr(instr->parent_block))
return NULL;
return list_entry(instr->link.prev, pco_instr, link);
}
/**
* \brief Returns the first instruction group in a block.
*
* \param[in] block The block.
* \return The first instruction group, or NULL if the block is empty.
*/
static inline pco_igrp *pco_first_igrp(pco_block *block)
{
assert(block->parent_func->parent_shader->is_grouped);
if (list_is_empty(&block->instrs))
return NULL;
return list_first_entry(&block->instrs, pco_igrp, link);
}
/**
* \brief Returns the last instruction group in a block.
*
* \param[in] block The block.
* \return The last instruction group, or NULL if the block is empty.
*/
static inline pco_igrp *pco_last_igrp(pco_block *block)
{
assert(block->parent_func->parent_shader->is_grouped);
if (list_is_empty(&block->instrs))
return NULL;
return list_last_entry(&block->instrs, pco_igrp, link);
}
/**
* \brief Returns the next instruction group.
*
* \param[in] igrp The current instruction group.
* \return The next instruction group, or NULL if the end of the block has been
* reached.
*/
static inline pco_igrp *pco_next_igrp(pco_igrp *igrp)
{
assert(igrp->parent_func->parent_shader->is_grouped);
if (!igrp || igrp == pco_last_igrp(igrp->parent_block))
return NULL;
return list_entry(igrp->link.next, pco_igrp, link);
}
/**
* \brief Returns the previous instruction group.
*
* \param[in] igrp The current instruction group.
* \return The previous instruction group, or NULL if the start of the block has
* been reached.
*/
static inline pco_igrp *pco_prev_igrp(pco_igrp *igrp)
{
assert(igrp->parent_func->parent_shader->is_grouped);
if (!igrp || igrp == pco_first_igrp(igrp->parent_block))
return NULL;
return list_entry(igrp->link.prev, pco_igrp, link);
}
#endif /* PCO_INTERNAL_H */
+4
View File
@@ -249,4 +249,8 @@ OM_PHASE2END = op_mod('phase2end', BaseType.bool)
# HW ops
O_NOP = hw_op('nop', [OM_EXEC_CND, OM_END])
O_WOP = hw_op('wop')
O_MBYP0 = hw_op('mbyp0', [OM_OLCHK, OM_EXEC_CND, OM_END, OM_ATOM, OM_RPT], 1, 1, [], [[RM_ABS, RM_NEG]])
O_FADD = hw_op('fadd', [OM_LP, OM_SAT], 1, 2, [], [[RM_ABS, RM_NEG, RM_FLR], [RM_ABS]])
+30 -6
View File
@@ -16,8 +16,9 @@ class BaseType(Enum):
enum = auto()
class Type(object):
def __init__(self, name, base_type, num_bits, dec_bits, check, encode, nzdefault, print_early, enum):
def __init__(self, name, tname, base_type, num_bits, dec_bits, check, encode, nzdefault, print_early, enum):
self.name = name
self.tname = tname
self.base_type = base_type
self.num_bits = num_bits
self.dec_bits = dec_bits
@@ -41,7 +42,7 @@ def type(name, base_type, num_bits=None, dec_bits=None, check=None, encode=None,
else:
assert False, f'Invalid base type for type {name}.'
t = Type(_name, base_type, num_bits, dec_bits, check, encode, nzdefault, print_early, enum)
t = Type(_name, name, base_type, num_bits, dec_bits, check, encode, nzdefault, print_early, enum)
types[name] = t
return t
@@ -360,12 +361,11 @@ def bit_struct(name, bit_set, field_mappings, data=None):
return bs
# Op definitions.
VARIABLE = ~0
class Op(object):
def __init__(self, name, cname, is_pseudo, op_mods, cop_mods, op_mod_map, num_dests, num_srcs, dest_mods, cdest_mods, src_mods, csrc_mods, has_target_cf_node):
def __init__(self, name, cname, bname, is_pseudo, op_mods, cop_mods, op_mod_map, num_dests, num_srcs, dest_mods, cdest_mods, src_mods, csrc_mods, has_target_cf_node, builder_params):
self.name = name
self.cname = cname
self.bname = bname
self.is_pseudo = is_pseudo
self.op_mods = op_mods
self.cop_mods = cop_mods
@@ -377,6 +377,7 @@ class Op(object):
self.src_mods = src_mods
self.csrc_mods = csrc_mods
self.has_target_cf_node = has_target_cf_node
self.builder_params = builder_params
ops = {}
@@ -384,11 +385,34 @@ def op(name, is_pseudo, op_mods, num_dests, num_srcs, dest_mods, src_mods, has_t
assert name not in ops.keys(), f'Duplicate op "{name}".'
cname = f'{prefix}_op_{name}'.replace('.', '_')
bname = f'{prefix}_{name}'.replace('.', '_')
cop_mods = 0 if not op_mods else ' | '.join([f'(1 << {mod[1]})' for mod in op_mods])
op_mod_map = {mod[1]: index + 1 for index, mod in enumerate(op_mods)}
cdest_mods = {i: 0 if not dest_mods else ' | '.join([f'(1 << {mod[1]})' for mod in destn_mods]) for i, destn_mods in enumerate(dest_mods)}
csrc_mods = {i: 0 if not src_mods else ' | '.join([f'(1 << {mod[1]})' for mod in srcn_mods]) for i, srcn_mods in enumerate(src_mods)}
op = Op(name, cname, is_pseudo, op_mods, cop_mods, op_mod_map, num_dests, num_srcs, dest_mods, cdest_mods, src_mods, csrc_mods, has_target_cf_node)
# Typed and untyped params for builder.
builder_params = ['', '', '', '']
builder_params[0] += 'pco_builder *b'
builder_params[1] += 'b'
if has_target_cf_node:
builder_params[0] += ', pco_cf_node *target_cf_node'
builder_params[1] += ', target_cf_node'
for d in range(num_dests):
builder_params[0] += f', pco_ref dest{d}'
builder_params[1] += f', dest{d}'
for s in range(num_srcs):
builder_params[0] += f', pco_ref src{s}'
builder_params[1] += f', src{s}'
if bool(op_mods):
builder_params[0] += f', struct {prefix}_{name}_mods mods'
builder_params[2] = ', ...'
builder_params[3] = f', (struct {bname}_mods){{0, ##__VA_ARGS__}}'
op = Op(name, cname, bname, is_pseudo, op_mods, cop_mods, op_mod_map, num_dests, num_srcs, dest_mods, cdest_mods, src_mods, csrc_mods, has_target_cf_node, builder_params)
ops[name] = op
return op
+1
View File
@@ -11,6 +11,7 @@
*/
#include "pco.h"
#include "pco_builder.h"
#include "pco_internal.h"
#include <stdio.h>