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

Side by Side Diff: src/IceTargetLoweringARM32.cpp

Issue 1214693004: ARM lowering integer divide and remainder, with div by 0 checks. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: fill in todo Created 5 years, 5 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/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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698