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->isa, &dst, &src)) { 63 brw_inst uncompacted; 64 65 brw_uncompact_instruction(p->isa, &uncompacted, &dst); 66 if (memcmp(&uncompacted, &src, sizeof(src))) { 67 brw_debug_compact_uncompact(p->isa, &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->isa, &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 brw_isa_info *isa, brw_inst *inst) 94{ 95 const struct intel_device_info *devinfo = isa->devinfo; 96 97 if (brw_inst_opcode(isa, inst) != BRW_OPCODE_SEND && 98 brw_inst_opcode(isa, inst) != BRW_OPCODE_SENDC && 99 brw_inst_src0_reg_file(devinfo, inst) != BRW_IMMEDIATE_VALUE && 100 brw_inst_src1_reg_file(devinfo, inst) != BRW_IMMEDIATE_VALUE) { 101 brw_inst_set_bits(inst, 127, 111, 0); 102 } 103 104 if (devinfo->ver == 8 && devinfo->platform != INTEL_PLATFORM_CHV && 105 is_3src(isa, brw_inst_opcode(isa, inst))) { 106 brw_inst_set_bits(inst, 105, 105, 0); 107 brw_inst_set_bits(inst, 84, 84, 0); 108 brw_inst_set_bits(inst, 36, 35, 0); 109 } 110} 111 112static bool 113skip_bit(const struct brw_isa_info *isa, brw_inst *src, int bit) 114{ 115 const struct intel_device_info *devinfo = isa->devinfo; 116 117 /* pad bit */ 118 if (bit == 7) 119 return true; 120 121 /* The compact bit -- uncompacted can't have it set. */ 122 if (bit == 29) 123 return true; 124 125 if (is_3src(isa, brw_inst_opcode(isa, src))) { 126 if (devinfo->ver >= 9 || devinfo->platform == INTEL_PLATFORM_CHV) { 127 if (bit == 127) 128 return true; 129 } else { 130 if (bit >= 126 && bit <= 127) 131 return true; 132 133 if (bit == 105) 134 return true; 135 136 if (bit == 84) 137 return true; 138 139 if (bit >= 35 && bit <= 36) 140 return true; 141 } 142 } else { 143 if (bit == 47) 144 return true; 145 146 if (devinfo->ver >= 8) { 147 if (bit == 11) 148 return true; 149 150 if (bit == 95) 151 return true; 152 } else { 153 if (devinfo->ver < 7 && bit == 90) 154 return true; 155 156 if (bit >= 91 && bit <= 95) 157 return true; 158 } 159 } 160 161 /* sometimes these are pad bits. */ 162 if (brw_inst_opcode(isa, src) != BRW_OPCODE_SEND && 163 brw_inst_opcode(isa, src) != BRW_OPCODE_SENDC && 164 brw_inst_src0_reg_file(devinfo, src) != BRW_IMMEDIATE_VALUE && 165 brw_inst_src1_reg_file(devinfo, src) != BRW_IMMEDIATE_VALUE && 166 bit >= 121) { 167 return true; 168 } 169 170 return false; 171} 172 173static bool 174test_fuzz_compact_instruction(struct brw_codegen *p, brw_inst src) 175{ 176 for (int bit0 = 0; bit0 < 128; bit0++) { 177 if (skip_bit(p->isa, &src, bit0)) 178 continue; 179 180 for (int bit1 = 0; bit1 < 128; bit1++) { 181 brw_inst instr = src; 182 uint64_t *bits = instr.data; 183 184 if (skip_bit(p->isa, &src, bit1)) 185 continue; 186 187 bits[bit0 / 64] ^= (1ull << (bit0 & 63)); 188 bits[bit1 / 64] ^= (1ull << (bit1 & 63)); 189 190 clear_pad_bits(p->isa, &instr); 191 192 if (!brw_validate_instruction(p->isa, &instr, 0, sizeof(brw_inst), NULL)) 193 continue; 194 195 if (!test_compact_instruction(p, instr)) { 196 printf(" twiddled bits for fuzzing %d, %d\n", bit0, bit1); 197 return false; 198 } 199 } 200 } 201 202 return true; 203} 204 205class CompactTestFixture : public testing::TestWithParam<CompactParams> { 206protected: 207 virtual void SetUp() { 208 CompactParams params = GetParam(); 209 mem_ctx = ralloc_context(NULL); 210 devinfo = rzalloc(mem_ctx, intel_device_info); 211 p = rzalloc(mem_ctx, brw_codegen); 212 213 devinfo->verx10 = params.verx10; 214 devinfo->ver = devinfo->verx10 / 10; 215 216 brw_init_isa_info(&isa, devinfo); 217 brw_init_codegen(&isa, p, p); 218 brw_set_default_predicate_control(p, BRW_PREDICATE_NONE); 219 brw_set_default_access_mode(p, params.align); 220 }; 221 222 virtual void TearDown() { 223 EXPECT_EQ(p->nr_insn, 1); 224 EXPECT_TRUE(test_compact_instruction(p, p->store[0])); 225 EXPECT_TRUE(test_fuzz_compact_instruction(p, p->store[0])); 226 227 ralloc_free(mem_ctx); 228 }; 229 230 void *mem_ctx; 231 struct brw_isa_info isa; 232 intel_device_info *devinfo; 233 brw_codegen *p; 234}; 235 236class Instructions : public CompactTestFixture {}; 237 238INSTANTIATE_TEST_CASE_P( 239 CompactTest, 240 Instructions, 241 testing::Values( 242 CompactParams{ 50, BRW_ALIGN_1 }, CompactParams{ 50, BRW_ALIGN_16 }, 243 CompactParams{ 60, BRW_ALIGN_1 }, CompactParams{ 60, BRW_ALIGN_16 }, 244 CompactParams{ 70, BRW_ALIGN_1 }, CompactParams{ 70, BRW_ALIGN_16 }, 245 CompactParams{ 75, BRW_ALIGN_1 }, CompactParams{ 75, BRW_ALIGN_16 }, 246 CompactParams{ 80, BRW_ALIGN_1 }, CompactParams{ 80, BRW_ALIGN_16 }, 247 CompactParams{ 90, BRW_ALIGN_1 }, CompactParams{ 90, BRW_ALIGN_16 }, 248 CompactParams{ 110, BRW_ALIGN_1 }, 249 CompactParams{ 120, BRW_ALIGN_1 }, 250 CompactParams{ 125, BRW_ALIGN_1 } 251 ), 252 get_compact_params_name); 253 254class InstructionsBeforeIvyBridge : public CompactTestFixture {}; 255 256INSTANTIATE_TEST_CASE_P( 257 CompactTest, 258 InstructionsBeforeIvyBridge, 259 testing::Values( 260 CompactParams{ 50, BRW_ALIGN_1 }, CompactParams{ 50, BRW_ALIGN_16 }, 261 CompactParams{ 60, BRW_ALIGN_1 }, CompactParams{ 60, BRW_ALIGN_16 } 262 ), 263 get_compact_params_name); 264 265 266TEST_P(Instructions, ADD_GRF_GRF_GRF) 267{ 268 struct brw_reg g0 = brw_vec8_grf(0, 0); 269 struct brw_reg g2 = brw_vec8_grf(2, 0); 270 struct brw_reg g4 = brw_vec8_grf(4, 0); 271 272 brw_ADD(p, g0, g2, g4); 273} 274 275TEST_P(Instructions, ADD_GRF_GRF_IMM) 276{ 277 struct brw_reg g0 = brw_vec8_grf(0, 0); 278 struct brw_reg g2 = brw_vec8_grf(2, 0); 279 280 brw_ADD(p, g0, g2, brw_imm_f(1.0)); 281} 282 283TEST_P(Instructions, ADD_GRF_GRF_IMM_d) 284{ 285 struct brw_reg g0 = retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_D); 286 struct brw_reg g2 = retype(brw_vec8_grf(2, 0), BRW_REGISTER_TYPE_D); 287 288 brw_ADD(p, g0, g2, brw_imm_d(1)); 289} 290 291TEST_P(Instructions, MOV_GRF_GRF) 292{ 293 struct brw_reg g0 = brw_vec8_grf(0, 0); 294 struct brw_reg g2 = brw_vec8_grf(2, 0); 295 296 brw_MOV(p, g0, g2); 297} 298 299TEST_P(InstructionsBeforeIvyBridge, ADD_MRF_GRF_GRF) 300{ 301 struct brw_reg m6 = brw_vec8_reg(BRW_MESSAGE_REGISTER_FILE, 6, 0); 302 struct brw_reg g2 = brw_vec8_grf(2, 0); 303 struct brw_reg g4 = brw_vec8_grf(4, 0); 304 305 brw_ADD(p, m6, g2, g4); 306} 307 308TEST_P(Instructions, ADD_vec1_GRF_GRF_GRF) 309{ 310 struct brw_reg g0 = brw_vec1_grf(0, 0); 311 struct brw_reg g2 = brw_vec1_grf(2, 0); 312 struct brw_reg g4 = brw_vec1_grf(4, 0); 313 314 brw_ADD(p, g0, g2, g4); 315} 316 317TEST_P(InstructionsBeforeIvyBridge, PLN_MRF_GRF_GRF) 318{ 319 struct brw_reg m6 = brw_vec8_reg(BRW_MESSAGE_REGISTER_FILE, 6, 0); 320 struct brw_reg interp = brw_vec1_grf(2, 0); 321 struct brw_reg g4 = brw_vec8_grf(4, 0); 322 323 brw_PLN(p, m6, interp, g4); 324} 325 326TEST_P(Instructions, f0_0_MOV_GRF_GRF) 327{ 328 struct brw_reg g0 = brw_vec8_grf(0, 0); 329 struct brw_reg g2 = brw_vec8_grf(2, 0); 330 331 brw_push_insn_state(p); 332 brw_set_default_predicate_control(p, BRW_PREDICATE_NORMAL); 333 brw_MOV(p, g0, g2); 334 brw_pop_insn_state(p); 335} 336 337/* The handling of f0.1 vs f0.0 changes between gfx6 and gfx7. Explicitly test 338 * it, so that we run the fuzzing can run over all the other bits that might 339 * interact with it. 340 */ 341TEST_P(Instructions, f0_1_MOV_GRF_GRF) 342{ 343 struct brw_reg g0 = brw_vec8_grf(0, 0); 344 struct brw_reg g2 = brw_vec8_grf(2, 0); 345 346 brw_push_insn_state(p); 347 brw_set_default_predicate_control(p, BRW_PREDICATE_NORMAL); 348 brw_inst *mov = brw_MOV(p, g0, g2); 349 brw_inst_set_flag_subreg_nr(p->devinfo, mov, 1); 350 brw_pop_insn_state(p); 351} 352