/* * Mesa 3-D graphics library * * Copyright (C) 2012-2013 LunarG, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * Authors: * Chia-I Wu */ #ifndef TOY_REG_H #define TOY_REG_H #include "pipe/p_compiler.h" #include "util/u_debug.h" /* for assert() */ #include "util/u_math.h" /* for union fi */ /* a toy reg is 256-bit wide */ #define TOY_REG_WIDTH 32 /** * Register files. */ enum toy_file { /* virtual register file */ TOY_FILE_VRF, TOY_FILE_ARF, TOY_FILE_GRF, TOY_FILE_MRF, TOY_FILE_IMM, TOY_FILE_COUNT, }; /** * Register types. */ enum toy_type { TOY_TYPE_F, TOY_TYPE_D, TOY_TYPE_UD, TOY_TYPE_W, TOY_TYPE_UW, TOY_TYPE_V, /* only valid for immediates */ TOY_TYPE_COUNT, }; /** * Register rectangles. The three numbers stand for vertical stride, width, * and horizontal stride respectively. */ enum toy_rect { TOY_RECT_LINEAR, TOY_RECT_041, TOY_RECT_010, TOY_RECT_220, TOY_RECT_440, TOY_RECT_240, TOY_RECT_COUNT, }; /** * Source swizzles. They are compatible with TGSI_SWIZZLE_x and hardware * values. */ enum toy_swizzle { TOY_SWIZZLE_X = 0, TOY_SWIZZLE_Y = 1, TOY_SWIZZLE_Z = 2, TOY_SWIZZLE_W = 3, }; /** * Destination writemasks. They are compatible with TGSI_WRITEMASK_x and * hardware values. */ enum toy_writemask { TOY_WRITEMASK_X = (1 << TOY_SWIZZLE_X), TOY_WRITEMASK_Y = (1 << TOY_SWIZZLE_Y), TOY_WRITEMASK_Z = (1 << TOY_SWIZZLE_Z), TOY_WRITEMASK_W = (1 << TOY_SWIZZLE_W), TOY_WRITEMASK_XY = (TOY_WRITEMASK_X | TOY_WRITEMASK_Y), TOY_WRITEMASK_XZ = (TOY_WRITEMASK_X | TOY_WRITEMASK_Z), TOY_WRITEMASK_XW = (TOY_WRITEMASK_X | TOY_WRITEMASK_W), TOY_WRITEMASK_YZ = (TOY_WRITEMASK_Y | TOY_WRITEMASK_Z), TOY_WRITEMASK_YW = (TOY_WRITEMASK_Y | TOY_WRITEMASK_W), TOY_WRITEMASK_ZW = (TOY_WRITEMASK_Z | TOY_WRITEMASK_W), TOY_WRITEMASK_XYZ = (TOY_WRITEMASK_X | TOY_WRITEMASK_Y | TOY_WRITEMASK_Z), TOY_WRITEMASK_XYW = (TOY_WRITEMASK_X | TOY_WRITEMASK_Y | TOY_WRITEMASK_W), TOY_WRITEMASK_XZW = (TOY_WRITEMASK_X | TOY_WRITEMASK_Z | TOY_WRITEMASK_W), TOY_WRITEMASK_YZW = (TOY_WRITEMASK_Y | TOY_WRITEMASK_Z | TOY_WRITEMASK_W), TOY_WRITEMASK_XYZW = (TOY_WRITEMASK_X | TOY_WRITEMASK_Y | TOY_WRITEMASK_Z | TOY_WRITEMASK_W), }; /** * Destination operand. */ struct toy_dst { unsigned file:3; /* TOY_FILE_x */ unsigned type:4; /* TOY_TYPE_x */ unsigned rect:3; /* TOY_RECT_x */ unsigned indirect:1; /* true or false */ unsigned indirect_subreg:6; /* which subreg of a0? */ unsigned writemask:4; /* TOY_WRITEMASK_x */ unsigned pad:11; uint32_t val32; }; /** * Source operand. */ struct toy_src { unsigned file:3; /* TOY_FILE_x */ unsigned type:4; /* TOY_TYPE_x */ unsigned rect:3; /* TOY_RECT_x */ unsigned indirect:1; /* true or false */ unsigned indirect_subreg:6; /* which subreg of a0? */ unsigned swizzle_x:2; /* TOY_SWIZZLE_x */ unsigned swizzle_y:2; /* TOY_SWIZZLE_x */ unsigned swizzle_z:2; /* TOY_SWIZZLE_x */ unsigned swizzle_w:2; /* TOY_SWIZZLE_x */ unsigned absolute:1; /* true or false */ unsigned negate:1; /* true or false */ unsigned pad:5; uint32_t val32; }; /** * Return true if the file is virtual. */ static inline bool toy_file_is_virtual(enum toy_file file) { return (file == TOY_FILE_VRF); } /** * Return true if the file is a hardware one. */ static inline bool toy_file_is_hw(enum toy_file file) { return !toy_file_is_virtual(file); } /** * Return the size of the file. */ static inline uint32_t toy_file_size(enum toy_file file) { switch (file) { case TOY_FILE_GRF: return 256 * TOY_REG_WIDTH; case TOY_FILE_MRF: /* there is no MRF on GEN7+ */ return 256 * TOY_REG_WIDTH; default: assert(!"invalid toy file"); return 0; } } /** * Return the size of the type. */ static inline int toy_type_size(enum toy_type type) { switch (type) { case TOY_TYPE_F: case TOY_TYPE_D: case TOY_TYPE_UD: return 4; case TOY_TYPE_W: case TOY_TYPE_UW: return 2; case TOY_TYPE_V: default: assert(!"invalid toy type"); return 0; } } /** * Return true if the destination operand is null. */ static inline bool tdst_is_null(struct toy_dst dst) { /* GEN6_ARF_NULL happens to be 0 */ return (dst.file == TOY_FILE_ARF && dst.val32 == 0); } /** * Validate the destination operand. */ static inline struct toy_dst tdst_validate(struct toy_dst dst) { switch (dst.file) { case TOY_FILE_VRF: case TOY_FILE_ARF: case TOY_FILE_MRF: assert(!dst.indirect); if (dst.file == TOY_FILE_MRF) assert(dst.val32 < toy_file_size(dst.file)); break; case TOY_FILE_GRF: if (!dst.indirect) assert(dst.val32 < toy_file_size(dst.file)); break; case TOY_FILE_IMM: /* yes, dst can be IMM of type W (for IF/ELSE/ENDIF/WHILE) */ assert(!dst.indirect); assert(dst.type == TOY_TYPE_W); break; default: assert(!"invalid dst file"); break; } switch (dst.type) { case TOY_TYPE_V: assert(!"invalid dst type"); break; default: break; } assert(dst.rect == TOY_RECT_LINEAR); if (dst.file != TOY_FILE_IMM) assert(dst.val32 % toy_type_size(dst.type) == 0); assert(dst.writemask <= TOY_WRITEMASK_XYZW); return dst; } /** * Change the type of the destination operand. */ static inline struct toy_dst tdst_type(struct toy_dst dst, enum toy_type type) { dst.type = type; return tdst_validate(dst); } /** * Change the type of the destination operand to TOY_TYPE_D. */ static inline struct toy_dst tdst_d(struct toy_dst dst) { return tdst_type(dst, TOY_TYPE_D); } /** * Change the type of the destination operand to TOY_TYPE_UD. */ static inline struct toy_dst tdst_ud(struct toy_dst dst) { return tdst_type(dst, TOY_TYPE_UD); } /** * Change the type of the destination operand to TOY_TYPE_W. */ static inline struct toy_dst tdst_w(struct toy_dst dst) { return tdst_type(dst, TOY_TYPE_W); } /** * Change the type of the destination operand to TOY_TYPE_UW. */ static inline struct toy_dst tdst_uw(struct toy_dst dst) { return tdst_type(dst, TOY_TYPE_UW); } /** * Change the rectangle of the destination operand. */ static inline struct toy_dst tdst_rect(struct toy_dst dst, enum toy_rect rect) { dst.rect = rect; return tdst_validate(dst); } /** * Apply writemask to the destination operand. Note that the current * writemask is honored. */ static inline struct toy_dst tdst_writemask(struct toy_dst dst, enum toy_writemask writemask) { dst.writemask &= writemask; return tdst_validate(dst); } /** * Offset the destination operand. */ static inline struct toy_dst tdst_offset(struct toy_dst dst, int reg, int subreg) { dst.val32 += reg * TOY_REG_WIDTH + subreg * toy_type_size(dst.type); return tdst_validate(dst); } /** * Construct a destination operand. */ static inline struct toy_dst tdst_full(enum toy_file file, enum toy_type type, enum toy_rect rect, bool indirect, unsigned indirect_subreg, enum toy_writemask writemask, uint32_t val32) { struct toy_dst dst; dst.file = file; dst.type = type; dst.rect = rect; dst.indirect = indirect; dst.indirect_subreg = indirect_subreg; dst.writemask = writemask; dst.pad = 0; dst.val32 = val32; return tdst_validate(dst); } /** * Construct a null destination operand. */ static inline struct toy_dst tdst_null(void) { static const struct toy_dst null_dst = { .file = TOY_FILE_ARF, .type = TOY_TYPE_F, .rect = TOY_RECT_LINEAR, .indirect = false, .indirect_subreg = 0, .writemask = TOY_WRITEMASK_XYZW, .pad = 0, .val32 = 0, }; return null_dst; } /** * Construct a destination operand from a source operand. */ static inline struct toy_dst tdst_from(struct toy_src src) { const enum toy_writemask writemask = (1 << src.swizzle_x) | (1 << src.swizzle_y) | (1 << src.swizzle_z) | (1 << src.swizzle_w); return tdst_full(src.file, src.type, src.rect, src.indirect, src.indirect_subreg, writemask, src.val32); } /** * Construct a destination operand, assuming the type is TOY_TYPE_F, the * rectangle is TOY_RECT_LINEAR, and the writemask is TOY_WRITEMASK_XYZW. */ static inline struct toy_dst tdst(enum toy_file file, unsigned reg, unsigned subreg_in_bytes) { const enum toy_type type = TOY_TYPE_F; const enum toy_rect rect = TOY_RECT_LINEAR; const uint32_t val32 = reg * TOY_REG_WIDTH + subreg_in_bytes; return tdst_full(file, type, rect, false, 0, TOY_WRITEMASK_XYZW, val32); } /** * Construct an immediate destination operand of type TOY_TYPE_W. */ static inline struct toy_dst tdst_imm_w(int16_t w) { const union fi fi = { .i = w }; return tdst_full(TOY_FILE_IMM, TOY_TYPE_W, TOY_RECT_LINEAR, false, 0, TOY_WRITEMASK_XYZW, fi.ui); } /** * Return true if the source operand is null. */ static inline bool tsrc_is_null(struct toy_src src) { /* GEN6_ARF_NULL happens to be 0 */ return (src.file == TOY_FILE_ARF && src.val32 == 0); } /** * Return true if the source operand is swizzled. */ static inline bool tsrc_is_swizzled(struct toy_src src) { return (src.swizzle_x != TOY_SWIZZLE_X || src.swizzle_y != TOY_SWIZZLE_Y || src.swizzle_z != TOY_SWIZZLE_Z || src.swizzle_w != TOY_SWIZZLE_W); } /** * Return true if the source operand is swizzled to the same channel. */ static inline bool tsrc_is_swizzle1(struct toy_src src) { return (src.swizzle_x == src.swizzle_y && src.swizzle_x == src.swizzle_z && src.swizzle_x == src.swizzle_w); } /** * Validate the source operand. */ static inline struct toy_src tsrc_validate(struct toy_src src) { switch (src.file) { case TOY_FILE_VRF: case TOY_FILE_ARF: case TOY_FILE_MRF: assert(!src.indirect); if (src.file == TOY_FILE_MRF) assert(src.val32 < toy_file_size(src.file)); break; case TOY_FILE_GRF: if (!src.indirect) assert(src.val32 < toy_file_size(src.file)); break; case TOY_FILE_IMM: assert(!src.indirect); break; default: assert(!"invalid src file"); break; } switch (src.type) { case TOY_TYPE_V: assert(src.file == TOY_FILE_IMM); break; default: break; } if (src.file != TOY_FILE_IMM) assert(src.val32 % toy_type_size(src.type) == 0); assert(src.swizzle_x < 4 && src.swizzle_y < 4 && src.swizzle_z < 4 && src.swizzle_w < 4); return src; } /** * Change the type of the source operand. */ static inline struct toy_src tsrc_type(struct toy_src src, enum toy_type type) { src.type = type; return tsrc_validate(src); } /** * Change the type of the source operand to TOY_TYPE_D. */ static inline struct toy_src tsrc_d(struct toy_src src) { return tsrc_type(src, TOY_TYPE_D); } /** * Change the type of the source operand to TOY_TYPE_UD. */ static inline struct toy_src tsrc_ud(struct toy_src src) { return tsrc_type(src, TOY_TYPE_UD); } /** * Change the type of the source operand to TOY_TYPE_W. */ static inline struct toy_src tsrc_w(struct toy_src src) { return tsrc_type(src, TOY_TYPE_W); } /** * Change the type of the source operand to TOY_TYPE_UW. */ static inline struct toy_src tsrc_uw(struct toy_src src) { return tsrc_type(src, TOY_TYPE_UW); } /** * Change the rectangle of the source operand. */ static inline struct toy_src tsrc_rect(struct toy_src src, enum toy_rect rect) { src.rect = rect; return tsrc_validate(src); } /** * Swizzle the source operand. Note that the current swizzles are honored. */ static inline struct toy_src tsrc_swizzle(struct toy_src src, enum toy_swizzle swizzle_x, enum toy_swizzle swizzle_y, enum toy_swizzle swizzle_z, enum toy_swizzle swizzle_w) { const enum toy_swizzle current[4] = { src.swizzle_x, src.swizzle_y, src.swizzle_z, src.swizzle_w, }; src.swizzle_x = current[swizzle_x]; src.swizzle_y = current[swizzle_y]; src.swizzle_z = current[swizzle_z]; src.swizzle_w = current[swizzle_w]; return tsrc_validate(src); } /** * Swizzle the source operand to the same channel. Note that the current * swizzles are honored. */ static inline struct toy_src tsrc_swizzle1(struct toy_src src, enum toy_swizzle swizzle) { return tsrc_swizzle(src, swizzle, swizzle, swizzle, swizzle); } /** * Set absolute and unset negate of the source operand. */ static inline struct toy_src tsrc_absolute(struct toy_src src) { src.absolute = true; src.negate = false; return tsrc_validate(src); } /** * Negate the source operand. */ static inline struct toy_src tsrc_negate(struct toy_src src) { src.negate = !src.negate; return tsrc_validate(src); } /** * Offset the source operand. */ static inline struct toy_src tsrc_offset(struct toy_src src, int reg, int subreg) { src.val32 += reg * TOY_REG_WIDTH + subreg * toy_type_size(src.type); return tsrc_validate(src); } /** * Construct a source operand. */ static inline struct toy_src tsrc_full(enum toy_file file, enum toy_type type, enum toy_rect rect, bool indirect, unsigned indirect_subreg, enum toy_swizzle swizzle_x, enum toy_swizzle swizzle_y, enum toy_swizzle swizzle_z, enum toy_swizzle swizzle_w, bool absolute, bool negate, uint32_t val32) { struct toy_src src; src.file = file; src.type = type; src.rect = rect; src.indirect = indirect; src.indirect_subreg = indirect_subreg; src.swizzle_x = swizzle_x; src.swizzle_y = swizzle_y; src.swizzle_z = swizzle_z; src.swizzle_w = swizzle_w; src.absolute = absolute; src.negate = negate; src.pad = 0; src.val32 = val32; return tsrc_validate(src); } /** * Construct a null source operand. */ static inline struct toy_src tsrc_null(void) { static const struct toy_src null_src = { .file = TOY_FILE_ARF, .type = TOY_TYPE_F, .rect = TOY_RECT_LINEAR, .indirect = false, .indirect_subreg = 0, .swizzle_x = TOY_SWIZZLE_X, .swizzle_y = TOY_SWIZZLE_Y, .swizzle_z = TOY_SWIZZLE_Z, .swizzle_w = TOY_SWIZZLE_W, .absolute = false, .negate = false, .pad = 0, .val32 = 0, }; return null_src; } /** * Construct a source operand from a destination operand. */ static inline struct toy_src tsrc_from(struct toy_dst dst) { enum toy_swizzle swizzle[4]; if (dst.writemask == TOY_WRITEMASK_XYZW) { swizzle[0] = TOY_SWIZZLE_X; swizzle[1] = TOY_SWIZZLE_Y; swizzle[2] = TOY_SWIZZLE_Z; swizzle[3] = TOY_SWIZZLE_W; } else { const enum toy_swizzle first = (dst.writemask & TOY_WRITEMASK_X) ? TOY_SWIZZLE_X : (dst.writemask & TOY_WRITEMASK_Y) ? TOY_SWIZZLE_Y : (dst.writemask & TOY_WRITEMASK_Z) ? TOY_SWIZZLE_Z : (dst.writemask & TOY_WRITEMASK_W) ? TOY_SWIZZLE_W : TOY_SWIZZLE_X; swizzle[0] = (dst.writemask & TOY_WRITEMASK_X) ? TOY_SWIZZLE_X : first; swizzle[1] = (dst.writemask & TOY_WRITEMASK_Y) ? TOY_SWIZZLE_Y : first; swizzle[2] = (dst.writemask & TOY_WRITEMASK_Z) ? TOY_SWIZZLE_Z : first; swizzle[3] = (dst.writemask & TOY_WRITEMASK_W) ? TOY_SWIZZLE_W : first; } return tsrc_full(dst.file, dst.type, dst.rect, dst.indirect, dst.indirect_subreg, swizzle[0], swizzle[1], swizzle[2], swizzle[3], false, false, dst.val32); } /** * Construct a source operand, assuming the type is TOY_TYPE_F, the * rectangle is TOY_RECT_LINEAR, and no swizzles/absolute/negate. */ static inline struct toy_src tsrc(enum toy_file file, unsigned reg, unsigned subreg_in_bytes) { const enum toy_type type = TOY_TYPE_F; const enum toy_rect rect = TOY_RECT_LINEAR; const uint32_t val32 = reg * TOY_REG_WIDTH + subreg_in_bytes; return tsrc_full(file, type, rect, false, 0, TOY_SWIZZLE_X, TOY_SWIZZLE_Y, TOY_SWIZZLE_Z, TOY_SWIZZLE_W, false, false, val32); } /** * Construct an immediate source operand. */ static inline struct toy_src tsrc_imm(enum toy_type type, uint32_t val32) { return tsrc_full(TOY_FILE_IMM, type, TOY_RECT_LINEAR, false, 0, TOY_SWIZZLE_X, TOY_SWIZZLE_Y, TOY_SWIZZLE_Z, TOY_SWIZZLE_W, false, false, val32); } /** * Construct an immediate source operand of type TOY_TYPE_F. */ static inline struct toy_src tsrc_imm_f(float f) { const union fi fi = { .f = f }; return tsrc_imm(TOY_TYPE_F, fi.ui); } /** * Construct an immediate source operand of type TOY_TYPE_D. */ static inline struct toy_src tsrc_imm_d(int32_t d) { const union fi fi = { .i = d }; return tsrc_imm(TOY_TYPE_D, fi.ui); } /** * Construct an immediate source operand of type TOY_TYPE_UD. */ static inline struct toy_src tsrc_imm_ud(uint32_t ud) { const union fi fi = { .ui = ud }; return tsrc_imm(TOY_TYPE_UD, fi.ui); } /** * Construct an immediate source operand of type TOY_TYPE_W. */ static inline struct toy_src tsrc_imm_w(int16_t w) { const union fi fi = { .i = w }; return tsrc_imm(TOY_TYPE_W, fi.ui); } /** * Construct an immediate source operand of type TOY_TYPE_UW. */ static inline struct toy_src tsrc_imm_uw(uint16_t uw) { const union fi fi = { .ui = uw }; return tsrc_imm(TOY_TYPE_UW, fi.ui); } /** * Construct an immediate source operand of type TOY_TYPE_V. */ static inline struct toy_src tsrc_imm_v(uint32_t v) { return tsrc_imm(TOY_TYPE_V, v); } #endif /* TOY_REG_H */