| OLD | NEW |
| 1 //===- subzero/src/IceAssemblerARM32.cpp - Assembler for ARM32 --*- C++ -*-===// | 1 //===- subzero/src/IceAssemblerARM32.cpp - Assembler for ARM32 --*- C++ -*-===// |
| 2 // | 2 // |
| 3 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 3 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 4 // for details. All rights reserved. Use of this source code is governed by a | 4 // for details. All rights reserved. Use of this source code is governed by a |
| 5 // BSD-style license that can be found in the LICENSE file. | 5 // BSD-style license that can be found in the LICENSE file. |
| 6 // | 6 // |
| 7 // Modified by the Subzero authors. | 7 // Modified by the Subzero authors. |
| 8 // | 8 // |
| 9 //===----------------------------------------------------------------------===// | 9 //===----------------------------------------------------------------------===// |
| 10 // | 10 // |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 // Extract out a Bit in Value. | 170 // Extract out a Bit in Value. |
| 171 inline bool isBitSet(IValueT Bit, IValueT Value) { | 171 inline bool isBitSet(IValueT Bit, IValueT Value) { |
| 172 return (Value & Bit) == Bit; | 172 return (Value & Bit) == Bit; |
| 173 } | 173 } |
| 174 | 174 |
| 175 // Returns the GPR register at given Shift in Value. | 175 // Returns the GPR register at given Shift in Value. |
| 176 inline RegARM32::GPRRegister getGPRReg(IValueT Shift, IValueT Value) { | 176 inline RegARM32::GPRRegister getGPRReg(IValueT Shift, IValueT Value) { |
| 177 return decodeGPRRegister((Value >> Shift) & 0xF); | 177 return decodeGPRRegister((Value >> Shift) & 0xF); |
| 178 } | 178 } |
| 179 | 179 |
| 180 // The way an operand was decoded in functions decodeOperand and decodeAddress | 180 // The way an operand is encoded into a sequence of bits in functions |
| 181 // below. | 181 // encodeOperand and encodeAddress below. |
| 182 enum DecodedResult { | 182 enum EncodedOperand { |
| 183 // Unable to decode, value left undefined. | 183 // Unable to encode, value left undefined. |
| 184 CantDecode = 0, | 184 CantEncode = 0, |
| 185 // Value is register found. | 185 // Value is register found. |
| 186 DecodedAsRegister, | 186 EncodedAsRegister, |
| 187 // Value=rrrriiiiiiii where rrrr is the rotation, and iiiiiiii is the imm8 | 187 // Value=rrrriiiiiiii where rrrr is the rotation, and iiiiiiii is the imm8 |
| 188 // value. | 188 // value. |
| 189 DecodedAsRotatedImm8, | 189 EncodedAsRotatedImm8, |
| 190 // Value=0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn, | 190 // Value=0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn, |
| 191 // p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to | 191 // p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to |
| 192 // Rn should be used, and iiiiiiiiiiii defines the rotated Imm8 value. | 192 // Rn should be used, and iiiiiiiiiiii defines the rotated Imm8 value. |
| 193 DecodedAsImmRegOffset, | 193 EncodedAsImmRegOffset, |
| 194 // Value=00000000pu0w0nnnn0000iiii0000jjjj where nnnn=Rn, iiiijjjj=Imm8, p=1 | 194 // Value=00000000pu0w0nnnn0000iiii0000jjjj where nnnn=Rn, iiiijjjj=Imm8, p=1 |
| 195 // if pre-indexed addressing, u=1 if offset positive, and w=1 if writeback to | 195 // if pre-indexed addressing, u=1 if offset positive, and w=1 if writeback to |
| 196 // Rn. | 196 // Rn. |
| 197 DecodedAsImmRegOffsetEnc3, | 197 EncodedAsImmRegOffsetEnc3, |
| 198 // Value=0000000pu0w00nnnnttttiiiiiss0mmmm where nnnn is the base register Rn, | 198 // Value=0000000pu0w00nnnnttttiiiiiss0mmmm where nnnn is the base register Rn, |
| 199 // mmmm is the index register Rm, iiiii is the shift amount, ss is the shift | 199 // mmmm is the index register Rm, iiiii is the shift amount, ss is the shift |
| 200 // kind, p=1 if pre-indexed addressing, u=1 if offset positive, and w=1 if | 200 // kind, p=1 if pre-indexed addressing, u=1 if offset positive, and w=1 if |
| 201 // writeback to Rn. | 201 // writeback to Rn. |
| 202 DecodedAsShiftRotateImm5, | 202 EncodedAsShiftRotateImm5, |
| 203 // Value=000000000000000000000iiiii0000000 where iiii defines the Imm5 value | 203 // Value=000000000000000000000iiiii0000000 where iiii defines the Imm5 value |
| 204 // to shift. | 204 // to shift. |
| 205 DecodedAsShiftImm5, | 205 EncodedAsShiftImm5, |
| 206 // i.e. iiiiiss0mmmm where mmmm is the register to rotate, ss is the shift | 206 // i.e. iiiiiss0mmmm where mmmm is the register to rotate, ss is the shift |
| 207 // kind, and iiiii is the shift amount. | 207 // kind, and iiiii is the shift amount. |
| 208 DecodedAsShiftedRegister, | 208 EncodedAsShiftedRegister, |
| 209 // Value is 32bit integer constant. | 209 // Value is 32bit integer constant. |
| 210 DecodedAsConstI32 | 210 EncodedAsConstI32 |
| 211 }; | 211 }; |
| 212 | 212 |
| 213 // Sets Encoding to a rotated Imm8 encoding of Value, if possible. | 213 // Sets Encoding to a rotated Imm8 encoding of Value, if possible. |
| 214 inline IValueT encodeRotatedImm8(IValueT RotateAmt, IValueT Immed8) { | 214 inline IValueT encodeRotatedImm8(IValueT RotateAmt, IValueT Immed8) { |
| 215 assert(RotateAmt < (1 << kRotateBits)); | 215 assert(RotateAmt < (1 << kRotateBits)); |
| 216 assert(Immed8 < (1 << kImmed8Bits)); | 216 assert(Immed8 < (1 << kImmed8Bits)); |
| 217 return (RotateAmt << kRotateShift) | (Immed8 << kImmed8Shift); | 217 return (RotateAmt << kRotateShift) | (Immed8 << kImmed8Shift); |
| 218 } | 218 } |
| 219 | 219 |
| 220 // Encodes iiiiitt0mmmm for data-processing (2nd) operands where iiiii=Imm5, | 220 // Encodes iiiiitt0mmmm for data-processing (2nd) operands where iiiii=Imm5, |
| 221 // tt=Shift, and mmmm=Rm. | 221 // tt=Shift, and mmmm=Rm. |
| 222 IValueT encodeShiftRotateImm5(IValueT Rm, OperandARM32::ShiftKind Shift, | 222 IValueT encodeShiftRotateImm5(IValueT Rm, OperandARM32::ShiftKind Shift, |
| 223 IOffsetT imm5) { | 223 IOffsetT imm5) { |
| 224 (void)kShiftImmBits; | 224 (void)kShiftImmBits; |
| 225 assert(imm5 < (1 << kShiftImmBits)); | 225 assert(imm5 < (1 << kShiftImmBits)); |
| 226 return (imm5 << kShiftImmShift) | (encodeShift(Shift) << kShiftShift) | Rm; | 226 return (imm5 << kShiftImmShift) | (encodeShift(Shift) << kShiftShift) | Rm; |
| 227 } | 227 } |
| 228 | 228 |
| 229 // Encodes mmmmtt01ssss for data-processing operands where mmmm=Rm, ssss=Rs, and | 229 // Encodes mmmmtt01ssss for data-processing operands where mmmm=Rm, ssss=Rs, and |
| 230 // tt=Shift. | 230 // tt=Shift. |
| 231 IValueT encodeShiftRotateReg(IValueT Rm, OperandARM32::ShiftKind Shift, | 231 IValueT encodeShiftRotateReg(IValueT Rm, OperandARM32::ShiftKind Shift, |
| 232 IValueT Rs) { | 232 IValueT Rs) { |
| 233 return (Rs << kRsShift) | (encodeShift(Shift) << kShiftShift) | B4 | | 233 return (Rs << kRsShift) | (encodeShift(Shift) << kShiftShift) | B4 | |
| 234 (Rm << kRmShift); | 234 (Rm << kRmShift); |
| 235 } | 235 } |
| 236 | 236 |
| 237 DecodedResult decodeOperand(const Operand *Opnd, IValueT &Value) { | 237 EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value) { |
| 238 Value = 0; // Make sure initialized. | 238 Value = 0; // Make sure initialized. |
| 239 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { | 239 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { |
| 240 if (Var->hasReg()) { | 240 if (Var->hasReg()) { |
| 241 Value = Var->getRegNum(); | 241 Value = Var->getRegNum(); |
| 242 return DecodedAsRegister; | 242 return EncodedAsRegister; |
| 243 } | 243 } |
| 244 return CantDecode; | 244 return CantEncode; |
| 245 } | 245 } |
| 246 if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Opnd)) { | 246 if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Opnd)) { |
| 247 const IValueT Immed8 = FlexImm->getImm(); | 247 const IValueT Immed8 = FlexImm->getImm(); |
| 248 const IValueT Rotate = FlexImm->getRotateAmt(); | 248 const IValueT Rotate = FlexImm->getRotateAmt(); |
| 249 if (!((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits)))) | 249 if (!((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits)))) |
| 250 return CantDecode; | 250 return CantEncode; |
| 251 Value = (Rotate << kRotateShift) | (Immed8 << kImmed8Shift); | 251 Value = (Rotate << kRotateShift) | (Immed8 << kImmed8Shift); |
| 252 return DecodedAsRotatedImm8; | 252 return EncodedAsRotatedImm8; |
| 253 } | 253 } |
| 254 if (const auto *Const = llvm::dyn_cast<ConstantInteger32>(Opnd)) { | 254 if (const auto *Const = llvm::dyn_cast<ConstantInteger32>(Opnd)) { |
| 255 Value = Const->getValue(); | 255 Value = Const->getValue(); |
| 256 return DecodedAsConstI32; | 256 return EncodedAsConstI32; |
| 257 } | 257 } |
| 258 if (const auto *FlexReg = llvm::dyn_cast<OperandARM32FlexReg>(Opnd)) { | 258 if (const auto *FlexReg = llvm::dyn_cast<OperandARM32FlexReg>(Opnd)) { |
| 259 Operand *Amt = FlexReg->getShiftAmt(); | 259 Operand *Amt = FlexReg->getShiftAmt(); |
| 260 if (const auto *Imm5 = llvm::dyn_cast<OperandARM32ShAmtImm>(Amt)) { | 260 if (const auto *Imm5 = llvm::dyn_cast<OperandARM32ShAmtImm>(Amt)) { |
| 261 IValueT Rm; | 261 IValueT Rm; |
| 262 if (decodeOperand(FlexReg->getReg(), Rm) != DecodedAsRegister) | 262 if (encodeOperand(FlexReg->getReg(), Rm) != EncodedAsRegister) |
| 263 return CantDecode; | 263 return CantEncode; |
| 264 Value = | 264 Value = |
| 265 encodeShiftRotateImm5(Rm, FlexReg->getShiftOp(), Imm5->getShAmtImm()); | 265 encodeShiftRotateImm5(Rm, FlexReg->getShiftOp(), Imm5->getShAmtImm()); |
| 266 return DecodedAsShiftedRegister; | 266 return EncodedAsShiftedRegister; |
| 267 } | 267 } |
| 268 // TODO(kschimpf): Handle case where Amt is a register? | 268 // TODO(kschimpf): Handle case where Amt is a register? |
| 269 } | 269 } |
| 270 if (const auto *ShImm = llvm::dyn_cast<OperandARM32ShAmtImm>(Opnd)) { | 270 if (const auto *ShImm = llvm::dyn_cast<OperandARM32ShAmtImm>(Opnd)) { |
| 271 const IValueT Immed5 = ShImm->getShAmtImm(); | 271 const IValueT Immed5 = ShImm->getShAmtImm(); |
| 272 assert(Immed5 < (1 << kShiftImmBits)); | 272 assert(Immed5 < (1 << kShiftImmBits)); |
| 273 Value = (Immed5 << kShiftImmShift); | 273 Value = (Immed5 << kShiftImmShift); |
| 274 return DecodedAsShiftImm5; | 274 return EncodedAsShiftImm5; |
| 275 } | 275 } |
| 276 return CantDecode; | 276 return CantEncode; |
| 277 } | 277 } |
| 278 | 278 |
| 279 IValueT encodeImmRegOffset(IValueT Reg, IOffsetT Offset, | 279 IValueT encodeImmRegOffset(IValueT Reg, IOffsetT Offset, |
| 280 OperandARM32Mem::AddrMode Mode) { | 280 OperandARM32Mem::AddrMode Mode) { |
| 281 IValueT Value = Mode | (Reg << kRnShift); | 281 IValueT Value = Mode | (Reg << kRnShift); |
| 282 if (Offset < 0) { | 282 if (Offset < 0) { |
| 283 Value = (Value ^ U) | -Offset; // Flip U to adjust sign. | 283 Value = (Value ^ U) | -Offset; // Flip U to adjust sign. |
| 284 } else { | 284 } else { |
| 285 Value |= Offset; | 285 Value |= Offset; |
| 286 } | 286 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 302 | 302 |
| 303 // Defines alternate layouts of instruction operands, should the (common) | 303 // Defines alternate layouts of instruction operands, should the (common) |
| 304 // default pattern not be used. | 304 // default pattern not be used. |
| 305 enum OpEncoding { | 305 enum OpEncoding { |
| 306 // No alternate layout specified. | 306 // No alternate layout specified. |
| 307 DefaultOpEncoding, | 307 DefaultOpEncoding, |
| 308 // Alternate encoding 3. | 308 // Alternate encoding 3. |
| 309 OpEncoding3 | 309 OpEncoding3 |
| 310 }; | 310 }; |
| 311 | 311 |
| 312 // Decodes memory address Opnd, and encodes that information into Value, | 312 // Encodes memory address Opnd, and encodes that information into Value, based |
| 313 // based on how ARM represents the address. Returns how the value was encoded. | 313 // on how ARM represents the address. Returns how the value was encoded. |
| 314 DecodedResult decodeAddress(const Operand *Opnd, IValueT &Value, | 314 EncodedOperand encodeAddress(const Operand *Opnd, IValueT &Value, |
| 315 const AssemblerARM32::TargetInfo &TInfo, | 315 const AssemblerARM32::TargetInfo &TInfo, |
| 316 OpEncoding AddressEncoding = DefaultOpEncoding) { | 316 OpEncoding AddressEncoding = DefaultOpEncoding) { |
| 317 Value = 0; // Make sure initialized. | 317 Value = 0; // Make sure initialized. |
| 318 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { | 318 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { |
| 319 // Should be a stack variable, with an offset. | 319 // Should be a stack variable, with an offset. |
| 320 if (Var->hasReg()) | 320 if (Var->hasReg()) |
| 321 return CantDecode; | 321 return CantEncode; |
| 322 IOffsetT Offset = Var->getStackOffset(); | 322 IOffsetT Offset = Var->getStackOffset(); |
| 323 if (!Utils::IsAbsoluteUint(12, Offset)) | 323 if (!Utils::IsAbsoluteUint(12, Offset)) |
| 324 return CantDecode; | 324 return CantEncode; |
| 325 int32_t BaseRegNum = Var->getBaseRegNum(); | 325 int32_t BaseRegNum = Var->getBaseRegNum(); |
| 326 if (BaseRegNum == Variable::NoRegister) | 326 if (BaseRegNum == Variable::NoRegister) |
| 327 BaseRegNum = TInfo.FrameOrStackReg; | 327 BaseRegNum = TInfo.FrameOrStackReg; |
| 328 Value = encodeImmRegOffset(BaseRegNum, Offset, OperandARM32Mem::Offset); | 328 Value = encodeImmRegOffset(BaseRegNum, Offset, OperandARM32Mem::Offset); |
| 329 return DecodedAsImmRegOffset; | 329 return EncodedAsImmRegOffset; |
| 330 } | 330 } |
| 331 if (const auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Opnd)) { | 331 if (const auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Opnd)) { |
| 332 Variable *Var = Mem->getBase(); | 332 Variable *Var = Mem->getBase(); |
| 333 if (!Var->hasReg()) | 333 if (!Var->hasReg()) |
| 334 return CantDecode; | 334 return CantEncode; |
| 335 IValueT Rn = Var->getRegNum(); | 335 IValueT Rn = Var->getRegNum(); |
| 336 if (Mem->isRegReg()) { | 336 if (Mem->isRegReg()) { |
| 337 const Variable *Index = Mem->getIndex(); | 337 const Variable *Index = Mem->getIndex(); |
| 338 if (Var == nullptr) | 338 if (Var == nullptr) |
| 339 return CantDecode; | 339 return CantEncode; |
| 340 Value = (Rn << kRnShift) | Mem->getAddrMode() | | 340 Value = (Rn << kRnShift) | Mem->getAddrMode() | |
| 341 encodeShiftRotateImm5(Index->getRegNum(), Mem->getShiftOp(), | 341 encodeShiftRotateImm5(Index->getRegNum(), Mem->getShiftOp(), |
| 342 Mem->getShiftAmt()); | 342 Mem->getShiftAmt()); |
| 343 return DecodedAsShiftRotateImm5; | 343 return EncodedAsShiftRotateImm5; |
| 344 } | 344 } |
| 345 // Decoded as immediate register offset. | 345 // Encoded as immediate register offset. |
| 346 ConstantInteger32 *Offset = Mem->getOffset(); | 346 ConstantInteger32 *Offset = Mem->getOffset(); |
| 347 switch (AddressEncoding) { | 347 switch (AddressEncoding) { |
| 348 case DefaultOpEncoding: | 348 case DefaultOpEncoding: |
| 349 Value = encodeImmRegOffset(Rn, Offset->getValue(), Mem->getAddrMode()); | 349 Value = encodeImmRegOffset(Rn, Offset->getValue(), Mem->getAddrMode()); |
| 350 return DecodedAsImmRegOffset; | 350 return EncodedAsImmRegOffset; |
| 351 case OpEncoding3: | 351 case OpEncoding3: |
| 352 Value = | 352 Value = |
| 353 encodeImmRegOffsetEnc3(Rn, Offset->getValue(), Mem->getAddrMode()); | 353 encodeImmRegOffsetEnc3(Rn, Offset->getValue(), Mem->getAddrMode()); |
| 354 return DecodedAsImmRegOffsetEnc3; | 354 return EncodedAsImmRegOffsetEnc3; |
| 355 } | 355 } |
| 356 } | 356 } |
| 357 return CantDecode; | 357 return CantEncode; |
| 358 } | 358 } |
| 359 | 359 |
| 360 // Checks that Offset can fit in imm24 constant of branch (b) instruction. | 360 // Checks that Offset can fit in imm24 constant of branch (b) instruction. |
| 361 bool canEncodeBranchOffset(IOffsetT Offset) { | 361 bool canEncodeBranchOffset(IOffsetT Offset) { |
| 362 return Utils::IsAligned(Offset, 4) && | 362 return Utils::IsAligned(Offset, 4) && |
| 363 Utils::IsInt(kBranchOffsetBits, Offset >> 2); | 363 Utils::IsInt(kBranchOffsetBits, Offset >> 2); |
| 364 } | 364 } |
| 365 | 365 |
| 366 } // end of anonymous namespace | 366 } // end of anonymous namespace |
| 367 | 367 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 assert(IsGoodOffset); | 454 assert(IsGoodOffset); |
| 455 // Note: Following cast is for MINIMAL build. | 455 // Note: Following cast is for MINIMAL build. |
| 456 (void)IsGoodOffset; | 456 (void)IsGoodOffset; |
| 457 | 457 |
| 458 // Properly preserve only the bits supported in the instruction. | 458 // Properly preserve only the bits supported in the instruction. |
| 459 Offset >>= 2; | 459 Offset >>= 2; |
| 460 Offset &= kBranchOffsetMask; | 460 Offset &= kBranchOffsetMask; |
| 461 return (Inst & ~kBranchOffsetMask) | Offset; | 461 return (Inst & ~kBranchOffsetMask) | Offset; |
| 462 } | 462 } |
| 463 | 463 |
| 464 // Pull out offset from branch Inst. |
| 464 IOffsetT AssemblerARM32::decodeBranchOffset(IValueT Inst) { | 465 IOffsetT AssemblerARM32::decodeBranchOffset(IValueT Inst) { |
| 465 // Sign-extend, left-shift by 2, and adjust to the way ARM CPUs read PC. | 466 // Sign-extend, left-shift by 2, and adjust to the way ARM CPUs read PC. |
| 466 IOffsetT Offset = static_cast<IOffsetT>((Inst & kBranchOffsetMask) << 8); | 467 IOffsetT Offset = static_cast<IOffsetT>((Inst & kBranchOffsetMask) << 8); |
| 467 return (Offset >> 6) + kPCReadOffset; | 468 return (Offset >> 6) + kPCReadOffset; |
| 468 } | 469 } |
| 469 | 470 |
| 470 void AssemblerARM32::bind(Label *L) { | 471 void AssemblerARM32::bind(Label *L) { |
| 471 IOffsetT BoundPc = Buffer.size(); | 472 IOffsetT BoundPc = Buffer.size(); |
| 472 assert(!L->isBound()); // Labels can only be bound once. | 473 assert(!L->isBound()); // Labels can only be bound once. |
| 473 while (L->isLinked()) { | 474 while (L->isLinked()) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 (encodeBool(SetFlags) << kSShift) | | 512 (encodeBool(SetFlags) << kSShift) | |
| 512 (Rn << kRnShift) | (Rd << kRdShift) | Imm12; | 513 (Rn << kRnShift) | (Rd << kRdShift) | Imm12; |
| 513 emitInst(Encoding); | 514 emitInst(Encoding); |
| 514 } | 515 } |
| 515 | 516 |
| 516 void AssemblerARM32::emitType01(IValueT Opcode, const Operand *OpRd, | 517 void AssemblerARM32::emitType01(IValueT Opcode, const Operand *OpRd, |
| 517 const Operand *OpRn, const Operand *OpSrc1, | 518 const Operand *OpRn, const Operand *OpSrc1, |
| 518 bool SetFlags, CondARM32::Cond Cond, | 519 bool SetFlags, CondARM32::Cond Cond, |
| 519 EmitChecks RuleChecks) { | 520 EmitChecks RuleChecks) { |
| 520 IValueT Rd; | 521 IValueT Rd; |
| 521 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 522 if (encodeOperand(OpRd, Rd) != EncodedAsRegister) |
| 522 return setNeedsTextFixup(); | 523 return setNeedsTextFixup(); |
| 523 IValueT Rn; | 524 IValueT Rn; |
| 524 if (decodeOperand(OpRn, Rn) != DecodedAsRegister) | 525 if (encodeOperand(OpRn, Rn) != EncodedAsRegister) |
| 525 return setNeedsTextFixup(); | 526 return setNeedsTextFixup(); |
| 526 emitType01(Opcode, Rd, Rn, OpSrc1, SetFlags, Cond, RuleChecks); | 527 emitType01(Opcode, Rd, Rn, OpSrc1, SetFlags, Cond, RuleChecks); |
| 527 } | 528 } |
| 528 | 529 |
| 529 void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn, | 530 void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn, |
| 530 const Operand *OpSrc1, bool SetFlags, | 531 const Operand *OpSrc1, bool SetFlags, |
| 531 CondARM32::Cond Cond, EmitChecks RuleChecks) { | 532 CondARM32::Cond Cond, EmitChecks RuleChecks) { |
| 532 | 533 |
| 533 IValueT Src1Value; | 534 IValueT Src1Value; |
| 534 // TODO(kschimpf) Other possible decodings of data operations. | 535 // TODO(kschimpf) Other possible decodings of data operations. |
| 535 switch (decodeOperand(OpSrc1, Src1Value)) { | 536 switch (encodeOperand(OpSrc1, Src1Value)) { |
| 536 default: | 537 default: |
| 537 return setNeedsTextFixup(); | 538 return setNeedsTextFixup(); |
| 538 case DecodedAsRegister: { | 539 case EncodedAsRegister: { |
| 539 // XXX (register) | 540 // XXX (register) |
| 540 // xxx{s}<c> <Rd>, <Rn>, <Rm>{, <shiff>} | 541 // xxx{s}<c> <Rd>, <Rn>, <Rm>{, <shiff>} |
| 541 // | 542 // |
| 542 // cccc0000100snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn, | 543 // cccc0000100snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn, |
| 543 // mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags. | 544 // mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags. |
| 544 constexpr IValueT Imm5 = 0; | 545 constexpr IValueT Imm5 = 0; |
| 545 Src1Value = encodeShiftRotateImm5(Src1Value, OperandARM32::kNoShift, Imm5); | 546 Src1Value = encodeShiftRotateImm5(Src1Value, OperandARM32::kNoShift, Imm5); |
| 546 emitType01(Cond, kInstTypeDataRegister, Opcode, SetFlags, Rn, Rd, Src1Value, | 547 emitType01(Cond, kInstTypeDataRegister, Opcode, SetFlags, Rn, Rd, Src1Value, |
| 547 RuleChecks); | 548 RuleChecks); |
| 548 return; | 549 return; |
| 549 } | 550 } |
| 550 case DecodedAsShiftedRegister: { | 551 case EncodedAsShiftedRegister: { |
| 551 // Form is defined in case DecodedAsRegister. (i.e. XXX (register)). | 552 // Form is defined in case EncodedAsRegister. (i.e. XXX (register)). |
| 552 emitType01(Cond, kInstTypeDataRegister, Opcode, SetFlags, Rn, Rd, Src1Value, | 553 emitType01(Cond, kInstTypeDataRegister, Opcode, SetFlags, Rn, Rd, Src1Value, |
| 553 RuleChecks); | 554 RuleChecks); |
| 554 return; | 555 return; |
| 555 } | 556 } |
| 556 case DecodedAsConstI32: { | 557 case EncodedAsConstI32: { |
| 557 // See if we can convert this to an XXX (immediate). | 558 // See if we can convert this to an XXX (immediate). |
| 558 IValueT RotateAmt; | 559 IValueT RotateAmt; |
| 559 IValueT Imm8; | 560 IValueT Imm8; |
| 560 if (!OperandARM32FlexImm::canHoldImm(Src1Value, &RotateAmt, &Imm8)) | 561 if (!OperandARM32FlexImm::canHoldImm(Src1Value, &RotateAmt, &Imm8)) |
| 561 return setNeedsTextFixup(); | 562 return setNeedsTextFixup(); |
| 562 Src1Value = encodeRotatedImm8(RotateAmt, Imm8); | 563 Src1Value = encodeRotatedImm8(RotateAmt, Imm8); |
| 563 // Intentionally fall to next case! | 564 // Intentionally fall to next case! |
| 564 } | 565 } |
| 565 case DecodedAsRotatedImm8: { | 566 case EncodedAsRotatedImm8: { |
| 566 // XXX (Immediate) | 567 // XXX (Immediate) |
| 567 // xxx{s}<c> <Rd>, <Rn>, #<RotatedImm8> | 568 // xxx{s}<c> <Rd>, <Rn>, #<RotatedImm8> |
| 568 // | 569 // |
| 569 // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, | 570 // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, |
| 570 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. | 571 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. |
| 571 emitType01(Cond, kInstTypeDataImmediate, Opcode, SetFlags, Rn, Rd, | 572 emitType01(Cond, kInstTypeDataImmediate, Opcode, SetFlags, Rn, Rd, |
| 572 Src1Value, RuleChecks); | 573 Src1Value, RuleChecks); |
| 573 return; | 574 return; |
| 574 } | 575 } |
| 575 } | 576 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 // | 616 // |
| 616 // XXX (immediate) | 617 // XXX (immediate) |
| 617 // XXX<c> <Rn>, #<RotatedImm8> | 618 // XXX<c> <Rn>, #<RotatedImm8> |
| 618 // | 619 // |
| 619 // ccccyyyxxxx1nnnn0000iiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, | 620 // ccccyyyxxxx1nnnn0000iiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, |
| 620 // yyy=kInstTypeDataImmdiate, xxxx=Opcode, and iiiiiiiiiiii=Src1Value | 621 // yyy=kInstTypeDataImmdiate, xxxx=Opcode, and iiiiiiiiiiii=Src1Value |
| 621 // defining RotatedImm8. | 622 // defining RotatedImm8. |
| 622 constexpr bool SetFlags = true; | 623 constexpr bool SetFlags = true; |
| 623 constexpr IValueT Rd = RegARM32::Encoded_Reg_r0; | 624 constexpr IValueT Rd = RegARM32::Encoded_Reg_r0; |
| 624 IValueT Rn; | 625 IValueT Rn; |
| 625 if (decodeOperand(OpRn, Rn) != DecodedAsRegister) | 626 if (encodeOperand(OpRn, Rn) != EncodedAsRegister) |
| 626 return setNeedsTextFixup(); | 627 return setNeedsTextFixup(); |
| 627 emitType01(Opcode, Rd, Rn, OpSrc1, SetFlags, Cond, NoChecks); | 628 emitType01(Opcode, Rd, Rn, OpSrc1, SetFlags, Cond, NoChecks); |
| 628 } | 629 } |
| 629 | 630 |
| 630 void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, IValueT InstType, | 631 void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, IValueT InstType, |
| 631 bool IsLoad, bool IsByte, IValueT Rt, | 632 bool IsLoad, bool IsByte, IValueT Rt, |
| 632 IValueT Address) { | 633 IValueT Address) { |
| 633 if (!isGPRRegisterDefined(Rt) || !isConditionDefined(Cond)) | 634 if (!isGPRRegisterDefined(Rt) || !isConditionDefined(Cond)) |
| 634 return setNeedsTextFixup(); | 635 return setNeedsTextFixup(); |
| 635 AssemblerBuffer::EnsureCapacity ensured(&Buffer); | 636 AssemblerBuffer::EnsureCapacity ensured(&Buffer); |
| 636 const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | | 637 const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | |
| 637 (InstType << kTypeShift) | (IsLoad ? L : 0) | | 638 (InstType << kTypeShift) | (IsLoad ? L : 0) | |
| 638 (IsByte ? B : 0) | (Rt << kRdShift) | Address; | 639 (IsByte ? B : 0) | (Rt << kRdShift) | Address; |
| 639 emitInst(Encoding); | 640 emitInst(Encoding); |
| 640 } | 641 } |
| 641 | 642 |
| 642 void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte, | 643 void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte, |
| 643 IValueT Rt, const Operand *OpAddress, | 644 IValueT Rt, const Operand *OpAddress, |
| 644 const TargetInfo &TInfo) { | 645 const TargetInfo &TInfo) { |
| 645 IValueT Address; | 646 IValueT Address; |
| 646 switch (decodeAddress(OpAddress, Address, TInfo)) { | 647 switch (encodeAddress(OpAddress, Address, TInfo)) { |
| 647 default: | 648 default: |
| 648 return setNeedsTextFixup(); | 649 return setNeedsTextFixup(); |
| 649 case DecodedAsImmRegOffset: { | 650 case EncodedAsImmRegOffset: { |
| 650 // XXX{B} (immediate): | 651 // XXX{B} (immediate): |
| 651 // xxx{b}<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 | 652 // xxx{b}<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 |
| 652 // xxx{b}<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 | 653 // xxx{b}<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 |
| 653 // xxx{b}<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 | 654 // xxx{b}<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 |
| 654 // | 655 // |
| 655 // cccc010pubwlnnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn, | 656 // cccc010pubwlnnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn, |
| 656 // iiiiiiiiiiii=imm12, b=IsByte, pu0w<<21 is a BlockAddr, l=IsLoad, and | 657 // iiiiiiiiiiii=imm12, b=IsByte, pu0w<<21 is a BlockAddr, l=IsLoad, and |
| 657 // pu0w0nnnn0000iiiiiiiiiiii=Address. | 658 // pu0w0nnnn0000iiiiiiiiiiii=Address. |
| 658 RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address); | 659 RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address); |
| 659 | 660 |
| 660 // Check if conditions of rules violated. | 661 // Check if conditions of rules violated. |
| 661 if (Rn == RegARM32::Encoded_Reg_pc) | 662 if (Rn == RegARM32::Encoded_Reg_pc) |
| 662 return setNeedsTextFixup(); | 663 return setNeedsTextFixup(); |
| 663 if (!isBitSet(P, Address) && isBitSet(W, Address)) | 664 if (!isBitSet(P, Address) && isBitSet(W, Address)) |
| 664 return setNeedsTextFixup(); | 665 return setNeedsTextFixup(); |
| 665 if (!IsByte && (Rn == RegARM32::Encoded_Reg_sp) && !isBitSet(P, Address) && | 666 if (!IsByte && (Rn == RegARM32::Encoded_Reg_sp) && !isBitSet(P, Address) && |
| 666 isBitSet(U, Address) & !isBitSet(W, Address) && | 667 isBitSet(U, Address) & !isBitSet(W, Address) && |
| 667 (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */)) | 668 (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */)) |
| 668 return setNeedsTextFixup(); | 669 return setNeedsTextFixup(); |
| 669 | 670 |
| 670 return emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address); | 671 return emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address); |
| 671 } | 672 } |
| 672 case DecodedAsShiftRotateImm5: { | 673 case EncodedAsShiftRotateImm5: { |
| 673 // XXX{B} (register) | 674 // XXX{B} (register) |
| 674 // xxx{b}<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!} | 675 // xxx{b}<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!} |
| 675 // xxx{b}<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>} | 676 // xxx{b}<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>} |
| 676 // | 677 // |
| 677 // cccc011pubwlnnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt, | 678 // cccc011pubwlnnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt, |
| 678 // b=IsByte, U=1 if +, pu0b is a BlockAddr, l=IsLoad, and | 679 // b=IsByte, U=1 if +, pu0b is a BlockAddr, l=IsLoad, and |
| 679 // pu0w0nnnn0000iiiiiss0mmmm=Address. | 680 // pu0w0nnnn0000iiiiiss0mmmm=Address. |
| 680 RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address); | 681 RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address); |
| 681 RegARM32::GPRRegister Rm = getGPRReg(kRmShift, Address); | 682 RegARM32::GPRRegister Rm = getGPRReg(kRmShift, Address); |
| 682 | 683 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 698 | 699 |
| 699 return emitMemOp(Cond, kInstTypeRegisterShift, IsLoad, IsByte, Rt, Address); | 700 return emitMemOp(Cond, kInstTypeRegisterShift, IsLoad, IsByte, Rt, Address); |
| 700 } | 701 } |
| 701 } | 702 } |
| 702 } | 703 } |
| 703 | 704 |
| 704 void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, | 705 void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, |
| 705 IValueT Rt, const Operand *OpAddress, | 706 IValueT Rt, const Operand *OpAddress, |
| 706 const TargetInfo &TInfo) { | 707 const TargetInfo &TInfo) { |
| 707 IValueT Address; | 708 IValueT Address; |
| 708 switch (decodeAddress(OpAddress, Address, TInfo, OpEncoding3)) { | 709 switch (encodeAddress(OpAddress, Address, TInfo, OpEncoding3)) { |
| 709 default: | 710 default: |
| 710 return setNeedsTextFixup(); | 711 return setNeedsTextFixup(); |
| 711 case DecodedAsImmRegOffsetEnc3: { | 712 case EncodedAsImmRegOffsetEnc3: { |
| 712 // XXXH (immediate) | 713 // XXXH (immediate) |
| 713 // xxxh<c> <Rt>, [<Rn>{, #+-<Imm8>}] | 714 // xxxh<c> <Rt>, [<Rn>{, #+-<Imm8>}] |
| 714 // xxxh<c> <Rt>, [<Rn>, #+/-<Imm8>] | 715 // xxxh<c> <Rt>, [<Rn>, #+/-<Imm8>] |
| 715 // xxxh<c> <Rt>, [<Rn>, #+/-<Imm8>]! | 716 // xxxh<c> <Rt>, [<Rn>, #+/-<Imm8>]! |
| 716 // | 717 // |
| 717 // cccc000pu0wxnnnnttttiiiiyyyyjjjj where cccc=Cond, nnnn=Rn, tttt=Rt, | 718 // cccc000pu0wxnnnnttttiiiiyyyyjjjj where cccc=Cond, nnnn=Rn, tttt=Rt, |
| 718 // iiiijjjj=Imm8, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode, | 719 // iiiijjjj=Imm8, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode, |
| 719 // and pu0w0nnnn0000iiii0000jjjj=Address. | 720 // and pu0w0nnnn0000iiii0000jjjj=Address. |
| 720 if (!isGPRRegisterDefined(Rt) || !isConditionDefined(Cond)) | 721 if (!isGPRRegisterDefined(Rt) || !isConditionDefined(Cond)) |
| 721 return setNeedsTextFixup(); | 722 return setNeedsTextFixup(); |
| 722 if (!isBitSet(P, Address) && isBitSet(W, Address)) | 723 if (!isBitSet(P, Address) && isBitSet(W, Address)) |
| 723 return setNeedsTextFixup(); | 724 return setNeedsTextFixup(); |
| 724 if ((Rt == RegARM32::Encoded_Reg_pc) || | 725 if ((Rt == RegARM32::Encoded_Reg_pc) || |
| 725 (isBitSet(W, Address) && | 726 (isBitSet(W, Address) && |
| 726 (getGPRReg(kRnShift, Address) == decodeGPRRegister(Rt)))) | 727 (getGPRReg(kRnShift, Address) == decodeGPRRegister(Rt)))) |
| 727 return setNeedsTextFixup(); | 728 return setNeedsTextFixup(); |
| 728 const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | | 729 const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | |
| 729 Opcode | (Rt << kRdShift) | Address; | 730 Opcode | (Rt << kRdShift) | Address; |
| 730 AssemblerBuffer::EnsureCapacity ensured(&Buffer); | 731 AssemblerBuffer::EnsureCapacity ensured(&Buffer); |
| 731 return emitInst(Encoding); | 732 return emitInst(Encoding); |
| 732 } | 733 } |
| 733 case DecodedAsShiftRotateImm5: { | 734 case EncodedAsShiftRotateImm5: { |
| 734 // XXXH (register) | 735 // XXXH (register) |
| 735 // xxxh<c> <Rt>, [<Rn>, +/-<Rm>]{!} | 736 // xxxh<c> <Rt>, [<Rn>, +/-<Rm>]{!} |
| 736 // xxxh<c> <Rt>, [<Rn>], +/-<Rm> | 737 // xxxh<c> <Rt>, [<Rn>], +/-<Rm> |
| 737 // | 738 // |
| 738 // cccc000pu0wxnnnntttt00001011mmmm where cccc=Cond, tttt=Rt, nnnn=Rn, | 739 // cccc000pu0wxnnnntttt00001011mmmm where cccc=Cond, tttt=Rt, nnnn=Rn, |
| 739 // mmmm=Rm, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode, and | 740 // mmmm=Rm, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode, and |
| 740 // pu0w0nnnn000000000000mmmm=Address. | 741 // pu0w0nnnn000000000000mmmm=Address. |
| 741 if (!isGPRRegisterDefined(Rt) || !isConditionDefined(Cond)) | 742 if (!isGPRRegisterDefined(Rt) || !isConditionDefined(Cond)) |
| 742 return setNeedsTextFixup(); | 743 return setNeedsTextFixup(); |
| 743 if (!isBitSet(P, Address) && isBitSet(W, Address)) | 744 if (!isBitSet(P, Address) && isBitSet(W, Address)) |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 914 // and iiiiiiiiiiiiiiiiiiiiiiii is the (encoded) Target to branch to. | 915 // and iiiiiiiiiiiiiiiiiiiiiiii is the (encoded) Target to branch to. |
| 915 emitFixup(createBlFixup(Target)); | 916 emitFixup(createBlFixup(Target)); |
| 916 constexpr CondARM32::Cond Cond = CondARM32::AL; | 917 constexpr CondARM32::Cond Cond = CondARM32::AL; |
| 917 constexpr IValueT Immed = 0; | 918 constexpr IValueT Immed = 0; |
| 918 constexpr bool Link = true; | 919 constexpr bool Link = true; |
| 919 emitType05(Cond, Immed, Link); | 920 emitType05(Cond, Immed, Link); |
| 920 } | 921 } |
| 921 | 922 |
| 922 void AssemblerARM32::blx(const Operand *Target) { | 923 void AssemblerARM32::blx(const Operand *Target) { |
| 923 IValueT Rm; | 924 IValueT Rm; |
| 924 if (decodeOperand(Target, Rm) != DecodedAsRegister) | 925 if (encodeOperand(Target, Rm) != EncodedAsRegister) |
| 925 return setNeedsTextFixup(); | 926 return setNeedsTextFixup(); |
| 926 // BLX (register) - ARM section A8.8.26, encoding A1: | 927 // BLX (register) - ARM section A8.8.26, encoding A1: |
| 927 // blx<c> <Rm> | 928 // blx<c> <Rm> |
| 928 // | 929 // |
| 929 // cccc000100101111111111110011mmmm where cccc=Cond (not currently allowed) | 930 // cccc000100101111111111110011mmmm where cccc=Cond (not currently allowed) |
| 930 // and mmmm=Rm. | 931 // and mmmm=Rm. |
| 931 if (Rm == RegARM32::Encoded_Reg_pc) | 932 if (Rm == RegARM32::Encoded_Reg_pc) |
| 932 // Unpredictable. | 933 // Unpredictable. |
| 933 return setNeedsTextFixup(); | 934 return setNeedsTextFixup(); |
| 934 AssemblerBuffer::EnsureCapacity ensured(&Buffer); | 935 AssemblerBuffer::EnsureCapacity ensured(&Buffer); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 984 // cccc0010001snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, | 985 // cccc0010001snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, |
| 985 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. | 986 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. |
| 986 constexpr IValueT Eor = B0; // 0001 | 987 constexpr IValueT Eor = B0; // 0001 |
| 987 emitType01(Eor, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags); | 988 emitType01(Eor, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags); |
| 988 } | 989 } |
| 989 | 990 |
| 990 void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, | 991 void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, |
| 991 CondARM32::Cond Cond, const TargetInfo &TInfo) { | 992 CondARM32::Cond Cond, const TargetInfo &TInfo) { |
| 992 constexpr bool IsLoad = true; | 993 constexpr bool IsLoad = true; |
| 993 IValueT Rt; | 994 IValueT Rt; |
| 994 if (decodeOperand(OpRt, Rt) != DecodedAsRegister) | 995 if (encodeOperand(OpRt, Rt) != EncodedAsRegister) |
| 995 return setNeedsTextFixup(); | 996 return setNeedsTextFixup(); |
| 996 const Type Ty = OpRt->getType(); | 997 const Type Ty = OpRt->getType(); |
| 997 switch (typeWidthInBytesLog2(Ty)) { | 998 switch (typeWidthInBytesLog2(Ty)) { |
| 998 case 3: | 999 case 3: |
| 999 // LDRD is not implemented because target lowering handles i64 and double by | 1000 // LDRD is not implemented because target lowering handles i64 and double by |
| 1000 // using two (32-bit) load instructions. Note: Intenionally drop to default | 1001 // using two (32-bit) load instructions. Note: Intenionally drop to default |
| 1001 // case. | 1002 // case. |
| 1002 default: | 1003 default: |
| 1003 llvm::report_fatal_error(std::string("Type ") + typeString(Ty) + | 1004 llvm::report_fatal_error(std::string("Type ") + typeString(Ty) + |
| 1004 " not implementable using ldr\n"); | 1005 " not implementable using ldr\n"); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1059 } | 1060 } |
| 1060 } | 1061 } |
| 1061 } | 1062 } |
| 1062 | 1063 |
| 1063 void AssemblerARM32::lsl(const Operand *OpRd, const Operand *OpRm, | 1064 void AssemblerARM32::lsl(const Operand *OpRd, const Operand *OpRm, |
| 1064 const Operand *OpSrc1, bool SetFlags, | 1065 const Operand *OpSrc1, bool SetFlags, |
| 1065 CondARM32::Cond Cond) { | 1066 CondARM32::Cond Cond) { |
| 1066 constexpr IValueT Lsl = B3 | B2 | B0; // 1101 | 1067 constexpr IValueT Lsl = B3 | B2 | B0; // 1101 |
| 1067 constexpr IValueT Rn = 0; // Rn field is not used. | 1068 constexpr IValueT Rn = 0; // Rn field is not used. |
| 1068 IValueT Rd; | 1069 IValueT Rd; |
| 1069 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 1070 if (encodeOperand(OpRd, Rd) != EncodedAsRegister) |
| 1070 return setNeedsTextFixup(); | 1071 return setNeedsTextFixup(); |
| 1071 IValueT Rm; | 1072 IValueT Rm; |
| 1072 if (decodeOperand(OpRm, Rm) != DecodedAsRegister) | 1073 if (encodeOperand(OpRm, Rm) != EncodedAsRegister) |
| 1073 return setNeedsTextFixup(); | 1074 return setNeedsTextFixup(); |
| 1074 IValueT Value; | 1075 IValueT Value; |
| 1075 switch (decodeOperand(OpSrc1, Value)) { | 1076 switch (encodeOperand(OpSrc1, Value)) { |
| 1076 default: | 1077 default: |
| 1077 return setNeedsTextFixup(); | 1078 return setNeedsTextFixup(); |
| 1078 case DecodedAsShiftImm5: { | 1079 case EncodedAsShiftImm5: { |
| 1079 // LSL (immediate) - ARM section A8.8.94, encoding A1: | 1080 // LSL (immediate) - ARM section A8.8.94, encoding A1: |
| 1080 // lsl{s}<c> <Rd>, <Rm>, #imm5 | 1081 // lsl{s}<c> <Rd>, <Rm>, #imm5 |
| 1081 // | 1082 // |
| 1082 // cccc0001101s0000ddddiiiii000mmmm where cccc=Cond, s=SetFlags, dddd=Rd, | 1083 // cccc0001101s0000ddddiiiii000mmmm where cccc=Cond, s=SetFlags, dddd=Rd, |
| 1083 // iiiii=imm5, and mmmm=Rm. | 1084 // iiiii=imm5, and mmmm=Rm. |
| 1084 Value = Value | (Rm << kRmShift); | 1085 Value = Value | (Rm << kRmShift); |
| 1085 emitType01(Cond, kInstTypeDataRegShift, Lsl, SetFlags, Rn, Rd, Value, | 1086 emitType01(Cond, kInstTypeDataRegShift, Lsl, SetFlags, Rn, Rd, Value, |
| 1086 RdIsPcAndSetFlags); | 1087 RdIsPcAndSetFlags); |
| 1087 return; | 1088 return; |
| 1088 } | 1089 } |
| 1089 case DecodedAsRegister: { | 1090 case EncodedAsRegister: { |
| 1090 // LSL (register) - ARM section A8.8.95, encoding A1: | 1091 // LSL (register) - ARM section A8.8.95, encoding A1: |
| 1091 // lsl{S}<c> <Rd>, <Rm>, <Rs> | 1092 // lsl{S}<c> <Rd>, <Rm>, <Rs> |
| 1092 // | 1093 // |
| 1093 // cccc0001101s0000ddddssss0001mmmm where cccc=Cond, s=SetFlags, dddd=Rd, | 1094 // cccc0001101s0000ddddssss0001mmmm where cccc=Cond, s=SetFlags, dddd=Rd, |
| 1094 // mmmm=Rm, and ssss=Rs. | 1095 // mmmm=Rm, and ssss=Rs. |
| 1095 IValueT Rs; | 1096 IValueT Rs; |
| 1096 if (decodeOperand(OpSrc1, Rs) != DecodedAsRegister) | 1097 if (encodeOperand(OpSrc1, Rs) != EncodedAsRegister) |
| 1097 return setNeedsTextFixup(); | 1098 return setNeedsTextFixup(); |
| 1098 if ((Rd == RegARM32::Encoded_Reg_pc) || (Rm == RegARM32::Encoded_Reg_pc) || | 1099 if ((Rd == RegARM32::Encoded_Reg_pc) || (Rm == RegARM32::Encoded_Reg_pc) || |
| 1099 (Rs == RegARM32::Encoded_Reg_pc)) | 1100 (Rs == RegARM32::Encoded_Reg_pc)) |
| 1100 setNeedsTextFixup(); | 1101 setNeedsTextFixup(); |
| 1101 emitType01(Cond, kInstTypeDataRegShift, Lsl, SetFlags, Rn, Rd, | 1102 emitType01(Cond, kInstTypeDataRegShift, Lsl, SetFlags, Rn, Rd, |
| 1102 encodeShiftRotateReg(Rm, OperandARM32::kNoShift, Rs), NoChecks); | 1103 encodeShiftRotateReg(Rm, OperandARM32::kNoShift, Rs), NoChecks); |
| 1103 return; | 1104 return; |
| 1104 } | 1105 } |
| 1105 } | 1106 } |
| 1106 } | 1107 } |
| 1107 | 1108 |
| 1108 void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, | 1109 void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, |
| 1109 CondARM32::Cond Cond) { | 1110 CondARM32::Cond Cond) { |
| 1110 // MOV (register) - ARM section A8.8.104, encoding A1: | 1111 // MOV (register) - ARM section A8.8.104, encoding A1: |
| 1111 // mov{S}<c> <Rd>, <Rn> | 1112 // mov{S}<c> <Rd>, <Rn> |
| 1112 // | 1113 // |
| 1113 // cccc0001101s0000dddd00000000mmmm where cccc=Cond, s=SetFlags, dddd=Rd, | 1114 // cccc0001101s0000dddd00000000mmmm where cccc=Cond, s=SetFlags, dddd=Rd, |
| 1114 // and nnnn=Rn. | 1115 // and nnnn=Rn. |
| 1115 // | 1116 // |
| 1116 // MOV (immediate) - ARM section A8.8.102, encoding A1: | 1117 // MOV (immediate) - ARM section A8.8.102, encoding A1: |
| 1117 // mov{S}<c> <Rd>, #<RotatedImm8> | 1118 // mov{S}<c> <Rd>, #<RotatedImm8> |
| 1118 // | 1119 // |
| 1119 // cccc0011101s0000ddddiiiiiiiiiiii where cccc=Cond, s=SetFlags, dddd=Rd, | 1120 // cccc0011101s0000ddddiiiiiiiiiiii where cccc=Cond, s=SetFlags, dddd=Rd, |
| 1120 // and iiiiiiiiiiii=RotatedImm8=Src. Note: We don't use movs in this | 1121 // and iiiiiiiiiiii=RotatedImm8=Src. Note: We don't use movs in this |
| 1121 // assembler. | 1122 // assembler. |
| 1122 IValueT Rd; | 1123 IValueT Rd; |
| 1123 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 1124 if (encodeOperand(OpRd, Rd) != EncodedAsRegister) |
| 1124 return setNeedsTextFixup(); | 1125 return setNeedsTextFixup(); |
| 1125 constexpr bool SetFlags = false; | 1126 constexpr bool SetFlags = false; |
| 1126 constexpr IValueT Rn = 0; | 1127 constexpr IValueT Rn = 0; |
| 1127 constexpr IValueT Mov = B3 | B2 | B0; // 1101. | 1128 constexpr IValueT Mov = B3 | B2 | B0; // 1101. |
| 1128 emitType01(Mov, Rd, Rn, OpSrc, SetFlags, Cond, RdIsPcAndSetFlags); | 1129 emitType01(Mov, Rd, Rn, OpSrc, SetFlags, Cond, RdIsPcAndSetFlags); |
| 1129 } | 1130 } |
| 1130 | 1131 |
| 1131 void AssemblerARM32::emitMovw(IValueT Opcode, IValueT Rd, IValueT Imm16, | 1132 void AssemblerARM32::emitMovw(IValueT Opcode, IValueT Rd, IValueT Imm16, |
| 1132 bool SetFlags, CondARM32::Cond Cond) { | 1133 bool SetFlags, CondARM32::Cond Cond) { |
| 1133 if (!isConditionDefined(Cond) || !Utils::IsAbsoluteUint(16, Imm16)) | 1134 if (!isConditionDefined(Cond) || !Utils::IsAbsoluteUint(16, Imm16)) |
| 1134 return setNeedsTextFixup(); | 1135 return setNeedsTextFixup(); |
| 1135 AssemblerBuffer::EnsureCapacity ensured(&Buffer); | 1136 AssemblerBuffer::EnsureCapacity ensured(&Buffer); |
| 1136 const IValueT Encoding = encodeCondition(Cond) << kConditionShift | Opcode | | 1137 const IValueT Encoding = encodeCondition(Cond) << kConditionShift | Opcode | |
| 1137 (encodeBool(SetFlags) << kSShift) | | 1138 (encodeBool(SetFlags) << kSShift) | |
| 1138 ((Imm16 >> 12) << 16) | Rd << kRdShift | | 1139 ((Imm16 >> 12) << 16) | Rd << kRdShift | |
| 1139 (Imm16 & 0xfff); | 1140 (Imm16 & 0xfff); |
| 1140 emitInst(Encoding); | 1141 emitInst(Encoding); |
| 1141 } | 1142 } |
| 1142 | 1143 |
| 1143 void AssemblerARM32::movw(const Operand *OpRd, const Operand *OpSrc, | 1144 void AssemblerARM32::movw(const Operand *OpRd, const Operand *OpSrc, |
| 1144 CondARM32::Cond Cond) { | 1145 CondARM32::Cond Cond) { |
| 1145 IValueT Rd; | 1146 IValueT Rd; |
| 1146 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 1147 if (encodeOperand(OpRd, Rd) != EncodedAsRegister) |
| 1147 return setNeedsTextFixup(); | 1148 return setNeedsTextFixup(); |
| 1148 if (const auto *Src = llvm::dyn_cast<ConstantRelocatable>(OpSrc)) { | 1149 if (const auto *Src = llvm::dyn_cast<ConstantRelocatable>(OpSrc)) { |
| 1149 // MOVW (immediate) - ARM section A8.8.102, encoding A2: | 1150 // MOVW (immediate) - ARM section A8.8.102, encoding A2: |
| 1150 // movw<c> <Rd>, #<imm16> | 1151 // movw<c> <Rd>, #<imm16> |
| 1151 // | 1152 // |
| 1152 // cccc00110000iiiiddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, and | 1153 // cccc00110000iiiiddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, and |
| 1153 // iiiiiiiiiiiiiiii=imm16. | 1154 // iiiiiiiiiiiiiiii=imm16. |
| 1154 if (!isConditionDefined(Cond)) | 1155 if (!isConditionDefined(Cond)) |
| 1155 // Conditions of rule violated. | 1156 // Conditions of rule violated. |
| 1156 return setNeedsTextFixup(); | 1157 return setNeedsTextFixup(); |
| 1157 // Use 0 for the lower 16 bits of the relocatable, and add a fixup to | 1158 // Use 0 for the lower 16 bits of the relocatable, and add a fixup to |
| 1158 // install the correct bits. | 1159 // install the correct bits. |
| 1159 constexpr bool IsMovW = true; | 1160 constexpr bool IsMovW = true; |
| 1160 emitFixup(createMoveFixup(IsMovW, Src)); | 1161 emitFixup(createMoveFixup(IsMovW, Src)); |
| 1161 constexpr IValueT Imm16 = 0; | 1162 constexpr IValueT Imm16 = 0; |
| 1162 constexpr bool SetFlags = false; | 1163 constexpr bool SetFlags = false; |
| 1163 emitMovw(B25 | B24, Rd, Imm16, SetFlags, Cond); | 1164 emitMovw(B25 | B24, Rd, Imm16, SetFlags, Cond); |
| 1164 return; | 1165 return; |
| 1165 } | 1166 } |
| 1166 IValueT ConstVal; | 1167 IValueT ConstVal; |
| 1167 if (decodeOperand(OpSrc, ConstVal) != DecodedAsConstI32) | 1168 if (encodeOperand(OpSrc, ConstVal) != EncodedAsConstI32) |
| 1168 return setNeedsTextFixup(); | 1169 return setNeedsTextFixup(); |
| 1169 // TODO(kschimpf): Determine if we want to handle rotated immediate 8 values | 1170 // TODO(kschimpf): Determine if we want to handle rotated immediate 8 values |
| 1170 // to handle cases where the constant is greater than 16 bits (encoding A1 | 1171 // to handle cases where the constant is greater than 16 bits (encoding A1 |
| 1171 // below). For now, handle using encoding A2. | 1172 // below). For now, handle using encoding A2. |
| 1172 constexpr bool SetFlags = 0; | 1173 constexpr bool SetFlags = 0; |
| 1173 emitMovw(B25 | B24, Rd, ConstVal, SetFlags, Cond); | 1174 emitMovw(B25 | B24, Rd, ConstVal, SetFlags, Cond); |
| 1174 return; | 1175 return; |
| 1175 | 1176 |
| 1176 // MOVW (immediate) - ARM section A8.8.102, encoding A1: | 1177 // MOVW (immediate) - ARM section A8.8.102, encoding A1: |
| 1177 // movw<c> <Rd>, #<RotatedImm8> | 1178 // movw<c> <Rd>, #<RotatedImm8> |
| 1178 // | 1179 // |
| 1179 // cccc0011101s0000ddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, s=SetFlags=0, | 1180 // cccc0011101s0000ddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, s=SetFlags=0, |
| 1180 // and iiiiiiiiiiii is a shift-rotated value defining RotatedImm8. | 1181 // and iiiiiiiiiiii is a shift-rotated value defining RotatedImm8. |
| 1181 } | 1182 } |
| 1182 | 1183 |
| 1183 void AssemblerARM32::movt(const Operand *OpRd, const Operand *OpSrc, | 1184 void AssemblerARM32::movt(const Operand *OpRd, const Operand *OpSrc, |
| 1184 CondARM32::Cond Cond) { | 1185 CondARM32::Cond Cond) { |
| 1185 IValueT Rd; | 1186 IValueT Rd; |
| 1186 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 1187 if (encodeOperand(OpRd, Rd) != EncodedAsRegister) |
| 1187 return setNeedsTextFixup(); | 1188 return setNeedsTextFixup(); |
| 1188 auto *Src = llvm::dyn_cast<ConstantRelocatable>(OpSrc); | 1189 auto *Src = llvm::dyn_cast<ConstantRelocatable>(OpSrc); |
| 1189 if (Src == nullptr) | 1190 if (Src == nullptr) |
| 1190 return setNeedsTextFixup(); | 1191 return setNeedsTextFixup(); |
| 1191 // MOVT - ARM section A8.8.102, encoding A2: | 1192 // MOVT - ARM section A8.8.102, encoding A2: |
| 1192 // movt<c> <Rd>, #<imm16> | 1193 // movt<c> <Rd>, #<imm16> |
| 1193 // | 1194 // |
| 1194 // cccc00110100iiiiddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, and | 1195 // cccc00110100iiiiddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, and |
| 1195 // iiiiiiiiiiiiiiii=imm16. | 1196 // iiiiiiiiiiiiiiii=imm16. |
| 1196 if (!isConditionDefined(Cond)) | 1197 if (!isConditionDefined(Cond)) |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1215 // | 1216 // |
| 1216 // cccc0011111s0000ddddiiiiiiiiiiii where cccc=Cond, s=SetFlags=0, dddd=Rd, | 1217 // cccc0011111s0000ddddiiiiiiiiiiii where cccc=Cond, s=SetFlags=0, dddd=Rd, |
| 1217 // and iiiiiiiiiiii=const | 1218 // and iiiiiiiiiiii=const |
| 1218 // | 1219 // |
| 1219 // MVN (register) - ARM section A8.8.116, encoding A1: | 1220 // MVN (register) - ARM section A8.8.116, encoding A1: |
| 1220 // mvn{s}<c> <Rd>, <Rm>{, <shift> | 1221 // mvn{s}<c> <Rd>, <Rm>{, <shift> |
| 1221 // | 1222 // |
| 1222 // cccc0001111s0000ddddiiiiitt0mmmm where cccc=Cond, s=SetFlags=0, dddd=Rd, | 1223 // cccc0001111s0000ddddiiiiitt0mmmm where cccc=Cond, s=SetFlags=0, dddd=Rd, |
| 1223 // mmmm=Rm, iiii defines shift constant, and tt=ShiftKind. | 1224 // mmmm=Rm, iiii defines shift constant, and tt=ShiftKind. |
| 1224 IValueT Rd; | 1225 IValueT Rd; |
| 1225 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 1226 if (encodeOperand(OpRd, Rd) != EncodedAsRegister) |
| 1226 return setNeedsTextFixup(); | 1227 return setNeedsTextFixup(); |
| 1227 constexpr IValueT MvnOpcode = B3 | B2 | B1 | B0; // i.e. 1111 | 1228 constexpr IValueT MvnOpcode = B3 | B2 | B1 | B0; // i.e. 1111 |
| 1228 constexpr IValueT Rn = 0; | 1229 constexpr IValueT Rn = 0; |
| 1229 constexpr bool SetFlags = false; | 1230 constexpr bool SetFlags = false; |
| 1230 emitType01(MvnOpcode, Rd, Rn, OpSrc, SetFlags, Cond, RdIsPcAndSetFlags); | 1231 emitType01(MvnOpcode, Rd, Rn, OpSrc, SetFlags, Cond, RdIsPcAndSetFlags); |
| 1231 } | 1232 } |
| 1232 | 1233 |
| 1233 void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn, | 1234 void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn, |
| 1234 const Operand *OpSrc1, bool SetFlags, | 1235 const Operand *OpSrc1, bool SetFlags, |
| 1235 CondARM32::Cond Cond) { | 1236 CondARM32::Cond Cond) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1249 } | 1250 } |
| 1250 | 1251 |
| 1251 void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn, | 1252 void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn, |
| 1252 const Operand *OpSrc1, CondARM32::Cond Cond) { | 1253 const Operand *OpSrc1, CondARM32::Cond Cond) { |
| 1253 // SDIV - ARM section A8.8.165, encoding A1. | 1254 // SDIV - ARM section A8.8.165, encoding A1. |
| 1254 // sdiv<c> <Rd>, <Rn>, <Rm> | 1255 // sdiv<c> <Rd>, <Rn>, <Rm> |
| 1255 // | 1256 // |
| 1256 // cccc01110001dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and | 1257 // cccc01110001dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and |
| 1257 // mmmm=Rm. | 1258 // mmmm=Rm. |
| 1258 IValueT Rd; | 1259 IValueT Rd; |
| 1259 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 1260 if (encodeOperand(OpRd, Rd) != EncodedAsRegister) |
| 1260 return setNeedsTextFixup(); | 1261 return setNeedsTextFixup(); |
| 1261 IValueT Rn; | 1262 IValueT Rn; |
| 1262 if (decodeOperand(OpRn, Rn) != DecodedAsRegister) | 1263 if (encodeOperand(OpRn, Rn) != EncodedAsRegister) |
| 1263 return setNeedsTextFixup(); | 1264 return setNeedsTextFixup(); |
| 1264 IValueT Rm; | 1265 IValueT Rm; |
| 1265 if (decodeOperand(OpSrc1, Rm) != DecodedAsRegister) | 1266 if (encodeOperand(OpSrc1, Rm) != EncodedAsRegister) |
| 1266 return setNeedsTextFixup(); | 1267 return setNeedsTextFixup(); |
| 1267 if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc || | 1268 if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc || |
| 1268 Rm == RegARM32::Encoded_Reg_pc) | 1269 Rm == RegARM32::Encoded_Reg_pc) |
| 1269 llvm::report_fatal_error("Sdiv instruction unpredictable on pc"); | 1270 llvm::report_fatal_error("Sdiv instruction unpredictable on pc"); |
| 1270 // Assembler registers rd, rn, rm are encoded as rn, rm, rs. | 1271 // Assembler registers rd, rn, rm are encoded as rn, rm, rs. |
| 1271 constexpr IValueT Opcode = 0; | 1272 constexpr IValueT Opcode = 0; |
| 1272 emitDivOp(Cond, Opcode, Rd, Rn, Rm); | 1273 emitDivOp(Cond, Opcode, Rd, Rn, Rm); |
| 1273 } | 1274 } |
| 1274 | 1275 |
| 1275 void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, | 1276 void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, |
| 1276 CondARM32::Cond Cond, const TargetInfo &TInfo) { | 1277 CondARM32::Cond Cond, const TargetInfo &TInfo) { |
| 1277 constexpr bool IsLoad = false; | 1278 constexpr bool IsLoad = false; |
| 1278 IValueT Rt; | 1279 IValueT Rt; |
| 1279 if (decodeOperand(OpRt, Rt) != DecodedAsRegister) | 1280 if (encodeOperand(OpRt, Rt) != EncodedAsRegister) |
| 1280 return setNeedsTextFixup(); | 1281 return setNeedsTextFixup(); |
| 1281 const Type Ty = OpRt->getType(); | 1282 const Type Ty = OpRt->getType(); |
| 1282 switch (typeWidthInBytesLog2(Ty)) { | 1283 switch (typeWidthInBytesLog2(Ty)) { |
| 1283 case 3: | 1284 case 3: |
| 1284 // STRD is not implemented because target lowering handles i64 and double by | 1285 // STRD is not implemented because target lowering handles i64 and double by |
| 1285 // using two (32-bit) store instructions. Note: Intenionally drop to | 1286 // using two (32-bit) store instructions. Note: Intenionally drop to |
| 1286 // default case. | 1287 // default case. |
| 1287 default: | 1288 default: |
| 1288 llvm::report_fatal_error(std::string("Type ") + typeString(Ty) + | 1289 llvm::report_fatal_error(std::string("Type ") + typeString(Ty) + |
| 1289 " not implementable using str\n"); | 1290 " not implementable using str\n"); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1348 constexpr IValueT Orr = B3 | B2; // i.e. 1100 | 1349 constexpr IValueT Orr = B3 | B2; // i.e. 1100 |
| 1349 emitType01(Orr, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags); | 1350 emitType01(Orr, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags); |
| 1350 } | 1351 } |
| 1351 | 1352 |
| 1352 void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) { | 1353 void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) { |
| 1353 // POP - ARM section A8.8.132, encoding A2: | 1354 // POP - ARM section A8.8.132, encoding A2: |
| 1354 // pop<c> {Rt} | 1355 // pop<c> {Rt} |
| 1355 // | 1356 // |
| 1356 // cccc010010011101dddd000000000100 where dddd=Rt and cccc=Cond. | 1357 // cccc010010011101dddd000000000100 where dddd=Rt and cccc=Cond. |
| 1357 IValueT Rt; | 1358 IValueT Rt; |
| 1358 if (decodeOperand(OpRt, Rt) != DecodedAsRegister) | 1359 if (encodeOperand(OpRt, Rt) != EncodedAsRegister) |
| 1359 return setNeedsTextFixup(); | 1360 return setNeedsTextFixup(); |
| 1360 assert(Rt != RegARM32::Encoded_Reg_sp); | 1361 assert(Rt != RegARM32::Encoded_Reg_sp); |
| 1361 // Same as load instruction. | 1362 // Same as load instruction. |
| 1362 constexpr bool IsLoad = true; | 1363 constexpr bool IsLoad = true; |
| 1363 constexpr bool IsByte = false; | 1364 constexpr bool IsByte = false; |
| 1364 IValueT Address = encodeImmRegOffset(RegARM32::Encoded_Reg_sp, kWordSize, | 1365 IValueT Address = encodeImmRegOffset(RegARM32::Encoded_Reg_sp, kWordSize, |
| 1365 OperandARM32Mem::PostIndex); | 1366 OperandARM32Mem::PostIndex); |
| 1366 emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address); | 1367 emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address); |
| 1367 } | 1368 } |
| 1368 | 1369 |
| 1369 void AssemblerARM32::popList(const IValueT Registers, CondARM32::Cond Cond) { | 1370 void AssemblerARM32::popList(const IValueT Registers, CondARM32::Cond Cond) { |
| 1370 // POP - ARM section A8.*.131, encoding A1: | 1371 // POP - ARM section A8.*.131, encoding A1: |
| 1371 // pop<c> <registers> | 1372 // pop<c> <registers> |
| 1372 // | 1373 // |
| 1373 // cccc100010111101rrrrrrrrrrrrrrrr where cccc=Cond and | 1374 // cccc100010111101rrrrrrrrrrrrrrrr where cccc=Cond and |
| 1374 // rrrrrrrrrrrrrrrr=Registers (one bit for each GP register). | 1375 // rrrrrrrrrrrrrrrr=Registers (one bit for each GP register). |
| 1375 constexpr bool IsLoad = true; | 1376 constexpr bool IsLoad = true; |
| 1376 emitMultiMemOp(Cond, IA_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers); | 1377 emitMultiMemOp(Cond, IA_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers); |
| 1377 } | 1378 } |
| 1378 | 1379 |
| 1379 void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) { | 1380 void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) { |
| 1380 // PUSH - ARM section A8.8.133, encoding A2: | 1381 // PUSH - ARM section A8.8.133, encoding A2: |
| 1381 // push<c> {Rt} | 1382 // push<c> {Rt} |
| 1382 // | 1383 // |
| 1383 // cccc010100101101dddd000000000100 where dddd=Rt and cccc=Cond. | 1384 // cccc010100101101dddd000000000100 where dddd=Rt and cccc=Cond. |
| 1384 IValueT Rt; | 1385 IValueT Rt; |
| 1385 if (decodeOperand(OpRt, Rt) != DecodedAsRegister) | 1386 if (encodeOperand(OpRt, Rt) != EncodedAsRegister) |
| 1386 return setNeedsTextFixup(); | 1387 return setNeedsTextFixup(); |
| 1387 assert(Rt != RegARM32::Encoded_Reg_sp); | 1388 assert(Rt != RegARM32::Encoded_Reg_sp); |
| 1388 // Same as store instruction. | 1389 // Same as store instruction. |
| 1389 constexpr bool isLoad = false; | 1390 constexpr bool isLoad = false; |
| 1390 constexpr bool isByte = false; | 1391 constexpr bool isByte = false; |
| 1391 IValueT Address = encodeImmRegOffset(RegARM32::Encoded_Reg_sp, -kWordSize, | 1392 IValueT Address = encodeImmRegOffset(RegARM32::Encoded_Reg_sp, -kWordSize, |
| 1392 OperandARM32Mem::PreIndex); | 1393 OperandARM32Mem::PreIndex); |
| 1393 emitMemOp(Cond, kInstTypeMemImmediate, isLoad, isByte, Rt, Address); | 1394 emitMemOp(Cond, kInstTypeMemImmediate, isLoad, isByte, Rt, Address); |
| 1394 } | 1395 } |
| 1395 | 1396 |
| 1396 void AssemblerARM32::pushList(const IValueT Registers, CondARM32::Cond Cond) { | 1397 void AssemblerARM32::pushList(const IValueT Registers, CondARM32::Cond Cond) { |
| 1397 // PUSH - ARM section A8.8.133, encoding A1: | 1398 // PUSH - ARM section A8.8.133, encoding A1: |
| 1398 // push<c> <Registers> | 1399 // push<c> <Registers> |
| 1399 // | 1400 // |
| 1400 // cccc100100101101rrrrrrrrrrrrrrrr where cccc=Cond and | 1401 // cccc100100101101rrrrrrrrrrrrrrrr where cccc=Cond and |
| 1401 // rrrrrrrrrrrrrrrr=Registers (one bit for each GP register). | 1402 // rrrrrrrrrrrrrrrr=Registers (one bit for each GP register). |
| 1402 constexpr bool IsLoad = false; | 1403 constexpr bool IsLoad = false; |
| 1403 emitMultiMemOp(Cond, DB_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers); | 1404 emitMultiMemOp(Cond, DB_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers); |
| 1404 } | 1405 } |
| 1405 | 1406 |
| 1406 void AssemblerARM32::mla(const Operand *OpRd, const Operand *OpRn, | 1407 void AssemblerARM32::mla(const Operand *OpRd, const Operand *OpRn, |
| 1407 const Operand *OpRm, const Operand *OpRa, | 1408 const Operand *OpRm, const Operand *OpRa, |
| 1408 CondARM32::Cond Cond) { | 1409 CondARM32::Cond Cond) { |
| 1409 IValueT Rd; | 1410 IValueT Rd; |
| 1410 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 1411 if (encodeOperand(OpRd, Rd) != EncodedAsRegister) |
| 1411 return setNeedsTextFixup(); | 1412 return setNeedsTextFixup(); |
| 1412 IValueT Rn; | 1413 IValueT Rn; |
| 1413 if (decodeOperand(OpRn, Rn) != DecodedAsRegister) | 1414 if (encodeOperand(OpRn, Rn) != EncodedAsRegister) |
| 1414 return setNeedsTextFixup(); | 1415 return setNeedsTextFixup(); |
| 1415 IValueT Rm; | 1416 IValueT Rm; |
| 1416 if (decodeOperand(OpRm, Rm) != DecodedAsRegister) | 1417 if (encodeOperand(OpRm, Rm) != EncodedAsRegister) |
| 1417 return setNeedsTextFixup(); | 1418 return setNeedsTextFixup(); |
| 1418 IValueT Ra; | 1419 IValueT Ra; |
| 1419 if (decodeOperand(OpRa, Ra) != DecodedAsRegister) | 1420 if (encodeOperand(OpRa, Ra) != EncodedAsRegister) |
| 1420 return setNeedsTextFixup(); | 1421 return setNeedsTextFixup(); |
| 1421 // MLA - ARM section A8.8.114, encoding A1. | 1422 // MLA - ARM section A8.8.114, encoding A1. |
| 1422 // mla{s}<c> <Rd>, <Rn>, <Rm>, <Ra> | 1423 // mla{s}<c> <Rd>, <Rn>, <Rm>, <Ra> |
| 1423 // | 1424 // |
| 1424 // cccc0000001sddddaaaammmm1001nnnn where cccc=Cond, s=SetFlags, dddd=Rd, | 1425 // cccc0000001sddddaaaammmm1001nnnn where cccc=Cond, s=SetFlags, dddd=Rd, |
| 1425 // aaaa=Ra, mmmm=Rm, and nnnn=Rn. | 1426 // aaaa=Ra, mmmm=Rm, and nnnn=Rn. |
| 1426 if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc || | 1427 if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc || |
| 1427 Rm == RegARM32::Encoded_Reg_pc || Ra == RegARM32::Encoded_Reg_pc) | 1428 Rm == RegARM32::Encoded_Reg_pc || Ra == RegARM32::Encoded_Reg_pc) |
| 1428 llvm::report_fatal_error("Mul instruction unpredictable on pc"); | 1429 llvm::report_fatal_error("Mul instruction unpredictable on pc"); |
| 1429 constexpr IValueT MlaOpcode = B21; | 1430 constexpr IValueT MlaOpcode = B21; |
| 1430 constexpr bool SetFlags = false; | 1431 constexpr bool SetFlags = false; |
| 1431 // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. | 1432 // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. |
| 1432 emitMulOp(Cond, MlaOpcode, Ra, Rd, Rn, Rm, SetFlags); | 1433 emitMulOp(Cond, MlaOpcode, Ra, Rd, Rn, Rm, SetFlags); |
| 1433 } | 1434 } |
| 1434 | 1435 |
| 1435 void AssemblerARM32::mul(const Operand *OpRd, const Operand *OpRn, | 1436 void AssemblerARM32::mul(const Operand *OpRd, const Operand *OpRn, |
| 1436 const Operand *OpSrc1, bool SetFlags, | 1437 const Operand *OpSrc1, bool SetFlags, |
| 1437 CondARM32::Cond Cond) { | 1438 CondARM32::Cond Cond) { |
| 1438 IValueT Rd; | 1439 IValueT Rd; |
| 1439 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 1440 if (encodeOperand(OpRd, Rd) != EncodedAsRegister) |
| 1440 return setNeedsTextFixup(); | 1441 return setNeedsTextFixup(); |
| 1441 IValueT Rn; | 1442 IValueT Rn; |
| 1442 if (decodeOperand(OpRn, Rn) != DecodedAsRegister) | 1443 if (encodeOperand(OpRn, Rn) != EncodedAsRegister) |
| 1443 return setNeedsTextFixup(); | 1444 return setNeedsTextFixup(); |
| 1444 IValueT Rm; | 1445 IValueT Rm; |
| 1445 if (decodeOperand(OpSrc1, Rm) != DecodedAsRegister) | 1446 if (encodeOperand(OpSrc1, Rm) != EncodedAsRegister) |
| 1446 return setNeedsTextFixup(); | 1447 return setNeedsTextFixup(); |
| 1447 // MUL - ARM section A8.8.114, encoding A1. | 1448 // MUL - ARM section A8.8.114, encoding A1. |
| 1448 // mul{s}<c> <Rd>, <Rn>, <Rm> | 1449 // mul{s}<c> <Rd>, <Rn>, <Rm> |
| 1449 // | 1450 // |
| 1450 // cccc0000000sdddd0000mmmm1001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, | 1451 // cccc0000000sdddd0000mmmm1001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, |
| 1451 // mmmm=Rm, and s=SetFlags. | 1452 // mmmm=Rm, and s=SetFlags. |
| 1452 if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc || | 1453 if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc || |
| 1453 Rm == RegARM32::Encoded_Reg_pc) | 1454 Rm == RegARM32::Encoded_Reg_pc) |
| 1454 llvm::report_fatal_error("Mul instruction unpredictable on pc"); | 1455 llvm::report_fatal_error("Mul instruction unpredictable on pc"); |
| 1455 // Assembler registers rd, rn, rm are encoded as rn, rm, rs. | 1456 // Assembler registers rd, rn, rm are encoded as rn, rm, rs. |
| 1456 constexpr IValueT MulOpcode = 0; | 1457 constexpr IValueT MulOpcode = 0; |
| 1457 emitMulOp(Cond, MulOpcode, RegARM32::Encoded_Reg_r0, Rd, Rn, Rm, SetFlags); | 1458 emitMulOp(Cond, MulOpcode, RegARM32::Encoded_Reg_r0, Rd, Rn, Rm, SetFlags); |
| 1458 } | 1459 } |
| 1459 | 1460 |
| 1460 void AssemblerARM32::udiv(const Operand *OpRd, const Operand *OpRn, | 1461 void AssemblerARM32::udiv(const Operand *OpRd, const Operand *OpRn, |
| 1461 const Operand *OpSrc1, CondARM32::Cond Cond) { | 1462 const Operand *OpSrc1, CondARM32::Cond Cond) { |
| 1462 // UDIV - ARM section A8.8.248, encoding A1. | 1463 // UDIV - ARM section A8.8.248, encoding A1. |
| 1463 // udiv<c> <Rd>, <Rn>, <Rm> | 1464 // udiv<c> <Rd>, <Rn>, <Rm> |
| 1464 // | 1465 // |
| 1465 // cccc01110011dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and | 1466 // cccc01110011dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and |
| 1466 // mmmm=Rm. | 1467 // mmmm=Rm. |
| 1467 IValueT Rd; | 1468 IValueT Rd; |
| 1468 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 1469 if (encodeOperand(OpRd, Rd) != EncodedAsRegister) |
| 1469 return setNeedsTextFixup(); | 1470 return setNeedsTextFixup(); |
| 1470 IValueT Rn; | 1471 IValueT Rn; |
| 1471 if (decodeOperand(OpRn, Rn) != DecodedAsRegister) | 1472 if (encodeOperand(OpRn, Rn) != EncodedAsRegister) |
| 1472 return setNeedsTextFixup(); | 1473 return setNeedsTextFixup(); |
| 1473 IValueT Rm; | 1474 IValueT Rm; |
| 1474 if (decodeOperand(OpSrc1, Rm) != DecodedAsRegister) | 1475 if (encodeOperand(OpSrc1, Rm) != EncodedAsRegister) |
| 1475 return setNeedsTextFixup(); | 1476 return setNeedsTextFixup(); |
| 1476 if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc || | 1477 if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc || |
| 1477 Rm == RegARM32::Encoded_Reg_pc) | 1478 Rm == RegARM32::Encoded_Reg_pc) |
| 1478 llvm::report_fatal_error("Udiv instruction unpredictable on pc"); | 1479 llvm::report_fatal_error("Udiv instruction unpredictable on pc"); |
| 1479 // Assembler registers rd, rn, rm are encoded as rn, rm, rs. | 1480 // Assembler registers rd, rn, rm are encoded as rn, rm, rs. |
| 1480 constexpr IValueT Opcode = B21; | 1481 constexpr IValueT Opcode = B21; |
| 1481 emitDivOp(Cond, Opcode, Rd, Rn, Rm); | 1482 emitDivOp(Cond, Opcode, Rd, Rn, Rm); |
| 1482 } | 1483 } |
| 1483 | 1484 |
| 1484 void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, | 1485 void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1525 CondARM32::Cond Cond) { | 1526 CondARM32::Cond Cond) { |
| 1526 // UMULL - ARM section A8.8.257, encoding A1: | 1527 // UMULL - ARM section A8.8.257, encoding A1: |
| 1527 // umull<c> <RdLo>, <RdHi>, <Rn>, <Rm> | 1528 // umull<c> <RdLo>, <RdHi>, <Rn>, <Rm> |
| 1528 // | 1529 // |
| 1529 // cccc0000100shhhhllllmmmm1001nnnn where hhhh=RdHi, llll=RdLo, nnnn=Rn, | 1530 // cccc0000100shhhhllllmmmm1001nnnn where hhhh=RdHi, llll=RdLo, nnnn=Rn, |
| 1530 // mmmm=Rm, and s=SetFlags | 1531 // mmmm=Rm, and s=SetFlags |
| 1531 IValueT RdLo; | 1532 IValueT RdLo; |
| 1532 IValueT RdHi; | 1533 IValueT RdHi; |
| 1533 IValueT Rn; | 1534 IValueT Rn; |
| 1534 IValueT Rm; | 1535 IValueT Rm; |
| 1535 if (decodeOperand(OpRdLo, RdLo) != DecodedAsRegister || | 1536 if (encodeOperand(OpRdLo, RdLo) != EncodedAsRegister || |
| 1536 decodeOperand(OpRdHi, RdHi) != DecodedAsRegister || | 1537 encodeOperand(OpRdHi, RdHi) != EncodedAsRegister || |
| 1537 decodeOperand(OpRn, Rn) != DecodedAsRegister || | 1538 encodeOperand(OpRn, Rn) != EncodedAsRegister || |
| 1538 decodeOperand(OpRm, Rm) != DecodedAsRegister) | 1539 encodeOperand(OpRm, Rm) != EncodedAsRegister) |
| 1539 return setNeedsTextFixup(); | 1540 return setNeedsTextFixup(); |
| 1540 if (RdHi == RegARM32::Encoded_Reg_pc || RdLo == RegARM32::Encoded_Reg_pc || | 1541 if (RdHi == RegARM32::Encoded_Reg_pc || RdLo == RegARM32::Encoded_Reg_pc || |
| 1541 Rn == RegARM32::Encoded_Reg_pc || Rm == RegARM32::Encoded_Reg_pc || | 1542 Rn == RegARM32::Encoded_Reg_pc || Rm == RegARM32::Encoded_Reg_pc || |
| 1542 RdHi == RdLo) | 1543 RdHi == RdLo) |
| 1543 llvm::report_fatal_error("Umull instruction unpredictable on pc"); | 1544 llvm::report_fatal_error("Umull instruction unpredictable on pc"); |
| 1544 constexpr bool SetFlags = false; | 1545 constexpr bool SetFlags = false; |
| 1545 emitMulOp(Cond, B23, RdLo, RdHi, Rn, Rm, SetFlags); | 1546 emitMulOp(Cond, B23, RdLo, RdHi, Rn, Rm, SetFlags); |
| 1546 } | 1547 } |
| 1547 | 1548 |
| 1548 void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0, | 1549 void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0, |
| 1549 CondARM32::Cond Cond) { | 1550 CondARM32::Cond Cond) { |
| 1550 IValueT Rd; | 1551 IValueT Rd; |
| 1551 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 1552 if (encodeOperand(OpRd, Rd) != EncodedAsRegister) |
| 1552 return setNeedsTextFixup(); | 1553 return setNeedsTextFixup(); |
| 1553 // Note: For the moment, we assume no rotation is specified. | 1554 // Note: For the moment, we assume no rotation is specified. |
| 1554 RotationValue Rotation = kRotateNone; | 1555 RotationValue Rotation = kRotateNone; |
| 1555 constexpr IValueT Rn = RegARM32::Encoded_Reg_pc; | 1556 constexpr IValueT Rn = RegARM32::Encoded_Reg_pc; |
| 1556 IValueT Rm; | 1557 IValueT Rm; |
| 1557 if (decodeOperand(OpSrc0, Rm) != DecodedAsRegister) | 1558 if (encodeOperand(OpSrc0, Rm) != EncodedAsRegister) |
| 1558 return setNeedsTextFixup(); | 1559 return setNeedsTextFixup(); |
| 1559 switch (typeWidthInBytes(OpSrc0->getType())) { | 1560 switch (typeWidthInBytes(OpSrc0->getType())) { |
| 1560 default: | 1561 default: |
| 1561 return setNeedsTextFixup(); | 1562 return setNeedsTextFixup(); |
| 1562 case 1: { | 1563 case 1: { |
| 1563 // UXTB - ARM section A8.8.274, encoding A1: | 1564 // UXTB - ARM section A8.8.274, encoding A1: |
| 1564 // uxtb<c> <Rd>, <Rm>{, <rotate>} | 1565 // uxtb<c> <Rd>, <Rm>{, <rotate>} |
| 1565 // | 1566 // |
| 1566 // cccc011011101111ddddrr000111mmmm where cccc=Cond, dddd=Rd, mmmm=Rm, and | 1567 // cccc011011101111ddddrr000111mmmm where cccc=Cond, dddd=Rd, mmmm=Rm, and |
| 1567 // rr defined (RotationValue) rotate. | 1568 // rr defined (RotationValue) rotate. |
| 1568 constexpr IValueT Opcode = B26 | B25 | B23 | B22 | B21; | 1569 constexpr IValueT Opcode = B26 | B25 | B23 | B22 | B21; |
| 1569 emitUxt(Cond, Opcode, Rd, Rn, Rm, Rotation); | 1570 emitUxt(Cond, Opcode, Rd, Rn, Rm, Rotation); |
| 1570 return; | 1571 return; |
| 1571 } | 1572 } |
| 1572 case 2: { | 1573 case 2: { |
| 1573 // UXTH - ARM section A8.8.276, encoding A1: | 1574 // UXTH - ARM section A8.8.276, encoding A1: |
| 1574 // uxth<c> <Rd>< <Rm>{, <rotate>} | 1575 // uxth<c> <Rd>< <Rm>{, <rotate>} |
| 1575 // | 1576 // |
| 1576 // cccc01101111nnnnddddrr000111mmmm where cccc=Cond, dddd=Rd, mmmm=Rm, and | 1577 // cccc01101111nnnnddddrr000111mmmm where cccc=Cond, dddd=Rd, mmmm=Rm, and |
| 1577 // rr defined (RotationValue) rotate. | 1578 // rr defined (RotationValue) rotate. |
| 1578 constexpr IValueT Opcode = B26 | B25 | B23 | B22 | B21 | B20; | 1579 constexpr IValueT Opcode = B26 | B25 | B23 | B22 | B21 | B20; |
| 1579 emitUxt(Cond, Opcode, Rd, Rn, Rm, Rotation); | 1580 emitUxt(Cond, Opcode, Rd, Rn, Rm, Rotation); |
| 1580 return; | 1581 return; |
| 1581 } | 1582 } |
| 1582 } | 1583 } |
| 1583 } | 1584 } |
| 1584 | 1585 |
| 1585 } // end of namespace ARM32 | 1586 } // end of namespace ARM32 |
| 1586 } // end of namespace Ice | 1587 } // end of namespace Ice |
| OLD | NEW |