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 // |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 137 } | 137 } |
| 138 | 138 |
| 139 RegARM32::GPRRegister decodeGPRRegister(IValueT R) { | 139 RegARM32::GPRRegister decodeGPRRegister(IValueT R) { |
| 140 return static_cast<RegARM32::GPRRegister>(R); | 140 return static_cast<RegARM32::GPRRegister>(R); |
| 141 } | 141 } |
| 142 | 142 |
| 143 IValueT encodeCondition(CondARM32::Cond Cond) { | 143 IValueT encodeCondition(CondARM32::Cond Cond) { |
| 144 return static_cast<IValueT>(Cond); | 144 return static_cast<IValueT>(Cond); |
| 145 } | 145 } |
| 146 | 146 |
| 147 // Returns the SIMD encoding of the element type for the vector. | |
| 148 IValueT encodeElmtType(Type ElmtTy) { | |
| 149 switch (ElmtTy) { | |
| 150 case IceType_i8: | |
| 151 case IceType_f32: | |
| 152 return 0; | |
| 153 case IceType_i16: | |
| 154 return 1; | |
| 155 case IceType_i32: | |
| 156 return 2; | |
| 157 case IceType_i64: | |
| 158 return 3; | |
| 159 default: | |
| 160 llvm::report_fatal_error( | |
| 161 std::string("SIMD op: Don't understand element type") + | |
|
Jim Stichnoth
2016/02/01 21:00:23
Nit: I think this might be a bit clearer:
...er
Karl
2016/02/01 21:44:53
Since (a) the name is typeString, and (b) c++ stri
Karl
2016/02/01 21:59:00
Ok. I understand the request. Doing in separate Cl
| |
| 162 typeString(ElmtTy)); | |
| 163 } | |
| 164 } | |
| 165 | |
| 147 IValueT encodeShift(OperandARM32::ShiftKind Shift) { | 166 IValueT encodeShift(OperandARM32::ShiftKind Shift) { |
| 148 // Follows encoding in ARM section A8.4.1 "Constant shifts". | 167 // Follows encoding in ARM section A8.4.1 "Constant shifts". |
| 149 switch (Shift) { | 168 switch (Shift) { |
| 150 case OperandARM32::kNoShift: | 169 case OperandARM32::kNoShift: |
| 151 case OperandARM32::LSL: | 170 case OperandARM32::LSL: |
| 152 return 0; // 0b00 | 171 return 0; // 0b00 |
| 153 case OperandARM32::LSR: | 172 case OperandARM32::LSR: |
| 154 return 1; // 0b01 | 173 return 1; // 0b01 |
| 155 case OperandARM32::ASR: | 174 case OperandARM32::ASR: |
| 156 return 2; // 0b10 | 175 return 2; // 0b10 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 184 | 203 |
| 185 IValueT getEncodedSRegNum(const Variable *Var) { | 204 IValueT getEncodedSRegNum(const Variable *Var) { |
| 186 assert(Var->hasReg()); | 205 assert(Var->hasReg()); |
| 187 return RegARM32::getEncodedSReg(Var->getRegNum()); | 206 return RegARM32::getEncodedSReg(Var->getRegNum()); |
| 188 } | 207 } |
| 189 | 208 |
| 190 IValueT getEncodedDRegNum(const Variable *Var) { | 209 IValueT getEncodedDRegNum(const Variable *Var) { |
| 191 return RegARM32::getEncodedDReg(Var->getRegNum()); | 210 return RegARM32::getEncodedDReg(Var->getRegNum()); |
| 192 } | 211 } |
| 193 | 212 |
| 213 IValueT getEncodedQRegNum(const Variable *Var) { | |
| 214 return RegARM32::getEncodedQReg(Var->getRegNum()); | |
| 215 } | |
| 216 | |
| 194 IValueT getYInRegXXXXY(IValueT RegXXXXY) { return RegXXXXY & 0x1; } | 217 IValueT getYInRegXXXXY(IValueT RegXXXXY) { return RegXXXXY & 0x1; } |
| 195 | 218 |
| 196 IValueT getXXXXInRegXXXXY(IValueT RegXXXXY) { return RegXXXXY >> 1; } | 219 IValueT getXXXXInRegXXXXY(IValueT RegXXXXY) { return RegXXXXY >> 1; } |
| 197 | 220 |
| 198 IValueT getYInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX >> 4; } | 221 IValueT getYInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX >> 4; } |
| 199 | 222 |
| 200 IValueT getXXXXInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX & 0x0f; } | 223 IValueT getXXXXInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX & 0x0f; } |
| 201 | 224 |
| 202 // Defines layouts of an operand representing a (register) memory address, | 225 // Defines layouts of an operand representing a (register) memory address, |
| 203 // possibly modified by an immediate value. | 226 // possibly modified by an immediate value. |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 298 | 321 |
| 299 // Encodes mmmmtt01ssss for data-processing operands where mmmm=Rm, ssss=Rs, and | 322 // Encodes mmmmtt01ssss for data-processing operands where mmmm=Rm, ssss=Rs, and |
| 300 // tt=Shift. | 323 // tt=Shift. |
| 301 IValueT encodeShiftRotateReg(IValueT Rm, OperandARM32::ShiftKind Shift, | 324 IValueT encodeShiftRotateReg(IValueT Rm, OperandARM32::ShiftKind Shift, |
| 302 IValueT Rs) { | 325 IValueT Rs) { |
| 303 return (Rs << kRsShift) | (encodeShift(Shift) << kShiftShift) | B4 | | 326 return (Rs << kRsShift) | (encodeShift(Shift) << kShiftShift) | B4 | |
| 304 (Rm << kRmShift); | 327 (Rm << kRmShift); |
| 305 } | 328 } |
| 306 | 329 |
| 307 // Defines the set of registers expected in an operand. | 330 // Defines the set of registers expected in an operand. |
| 308 enum RegSetWanted { WantGPRegs, WantSRegs, WantDRegs }; | 331 enum RegSetWanted { WantGPRegs, WantSRegs, WantDRegs, WantQRegs }; |
| 309 | 332 |
| 310 EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value, | 333 EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value, |
| 311 RegSetWanted WantedRegSet) { | 334 RegSetWanted WantedRegSet) { |
| 312 Value = 0; // Make sure initialized. | 335 Value = 0; // Make sure initialized. |
| 313 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { | 336 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { |
| 314 if (Var->hasReg()) { | 337 if (Var->hasReg()) { |
| 315 switch (WantedRegSet) { | 338 switch (WantedRegSet) { |
| 316 case WantGPRegs: | 339 case WantGPRegs: |
| 317 Value = getEncodedGPRegNum(Var); | 340 Value = getEncodedGPRegNum(Var); |
| 318 break; | 341 break; |
| 319 case WantSRegs: | 342 case WantSRegs: |
| 320 Value = getEncodedSRegNum(Var); | 343 Value = getEncodedSRegNum(Var); |
| 321 break; | 344 break; |
| 322 case WantDRegs: | 345 case WantDRegs: |
| 323 Value = getEncodedDRegNum(Var); | 346 Value = getEncodedDRegNum(Var); |
| 324 break; | 347 break; |
| 348 case WantQRegs: | |
| 349 Value = getEncodedQRegNum(Var); | |
| 350 break; | |
| 325 } | 351 } |
| 326 return EncodedAsRegister; | 352 return EncodedAsRegister; |
| 327 } | 353 } |
| 328 return CantEncode; | 354 return CantEncode; |
| 329 } | 355 } |
| 330 if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Opnd)) { | 356 if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Opnd)) { |
| 331 const IValueT Immed8 = FlexImm->getImm(); | 357 const IValueT Immed8 = FlexImm->getImm(); |
| 332 const IValueT Rotate = FlexImm->getRotateAmt(); | 358 const IValueT Rotate = FlexImm->getRotateAmt(); |
| 333 if (!((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits)))) | 359 if (!((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits)))) |
| 334 return CantEncode; | 360 return CantEncode; |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 496 IValueT encodeSRegister(const Operand *OpReg, const char *RegName, | 522 IValueT encodeSRegister(const Operand *OpReg, const char *RegName, |
| 497 const char *InstName) { | 523 const char *InstName) { |
| 498 return encodeRegister(OpReg, WantSRegs, RegName, InstName); | 524 return encodeRegister(OpReg, WantSRegs, RegName, InstName); |
| 499 } | 525 } |
| 500 | 526 |
| 501 IValueT encodeDRegister(const Operand *OpReg, const char *RegName, | 527 IValueT encodeDRegister(const Operand *OpReg, const char *RegName, |
| 502 const char *InstName) { | 528 const char *InstName) { |
| 503 return encodeRegister(OpReg, WantDRegs, RegName, InstName); | 529 return encodeRegister(OpReg, WantDRegs, RegName, InstName); |
| 504 } | 530 } |
| 505 | 531 |
| 532 IValueT encodeQRegister(const Operand *OpReg, const char *RegName, | |
| 533 const char *InstName) { | |
| 534 return encodeRegister(OpReg, WantQRegs, RegName, InstName); | |
| 535 } | |
| 536 | |
| 506 void verifyPOrNotW(IValueT Address, const char *InstName) { | 537 void verifyPOrNotW(IValueT Address, const char *InstName) { |
| 507 if (BuildDefs::minimal()) | 538 if (BuildDefs::minimal()) |
| 508 return; | 539 return; |
| 509 if (!isBitSet(P, Address) && isBitSet(W, Address)) | 540 if (!isBitSet(P, Address) && isBitSet(W, Address)) |
| 510 llvm::report_fatal_error(std::string(InstName) + | 541 llvm::report_fatal_error(std::string(InstName) + |
| 511 ": P=0 when W=1 not allowed"); | 542 ": P=0 when W=1 not allowed"); |
| 512 } | 543 } |
| 513 | 544 |
| 514 void verifyRegsNotEq(IValueT Reg1, const char *Reg1Name, IValueT Reg2, | 545 void verifyRegsNotEq(IValueT Reg1, const char *Reg1Name, IValueT Reg2, |
| 515 const char *Reg2Name, const char *InstName) { | 546 const char *Reg2Name, const char *InstName) { |
| (...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1023 IValueT Rot = encodeRotation(Rotation); | 1054 IValueT Rot = encodeRotation(Rotation); |
| 1024 if (!Utils::IsUint(2, Rot)) | 1055 if (!Utils::IsUint(2, Rot)) |
| 1025 llvm::report_fatal_error(std::string(InstName) + | 1056 llvm::report_fatal_error(std::string(InstName) + |
| 1026 ": Illegal rotation value"); | 1057 ": Illegal rotation value"); |
| 1027 IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | Opcode | | 1058 IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | Opcode | |
| 1028 (Rn << kRnShift) | (Rd << kRdShift) | | 1059 (Rn << kRnShift) | (Rd << kRdShift) | |
| 1029 (Rot << kRotationShift) | B6 | B5 | B4 | (Rm << kRmShift); | 1060 (Rot << kRotationShift) | B6 | B5 | B4 | (Rm << kRmShift); |
| 1030 emitInst(Encoding); | 1061 emitInst(Encoding); |
| 1031 } | 1062 } |
| 1032 | 1063 |
| 1064 void AssemblerARM32::emitSIMD(IValueT Opcode, Type ElmtTy, IValueT Dd, | |
| 1065 IValueT Dn, IValueT Dm, bool UseQRegs) { | |
| 1066 IValueT Sz = encodeElmtType(ElmtTy); | |
| 1067 assert(Utils::IsUint(2, Sz)); | |
| 1068 IValueT Encoding = | |
| 1069 Opcode | B25 | (encodeCondition(CondARM32::kNone) << kConditionShift) | | |
| 1070 (Sz << 20) | (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dn) << 16) | | |
| 1071 (getXXXXInRegYXXXX(Dd) << 12) | (getYInRegYXXXX(Dn) << 7) | | |
| 1072 (encodeBool(UseQRegs) << 6) | (getYInRegYXXXX(Dm) << 5) | | |
| 1073 getXXXXInRegYXXXX(Dm); | |
| 1074 emitInst(Encoding); | |
| 1075 } | |
| 1076 | |
| 1077 void AssemblerARM32::emitSIMDqqq(IValueT Opcode, Type ElmtTy, | |
| 1078 const Operand *OpQd, const Operand *OpQn, | |
| 1079 const Operand *OpQm, const char *OpcodeName) { | |
| 1080 IValueT Qd = encodeQRegister(OpQd, "Qd", OpcodeName); | |
| 1081 IValueT Qn = encodeQRegister(OpQn, "Qn", OpcodeName); | |
| 1082 IValueT Qm = encodeQRegister(OpQm, "Qm", OpcodeName); | |
| 1083 constexpr bool UseQRegs = true; | |
| 1084 emitSIMD(Opcode, ElmtTy, Qd << 1, Qn << 1, Qm << 1, UseQRegs); | |
|
Jim Stichnoth
2016/02/01 21:00:23
The "Qx << 1" is a bit jarring compared to the nor
Karl
2016/02/01 21:44:53
Done.
| |
| 1085 } | |
| 1086 | |
| 1033 void AssemblerARM32::emitVFPddd(CondARM32::Cond Cond, IValueT Opcode, | 1087 void AssemblerARM32::emitVFPddd(CondARM32::Cond Cond, IValueT Opcode, |
| 1034 IValueT Dd, IValueT Dn, IValueT Dm) { | 1088 IValueT Dd, IValueT Dn, IValueT Dm) { |
| 1035 assert(Dd < RegARM32::getNumDRegs()); | 1089 assert(Dd < RegARM32::getNumDRegs()); |
| 1036 assert(Dn < RegARM32::getNumDRegs()); | 1090 assert(Dn < RegARM32::getNumDRegs()); |
| 1037 assert(Dm < RegARM32::getNumDRegs()); | 1091 assert(Dm < RegARM32::getNumDRegs()); |
| 1038 assert(CondARM32::isDefined(Cond)); | 1092 assert(CondARM32::isDefined(Cond)); |
| 1039 constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9 | B8; | 1093 constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9 | B8; |
| 1040 const IValueT Encoding = | 1094 const IValueT Encoding = |
| 1041 Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) | | 1095 Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) | |
| 1042 (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dn) << 16) | | 1096 (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dn) << 16) | |
| (...skipping 1047 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2090 // VADD (floating-point) - ARM section A8.8.283, encoding A2: | 2144 // VADD (floating-point) - ARM section A8.8.283, encoding A2: |
| 2091 // vadd<c>.f32 <Sd>, <Sn>, <Sm> | 2145 // vadd<c>.f32 <Sd>, <Sn>, <Sm> |
| 2092 // | 2146 // |
| 2093 // cccc11100D11nnnndddd101sN0M0mmmm where cccc=Cond, s=0, ddddD=Rd, nnnnN=Rn, | 2147 // cccc11100D11nnnndddd101sN0M0mmmm where cccc=Cond, s=0, ddddD=Rd, nnnnN=Rn, |
| 2094 // and mmmmM=Rm. | 2148 // and mmmmM=Rm. |
| 2095 constexpr const char *Vadds = "vadds"; | 2149 constexpr const char *Vadds = "vadds"; |
| 2096 constexpr IValueT VaddsOpcode = B21 | B20; | 2150 constexpr IValueT VaddsOpcode = B21 | B20; |
| 2097 emitVFPsss(Cond, VaddsOpcode, OpSd, OpSn, OpSm, Vadds); | 2151 emitVFPsss(Cond, VaddsOpcode, OpSd, OpSn, OpSm, Vadds); |
| 2098 } | 2152 } |
| 2099 | 2153 |
| 2154 void AssemblerARM32::vaddqi(Type ElmtTy, const Operand *OpQd, | |
| 2155 const Operand *OpQm, const Operand *OpQn) { | |
| 2156 // VADD (integer) - ARM section A8.8.282, encoding A1: | |
| 2157 // vadd.<dt> <Qd>, <Qn>, <Qm> | |
| 2158 // | |
| 2159 // 111100100Dssnnn0ddd01000NqM0mmm0 where Dddd=OpQd, Nnnn=OpQm, Mmmm=OpQm, | |
| 2160 // and dt in [i8, i16, i32, i64] where ss is the index. | |
| 2161 constexpr const char *Vaddqi = "vaddqi"; | |
| 2162 constexpr IValueT VaddqiOpcode = B11; | |
| 2163 emitSIMDqqq(VaddqiOpcode, ElmtTy, OpQd, OpQm, OpQn, Vaddqi); | |
| 2164 } | |
| 2165 | |
| 2166 void AssemblerARM32::vaddqf(const Operand *OpQd, const Operand *OpQn, | |
| 2167 const Operand *OpQm) { | |
| 2168 // VADD (floating-point) - ARM section A8.8.283, Encoding A1: | |
| 2169 // vadd.f32 <Qd>, <Qn>, <Qm> | |
| 2170 // | |
| 2171 // 111100100D00nnn0ddd01101N1M0mmm0 where Dddd=Qd, Nnnn=Qn, and Mmmm=Qm. | |
| 2172 constexpr const char *Vaddqf = "vaddqf"; | |
| 2173 constexpr IValueT VaddqfOpcode = B11 | B10 | B8; | |
| 2174 emitSIMDqqq(VaddqfOpcode, IceType_f32, OpQd, OpQn, OpQm, Vaddqf); | |
| 2175 } | |
| 2176 | |
| 2100 void AssemblerARM32::vaddd(const Operand *OpDd, const Operand *OpDn, | 2177 void AssemblerARM32::vaddd(const Operand *OpDd, const Operand *OpDn, |
| 2101 const Operand *OpDm, CondARM32::Cond Cond) { | 2178 const Operand *OpDm, CondARM32::Cond Cond) { |
| 2102 // VADD (floating-point) - ARM section A8.8.283, encoding A2: | 2179 // VADD (floating-point) - ARM section A8.8.283, encoding A2: |
| 2103 // vadd<c>.f64 <Dd>, <Dn>, <Dm> | 2180 // vadd<c>.f64 <Dd>, <Dn>, <Dm> |
| 2104 // | 2181 // |
| 2105 // cccc11100D11nnnndddd101sN0M0mmmm where cccc=Cond, s=1, Ddddd=Rd, Nnnnn=Rn, | 2182 // cccc11100D11nnnndddd101sN0M0mmmm where cccc=Cond, s=1, Ddddd=Rd, Nnnnn=Rn, |
| 2106 // and Mmmmm=Rm. | 2183 // and Mmmmm=Rm. |
| 2107 constexpr const char *Vaddd = "vaddd"; | 2184 constexpr const char *Vaddd = "vaddd"; |
| 2108 constexpr IValueT VadddOpcode = B21 | B20; | 2185 constexpr IValueT VadddOpcode = B21 | B20; |
| 2109 emitVFPddd(Cond, VadddOpcode, OpDd, OpDn, OpDm, Vaddd); | 2186 emitVFPddd(Cond, VadddOpcode, OpDd, OpDn, OpDm, Vaddd); |
| (...skipping 657 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2767 constexpr const char *Vsqrts = "vsqrts"; | 2844 constexpr const char *Vsqrts = "vsqrts"; |
| 2768 IValueT Sd = encodeSRegister(OpSd, "Sd", Vsqrts); | 2845 IValueT Sd = encodeSRegister(OpSd, "Sd", Vsqrts); |
| 2769 IValueT Sm = encodeSRegister(OpSm, "Sm", Vsqrts); | 2846 IValueT Sm = encodeSRegister(OpSm, "Sm", Vsqrts); |
| 2770 constexpr IValueT VsqrtsOpcode = B23 | B21 | B20 | B16 | B7 | B6; | 2847 constexpr IValueT VsqrtsOpcode = B23 | B21 | B20 | B16 | B7 | B6; |
| 2771 constexpr IValueT S0 = 0; | 2848 constexpr IValueT S0 = 0; |
| 2772 emitVFPsss(Cond, VsqrtsOpcode, Sd, S0, Sm); | 2849 emitVFPsss(Cond, VsqrtsOpcode, Sd, S0, Sm); |
| 2773 } | 2850 } |
| 2774 | 2851 |
| 2775 } // end of namespace ARM32 | 2852 } // end of namespace ARM32 |
| 2776 } // end of namespace Ice | 2853 } // end of namespace Ice |
| OLD | NEW |