Chromium Code Reviews| 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 non-zero. | |
| 146 bool operandMustNotBeZero(const Operand *Op) { | |
|
Jim Stichnoth
2015/06/30 14:14:09
May want to tweak the function name to express the
jvoung (off chromium)
2015/06/30 16:58:08
Done.
| |
| 147 if (auto *Const = llvm::dyn_cast<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 InstARM32Label *TargetARM32::beginDiv0Check(Type Ty, Operand *SrcLo, | |
| 1026 Operand *SrcHi) { | |
| 1027 bool ElideCheck = operandMustNotBeZero(SrcLo); | |
|
Jim Stichnoth
2015/06/30 14:14:09
What do you think about starting the function like
jvoung (off chromium)
2015/06/30 16:58:08
Done.
| |
| 1028 if (Ty == IceType_i64) { | |
| 1029 ElideCheck = ElideCheck || operandMustNotBeZero(SrcHi); | |
| 1030 } | |
| 1031 if (ElideCheck) | |
| 1032 return nullptr; | |
| 1033 InstARM32Label *Label = InstARM32Label::create(Func, this); | |
| 1034 Variable *SrcLoReg = legalizeToVar(SrcLo); | |
| 1035 switch (Ty) { | |
| 1036 default: | |
| 1037 llvm_unreachable("Unexpected type"); | |
| 1038 case IceType_i8: { | |
| 1039 Operand *Mask = | |
| 1040 legalize(Ctx->getConstantInt32(0xFF), Legal_Reg | Legal_Flex); | |
| 1041 _tst(SrcLoReg, Mask); | |
| 1042 break; | |
| 1043 } | |
| 1044 case IceType_i16: { | |
| 1045 Operand *Mask = | |
| 1046 legalize(Ctx->getConstantInt32(0xFFFF), Legal_Reg | Legal_Flex); | |
| 1047 _tst(SrcLoReg, Mask); | |
| 1048 break; | |
| 1049 } | |
| 1050 case IceType_i32: { | |
| 1051 _tst(SrcLoReg, SrcLoReg); | |
| 1052 break; | |
| 1053 } | |
| 1054 case IceType_i64: { | |
| 1055 Variable *ScratchReg = makeReg(IceType_i32); | |
| 1056 _orrs(ScratchReg, SrcLoReg, SrcHi); | |
| 1057 // ScratchReg isn't going to be used, but we need the | |
| 1058 // side-effect of setting flags from this operation. | |
| 1059 Context.insert(InstFakeUse::create(Func, ScratchReg)); | |
| 1060 } | |
| 1061 } | |
| 1062 _br(Label, CondARM32::EQ); | |
| 1063 return Label; | |
| 1064 } | |
| 1065 | |
| 1066 void TargetARM32::endDiv0Check(InstARM32Label *CheckLabel) { | |
| 1067 if (CheckLabel) { | |
| 1068 Context.insert(CheckLabel); | |
|
jvoung (off chromium)
2015/06/30 16:58:08
Oops, also realized that I need to do the trap, an
Jim Stichnoth
2015/06/30 17:06:51
Heh... I think those cross tests explicitly avoid
| |
| 1069 _trap(); | |
| 1070 } | |
| 1071 } | |
| 1072 | |
| 1073 void TargetARM32::lowerIDivRem(Variable *Dest, Variable *T, Variable *Src0R, | |
| 1074 Operand *Src1, ExtInstr ExtFunc, | |
| 1075 DivInstr DivFunc, const char *DivHelperName, | |
| 1076 bool IsRemainder) { | |
| 1077 InstARM32Label *Label = beginDiv0Check(Dest->getType(), Src1, nullptr); | |
| 1078 Variable *Src1R = legalizeToVar(Src1); | |
| 1079 Variable *T0R = Src0R; | |
| 1080 Variable *T1R = Src1R; | |
| 1081 if (Dest->getType() != IceType_i32) { | |
| 1082 T0R = makeReg(IceType_i32); | |
| 1083 (this->*ExtFunc)(T0R, Src0R, CondARM32::AL); | |
| 1084 T1R = makeReg(IceType_i32); | |
| 1085 (this->*ExtFunc)(T1R, Src1R, CondARM32::AL); | |
| 1086 } | |
| 1087 if (hasCPUFeature(TargetARM32Features::HWDivArm)) { | |
| 1088 (this->*DivFunc)(T, T0R, T1R, CondARM32::AL); | |
| 1089 if (IsRemainder) { | |
| 1090 Variable *T2 = makeReg(IceType_i32); | |
| 1091 _mls(T2, T, T1R, T0R); | |
| 1092 T = T2; | |
| 1093 } | |
| 1094 _mov(Dest, T); | |
| 1095 } else { | |
| 1096 const SizeT MaxSrcs = 2; | |
| 1097 InstCall *Call = makeHelperCall(DivHelperName, Dest, MaxSrcs); | |
| 1098 Call->addArg(T0R); | |
| 1099 Call->addArg(T1R); | |
| 1100 lowerCall(Call); | |
| 1101 } | |
| 1102 endDiv0Check(Label); | |
| 1103 return; | |
| 1104 } | |
| 1105 | |
| 1012 void TargetARM32::lowerArithmetic(const InstArithmetic *Inst) { | 1106 void TargetARM32::lowerArithmetic(const InstArithmetic *Inst) { |
| 1013 Variable *Dest = Inst->getDest(); | 1107 Variable *Dest = Inst->getDest(); |
| 1014 // TODO(jvoung): Should be able to flip Src0 and Src1 if it is easier | 1108 // 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 | 1109 // to legalize Src0 to flex or Src1 to flex and there is a reversible |
| 1016 // instruction. E.g., reverse subtract with immediate, register vs | 1110 // instruction. E.g., reverse subtract with immediate, register vs |
| 1017 // register, immediate. | 1111 // register, immediate. |
| 1018 // Or it may be the case that the operands aren't swapped, but the | 1112 // Or it may be the case that the operands aren't swapped, but the |
| 1019 // bits can be flipped and a different operation applied. | 1113 // bits can be flipped and a different operation applied. |
| 1020 // E.g., use BIC (bit clear) instead of AND for some masks. | 1114 // E.g., use BIC (bit clear) instead of AND for some masks. |
| 1021 Operand *Src0 = Inst->getSrc(0); | 1115 Operand *Src0 = Inst->getSrc(0); |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1175 Pred); | 1269 Pred); |
| 1176 _mov(DestLo, T_Lo); | 1270 _mov(DestLo, T_Lo); |
| 1177 Variable *T_Hi = makeReg(IceType_i32); | 1271 Variable *T_Hi = makeReg(IceType_i32); |
| 1178 _mov(T_Hi, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi, | 1272 _mov(T_Hi, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi, |
| 1179 RShiftKind, Src1RLo)); | 1273 RShiftKind, Src1RLo)); |
| 1180 _mov(DestHi, T_Hi); | 1274 _mov(DestHi, T_Hi); |
| 1181 } break; | 1275 } break; |
| 1182 case InstArithmetic::Udiv: | 1276 case InstArithmetic::Udiv: |
| 1183 case InstArithmetic::Sdiv: | 1277 case InstArithmetic::Sdiv: |
| 1184 case InstArithmetic::Urem: | 1278 case InstArithmetic::Urem: |
| 1185 case InstArithmetic::Srem: | 1279 case InstArithmetic::Srem: { |
| 1186 UnimplementedError(Func->getContext()->getFlags()); | 1280 // Check for divide by 0 (ARM normally doesn't trap, but we want it |
| 1187 break; | 1281 // to trap for NaCl). |
| 1282 InstARM32Label *Label = nullptr; | |
| 1283 // Src1Lo and Src1Hi may have already been legalized to a register, | |
| 1284 // which will hide a constant source operand. Instead, check the | |
| 1285 // not-yet-legalized Src1 to optimize-out a divide by 0 check. | |
| 1286 if (auto *C64 = llvm::dyn_cast<ConstantInteger64>(Src1)) { | |
| 1287 if (C64->getValue() == 0) { | |
| 1288 Label = beginDiv0Check(IceType_i64, Src1Lo, Src1Hi); | |
| 1289 } | |
| 1290 } else { | |
| 1291 Label = beginDiv0Check(IceType_i64, Src1Lo, Src1Hi); | |
| 1292 } | |
| 1293 // Technically, ARM has their own aeabi routines, but we can use the | |
| 1294 // non-aeabi routine as well. LLVM uses __aeabi_ldivmod for div, | |
| 1295 // but uses the more standard __moddi3 for rem. | |
| 1296 const char *HelperName = ""; | |
| 1297 switch (Inst->getOp()) { | |
| 1298 case InstArithmetic::Udiv: | |
| 1299 HelperName = H_udiv_i64; | |
| 1300 break; | |
| 1301 case InstArithmetic::Sdiv: | |
| 1302 HelperName = H_sdiv_i64; | |
| 1303 break; | |
| 1304 case InstArithmetic::Urem: | |
| 1305 HelperName = H_urem_i64; | |
| 1306 break; | |
| 1307 case InstArithmetic::Srem: | |
| 1308 HelperName = H_srem_i64; | |
| 1309 break; | |
| 1310 default: | |
| 1311 llvm_unreachable("Should have only matched div ops."); | |
| 1312 break; | |
| 1313 } | |
| 1314 const SizeT MaxSrcs = 2; | |
|
Jim Stichnoth
2015/06/30 14:14:09
constexpr?
jvoung (off chromium)
2015/06/30 16:58:08
Done.
| |
| 1315 InstCall *Call = makeHelperCall(HelperName, Dest, MaxSrcs); | |
| 1316 Call->addArg(Inst->getSrc(0)); | |
| 1317 Call->addArg(Inst->getSrc(1)); | |
| 1318 lowerCall(Call); | |
| 1319 endDiv0Check(Label); | |
| 1320 return; | |
| 1321 } | |
| 1188 case InstArithmetic::Fadd: | 1322 case InstArithmetic::Fadd: |
| 1189 case InstArithmetic::Fsub: | 1323 case InstArithmetic::Fsub: |
| 1190 case InstArithmetic::Fmul: | 1324 case InstArithmetic::Fmul: |
| 1191 case InstArithmetic::Fdiv: | 1325 case InstArithmetic::Fdiv: |
| 1192 case InstArithmetic::Frem: | 1326 case InstArithmetic::Frem: |
| 1193 llvm_unreachable("FP instruction with i64 type"); | 1327 llvm_unreachable("FP instruction with i64 type"); |
| 1194 break; | 1328 break; |
| 1195 } | 1329 } |
| 1196 } else if (isVectorType(Dest->getType())) { | 1330 } else if (isVectorType(Dest->getType())) { |
| 1197 UnimplementedError(Func->getContext()->getFlags()); | 1331 UnimplementedError(Func->getContext()->getFlags()); |
| 1198 } else { // Dest->getType() is non-i64 scalar | 1332 } else { // Dest->getType() is non-i64 scalar |
| 1199 Variable *Src0R = legalizeToVar(Inst->getSrc(0)); | 1333 Variable *Src0R = legalizeToVar(Inst->getSrc(0)); |
| 1200 Src1 = legalize(Inst->getSrc(1), Legal_Reg | Legal_Flex); | 1334 Operand *Src1RF = legalize(Inst->getSrc(1), Legal_Reg | Legal_Flex); |
| 1201 Variable *T = makeReg(Dest->getType()); | 1335 Variable *T = makeReg(Dest->getType()); |
| 1202 switch (Inst->getOp()) { | 1336 switch (Inst->getOp()) { |
| 1203 case InstArithmetic::_num: | 1337 case InstArithmetic::_num: |
| 1204 llvm_unreachable("Unknown arithmetic operator"); | 1338 llvm_unreachable("Unknown arithmetic operator"); |
| 1205 break; | 1339 break; |
| 1206 case InstArithmetic::Add: { | 1340 case InstArithmetic::Add: { |
| 1207 _add(T, Src0R, Src1); | 1341 _add(T, Src0R, Src1RF); |
| 1208 _mov(Dest, T); | 1342 _mov(Dest, T); |
| 1209 } break; | 1343 } break; |
| 1210 case InstArithmetic::And: { | 1344 case InstArithmetic::And: { |
| 1211 _and(T, Src0R, Src1); | 1345 _and(T, Src0R, Src1RF); |
| 1212 _mov(Dest, T); | 1346 _mov(Dest, T); |
| 1213 } break; | 1347 } break; |
| 1214 case InstArithmetic::Or: { | 1348 case InstArithmetic::Or: { |
| 1215 _orr(T, Src0R, Src1); | 1349 _orr(T, Src0R, Src1RF); |
| 1216 _mov(Dest, T); | 1350 _mov(Dest, T); |
| 1217 } break; | 1351 } break; |
| 1218 case InstArithmetic::Xor: { | 1352 case InstArithmetic::Xor: { |
| 1219 _eor(T, Src0R, Src1); | 1353 _eor(T, Src0R, Src1RF); |
| 1220 _mov(Dest, T); | 1354 _mov(Dest, T); |
| 1221 } break; | 1355 } break; |
| 1222 case InstArithmetic::Sub: { | 1356 case InstArithmetic::Sub: { |
| 1223 _sub(T, Src0R, Src1); | 1357 _sub(T, Src0R, Src1RF); |
| 1224 _mov(Dest, T); | 1358 _mov(Dest, T); |
| 1225 } break; | 1359 } break; |
| 1226 case InstArithmetic::Mul: { | 1360 case InstArithmetic::Mul: { |
| 1227 Variable *Src1R = legalizeToVar(Src1); | 1361 Variable *Src1R = legalizeToVar(Src1RF); |
| 1228 _mul(T, Src0R, Src1R); | 1362 _mul(T, Src0R, Src1R); |
| 1229 _mov(Dest, T); | 1363 _mov(Dest, T); |
| 1230 } break; | 1364 } break; |
| 1231 case InstArithmetic::Shl: | 1365 case InstArithmetic::Shl: |
| 1232 _lsl(T, Src0R, Src1); | 1366 _lsl(T, Src0R, Src1RF); |
| 1233 _mov(Dest, T); | 1367 _mov(Dest, T); |
| 1234 break; | 1368 break; |
| 1235 case InstArithmetic::Lshr: | 1369 case InstArithmetic::Lshr: |
| 1236 _lsr(T, Src0R, Src1); | 1370 _lsr(T, Src0R, Src1RF); |
| 1237 _mov(Dest, T); | 1371 _mov(Dest, T); |
| 1238 break; | 1372 break; |
| 1239 case InstArithmetic::Ashr: | 1373 case InstArithmetic::Ashr: |
| 1240 _asr(T, Src0R, Src1); | 1374 _asr(T, Src0R, Src1RF); |
| 1241 _mov(Dest, T); | 1375 _mov(Dest, T); |
| 1242 break; | 1376 break; |
| 1243 case InstArithmetic::Udiv: | 1377 case InstArithmetic::Udiv: { |
| 1244 UnimplementedError(Func->getContext()->getFlags()); | 1378 constexpr bool IsRemainder = false; |
| 1245 break; | 1379 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_uxt, |
| 1246 case InstArithmetic::Sdiv: | 1380 &TargetARM32::_udiv, H_udiv_i32, IsRemainder); |
| 1247 UnimplementedError(Func->getContext()->getFlags()); | 1381 return; |
| 1248 break; | 1382 } |
| 1249 case InstArithmetic::Urem: | 1383 case InstArithmetic::Sdiv: { |
| 1250 UnimplementedError(Func->getContext()->getFlags()); | 1384 constexpr bool IsRemainder = false; |
| 1251 break; | 1385 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_sxt, |
| 1252 case InstArithmetic::Srem: | 1386 &TargetARM32::_sdiv, H_sdiv_i32, IsRemainder); |
| 1253 UnimplementedError(Func->getContext()->getFlags()); | 1387 return; |
| 1254 break; | 1388 } |
| 1389 case InstArithmetic::Urem: { | |
| 1390 constexpr bool IsRemainder = true; | |
| 1391 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_uxt, | |
| 1392 &TargetARM32::_udiv, H_urem_i32, IsRemainder); | |
| 1393 return; | |
| 1394 } | |
| 1395 case InstArithmetic::Srem: { | |
| 1396 constexpr bool IsRemainder = true; | |
| 1397 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_sxt, | |
| 1398 &TargetARM32::_sdiv, H_srem_i32, IsRemainder); | |
| 1399 return; | |
| 1400 } | |
| 1255 case InstArithmetic::Fadd: | 1401 case InstArithmetic::Fadd: |
| 1256 UnimplementedError(Func->getContext()->getFlags()); | 1402 UnimplementedError(Func->getContext()->getFlags()); |
| 1257 break; | 1403 break; |
| 1258 case InstArithmetic::Fsub: | 1404 case InstArithmetic::Fsub: |
| 1259 UnimplementedError(Func->getContext()->getFlags()); | 1405 UnimplementedError(Func->getContext()->getFlags()); |
| 1260 break; | 1406 break; |
| 1261 case InstArithmetic::Fmul: | 1407 case InstArithmetic::Fmul: |
| 1262 UnimplementedError(Func->getContext()->getFlags()); | 1408 UnimplementedError(Func->getContext()->getFlags()); |
| 1263 break; | 1409 break; |
| 1264 case InstArithmetic::Fdiv: | 1410 case InstArithmetic::Fdiv: |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1315 if (Inst->isUnconditional()) { | 1461 if (Inst->isUnconditional()) { |
| 1316 _br(Inst->getTargetUnconditional()); | 1462 _br(Inst->getTargetUnconditional()); |
| 1317 return; | 1463 return; |
| 1318 } | 1464 } |
| 1319 Operand *Cond = Inst->getCondition(); | 1465 Operand *Cond = Inst->getCondition(); |
| 1320 // TODO(jvoung): Handle folding opportunities. | 1466 // TODO(jvoung): Handle folding opportunities. |
| 1321 | 1467 |
| 1322 Variable *Src0R = legalizeToVar(Cond); | 1468 Variable *Src0R = legalizeToVar(Cond); |
| 1323 Constant *Zero = Ctx->getConstantZero(IceType_i32); | 1469 Constant *Zero = Ctx->getConstantZero(IceType_i32); |
| 1324 _cmp(Src0R, Zero); | 1470 _cmp(Src0R, Zero); |
| 1325 _br(CondARM32::NE, Inst->getTargetTrue(), Inst->getTargetFalse()); | 1471 _br(Inst->getTargetTrue(), Inst->getTargetFalse(), CondARM32::NE); |
| 1326 } | 1472 } |
| 1327 | 1473 |
| 1328 void TargetARM32::lowerCall(const InstCall *Instr) { | 1474 void TargetARM32::lowerCall(const InstCall *Instr) { |
| 1329 MaybeLeafFunc = false; | 1475 MaybeLeafFunc = false; |
| 1330 NeedsStackAlignment = true; | 1476 NeedsStackAlignment = true; |
| 1331 | 1477 |
| 1332 // Assign arguments to registers and stack. Also reserve stack. | 1478 // Assign arguments to registers and stack. Also reserve stack. |
| 1333 TargetARM32::CallingConv CC; | 1479 TargetARM32::CallingConv CC; |
| 1334 // Pair of Arg Operand -> GPR number assignments. | 1480 // Pair of Arg Operand -> GPR number assignments. |
| 1335 llvm::SmallVector<std::pair<Operand *, int32_t>, | 1481 llvm::SmallVector<std::pair<Operand *, int32_t>, |
| (...skipping 714 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2050 Operand *ValueHi = Ctx->getConstantInt32(Inst->getValue(I) >> 32); | 2196 Operand *ValueHi = Ctx->getConstantInt32(Inst->getValue(I) >> 32); |
| 2051 ValueLo = legalize(ValueLo, Legal_Reg | Legal_Flex); | 2197 ValueLo = legalize(ValueLo, Legal_Reg | Legal_Flex); |
| 2052 ValueHi = legalize(ValueHi, Legal_Reg | Legal_Flex); | 2198 ValueHi = legalize(ValueHi, Legal_Reg | Legal_Flex); |
| 2053 _cmp(Src0Lo, ValueLo); | 2199 _cmp(Src0Lo, ValueLo); |
| 2054 _cmp(Src0Hi, ValueHi, CondARM32::EQ); | 2200 _cmp(Src0Hi, ValueHi, CondARM32::EQ); |
| 2055 _br(Inst->getLabel(I), CondARM32::EQ); | 2201 _br(Inst->getLabel(I), CondARM32::EQ); |
| 2056 } | 2202 } |
| 2057 _br(Inst->getLabelDefault()); | 2203 _br(Inst->getLabelDefault()); |
| 2058 return; | 2204 return; |
| 2059 } | 2205 } |
| 2060 | 2206 |
| 2061 // 32 bit integer | 2207 // 32 bit integer |
| 2062 Variable *Src0Var = legalizeToVar(Src0); | 2208 Variable *Src0Var = legalizeToVar(Src0); |
| 2063 for (SizeT I = 0; I < NumCases; ++I) { | 2209 for (SizeT I = 0; I < NumCases; ++I) { |
| 2064 Operand *Value = Ctx->getConstantInt32(Inst->getValue(I)); | 2210 Operand *Value = Ctx->getConstantInt32(Inst->getValue(I)); |
| 2065 Value = legalize(Value, Legal_Reg | Legal_Flex); | 2211 Value = legalize(Value, Legal_Reg | Legal_Flex); |
| 2066 _cmp(Src0Var, Value); | 2212 _cmp(Src0Var, Value); |
| 2067 _br(Inst->getLabel(I), CondARM32::EQ); | 2213 _br(Inst->getLabel(I), CondARM32::EQ); |
| 2068 } | 2214 } |
| 2069 _br(Inst->getLabelDefault()); | 2215 _br(Inst->getLabelDefault()); |
| 2070 } | 2216 } |
| 2071 | 2217 |
| 2072 void TargetARM32::lowerUnreachable(const InstUnreachable * /*Inst*/) { | 2218 void TargetARM32::lowerUnreachable(const InstUnreachable * /*Inst*/) { |
| 2073 UnimplementedError(Func->getContext()->getFlags()); | 2219 _trap(); |
| 2074 } | 2220 } |
| 2075 | 2221 |
| 2076 // Turn an i64 Phi instruction into a pair of i32 Phi instructions, to | 2222 // Turn an i64 Phi instruction into a pair of i32 Phi instructions, to |
| 2077 // preserve integrity of liveness analysis. Undef values are also | 2223 // preserve integrity of liveness analysis. Undef values are also |
| 2078 // turned into zeroes, since loOperand() and hiOperand() don't expect | 2224 // turned into zeroes, since loOperand() and hiOperand() don't expect |
| 2079 // Undef input. | 2225 // Undef input. |
| 2080 void TargetARM32::prelowerPhis() { | 2226 void TargetARM32::prelowerPhis() { |
| 2081 UnimplementedError(Func->getContext()->getFlags()); | 2227 UnimplementedError(Func->getContext()->getFlags()); |
| 2082 } | 2228 } |
| 2083 | 2229 |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2367 } | 2513 } |
| 2368 } | 2514 } |
| 2369 | 2515 |
| 2370 void TargetDataARM32::lowerConstants() { | 2516 void TargetDataARM32::lowerConstants() { |
| 2371 if (Ctx->getFlags().getDisableTranslation()) | 2517 if (Ctx->getFlags().getDisableTranslation()) |
| 2372 return; | 2518 return; |
| 2373 UnimplementedError(Ctx->getFlags()); | 2519 UnimplementedError(Ctx->getFlags()); |
| 2374 } | 2520 } |
| 2375 | 2521 |
| 2376 TargetHeaderARM32::TargetHeaderARM32(GlobalContext *Ctx) | 2522 TargetHeaderARM32::TargetHeaderARM32(GlobalContext *Ctx) |
| 2377 : TargetHeaderLowering(Ctx) {} | 2523 : TargetHeaderLowering(Ctx), CPUFeatures(Ctx->getFlags()) {} |
| 2378 | 2524 |
| 2379 void TargetHeaderARM32::lower() { | 2525 void TargetHeaderARM32::lower() { |
| 2380 OstreamLocker L(Ctx); | 2526 OstreamLocker L(Ctx); |
| 2381 Ostream &Str = Ctx->getStrEmit(); | 2527 Ostream &Str = Ctx->getStrEmit(); |
| 2382 Str << ".syntax unified\n"; | 2528 Str << ".syntax unified\n"; |
| 2383 // Emit build attributes in format: .eabi_attribute TAG, VALUE. | 2529 // Emit build attributes in format: .eabi_attribute TAG, VALUE. |
| 2384 // See Sec. 2 of "Addenda to, and Errata in the ABI for the ARM architecture" | 2530 // See Sec. 2 of "Addenda to, and Errata in the ABI for the ARM architecture" |
| 2385 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0045d/IHI0045D_ABI_adde nda.pdf | 2531 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0045d/IHI0045D_ABI_adde nda.pdf |
| 2386 // | 2532 // |
| 2387 // Tag_conformance should be be emitted first in a file-scope | 2533 // Tag_conformance should be be emitted first in a file-scope |
| 2388 // sub-subsection of the first public subsection of the attributes. | 2534 // sub-subsection of the first public subsection of the attributes. |
| 2389 Str << ".eabi_attribute 67, \"2.09\" @ Tag_conformance\n"; | 2535 Str << ".eabi_attribute 67, \"2.09\" @ Tag_conformance\n"; |
| 2390 // Chromebooks are at least A15, but do A9 for higher compat. | 2536 // Chromebooks are at least A15, but do A9 for higher compat. |
| 2391 Str << ".cpu cortex-a9\n" | 2537 // For some reason, the LLVM ARM asm parser has the .cpu directive override |
| 2392 << ".eabi_attribute 6, 10 @ Tag_CPU_arch: ARMv7\n" | 2538 // the mattr specified on the commandline. So to test hwdiv, we need to set |
| 2539 // the .cpu directive higher (can't just rely on --mattr=...). | |
| 2540 if (CPUFeatures.hasFeature(TargetARM32Features::HWDivArm)) { | |
| 2541 Str << ".cpu cortex-a15\n"; | |
| 2542 } else { | |
| 2543 Str << ".cpu cortex-a9\n"; | |
| 2544 } | |
| 2545 Str << ".eabi_attribute 6, 10 @ Tag_CPU_arch: ARMv7\n" | |
| 2393 << ".eabi_attribute 7, 65 @ Tag_CPU_arch_profile: App profile\n"; | 2546 << ".eabi_attribute 7, 65 @ Tag_CPU_arch_profile: App profile\n"; |
| 2394 Str << ".eabi_attribute 8, 1 @ Tag_ARM_ISA_use: Yes\n" | 2547 Str << ".eabi_attribute 8, 1 @ Tag_ARM_ISA_use: Yes\n" |
| 2395 << ".eabi_attribute 9, 2 @ Tag_THUMB_ISA_use: Thumb-2\n"; | 2548 << ".eabi_attribute 9, 2 @ Tag_THUMB_ISA_use: Thumb-2\n"; |
| 2396 // TODO(jvoung): check other CPU features like HW div. | |
| 2397 Str << ".fpu neon\n" | 2549 Str << ".fpu neon\n" |
| 2398 << ".eabi_attribute 17, 1 @ Tag_ABI_PCS_GOT_use: permit directly\n" | 2550 << ".eabi_attribute 17, 1 @ Tag_ABI_PCS_GOT_use: permit directly\n" |
| 2399 << ".eabi_attribute 20, 1 @ Tag_ABI_FP_denormal\n" | 2551 << ".eabi_attribute 20, 1 @ Tag_ABI_FP_denormal\n" |
| 2400 << ".eabi_attribute 21, 1 @ Tag_ABI_FP_exceptions\n" | 2552 << ".eabi_attribute 21, 1 @ Tag_ABI_FP_exceptions\n" |
| 2401 << ".eabi_attribute 23, 3 @ Tag_ABI_FP_number_model: IEEE 754\n" | 2553 << ".eabi_attribute 23, 3 @ Tag_ABI_FP_number_model: IEEE 754\n" |
| 2402 << ".eabi_attribute 34, 1 @ Tag_CPU_unaligned_access\n" | 2554 << ".eabi_attribute 34, 1 @ Tag_CPU_unaligned_access\n" |
| 2403 << ".eabi_attribute 24, 1 @ Tag_ABI_align_needed: 8-byte\n" | 2555 << ".eabi_attribute 24, 1 @ Tag_ABI_align_needed: 8-byte\n" |
| 2404 << ".eabi_attribute 25, 1 @ Tag_ABI_align_preserved: 8-byte\n" | 2556 << ".eabi_attribute 25, 1 @ Tag_ABI_align_preserved: 8-byte\n" |
| 2405 << ".eabi_attribute 28, 1 @ Tag_ABI_VFP_args\n" | 2557 << ".eabi_attribute 28, 1 @ Tag_ABI_VFP_args\n" |
| 2406 << ".eabi_attribute 36, 1 @ Tag_FP_HP_extension\n" | 2558 << ".eabi_attribute 36, 1 @ Tag_FP_HP_extension\n" |
| 2407 << ".eabi_attribute 38, 1 @ Tag_ABI_FP_16bit_format\n" | 2559 << ".eabi_attribute 38, 1 @ Tag_ABI_FP_16bit_format\n" |
| 2408 << ".eabi_attribute 42, 1 @ Tag_MPextension_use\n" | 2560 << ".eabi_attribute 42, 1 @ Tag_MPextension_use\n" |
| 2409 << ".eabi_attribute 68, 1 @ Tag_Virtualization_use\n"; | 2561 << ".eabi_attribute 68, 1 @ Tag_Virtualization_use\n"; |
| 2562 if (CPUFeatures.hasFeature(TargetARM32Features::HWDivArm)) { | |
| 2563 Str << ".eabi_attribute 44, 2 @ Tag_DIV_use\n"; | |
| 2564 } | |
| 2410 // Technically R9 is used for TLS with Sandboxing, and we reserve it. | 2565 // Technically R9 is used for TLS with Sandboxing, and we reserve it. |
| 2411 // However, for compatibility with current NaCl LLVM, don't claim that. | 2566 // However, for compatibility with current NaCl LLVM, don't claim that. |
| 2412 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; | 2567 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; |
| 2413 } | 2568 } |
| 2414 | 2569 |
| 2415 } // end of namespace Ice | 2570 } // end of namespace Ice |
| OLD | NEW |