1/* 2 * Copyright © 2012 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 <stdlib.h> 25#include <stdio.h> 26#include <stdbool.h> 27#include "util/ralloc.h" 28#include "brw_eu.h" 29 30#include <gtest/gtest.h> 31 32struct CompactParams { 33 unsigned verx10; 34 unsigned align; 35}; 36 37std::string 38get_compact_params_name(const testing::TestParamInfo<CompactParams> p) 39{ 40 CompactParams params = p.param; 41 std::stringstream ss; 42 ss << params.verx10 << "_"; 43 switch (params.align) { 44 case BRW_ALIGN_1: 45 ss << "Align_1"; 46 break; 47 case BRW_ALIGN_16: 48 ss << "Align_16"; 49 break; 50 default: 51 unreachable("invalid align"); 52 } 53 return ss.str(); 54} 55 56static bool 57test_compact_instruction(struct brw_codegen *p, brw_inst src) 58{ 59 brw_compact_inst dst; 60 memset(&dst, 0xd0, sizeof(dst)); 61 62 if (brw_try_compact_instruction(p->devinfo, &dst, &src)) { 63 brw_inst uncompacted; 64 65 brw_uncompact_instruction(p->devinfo, &uncompacted, &dst); 66 if (memcmp(&uncompacted, &src, sizeof(src))) { 67 brw_debug_compact_uncompact(p->devinfo, &src, &uncompacted); 68 return false; 69 } 70 } else { 71 brw_compact_inst unchanged; 72 memset(&unchanged, 0xd0, sizeof(unchanged)); 73 /* It's not supposed to change dst unless it compacted. */ 74 if (memcmp(&unchanged, &dst, sizeof(dst))) { 75 fprintf(stderr, "Failed to compact, but dst changed\n"); 76 fprintf(stderr, " Instruction: "); 77 brw_disassemble_inst(stderr, p->devinfo, &src, false, 0, NULL); 78 return false; 79 } 80 } 81 82 return true; 83} 84 85/** 86 * When doing fuzz testing, pad bits won't round-trip. 87 * 88 * This sort of a superset of skip_bit, which is testing for changing bits that 89 * aren't worth testing for fuzzing. We also just want to clear bits that 90 * become meaningless once fuzzing twiddles a related bit. 91 */ 92static void 93clear_pad_bits(const struct intel_device_info *devinfo, brw_inst *inst) 94{ 95 if (brw_inst_opcode(devinfo, inst) != BRW_OPCODE_SEND && 96 brw_inst_opcode(devinfo, inst) != BRW_OPCODE_SENDC && 97 brw_inst_src0_reg_file(devinfo, inst) != BRW_IMMEDIATE_VALUE && 98 brw_inst_src1_reg_file(devinfo, inst) != BRW_IMMEDIATE_VALUE) { 99 brw_inst_set_bits(inst, 127, 111, 0); 100 } 101 102 if (devinfo->ver == 8 && !devinfo->is_cherryview && 103 is_3src(devinfo, brw_inst_opcode(devinfo, inst))) { 104 brw_inst_set_bits(inst, 105, 105, 0); 105 brw_inst_set_bits(inst, 84, 84, 0); 106 brw_inst_set_bits(inst, 36, 35, 0); 107 } 108} 109 110static bool 111skip_bit(const struct intel_device_info *devinfo, brw_inst *src, int bit) 112{ 113 /* pad bit */ 114 if (bit == 7) 115 return true; 116 117 /* The compact bit -- uncompacted can't have it set. */ 118 if (bit == 29) 119 return true; 120 121 if (is_3src(devinfo, brw_inst_opcode(devinfo, src))) { 122 if (devinfo->ver >= 9 || devinfo->is_cherryview) { 123 if (bit == 127) 124 return true; 125 } else { 126 if (bit >= 126 && bit <= 127) 127 return true; 128 129 if (bit == 105) 130 return true; 131 132 if (bit == 84) 133 return true; 134 135 if (bit >= 35 && bit <= 36) 136 return true; 137 } 138 } else { 139 if (bit == 47) 140 return true; 141 142 if (devinfo->ver >= 8) { 143 if (bit == 11) 144 return true; 145 146 if (bit == 95) 147 return true; 148 } else { 149 if (devinfo->ver < 7 && bit == 90) 150 return true; 151 152 if (bit >= 91 && bit <= 95) 153 return true; 154 } 155 } 156 157 /* sometimes these are pad bits. */ 158 if (brw_inst_opcode(devinfo, src) != BRW_OPCODE_SEND && 159 brw_inst_opcode(devinfo, src) != BRW_OPCODE_SENDC && 160 brw_inst_src0_reg_file(devinfo, src) != BRW_IMMEDIATE_VALUE && 161 brw_inst_src1_reg_file(devinfo, src) != BRW_IMMEDIATE_VALUE && 162 bit >= 121) { 163 return true; 164 } 165 166 return false; 167} 168 169static bool 170test_fuzz_compact_instruction(struct brw_codegen *p, brw_inst src) 171{ 172 for (int bit0 = 0; bit0 < 128; bit0++) { 173 if (skip_bit(p->devinfo, &src, bit0)) 174 continue; 175 176 for (int bit1 = 0; bit1 < 128; bit1++) { 177 brw_inst instr = src; 178 uint64_t *bits = instr.data; 179 180 if (skip_bit(p->devinfo, &src, bit1)) 181 continue; 182 183 bits[bit0 / 64] ^= (1ull << (bit0 & 63)); 184 bits[bit1 / 64] ^= (1ull << (bit1 & 63)); 185 186 clear_pad_bits(p->devinfo, &instr); 187 188 if (!brw_validate_instruction(p->devinfo, &instr, 0, NULL)) 189 continue; 190 191 if (!test_compact_instruction(p, instr)) { 192 printf(" twiddled bits for fuzzing %d, %d\n", bit0, bit1); 193 return false; 194 } 195 } 196 } 197 198 return true; 199} 200 201class CompactTestFixture : public testing::TestWithParam<CompactParams> { 202protected: 203 virtual void SetUp() { 204 CompactParams params = GetParam(); 205 mem_ctx = ralloc_context(NULL); 206 devinfo = rzalloc(mem_ctx, intel_device_info); 207 p = rzalloc(mem_ctx, brw_codegen); 208 209 devinfo->verx10 = params.verx10; 210 devinfo->ver = devinfo->verx10 / 10; 211 212 brw_init_codegen(devinfo, p, p); 213 brw_set_default_predicate_control(p, BRW_PREDICATE_NONE); 214 brw_set_default_access_mode(p, params.align); 215 }; 216 217 virtual void TearDown() { 218 EXPECT_EQ(p->nr_insn, 1); 219 EXPECT_TRUE(test_compact_instruction(p, p->store[0])); 220 EXPECT_TRUE(test_fuzz_compact_instruction(p, p->store[0])); 221 222 ralloc_free(mem_ctx); 223 }; 224 225 void *mem_ctx; 226 intel_device_info *devinfo; 227 brw_codegen *p; 228}; 229 230class Instructions : public CompactTestFixture {}; 231 232INSTANTIATE_TEST_CASE_P( 233 CompactTest, 234 Instructions, 235 testing::Values( 236 CompactParams{ 50, BRW_ALIGN_1 }, CompactParams{ 50, BRW_ALIGN_16 }, 237 CompactParams{ 60, BRW_ALIGN_1 }, CompactParams{ 60, BRW_ALIGN_16 }, 238 CompactParams{ 70, BRW_ALIGN_1 }, CompactParams{ 70, BRW_ALIGN_16 }, 239 CompactParams{ 75, BRW_ALIGN_1 }, CompactParams{ 75, BRW_ALIGN_16 }, 240 CompactParams{ 80, BRW_ALIGN_1 }, CompactParams{ 80, BRW_ALIGN_16 }, 241 CompactParams{ 90, BRW_ALIGN_1 }, CompactParams{ 90, BRW_ALIGN_16 }, 242 CompactParams{ 110, BRW_ALIGN_1 }, 243 CompactParams{ 120, BRW_ALIGN_1 }, 244 CompactParams{ 125, BRW_ALIGN_1 } 245 ), 246 get_compact_params_name); 247 248class InstructionsBeforeIvyBridge : public CompactTestFixture {}; 249 250INSTANTIATE_TEST_CASE_P( 251 CompactTest, 252 InstructionsBeforeIvyBridge, 253 testing::Values( 254 CompactParams{ 50, BRW_ALIGN_1 }, CompactParams{ 50, BRW_ALIGN_16 }, 255 CompactParams{ 60, BRW_ALIGN_1 }, CompactParams{ 60, BRW_ALIGN_16 } 256 ), 257 get_compact_params_name); 258 259 260TEST_P(Instructions, ADD_GRF_GRF_GRF) 261{ 262 struct brw_reg g0 = brw_vec8_grf(0, 0); 263 struct brw_reg g2 = brw_vec8_grf(2, 0); 264 struct brw_reg g4 = brw_vec8_grf(4, 0); 265 266 brw_ADD(p, g0, g2, g4); 267} 268 269TEST_P(Instructions, ADD_GRF_GRF_IMM) 270{ 271 struct brw_reg g0 = brw_vec8_grf(0, 0); 272 struct brw_reg g2 = brw_vec8_grf(2, 0); 273 274 brw_ADD(p, g0, g2, brw_imm_f(1.0)); 275} 276 277TEST_P(Instructions, ADD_GRF_GRF_IMM_d) 278{ 279 struct brw_reg g0 = retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_D); 280 struct brw_reg g2 = retype(brw_vec8_grf(2, 0), BRW_REGISTER_TYPE_D); 281 282 brw_ADD(p, g0, g2, brw_imm_d(1)); 283} 284 285TEST_P(Instructions, MOV_GRF_GRF) 286{ 287 struct brw_reg g0 = brw_vec8_grf(0, 0); 288 struct brw_reg g2 = brw_vec8_grf(2, 0); 289 290 brw_MOV(p, g0, g2); 291} 292 293TEST_P(InstructionsBeforeIvyBridge, ADD_MRF_GRF_GRF) 294{ 295 struct brw_reg m6 = brw_vec8_reg(BRW_MESSAGE_REGISTER_FILE, 6, 0); 296 struct brw_reg g2 = brw_vec8_grf(2, 0); 297 struct brw_reg g4 = brw_vec8_grf(4, 0); 298 299 brw_ADD(p, m6, g2, g4); 300} 301 302TEST_P(Instructions, ADD_vec1_GRF_GRF_GRF) 303{ 304 struct brw_reg g0 = brw_vec1_grf(0, 0); 305 struct brw_reg g2 = brw_vec1_grf(2, 0); 306 struct brw_reg g4 = brw_vec1_grf(4, 0); 307 308 brw_ADD(p, g0, g2, g4); 309} 310 311TEST_P(InstructionsBeforeIvyBridge, PLN_MRF_GRF_GRF) 312{ 313 struct brw_reg m6 = brw_vec8_reg(BRW_MESSAGE_REGISTER_FILE, 6, 0); 314 struct brw_reg interp = brw_vec1_grf(2, 0); 315 struct brw_reg g4 = brw_vec8_grf(4, 0); 316 317 brw_PLN(p, m6, interp, g4); 318} 319 320TEST_P(Instructions, f0_0_MOV_GRF_GRF) 321{ 322 struct brw_reg g0 = brw_vec8_grf(0, 0); 323 struct brw_reg g2 = brw_vec8_grf(2, 0); 324 325 brw_push_insn_state(p); 326 brw_set_default_predicate_control(p, BRW_PREDICATE_NORMAL); 327 brw_MOV(p, g0, g2); 328 brw_pop_insn_state(p); 329} 330 331/* The handling of f0.1 vs f0.0 changes between gfx6 and gfx7. Explicitly test 332 * it, so that we run the fuzzing can run over all the other bits that might 333 * interact with it. 334 */ 335TEST_P(Instructions, f0_1_MOV_GRF_GRF) 336{ 337 struct brw_reg g0 = brw_vec8_grf(0, 0); 338 struct brw_reg g2 = brw_vec8_grf(2, 0); 339 340 brw_push_insn_state(p); 341 brw_set_default_predicate_control(p, BRW_PREDICATE_NORMAL); 342 brw_inst *mov = brw_MOV(p, g0, g2); 343 brw_inst_set_flag_subreg_nr(p->devinfo, mov, 1); 344 brw_pop_insn_state(p); 345} 346