| OLD | NEW |
| 1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// | 1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 // | 9 // |
| 10 // This file implements the TargetLoweringARM32 class, which consists almost | 10 // This file implements the TargetLoweringARM32 class, which consists almost |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 uint32_t applyStackAlignmentTy(uint32_t Value, Type Ty) { | 134 uint32_t applyStackAlignmentTy(uint32_t Value, Type Ty) { |
| 135 // Use natural alignment, except that normally (non-NaCl) ARM only | 135 // Use natural alignment, except that normally (non-NaCl) ARM only |
| 136 // aligns vectors to 8 bytes. | 136 // aligns vectors to 8 bytes. |
| 137 // TODO(jvoung): Check this ... | 137 // TODO(jvoung): Check this ... |
| 138 size_t typeAlignInBytes = typeWidthInBytes(Ty); | 138 size_t typeAlignInBytes = typeWidthInBytes(Ty); |
| 139 if (isVectorType(Ty)) | 139 if (isVectorType(Ty)) |
| 140 typeAlignInBytes = 8; | 140 typeAlignInBytes = 8; |
| 141 return Utils::applyAlignment(Value, typeAlignInBytes); | 141 return Utils::applyAlignment(Value, typeAlignInBytes); |
| 142 } | 142 } |
| 143 | 143 |
| 144 // Conservatively check if at compile time we know that the operand is |
| 145 // definitely a non-zero integer. |
| 146 bool isGuaranteedNonzeroInt(const Operand *Op) { |
| 147 if (auto *Const = llvm::dyn_cast_or_null<ConstantInteger32>(Op)) { |
| 148 return Const->getValue() != 0; |
| 149 } |
| 150 return false; |
| 151 } |
| 152 |
| 144 } // end of anonymous namespace | 153 } // end of anonymous namespace |
| 145 | 154 |
| 146 TargetARM32::TargetARM32(Cfg *Func) : TargetLowering(Func) { | 155 TargetARM32Features::TargetARM32Features(const ClFlags &Flags) { |
| 147 static_assert( | 156 static_assert( |
| 148 (ARM32InstructionSet::End - ARM32InstructionSet::Begin) == | 157 (ARM32InstructionSet::End - ARM32InstructionSet::Begin) == |
| 149 (TargetInstructionSet::ARM32InstructionSet_End - | 158 (TargetInstructionSet::ARM32InstructionSet_End - |
| 150 TargetInstructionSet::ARM32InstructionSet_Begin), | 159 TargetInstructionSet::ARM32InstructionSet_Begin), |
| 151 "ARM32InstructionSet range different from TargetInstructionSet"); | 160 "ARM32InstructionSet range different from TargetInstructionSet"); |
| 152 if (Func->getContext()->getFlags().getTargetInstructionSet() != | 161 if (Flags.getTargetInstructionSet() != |
| 153 TargetInstructionSet::BaseInstructionSet) { | 162 TargetInstructionSet::BaseInstructionSet) { |
| 154 InstructionSet = static_cast<ARM32InstructionSet>( | 163 InstructionSet = static_cast<ARM32InstructionSet>( |
| 155 (Func->getContext()->getFlags().getTargetInstructionSet() - | 164 (Flags.getTargetInstructionSet() - |
| 156 TargetInstructionSet::ARM32InstructionSet_Begin) + | 165 TargetInstructionSet::ARM32InstructionSet_Begin) + |
| 157 ARM32InstructionSet::Begin); | 166 ARM32InstructionSet::Begin); |
| 158 } | 167 } |
| 168 } |
| 169 |
| 170 TargetARM32::TargetARM32(Cfg *Func) |
| 171 : TargetLowering(Func), CPUFeatures(Func->getContext()->getFlags()) { |
| 159 // TODO: Don't initialize IntegerRegisters and friends every time. | 172 // TODO: Don't initialize IntegerRegisters and friends every time. |
| 160 // Instead, initialize in some sort of static initializer for the | 173 // Instead, initialize in some sort of static initializer for the |
| 161 // class. | 174 // class. |
| 162 llvm::SmallBitVector IntegerRegisters(RegARM32::Reg_NUM); | 175 llvm::SmallBitVector IntegerRegisters(RegARM32::Reg_NUM); |
| 163 llvm::SmallBitVector FloatRegisters(RegARM32::Reg_NUM); | 176 llvm::SmallBitVector FloatRegisters(RegARM32::Reg_NUM); |
| 164 llvm::SmallBitVector VectorRegisters(RegARM32::Reg_NUM); | 177 llvm::SmallBitVector VectorRegisters(RegARM32::Reg_NUM); |
| 165 llvm::SmallBitVector InvalidRegisters(RegARM32::Reg_NUM); | 178 llvm::SmallBitVector InvalidRegisters(RegARM32::Reg_NUM); |
| 166 ScratchRegs.resize(RegARM32::Reg_NUM); | 179 ScratchRegs.resize(RegARM32::Reg_NUM); |
| 167 #define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt, \ | 180 #define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt, \ |
| 168 isFP) \ | 181 isFP) \ |
| (...skipping 833 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1002 Variable *T = makeReg(IceType_i32); | 1015 Variable *T = makeReg(IceType_i32); |
| 1003 _mov(T, TotalSize); | 1016 _mov(T, TotalSize); |
| 1004 Operand *AddAmount = legalize(Ctx->getConstantInt32(Alignment - 1)); | 1017 Operand *AddAmount = legalize(Ctx->getConstantInt32(Alignment - 1)); |
| 1005 _add(T, T, AddAmount); | 1018 _add(T, T, AddAmount); |
| 1006 alignRegisterPow2(T, Alignment); | 1019 alignRegisterPow2(T, Alignment); |
| 1007 _sub(SP, SP, T); | 1020 _sub(SP, SP, T); |
| 1008 } | 1021 } |
| 1009 _mov(Dest, SP); | 1022 _mov(Dest, SP); |
| 1010 } | 1023 } |
| 1011 | 1024 |
| 1025 void TargetARM32::div0Check(Type Ty, Operand *SrcLo, Operand *SrcHi) { |
| 1026 if (isGuaranteedNonzeroInt(SrcLo) || isGuaranteedNonzeroInt(SrcHi)) |
| 1027 return; |
| 1028 Variable *SrcLoReg = legalizeToVar(SrcLo); |
| 1029 switch (Ty) { |
| 1030 default: |
| 1031 llvm_unreachable("Unexpected type"); |
| 1032 case IceType_i8: { |
| 1033 Operand *Mask = |
| 1034 legalize(Ctx->getConstantInt32(0xFF), Legal_Reg | Legal_Flex); |
| 1035 _tst(SrcLoReg, Mask); |
| 1036 break; |
| 1037 } |
| 1038 case IceType_i16: { |
| 1039 Operand *Mask = |
| 1040 legalize(Ctx->getConstantInt32(0xFFFF), Legal_Reg | Legal_Flex); |
| 1041 _tst(SrcLoReg, Mask); |
| 1042 break; |
| 1043 } |
| 1044 case IceType_i32: { |
| 1045 _tst(SrcLoReg, SrcLoReg); |
| 1046 break; |
| 1047 } |
| 1048 case IceType_i64: { |
| 1049 Variable *ScratchReg = makeReg(IceType_i32); |
| 1050 _orrs(ScratchReg, SrcLoReg, SrcHi); |
| 1051 // ScratchReg isn't going to be used, but we need the |
| 1052 // side-effect of setting flags from this operation. |
| 1053 Context.insert(InstFakeUse::create(Func, ScratchReg)); |
| 1054 } |
| 1055 } |
| 1056 InstARM32Label *Label = InstARM32Label::create(Func, this); |
| 1057 _br(Label, CondARM32::NE); |
| 1058 _trap(); |
| 1059 Context.insert(Label); |
| 1060 } |
| 1061 |
| 1062 void TargetARM32::lowerIDivRem(Variable *Dest, Variable *T, Variable *Src0R, |
| 1063 Operand *Src1, ExtInstr ExtFunc, |
| 1064 DivInstr DivFunc, const char *DivHelperName, |
| 1065 bool IsRemainder) { |
| 1066 div0Check(Dest->getType(), Src1, nullptr); |
| 1067 Variable *Src1R = legalizeToVar(Src1); |
| 1068 Variable *T0R = Src0R; |
| 1069 Variable *T1R = Src1R; |
| 1070 if (Dest->getType() != IceType_i32) { |
| 1071 T0R = makeReg(IceType_i32); |
| 1072 (this->*ExtFunc)(T0R, Src0R, CondARM32::AL); |
| 1073 T1R = makeReg(IceType_i32); |
| 1074 (this->*ExtFunc)(T1R, Src1R, CondARM32::AL); |
| 1075 } |
| 1076 if (hasCPUFeature(TargetARM32Features::HWDivArm)) { |
| 1077 (this->*DivFunc)(T, T0R, T1R, CondARM32::AL); |
| 1078 if (IsRemainder) { |
| 1079 Variable *T2 = makeReg(IceType_i32); |
| 1080 _mls(T2, T, T1R, T0R); |
| 1081 T = T2; |
| 1082 } |
| 1083 _mov(Dest, T); |
| 1084 } else { |
| 1085 constexpr SizeT MaxSrcs = 2; |
| 1086 InstCall *Call = makeHelperCall(DivHelperName, Dest, MaxSrcs); |
| 1087 Call->addArg(T0R); |
| 1088 Call->addArg(T1R); |
| 1089 lowerCall(Call); |
| 1090 } |
| 1091 return; |
| 1092 } |
| 1093 |
| 1012 void TargetARM32::lowerArithmetic(const InstArithmetic *Inst) { | 1094 void TargetARM32::lowerArithmetic(const InstArithmetic *Inst) { |
| 1013 Variable *Dest = Inst->getDest(); | 1095 Variable *Dest = Inst->getDest(); |
| 1014 // TODO(jvoung): Should be able to flip Src0 and Src1 if it is easier | 1096 // TODO(jvoung): Should be able to flip Src0 and Src1 if it is easier |
| 1015 // to legalize Src0 to flex or Src1 to flex and there is a reversible | 1097 // to legalize Src0 to flex or Src1 to flex and there is a reversible |
| 1016 // instruction. E.g., reverse subtract with immediate, register vs | 1098 // instruction. E.g., reverse subtract with immediate, register vs |
| 1017 // register, immediate. | 1099 // register, immediate. |
| 1018 // Or it may be the case that the operands aren't swapped, but the | 1100 // Or it may be the case that the operands aren't swapped, but the |
| 1019 // bits can be flipped and a different operation applied. | 1101 // bits can be flipped and a different operation applied. |
| 1020 // E.g., use BIC (bit clear) instead of AND for some masks. | 1102 // E.g., use BIC (bit clear) instead of AND for some masks. |
| 1021 Operand *Src0 = Inst->getSrc(0); | 1103 Operand *Src0 = Inst->getSrc(0); |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1175 Pred); | 1257 Pred); |
| 1176 _mov(DestLo, T_Lo); | 1258 _mov(DestLo, T_Lo); |
| 1177 Variable *T_Hi = makeReg(IceType_i32); | 1259 Variable *T_Hi = makeReg(IceType_i32); |
| 1178 _mov(T_Hi, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi, | 1260 _mov(T_Hi, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi, |
| 1179 RShiftKind, Src1RLo)); | 1261 RShiftKind, Src1RLo)); |
| 1180 _mov(DestHi, T_Hi); | 1262 _mov(DestHi, T_Hi); |
| 1181 } break; | 1263 } break; |
| 1182 case InstArithmetic::Udiv: | 1264 case InstArithmetic::Udiv: |
| 1183 case InstArithmetic::Sdiv: | 1265 case InstArithmetic::Sdiv: |
| 1184 case InstArithmetic::Urem: | 1266 case InstArithmetic::Urem: |
| 1185 case InstArithmetic::Srem: | 1267 case InstArithmetic::Srem: { |
| 1186 UnimplementedError(Func->getContext()->getFlags()); | 1268 // Check for divide by 0 (ARM normally doesn't trap, but we want it |
| 1187 break; | 1269 // to trap for NaCl). Src1Lo and Src1Hi may have already been legalized |
| 1270 // to a register, which will hide a constant source operand. |
| 1271 // Instead, check the not-yet-legalized Src1 to optimize-out a divide |
| 1272 // by 0 check. |
| 1273 if (auto *C64 = llvm::dyn_cast<ConstantInteger64>(Src1)) { |
| 1274 if (C64->getValue() == 0) { |
| 1275 div0Check(IceType_i64, Src1Lo, Src1Hi); |
| 1276 } |
| 1277 } else { |
| 1278 div0Check(IceType_i64, Src1Lo, Src1Hi); |
| 1279 } |
| 1280 // Technically, ARM has their own aeabi routines, but we can use the |
| 1281 // non-aeabi routine as well. LLVM uses __aeabi_ldivmod for div, |
| 1282 // but uses the more standard __moddi3 for rem. |
| 1283 const char *HelperName = ""; |
| 1284 switch (Inst->getOp()) { |
| 1285 case InstArithmetic::Udiv: |
| 1286 HelperName = H_udiv_i64; |
| 1287 break; |
| 1288 case InstArithmetic::Sdiv: |
| 1289 HelperName = H_sdiv_i64; |
| 1290 break; |
| 1291 case InstArithmetic::Urem: |
| 1292 HelperName = H_urem_i64; |
| 1293 break; |
| 1294 case InstArithmetic::Srem: |
| 1295 HelperName = H_srem_i64; |
| 1296 break; |
| 1297 default: |
| 1298 llvm_unreachable("Should have only matched div ops."); |
| 1299 break; |
| 1300 } |
| 1301 constexpr SizeT MaxSrcs = 2; |
| 1302 InstCall *Call = makeHelperCall(HelperName, Dest, MaxSrcs); |
| 1303 Call->addArg(Inst->getSrc(0)); |
| 1304 Call->addArg(Inst->getSrc(1)); |
| 1305 lowerCall(Call); |
| 1306 return; |
| 1307 } |
| 1188 case InstArithmetic::Fadd: | 1308 case InstArithmetic::Fadd: |
| 1189 case InstArithmetic::Fsub: | 1309 case InstArithmetic::Fsub: |
| 1190 case InstArithmetic::Fmul: | 1310 case InstArithmetic::Fmul: |
| 1191 case InstArithmetic::Fdiv: | 1311 case InstArithmetic::Fdiv: |
| 1192 case InstArithmetic::Frem: | 1312 case InstArithmetic::Frem: |
| 1193 llvm_unreachable("FP instruction with i64 type"); | 1313 llvm_unreachable("FP instruction with i64 type"); |
| 1194 break; | 1314 break; |
| 1195 } | 1315 } |
| 1196 } else if (isVectorType(Dest->getType())) { | 1316 } else if (isVectorType(Dest->getType())) { |
| 1197 UnimplementedError(Func->getContext()->getFlags()); | 1317 UnimplementedError(Func->getContext()->getFlags()); |
| 1198 } else { // Dest->getType() is non-i64 scalar | 1318 } else { // Dest->getType() is non-i64 scalar |
| 1199 Variable *Src0R = legalizeToVar(Inst->getSrc(0)); | 1319 Variable *Src0R = legalizeToVar(Inst->getSrc(0)); |
| 1200 Src1 = legalize(Inst->getSrc(1), Legal_Reg | Legal_Flex); | 1320 Operand *Src1RF = legalize(Inst->getSrc(1), Legal_Reg | Legal_Flex); |
| 1201 Variable *T = makeReg(Dest->getType()); | 1321 Variable *T = makeReg(Dest->getType()); |
| 1202 switch (Inst->getOp()) { | 1322 switch (Inst->getOp()) { |
| 1203 case InstArithmetic::_num: | 1323 case InstArithmetic::_num: |
| 1204 llvm_unreachable("Unknown arithmetic operator"); | 1324 llvm_unreachable("Unknown arithmetic operator"); |
| 1205 break; | 1325 break; |
| 1206 case InstArithmetic::Add: { | 1326 case InstArithmetic::Add: { |
| 1207 _add(T, Src0R, Src1); | 1327 _add(T, Src0R, Src1RF); |
| 1208 _mov(Dest, T); | 1328 _mov(Dest, T); |
| 1209 } break; | 1329 } break; |
| 1210 case InstArithmetic::And: { | 1330 case InstArithmetic::And: { |
| 1211 _and(T, Src0R, Src1); | 1331 _and(T, Src0R, Src1RF); |
| 1212 _mov(Dest, T); | 1332 _mov(Dest, T); |
| 1213 } break; | 1333 } break; |
| 1214 case InstArithmetic::Or: { | 1334 case InstArithmetic::Or: { |
| 1215 _orr(T, Src0R, Src1); | 1335 _orr(T, Src0R, Src1RF); |
| 1216 _mov(Dest, T); | 1336 _mov(Dest, T); |
| 1217 } break; | 1337 } break; |
| 1218 case InstArithmetic::Xor: { | 1338 case InstArithmetic::Xor: { |
| 1219 _eor(T, Src0R, Src1); | 1339 _eor(T, Src0R, Src1RF); |
| 1220 _mov(Dest, T); | 1340 _mov(Dest, T); |
| 1221 } break; | 1341 } break; |
| 1222 case InstArithmetic::Sub: { | 1342 case InstArithmetic::Sub: { |
| 1223 _sub(T, Src0R, Src1); | 1343 _sub(T, Src0R, Src1RF); |
| 1224 _mov(Dest, T); | 1344 _mov(Dest, T); |
| 1225 } break; | 1345 } break; |
| 1226 case InstArithmetic::Mul: { | 1346 case InstArithmetic::Mul: { |
| 1227 Variable *Src1R = legalizeToVar(Src1); | 1347 Variable *Src1R = legalizeToVar(Src1RF); |
| 1228 _mul(T, Src0R, Src1R); | 1348 _mul(T, Src0R, Src1R); |
| 1229 _mov(Dest, T); | 1349 _mov(Dest, T); |
| 1230 } break; | 1350 } break; |
| 1231 case InstArithmetic::Shl: | 1351 case InstArithmetic::Shl: |
| 1232 _lsl(T, Src0R, Src1); | 1352 _lsl(T, Src0R, Src1RF); |
| 1233 _mov(Dest, T); | 1353 _mov(Dest, T); |
| 1234 break; | 1354 break; |
| 1235 case InstArithmetic::Lshr: | 1355 case InstArithmetic::Lshr: |
| 1236 _lsr(T, Src0R, Src1); | 1356 _lsr(T, Src0R, Src1RF); |
| 1237 _mov(Dest, T); | 1357 _mov(Dest, T); |
| 1238 break; | 1358 break; |
| 1239 case InstArithmetic::Ashr: | 1359 case InstArithmetic::Ashr: |
| 1240 _asr(T, Src0R, Src1); | 1360 _asr(T, Src0R, Src1RF); |
| 1241 _mov(Dest, T); | 1361 _mov(Dest, T); |
| 1242 break; | 1362 break; |
| 1243 case InstArithmetic::Udiv: | 1363 case InstArithmetic::Udiv: { |
| 1244 UnimplementedError(Func->getContext()->getFlags()); | 1364 constexpr bool IsRemainder = false; |
| 1245 break; | 1365 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_uxt, |
| 1246 case InstArithmetic::Sdiv: | 1366 &TargetARM32::_udiv, H_udiv_i32, IsRemainder); |
| 1247 UnimplementedError(Func->getContext()->getFlags()); | 1367 return; |
| 1248 break; | 1368 } |
| 1249 case InstArithmetic::Urem: | 1369 case InstArithmetic::Sdiv: { |
| 1250 UnimplementedError(Func->getContext()->getFlags()); | 1370 constexpr bool IsRemainder = false; |
| 1251 break; | 1371 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_sxt, |
| 1252 case InstArithmetic::Srem: | 1372 &TargetARM32::_sdiv, H_sdiv_i32, IsRemainder); |
| 1253 UnimplementedError(Func->getContext()->getFlags()); | 1373 return; |
| 1254 break; | 1374 } |
| 1375 case InstArithmetic::Urem: { |
| 1376 constexpr bool IsRemainder = true; |
| 1377 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_uxt, |
| 1378 &TargetARM32::_udiv, H_urem_i32, IsRemainder); |
| 1379 return; |
| 1380 } |
| 1381 case InstArithmetic::Srem: { |
| 1382 constexpr bool IsRemainder = true; |
| 1383 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_sxt, |
| 1384 &TargetARM32::_sdiv, H_srem_i32, IsRemainder); |
| 1385 return; |
| 1386 } |
| 1255 case InstArithmetic::Fadd: | 1387 case InstArithmetic::Fadd: |
| 1256 UnimplementedError(Func->getContext()->getFlags()); | 1388 UnimplementedError(Func->getContext()->getFlags()); |
| 1257 break; | 1389 break; |
| 1258 case InstArithmetic::Fsub: | 1390 case InstArithmetic::Fsub: |
| 1259 UnimplementedError(Func->getContext()->getFlags()); | 1391 UnimplementedError(Func->getContext()->getFlags()); |
| 1260 break; | 1392 break; |
| 1261 case InstArithmetic::Fmul: | 1393 case InstArithmetic::Fmul: |
| 1262 UnimplementedError(Func->getContext()->getFlags()); | 1394 UnimplementedError(Func->getContext()->getFlags()); |
| 1263 break; | 1395 break; |
| 1264 case InstArithmetic::Fdiv: | 1396 case InstArithmetic::Fdiv: |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1315 if (Inst->isUnconditional()) { | 1447 if (Inst->isUnconditional()) { |
| 1316 _br(Inst->getTargetUnconditional()); | 1448 _br(Inst->getTargetUnconditional()); |
| 1317 return; | 1449 return; |
| 1318 } | 1450 } |
| 1319 Operand *Cond = Inst->getCondition(); | 1451 Operand *Cond = Inst->getCondition(); |
| 1320 // TODO(jvoung): Handle folding opportunities. | 1452 // TODO(jvoung): Handle folding opportunities. |
| 1321 | 1453 |
| 1322 Variable *Src0R = legalizeToVar(Cond); | 1454 Variable *Src0R = legalizeToVar(Cond); |
| 1323 Constant *Zero = Ctx->getConstantZero(IceType_i32); | 1455 Constant *Zero = Ctx->getConstantZero(IceType_i32); |
| 1324 _cmp(Src0R, Zero); | 1456 _cmp(Src0R, Zero); |
| 1325 _br(CondARM32::NE, Inst->getTargetTrue(), Inst->getTargetFalse()); | 1457 _br(Inst->getTargetTrue(), Inst->getTargetFalse(), CondARM32::NE); |
| 1326 } | 1458 } |
| 1327 | 1459 |
| 1328 void TargetARM32::lowerCall(const InstCall *Instr) { | 1460 void TargetARM32::lowerCall(const InstCall *Instr) { |
| 1329 MaybeLeafFunc = false; | 1461 MaybeLeafFunc = false; |
| 1330 NeedsStackAlignment = true; | 1462 NeedsStackAlignment = true; |
| 1331 | 1463 |
| 1332 // Assign arguments to registers and stack. Also reserve stack. | 1464 // Assign arguments to registers and stack. Also reserve stack. |
| 1333 TargetARM32::CallingConv CC; | 1465 TargetARM32::CallingConv CC; |
| 1334 // Pair of Arg Operand -> GPR number assignments. | 1466 // Pair of Arg Operand -> GPR number assignments. |
| 1335 llvm::SmallVector<std::pair<Operand *, int32_t>, | 1467 llvm::SmallVector<std::pair<Operand *, int32_t>, |
| (...skipping 770 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2106 for (SizeT I = 0; I < NumCases; ++I) { | 2238 for (SizeT I = 0; I < NumCases; ++I) { |
| 2107 Operand *Value = Ctx->getConstantInt32(Inst->getValue(I)); | 2239 Operand *Value = Ctx->getConstantInt32(Inst->getValue(I)); |
| 2108 Value = legalize(Value, Legal_Reg | Legal_Flex); | 2240 Value = legalize(Value, Legal_Reg | Legal_Flex); |
| 2109 _cmp(Src0Var, Value); | 2241 _cmp(Src0Var, Value); |
| 2110 _br(Inst->getLabel(I), CondARM32::EQ); | 2242 _br(Inst->getLabel(I), CondARM32::EQ); |
| 2111 } | 2243 } |
| 2112 _br(Inst->getLabelDefault()); | 2244 _br(Inst->getLabelDefault()); |
| 2113 } | 2245 } |
| 2114 | 2246 |
| 2115 void TargetARM32::lowerUnreachable(const InstUnreachable * /*Inst*/) { | 2247 void TargetARM32::lowerUnreachable(const InstUnreachable * /*Inst*/) { |
| 2116 UnimplementedError(Func->getContext()->getFlags()); | 2248 _trap(); |
| 2117 } | 2249 } |
| 2118 | 2250 |
| 2119 // Turn an i64 Phi instruction into a pair of i32 Phi instructions, to | 2251 // Turn an i64 Phi instruction into a pair of i32 Phi instructions, to |
| 2120 // preserve integrity of liveness analysis. Undef values are also | 2252 // preserve integrity of liveness analysis. Undef values are also |
| 2121 // turned into zeroes, since loOperand() and hiOperand() don't expect | 2253 // turned into zeroes, since loOperand() and hiOperand() don't expect |
| 2122 // Undef input. | 2254 // Undef input. |
| 2123 void TargetARM32::prelowerPhis() { | 2255 void TargetARM32::prelowerPhis() { |
| 2124 UnimplementedError(Func->getContext()->getFlags()); | 2256 UnimplementedError(Func->getContext()->getFlags()); |
| 2125 } | 2257 } |
| 2126 | 2258 |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2410 } | 2542 } |
| 2411 } | 2543 } |
| 2412 | 2544 |
| 2413 void TargetDataARM32::lowerConstants() { | 2545 void TargetDataARM32::lowerConstants() { |
| 2414 if (Ctx->getFlags().getDisableTranslation()) | 2546 if (Ctx->getFlags().getDisableTranslation()) |
| 2415 return; | 2547 return; |
| 2416 UnimplementedError(Ctx->getFlags()); | 2548 UnimplementedError(Ctx->getFlags()); |
| 2417 } | 2549 } |
| 2418 | 2550 |
| 2419 TargetHeaderARM32::TargetHeaderARM32(GlobalContext *Ctx) | 2551 TargetHeaderARM32::TargetHeaderARM32(GlobalContext *Ctx) |
| 2420 : TargetHeaderLowering(Ctx) {} | 2552 : TargetHeaderLowering(Ctx), CPUFeatures(Ctx->getFlags()) {} |
| 2421 | 2553 |
| 2422 void TargetHeaderARM32::lower() { | 2554 void TargetHeaderARM32::lower() { |
| 2423 OstreamLocker L(Ctx); | 2555 OstreamLocker L(Ctx); |
| 2424 Ostream &Str = Ctx->getStrEmit(); | 2556 Ostream &Str = Ctx->getStrEmit(); |
| 2425 Str << ".syntax unified\n"; | 2557 Str << ".syntax unified\n"; |
| 2426 // Emit build attributes in format: .eabi_attribute TAG, VALUE. | 2558 // Emit build attributes in format: .eabi_attribute TAG, VALUE. |
| 2427 // See Sec. 2 of "Addenda to, and Errata in the ABI for the ARM architecture" | 2559 // See Sec. 2 of "Addenda to, and Errata in the ABI for the ARM architecture" |
| 2428 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0045d/IHI0045D_ABI_adde
nda.pdf | 2560 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0045d/IHI0045D_ABI_adde
nda.pdf |
| 2429 // | 2561 // |
| 2430 // Tag_conformance should be be emitted first in a file-scope | 2562 // Tag_conformance should be be emitted first in a file-scope |
| 2431 // sub-subsection of the first public subsection of the attributes. | 2563 // sub-subsection of the first public subsection of the attributes. |
| 2432 Str << ".eabi_attribute 67, \"2.09\" @ Tag_conformance\n"; | 2564 Str << ".eabi_attribute 67, \"2.09\" @ Tag_conformance\n"; |
| 2433 // Chromebooks are at least A15, but do A9 for higher compat. | 2565 // Chromebooks are at least A15, but do A9 for higher compat. |
| 2434 Str << ".cpu cortex-a9\n" | 2566 // For some reason, the LLVM ARM asm parser has the .cpu directive override |
| 2435 << ".eabi_attribute 6, 10 @ Tag_CPU_arch: ARMv7\n" | 2567 // the mattr specified on the commandline. So to test hwdiv, we need to set |
| 2568 // the .cpu directive higher (can't just rely on --mattr=...). |
| 2569 if (CPUFeatures.hasFeature(TargetARM32Features::HWDivArm)) { |
| 2570 Str << ".cpu cortex-a15\n"; |
| 2571 } else { |
| 2572 Str << ".cpu cortex-a9\n"; |
| 2573 } |
| 2574 Str << ".eabi_attribute 6, 10 @ Tag_CPU_arch: ARMv7\n" |
| 2436 << ".eabi_attribute 7, 65 @ Tag_CPU_arch_profile: App profile\n"; | 2575 << ".eabi_attribute 7, 65 @ Tag_CPU_arch_profile: App profile\n"; |
| 2437 Str << ".eabi_attribute 8, 1 @ Tag_ARM_ISA_use: Yes\n" | 2576 Str << ".eabi_attribute 8, 1 @ Tag_ARM_ISA_use: Yes\n" |
| 2438 << ".eabi_attribute 9, 2 @ Tag_THUMB_ISA_use: Thumb-2\n"; | 2577 << ".eabi_attribute 9, 2 @ Tag_THUMB_ISA_use: Thumb-2\n"; |
| 2439 // TODO(jvoung): check other CPU features like HW div. | |
| 2440 Str << ".fpu neon\n" | 2578 Str << ".fpu neon\n" |
| 2441 << ".eabi_attribute 17, 1 @ Tag_ABI_PCS_GOT_use: permit directly\n" | 2579 << ".eabi_attribute 17, 1 @ Tag_ABI_PCS_GOT_use: permit directly\n" |
| 2442 << ".eabi_attribute 20, 1 @ Tag_ABI_FP_denormal\n" | 2580 << ".eabi_attribute 20, 1 @ Tag_ABI_FP_denormal\n" |
| 2443 << ".eabi_attribute 21, 1 @ Tag_ABI_FP_exceptions\n" | 2581 << ".eabi_attribute 21, 1 @ Tag_ABI_FP_exceptions\n" |
| 2444 << ".eabi_attribute 23, 3 @ Tag_ABI_FP_number_model: IEEE 754\n" | 2582 << ".eabi_attribute 23, 3 @ Tag_ABI_FP_number_model: IEEE 754\n" |
| 2445 << ".eabi_attribute 34, 1 @ Tag_CPU_unaligned_access\n" | 2583 << ".eabi_attribute 34, 1 @ Tag_CPU_unaligned_access\n" |
| 2446 << ".eabi_attribute 24, 1 @ Tag_ABI_align_needed: 8-byte\n" | 2584 << ".eabi_attribute 24, 1 @ Tag_ABI_align_needed: 8-byte\n" |
| 2447 << ".eabi_attribute 25, 1 @ Tag_ABI_align_preserved: 8-byte\n" | 2585 << ".eabi_attribute 25, 1 @ Tag_ABI_align_preserved: 8-byte\n" |
| 2448 << ".eabi_attribute 28, 1 @ Tag_ABI_VFP_args\n" | 2586 << ".eabi_attribute 28, 1 @ Tag_ABI_VFP_args\n" |
| 2449 << ".eabi_attribute 36, 1 @ Tag_FP_HP_extension\n" | 2587 << ".eabi_attribute 36, 1 @ Tag_FP_HP_extension\n" |
| 2450 << ".eabi_attribute 38, 1 @ Tag_ABI_FP_16bit_format\n" | 2588 << ".eabi_attribute 38, 1 @ Tag_ABI_FP_16bit_format\n" |
| 2451 << ".eabi_attribute 42, 1 @ Tag_MPextension_use\n" | 2589 << ".eabi_attribute 42, 1 @ Tag_MPextension_use\n" |
| 2452 << ".eabi_attribute 68, 1 @ Tag_Virtualization_use\n"; | 2590 << ".eabi_attribute 68, 1 @ Tag_Virtualization_use\n"; |
| 2591 if (CPUFeatures.hasFeature(TargetARM32Features::HWDivArm)) { |
| 2592 Str << ".eabi_attribute 44, 2 @ Tag_DIV_use\n"; |
| 2593 } |
| 2453 // Technically R9 is used for TLS with Sandboxing, and we reserve it. | 2594 // Technically R9 is used for TLS with Sandboxing, and we reserve it. |
| 2454 // However, for compatibility with current NaCl LLVM, don't claim that. | 2595 // However, for compatibility with current NaCl LLVM, don't claim that. |
| 2455 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; | 2596 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; |
| 2456 } | 2597 } |
| 2457 | 2598 |
| 2458 } // end of namespace Ice | 2599 } // end of namespace Ice |
| OLD | NEW |