Chromium Code Reviews| 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 // |
| 11 // The Subzero Code Generator | 11 // The Subzero Code Generator |
| 12 // | 12 // |
| 13 // This file is distributed under the University of Illinois Open Source | 13 // This file is distributed under the University of Illinois Open Source |
| 14 // License. See LICENSE.TXT for details. | 14 // License. See LICENSE.TXT for details. |
| 15 // | 15 // |
| 16 //===----------------------------------------------------------------------===// | 16 //===----------------------------------------------------------------------===// |
| 17 /// | 17 /// |
| 18 /// \file | 18 /// \file |
| 19 /// This file implements the Assembler class for ARM32. | 19 /// This file implements the Assembler class for ARM32. |
| 20 /// | 20 /// |
| 21 //===----------------------------------------------------------------------===// | 21 //===----------------------------------------------------------------------===// |
| 22 | 22 |
| 23 #include "IceAssemblerARM32.h" | 23 #include "IceAssemblerARM32.h" |
| 24 #include "IceCfgNode.h" | 24 #include "IceCfgNode.h" |
| 25 #include "IceUtils.h" | 25 #include "IceUtils.h" |
| 26 | 26 |
| 27 namespace { | 27 namespace { |
| 28 | 28 |
| 29 using namespace Ice; | 29 using namespace Ice; |
| 30 using namespace Ice::ARM32; | |
| 30 | 31 |
| 31 // The following define individual bits. | 32 // The following define individual bits. |
| 32 static constexpr uint32_t B0 = 1; | 33 static constexpr InstValueType B0 = 1; |
| 33 static constexpr uint32_t B1 = 1 << 1; | 34 static constexpr InstValueType B1 = 1 << 1; |
| 34 static constexpr uint32_t B2 = 1 << 2; | 35 static constexpr InstValueType B2 = 1 << 2; |
| 35 static constexpr uint32_t B3 = 1 << 3; | 36 static constexpr InstValueType B3 = 1 << 3; |
| 36 static constexpr uint32_t B4 = 1 << 4; | 37 static constexpr InstValueType B4 = 1 << 4; |
| 37 static constexpr uint32_t B5 = 1 << 5; | 38 static constexpr InstValueType B5 = 1 << 5; |
| 38 static constexpr uint32_t B6 = 1 << 6; | 39 static constexpr InstValueType B6 = 1 << 6; |
| 39 static constexpr uint32_t B21 = 1 << 21; | 40 static constexpr InstValueType B21 = 1 << 21; |
| 40 static constexpr uint32_t B24 = 1 << 24; | 41 static constexpr InstValueType B24 = 1 << 24; |
| 41 | 42 |
| 42 // Constants used for the decoding or encoding of the individual fields of | 43 // Constants used for the decoding or encoding of the individual fields of |
| 43 // instructions. Based on ARM section A5.1. | 44 // instructions. Based on ARM section A5.1. |
| 44 static constexpr uint32_t L = 1 << 20; // load (or store) | 45 static constexpr InstValueType L = 1 << 20; // load (or store) |
| 45 static constexpr uint32_t W = 1 << 21; // writeback base register (or leave | 46 static constexpr InstValueType W = 1 << 21; // writeback base register |
| 46 // unchanged) | 47 // (or leave unchanged) |
| 47 static constexpr uint32_t B = 1 << 22; // unsigned byte (or word) | 48 static constexpr InstValueType B = 1 << 22; // unsigned byte (or word) |
| 48 static constexpr uint32_t U = 1 << 23; // positive (or negative) offset/index | 49 static constexpr InstValueType U = 1 << 23; // positive (or negative) |
| 49 static constexpr uint32_t P = 1 << 24; // offset/pre-indexed addressing (or | 50 // offset/index |
| 50 // post-indexed addressing) | 51 static constexpr InstValueType P = 1 << 24; // offset/pre-indexed |
| 52 // addressing (or | |
| 53 // post-indexed addressing) | |
| 51 | 54 |
| 52 static constexpr uint32_t kConditionShift = 28; | 55 static constexpr InstValueType kConditionShift = 28; |
| 53 static constexpr uint32_t kOpcodeShift = 21; | 56 static constexpr InstValueType kLinkShift = 24; |
| 54 static constexpr uint32_t kRdShift = 12; | 57 static constexpr InstValueType kOpcodeShift = 21; |
| 55 static constexpr uint32_t kRmShift = 0; | 58 static constexpr InstValueType kRdShift = 12; |
| 56 static constexpr uint32_t kRnShift = 16; | 59 static constexpr InstValueType kRmShift = 0; |
| 57 static constexpr uint32_t kSShift = 20; | 60 static constexpr InstValueType kRnShift = 16; |
| 58 static constexpr uint32_t kTypeShift = 25; | 61 static constexpr InstValueType kSShift = 20; |
| 62 static constexpr InstValueType kTypeShift = 25; | |
| 59 | 63 |
| 60 // Immediate instruction fields encoding. | 64 // Immediate instruction fields encoding. |
| 61 static constexpr uint32_t kImmed8Bits = 8; | 65 static constexpr InstValueType kImmed8Bits = 8; |
| 62 static constexpr uint32_t kImmed8Shift = 0; | 66 static constexpr InstValueType kImmed8Shift = 0; |
| 63 static constexpr uint32_t kRotateBits = 4; | 67 static constexpr InstValueType kRotateBits = 4; |
| 64 static constexpr uint32_t kRotateShift = 8; | 68 static constexpr InstValueType kRotateShift = 8; |
| 65 | 69 |
| 66 // Shift instruction register fields encodings. | 70 // Shift instruction register fields encodings. |
| 67 static constexpr uint32_t kShiftImmShift = 7; | 71 static constexpr InstValueType kShiftImmShift = 7; |
| 68 static constexpr uint32_t kShiftImmBits = 5; | 72 static constexpr InstValueType kShiftImmBits = 5; |
| 69 static constexpr uint32_t kShiftShift = 5; | 73 static constexpr InstValueType kShiftShift = 5; |
| 70 | 74 |
| 71 static constexpr uint32_t kImmed12Bits = 12; | 75 static constexpr InstValueType kImmed12Bits = 12; |
| 72 static constexpr uint32_t kImm12Shift = 0; | 76 static constexpr InstValueType kImm12Shift = 0; |
| 73 | 77 |
| 74 // Type of instruction encoding (bits 25-27). See ARM section A5.1 | 78 // Type of instruction encoding (bits 25-27). See ARM section A5.1 |
| 75 static constexpr uint32_t kInstTypeDataRegister = 0; // i.e. 000 | 79 static constexpr InstValueType kInstTypeDataRegister = 0; // i.e. 000 |
| 76 static constexpr uint32_t kInstTypeDataImmediate = 1; // i.e. 001 | 80 static constexpr InstValueType kInstTypeDataImmediate = 1; // i.e. 001 |
| 77 static constexpr uint32_t kInstTypeMemImmediate = 2; // i.e. 010 | 81 static constexpr InstValueType kInstTypeMemImmediate = 2; // i.e. 010 |
| 78 | 82 |
| 79 inline uint32_t encodeBool(bool b) { return b ? 1 : 0; } | 83 // Offset modifier to current PC for next instruction. The offset is off by 8 |
| 84 // due to the way the ARM CPUs read PC. | |
| 85 static constexpr InstOffsetType kPCReadOffset = 8; | |
| 80 | 86 |
| 81 inline uint32_t encodeGPRRegister(RegARM32::GPRRegister Rn) { | 87 // Mask to pull out PC offset from branch (b) instruction. |
| 82 return static_cast<uint32_t>(Rn); | 88 static constexpr InstOffsetType kBranchOffsetMask = 0x00ffffff; |
| 89 | |
| 90 inline InstValueType encodeBool(bool b) { return b ? 1 : 0; } | |
| 91 | |
| 92 inline InstValueType encodeGPRRegister(RegARM32::GPRRegister Rn) { | |
| 93 return static_cast<InstValueType>(Rn); | |
| 83 } | 94 } |
| 84 | 95 |
| 85 inline bool isGPRRegisterDefined(RegARM32::GPRRegister R) { | 96 inline bool isGPRRegisterDefined(RegARM32::GPRRegister R) { |
| 86 return R != RegARM32::Encoded_Not_GPR; | 97 return R != RegARM32::Encoded_Not_GPR; |
| 87 } | 98 } |
| 88 | 99 |
| 89 inline bool isGPRRegisterDefined(uint32_t R) { | 100 inline bool isGPRRegisterDefined(InstValueType R) { |
| 90 return R != encodeGPRRegister(RegARM32::Encoded_Not_GPR); | 101 return R != encodeGPRRegister(RegARM32::Encoded_Not_GPR); |
| 91 } | 102 } |
| 92 | 103 |
| 93 inline bool isConditionDefined(CondARM32::Cond Cond) { | 104 inline bool isConditionDefined(CondARM32::Cond Cond) { |
| 94 return Cond != CondARM32::kNone; | 105 return Cond != CondARM32::kNone; |
| 95 } | 106 } |
| 96 | 107 |
| 97 inline uint32_t encodeCondition(CondARM32::Cond Cond) { | 108 inline InstValueType encodeCondition(CondARM32::Cond Cond) { |
| 98 return static_cast<uint32_t>(Cond); | 109 return static_cast<InstValueType>(Cond); |
| 99 } | 110 } |
| 100 | 111 |
| 101 uint32_t encodeShift(OperandARM32::ShiftKind Shift) { | 112 InstValueType encodeShift(OperandARM32::ShiftKind Shift) { |
| 102 // Follows encoding in ARM section A8.4.1 "Constant shifts". | 113 // Follows encoding in ARM section A8.4.1 "Constant shifts". |
| 103 switch (Shift) { | 114 switch (Shift) { |
| 104 case OperandARM32::kNoShift: | 115 case OperandARM32::kNoShift: |
| 105 case OperandARM32::LSL: | 116 case OperandARM32::LSL: |
| 106 return 0; // 0b00 | 117 return 0; // 0b00 |
| 107 case OperandARM32::LSR: | 118 case OperandARM32::LSR: |
| 108 return 1; // 0b01 | 119 return 1; // 0b01 |
| 109 case OperandARM32::ASR: | 120 case OperandARM32::ASR: |
| 110 return 2; // 0b10 | 121 return 2; // 0b10 |
| 111 case OperandARM32::ROR: | 122 case OperandARM32::ROR: |
| 112 case OperandARM32::RRX: | 123 case OperandARM32::RRX: |
| 113 return 3; // 0b11 | 124 return 3; // 0b11 |
| 114 } | 125 } |
| 115 } | 126 } |
| 116 | 127 |
| 117 // Returns the bits in the corresponding masked value. | 128 // Returns the bits in the corresponding masked value. |
| 118 inline uint32_t mask(uint32_t Value, uint32_t Shift, uint32_t Bits) { | 129 inline InstValueType mask(InstValueType Value, InstValueType Shift, |
| 130 InstValueType Bits) { | |
| 119 return (Value >> Shift) & ((1 << Bits) - 1); | 131 return (Value >> Shift) & ((1 << Bits) - 1); |
| 120 } | 132 } |
| 121 | 133 |
| 122 // Extract out a Bit in Value. | 134 // Extract out a Bit in Value. |
| 123 inline bool isBitSet(uint32_t Bit, uint32_t Value) { | 135 inline bool isBitSet(InstValueType Bit, InstValueType Value) { |
| 124 return (Value & Bit) == Bit; | 136 return (Value & Bit) == Bit; |
| 125 } | 137 } |
| 126 | 138 |
| 127 // Returns the GPR register at given Shift in Value. | 139 // Returns the GPR register at given Shift in Value. |
| 128 inline RegARM32::GPRRegister getGPRReg(uint32_t Shift, uint32_t Value) { | 140 inline RegARM32::GPRRegister getGPRReg(InstValueType Shift, |
| 141 InstValueType Value) { | |
| 129 return static_cast<RegARM32::GPRRegister>((Value >> Shift) & 0xF); | 142 return static_cast<RegARM32::GPRRegister>((Value >> Shift) & 0xF); |
| 130 } | 143 } |
| 131 | 144 |
| 132 // The way an operand was decoded in functions decodeOperand and decodeAddress | 145 // The way an operand was decoded in functions decodeOperand and decodeAddress |
| 133 // below. | 146 // below. |
| 134 enum DecodedResult { | 147 enum DecodedResult { |
| 135 // Unable to decode, value left undefined. | 148 // Unable to decode, value left undefined. |
| 136 CantDecode = 0, | 149 CantDecode = 0, |
| 137 // Value is register found. | 150 // Value is register found. |
| 138 DecodedAsRegister, | 151 DecodedAsRegister, |
| 139 // Value=rrrriiiiiiii where rrrr is the rotation, and iiiiiiii is the imm8 | 152 // Value=rrrriiiiiiii where rrrr is the rotation, and iiiiiiii is the imm8 |
| 140 // value. | 153 // value. |
| 141 DecodedAsRotatedImm8, | 154 DecodedAsRotatedImm8, |
| 142 // i.e. 0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn, | 155 // i.e. 0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn, |
| 143 // p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to | 156 // p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to |
| 144 // Rn should be used, and iiiiiiiiiiii is the offset. | 157 // Rn should be used, and iiiiiiiiiiii is the offset. |
| 145 DecodedAsImmRegOffset | 158 DecodedAsImmRegOffset |
| 146 }; | 159 }; |
| 147 | 160 |
| 148 // Encodes iiiiitt0mmmm for data-processing (2nd) operands where iiiii=Imm5, | 161 // Encodes iiiiitt0mmmm for data-processing (2nd) operands where iiiii=Imm5, |
| 149 // tt=Shift, and mmmm=Rm. | 162 // tt=Shift, and mmmm=Rm. |
| 150 uint32_t encodeShiftRotateImm5(uint32_t Rm, OperandARM32::ShiftKind Shift, | 163 InstValueType encodeShiftRotateImm5(InstValueType Rm, |
| 151 uint32_t imm5) { | 164 OperandARM32::ShiftKind Shift, |
| 165 InstValueType imm5) { | |
| 152 (void)kShiftImmBits; | 166 (void)kShiftImmBits; |
| 153 assert(imm5 < (1 << kShiftImmBits)); | 167 assert(imm5 < (1 << kShiftImmBits)); |
| 154 return (imm5 << kShiftImmShift) | (encodeShift(Shift) << kShiftShift) | Rm; | 168 return (imm5 << kShiftImmShift) | (encodeShift(Shift) << kShiftShift) | Rm; |
| 155 } | 169 } |
| 156 | 170 |
| 157 DecodedResult decodeOperand(const Operand *Opnd, uint32_t &Value) { | 171 DecodedResult decodeOperand(const Operand *Opnd, InstValueType &Value) { |
| 158 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { | 172 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { |
| 159 if (Var->hasReg()) { | 173 if (Var->hasReg()) { |
| 160 Value = Var->getRegNum(); | 174 Value = Var->getRegNum(); |
| 161 return DecodedAsRegister; | 175 return DecodedAsRegister; |
| 162 } | 176 } |
| 163 } else if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Opnd)) { | 177 } else if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Opnd)) { |
| 164 const uint32_t Immed8 = FlexImm->getImm(); | 178 const InstValueType Immed8 = FlexImm->getImm(); |
| 165 const uint32_t Rotate = FlexImm->getRotateAmt(); | 179 const InstValueType Rotate = FlexImm->getRotateAmt(); |
| 166 assert((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits))); | 180 if (!((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits)))) |
| 167 // TODO(kschimpf): Remove void casts when MINIMAL build allows. | 181 return CantDecode; |
| 168 (void)kRotateBits; | |
| 169 (void)kImmed8Bits; | |
| 170 Value = (Rotate << kRotateShift) | (Immed8 << kImmed8Shift); | 182 Value = (Rotate << kRotateShift) | (Immed8 << kImmed8Shift); |
| 171 return DecodedAsRotatedImm8; | 183 return DecodedAsRotatedImm8; |
| 172 } | 184 } |
| 173 return CantDecode; | 185 return CantDecode; |
| 174 } | 186 } |
| 175 | 187 |
| 176 uint32_t decodeImmRegOffset(RegARM32::GPRRegister Reg, int32_t Offset, | 188 InstValueType decodeImmRegOffset(RegARM32::GPRRegister Reg, |
| 177 OperandARM32Mem::AddrMode Mode) { | 189 InstOffsetType Offset, |
| 178 uint32_t Value = Mode | (encodeGPRRegister(Reg) << kRnShift); | 190 OperandARM32Mem::AddrMode Mode) { |
| 191 InstValueType Value = Mode | (encodeGPRRegister(Reg) << kRnShift); | |
| 179 if (Offset < 0) { | 192 if (Offset < 0) { |
| 180 Value = (Value ^ U) | -Offset; // Flip U to adjust sign. | 193 Value = (Value ^ U) | -Offset; // Flip U to adjust sign. |
| 181 } else { | 194 } else { |
| 182 Value |= Offset; | 195 Value |= Offset; |
| 183 } | 196 } |
| 184 return Value; | 197 return Value; |
| 185 } | 198 } |
| 186 | 199 |
| 187 // Decodes memory address Opnd, and encodes that information into Value, | 200 // Decodes memory address Opnd, and encodes that information into Value, |
| 188 // based on how ARM represents the address. Returns how the value was encoded. | 201 // based on how ARM represents the address. Returns how the value was encoded. |
| 189 DecodedResult decodeAddress(const Operand *Opnd, uint32_t &Value) { | 202 DecodedResult decodeAddress(const Operand *Opnd, InstValueType &Value) { |
| 190 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { | 203 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { |
| 191 // Should be a stack variable, with an offset. | 204 // Should be a stack variable, with an offset. |
| 192 if (Var->hasReg()) | 205 if (Var->hasReg()) |
| 193 return CantDecode; | 206 return CantDecode; |
| 194 const int32_t Offset = Var->getStackOffset(); | 207 const InstOffsetType Offset = Var->getStackOffset(); |
| 195 if (!Utils::IsAbsoluteUint(12, Offset)) | 208 if (!Utils::IsAbsoluteUint(12, Offset)) |
| 196 return CantDecode; | 209 return CantDecode; |
| 197 Value = decodeImmRegOffset(RegARM32::Encoded_Reg_sp, Offset, | 210 Value = decodeImmRegOffset(RegARM32::Encoded_Reg_sp, Offset, |
| 198 OperandARM32Mem::Offset); | 211 OperandARM32Mem::Offset); |
| 199 return DecodedAsImmRegOffset; | 212 return DecodedAsImmRegOffset; |
| 200 } | 213 } |
| 201 return CantDecode; | 214 return CantDecode; |
| 202 } | 215 } |
| 203 | 216 |
| 204 } // end of anonymous namespace | 217 } // end of anonymous namespace |
| 205 | 218 |
| 206 namespace Ice { | 219 namespace Ice { |
| 220 namespace ARM32 { | |
| 207 | 221 |
| 208 void ARM32::AssemblerARM32::bindCfgNodeLabel(const CfgNode *Node) { | 222 void AssemblerARM32::bindCfgNodeLabel(const CfgNode *Node) { |
| 209 if (BuildDefs::dump() && !Ctx->getFlags().getDisableHybridAssembly()) { | 223 if (BuildDefs::dump() && !Ctx->getFlags().getDisableHybridAssembly()) { |
| 210 // Generate label name so that branches can find it. | 224 // Generate label name so that branches can find it. |
| 211 constexpr SizeT InstSize = 0; | 225 constexpr SizeT InstSize = 0; |
| 212 emitTextInst(Node->getAsmName() + ":", InstSize); | 226 emitTextInst(Node->getAsmName() + ":", InstSize); |
| 213 } | 227 } |
| 214 SizeT NodeNumber = Node->getIndex(); | 228 SizeT NodeNumber = Node->getIndex(); |
| 215 assert(!getPreliminary()); | 229 assert(!getPreliminary()); |
| 216 Label *L = getOrCreateCfgNodeLabel(NodeNumber); | 230 Label *L = getOrCreateCfgNodeLabel(NodeNumber); |
| 217 this->bind(L); | 231 this->bind(L); |
| 218 } | 232 } |
| 219 | 233 |
| 220 Label *ARM32::AssemblerARM32::getOrCreateLabel(SizeT Number, | 234 Label *AssemblerARM32::getOrCreateLabel(SizeT Number, LabelVector &Labels) { |
| 221 LabelVector &Labels) { | |
| 222 Label *L = nullptr; | 235 Label *L = nullptr; |
| 223 if (Number == Labels.size()) { | 236 if (Number == Labels.size()) { |
| 224 L = new (this->allocate<Label>()) Label(); | 237 L = new (this->allocate<Label>()) Label(); |
| 225 Labels.push_back(L); | 238 Labels.push_back(L); |
| 226 return L; | 239 return L; |
| 227 } | 240 } |
| 228 if (Number > Labels.size()) { | 241 if (Number > Labels.size()) { |
| 229 Labels.resize(Number + 1); | 242 Labels.resize(Number + 1); |
| 230 } | 243 } |
| 231 L = Labels[Number]; | 244 L = Labels[Number]; |
| 232 if (!L) { | 245 if (!L) { |
| 233 L = new (this->allocate<Label>()) Label(); | 246 L = new (this->allocate<Label>()) Label(); |
| 234 Labels[Number] = L; | 247 Labels[Number] = L; |
| 235 } | 248 } |
| 236 return L; | 249 return L; |
| 237 } | 250 } |
| 238 | 251 |
| 239 void ARM32::AssemblerARM32::bind(Label *label) { | 252 InstValueType AssemblerARM32::encodeBranchOffset(InstOffsetType Offset, |
| 240 intptr_t bound = Buffer.size(); | 253 InstValueType Inst) { |
| 241 assert(!label->isBound()); // Labels can only be bound once. | 254 // TODO(kschimpf): Decide if we need to handle far jumps (ignoring for now). |
|
Jim Stichnoth
2015/10/23 21:32:07
For this TODO and the related one below, this is a
Karl
2015/10/26 18:32:43
Added function canEncodeBranchOffset to do check.
| |
| 242 while (label->isLinked()) { | 255 // Adjust offset to the way ARM CPUs read PC. |
| 243 intptr_t position = label->getLinkPosition(); | 256 Offset -= kPCReadOffset; |
| 244 intptr_t next = Buffer.load<int32_t>(position); | 257 |
| 245 Buffer.store<int32_t>(position, bound - (position + 4)); | 258 // Properly preserve only the bits supported in the instruction. |
| 246 label->setPosition(next); | 259 Offset >>= 2; |
| 247 } | 260 Offset &= kBranchOffsetMask; |
| 248 // TODO(kschimpf) Decide if we have near jumps. | 261 return (Inst & ~kBranchOffsetMask) | Offset; |
| 249 label->bindTo(bound); | |
| 250 } | 262 } |
| 251 | 263 |
| 252 void ARM32::AssemblerARM32::emitTextInst(const std::string &Text, | 264 InstOffsetType AssemblerARM32::decodeBranchOffset(InstValueType Inst) { |
| 253 SizeT InstSize) { | 265 // Sign-extend, left-shift by 2, and adjust to the way ARM CPUs read PC. |
| 266 InstOffsetType Offset = | |
| 267 static_cast<InstOffsetType>((Inst & kBranchOffsetMask) << 8); | |
| 268 return (Offset >> 6) + kPCReadOffset; | |
| 269 } | |
| 270 | |
| 271 void AssemblerARM32::bind(Label *L) { | |
| 272 // TODO(kschimpf): Decide if we need to handle far jumps (ignoring for now). | |
| 273 InstOffsetType BoundPc = Buffer.size(); | |
| 274 assert(!L->isBound()); // Labels can only be bound once. | |
| 275 while (L->isLinked()) { | |
| 276 InstOffsetType Position = L->getLinkPosition(); | |
| 277 InstOffsetType Dest = BoundPc - Position; | |
| 278 InstValueType Inst = Buffer.load<InstValueType>(Position); | |
| 279 Buffer.store<InstValueType>(Position, encodeBranchOffset(Dest, Inst)); | |
| 280 L->setPosition(decodeBranchOffset(Inst)); | |
| 281 } | |
| 282 L->bindTo(BoundPc); | |
| 283 } | |
| 284 | |
| 285 void AssemblerARM32::emitTextInst(const std::string &Text, SizeT InstSize) { | |
| 254 AssemblerBuffer::EnsureCapacity ensured(&Buffer); | 286 AssemblerBuffer::EnsureCapacity ensured(&Buffer); |
| 255 AssemblerFixup *F = createTextFixup(Text, InstSize); | 287 AssemblerFixup *F = createTextFixup(Text, InstSize); |
| 256 emitFixup(F); | 288 emitFixup(F); |
| 257 for (SizeT I = 0; I < InstSize; ++I) | 289 for (SizeT I = 0; I < InstSize; ++I) |
| 258 Buffer.emit<char>(0); | 290 Buffer.emit<char>(0); |
| 259 } | 291 } |
| 260 | 292 |
| 261 void ARM32::AssemblerARM32::emitType01(CondARM32::Cond Cond, uint32_t Type, | 293 void AssemblerARM32::emitType01(CondARM32::Cond Cond, InstValueType Type, |
| 262 uint32_t Opcode, bool SetCc, uint32_t Rn, | 294 InstValueType Opcode, bool SetCc, |
| 263 uint32_t Rd, uint32_t Imm12) { | 295 InstValueType Rn, InstValueType Rd, |
| 296 InstValueType Imm12) { | |
| 264 assert(isGPRRegisterDefined(Rd)); | 297 assert(isGPRRegisterDefined(Rd)); |
| 265 // TODO(kschimpf): Remove void cast when MINIMAL build allows. | 298 // TODO(kschimpf): Remove void cast when MINIMAL build allows. |
| 266 (void)isGPRRegisterDefined(Rd); | 299 (void)isGPRRegisterDefined(Rd); |
| 267 assert(Cond != CondARM32::kNone); | 300 assert(Cond != CondARM32::kNone); |
| 268 AssemblerBuffer::EnsureCapacity ensured(&Buffer); | 301 AssemblerBuffer::EnsureCapacity ensured(&Buffer); |
| 269 const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | | 302 const InstValueType Encoding = |
| 270 (Type << kTypeShift) | (Opcode << kOpcodeShift) | | 303 (encodeCondition(Cond) << kConditionShift) | (Type << kTypeShift) | |
| 271 (encodeBool(SetCc) << kSShift) | (Rn << kRnShift) | | 304 (Opcode << kOpcodeShift) | (encodeBool(SetCc) << kSShift) | |
| 272 (Rd << kRdShift) | Imm12; | 305 (Rn << kRnShift) | (Rd << kRdShift) | Imm12; |
| 273 emitInst(Encoding); | 306 emitInst(Encoding); |
| 274 } | 307 } |
| 275 | 308 |
| 276 void ARM32::AssemblerARM32::emitMemOp(CondARM32::Cond Cond, uint32_t InstType, | 309 void AssemblerARM32::emitType05(CondARM32::Cond Cond, InstOffsetType Offset, |
| 277 bool IsLoad, bool IsByte, uint32_t Rt, | 310 bool Link) { |
| 278 uint32_t Address) { | 311 // cccc101liiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond, l=Link, and |
| 312 // iiiiiiiiiiiiiiiiiiiiiiii= | |
| 313 // EncodedBranchOffset(cccc101l000000000000000000000000, Offset); | |
| 314 if (!isConditionDefined(Cond)) | |
| 315 return setNeedsTextFixup(); | |
| 316 AssemblerBuffer::EnsureCapacity ensured(&Buffer); | |
| 317 InstValueType Encoding = static_cast<int32_t>(Cond) << kConditionShift | | |
| 318 5 << kTypeShift | (Link ? 1 : 0) << kLinkShift; | |
| 319 Encoding = encodeBranchOffset(Offset, Encoding); | |
| 320 emitInst(Encoding); | |
| 321 } | |
| 322 | |
| 323 void AssemblerARM32::emitBranch(Label *L, CondARM32::Cond Cond, bool Link) { | |
| 324 // TODO(kschimpf): Is there a way to verify that near jump applies? | |
| 325 if (L->isBound()) { | |
| 326 const int32_t Dest = L->getPosition() - Buffer.size(); | |
| 327 emitType05(Cond, Dest, Link); | |
| 328 return; | |
| 329 } | |
| 330 const InstOffsetType Position = Buffer.size(); | |
| 331 // Use the offset field of the branch instruction for linking the sites. | |
| 332 emitType05(Cond, L->getEncodedPosition(), Link); | |
| 333 if (!needsTextFixup()) | |
| 334 L->linkTo(Position); | |
| 335 } | |
| 336 | |
| 337 void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, InstValueType InstType, | |
| 338 bool IsLoad, bool IsByte, InstValueType Rt, | |
| 339 InstValueType Address) { | |
| 279 assert(isGPRRegisterDefined(Rt)); | 340 assert(isGPRRegisterDefined(Rt)); |
| 280 assert(Cond != CondARM32::kNone); | 341 assert(Cond != CondARM32::kNone); |
| 281 AssemblerBuffer::EnsureCapacity ensured(&Buffer); | 342 AssemblerBuffer::EnsureCapacity ensured(&Buffer); |
| 282 const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | | 343 const InstValueType Encoding = (encodeCondition(Cond) << kConditionShift) | |
| 283 (InstType << kTypeShift) | (IsLoad ? L : 0) | | 344 (InstType << kTypeShift) | (IsLoad ? L : 0) | |
| 284 (IsByte ? B : 0) | (Rt << kRdShift) | Address; | 345 (IsByte ? B : 0) | (Rt << kRdShift) | Address; |
| 285 emitInst(Encoding); | 346 emitInst(Encoding); |
| 286 } | 347 } |
| 287 | 348 |
| 288 void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, | 349 void AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, |
| 289 const Operand *OpSrc1, bool SetFlags, | 350 const Operand *OpSrc1, bool SetFlags, |
| 290 CondARM32::Cond Cond) { | 351 CondARM32::Cond Cond) { |
| 291 uint32_t Rd; | 352 InstValueType Rd; |
| 292 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 353 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) |
| 293 return setNeedsTextFixup(); | 354 return setNeedsTextFixup(); |
| 294 uint32_t Rn; | 355 InstValueType Rn; |
| 295 if (decodeOperand(OpRn, Rn) != DecodedAsRegister) | 356 if (decodeOperand(OpRn, Rn) != DecodedAsRegister) |
| 296 return setNeedsTextFixup(); | 357 return setNeedsTextFixup(); |
| 297 constexpr uint32_t Add = B2; // 0100 | 358 constexpr InstValueType Add = B2; // 0100 |
| 298 uint32_t Src1Value; | 359 InstValueType Src1Value; |
| 299 // TODO(kschimpf) Other possible decodings of add. | 360 // TODO(kschimpf) Other possible decodings of add. |
| 300 switch (decodeOperand(OpSrc1, Src1Value)) { | 361 switch (decodeOperand(OpSrc1, Src1Value)) { |
| 301 default: | 362 default: |
| 302 return setNeedsTextFixup(); | 363 return setNeedsTextFixup(); |
| 303 case DecodedAsRegister: { | 364 case DecodedAsRegister: { |
| 304 // ADD (register) - ARM section A8.8.7, encoding A1: | 365 // ADD (register) - ARM section A8.8.7, encoding A1: |
| 305 // add{s}<c> <Rd>, <Rn>, <Rm>{, <shiff>} | 366 // add{s}<c> <Rd>, <Rn>, <Rm>{, <shiff>} |
| 306 // ADD (Sp plus register) - ARM section A8.8.11, encoding A1: | 367 // ADD (Sp plus register) - ARM section A8.8.11, encoding A1: |
| 307 // add{s}<c> sp, <Rn>, <Rm>{, <shiff>} | 368 // add{s}<c> sp, <Rn>, <Rm>{, <shiff>} |
| 308 // | 369 // |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 325 // s=SetFlags and iiiiiiiiiiii=Src1Value=RotatedImm8. | 386 // s=SetFlags and iiiiiiiiiiii=Src1Value=RotatedImm8. |
| 326 if ((Rd == RegARM32::Encoded_Reg_pc && SetFlags)) | 387 if ((Rd == RegARM32::Encoded_Reg_pc && SetFlags)) |
| 327 // Conditions of rule violated. | 388 // Conditions of rule violated. |
| 328 return setNeedsTextFixup(); | 389 return setNeedsTextFixup(); |
| 329 emitType01(Cond, kInstTypeDataImmediate, Add, SetFlags, Rn, Rd, Src1Value); | 390 emitType01(Cond, kInstTypeDataImmediate, Add, SetFlags, Rn, Rd, Src1Value); |
| 330 return; | 391 return; |
| 331 } | 392 } |
| 332 }; | 393 }; |
| 333 } | 394 } |
| 334 | 395 |
| 335 void ARM32::AssemblerARM32::bkpt(uint16_t Imm16) { | 396 void AssemblerARM32::b(Label *L, CondARM32::Cond Cond) { |
| 397 emitBranch(L, Cond, false); | |
| 398 } | |
| 399 | |
| 400 void AssemblerARM32::bkpt(uint16_t Imm16) { | |
| 336 // BKPT - ARM section A*.8.24 - encoding A1: | 401 // BKPT - ARM section A*.8.24 - encoding A1: |
| 337 // bkpt #<Imm16> | 402 // bkpt #<Imm16> |
| 338 // | 403 // |
| 339 // cccc00010010iiiiiiiiiiii0111iiii where cccc=AL and iiiiiiiiiiiiiiii=Imm16 | 404 // cccc00010010iiiiiiiiiiii0111iiii where cccc=AL and iiiiiiiiiiiiiiii=Imm16 |
| 340 AssemblerBuffer::EnsureCapacity ensured(&Buffer); | 405 AssemblerBuffer::EnsureCapacity ensured(&Buffer); |
| 341 const uint32_t Encoding = (CondARM32::AL << kConditionShift) | B24 | B21 | | 406 const InstValueType Encoding = (CondARM32::AL << kConditionShift) | B24 | |
| 342 ((Imm16 >> 4) << 8) | B6 | B5 | B4 | (Imm16 & 0xf); | 407 B21 | ((Imm16 >> 4) << 8) | B6 | B5 | B4 | |
| 408 (Imm16 & 0xf); | |
| 343 emitInst(Encoding); | 409 emitInst(Encoding); |
| 344 } | 410 } |
| 345 | 411 |
| 346 void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) { | 412 void AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) { |
| 347 // BX - ARM section A8.8.27, encoding A1: | 413 // BX - ARM section A8.8.27, encoding A1: |
| 348 // bx<c> <Rm> | 414 // bx<c> <Rm> |
| 349 // | 415 // |
| 350 // cccc000100101111111111110001mmmm where mmmm=rm and cccc=Cond. | 416 // cccc000100101111111111110001mmmm where mmmm=rm and cccc=Cond. |
| 351 if (!(isGPRRegisterDefined(Rm) && isConditionDefined(Cond))) | 417 if (!(isGPRRegisterDefined(Rm) && isConditionDefined(Cond))) |
| 352 return setNeedsTextFixup(); | 418 return setNeedsTextFixup(); |
| 353 AssemblerBuffer::EnsureCapacity ensured(&Buffer); | 419 AssemblerBuffer::EnsureCapacity ensured(&Buffer); |
| 354 const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | B24 | | 420 const InstValueType Encoding = (encodeCondition(Cond) << kConditionShift) | |
| 355 B21 | (0xfff << 8) | B4 | | 421 B24 | B21 | (0xfff << 8) | B4 | |
| 356 (encodeGPRRegister(Rm) << kRmShift); | 422 (encodeGPRRegister(Rm) << kRmShift); |
| 357 emitInst(Encoding); | 423 emitInst(Encoding); |
| 358 } | 424 } |
| 359 | 425 |
| 360 void ARM32::AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, | 426 void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, |
| 361 CondARM32::Cond Cond) { | 427 CondARM32::Cond Cond) { |
| 362 uint32_t Rt; | 428 InstValueType Rt; |
| 363 if (decodeOperand(OpRt, Rt) != DecodedAsRegister) | 429 if (decodeOperand(OpRt, Rt) != DecodedAsRegister) |
| 364 return setNeedsTextFixup(); | 430 return setNeedsTextFixup(); |
| 365 uint32_t Address; | 431 InstValueType Address; |
| 366 if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset) | 432 if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset) |
| 367 return setNeedsTextFixup(); | 433 return setNeedsTextFixup(); |
| 368 // LDR (immediate) - ARM section A8.8.63, encoding A1: | 434 // LDR (immediate) - ARM section A8.8.63, encoding A1: |
| 369 // ldr<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 | 435 // ldr<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 |
| 370 // ldr<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 | 436 // ldr<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 |
| 371 // ldr<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 | 437 // ldr<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 |
| 372 // LDRB (immediate) - ARM section A8.8.68, encoding A1: | 438 // LDRB (immediate) - ARM section A8.8.68, encoding A1: |
| 373 // ldrb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 | 439 // ldrb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 |
| 374 // ldrb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 | 440 // ldrb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 |
| 375 // ldrb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 | 441 // ldrb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 386 return setNeedsTextFixup(); | 452 return setNeedsTextFixup(); |
| 387 if (!isBitSet(P, Address) && isBitSet(W, Address)) | 453 if (!isBitSet(P, Address) && isBitSet(W, Address)) |
| 388 return setNeedsTextFixup(); | 454 return setNeedsTextFixup(); |
| 389 if (!IsByte && (getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) && | 455 if (!IsByte && (getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) && |
| 390 !isBitSet(P, Address) && isBitSet(U, Address) & !isBitSet(W, Address) && | 456 !isBitSet(P, Address) && isBitSet(U, Address) & !isBitSet(W, Address) && |
| 391 (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */)) | 457 (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */)) |
| 392 return setNeedsTextFixup(); | 458 return setNeedsTextFixup(); |
| 393 emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address); | 459 emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address); |
| 394 } | 460 } |
| 395 | 461 |
| 396 void ARM32::AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, | 462 void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, |
| 397 CondARM32::Cond Cond) { | 463 CondARM32::Cond Cond) { |
| 398 uint32_t Rd; | 464 InstValueType Rd; |
| 399 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 465 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) |
| 400 return setNeedsTextFixup(); | 466 return setNeedsTextFixup(); |
| 401 uint32_t Src; | 467 InstValueType Src; |
| 402 // TODO(kschimpf) Handle other forms of mov. | 468 // TODO(kschimpf) Handle other forms of mov. |
| 403 if (decodeOperand(OpSrc, Src) != DecodedAsRotatedImm8) | 469 if (decodeOperand(OpSrc, Src) != DecodedAsRotatedImm8) |
| 404 return setNeedsTextFixup(); | 470 return setNeedsTextFixup(); |
| 405 // MOV (immediate) - ARM section A8.8.102, encoding A1: | 471 // MOV (immediate) - ARM section A8.8.102, encoding A1: |
| 406 // mov{S}<c> <Rd>, #<RotatedImm8> | 472 // mov{S}<c> <Rd>, #<RotatedImm8> |
| 407 // | 473 // |
| 408 // cccc0011101s0000ddddiiiiiiiiiiii where cccc=Cond, s=SetFlags, dddd=Rd, | 474 // cccc0011101s0000ddddiiiiiiiiiiii where cccc=Cond, s=SetFlags, dddd=Rd, |
| 409 // and iiiiiiiiiiii=RotatedImm8=Src. Note: We don't use movs in this | 475 // and iiiiiiiiiiii=RotatedImm8=Src. Note: We don't use movs in this |
| 410 // assembler. | 476 // assembler. |
| 411 constexpr bool SetFlags = false; | 477 constexpr bool SetFlags = false; |
| 412 if ((Rd == RegARM32::Encoded_Reg_pc && SetFlags)) | 478 if ((Rd == RegARM32::Encoded_Reg_pc && SetFlags)) |
| 413 // Conditions of rule violated. | 479 // Conditions of rule violated. |
| 414 return setNeedsTextFixup(); | 480 return setNeedsTextFixup(); |
| 415 constexpr uint32_t Rn = 0; | 481 constexpr InstValueType Rn = 0; |
| 416 constexpr uint32_t Mov = B3 | B2 | B0; // 1101. | 482 constexpr InstValueType Mov = B3 | B2 | B0; // 1101. |
| 417 emitType01(Cond, kInstTypeDataImmediate, Mov, SetFlags, Rn, Rd, Src); | 483 emitType01(Cond, kInstTypeDataImmediate, Mov, SetFlags, Rn, Rd, Src); |
| 418 } | 484 } |
| 419 | 485 |
| 420 void ARM32::AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, | 486 void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, |
| 421 CondARM32::Cond Cond) { | 487 CondARM32::Cond Cond) { |
| 422 uint32_t Rt; | 488 InstValueType Rt; |
| 423 if (decodeOperand(OpRt, Rt) != DecodedAsRegister) | 489 if (decodeOperand(OpRt, Rt) != DecodedAsRegister) |
| 424 return setNeedsTextFixup(); | 490 return setNeedsTextFixup(); |
| 425 uint32_t Address; | 491 InstValueType Address; |
| 426 if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset) | 492 if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset) |
| 427 return setNeedsTextFixup(); | 493 return setNeedsTextFixup(); |
| 428 // STR (immediate) - ARM section A8.8.204, encoding A1: | 494 // STR (immediate) - ARM section A8.8.204, encoding A1: |
| 429 // str<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 | 495 // str<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 |
| 430 // str<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 | 496 // str<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 |
| 431 // str<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 | 497 // str<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 |
| 432 // STRB (immediate) - ARM section A8.8.207, encoding A1: | 498 // STRB (immediate) - ARM section A8.8.207, encoding A1: |
| 433 // strb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 | 499 // strb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 |
| 434 // strb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 | 500 // strb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 |
| 435 // strb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 | 501 // strb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 446 return setNeedsTextFixup(); | 512 return setNeedsTextFixup(); |
| 447 if (!isBitSet(P, Address) && isBitSet(W, Address)) | 513 if (!isBitSet(P, Address) && isBitSet(W, Address)) |
| 448 return setNeedsTextFixup(); | 514 return setNeedsTextFixup(); |
| 449 if (!IsByte && (getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) && | 515 if (!IsByte && (getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) && |
| 450 isBitSet(P, Address) && !isBitSet(U, Address) && isBitSet(W, Address) && | 516 isBitSet(P, Address) && !isBitSet(U, Address) && isBitSet(W, Address) && |
| 451 (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */)) | 517 (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */)) |
| 452 return setNeedsTextFixup(); | 518 return setNeedsTextFixup(); |
| 453 emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address); | 519 emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address); |
| 454 } | 520 } |
| 455 | 521 |
| 456 void ARM32::AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, | 522 void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, |
| 457 const Operand *OpSrc1, bool SetFlags, | 523 const Operand *OpSrc1, bool SetFlags, |
| 458 CondARM32::Cond Cond) { | 524 CondARM32::Cond Cond) { |
| 459 uint32_t Rd; | 525 InstValueType Rd; |
| 460 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) | 526 if (decodeOperand(OpRd, Rd) != DecodedAsRegister) |
| 461 return setNeedsTextFixup(); | 527 return setNeedsTextFixup(); |
| 462 uint32_t Rn; | 528 InstValueType Rn; |
| 463 if (decodeOperand(OpRn, Rn) != DecodedAsRegister) | 529 if (decodeOperand(OpRn, Rn) != DecodedAsRegister) |
| 464 return setNeedsTextFixup(); | 530 return setNeedsTextFixup(); |
| 465 constexpr uint32_t Sub = B1; // 0010 | 531 constexpr InstValueType Sub = B1; // 0010 |
| 466 uint32_t Src1Value; | 532 InstValueType Src1Value; |
| 467 // TODO(kschimpf) Other possible decodings of sub. | 533 // TODO(kschimpf) Other possible decodings of sub. |
| 468 switch (decodeOperand(OpSrc1, Src1Value)) { | 534 switch (decodeOperand(OpSrc1, Src1Value)) { |
| 469 default: | 535 default: |
| 470 return setNeedsTextFixup(); | 536 return setNeedsTextFixup(); |
| 471 case DecodedAsRegister: { | 537 case DecodedAsRegister: { |
| 472 // SUB (register) - ARM section A8.8.223, encoding A1: | 538 // SUB (register) - ARM section A8.8.223, encoding A1: |
| 473 // sub{s}<c> <Rd>, <Rn>, <Rm>{, <shift>} | 539 // sub{s}<c> <Rd>, <Rn>, <Rm>{, <shift>} |
| 474 // SUB (SP minus register): See ARM section 8.8.226, encoding A1: | 540 // SUB (SP minus register): See ARM section 8.8.226, encoding A1: |
| 475 // sub{s}<c> <Rd>, sp, <Rm>{, <Shift>} | 541 // sub{s}<c> <Rd>, sp, <Rm>{, <Shift>} |
| 476 // | 542 // |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 493 // s=SetFlags and iiiiiiiiiiii=Src1Value=RotatedImm8 | 559 // s=SetFlags and iiiiiiiiiiii=Src1Value=RotatedImm8 |
| 494 if (Rd == RegARM32::Encoded_Reg_pc) | 560 if (Rd == RegARM32::Encoded_Reg_pc) |
| 495 // Conditions of rule violated. | 561 // Conditions of rule violated. |
| 496 return setNeedsTextFixup(); | 562 return setNeedsTextFixup(); |
| 497 emitType01(Cond, kInstTypeDataImmediate, Sub, SetFlags, Rn, Rd, Src1Value); | 563 emitType01(Cond, kInstTypeDataImmediate, Sub, SetFlags, Rn, Rd, Src1Value); |
| 498 return; | 564 return; |
| 499 } | 565 } |
| 500 } | 566 } |
| 501 } | 567 } |
| 502 | 568 |
| 569 } // end of namespace ARM32 | |
| 503 } // end of namespace Ice | 570 } // end of namespace Ice |
| OLD | NEW |