Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 1 | //===- subzero/src/IceInstARM32.cpp - ARM32 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 | //===----------------------------------------------------------------------===// |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 9 | /// |
| 10 | /// \file |
| 11 | /// This file implements the InstARM32 and OperandARM32 classes, |
| 12 | /// primarily the constructors and the dump()/emit() methods. |
| 13 | /// |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 14 | //===----------------------------------------------------------------------===// |
| 15 | |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 16 | #include "IceInstARM32.h" |
| 17 | |
John Porto | aff4ccf | 2015-06-10 16:35:06 -0700 | [diff] [blame] | 18 | #include "IceAssemblerARM32.h" |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 19 | #include "IceCfg.h" |
| 20 | #include "IceCfgNode.h" |
| 21 | #include "IceInst.h" |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 22 | #include "IceOperand.h" |
| 23 | #include "IceRegistersARM32.h" |
| 24 | #include "IceTargetLoweringARM32.h" |
| 25 | |
| 26 | namespace Ice { |
| 27 | |
| 28 | namespace { |
| 29 | |
| 30 | const struct TypeARM32Attributes_ { |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 31 | const char *WidthString; // b, h, <blank>, or d |
| 32 | const char *VecWidthString; // i8, i16, i32, f32, f64 |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 33 | int8_t SExtAddrOffsetBits; |
| 34 | int8_t ZExtAddrOffsetBits; |
| 35 | } TypeARM32Attributes[] = { |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 36 | #define X(tag, elementty, int_width, vec_width, sbits, ubits) \ |
| 37 | { int_width, vec_width, sbits, ubits } \ |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 38 | , |
| 39 | ICETYPEARM32_TABLE |
| 40 | #undef X |
| 41 | }; |
| 42 | |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 43 | const struct InstARM32ShiftAttributes_ { |
| 44 | const char *EmitString; |
| 45 | } InstARM32ShiftAttributes[] = { |
| 46 | #define X(tag, emit) \ |
| 47 | { emit } \ |
| 48 | , |
| 49 | ICEINSTARM32SHIFT_TABLE |
| 50 | #undef X |
| 51 | }; |
| 52 | |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 53 | const struct InstARM32CondAttributes_ { |
| 54 | CondARM32::Cond Opposite; |
| 55 | const char *EmitString; |
| 56 | } InstARM32CondAttributes[] = { |
| 57 | #define X(tag, encode, opp, emit) \ |
| 58 | { CondARM32::opp, emit } \ |
| 59 | , |
| 60 | ICEINSTARM32COND_TABLE |
| 61 | #undef X |
| 62 | }; |
| 63 | |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 64 | } // end of anonymous namespace |
| 65 | |
| 66 | const char *InstARM32::getWidthString(Type Ty) { |
| 67 | return TypeARM32Attributes[Ty].WidthString; |
| 68 | } |
| 69 | |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 70 | const char *InstARM32::getVecWidthString(Type Ty) { |
| 71 | return TypeARM32Attributes[Ty].VecWidthString; |
| 72 | } |
| 73 | |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 74 | const char *InstARM32Pred::predString(CondARM32::Cond Pred) { |
| 75 | return InstARM32CondAttributes[Pred].EmitString; |
| 76 | } |
| 77 | |
| 78 | void InstARM32Pred::dumpOpcodePred(Ostream &Str, const char *Opcode, |
| 79 | Type Ty) const { |
| 80 | Str << Opcode << getPredicate() << "." << Ty; |
| 81 | } |
| 82 | |
| 83 | CondARM32::Cond InstARM32::getOppositeCondition(CondARM32::Cond Cond) { |
| 84 | return InstARM32CondAttributes[Cond].Opposite; |
| 85 | } |
| 86 | |
Jan Voung | 66c3d5e | 2015-06-04 17:02:31 -0700 | [diff] [blame] | 87 | void InstARM32Pred::emitUnaryopGPR(const char *Opcode, |
Jan Voung | f645d85 | 2015-07-09 10:35:09 -0700 | [diff] [blame] | 88 | const InstARM32Pred *Inst, const Cfg *Func, |
| 89 | bool NeedsWidthSuffix) { |
Jan Voung | 66c3d5e | 2015-06-04 17:02:31 -0700 | [diff] [blame] | 90 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 91 | assert(Inst->getSrcSize() == 1); |
| 92 | Type SrcTy = Inst->getSrc(0)->getType(); |
Jan Voung | 66c3d5e | 2015-06-04 17:02:31 -0700 | [diff] [blame] | 93 | Str << "\t" << Opcode; |
Jan Voung | f645d85 | 2015-07-09 10:35:09 -0700 | [diff] [blame] | 94 | if (NeedsWidthSuffix) |
Jan Voung | 66c3d5e | 2015-06-04 17:02:31 -0700 | [diff] [blame] | 95 | Str << getWidthString(SrcTy); |
Jan Voung | f645d85 | 2015-07-09 10:35:09 -0700 | [diff] [blame] | 96 | Str << Inst->getPredicate() << "\t"; |
Jan Voung | 66c3d5e | 2015-06-04 17:02:31 -0700 | [diff] [blame] | 97 | Inst->getDest()->emit(Func); |
| 98 | Str << ", "; |
| 99 | Inst->getSrc(0)->emit(Func); |
| 100 | } |
| 101 | |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 102 | void InstARM32Pred::emitUnaryopFP(const char *Opcode, const InstARM32Pred *Inst, |
| 103 | const Cfg *Func) { |
| 104 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 105 | assert(Inst->getSrcSize() == 1); |
| 106 | Type SrcTy = Inst->getSrc(0)->getType(); |
| 107 | Str << "\t" << Opcode << Inst->getPredicate() << getVecWidthString(SrcTy) |
| 108 | << "\t"; |
| 109 | Inst->getDest()->emit(Func); |
| 110 | Str << ", "; |
| 111 | Inst->getSrc(0)->emit(Func); |
| 112 | } |
| 113 | |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 114 | void InstARM32Pred::emitTwoAddr(const char *Opcode, const InstARM32Pred *Inst, |
| 115 | const Cfg *Func) { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 116 | if (!BuildDefs::dump()) |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 117 | return; |
| 118 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 119 | assert(Inst->getSrcSize() == 2); |
| 120 | Variable *Dest = Inst->getDest(); |
| 121 | assert(Dest == Inst->getSrc(0)); |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 122 | Str << "\t" << Opcode << Inst->getPredicate() << "\t"; |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 123 | Dest->emit(Func); |
| 124 | Str << ", "; |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 125 | Inst->getSrc(1)->emit(Func); |
| 126 | } |
| 127 | |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 128 | void InstARM32Pred::emitThreeAddr(const char *Opcode, const InstARM32Pred *Inst, |
| 129 | const Cfg *Func, bool SetFlags) { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 130 | if (!BuildDefs::dump()) |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 131 | return; |
| 132 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 133 | assert(Inst->getSrcSize() == 2); |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 134 | Str << "\t" << Opcode << (SetFlags ? "s" : "") << Inst->getPredicate() |
| 135 | << "\t"; |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 136 | Inst->getDest()->emit(Func); |
| 137 | Str << ", "; |
| 138 | Inst->getSrc(0)->emit(Func); |
| 139 | Str << ", "; |
| 140 | Inst->getSrc(1)->emit(Func); |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 141 | } |
| 142 | |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 143 | void InstARM32::emitThreeAddrFP(const char *Opcode, const InstARM32 *Inst, |
| 144 | const Cfg *Func) { |
| 145 | if (!BuildDefs::dump()) |
| 146 | return; |
| 147 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 148 | assert(Inst->getSrcSize() == 2); |
| 149 | Str << "\t" << Opcode << getVecWidthString(Inst->getDest()->getType()) |
| 150 | << "\t"; |
| 151 | Inst->getDest()->emit(Func); |
| 152 | Str << ", "; |
| 153 | Inst->getSrc(0)->emit(Func); |
| 154 | Str << ", "; |
| 155 | Inst->getSrc(1)->emit(Func); |
| 156 | } |
| 157 | |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 158 | void InstARM32Pred::emitFourAddr(const char *Opcode, const InstARM32Pred *Inst, |
| 159 | const Cfg *Func) { |
| 160 | if (!BuildDefs::dump()) |
| 161 | return; |
| 162 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 163 | assert(Inst->getSrcSize() == 3); |
| 164 | Str << "\t" << Opcode << Inst->getPredicate() << "\t"; |
| 165 | Inst->getDest()->emit(Func); |
| 166 | Str << ", "; |
| 167 | Inst->getSrc(0)->emit(Func); |
| 168 | Str << ", "; |
| 169 | Inst->getSrc(1)->emit(Func); |
| 170 | Str << ", "; |
| 171 | Inst->getSrc(2)->emit(Func); |
| 172 | } |
| 173 | |
| 174 | void InstARM32Pred::emitCmpLike(const char *Opcode, const InstARM32Pred *Inst, |
| 175 | const Cfg *Func) { |
| 176 | if (!BuildDefs::dump()) |
| 177 | return; |
| 178 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 179 | assert(Inst->getSrcSize() == 2); |
| 180 | Str << "\t" << Opcode << Inst->getPredicate() << "\t"; |
| 181 | Inst->getSrc(0)->emit(Func); |
| 182 | Str << ", "; |
| 183 | Inst->getSrc(1)->emit(Func); |
| 184 | } |
| 185 | |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 186 | OperandARM32Mem::OperandARM32Mem(Cfg * /* Func */, Type Ty, Variable *Base, |
| 187 | ConstantInteger32 *ImmOffset, AddrMode Mode) |
| 188 | : OperandARM32(kMem, Ty), Base(Base), ImmOffset(ImmOffset), Index(nullptr), |
| 189 | ShiftOp(kNoShift), ShiftAmt(0), Mode(Mode) { |
| 190 | // The Neg modes are only needed for Reg +/- Reg. |
| 191 | assert(!isNegAddrMode()); |
| 192 | NumVars = 1; |
| 193 | Vars = &this->Base; |
| 194 | } |
| 195 | |
| 196 | OperandARM32Mem::OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, |
| 197 | Variable *Index, ShiftKind ShiftOp, |
| 198 | uint16_t ShiftAmt, AddrMode Mode) |
| 199 | : OperandARM32(kMem, Ty), Base(Base), ImmOffset(0), Index(Index), |
| 200 | ShiftOp(ShiftOp), ShiftAmt(ShiftAmt), Mode(Mode) { |
| 201 | NumVars = 2; |
| 202 | Vars = Func->allocateArrayOf<Variable *>(2); |
| 203 | Vars[0] = Base; |
| 204 | Vars[1] = Index; |
| 205 | } |
| 206 | |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 207 | bool OperandARM32Mem::canHoldOffset(Type Ty, bool SignExt, int32_t Offset) { |
| 208 | int32_t Bits = SignExt ? TypeARM32Attributes[Ty].SExtAddrOffsetBits |
| 209 | : TypeARM32Attributes[Ty].ZExtAddrOffsetBits; |
| 210 | if (Bits == 0) |
| 211 | return Offset == 0; |
| 212 | // Note that encodings for offsets are sign-magnitude for ARM, so we check |
| 213 | // with IsAbsoluteUint(). |
| 214 | if (isScalarFloatingType(Ty)) |
| 215 | return Utils::IsAligned(Offset, 4) && Utils::IsAbsoluteUint(Bits, Offset); |
| 216 | return Utils::IsAbsoluteUint(Bits, Offset); |
| 217 | } |
| 218 | |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 219 | OperandARM32FlexImm::OperandARM32FlexImm(Cfg * /* Func */, Type Ty, |
| 220 | uint32_t Imm, uint32_t RotateAmt) |
| 221 | : OperandARM32Flex(kFlexImm, Ty), Imm(Imm), RotateAmt(RotateAmt) { |
| 222 | NumVars = 0; |
| 223 | Vars = nullptr; |
| 224 | } |
| 225 | |
| 226 | bool OperandARM32FlexImm::canHoldImm(uint32_t Immediate, uint32_t *RotateAmt, |
| 227 | uint32_t *Immed_8) { |
| 228 | // Avoid the more expensive test for frequent small immediate values. |
| 229 | if (Immediate <= 0xFF) { |
| 230 | *RotateAmt = 0; |
| 231 | *Immed_8 = Immediate; |
| 232 | return true; |
| 233 | } |
| 234 | // Note that immediate must be unsigned for the test to work correctly. |
| 235 | for (int Rot = 1; Rot < 16; Rot++) { |
| 236 | uint32_t Imm8 = Utils::rotateLeft32(Immediate, 2 * Rot); |
| 237 | if (Imm8 <= 0xFF) { |
| 238 | *RotateAmt = Rot; |
| 239 | *Immed_8 = Imm8; |
| 240 | return true; |
| 241 | } |
| 242 | } |
| 243 | return false; |
| 244 | } |
| 245 | |
| 246 | OperandARM32FlexReg::OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, |
| 247 | ShiftKind ShiftOp, Operand *ShiftAmt) |
| 248 | : OperandARM32Flex(kFlexReg, Ty), Reg(Reg), ShiftOp(ShiftOp), |
| 249 | ShiftAmt(ShiftAmt) { |
| 250 | NumVars = 1; |
| 251 | Variable *ShiftVar = llvm::dyn_cast_or_null<Variable>(ShiftAmt); |
| 252 | if (ShiftVar) |
| 253 | ++NumVars; |
| 254 | Vars = Func->allocateArrayOf<Variable *>(NumVars); |
| 255 | Vars[0] = Reg; |
| 256 | if (ShiftVar) |
| 257 | Vars[1] = ShiftVar; |
| 258 | } |
| 259 | |
Jan Voung | b0a8c24 | 2015-06-18 15:00:14 -0700 | [diff] [blame] | 260 | InstARM32AdjustStack::InstARM32AdjustStack(Cfg *Func, Variable *SP, |
| 261 | SizeT Amount, Operand *SrcAmount) |
| 262 | : InstARM32(Func, InstARM32::Adjuststack, 2, SP), Amount(Amount) { |
| 263 | addSource(SP); |
| 264 | addSource(SrcAmount); |
| 265 | } |
| 266 | |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 267 | InstARM32Br::InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 268 | const CfgNode *TargetFalse, |
| 269 | const InstARM32Label *Label, CondARM32::Cond Pred) |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 270 | : InstARM32Pred(Func, InstARM32::Br, 0, nullptr, Pred), |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 271 | TargetTrue(TargetTrue), TargetFalse(TargetFalse), Label(Label) {} |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 272 | |
| 273 | bool InstARM32Br::optimizeBranch(const CfgNode *NextNode) { |
| 274 | // If there is no next block, then there can be no fallthrough to |
| 275 | // optimize. |
| 276 | if (NextNode == nullptr) |
| 277 | return false; |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 278 | // Intra-block conditional branches can't be optimized. |
| 279 | if (Label) |
| 280 | return false; |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 281 | // If there is no fallthrough node, such as a non-default case label |
| 282 | // for a switch instruction, then there is no opportunity to |
| 283 | // optimize. |
| 284 | if (getTargetFalse() == nullptr) |
| 285 | return false; |
| 286 | |
| 287 | // Unconditional branch to the next node can be removed. |
| 288 | if (isUnconditionalBranch() && getTargetFalse() == NextNode) { |
| 289 | assert(getTargetTrue() == nullptr); |
| 290 | setDeleted(); |
| 291 | return true; |
| 292 | } |
| 293 | // If the fallthrough is to the next node, set fallthrough to nullptr |
| 294 | // to indicate. |
| 295 | if (getTargetFalse() == NextNode) { |
| 296 | TargetFalse = nullptr; |
| 297 | return true; |
| 298 | } |
| 299 | // If TargetTrue is the next node, and TargetFalse is not nullptr |
| 300 | // (which was already tested above), then invert the branch |
| 301 | // condition, swap the targets, and set new fallthrough to nullptr. |
| 302 | if (getTargetTrue() == NextNode) { |
| 303 | assert(Predicate != CondARM32::AL); |
| 304 | setPredicate(getOppositeCondition(getPredicate())); |
| 305 | TargetTrue = getTargetFalse(); |
| 306 | TargetFalse = nullptr; |
| 307 | return true; |
| 308 | } |
| 309 | return false; |
| 310 | } |
| 311 | |
Andrew Scull | 87f80c1 | 2015-07-20 10:19:16 -0700 | [diff] [blame] | 312 | bool InstARM32Br::repointEdges(CfgNode *OldNode, CfgNode *NewNode) { |
| 313 | bool Found = false; |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 314 | if (TargetFalse == OldNode) { |
| 315 | TargetFalse = NewNode; |
Andrew Scull | 87f80c1 | 2015-07-20 10:19:16 -0700 | [diff] [blame] | 316 | Found = true; |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 317 | } |
Andrew Scull | 87f80c1 | 2015-07-20 10:19:16 -0700 | [diff] [blame] | 318 | if (TargetTrue == OldNode) { |
| 319 | TargetTrue = NewNode; |
| 320 | Found = true; |
| 321 | } |
| 322 | return Found; |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 323 | } |
| 324 | |
| 325 | InstARM32Call::InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget) |
| 326 | : InstARM32(Func, InstARM32::Call, 1, Dest) { |
| 327 | HasSideEffects = true; |
| 328 | addSource(CallTarget); |
| 329 | } |
| 330 | |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 331 | InstARM32Label::InstARM32Label(Cfg *Func, TargetARM32 *Target) |
| 332 | : InstARM32(Func, InstARM32::Label, 0, nullptr), |
| 333 | Number(Target->makeNextLabelNumber()) {} |
| 334 | |
| 335 | IceString InstARM32Label::getName(const Cfg *Func) const { |
| 336 | return ".L" + Func->getFunctionName() + "$local$__" + std::to_string(Number); |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 337 | } |
| 338 | |
Jan Voung | 0fa6c5a | 2015-06-01 11:04:04 -0700 | [diff] [blame] | 339 | InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests) |
| 340 | : InstARM32(Func, InstARM32::Pop, 0, nullptr), Dests(Dests) { |
| 341 | // Track modifications to Dests separately via FakeDefs. |
| 342 | // Also, a pop instruction affects the stack pointer and so it should not |
| 343 | // be allowed to be automatically dead-code eliminated. This is automatic |
| 344 | // since we leave the Dest as nullptr. |
| 345 | } |
| 346 | |
| 347 | InstARM32Push::InstARM32Push(Cfg *Func, const VarList &Srcs) |
| 348 | : InstARM32(Func, InstARM32::Push, Srcs.size(), nullptr) { |
| 349 | for (Variable *Source : Srcs) |
| 350 | addSource(Source); |
| 351 | } |
| 352 | |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 353 | InstARM32Ret::InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source) |
| 354 | : InstARM32(Func, InstARM32::Ret, Source ? 2 : 1, nullptr) { |
| 355 | addSource(LR); |
| 356 | if (Source) |
| 357 | addSource(Source); |
| 358 | } |
| 359 | |
Jan Voung | befd03a | 2015-06-02 11:03:03 -0700 | [diff] [blame] | 360 | InstARM32Str::InstARM32Str(Cfg *Func, Variable *Value, OperandARM32Mem *Mem, |
| 361 | CondARM32::Cond Predicate) |
| 362 | : InstARM32Pred(Func, InstARM32::Str, 2, nullptr, Predicate) { |
| 363 | addSource(Value); |
| 364 | addSource(Mem); |
| 365 | } |
| 366 | |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 367 | InstARM32Trap::InstARM32Trap(Cfg *Func) |
| 368 | : InstARM32(Func, InstARM32::Trap, 0, nullptr) {} |
| 369 | |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 370 | InstARM32Umull::InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 371 | Variable *Src0, Variable *Src1, |
| 372 | CondARM32::Cond Predicate) |
| 373 | : InstARM32Pred(Func, InstARM32::Umull, 2, DestLo, Predicate), |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 374 | // DestHi is expected to have a FakeDef inserted by the lowering code. |
| 375 | DestHi(DestHi) { |
| 376 | addSource(Src0); |
| 377 | addSource(Src1); |
| 378 | } |
| 379 | |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 380 | // ======================== Dump routines ======================== // |
| 381 | |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 382 | // Two-addr ops |
| 383 | template <> const char *InstARM32Movt::Opcode = "movt"; |
| 384 | // Unary ops |
| 385 | template <> const char *InstARM32Movw::Opcode = "movw"; |
Jan Voung | f645d85 | 2015-07-09 10:35:09 -0700 | [diff] [blame] | 386 | template <> const char *InstARM32Clz::Opcode = "clz"; |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 387 | template <> const char *InstARM32Mvn::Opcode = "mvn"; |
Jan Voung | f645d85 | 2015-07-09 10:35:09 -0700 | [diff] [blame] | 388 | template <> const char *InstARM32Rbit::Opcode = "rbit"; |
| 389 | template <> const char *InstARM32Rev::Opcode = "rev"; |
Jan Voung | 66c3d5e | 2015-06-04 17:02:31 -0700 | [diff] [blame] | 390 | template <> const char *InstARM32Sxt::Opcode = "sxt"; // still requires b/h |
| 391 | template <> const char *InstARM32Uxt::Opcode = "uxt"; // still requires b/h |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 392 | // FP |
| 393 | template <> const char *InstARM32Vsqrt::Opcode = "vsqrt"; |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 394 | // Mov-like ops |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 395 | template <> const char *InstARM32Ldr::Opcode = "ldr"; |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 396 | template <> const char *InstARM32Mov::Opcode = "mov"; |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 397 | // FP |
| 398 | template <> const char *InstARM32Vldr::Opcode = "vldr"; |
| 399 | template <> const char *InstARM32Vmov::Opcode = "vmov"; |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 400 | // Three-addr ops |
| 401 | template <> const char *InstARM32Adc::Opcode = "adc"; |
| 402 | template <> const char *InstARM32Add::Opcode = "add"; |
| 403 | template <> const char *InstARM32And::Opcode = "and"; |
Jan Voung | 66c3d5e | 2015-06-04 17:02:31 -0700 | [diff] [blame] | 404 | template <> const char *InstARM32Asr::Opcode = "asr"; |
Jan Voung | 55500db | 2015-05-26 14:25:40 -0700 | [diff] [blame] | 405 | template <> const char *InstARM32Bic::Opcode = "bic"; |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 406 | template <> const char *InstARM32Eor::Opcode = "eor"; |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 407 | template <> const char *InstARM32Lsl::Opcode = "lsl"; |
Jan Voung | 66c3d5e | 2015-06-04 17:02:31 -0700 | [diff] [blame] | 408 | template <> const char *InstARM32Lsr::Opcode = "lsr"; |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 409 | template <> const char *InstARM32Mul::Opcode = "mul"; |
| 410 | template <> const char *InstARM32Orr::Opcode = "orr"; |
Jan Voung | 66c3d5e | 2015-06-04 17:02:31 -0700 | [diff] [blame] | 411 | template <> const char *InstARM32Rsb::Opcode = "rsb"; |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 412 | template <> const char *InstARM32Sbc::Opcode = "sbc"; |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 413 | template <> const char *InstARM32Sdiv::Opcode = "sdiv"; |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 414 | template <> const char *InstARM32Sub::Opcode = "sub"; |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 415 | template <> const char *InstARM32Udiv::Opcode = "udiv"; |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 416 | // FP |
| 417 | template <> const char *InstARM32Vadd::Opcode = "vadd"; |
| 418 | template <> const char *InstARM32Vdiv::Opcode = "vdiv"; |
| 419 | template <> const char *InstARM32Vmul::Opcode = "vmul"; |
| 420 | template <> const char *InstARM32Vsub::Opcode = "vsub"; |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 421 | // Four-addr ops |
| 422 | template <> const char *InstARM32Mla::Opcode = "mla"; |
| 423 | template <> const char *InstARM32Mls::Opcode = "mls"; |
| 424 | // Cmp-like ops |
| 425 | template <> const char *InstARM32Cmp::Opcode = "cmp"; |
| 426 | template <> const char *InstARM32Tst::Opcode = "tst"; |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 427 | |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 428 | void InstARM32::dump(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 429 | if (!BuildDefs::dump()) |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 430 | return; |
| 431 | Ostream &Str = Func->getContext()->getStrDump(); |
| 432 | Str << "[ARM32] "; |
| 433 | Inst::dump(Func); |
| 434 | } |
| 435 | |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 436 | template <> void InstARM32Mov::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 437 | if (!BuildDefs::dump()) |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 438 | return; |
| 439 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 440 | assert(getSrcSize() == 1); |
| 441 | Variable *Dest = getDest(); |
| 442 | if (Dest->hasReg()) { |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 443 | IceString ActualOpcode = Opcode; |
Jan Voung | c207d51 | 2015-05-27 14:34:34 -0700 | [diff] [blame] | 444 | Operand *Src0 = getSrc(0); |
| 445 | if (const auto *Src0V = llvm::dyn_cast<Variable>(Src0)) { |
| 446 | if (!Src0V->hasReg()) { |
Jan Voung | 28068ad | 2015-07-31 12:58:46 -0700 | [diff] [blame] | 447 | // Always use the whole stack slot. A 32-bit load has a larger range |
| 448 | // of offsets than 16-bit, etc. |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 449 | ActualOpcode = IceString("ldr"); |
Jan Voung | c207d51 | 2015-05-27 14:34:34 -0700 | [diff] [blame] | 450 | } |
| 451 | } else { |
Jan Voung | befd03a | 2015-06-02 11:03:03 -0700 | [diff] [blame] | 452 | if (llvm::isa<OperandARM32Mem>(Src0)) |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 453 | ActualOpcode = IceString("ldr") + getWidthString(Dest->getType()); |
Jan Voung | c207d51 | 2015-05-27 14:34:34 -0700 | [diff] [blame] | 454 | } |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 455 | Str << "\t" << ActualOpcode << getPredicate() << "\t"; |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 456 | getDest()->emit(Func); |
| 457 | Str << ", "; |
| 458 | getSrc(0)->emit(Func); |
| 459 | } else { |
| 460 | Variable *Src0 = llvm::cast<Variable>(getSrc(0)); |
| 461 | assert(Src0->hasReg()); |
| 462 | Str << "\t" |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 463 | << "str" << getPredicate() << "\t"; |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 464 | Src0->emit(Func); |
| 465 | Str << ", "; |
| 466 | Dest->emit(Func); |
| 467 | } |
| 468 | } |
| 469 | |
| 470 | template <> void InstARM32Mov::emitIAS(const Cfg *Func) const { |
| 471 | assert(getSrcSize() == 1); |
| 472 | (void)Func; |
| 473 | llvm_unreachable("Not yet implemented"); |
| 474 | } |
| 475 | |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 476 | template <> void InstARM32Vldr::emit(const Cfg *Func) const { |
| 477 | if (!BuildDefs::dump()) |
| 478 | return; |
| 479 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 480 | assert(getSrcSize() == 1); |
| 481 | assert(getDest()->hasReg()); |
Jim Stichnoth | 992f91d | 2015-08-10 11:18:38 -0700 | [diff] [blame] | 482 | Str << "\t" << Opcode << getPredicate() << "\t"; |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 483 | getDest()->emit(Func); |
| 484 | Str << ", "; |
| 485 | getSrc(0)->emit(Func); |
| 486 | } |
| 487 | |
| 488 | template <> void InstARM32Vldr::emitIAS(const Cfg *Func) const { |
| 489 | assert(getSrcSize() == 1); |
| 490 | (void)Func; |
| 491 | llvm_unreachable("Not yet implemented"); |
| 492 | } |
| 493 | |
| 494 | template <> void InstARM32Vmov::emit(const Cfg *Func) const { |
| 495 | if (!BuildDefs::dump()) |
| 496 | return; |
| 497 | assert(CondARM32::AL == getPredicate()); |
| 498 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 499 | assert(getSrcSize() == 1); |
| 500 | Variable *Dest = getDest(); |
| 501 | if (Dest->hasReg()) { |
| 502 | IceString ActualOpcode = Opcode; |
| 503 | Operand *Src0 = getSrc(0); |
| 504 | if (const auto *Src0V = llvm::dyn_cast<Variable>(Src0)) { |
| 505 | if (!Src0V->hasReg()) { |
| 506 | ActualOpcode = IceString("vldr"); |
| 507 | } |
| 508 | } else { |
| 509 | if (llvm::isa<OperandARM32Mem>(Src0)) |
| 510 | ActualOpcode = IceString("vldr"); |
| 511 | } |
| 512 | Str << "\t" << ActualOpcode << "\t"; |
| 513 | getDest()->emit(Func); |
| 514 | Str << ", "; |
| 515 | getSrc(0)->emit(Func); |
| 516 | } else { |
| 517 | Variable *Src0 = llvm::cast<Variable>(getSrc(0)); |
| 518 | assert(Src0->hasReg()); |
| 519 | Str << "\t" |
| 520 | "vstr" |
| 521 | "\t"; |
| 522 | Src0->emit(Func); |
| 523 | Str << ", "; |
| 524 | Dest->emit(Func); |
| 525 | } |
| 526 | } |
| 527 | |
| 528 | template <> void InstARM32Vmov::emitIAS(const Cfg *Func) const { |
| 529 | assert(getSrcSize() == 1); |
| 530 | (void)Func; |
| 531 | llvm_unreachable("Not yet implemented"); |
| 532 | } |
| 533 | |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 534 | void InstARM32Br::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 535 | if (!BuildDefs::dump()) |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 536 | return; |
| 537 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 538 | Str << "\t" |
| 539 | << "b" << getPredicate() << "\t"; |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 540 | if (Label) { |
| 541 | Str << Label->getName(Func); |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 542 | } else { |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 543 | if (isUnconditionalBranch()) { |
| 544 | Str << getTargetFalse()->getAsmName(); |
| 545 | } else { |
| 546 | Str << getTargetTrue()->getAsmName(); |
| 547 | if (getTargetFalse()) { |
| 548 | Str << "\n\t" |
| 549 | << "b" |
| 550 | << "\t" << getTargetFalse()->getAsmName(); |
| 551 | } |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 552 | } |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | void InstARM32Br::emitIAS(const Cfg *Func) const { |
| 557 | (void)Func; |
| 558 | llvm_unreachable("Not yet implemented"); |
| 559 | } |
| 560 | |
| 561 | void InstARM32Br::dump(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 562 | if (!BuildDefs::dump()) |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 563 | return; |
| 564 | Ostream &Str = Func->getContext()->getStrDump(); |
| 565 | Str << "br "; |
| 566 | |
| 567 | if (getPredicate() == CondARM32::AL) { |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 568 | Str << "label %" |
| 569 | << (Label ? Label->getName(Func) : getTargetFalse()->getName()); |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 570 | return; |
| 571 | } |
| 572 | |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 573 | if (Label) { |
| 574 | Str << "label %" << Label->getName(Func); |
| 575 | } else { |
| 576 | Str << getPredicate() << ", label %" << getTargetTrue()->getName(); |
| 577 | if (getTargetFalse()) { |
| 578 | Str << ", label %" << getTargetFalse()->getName(); |
| 579 | } |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 580 | } |
| 581 | } |
| 582 | |
| 583 | void InstARM32Call::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 584 | if (!BuildDefs::dump()) |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 585 | return; |
| 586 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 587 | assert(getSrcSize() == 1); |
| 588 | if (llvm::isa<ConstantInteger32>(getCallTarget())) { |
| 589 | // This shouldn't happen (typically have to copy the full 32-bits |
| 590 | // to a register and do an indirect jump). |
| 591 | llvm::report_fatal_error("ARM32Call to ConstantInteger32"); |
| 592 | } else if (const auto CallTarget = |
| 593 | llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) { |
| 594 | // Calls only have 24-bits, but the linker should insert veneers to |
| 595 | // extend the range if needed. |
| 596 | Str << "\t" |
| 597 | << "bl" |
| 598 | << "\t"; |
| 599 | CallTarget->emitWithoutPrefix(Func->getTarget()); |
| 600 | } else { |
| 601 | Str << "\t" |
| 602 | << "blx" |
| 603 | << "\t"; |
| 604 | getCallTarget()->emit(Func); |
| 605 | } |
| 606 | Func->getTarget()->resetStackAdjustment(); |
| 607 | } |
| 608 | |
| 609 | void InstARM32Call::emitIAS(const Cfg *Func) const { |
| 610 | (void)Func; |
| 611 | llvm_unreachable("Not yet implemented"); |
| 612 | } |
| 613 | |
| 614 | void InstARM32Call::dump(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 615 | if (!BuildDefs::dump()) |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 616 | return; |
| 617 | Ostream &Str = Func->getContext()->getStrDump(); |
| 618 | if (getDest()) { |
| 619 | dumpDest(Func); |
| 620 | Str << " = "; |
| 621 | } |
| 622 | Str << "call "; |
| 623 | getCallTarget()->dump(Func); |
| 624 | } |
| 625 | |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 626 | void InstARM32Label::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 627 | if (!BuildDefs::dump()) |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 628 | return; |
| 629 | Ostream &Str = Func->getContext()->getStrEmit(); |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 630 | Str << getName(Func) << ":"; |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 631 | } |
| 632 | |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 633 | void InstARM32Label::emitIAS(const Cfg *Func) const { |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 634 | (void)Func; |
| 635 | llvm_unreachable("Not yet implemented"); |
| 636 | } |
| 637 | |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 638 | void InstARM32Label::dump(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 639 | if (!BuildDefs::dump()) |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 640 | return; |
| 641 | Ostream &Str = Func->getContext()->getStrDump(); |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 642 | Str << getName(Func) << ":"; |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 643 | } |
| 644 | |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 645 | template <> void InstARM32Ldr::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 646 | if (!BuildDefs::dump()) |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 647 | return; |
| 648 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 649 | assert(getSrcSize() == 1); |
| 650 | assert(getDest()->hasReg()); |
| 651 | Type Ty = getSrc(0)->getType(); |
Jim Stichnoth | 992f91d | 2015-08-10 11:18:38 -0700 | [diff] [blame] | 652 | Str << "\t" << Opcode << getWidthString(Ty) << getPredicate() << "\t"; |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 653 | getDest()->emit(Func); |
| 654 | Str << ", "; |
| 655 | getSrc(0)->emit(Func); |
| 656 | } |
| 657 | |
Jan Voung | 86ebec1 | 2015-08-09 07:58:35 -0700 | [diff] [blame] | 658 | template <> void InstARM32Ldr::emitIAS(const Cfg *Func) const { |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 659 | assert(getSrcSize() == 1); |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 660 | (void)Func; |
| 661 | llvm_unreachable("Not yet implemented"); |
| 662 | } |
| 663 | |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 664 | template <> void InstARM32Movw::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 665 | if (!BuildDefs::dump()) |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 666 | return; |
| 667 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 668 | assert(getSrcSize() == 1); |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 669 | Str << "\t" << Opcode << getPredicate() << "\t"; |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 670 | getDest()->emit(Func); |
| 671 | Str << ", "; |
| 672 | Constant *Src0 = llvm::cast<Constant>(getSrc(0)); |
| 673 | if (auto CR = llvm::dyn_cast<ConstantRelocatable>(Src0)) { |
| 674 | Str << "#:lower16:"; |
| 675 | CR->emitWithoutPrefix(Func->getTarget()); |
| 676 | } else { |
| 677 | Src0->emit(Func); |
| 678 | } |
| 679 | } |
| 680 | |
| 681 | template <> void InstARM32Movt::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 682 | if (!BuildDefs::dump()) |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 683 | return; |
| 684 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 685 | assert(getSrcSize() == 2); |
| 686 | Variable *Dest = getDest(); |
| 687 | Constant *Src1 = llvm::cast<Constant>(getSrc(1)); |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 688 | Str << "\t" << Opcode << getPredicate() << "\t"; |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 689 | Dest->emit(Func); |
| 690 | Str << ", "; |
| 691 | if (auto CR = llvm::dyn_cast<ConstantRelocatable>(Src1)) { |
| 692 | Str << "#:upper16:"; |
| 693 | CR->emitWithoutPrefix(Func->getTarget()); |
| 694 | } else { |
| 695 | Src1->emit(Func); |
| 696 | } |
| 697 | } |
| 698 | |
Jan Voung | 0fa6c5a | 2015-06-01 11:04:04 -0700 | [diff] [blame] | 699 | void InstARM32Pop::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 700 | if (!BuildDefs::dump()) |
Jan Voung | 0fa6c5a | 2015-06-01 11:04:04 -0700 | [diff] [blame] | 701 | return; |
| 702 | assert(Dests.size() > 0); |
| 703 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 704 | Str << "\t" |
| 705 | << "pop" |
| 706 | << "\t{"; |
| 707 | for (SizeT I = 0; I < Dests.size(); ++I) { |
| 708 | if (I > 0) |
| 709 | Str << ", "; |
| 710 | Dests[I]->emit(Func); |
| 711 | } |
| 712 | Str << "}"; |
| 713 | } |
| 714 | |
| 715 | void InstARM32Pop::emitIAS(const Cfg *Func) const { |
| 716 | (void)Func; |
| 717 | llvm_unreachable("Not yet implemented"); |
| 718 | } |
| 719 | |
| 720 | void InstARM32Pop::dump(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 721 | if (!BuildDefs::dump()) |
Jan Voung | 0fa6c5a | 2015-06-01 11:04:04 -0700 | [diff] [blame] | 722 | return; |
| 723 | Ostream &Str = Func->getContext()->getStrDump(); |
| 724 | Str << "pop" |
| 725 | << " "; |
| 726 | for (SizeT I = 0; I < Dests.size(); ++I) { |
| 727 | if (I > 0) |
| 728 | Str << ", "; |
| 729 | Dests[I]->dump(Func); |
| 730 | } |
| 731 | } |
| 732 | |
Jan Voung | b0a8c24 | 2015-06-18 15:00:14 -0700 | [diff] [blame] | 733 | void InstARM32AdjustStack::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 734 | if (!BuildDefs::dump()) |
Jan Voung | b0a8c24 | 2015-06-18 15:00:14 -0700 | [diff] [blame] | 735 | return; |
| 736 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 737 | assert(getSrcSize() == 2); |
| 738 | Str << "\t" |
| 739 | << "sub" |
| 740 | << "\t"; |
| 741 | getDest()->emit(Func); |
| 742 | Str << ", "; |
| 743 | getSrc(0)->emit(Func); |
| 744 | Str << ", "; |
| 745 | getSrc(1)->emit(Func); |
| 746 | Func->getTarget()->updateStackAdjustment(Amount); |
| 747 | } |
| 748 | |
| 749 | void InstARM32AdjustStack::emitIAS(const Cfg *Func) const { |
| 750 | (void)Func; |
| 751 | llvm_unreachable("Not yet implemented"); |
| 752 | Func->getTarget()->updateStackAdjustment(Amount); |
| 753 | } |
| 754 | |
| 755 | void InstARM32AdjustStack::dump(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 756 | if (!BuildDefs::dump()) |
Jan Voung | b0a8c24 | 2015-06-18 15:00:14 -0700 | [diff] [blame] | 757 | return; |
| 758 | Ostream &Str = Func->getContext()->getStrDump(); |
| 759 | getDest()->dump(Func); |
| 760 | Str << " = sub.i32 "; |
| 761 | getSrc(0)->dump(Func); |
| 762 | Str << ", " << Amount << " ; "; |
| 763 | getSrc(1)->dump(Func); |
| 764 | } |
| 765 | |
Jan Voung | 0fa6c5a | 2015-06-01 11:04:04 -0700 | [diff] [blame] | 766 | void InstARM32Push::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 767 | if (!BuildDefs::dump()) |
Jan Voung | 0fa6c5a | 2015-06-01 11:04:04 -0700 | [diff] [blame] | 768 | return; |
| 769 | assert(getSrcSize() > 0); |
| 770 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 771 | Str << "\t" |
| 772 | << "push" |
| 773 | << "\t{"; |
| 774 | emitSources(Func); |
| 775 | Str << "}"; |
| 776 | } |
| 777 | |
| 778 | void InstARM32Push::emitIAS(const Cfg *Func) const { |
| 779 | (void)Func; |
| 780 | llvm_unreachable("Not yet implemented"); |
| 781 | } |
| 782 | |
| 783 | void InstARM32Push::dump(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 784 | if (!BuildDefs::dump()) |
Jan Voung | 0fa6c5a | 2015-06-01 11:04:04 -0700 | [diff] [blame] | 785 | return; |
| 786 | Ostream &Str = Func->getContext()->getStrDump(); |
| 787 | Str << "push" |
| 788 | << " "; |
| 789 | dumpSources(Func); |
| 790 | } |
| 791 | |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 792 | void InstARM32Ret::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 793 | if (!BuildDefs::dump()) |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 794 | return; |
| 795 | assert(getSrcSize() > 0); |
| 796 | Variable *LR = llvm::cast<Variable>(getSrc(0)); |
| 797 | assert(LR->hasReg()); |
| 798 | assert(LR->getRegNum() == RegARM32::Reg_lr); |
| 799 | Ostream &Str = Func->getContext()->getStrEmit(); |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 800 | Str << "\t" |
| 801 | << "bx" |
| 802 | << "\t"; |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 803 | LR->emit(Func); |
| 804 | } |
| 805 | |
| 806 | void InstARM32Ret::emitIAS(const Cfg *Func) const { |
| 807 | (void)Func; |
| 808 | llvm_unreachable("Not yet implemented"); |
| 809 | } |
| 810 | |
| 811 | void InstARM32Ret::dump(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 812 | if (!BuildDefs::dump()) |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 813 | return; |
| 814 | Ostream &Str = Func->getContext()->getStrDump(); |
| 815 | Type Ty = (getSrcSize() == 1 ? IceType_void : getSrc(0)->getType()); |
| 816 | Str << "ret." << Ty << " "; |
| 817 | dumpSources(Func); |
| 818 | } |
| 819 | |
Jan Voung | befd03a | 2015-06-02 11:03:03 -0700 | [diff] [blame] | 820 | void InstARM32Str::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 821 | if (!BuildDefs::dump()) |
Jan Voung | befd03a | 2015-06-02 11:03:03 -0700 | [diff] [blame] | 822 | return; |
| 823 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 824 | assert(getSrcSize() == 2); |
| 825 | Type Ty = getSrc(0)->getType(); |
| 826 | Str << "\t" |
| 827 | << "str" << getWidthString(Ty) << getPredicate() << "\t"; |
| 828 | getSrc(0)->emit(Func); |
| 829 | Str << ", "; |
| 830 | getSrc(1)->emit(Func); |
| 831 | } |
| 832 | |
| 833 | void InstARM32Str::emitIAS(const Cfg *Func) const { |
| 834 | assert(getSrcSize() == 2); |
| 835 | (void)Func; |
| 836 | llvm_unreachable("Not yet implemented"); |
| 837 | } |
| 838 | |
| 839 | void InstARM32Str::dump(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 840 | if (!BuildDefs::dump()) |
Jan Voung | befd03a | 2015-06-02 11:03:03 -0700 | [diff] [blame] | 841 | return; |
| 842 | Ostream &Str = Func->getContext()->getStrDump(); |
Jan Voung | 66c3d5e | 2015-06-04 17:02:31 -0700 | [diff] [blame] | 843 | Type Ty = getSrc(0)->getType(); |
| 844 | dumpOpcodePred(Str, "str", Ty); |
Jan Voung | befd03a | 2015-06-02 11:03:03 -0700 | [diff] [blame] | 845 | Str << " "; |
| 846 | getSrc(1)->dump(Func); |
| 847 | Str << ", "; |
| 848 | getSrc(0)->dump(Func); |
| 849 | } |
| 850 | |
Jan Voung | 6ec369e | 2015-06-30 11:03:15 -0700 | [diff] [blame] | 851 | void InstARM32Trap::emit(const Cfg *Func) const { |
| 852 | if (!BuildDefs::dump()) |
| 853 | return; |
| 854 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 855 | assert(getSrcSize() == 0); |
| 856 | // There isn't a mnemonic for the special NaCl Trap encoding, so dump |
| 857 | // the raw bytes. |
| 858 | Str << "\t.long 0x"; |
| 859 | ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); |
| 860 | for (uint8_t I : Asm->getNonExecBundlePadding()) { |
| 861 | Str.write_hex(I); |
| 862 | } |
| 863 | } |
| 864 | |
| 865 | void InstARM32Trap::emitIAS(const Cfg *Func) const { |
| 866 | assert(getSrcSize() == 0); |
| 867 | (void)Func; |
| 868 | llvm_unreachable("Not yet implemented"); |
| 869 | } |
| 870 | |
| 871 | void InstARM32Trap::dump(const Cfg *Func) const { |
| 872 | if (!BuildDefs::dump()) |
| 873 | return; |
| 874 | Ostream &Str = Func->getContext()->getStrDump(); |
| 875 | Str << "trap"; |
| 876 | } |
| 877 | |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 878 | void InstARM32Umull::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 879 | if (!BuildDefs::dump()) |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 880 | return; |
| 881 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 882 | assert(getSrcSize() == 2); |
| 883 | assert(getDest()->hasReg()); |
| 884 | Str << "\t" |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 885 | << "umull" << getPredicate() << "\t"; |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 886 | getDest()->emit(Func); |
| 887 | Str << ", "; |
| 888 | DestHi->emit(Func); |
| 889 | Str << ", "; |
| 890 | getSrc(0)->emit(Func); |
| 891 | Str << ", "; |
| 892 | getSrc(1)->emit(Func); |
| 893 | } |
| 894 | |
| 895 | void InstARM32Umull::emitIAS(const Cfg *Func) const { |
| 896 | assert(getSrcSize() == 2); |
| 897 | (void)Func; |
| 898 | llvm_unreachable("Not yet implemented"); |
| 899 | } |
| 900 | |
| 901 | void InstARM32Umull::dump(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 902 | if (!BuildDefs::dump()) |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 903 | return; |
| 904 | Ostream &Str = Func->getContext()->getStrDump(); |
| 905 | dumpDest(Func); |
Jan Voung | 3bfd99a | 2015-05-22 16:35:25 -0700 | [diff] [blame] | 906 | Str << " = "; |
| 907 | dumpOpcodePred(Str, "umull", getDest()->getType()); |
| 908 | Str << " "; |
Jan Voung | 2971997 | 2015-05-19 11:24:51 -0700 | [diff] [blame] | 909 | dumpSources(Func); |
| 910 | } |
| 911 | |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 912 | void OperandARM32Mem::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 913 | if (!BuildDefs::dump()) |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 914 | return; |
| 915 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 916 | Str << "["; |
| 917 | getBase()->emit(Func); |
| 918 | switch (getAddrMode()) { |
| 919 | case PostIndex: |
| 920 | case NegPostIndex: |
| 921 | Str << "], "; |
| 922 | break; |
| 923 | default: |
| 924 | Str << ", "; |
| 925 | break; |
| 926 | } |
| 927 | if (isRegReg()) { |
| 928 | if (isNegAddrMode()) { |
| 929 | Str << "-"; |
| 930 | } |
| 931 | getIndex()->emit(Func); |
| 932 | if (getShiftOp() != kNoShift) { |
| 933 | Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #" |
| 934 | << getShiftAmt(); |
| 935 | } |
| 936 | } else { |
| 937 | getOffset()->emit(Func); |
| 938 | } |
| 939 | switch (getAddrMode()) { |
| 940 | case Offset: |
| 941 | case NegOffset: |
| 942 | Str << "]"; |
| 943 | break; |
| 944 | case PreIndex: |
| 945 | case NegPreIndex: |
| 946 | Str << "]!"; |
| 947 | break; |
| 948 | case PostIndex: |
| 949 | case NegPostIndex: |
| 950 | // Brace is already closed off. |
| 951 | break; |
| 952 | } |
| 953 | } |
| 954 | |
| 955 | void OperandARM32Mem::dump(const Cfg *Func, Ostream &Str) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 956 | if (!BuildDefs::dump()) |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 957 | return; |
| 958 | Str << "["; |
| 959 | if (Func) |
| 960 | getBase()->dump(Func); |
| 961 | else |
| 962 | getBase()->dump(Str); |
| 963 | Str << ", "; |
| 964 | if (isRegReg()) { |
| 965 | if (isNegAddrMode()) { |
| 966 | Str << "-"; |
| 967 | } |
| 968 | if (Func) |
| 969 | getIndex()->dump(Func); |
| 970 | else |
| 971 | getIndex()->dump(Str); |
| 972 | if (getShiftOp() != kNoShift) { |
| 973 | Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #" |
| 974 | << getShiftAmt(); |
| 975 | } |
| 976 | } else { |
| 977 | getOffset()->dump(Func, Str); |
| 978 | } |
Jan Voung | 0fa6c5a | 2015-06-01 11:04:04 -0700 | [diff] [blame] | 979 | Str << "] AddrMode==" << getAddrMode(); |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 980 | } |
| 981 | |
| 982 | void OperandARM32FlexImm::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 983 | if (!BuildDefs::dump()) |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 984 | return; |
| 985 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 986 | uint32_t Imm = getImm(); |
| 987 | uint32_t RotateAmt = getRotateAmt(); |
| 988 | Str << "#" << Utils::rotateRight32(Imm, 2 * RotateAmt); |
| 989 | } |
| 990 | |
| 991 | void OperandARM32FlexImm::dump(const Cfg * /* Func */, Ostream &Str) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 992 | if (!BuildDefs::dump()) |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 993 | return; |
| 994 | uint32_t Imm = getImm(); |
| 995 | uint32_t RotateAmt = getRotateAmt(); |
| 996 | Str << "#(" << Imm << " ror 2*" << RotateAmt << ")"; |
| 997 | } |
| 998 | |
| 999 | void OperandARM32FlexReg::emit(const Cfg *Func) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 1000 | if (!BuildDefs::dump()) |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 1001 | return; |
| 1002 | Ostream &Str = Func->getContext()->getStrEmit(); |
| 1003 | getReg()->emit(Func); |
| 1004 | if (getShiftOp() != kNoShift) { |
| 1005 | Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; |
| 1006 | getShiftAmt()->emit(Func); |
| 1007 | } |
| 1008 | } |
| 1009 | |
| 1010 | void OperandARM32FlexReg::dump(const Cfg *Func, Ostream &Str) const { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 1011 | if (!BuildDefs::dump()) |
Jan Voung | b3401d2 | 2015-05-18 09:38:21 -0700 | [diff] [blame] | 1012 | return; |
| 1013 | Variable *Reg = getReg(); |
| 1014 | if (Func) |
| 1015 | Reg->dump(Func); |
| 1016 | else |
| 1017 | Reg->dump(Str); |
| 1018 | if (getShiftOp() != kNoShift) { |
| 1019 | Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " "; |
| 1020 | if (Func) |
| 1021 | getShiftAmt()->dump(Func); |
| 1022 | else |
| 1023 | getShiftAmt()->dump(Str); |
| 1024 | } |
| 1025 | } |
| 1026 | |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 1027 | } // end of namespace Ice |