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 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 | 217 |
218 // Figures out Op/Cmode values for given Value. Returns true if able to encode. | 218 // Figures out Op/Cmode values for given Value. Returns true if able to encode. |
219 bool encodeAdvSIMDExpandImm(IValueT Value, Type ElmtTy, IValueT &Op, | 219 bool encodeAdvSIMDExpandImm(IValueT Value, Type ElmtTy, IValueT &Op, |
220 IValueT &Cmode, IValueT &Imm8) { | 220 IValueT &Cmode, IValueT &Imm8) { |
221 // TODO(kschimpf): Handle other shifted 8-bit values. | 221 // TODO(kschimpf): Handle other shifted 8-bit values. |
222 constexpr IValueT Imm8Mask = 0xFF; | 222 constexpr IValueT Imm8Mask = 0xFF; |
223 if ((Value & IValueT(~Imm8Mask)) != 0) | 223 if ((Value & IValueT(~Imm8Mask)) != 0) |
224 return false; | 224 return false; |
225 Imm8 = Value; | 225 Imm8 = Value; |
226 switch (ElmtTy) { | 226 switch (ElmtTy) { |
| 227 case IceType_i8: |
| 228 Op = 0; |
| 229 Cmode = 14; // 0b1110 |
| 230 return true; |
227 case IceType_i16: | 231 case IceType_i16: |
228 Op = 0; | 232 Op = 0; |
229 Cmode = 8; // 100:0 | 233 Cmode = 8; // 0b1000 |
230 return true; | 234 return true; |
231 case IceType_i32: | 235 case IceType_i32: |
232 Op = 0; | 236 Op = 0; |
233 Cmode = 0; // 000:0 | 237 Cmode = 0; // 0b0000 |
234 return true; | 238 return true; |
235 default: | 239 default: |
236 return false; | 240 return false; |
237 } | 241 } |
238 } | 242 } |
239 | 243 |
240 // Defines layouts of an operand representing a (register) memory address, | 244 // Defines layouts of an operand representing a (register) memory address, |
241 // possibly modified by an immediate value. | 245 // possibly modified by an immediate value. |
242 enum EncodedImmAddress { | 246 enum EncodedImmAddress { |
243 // Address modified by a rotated immediate 8-bit value. | 247 // Address modified by a rotated immediate 8-bit value. |
(...skipping 964 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1208 void AssemblerARM32::emitSIMDqqq(IValueT Opcode, Type ElmtTy, | 1212 void AssemblerARM32::emitSIMDqqq(IValueT Opcode, Type ElmtTy, |
1209 const Operand *OpQd, const Operand *OpQn, | 1213 const Operand *OpQd, const Operand *OpQn, |
1210 const Operand *OpQm, const char *OpcodeName) { | 1214 const Operand *OpQm, const char *OpcodeName) { |
1211 constexpr IValueT ElmtShift = 20; | 1215 constexpr IValueT ElmtShift = 20; |
1212 const IValueT ElmtSize = encodeElmtType(ElmtTy); | 1216 const IValueT ElmtSize = encodeElmtType(ElmtTy); |
1213 assert(Utils::IsUint(2, ElmtSize)); | 1217 assert(Utils::IsUint(2, ElmtSize)); |
1214 emitSIMDqqqBase(Opcode | (ElmtSize << ElmtShift), OpQd, OpQn, OpQm, | 1218 emitSIMDqqqBase(Opcode | (ElmtSize << ElmtShift), OpQd, OpQn, OpQm, |
1215 isFloatingType(ElmtTy), OpcodeName); | 1219 isFloatingType(ElmtTy), OpcodeName); |
1216 } | 1220 } |
1217 | 1221 |
| 1222 void AssemblerARM32::emitSIMDShiftqqc(IValueT Opcode, const Operand *OpQd, |
| 1223 const Operand *OpQm, const IValueT Imm6, |
| 1224 const char *OpcodeName) { |
| 1225 const IValueT Qd = encodeQRegister(OpQd, "Qd", OpcodeName); |
| 1226 const IValueT Qn = 0; |
| 1227 const IValueT Qm = encodeQRegister(OpQm, "Qm", OpcodeName); |
| 1228 constexpr bool UseQRegs = true; |
| 1229 constexpr bool IsFloatTy = false; |
| 1230 constexpr IValueT ElmtShift = 16; |
| 1231 emitSIMDBase(Opcode | (Imm6 << ElmtShift), mapQRegToDReg(Qd), |
| 1232 mapQRegToDReg(Qn), mapQRegToDReg(Qm), UseQRegs, IsFloatTy); |
| 1233 } |
| 1234 |
| 1235 void AssemblerARM32::emitSIMDCvtqq(IValueT Opcode, const Operand *OpQd, |
| 1236 const Operand *OpQm, |
| 1237 const char *OpcodeName) { |
| 1238 const IValueT SIMDOpcode = |
| 1239 B24 | B23 | B21 | B20 | B19 | B17 | B16 | B10 | B9 | Opcode; |
| 1240 constexpr bool UseQRegs = true; |
| 1241 constexpr bool IsFloatTy = false; |
| 1242 const IValueT Qd = encodeQRegister(OpQd, "Qd", OpcodeName); |
| 1243 constexpr IValueT Qn = 0; |
| 1244 const IValueT Qm = encodeQRegister(OpQm, "Qm", OpcodeName); |
| 1245 emitSIMDBase(SIMDOpcode, mapQRegToDReg(Qd), mapQRegToDReg(Qn), |
| 1246 mapQRegToDReg(Qm), UseQRegs, IsFloatTy); |
| 1247 } |
| 1248 |
1218 void AssemblerARM32::emitVFPddd(CondARM32::Cond Cond, IValueT Opcode, | 1249 void AssemblerARM32::emitVFPddd(CondARM32::Cond Cond, IValueT Opcode, |
1219 IValueT Dd, IValueT Dn, IValueT Dm) { | 1250 IValueT Dd, IValueT Dn, IValueT Dm) { |
1220 assert(Dd < RegARM32::getNumDRegs()); | 1251 assert(Dd < RegARM32::getNumDRegs()); |
1221 assert(Dn < RegARM32::getNumDRegs()); | 1252 assert(Dn < RegARM32::getNumDRegs()); |
1222 assert(Dm < RegARM32::getNumDRegs()); | 1253 assert(Dm < RegARM32::getNumDRegs()); |
1223 assert(CondARM32::isDefined(Cond)); | 1254 assert(CondARM32::isDefined(Cond)); |
1224 constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9 | B8; | 1255 constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9 | B8; |
1225 const IValueT Encoding = | 1256 const IValueT Encoding = |
1226 Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) | | 1257 Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) | |
1227 (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dn) << 16) | | 1258 (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dn) << 16) | |
(...skipping 1322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2550 // | 2581 // |
2551 // cccc11101D111100dddd10011M0mmmm where cccc=Cond, ddddD=Sd, and mmmmM=Sm. | 2582 // cccc11101D111100dddd10011M0mmmm where cccc=Cond, ddddD=Sd, and mmmmM=Sm. |
2552 constexpr const char *Vcvtus = "vcvtus"; | 2583 constexpr const char *Vcvtus = "vcvtus"; |
2553 IValueT Sd = encodeSRegister(OpSd, "Sd", Vcvtus); | 2584 IValueT Sd = encodeSRegister(OpSd, "Sd", Vcvtus); |
2554 IValueT Sm = encodeSRegister(OpSm, "Sm", Vcvtus); | 2585 IValueT Sm = encodeSRegister(OpSm, "Sm", Vcvtus); |
2555 constexpr IValueT VcvtsiOpcode = B23 | B21 | B20 | B19 | B18 | B7 | B6; | 2586 constexpr IValueT VcvtsiOpcode = B23 | B21 | B20 | B19 | B18 | B7 | B6; |
2556 constexpr IValueT S0 = 0; | 2587 constexpr IValueT S0 = 0; |
2557 emitVFPsss(Cond, VcvtsiOpcode, Sd, S0, Sm); | 2588 emitVFPsss(Cond, VcvtsiOpcode, Sd, S0, Sm); |
2558 } | 2589 } |
2559 | 2590 |
| 2591 void AssemblerARM32::vcvtqsi(const Operand *OpQd, const Operand *OpQm) { |
| 2592 // VCVT (between floating-point and integer, Advanced SIMD) |
| 2593 // - ARM Section A8.8.305, encoding A1: |
| 2594 // vcvt<c>.f32.s32 <Qd>, <Qm> |
| 2595 // |
| 2596 // 111100111D11ss11dddd011ooQM0mmmm where Ddddd=Qd, Mmmmm=Qm, and 10=op. |
| 2597 constexpr const char *Vcvtqsi = "vcvt.s32.f32"; |
| 2598 constexpr IValueT VcvtqsiOpcode = B8; |
| 2599 emitSIMDCvtqq(VcvtqsiOpcode, OpQd, OpQm, Vcvtqsi); |
| 2600 } |
| 2601 |
| 2602 void AssemblerARM32::vcvtqsu(const Operand *OpQd, const Operand *OpQm) { |
| 2603 // VCVT (between floating-point and integer, Advanced SIMD) |
| 2604 // - ARM Section A8.8.305, encoding A1: |
| 2605 // vcvt<c>.f32.u32 <Qd>, <Qm> |
| 2606 // |
| 2607 // 111100111D11ss11dddd011ooQM0mmmm where Ddddd=Qd, Mmmmm=Qm, and 11=op. |
| 2608 constexpr const char *Vcvtqsu = "vcvt.u32.f32"; |
| 2609 constexpr IValueT VcvtqsuOpcode = B8 | B7; |
| 2610 emitSIMDCvtqq(VcvtqsuOpcode, OpQd, OpQm, Vcvtqsu); |
| 2611 } |
| 2612 |
| 2613 void AssemblerARM32::vcvtqis(const Operand *OpQd, const Operand *OpQm) { |
| 2614 // VCVT (between floating-point and integer, Advanced SIMD) |
| 2615 // - ARM Section A8.8.305, encoding A1: |
| 2616 // vcvt<c>.f32.s32 <Qd>, <Qm> |
| 2617 // |
| 2618 // 111100111D11ss11dddd011ooQM0mmmm where Ddddd=Qd, Mmmmm=Qm, and 01=op. |
| 2619 constexpr const char *Vcvtqis = "vcvt.f32.s32"; |
| 2620 constexpr IValueT VcvtqisOpcode = 0; |
| 2621 emitSIMDCvtqq(VcvtqisOpcode, OpQd, OpQm, Vcvtqis); |
| 2622 } |
| 2623 |
| 2624 void AssemblerARM32::vcvtqus(const Operand *OpQd, const Operand *OpQm) { |
| 2625 // VCVT (between floating-point and integer, Advanced SIMD) |
| 2626 // - ARM Section A8.8.305, encoding A1: |
| 2627 // vcvt<c>.f32.u32 <Qd>, <Qm> |
| 2628 // |
| 2629 // 111100111D11ss11dddd011ooQM0mmmm where Ddddd=Qd, Mmmmm=Qm, and 01=op. |
| 2630 constexpr const char *Vcvtqus = "vcvt.f32.u32"; |
| 2631 constexpr IValueT VcvtqusOpcode = B7; |
| 2632 emitSIMDCvtqq(VcvtqusOpcode, OpQd, OpQm, Vcvtqus); |
| 2633 } |
| 2634 |
2560 void AssemblerARM32::emitVFPds(CondARM32::Cond Cond, IValueT Opcode, IValueT Dd, | 2635 void AssemblerARM32::emitVFPds(CondARM32::Cond Cond, IValueT Opcode, IValueT Dd, |
2561 IValueT Sm) { | 2636 IValueT Sm) { |
2562 assert(Dd < RegARM32::getNumDRegs()); | 2637 assert(Dd < RegARM32::getNumDRegs()); |
2563 assert(Sm < RegARM32::getNumSRegs()); | 2638 assert(Sm < RegARM32::getNumSRegs()); |
2564 assert(CondARM32::isDefined(Cond)); | 2639 assert(CondARM32::isDefined(Cond)); |
2565 constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9; | 2640 constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9; |
2566 const IValueT Encoding = | 2641 const IValueT Encoding = |
2567 Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) | | 2642 Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) | |
2568 (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dd) << 12) | | 2643 (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dd) << 12) | |
2569 (getYInRegXXXXY(Sm) << 5) | getXXXXInRegXXXXY(Sm); | 2644 (getYInRegXXXXY(Sm) << 5) | getXXXXInRegXXXXY(Sm); |
(...skipping 690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3260 // | 3335 // |
3261 // 1111001U0Dssnnnndddd0100NQM0mmmm where Ddddd=Qd, Mmmmm=Qm, Nnnnn=Qn, 0=U, | 3336 // 1111001U0Dssnnnndddd0100NQM0mmmm where Ddddd=Qd, Mmmmm=Qm, Nnnnn=Qn, 0=U, |
3262 // 1=Q | 3337 // 1=Q |
3263 assert(isScalarIntegerType(ElmtTy) && | 3338 assert(isScalarIntegerType(ElmtTy) && |
3264 "vshl expects vector with integer element type"); | 3339 "vshl expects vector with integer element type"); |
3265 constexpr const char *Vshl = "vshl"; | 3340 constexpr const char *Vshl = "vshl"; |
3266 constexpr IValueT VshlOpcode = B10 | B6; | 3341 constexpr IValueT VshlOpcode = B10 | B6; |
3267 emitSIMDqqq(VshlOpcode, ElmtTy, OpQd, OpQn, OpQm, Vshl); | 3342 emitSIMDqqq(VshlOpcode, ElmtTy, OpQd, OpQn, OpQm, Vshl); |
3268 } | 3343 } |
3269 | 3344 |
| 3345 namespace { |
| 3346 enum SIMDShiftType { ST_Vshl, ST_Vshr }; |
| 3347 IValueT encodeSIMDShiftImm6(SIMDShiftType Shift, Type ElmtTy, |
| 3348 const ConstantInteger32 *Imm6) { |
| 3349 const IValueT Imm = Imm6->getValue(); |
| 3350 assert(Imm > 0); |
| 3351 const SizeT MaxShift = getScalarIntBitWidth(ElmtTy); |
| 3352 assert(Imm < MaxShift); |
| 3353 assert(ElmtTy == IceType_i8 || ElmtTy == IceType_i16 || |
| 3354 ElmtTy == IceType_i32); |
| 3355 const IValueT VshlImm = Imm - MaxShift; |
| 3356 const IValueT VshrImm = 2 * MaxShift - Imm; |
| 3357 return ((Shift == ST_Vshl) ? VshlImm : VshrImm) & (2 * MaxShift - 1); |
| 3358 } |
| 3359 } // end of anonymous namespace |
| 3360 |
| 3361 void AssemblerARM32::vshlqc(Type ElmtTy, const Operand *OpQd, |
| 3362 const Operand *OpQm, |
| 3363 const ConstantInteger32 *Imm6) { |
| 3364 // VSHL - ARM section A8.8.395, encoding A1: |
| 3365 // vshl Qd, Qm, #Imm |
| 3366 // |
| 3367 // 1111001U1Diiiiiidddd0101LQM1mmmm where Ddddd=Qd, Mmmmm=Qm, iiiiii=Imm6, |
| 3368 // 0=U, 1=Q, 0=L. |
| 3369 assert(isScalarIntegerType(ElmtTy) && |
| 3370 "vshl expects vector with integer element type"); |
| 3371 constexpr const char *Vshl = "vshl"; |
| 3372 constexpr IValueT VshlOpcode = B23 | B10 | B8 | B4; |
| 3373 emitSIMDShiftqqc(VshlOpcode, OpQd, OpQm, |
| 3374 encodeSIMDShiftImm6(ST_Vshl, ElmtTy, Imm6), Vshl); |
| 3375 } |
| 3376 |
| 3377 void AssemblerARM32::vshrqic(Type ElmtTy, const Operand *OpQd, |
| 3378 const Operand *OpQm, |
| 3379 const ConstantInteger32 *Imm6) { |
| 3380 // VSHR - ARM section A8.8.398, encoding A1: |
| 3381 // vshr Qd, Qm, #Imm |
| 3382 // |
| 3383 // 1111001U1Diiiiiidddd0101LQM1mmmm where Ddddd=Qd, Mmmmm=Qm, iiiiii=Imm6, |
| 3384 // 0=U, 1=Q, 0=L. |
| 3385 assert(isScalarIntegerType(ElmtTy) && |
| 3386 "vshr expects vector with integer element type"); |
| 3387 constexpr const char *Vshr = "vshr"; |
| 3388 constexpr IValueT VshrOpcode = B23 | B4; |
| 3389 emitSIMDShiftqqc(VshrOpcode, OpQd, OpQm, |
| 3390 encodeSIMDShiftImm6(ST_Vshr, ElmtTy, Imm6), Vshr); |
| 3391 } |
| 3392 |
| 3393 void AssemblerARM32::vshrquc(Type ElmtTy, const Operand *OpQd, |
| 3394 const Operand *OpQm, |
| 3395 const ConstantInteger32 *Imm6) { |
| 3396 // VSHR - ARM section A8.8.398, encoding A1: |
| 3397 // vshr Qd, Qm, #Imm |
| 3398 // |
| 3399 // 1111001U1Diiiiiidddd0101LQM1mmmm where Ddddd=Qd, Mmmmm=Qm, iiiiii=Imm6, |
| 3400 // 0=U, 1=Q, 0=L. |
| 3401 assert(isScalarIntegerType(ElmtTy) && |
| 3402 "vshr expects vector with integer element type"); |
| 3403 constexpr const char *Vshr = "vshr"; |
| 3404 constexpr IValueT VshrOpcode = B23 | B4; |
| 3405 emitSIMDShiftqqc(VshrOpcode, OpQd, OpQm, |
| 3406 encodeSIMDShiftImm6(ST_Vshr, ElmtTy, Imm6), Vshr); |
| 3407 } |
| 3408 |
3270 void AssemblerARM32::vshlqu(Type ElmtTy, const Operand *OpQd, | 3409 void AssemblerARM32::vshlqu(Type ElmtTy, const Operand *OpQd, |
3271 const Operand *OpQm, const Operand *OpQn) { | 3410 const Operand *OpQm, const Operand *OpQn) { |
3272 // VSHL - ARM section A8.8.396, encoding A1: | 3411 // VSHL - ARM section A8.8.396, encoding A1: |
3273 // vshl Qd, Qm, Qn | 3412 // vshl Qd, Qm, Qn |
3274 // | 3413 // |
3275 // 1111001U0Dssnnnndddd0100NQM0mmmm where Ddddd=Qd, Mmmmm=Qm, Nnnnn=Qn, 1=U, | 3414 // 1111001U0Dssnnnndddd0100NQM0mmmm where Ddddd=Qd, Mmmmm=Qm, Nnnnn=Qn, 1=U, |
3276 // 1=Q | 3415 // 1=Q |
3277 assert(isScalarIntegerType(ElmtTy) && | 3416 assert(isScalarIntegerType(ElmtTy) && |
3278 "vshl expects vector with integer element type"); | 3417 "vshl expects vector with integer element type"); |
3279 constexpr const char *Vshl = "vshl"; | 3418 constexpr const char *Vshl = "vshl"; |
(...skipping 24 matching lines...) Expand all Loading... |
3304 constexpr const char *Vsqrts = "vsqrts"; | 3443 constexpr const char *Vsqrts = "vsqrts"; |
3305 IValueT Sd = encodeSRegister(OpSd, "Sd", Vsqrts); | 3444 IValueT Sd = encodeSRegister(OpSd, "Sd", Vsqrts); |
3306 IValueT Sm = encodeSRegister(OpSm, "Sm", Vsqrts); | 3445 IValueT Sm = encodeSRegister(OpSm, "Sm", Vsqrts); |
3307 constexpr IValueT VsqrtsOpcode = B23 | B21 | B20 | B16 | B7 | B6; | 3446 constexpr IValueT VsqrtsOpcode = B23 | B21 | B20 | B16 | B7 | B6; |
3308 constexpr IValueT S0 = 0; | 3447 constexpr IValueT S0 = 0; |
3309 emitVFPsss(Cond, VsqrtsOpcode, Sd, S0, Sm); | 3448 emitVFPsss(Cond, VsqrtsOpcode, Sd, S0, Sm); |
3310 } | 3449 } |
3311 | 3450 |
3312 } // end of namespace ARM32 | 3451 } // end of namespace ARM32 |
3313 } // end of namespace Ice | 3452 } // end of namespace Ice |
OLD | NEW |