Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(401)

Side by Side Diff: src/IceAssemblerARM32.cpp

Issue 1652173002: Implements the vector add instructions in the integrated ARM assembler. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Fix nits. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698