operand.cc revision 11308:7d8836fd043d
1/* 2 * Copyright (c) 2012-2015 Advanced Micro Devices, Inc. 3 * All rights reserved. 4 * 5 * For use for simulation and test purposes only 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the copyright holder nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 * 33 * Author: Steve Reinhardt 34 */ 35 36#include "arch/hsail/operand.hh" 37 38using namespace Brig; 39 40bool 41BaseRegOperand::init(unsigned opOffset, const BrigObject *obj, 42 unsigned &maxRegIdx, char _regFileChar) 43{ 44 regFileChar = _regFileChar; 45 const BrigOperand *brigOp = obj->getOperand(opOffset); 46 47 if (brigOp->kind != BRIG_KIND_OPERAND_REGISTER) 48 return false; 49 50 const BrigOperandRegister *brigRegOp = (const BrigOperandRegister*)brigOp; 51 52 regIdx = brigRegOp->regNum; 53 54 DPRINTF(GPUReg, "Operand: regNum: %d, kind: %d\n", regIdx, 55 brigRegOp->regKind); 56 57 maxRegIdx = std::max(maxRegIdx, regIdx); 58 59 return true; 60} 61 62void 63ListOperand::init(unsigned opOffset, const BrigObject *obj) 64{ 65 const BrigOperand *brigOp = (const BrigOperand*)obj->getOperand(opOffset); 66 67 switch (brigOp->kind) { 68 case BRIG_KIND_OPERAND_CODE_LIST: 69 { 70 const BrigOperandCodeList *opList = 71 (const BrigOperandCodeList*)brigOp; 72 73 const Brig::BrigData *oprnd_data = 74 obj->getBrigBaseData(opList->elements); 75 76 // Note: for calls Dest list of operands could be size of 0. 77 elementCount = oprnd_data->byteCount / 4; 78 79 DPRINTF(GPUReg, "Operand Code List: # elements: %d\n", 80 elementCount); 81 82 for (int i = 0; i < elementCount; ++i) { 83 unsigned *data_offset = 84 (unsigned*)obj->getData(opList->elements + 4 * (i + 1)); 85 86 const BrigDirectiveVariable *p = 87 (const BrigDirectiveVariable*)obj-> 88 getCodeSectionEntry(*data_offset); 89 90 StorageElement *se = obj->currentCode->storageMap-> 91 findSymbol(BRIG_SEGMENT_ARG, p); 92 93 assert(se); 94 callArgs.push_back(se); 95 } 96 } 97 break; 98 default: 99 fatal("ListOperand: bad operand kind %d\n", brigOp->kind); 100 } 101} 102 103std::string 104ListOperand::disassemble() 105{ 106 std::string res_str(""); 107 108 for (auto it : callArgs) { 109 res_str += csprintf("%s ", it->name.c_str()); 110 } 111 112 return res_str; 113} 114 115void 116FunctionRefOperand::init(unsigned opOffset, const BrigObject *obj) 117{ 118 const BrigOperand *baseOp = obj->getOperand(opOffset); 119 120 if (baseOp->kind != BRIG_KIND_OPERAND_CODE_REF) { 121 fatal("FunctionRefOperand: bad operand kind %d\n", baseOp->kind); 122 } 123 124 const BrigOperandCodeRef *brigOp = (const BrigOperandCodeRef*)baseOp; 125 126 const BrigDirectiveExecutable *p = 127 (const BrigDirectiveExecutable*)obj->getCodeSectionEntry(brigOp->ref); 128 129 func_name = obj->getString(p->name); 130} 131 132std::string 133FunctionRefOperand::disassemble() 134{ 135 DPRINTF(GPUReg, "Operand Func-ref name: %s\n", func_name); 136 137 return csprintf("%s", func_name); 138} 139 140bool 141BaseRegOperand::init_from_vect(unsigned opOffset, const BrigObject *obj, 142 int at, unsigned &maxRegIdx, char _regFileChar) 143{ 144 regFileChar = _regFileChar; 145 const BrigOperand *brigOp = obj->getOperand(opOffset); 146 147 if (brigOp->kind != BRIG_KIND_OPERAND_OPERAND_LIST) 148 return false; 149 150 151 const Brig::BrigOperandOperandList *brigRegVecOp = 152 (const Brig::BrigOperandOperandList*)brigOp; 153 154 unsigned *data_offset = 155 (unsigned*)obj->getData(brigRegVecOp->elements + 4 * (at + 1)); 156 157 const BrigOperand *p = 158 (const BrigOperand*)obj->getOperand(*data_offset); 159 if (p->kind != BRIG_KIND_OPERAND_REGISTER) { 160 return false; 161 } 162 163 const BrigOperandRegister *brigRegOp =(const BrigOperandRegister*)p; 164 165 regIdx = brigRegOp->regNum; 166 167 DPRINTF(GPUReg, "Operand: regNum: %d, kind: %d \n", regIdx, 168 brigRegOp->regKind); 169 170 maxRegIdx = std::max(maxRegIdx, regIdx); 171 172 return true; 173} 174 175void 176BaseRegOperand::initWithStrOffset(unsigned strOffset, const BrigObject *obj, 177 unsigned &maxRegIdx, char _regFileChar) 178{ 179 const char *name = obj->getString(strOffset); 180 char *endptr; 181 regIdx = strtoul(name + 2, &endptr, 10); 182 183 if (name[0] != '$' || name[1] != _regFileChar) { 184 fatal("register operand parse error on \"%s\"\n", name); 185 } 186 187 maxRegIdx = std::max(maxRegIdx, regIdx); 188} 189 190unsigned SRegOperand::maxRegIdx; 191unsigned DRegOperand::maxRegIdx; 192unsigned CRegOperand::maxRegIdx; 193 194std::string 195SRegOperand::disassemble() 196{ 197 return csprintf("$s%d", regIdx); 198} 199 200std::string 201DRegOperand::disassemble() 202{ 203 return csprintf("$d%d", regIdx); 204} 205 206std::string 207CRegOperand::disassemble() 208{ 209 return csprintf("$c%d", regIdx); 210} 211 212BrigRegOperandInfo 213findRegDataType(unsigned opOffset, const BrigObject *obj) 214{ 215 const BrigOperand *baseOp = obj->getOperand(opOffset); 216 217 switch (baseOp->kind) { 218 case BRIG_KIND_OPERAND_REGISTER: 219 { 220 const BrigOperandRegister *op = (BrigOperandRegister*)baseOp; 221 222 return BrigRegOperandInfo((BrigKind16_t)baseOp->kind, 223 (BrigRegisterKind)op->regKind); 224 } 225 break; 226 227 case BRIG_KIND_OPERAND_OPERAND_LIST: 228 { 229 const BrigOperandOperandList *op = 230 (BrigOperandOperandList*)baseOp; 231 const BrigData *data_p = (BrigData*)obj->getData(op->elements); 232 233 234 int num_operands = 0; 235 BrigRegisterKind reg_kind = (BrigRegisterKind)0; 236 for (int offset = 0; offset < data_p->byteCount; offset += 4) { 237 const BrigOperand *op_p = (const BrigOperand *) 238 obj->getOperand(((int *)data_p->bytes)[offset/4]); 239 240 if (op_p->kind == BRIG_KIND_OPERAND_REGISTER) { 241 const BrigOperandRegister *brigRegOp = 242 (const BrigOperandRegister*)op_p; 243 reg_kind = (BrigRegisterKind)brigRegOp->regKind; 244 } else if (op_p->kind == BRIG_KIND_OPERAND_CONSTANT_BYTES) { 245 uint16_t num_bytes = 246 ((Brig::BrigOperandConstantBytes*)op_p)->base.byteCount 247 - sizeof(BrigBase); 248 if (num_bytes == sizeof(uint32_t)) { 249 reg_kind = BRIG_REGISTER_KIND_SINGLE; 250 } else if (num_bytes == sizeof(uint64_t)) { 251 reg_kind = BRIG_REGISTER_KIND_DOUBLE; 252 } else { 253 fatal("OperandList: bad operand size %d\n", num_bytes); 254 } 255 } else { 256 fatal("OperandList: bad operand kind %d\n", op_p->kind); 257 } 258 259 num_operands++; 260 } 261 assert(baseOp->kind == BRIG_KIND_OPERAND_OPERAND_LIST); 262 263 return BrigRegOperandInfo((BrigKind16_t)baseOp->kind, reg_kind); 264 } 265 break; 266 267 case BRIG_KIND_OPERAND_ADDRESS: 268 { 269 const BrigOperandAddress *op = (BrigOperandAddress*)baseOp; 270 271 if (!op->reg) { 272 BrigType type = BRIG_TYPE_NONE; 273 274 if (op->symbol) { 275 const BrigDirective *dir = (BrigDirective*) 276 obj->getCodeSectionEntry(op->symbol); 277 278 assert(dir->kind == BRIG_KIND_DIRECTIVE_VARIABLE); 279 280 const BrigDirectiveVariable *sym = 281 (const BrigDirectiveVariable*)dir; 282 283 type = (BrigType)sym->type; 284 } 285 return BrigRegOperandInfo(BRIG_KIND_OPERAND_ADDRESS, 286 (BrigType)type); 287 } else { 288 const BrigOperandAddress *b = (const BrigOperandAddress*)baseOp; 289 const BrigOperand *reg = obj->getOperand(b->reg); 290 const BrigOperandRegister *rop = (BrigOperandRegister*)reg; 291 292 return BrigRegOperandInfo(BRIG_KIND_OPERAND_REGISTER, 293 (BrigRegisterKind)rop->regKind); 294 } 295 } 296 break; 297 298 default: 299 fatal("AddrOperand: bad operand kind %d\n", baseOp->kind); 300 break; 301 } 302} 303 304void 305AddrOperandBase::parseAddr(const BrigOperandAddress *op, const BrigObject *obj) 306{ 307 assert(op->base.kind == BRIG_KIND_OPERAND_ADDRESS); 308 309 const BrigDirective *d = 310 (BrigDirective*)obj->getCodeSectionEntry(op->symbol); 311 312 assert(d->kind == BRIG_KIND_DIRECTIVE_VARIABLE); 313 const BrigDirectiveVariable *sym = (BrigDirectiveVariable*)d; 314 name = obj->getString(sym->name); 315 316 if (sym->segment != BRIG_SEGMENT_ARG) { 317 storageElement = 318 obj->currentCode->storageMap->findSymbol(sym->segment, name); 319 assert(storageElement); 320 offset = 0; 321 } else { 322 // sym->name does not work for BRIG_SEGMENT_ARG for the following case: 323 // 324 // void foo(int a); 325 // void bar(double a); 326 // 327 // foo(...) --> arg_u32 %param_p0; 328 // st_arg_u32 $s0, [%param_p0]; 329 // call &foo (%param_p0); 330 // bar(...) --> arg_f64 %param_p0; 331 // st_arg_u64 $d0, [%param_p0]; 332 // call &foo (%param_p0); 333 // 334 // Both functions use the same variable name (param_p0)!!! 335 // 336 // Maybe this is a bug in the compiler (I don't know). 337 // 338 // Solution: 339 // Use directive pointer (BrigDirectiveVariable) to differentiate 2 340 // versions of param_p0. 341 // 342 // Note this solution is kind of stupid, because we are pulling stuff 343 // out of the brig binary via the directive pointer and putting it into 344 // the symbol table, but now we are indexing the symbol table by the 345 // brig directive pointer! It makes the symbol table sort of pointless. 346 // But I don't want to mess with the rest of the infrastructure, so 347 // let's go with this for now. 348 // 349 // When we update the compiler again, we should see if this problem goes 350 // away. If so, we can fold some of this functionality into the code for 351 // kernel arguments. If not, maybe we can index the symbol name on a 352 // hash of the variable AND function name 353 storageElement = obj->currentCode-> 354 storageMap->findSymbol((Brig::BrigSegment)sym->segment, sym); 355 356 assert(storageElement); 357 } 358} 359 360uint64_t 361AddrOperandBase::calcUniformBase() 362{ 363 // start with offset, will be 0 if not specified 364 uint64_t address = offset; 365 366 // add in symbol value if specified 367 if (storageElement) { 368 address += storageElement->offset; 369 } 370 371 return address; 372} 373 374std::string 375AddrOperandBase::disassemble(std::string reg_disassembly) 376{ 377 std::string disasm; 378 379 if (offset || reg_disassembly != "") { 380 disasm += "["; 381 382 if (reg_disassembly != "") { 383 disasm += reg_disassembly; 384 385 if (offset > 0) { 386 disasm += "+"; 387 } 388 } 389 390 if (offset) { 391 disasm += csprintf("%d", offset); 392 } 393 394 disasm += "]"; 395 } else if (name) { 396 disasm += csprintf("[%s]", name); 397 } 398 399 return disasm; 400} 401 402void 403NoRegAddrOperand::init(unsigned opOffset, const BrigObject *obj) 404{ 405 const BrigOperand *baseOp = obj->getOperand(opOffset); 406 407 if (baseOp->kind == BRIG_KIND_OPERAND_ADDRESS) { 408 BrigOperandAddress *addrOp = (BrigOperandAddress*)baseOp; 409 parseAddr(addrOp, obj); 410 offset = (uint64_t(addrOp->offset.hi) << 32) | 411 uint64_t(addrOp->offset.lo); 412 } else { 413 fatal("NoRegAddrOperand: bad operand kind %d\n", baseOp->kind); 414 } 415 416} 417 418std::string 419NoRegAddrOperand::disassemble() 420{ 421 return AddrOperandBase::disassemble(std::string("")); 422} 423 424void 425LabelOperand::init(unsigned opOffset, const BrigObject *obj) 426{ 427 const BrigOperandCodeRef *op = 428 (const BrigOperandCodeRef*)obj->getOperand(opOffset); 429 430 assert(op->base.kind == BRIG_KIND_OPERAND_CODE_REF); 431 432 const BrigDirective *dir = 433 (const BrigDirective*)obj->getCodeSectionEntry(op->ref); 434 435 assert(dir->kind == BRIG_KIND_DIRECTIVE_LABEL); 436 label = obj->currentCode->refLabel((BrigDirectiveLabel*)dir, obj); 437} 438 439uint32_t 440LabelOperand::getTarget(Wavefront *w, int lane) 441{ 442 return label->get(); 443} 444 445std::string 446LabelOperand::disassemble() 447{ 448 return label->name; 449} 450