1/* 2 * Copyright © 2018 Intel Corporation 3 * 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: 10 * 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 13 * Software. 14 * 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 21 * IN THE SOFTWARE. 22 */ 23 24#include "brw_nir.h" 25#include "compiler/nir/nir_builder.h" 26 27static nir_op 28get_conversion_op(nir_alu_type src_type, 29 unsigned src_bit_size, 30 nir_alu_type dst_type, 31 unsigned dst_bit_size, 32 nir_rounding_mode rounding_mode) 33{ 34 nir_alu_type src_full_type = (nir_alu_type) (src_type | src_bit_size); 35 nir_alu_type dst_full_type = (nir_alu_type) (dst_type | dst_bit_size); 36 37 return nir_type_conversion_op(src_full_type, dst_full_type, rounding_mode); 38} 39 40static nir_rounding_mode 41get_opcode_rounding_mode(nir_op op) 42{ 43 switch (op) { 44 case nir_op_f2f16_rtz: 45 return nir_rounding_mode_rtz; 46 case nir_op_f2f16_rtne: 47 return nir_rounding_mode_rtne; 48 default: 49 return nir_rounding_mode_undef; 50 } 51} 52 53static void 54split_conversion(nir_builder *b, nir_alu_instr *alu, nir_op op1, nir_op op2) 55{ 56 b->cursor = nir_before_instr(&alu->instr); 57 assert(alu->dest.write_mask == 1); 58 nir_ssa_def *src = nir_ssa_for_alu_src(b, alu, 0); 59 nir_ssa_def *tmp = nir_build_alu(b, op1, src, NULL, NULL, NULL); 60 nir_ssa_def *res = nir_build_alu(b, op2, tmp, NULL, NULL, NULL); 61 nir_ssa_def_rewrite_uses(&alu->dest.dest.ssa, res); 62 nir_instr_remove(&alu->instr); 63} 64 65static bool 66lower_alu_instr(nir_builder *b, nir_alu_instr *alu) 67{ 68 unsigned src_bit_size = nir_src_bit_size(alu->src[0].src); 69 nir_alu_type src_type = nir_op_infos[alu->op].input_types[0]; 70 nir_alu_type src_full_type = (nir_alu_type) (src_type | src_bit_size); 71 72 unsigned dst_bit_size = nir_dest_bit_size(alu->dest.dest); 73 nir_alu_type dst_full_type = nir_op_infos[alu->op].output_type; 74 nir_alu_type dst_type = nir_alu_type_get_base_type(dst_full_type); 75 76 /* BDW PRM, vol02, Command Reference Instructions, mov - MOVE: 77 * 78 * "There is no direct conversion from HF to DF or DF to HF. 79 * Use two instructions and F (Float) as an intermediate type. 80 * 81 * There is no direct conversion from HF to Q/UQ or Q/UQ to HF. 82 * Use two instructions and F (Float) or a word integer type 83 * or a DWord integer type as an intermediate type." 84 * 85 * It is important that the intermediate conversion happens through a 86 * 32-bit float type so we don't lose range when we convert from 87 * a 64-bit integer. 88 */ 89 if ((src_full_type == nir_type_float16 && dst_bit_size == 64) || 90 (src_bit_size == 64 && dst_full_type == nir_type_float16)) { 91 nir_op op1 = get_conversion_op(src_type, src_bit_size, 92 nir_type_float, 32, 93 nir_rounding_mode_undef); 94 nir_op op2 = get_conversion_op(nir_type_float, 32, 95 dst_type, dst_bit_size, 96 get_opcode_rounding_mode(alu->op)); 97 split_conversion(b, alu, op1, op2); 98 return true; 99 } 100 101 /* SKL PRM, vol 02a, Command Reference: Instructions, Move: 102 * 103 * "There is no direct conversion from B/UB to DF or DF to B/UB. Use 104 * two instructions and a word or DWord intermediate type." 105 * 106 * "There is no direct conversion from B/UB to Q/UQ or Q/UQ to B/UB. 107 * Use two instructions and a word or DWord intermediate integer 108 * type." 109 * 110 * It is important that we use a 32-bit integer matching the sign of the 111 * destination as the intermediate type so we avoid any chance of rtne 112 * rounding happening before the conversion to integer (which is expected 113 * to round towards zero) in double to byte conversions. 114 */ 115 if ((src_bit_size == 8 && dst_bit_size == 64) || 116 (src_bit_size == 64 && dst_bit_size == 8)) { 117 nir_op op1 = get_conversion_op(src_type, src_bit_size, dst_type, 32, 118 nir_rounding_mode_undef); 119 nir_op op2 = get_conversion_op(dst_type, 32, dst_type, dst_bit_size, 120 nir_rounding_mode_undef); 121 split_conversion(b, alu, op1, op2); 122 return true; 123 } 124 125 return false; 126} 127 128static bool 129lower_instr(nir_builder *b, nir_instr *instr, UNUSED void *cb_data) 130{ 131 if (instr->type != nir_instr_type_alu) 132 return false; 133 134 nir_alu_instr *alu = nir_instr_as_alu(instr); 135 assert(alu->dest.dest.is_ssa); 136 137 if (!nir_op_infos[alu->op].is_conversion) 138 return false; 139 140 return lower_alu_instr(b, alu); 141} 142 143bool 144brw_nir_lower_conversions(nir_shader *shader) 145{ 146 return nir_shader_instructions_pass(shader, lower_instr, 147 nir_metadata_block_index | 148 nir_metadata_dominance, 149 NULL); 150} 151