OLD | NEW |
(Empty) | |
| 1 //===- subzero/src/IceInst.cpp - High-level instruction implementation ----===// |
| 2 // |
| 3 // The Subzero Code Generator |
| 4 // |
| 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. |
| 7 // |
| 8 //===----------------------------------------------------------------------===// |
| 9 // |
| 10 // This file implements the Inst class, primarily the various |
| 11 // subclass constructors and dump routines. |
| 12 // |
| 13 //===----------------------------------------------------------------------===// |
| 14 |
| 15 #include "IceCfg.h" |
| 16 #include "IceCfgNode.h" |
| 17 #include "IceInst.h" |
| 18 #include "IceOperand.h" |
| 19 |
| 20 namespace Ice { |
| 21 |
| 22 namespace { |
| 23 |
| 24 // Using non-anonymous struct so that array_lengthof works. |
| 25 const struct _InstArithmeticAttributes { |
| 26 const char *DisplayString; |
| 27 bool IsCommutative; |
| 28 } InstArithmeticAttributes[] = { |
| 29 #define X(tag, str, commutative) \ |
| 30 { str, commutative } \ |
| 31 , |
| 32 ICEINSTARITHMETIC_TABLE |
| 33 #undef X |
| 34 }; |
| 35 const size_t InstArithmeticAttributesSize = |
| 36 llvm::array_lengthof(InstArithmeticAttributes); |
| 37 |
| 38 // Using non-anonymous struct so that array_lengthof works. |
| 39 const struct _InstCastAttributes { |
| 40 const char *DisplayString; |
| 41 } InstCastAttributes[] = { |
| 42 #define X(tag, str) \ |
| 43 { str } \ |
| 44 , |
| 45 ICEINSTCAST_TABLE |
| 46 #undef X |
| 47 }; |
| 48 const size_t InstCastAttributesSize = llvm::array_lengthof(InstCastAttributes); |
| 49 |
| 50 // Using non-anonymous struct so that array_lengthof works. |
| 51 const struct _InstFcmpAttributes { |
| 52 const char *DisplayString; |
| 53 } InstFcmpAttributes[] = { |
| 54 #define X(tag, str) \ |
| 55 { str } \ |
| 56 , |
| 57 ICEINSTFCMP_TABLE |
| 58 #undef X |
| 59 }; |
| 60 const size_t InstFcmpAttributesSize = llvm::array_lengthof(InstFcmpAttributes); |
| 61 |
| 62 // Using non-anonymous struct so that array_lengthof works. |
| 63 const struct _InstIcmpAttributes { |
| 64 const char *DisplayString; |
| 65 } InstIcmpAttributes[] = { |
| 66 #define X(tag, str) \ |
| 67 { str } \ |
| 68 , |
| 69 ICEINSTICMP_TABLE |
| 70 #undef X |
| 71 }; |
| 72 const size_t InstIcmpAttributesSize = llvm::array_lengthof(InstIcmpAttributes); |
| 73 |
| 74 } // end of anonymous namespace |
| 75 |
| 76 Inst::Inst(Cfg *Func, InstKind Kind, SizeT MaxSrcs, Variable *Dest) |
| 77 : Kind(Kind), Number(Func->newInstNumber()), Deleted(false), |
| 78 HasSideEffects(false), Dest(Dest), MaxSrcs(MaxSrcs), NumSrcs(0), |
| 79 Srcs(Func->allocateArrayOf<Operand *>(MaxSrcs)) {} |
| 80 |
| 81 void Inst::updateVars(CfgNode *Node) { |
| 82 if (Dest) |
| 83 Dest->setDefinition(this, Node); |
| 84 |
| 85 SizeT VarIndex = 0; |
| 86 for (SizeT I = 0; I < getSrcSize(); ++I) { |
| 87 Operand *Src = getSrc(I); |
| 88 SizeT NumVars = Src->getNumVars(); |
| 89 for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) { |
| 90 Variable *Var = Src->getVar(J); |
| 91 Var->setUse(this, Node); |
| 92 } |
| 93 } |
| 94 } |
| 95 |
| 96 InstAlloca::InstAlloca(Cfg *Func, Operand *ByteCount, uint32_t AlignInBytes, |
| 97 Variable *Dest) |
| 98 : Inst(Func, Inst::Alloca, 1, Dest), AlignInBytes(AlignInBytes) { |
| 99 // Verify AlignInBytes is 0 or a power of 2. |
| 100 assert(AlignInBytes == 0 || llvm::isPowerOf2_32(AlignInBytes)); |
| 101 addSource(ByteCount); |
| 102 } |
| 103 |
| 104 InstArithmetic::InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest, |
| 105 Operand *Source1, Operand *Source2) |
| 106 : Inst(Func, Inst::Arithmetic, 2, Dest), Op(Op) { |
| 107 addSource(Source1); |
| 108 addSource(Source2); |
| 109 } |
| 110 |
| 111 bool InstArithmetic::isCommutative() const { |
| 112 return InstArithmeticAttributes[getOp()].IsCommutative; |
| 113 } |
| 114 |
| 115 InstAssign::InstAssign(Cfg *Func, Variable *Dest, Operand *Source) |
| 116 : Inst(Func, Inst::Assign, 1, Dest) { |
| 117 addSource(Source); |
| 118 } |
| 119 |
| 120 // If TargetTrue==TargetFalse, we turn it into an unconditional |
| 121 // branch. This ensures that, along with the 'switch' instruction |
| 122 // semantics, there is at most one edge from one node to another. |
| 123 InstBr::InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue, |
| 124 CfgNode *TargetFalse) |
| 125 : Inst(Func, Inst::Br, 1, NULL), TargetFalse(TargetFalse), |
| 126 TargetTrue(TargetTrue) { |
| 127 if (TargetTrue == TargetFalse) { |
| 128 TargetTrue = NULL; // turn into unconditional version |
| 129 } else { |
| 130 addSource(Source); |
| 131 } |
| 132 } |
| 133 |
| 134 InstBr::InstBr(Cfg *Func, CfgNode *Target) |
| 135 : Inst(Func, Inst::Br, 0, NULL), TargetFalse(Target), TargetTrue(NULL) {} |
| 136 |
| 137 NodeList InstBr::getTerminatorEdges() const { |
| 138 NodeList OutEdges; |
| 139 OutEdges.push_back(TargetFalse); |
| 140 if (TargetTrue) |
| 141 OutEdges.push_back(TargetTrue); |
| 142 return OutEdges; |
| 143 } |
| 144 |
| 145 InstCast::InstCast(Cfg *Func, OpKind CastKind, Variable *Dest, Operand *Source) |
| 146 : Inst(Func, Inst::Cast, 1, Dest), CastKind(CastKind) { |
| 147 addSource(Source); |
| 148 } |
| 149 |
| 150 InstFcmp::InstFcmp(Cfg *Func, FCond Condition, Variable *Dest, Operand *Source1, |
| 151 Operand *Source2) |
| 152 : Inst(Func, Inst::Fcmp, 2, Dest), Condition(Condition) { |
| 153 addSource(Source1); |
| 154 addSource(Source2); |
| 155 } |
| 156 |
| 157 InstIcmp::InstIcmp(Cfg *Func, ICond Condition, Variable *Dest, Operand *Source1, |
| 158 Operand *Source2) |
| 159 : Inst(Func, Inst::Icmp, 2, Dest), Condition(Condition) { |
| 160 addSource(Source1); |
| 161 addSource(Source2); |
| 162 } |
| 163 |
| 164 InstLoad::InstLoad(Cfg *Func, Variable *Dest, Operand *SourceAddr) |
| 165 : Inst(Func, Inst::Load, 1, Dest) { |
| 166 addSource(SourceAddr); |
| 167 } |
| 168 |
| 169 InstPhi::InstPhi(Cfg *Func, SizeT MaxSrcs, Variable *Dest) |
| 170 : Inst(Func, Phi, MaxSrcs, Dest) { |
| 171 Labels = Func->allocateArrayOf<CfgNode *>(MaxSrcs); |
| 172 } |
| 173 |
| 174 // TODO: A Switch instruction (and maybe others) can add duplicate |
| 175 // edges. We may want to de-dup Phis and validate consistency (i.e., |
| 176 // the source operands are the same for duplicate edges), though it |
| 177 // seems the current lowering code is OK with this situation. |
| 178 void InstPhi::addArgument(Operand *Source, CfgNode *Label) { |
| 179 Labels[getSrcSize()] = Label; |
| 180 addSource(Source); |
| 181 } |
| 182 |
| 183 InstRet::InstRet(Cfg *Func, Operand *RetValue) |
| 184 : Inst(Func, Ret, RetValue ? 1 : 0, NULL) { |
| 185 if (RetValue) |
| 186 addSource(RetValue); |
| 187 } |
| 188 |
| 189 InstSelect::InstSelect(Cfg *Func, Variable *Dest, Operand *Condition, |
| 190 Operand *SourceTrue, Operand *SourceFalse) |
| 191 : Inst(Func, Inst::Select, 3, Dest) { |
| 192 assert(Condition->getType() == IceType_i1); |
| 193 addSource(Condition); |
| 194 addSource(SourceTrue); |
| 195 addSource(SourceFalse); |
| 196 } |
| 197 |
| 198 InstStore::InstStore(Cfg *Func, Operand *Data, Operand *Addr) |
| 199 : Inst(Func, Inst::Store, 2, NULL) { |
| 200 addSource(Data); |
| 201 addSource(Addr); |
| 202 } |
| 203 |
| 204 InstSwitch::InstSwitch(Cfg *Func, SizeT NumCases, Operand *Source, |
| 205 CfgNode *LabelDefault) |
| 206 : Inst(Func, Inst::Switch, 1, NULL), LabelDefault(LabelDefault), |
| 207 NumCases(NumCases) { |
| 208 addSource(Source); |
| 209 Values = Func->allocateArrayOf<uint64_t>(NumCases); |
| 210 Labels = Func->allocateArrayOf<CfgNode *>(NumCases); |
| 211 // Initialize in case buggy code doesn't set all entries |
| 212 for (SizeT I = 0; I < NumCases; ++I) { |
| 213 Values[I] = 0; |
| 214 Labels[I] = NULL; |
| 215 } |
| 216 } |
| 217 |
| 218 void InstSwitch::addBranch(SizeT CaseIndex, uint64_t Value, CfgNode *Label) { |
| 219 assert(CaseIndex < NumCases); |
| 220 Values[CaseIndex] = Value; |
| 221 Labels[CaseIndex] = Label; |
| 222 } |
| 223 |
| 224 NodeList InstSwitch::getTerminatorEdges() const { |
| 225 NodeList OutEdges; |
| 226 OutEdges.push_back(LabelDefault); |
| 227 for (SizeT I = 0; I < NumCases; ++I) { |
| 228 OutEdges.push_back(Labels[I]); |
| 229 } |
| 230 return OutEdges; |
| 231 } |
| 232 |
| 233 InstUnreachable::InstUnreachable(Cfg *Func) |
| 234 : Inst(Func, Inst::Unreachable, 0, NULL) {} |
| 235 |
| 236 // ======================== Dump routines ======================== // |
| 237 |
| 238 void Inst::dumpDecorated(const Cfg *Func) const { |
| 239 Ostream &Str = Func->getContext()->getStrDump(); |
| 240 if (!Func->getContext()->isVerbose(IceV_Deleted) && isDeleted()) |
| 241 return; |
| 242 if (Func->getContext()->isVerbose(IceV_InstNumbers)) { |
| 243 char buf[30]; |
| 244 int32_t Number = getNumber(); |
| 245 if (Number < 0) |
| 246 snprintf(buf, llvm::array_lengthof(buf), "[XXX]"); |
| 247 else |
| 248 snprintf(buf, llvm::array_lengthof(buf), "[%3d]", Number); |
| 249 Str << buf; |
| 250 } |
| 251 Str << " "; |
| 252 if (isDeleted()) |
| 253 Str << " //"; |
| 254 dump(Func); |
| 255 Str << "\n"; |
| 256 } |
| 257 |
| 258 void Inst::dump(const Cfg *Func) const { |
| 259 Ostream &Str = Func->getContext()->getStrDump(); |
| 260 dumpDest(Func); |
| 261 Str << " =~ "; |
| 262 dumpSources(Func); |
| 263 } |
| 264 |
| 265 void Inst::dumpSources(const Cfg *Func) const { |
| 266 Ostream &Str = Func->getContext()->getStrDump(); |
| 267 for (SizeT I = 0; I < getSrcSize(); ++I) { |
| 268 if (I > 0) |
| 269 Str << ", "; |
| 270 getSrc(I)->dump(Func); |
| 271 } |
| 272 } |
| 273 |
| 274 void Inst::dumpDest(const Cfg *Func) const { |
| 275 if (getDest()) |
| 276 getDest()->dump(Func); |
| 277 } |
| 278 |
| 279 void InstAlloca::dump(const Cfg *Func) const { |
| 280 Ostream &Str = Func->getContext()->getStrDump(); |
| 281 dumpDest(Func); |
| 282 Str << " = alloca i8, i32 "; |
| 283 getSizeInBytes()->dump(Func); |
| 284 Str << ", align " << getAlignInBytes(); |
| 285 } |
| 286 |
| 287 void InstArithmetic::dump(const Cfg *Func) const { |
| 288 Ostream &Str = Func->getContext()->getStrDump(); |
| 289 dumpDest(Func); |
| 290 Str << " = " << InstArithmeticAttributes[getOp()].DisplayString << " " |
| 291 << getDest()->getType() << " "; |
| 292 dumpSources(Func); |
| 293 } |
| 294 |
| 295 void InstAssign::dump(const Cfg *Func) const { |
| 296 Ostream &Str = Func->getContext()->getStrDump(); |
| 297 dumpDest(Func); |
| 298 Str << " = " << getDest()->getType() << " "; |
| 299 dumpSources(Func); |
| 300 } |
| 301 |
| 302 void InstBr::dump(const Cfg *Func) const { |
| 303 Ostream &Str = Func->getContext()->getStrDump(); |
| 304 dumpDest(Func); |
| 305 Str << "br "; |
| 306 if (!isUnconditional()) { |
| 307 Str << "i1 "; |
| 308 getCondition()->dump(Func); |
| 309 Str << ", label %" << getTargetTrue()->getName() << ", "; |
| 310 } |
| 311 Str << "label %" << getTargetFalse()->getName(); |
| 312 } |
| 313 |
| 314 void InstCall::dump(const Cfg *Func) const { |
| 315 Ostream &Str = Func->getContext()->getStrDump(); |
| 316 if (getDest()) { |
| 317 dumpDest(Func); |
| 318 Str << " = "; |
| 319 } |
| 320 Str << "call "; |
| 321 if (getDest()) |
| 322 Str << getDest()->getType(); |
| 323 else |
| 324 Str << "void"; |
| 325 Str << " "; |
| 326 getCallTarget()->dump(Func); |
| 327 Str << "("; |
| 328 for (SizeT I = 0; I < getNumArgs(); ++I) { |
| 329 if (I > 0) |
| 330 Str << ", "; |
| 331 Str << getArg(I)->getType() << " "; |
| 332 getArg(I)->dump(Func); |
| 333 } |
| 334 Str << ")"; |
| 335 } |
| 336 |
| 337 void InstCast::dump(const Cfg *Func) const { |
| 338 Ostream &Str = Func->getContext()->getStrDump(); |
| 339 dumpDest(Func); |
| 340 Str << " = " << InstCastAttributes[getCastKind()].DisplayString << " " |
| 341 << getSrc(0)->getType() << " "; |
| 342 dumpSources(Func); |
| 343 Str << " to " << getDest()->getType(); |
| 344 } |
| 345 |
| 346 void InstIcmp::dump(const Cfg *Func) const { |
| 347 Ostream &Str = Func->getContext()->getStrDump(); |
| 348 dumpDest(Func); |
| 349 Str << " = icmp " << InstIcmpAttributes[getCondition()].DisplayString << " " |
| 350 << getSrc(0)->getType() << " "; |
| 351 dumpSources(Func); |
| 352 } |
| 353 |
| 354 void InstFcmp::dump(const Cfg *Func) const { |
| 355 Ostream &Str = Func->getContext()->getStrDump(); |
| 356 dumpDest(Func); |
| 357 Str << " = fcmp " << InstFcmpAttributes[getCondition()].DisplayString << " " |
| 358 << getSrc(0)->getType() << " "; |
| 359 dumpSources(Func); |
| 360 } |
| 361 |
| 362 void InstLoad::dump(const Cfg *Func) const { |
| 363 Ostream &Str = Func->getContext()->getStrDump(); |
| 364 dumpDest(Func); |
| 365 Type Ty = getDest()->getType(); |
| 366 Str << " = load " << Ty << "* "; |
| 367 dumpSources(Func); |
| 368 Str << ", align " << typeAlignInBytes(Ty); |
| 369 } |
| 370 |
| 371 void InstStore::dump(const Cfg *Func) const { |
| 372 Ostream &Str = Func->getContext()->getStrDump(); |
| 373 Type Ty = getData()->getType(); |
| 374 Str << "store " << Ty << " "; |
| 375 getData()->dump(Func); |
| 376 Str << ", " << Ty << "* "; |
| 377 getAddr()->dump(Func); |
| 378 Str << ", align " << typeAlignInBytes(Ty); |
| 379 } |
| 380 |
| 381 void InstSwitch::dump(const Cfg *Func) const { |
| 382 Ostream &Str = Func->getContext()->getStrDump(); |
| 383 Type Ty = getComparison()->getType(); |
| 384 Str << "switch " << Ty << " "; |
| 385 getSrc(0)->dump(Func); |
| 386 Str << ", label %" << getLabelDefault()->getName() << " [\n"; |
| 387 for (SizeT I = 0; I < getNumCases(); ++I) { |
| 388 Str << " " << Ty << " " << getValue(I) << ", label %" |
| 389 << getLabel(I)->getName() << "\n"; |
| 390 } |
| 391 Str << " ]"; |
| 392 } |
| 393 |
| 394 void InstPhi::dump(const Cfg *Func) const { |
| 395 Ostream &Str = Func->getContext()->getStrDump(); |
| 396 dumpDest(Func); |
| 397 Str << " = phi " << getDest()->getType() << " "; |
| 398 for (SizeT I = 0; I < getSrcSize(); ++I) { |
| 399 if (I > 0) |
| 400 Str << ", "; |
| 401 Str << "[ "; |
| 402 getSrc(I)->dump(Func); |
| 403 Str << ", %" << Labels[I]->getName() << " ]"; |
| 404 } |
| 405 } |
| 406 |
| 407 void InstRet::dump(const Cfg *Func) const { |
| 408 Ostream &Str = Func->getContext()->getStrDump(); |
| 409 Type Ty = hasRetValue() ? getSrc(0)->getType() : IceType_void; |
| 410 Str << "ret " << Ty; |
| 411 if (hasRetValue()) { |
| 412 Str << " "; |
| 413 dumpSources(Func); |
| 414 } |
| 415 } |
| 416 |
| 417 void InstSelect::dump(const Cfg *Func) const { |
| 418 Ostream &Str = Func->getContext()->getStrDump(); |
| 419 dumpDest(Func); |
| 420 Operand *Condition = getCondition(); |
| 421 Operand *TrueOp = getTrueOperand(); |
| 422 Operand *FalseOp = getFalseOperand(); |
| 423 Str << " = select " << Condition->getType() << " "; |
| 424 Condition->dump(Func); |
| 425 Str << ", " << TrueOp->getType() << " "; |
| 426 TrueOp->dump(Func); |
| 427 Str << ", " << FalseOp->getType() << " "; |
| 428 FalseOp->dump(Func); |
| 429 } |
| 430 |
| 431 void InstUnreachable::dump(const Cfg *Func) const { |
| 432 Ostream &Str = Func->getContext()->getStrDump(); |
| 433 Str << "unreachable"; |
| 434 } |
| 435 |
| 436 } // end of namespace Ice |
OLD | NEW |