| Index: src/IceAssemblerARM32.cpp | 
| diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp | 
| index 9972b44f29506f286618f931909fffdcca5422d9..c99737d81731c85ad26d29254c64ca200123d3ce 100644 | 
| --- a/src/IceAssemblerARM32.cpp | 
| +++ b/src/IceAssemblerARM32.cpp | 
| @@ -21,6 +21,7 @@ | 
| //===----------------------------------------------------------------------===// | 
|  | 
| #include "IceAssemblerARM32.h" | 
| +#include "IceUtils.h" | 
|  | 
| namespace { | 
|  | 
| @@ -39,6 +40,14 @@ static constexpr uint32_t B24 = 1 << 24; | 
|  | 
| // Constants used for the decoding or encoding of the individual fields of | 
| // instructions. Based on ARM section A5.1. | 
| +static constexpr uint32_t L = 1 << 20; // load (or store) | 
| +static constexpr uint32_t W = 1 << 21; // writeback base register (or leave | 
| +                                       // unchanged) | 
| +static constexpr uint32_t B = 1 << 22; // unsigned byte (or word) | 
| +static constexpr uint32_t U = 1 << 23; // positive (or negative) offset/index | 
| +static constexpr uint32_t P = 1 << 24; // offset/pre-indexed addressing (or | 
| +                                       // post-indexed addressing) | 
| + | 
| static constexpr uint32_t kConditionShift = 28; | 
| static constexpr uint32_t kOpcodeShift = 21; | 
| static constexpr uint32_t kRdShift = 12; | 
| @@ -53,6 +62,9 @@ static constexpr uint32_t kImmed8Shift = 0; | 
| static constexpr uint32_t kRotateBits = 4; | 
| static constexpr uint32_t kRotateShift = 8; | 
|  | 
| +static constexpr uint32_t kImmed12Bits = 12; | 
| +static constexpr uint32_t kImm12Shift = 0; | 
| + | 
| inline uint32_t encodeBool(bool b) { return b ? 1 : 0; } | 
|  | 
| inline uint32_t encodeGPRRegister(RegARM32::GPRRegister Rn) { | 
| @@ -75,22 +87,46 @@ inline uint32_t encodeCondition(CondARM32::Cond Cond) { | 
| return static_cast<uint32_t>(Cond); | 
| } | 
|  | 
| -// The way an operand was decoded in function decode below. | 
| +// Returns the bits in the corresponding masked value. | 
| +inline uint32_t mask(uint32_t Value, uint32_t Shift, uint32_t Bits) { | 
| +  return (Value >> Shift) & ((1 << Bits) - 1); | 
| +} | 
| + | 
| +// Extract out a Bit in Value. | 
| +inline bool isBitSet(uint32_t Bit, uint32_t Value) { | 
| +  return (Value & Bit) == Bit; | 
| +} | 
| + | 
| +// Returns the GPR register at given Shift in Value. | 
| +inline RegARM32::GPRRegister getGPRReg(uint32_t Shift, uint32_t Value) { | 
| +  return static_cast<RegARM32::GPRRegister>((Value >> Shift) & 0xF); | 
| +} | 
| + | 
| +// The way an operand was decoded in functions decodeOperand and decodeAddress | 
| +// below. | 
| enum DecodedResult { | 
| -  CantDecode = 0, // I.e. will fail in test. | 
| +  // Unable to decode, value left undefined. | 
| +  CantDecode = 0, | 
| +  // Value is register found. | 
| DecodedAsRegister, | 
| -  DecodedAsRotatedImm8 | 
| +  // Value=rrrriiiiiiii where rrrr is the rotation, and iiiiiiii is the imm8 | 
| +  // value. | 
| +  DecodedAsRotatedImm8, | 
| +  // i.e. 0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn, | 
| +  // p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to | 
| +  // Rn should be used, and iiiiiiiiiiii is the offset. | 
| +  DecodedAsImmRegOffset | 
| }; | 
|  | 
| -DecodedResult decode(const Operand *Opnd, uint32_t &Value) { | 
| +DecodedResult decodeOperand(const Operand *Opnd, uint32_t &Value) { | 
| if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { | 
| if (Var->hasReg()) { | 
| Value = Var->getRegNum(); | 
| return DecodedAsRegister; | 
| } | 
| } else if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Opnd)) { | 
| -    uint32_t Immed8 = FlexImm->getImm(); | 
| -    uint32_t Rotate = FlexImm->getRotateAmt(); | 
| +    const uint32_t Immed8 = FlexImm->getImm(); | 
| +    const uint32_t Rotate = FlexImm->getRotateAmt(); | 
| assert((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits))); | 
| Value = (Rotate << kRotateShift) | (Immed8 << kImmed8Shift); | 
| return DecodedAsRotatedImm8; | 
| @@ -98,6 +134,34 @@ DecodedResult decode(const Operand *Opnd, uint32_t &Value) { | 
| return CantDecode; | 
| } | 
|  | 
| +uint32_t decodeImmRegOffset(RegARM32::GPRRegister Reg, int32_t Offset, | 
| +                            OperandARM32Mem::AddrMode Mode) { | 
| +  uint32_t Value = Mode | (encodeGPRRegister(Reg) << kRnShift); | 
| +  if (Offset < 0) { | 
| +    Value = (Value ^ U) | -Offset; // Flip U to adjust sign. | 
| +  } else { | 
| +    Value |= Offset; | 
| +  } | 
| +  return Value; | 
| +} | 
| + | 
| +// Decodes memory address Opnd, and encodes that information into Value, | 
| +// based on how ARM represents the address. Returns how the value was encoded. | 
| +DecodedResult decodeAddress(const Operand *Opnd, uint32_t &Value) { | 
| +  if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { | 
| +    // Should be a stack variable, with an offset. | 
| +    if (Var->hasReg()) | 
| +      return CantDecode; | 
| +    const int32_t Offset = Var->getStackOffset(); | 
| +    if (!Utils::IsAbsoluteUint(12, Offset)) | 
| +      return CantDecode; | 
| +    Value = decodeImmRegOffset(RegARM32::Encoded_Reg_sp, Offset, | 
| +                               OperandARM32Mem::Offset); | 
| +    return DecodedAsImmRegOffset; | 
| +  } | 
| +  return CantDecode; | 
| +} | 
| + | 
| } // end of anonymous namespace | 
|  | 
| namespace Ice { | 
| @@ -140,10 +204,22 @@ void ARM32::AssemblerARM32::emitType01(CondARM32::Cond Cond, uint32_t Type, | 
| assert(isGPRRegisterDefined(Rd)); | 
| assert(Cond != CondARM32::kNone); | 
| AssemblerBuffer::EnsureCapacity ensured(&Buffer); | 
| -  uint32_t Encoding = encodeCondition(Cond) << kConditionShift | | 
| -                      (Type << kTypeShift) | (Opcode << kOpcodeShift) | | 
| -                      (encodeBool(SetCc) << kSShift) | (Rn << kRnShift) | | 
| -                      (Rd << kRdShift) | Imm12; | 
| +  const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | | 
| +                            (Type << kTypeShift) | (Opcode << kOpcodeShift) | | 
| +                            (encodeBool(SetCc) << kSShift) | (Rn << kRnShift) | | 
| +                            (Rd << kRdShift) | Imm12; | 
| +  emitInst(Encoding); | 
| +} | 
| + | 
| +void ARM32::AssemblerARM32::emitMemOp(CondARM32::Cond Cond, uint32_t InstType, | 
| +                                      bool IsLoad, bool IsByte, uint32_t Rt, | 
| +                                      uint32_t Address) { | 
| +  assert(isGPRRegisterDefined(Rt)); | 
| +  assert(Cond != CondARM32::kNone); | 
| +  AssemblerBuffer::EnsureCapacity ensured(&Buffer); | 
| +  const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | | 
| +                            (InstType << kTypeShift) | (IsLoad ? L : 0) | | 
| +                            (IsByte ? B : 0) | (Rt << kRdShift) | Address; | 
| emitInst(Encoding); | 
| } | 
|  | 
| @@ -153,14 +229,14 @@ void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, | 
| // Note: Loop is used so that we can short circuit using break; | 
| do { | 
| uint32_t Rd; | 
| -    if (decode(OpRd, Rd) != DecodedAsRegister) | 
| +    if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 
| break; | 
| uint32_t Rn; | 
| -    if (decode(OpRn, Rn) != DecodedAsRegister) | 
| +    if (decodeOperand(OpRn, Rn) != DecodedAsRegister) | 
| break; | 
| uint32_t Src1Value; | 
| // TODO(kschimpf) Other possible decodings of add. | 
| -    if (decode(OpSrc1, Src1Value) == DecodedAsRotatedImm8) { | 
| +    if (decodeOperand(OpSrc1, Src1Value) == DecodedAsRotatedImm8) { | 
| // ADD (Immediate): See ARM section A8.8.5, rule A1. | 
| // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, | 
| // s=SetFlags and iiiiiiiiiiii=Src1Value | 
| @@ -168,8 +244,8 @@ void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, | 
| (Rn == RegARM32::Reg_lr) || (Rn == RegARM32::Reg_pc && SetFlags)) | 
| // Conditions of rule violated. | 
| break; | 
| -      uint32_t Add = B2; // 0100 | 
| -      uint32_t InstType = 1; | 
| +      constexpr uint32_t Add = B2; // 0100 | 
| +      constexpr uint32_t InstType = 1; | 
| emitType01(Cond, InstType, Add, SetFlags, Rn, Rd, Src1Value); | 
| return; | 
| } | 
| @@ -179,8 +255,8 @@ void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, | 
|  | 
| void ARM32::AssemblerARM32::bkpt(uint16_t imm16) { | 
| AssemblerBuffer::EnsureCapacity ensured(&Buffer); | 
| -  uint32_t Encoding = (CondARM32::AL << kConditionShift) | B24 | B21 | | 
| -                      ((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf); | 
| +  const uint32_t Encoding = (CondARM32::AL << kConditionShift) | B24 | B21 | | 
| +                            ((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf); | 
| emitInst(Encoding); | 
| } | 
|  | 
| @@ -190,30 +266,62 @@ void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) { | 
| assert(isGPRRegisterDefined(Rm)); | 
| assert(isConditionDefined(Cond)); | 
| AssemblerBuffer::EnsureCapacity ensured(&Buffer); | 
| -  uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | B24 | B21 | | 
| -                      (0xfff << 8) | B4 | (encodeGPRRegister(Rm) << kRmShift); | 
| +  const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | B24 | | 
| +                            B21 | (0xfff << 8) | B4 | | 
| +                            (encodeGPRRegister(Rm) << kRmShift); | 
| emitInst(Encoding); | 
| } | 
|  | 
| +void ARM32::AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, | 
| +                                CondARM32::Cond Cond) { | 
| +  // Note: Loop is used so that we can short ciruit using break; | 
| +  do { | 
| +    uint32_t Rt; | 
| +    if (decodeOperand(OpRt, Rt) != DecodedAsRegister) | 
| +      break; | 
| +    uint32_t Address; | 
| +    if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset) | 
| +      break; | 
| +    // cccc010pu0w1nnnnttttiiiiiiiiiiii (ARM section A8.8.63, encoding A1; and | 
| +    // section A8.6.68, encoding A1). | 
| +    constexpr uint32_t InstType = B1; // 010 | 
| +    constexpr bool IsLoad = true; | 
| +    const Type Ty = OpRt->getType(); | 
| +    if (!(Ty == IceType_i32 || Ty == IceType_i8)) // TODO(kschimpf) Expand? | 
| +      break; | 
| +    const bool IsByte = typeWidthInBytes(Ty) == 1; | 
| +    if ((getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_pc) || | 
| +        (!IsByte && !isBitSet(P, Address) && isBitSet(W, Address)) || | 
| +        ((getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) && | 
| +         !isBitSet(P, Address) && | 
| +         isBitSet(U, Address) & !isBitSet(W, Address) && | 
| +         (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */))) | 
| +      break; | 
| +    emitMemOp(Cond, InstType, IsLoad, IsByte, Rt, Address); | 
| +    return; | 
| +  } while (0); | 
| +  UnimplementedError(Ctx->getFlags()); | 
| +} | 
| + | 
| void ARM32::AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, | 
| CondARM32::Cond Cond) { | 
| // Note: Loop is used so that we can short ciruit using break; | 
| do { | 
| uint32_t Rd; | 
| -    if (decode(OpRd, Rd) != DecodedAsRegister) | 
| +    if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 
| break; | 
| uint32_t Src; | 
| // TODO(kschimpf) Handle other forms of mov. | 
| -    if (decode(OpSrc, Src) == DecodedAsRotatedImm8) { | 
| +    if (decodeOperand(OpSrc, Src) == DecodedAsRotatedImm8) { | 
| // cccc0011101s0000ddddiiiiiiiiiiii (ARM section A8.8.102, encoding A1) | 
| // Note: We don't use movs in this assembler. | 
| constexpr bool SetFlags = false; | 
| if (!isConditionDefined(Cond) || (Rd == RegARM32::Reg_pc && SetFlags)) | 
| // Conditions of rule violated. | 
| break; | 
| -      uint32_t Rn = 0; | 
| -      uint32_t Mov = B3 | B2 | B0; // 1101. | 
| -      uint32_t InstType = 1; | 
| +      constexpr uint32_t Rn = 0; | 
| +      constexpr uint32_t Mov = B3 | B2 | B0; // 1101. | 
| +      constexpr uint32_t InstType = 1; | 
| emitType01(Cond, InstType, Mov, SetFlags, Rn, Rd, Src); | 
| return; | 
| } | 
| @@ -221,20 +329,53 @@ void ARM32::AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, | 
| UnimplementedError(Ctx->getFlags()); | 
| } | 
|  | 
| +void ARM32::AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, | 
| +                                CondARM32::Cond Cond) { | 
| +  // Note: Loop is used so that we can short ciruit using break; | 
| +  do { | 
| +    uint32_t Rt; | 
| +    if (decodeOperand(OpRt, Rt) != DecodedAsRegister) | 
| +      break; | 
| +    uint32_t Address; | 
| +    if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset) | 
| +      break; | 
| +    // cccc010pub0nnnnttttiiiiiiiiiiii (ARM section A8.8.204, encoding A1; and | 
| +    // section 18.8.207, encoding A1). | 
| +    constexpr uint32_t InstType = B1; // 010 | 
| +    constexpr bool IsLoad = false; | 
| +    const Type Ty = OpRt->getType(); | 
| +    if (!(Ty == IceType_i32 || Ty == IceType_i8)) // TODO(kschimpf) Expand? | 
| +      break; | 
| +    const bool IsByte = typeWidthInBytes(Ty) == 1; | 
| +    // Check for rule violations. | 
| +    if ((getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_pc) || | 
| +        (!isBitSet(P, Address) && isBitSet(W, Address)) || | 
| +        (!IsByte && | 
| +         (getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) && | 
| +         isBitSet(P, Address) && !isBitSet(U, Address) && | 
| +         isBitSet(W, Address) && | 
| +         (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */))) | 
| +      break; | 
| +    emitMemOp(Cond, InstType, IsLoad, IsByte, Rt, Address); | 
| +    return; | 
| +  } while (0); | 
| +  UnimplementedError(Ctx->getFlags()); | 
| +} | 
| + | 
| void ARM32::AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, | 
| const Operand *OpSrc1, bool SetFlags, | 
| CondARM32::Cond Cond) { | 
| // Note: Loop is used so that we can short circuit using break; | 
| do { | 
| uint32_t Rd; | 
| -    if (decode(OpRd, Rd) != DecodedAsRegister) | 
| +    if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 
| break; | 
| uint32_t Rn; | 
| -    if (decode(OpRn, Rn) != DecodedAsRegister) | 
| +    if (decodeOperand(OpRn, Rn) != DecodedAsRegister) | 
| break; | 
| uint32_t Src1Value; | 
| // TODO(kschimpf) Other possible decodings of add. | 
| -    if (decode(OpSrc1, Src1Value) == DecodedAsRotatedImm8) { | 
| +    if (decodeOperand(OpSrc1, Src1Value) == DecodedAsRotatedImm8) { | 
| // Sub (Immediate): See ARM section A8.8.222, rule A1. | 
| // cccc0010010snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, | 
| // s=SetFlags and iiiiiiiiiiii=Src1Value | 
| @@ -242,8 +383,8 @@ void ARM32::AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, | 
| (Rn == RegARM32::Reg_lr) || (Rn == RegARM32::Reg_pc && SetFlags)) | 
| // Conditions of rule violated. | 
| break; | 
| -      uint32_t Add = B1; // 0010 | 
| -      uint32_t InstType = 1; | 
| +      constexpr uint32_t Add = B1; // 0010 | 
| +      constexpr uint32_t InstType = 1; | 
| emitType01(Cond, InstType, Add, SetFlags, Rn, Rd, Src1Value); | 
| return; | 
| } | 
|  |