llvm.org GIT mirror llvm / a479e53
[ARM] GlobalISel: Select hard G_FCMP for s32 We lower to a sequence consisting of: - MOVi 0 into a register - VCMPS to do the actual comparison and set the VFP flags - FMSTAT to move the flags out of the VFP unit - MOVCCi to either use the "zero register" that we have previously set with the MOVi, or move 1 into the result register, based on the values of the flags As was the case with soft-float, for some predicates (one, ueq) we actually need two comparisons instead of just one. When that happens, we generate two VCMPS-FMSTAT-MOVCCi sequences and chain them by means of using the result of the first MOVCCi as the "zero register" for the second one. This is a bit overkill, since one comparison followed by two non-flag-setting conditional moves should be enough. In any case, the backend manages to CSE one of the comparisons away so it doesn't matter much. Note that unlike SelectionDAG and FastISel, we always use VCMPS, and not VCMPES. This makes the code a lot simpler, and it also seems correct since the LLVM Lang Ref defines simple true/false returns if the operands are QNaN's. For SNaN's, even VCMPS throws an Invalid Operand exception, so they won't be slipping through unnoticed. Implementation-wise, this introduces a template so we can share the same code that we use for handling integer comparisons, since the only differences are in the details (exact opcodes to be used etc). Hopefully this will be easy to extend to s64 G_FCMP. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@307365 91177308-0d34-0410-b5e6-96231b3b80d8 Diana Picus 3 years ago
3 changed file(s) with 876 addition(s) and 68 deletion(s). Raw diff Collapse all Expand all
4343 private:
4444 bool selectImpl(MachineInstr &I) const;
4545
46 bool selectICmp(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII,
47 MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
48 const RegisterBankInfo &RBI) const;
46 template struct CmpHelper;
47
48 template
49 bool selectCmp(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII,
50 MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
51 const RegisterBankInfo &RBI) const;
4952
5053 bool selectSelect(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII,
5154 MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
252255 return Opc;
253256 }
254257
255 static ARMCC::CondCodes getComparePred(CmpInst::Predicate Pred) {
258 // When lowering comparisons, we sometimes need to perform two compares instead
259 // of just one. Get the condition codes for both comparisons. If only one is
260 // needed, the second member of the pair is ARMCC::AL.
261 static std::pair
262 getComparePreds(CmpInst::Predicate Pred) {
263 std::pair Preds = {ARMCC::AL, ARMCC::AL};
256264 switch (Pred) {
257 // Needs two compares...
258265 case CmpInst::FCMP_ONE:
266 Preds = {ARMCC::GT, ARMCC::MI};
267 break;
259268 case CmpInst::FCMP_UEQ:
260 default:
261 // AL is our "false" for now. The other two need more compares.
262 return ARMCC::AL;
269 Preds = {ARMCC::EQ, ARMCC::VS};
270 break;
263271 case CmpInst::ICMP_EQ:
264272 case CmpInst::FCMP_OEQ:
265 return ARMCC::EQ;
273 Preds.first = ARMCC::EQ;
274 break;
266275 case CmpInst::ICMP_SGT:
267276 case CmpInst::FCMP_OGT:
268 return ARMCC::GT;
277 Preds.first = ARMCC::GT;
278 break;
269279 case CmpInst::ICMP_SGE:
270280 case CmpInst::FCMP_OGE:
271 return ARMCC::GE;
281 Preds.first = ARMCC::GE;
282 break;
272283 case CmpInst::ICMP_UGT:
273284 case CmpInst::FCMP_UGT:
274 return ARMCC::HI;
285 Preds.first = ARMCC::HI;
286 break;
275287 case CmpInst::FCMP_OLT:
276 return ARMCC::MI;
288 Preds.first = ARMCC::MI;
289 break;
277290 case CmpInst::ICMP_ULE:
278291 case CmpInst::FCMP_OLE:
279 return ARMCC::LS;
292 Preds.first = ARMCC::LS;
293 break;
280294 case CmpInst::FCMP_ORD:
281 return ARMCC::VC;
295 Preds.first = ARMCC::VC;
296 break;
282297 case CmpInst::FCMP_UNO:
283 return ARMCC::VS;
298 Preds.first = ARMCC::VS;
299 break;
284300 case CmpInst::FCMP_UGE:
285 return ARMCC::PL;
301 Preds.first = ARMCC::PL;
302 break;
286303 case CmpInst::ICMP_SLT:
287304 case CmpInst::FCMP_ULT:
288 return ARMCC::LT;
305 Preds.first = ARMCC::LT;
306 break;
289307 case CmpInst::ICMP_SLE:
290308 case CmpInst::FCMP_ULE:
291 return ARMCC::LE;
309 Preds.first = ARMCC::LE;
310 break;
292311 case CmpInst::FCMP_UNE:
293312 case CmpInst::ICMP_NE:
294 return ARMCC::NE;
313 Preds.first = ARMCC::NE;
314 break;
295315 case CmpInst::ICMP_UGE:
296 return ARMCC::HS;
316 Preds.first = ARMCC::HS;
317 break;
297318 case CmpInst::ICMP_ULT:
298 return ARMCC::LO;
299 }
300 }
301
302 bool ARMInstructionSelector::selectICmp(MachineInstrBuilder &MIB,
303 const ARMBaseInstrInfo &TII,
304 MachineRegisterInfo &MRI,
305 const TargetRegisterInfo &TRI,
306 const RegisterBankInfo &RBI) const {
307 auto &MBB = *MIB->getParent();
308 auto InsertBefore = std::next(MIB->getIterator());
309 auto &DebugLoc = MIB->getDebugLoc();
310
311 // Move 0 into the result register.
312 auto Mov0I = BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ARM::MOVi))
313 .addDef(MRI.createVirtualRegister(&ARM::GPRRegClass))
314 .addImm(0)
315 .add(predOps(ARMCC::AL))
316 .add(condCodeOp());
317 if (!constrainSelectedInstRegOperands(*Mov0I, TII, TRI, RBI))
319 Preds.first = ARMCC::LO;
320 break;
321 default:
322 break;
323 }
324 assert(Preds.first != ARMCC::AL && "No comparisons needed?");
325 return Preds;
326 }
327
328 template struct ARMInstructionSelector::CmpHelper {
329 CmpHelper(const ARMInstructionSelector &Selector, MachineInstrBuilder &MIB,
330 const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI,
331 const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
332 : MBB(*MIB->getParent()), InsertBefore(std::next(MIB->getIterator())),
333 DebugLoc(MIB->getDebugLoc()), TII(TII), MRI(MRI), TRI(TRI), RBI(RBI),
334 Selector(Selector) {}
335
336 // The opcode used for performing the comparison.
337 static const unsigned ComparisonOpcode;
338
339 // The opcode used for reading the flags set by the comparison. May be
340 // ARM::INSTRUCTION_LIST_END if we don't need to read the flags.
341 static const unsigned ReadFlagsOpcode;
342
343 // The opcode used for selecting the result register, based on the value
344 // of the flags.
345 static const unsigned SetResultOpcode = ARM::MOVCCi;
346
347 // The assumed register bank ID for the operands.
348 static const unsigned OperandRegBankID;
349
350 // The assumed register bank ID for the result.
351 static const unsigned ResultRegBankID = ARM::GPRRegBankID;
352
353 unsigned getZeroRegister() {
354 unsigned Reg = MRI.createVirtualRegister(&ARM::GPRRegClass);
355 putConstant(Reg, 0);
356 return Reg;
357 }
358
359 void putConstant(unsigned DestReg, unsigned Constant) {
360 (void)BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ARM::MOVi))
361 .addDef(DestReg)
362 .addImm(Constant)
363 .add(predOps(ARMCC::AL))
364 .add(condCodeOp());
365 }
366
367 bool insertComparison(unsigned ResReg, ARMCC::CondCodes Cond, unsigned LHSReg,
368 unsigned RHSReg, unsigned PrevRes) {
369
370 // Perform the comparison.
371 auto CmpI = BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ComparisonOpcode))
372 .addUse(LHSReg)
373 .addUse(RHSReg)
374 .add(predOps(ARMCC::AL));
375 if (!Selector.constrainSelectedInstRegOperands(*CmpI, TII, TRI, RBI))
376 return false;
377
378 // Read the comparison flags (if necessary).
379 if (ReadFlagsOpcode != ARM::INSTRUCTION_LIST_END) {
380 auto ReadI =
381 BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ReadFlagsOpcode))
382 .add(predOps(ARMCC::AL));
383 if (!Selector.constrainSelectedInstRegOperands(*ReadI, TII, TRI, RBI))
384 return false;
385 }
386
387 // Select either 1 or the previous result based on the value of the flags.
388 auto Mov1I = BuildMI(MBB, InsertBefore, DebugLoc, TII.get(SetResultOpcode))
389 .addDef(ResReg)
390 .addUse(PrevRes)
391 .addImm(1)
392 .add(predOps(Cond, ARM::CPSR));
393 if (!Selector.constrainSelectedInstRegOperands(*Mov1I, TII, TRI, RBI))
394 return false;
395
396 return true;
397 }
398
399 bool validateOpRegs(unsigned LHSReg, unsigned RHSReg) {
400 return MRI.getType(LHSReg) == MRI.getType(RHSReg) &&
401 validateOpReg(LHSReg, MRI, TRI, RBI) &&
402 validateOpReg(RHSReg, MRI, TRI, RBI);
403 }
404
405 bool validateResReg(unsigned ResReg) {
406 if (MRI.getType(ResReg).getSizeInBits() != 1) {
407 DEBUG(dbgs() << "Unsupported size for comparison operand");
408 return false;
409 }
410
411 if (RBI.getRegBank(ResReg, MRI, TRI)->getID() != ResultRegBankID) {
412 DEBUG(dbgs() << "Unsupported register bank for comparison operand");
413 return false;
414 }
415
416 return true;
417 }
418
419 private:
420 bool validateOpReg(unsigned OpReg, MachineRegisterInfo &MRI,
421 const TargetRegisterInfo &TRI,
422 const RegisterBankInfo &RBI) {
423 if (MRI.getType(OpReg).getSizeInBits() != 32) {
424 DEBUG(dbgs() << "Unsupported size for comparison operand");
425 return false;
426 }
427
428 if (RBI.getRegBank(OpReg, MRI, TRI)->getID() != OperandRegBankID) {
429 DEBUG(dbgs() << "Unsupported register bank for comparison operand");
430 return false;
431 }
432
433 return true;
434 }
435
436 MachineBasicBlock &MBB;
437 MachineBasicBlock::instr_iterator InsertBefore;
438 const DebugLoc &DebugLoc;
439
440 const ARMBaseInstrInfo &TII;
441 MachineRegisterInfo &MRI;
442 const TargetRegisterInfo &TRI;
443 const RegisterBankInfo &RBI;
444
445 const ARMInstructionSelector &Selector;
446 };
447
448 // Specialize the opcode to be used for comparing different types of operands.
449 template <>
450 const unsigned ARMInstructionSelector::CmpHelper::ComparisonOpcode =
451 ARM::CMPrr;
452 template <>
453 const unsigned ARMInstructionSelector::CmpHelper::ComparisonOpcode =
454 ARM::VCMPS;
455
456 // Specialize the opcode to be used for reading the comparison flags for
457 // different types of operands.
458 template <>
459 const unsigned ARMInstructionSelector::CmpHelper::ReadFlagsOpcode =
460 ARM::INSTRUCTION_LIST_END;
461 template <>
462 const unsigned ARMInstructionSelector::CmpHelper::ReadFlagsOpcode =
463 ARM::FMSTAT;
464
465 // Specialize the register bank where the operands of the comparison are assumed
466 // to live.
467 template <>
468 const unsigned ARMInstructionSelector::CmpHelper::OperandRegBankID =
469 ARM::GPRRegBankID;
470 template <>
471 const unsigned ARMInstructionSelector::CmpHelper::OperandRegBankID =
472 ARM::FPRRegBankID;
473
474 template
475 bool ARMInstructionSelector::selectCmp(MachineInstrBuilder &MIB,
476 const ARMBaseInstrInfo &TII,
477 MachineRegisterInfo &MRI,
478 const TargetRegisterInfo &TRI,
479 const RegisterBankInfo &RBI) const {
480 auto Helper = CmpHelper(*this, MIB, TII, MRI, TRI, RBI);
481
482 auto ResReg = MIB->getOperand(0).getReg();
483 if (!Helper.validateResReg(ResReg))
318484 return false;
319485
320 // Perform the comparison.
486 auto Cond =
487 static_cast(MIB->getOperand(1).getPredicate());
488 if (Cond == CmpInst::FCMP_TRUE || Cond == CmpInst::FCMP_FALSE) {
489 Helper.putConstant(ResReg, Cond == CmpInst::FCMP_TRUE ? 1 : 0);
490 MIB->eraseFromParent();
491 return true;
492 }
493
321494 auto LHSReg = MIB->getOperand(2).getReg();
322495 auto RHSReg = MIB->getOperand(3).getReg();
323 assert(MRI.getType(LHSReg) == MRI.getType(RHSReg) &&
324 MRI.getType(LHSReg).getSizeInBits() == 32 &&
325 MRI.getType(RHSReg).getSizeInBits() == 32 &&
326 "Unsupported types for comparison operation");
327 auto CmpI = BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ARM::CMPrr))
328 .addUse(LHSReg)
329 .addUse(RHSReg)
330 .add(predOps(ARMCC::AL));
331 if (!constrainSelectedInstRegOperands(*CmpI, TII, TRI, RBI))
496 if (!Helper.validateOpRegs(LHSReg, RHSReg))
332497 return false;
333498
334 // Move 1 into the result register if the flags say so.
335 auto ResReg = MIB->getOperand(0).getReg();
336 auto Cond =
337 static_cast(MIB->getOperand(1).getPredicate());
338 auto ARMCond = getComparePred(Cond);
339 if (ARMCond == ARMCC::AL)
340 return false;
341
342 auto Mov1I = BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ARM::MOVCCi))
343 .addDef(ResReg)
344 .addUse(Mov0I->getOperand(0).getReg())
345 .addImm(1)
346 .add(predOps(ARMCond, ARM::CPSR));
347 if (!constrainSelectedInstRegOperands(*Mov1I, TII, TRI, RBI))
348 return false;
499 auto ARMConds = getComparePreds(Cond);
500 auto ZeroReg = Helper.getZeroRegister();
501
502 if (ARMConds.second == ARMCC::AL) {
503 // Simple case, we only need one comparison and we're done.
504 if (!Helper.insertComparison(ResReg, ARMConds.first, LHSReg, RHSReg,
505 ZeroReg))
506 return false;
507 } else {
508 // Not so simple, we need two successive comparisons.
509 auto IntermediateRes = MRI.createVirtualRegister(&ARM::GPRRegClass);
510 if (!Helper.insertComparison(IntermediateRes, ARMConds.first, LHSReg,
511 RHSReg, ZeroReg))
512 return false;
513 if (!Helper.insertComparison(ResReg, ARMConds.second, LHSReg, RHSReg,
514 IntermediateRes))
515 return false;
516 }
349517
350518 MIB->eraseFromParent();
351519 return true;
495663 I.setDesc(TII.get(COPY));
496664 return selectCopy(I, TII, MRI, TRI, RBI);
497665 }
498 case G_ICMP:
499 return selectICmp(MIB, TII, MRI, TRI, RBI);
500666 case G_SELECT:
501667 return selectSelect(MIB, TII, MRI, TRI, RBI);
668 case G_ICMP:
669 return selectCmp(MIB, TII, MRI, TRI, RBI);
670 case G_FCMP:
671 assert(TII.getSubtarget().hasVFP2() && "Can't select fcmp without VFP");
672 return selectCmp(MIB, TII, MRI, TRI, RBI);
502673 case G_GEP:
503674 I.setDesc(TII.get(ARM::ADDrr));
504675 MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
99 define void @test_icmp_sge_s32() { ret void }
1010 define void @test_icmp_slt_s32() { ret void }
1111 define void @test_icmp_sle_s32() { ret void }
12
13 define void @test_fcmp_true_s32() #0 { ret void }
14 define void @test_fcmp_false_s32() #0 { ret void }
15
16 define void @test_fcmp_oeq_s32() #0 { ret void }
17 define void @test_fcmp_ogt_s32() #0 { ret void }
18 define void @test_fcmp_oge_s32() #0 { ret void }
19 define void @test_fcmp_olt_s32() #0 { ret void }
20 define void @test_fcmp_ole_s32() #0 { ret void }
21 define void @test_fcmp_ord_s32() #0 { ret void }
22 define void @test_fcmp_ugt_s32() #0 { ret void }
23 define void @test_fcmp_uge_s32() #0 { ret void }
24 define void @test_fcmp_ult_s32() #0 { ret void }
25 define void @test_fcmp_ule_s32() #0 { ret void }
26 define void @test_fcmp_une_s32() #0 { ret void }
27 define void @test_fcmp_uno_s32() #0 { ret void }
28
29 define void @test_fcmp_one_s32() #0 { ret void }
30 define void @test_fcmp_ueq_s32() #0 { ret void }
31
32 attributes #0 = { "target-features"="+vfp2" }
1233 ...
1334 ---
1435 name: test_icmp_eq_s32
370391 BX_RET 14, _, implicit %r0
371392 ; CHECK: BX_RET 14, _, implicit %r0
372393 ...
394 ---
395 name: test_fcmp_true_s32
396 # CHECK-LABEL: name: test_fcmp_true_s32
397 legalized: true
398 regBankSelected: true
399 selected: false
400 # CHECK: selected: true
401 registers:
402 - { id: 0, class: fprb }
403 - { id: 1, class: fprb }
404 - { id: 2, class: gprb }
405 - { id: 3, class: gprb }
406 body: |
407 bb.0:
408 liveins: %s0, %s1
409
410 %0(s32) = COPY %s0
411 %1(s32) = COPY %s1
412
413 %2(s1) = G_FCMP floatpred(true), %0(s32), %1
414 ; CHECK: [[RES:%[0-9]+]] = MOVi 1, 14, _, _
415
416 %3(s32) = G_ZEXT %2(s1)
417 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
418
419 %r0 = COPY %3(s32)
420 ; CHECK: %r0 = COPY [[RET]]
421
422 BX_RET 14, _, implicit %r0
423 ; CHECK: BX_RET 14, _, implicit %r0
424 ...
425 ---
426 name: test_fcmp_false_s32
427 # CHECK-LABEL: name: test_fcmp_false_s32
428 legalized: true
429 regBankSelected: true
430 selected: false
431 # CHECK: selected: true
432 registers:
433 - { id: 0, class: fprb }
434 - { id: 1, class: fprb }
435 - { id: 2, class: gprb }
436 - { id: 3, class: gprb }
437 body: |
438 bb.0:
439 liveins: %s0, %s1
440
441 %0(s32) = COPY %s0
442 %1(s32) = COPY %s1
443
444 %2(s1) = G_FCMP floatpred(false), %0(s32), %1
445 ; CHECK: [[RES:%[0-9]+]] = MOVi 0, 14, _, _
446
447 %3(s32) = G_ZEXT %2(s1)
448 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
449
450 %r0 = COPY %3(s32)
451 ; CHECK: %r0 = COPY [[RET]]
452
453 BX_RET 14, _, implicit %r0
454 ; CHECK: BX_RET 14, _, implicit %r0
455 ...
456 ---
457 name: test_fcmp_oeq_s32
458 # CHECK-LABEL: name: test_fcmp_oeq_s32
459 legalized: true
460 regBankSelected: true
461 selected: false
462 # CHECK: selected: true
463 registers:
464 - { id: 0, class: fprb }
465 - { id: 1, class: fprb }
466 - { id: 2, class: gprb }
467 - { id: 3, class: gprb }
468 body: |
469 bb.0:
470 liveins: %s0, %s1
471
472 %0(s32) = COPY %s0
473 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
474
475 %1(s32) = COPY %s1
476 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
477
478 %2(s1) = G_FCMP floatpred(oeq), %0(s32), %1
479 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
480 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
481 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
482 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 0, %cpsr
483
484 %3(s32) = G_ZEXT %2(s1)
485 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
486
487 %r0 = COPY %3(s32)
488 ; CHECK: %r0 = COPY [[RET]]
489
490 BX_RET 14, _, implicit %r0
491 ; CHECK: BX_RET 14, _, implicit %r0
492 ...
493 ---
494 name: test_fcmp_ogt_s32
495 # CHECK-LABEL: name: test_fcmp_ogt_s32
496 legalized: true
497 regBankSelected: true
498 selected: false
499 # CHECK: selected: true
500 registers:
501 - { id: 0, class: fprb }
502 - { id: 1, class: fprb }
503 - { id: 2, class: gprb }
504 - { id: 3, class: gprb }
505 body: |
506 bb.0:
507 liveins: %s0, %s1
508
509 %0(s32) = COPY %s0
510 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
511
512 %1(s32) = COPY %s1
513 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
514
515 %2(s1) = G_FCMP floatpred(ogt), %0(s32), %1
516 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
517 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
518 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
519 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 12, %cpsr
520
521 %3(s32) = G_ZEXT %2(s1)
522 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
523
524 %r0 = COPY %3(s32)
525 ; CHECK: %r0 = COPY [[RET]]
526
527 BX_RET 14, _, implicit %r0
528 ; CHECK: BX_RET 14, _, implicit %r0
529 ...
530 ---
531 name: test_fcmp_oge_s32
532 # CHECK-LABEL: name: test_fcmp_oge_s32
533 legalized: true
534 regBankSelected: true
535 selected: false
536 # CHECK: selected: true
537 registers:
538 - { id: 0, class: fprb }
539 - { id: 1, class: fprb }
540 - { id: 2, class: gprb }
541 - { id: 3, class: gprb }
542 body: |
543 bb.0:
544 liveins: %s0, %s1
545
546 %0(s32) = COPY %s0
547 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
548
549 %1(s32) = COPY %s1
550 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
551
552 %2(s1) = G_FCMP floatpred(oge), %0(s32), %1
553 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
554 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
555 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
556 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 10, %cpsr
557
558 %3(s32) = G_ZEXT %2(s1)
559 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
560
561 %r0 = COPY %3(s32)
562 ; CHECK: %r0 = COPY [[RET]]
563
564 BX_RET 14, _, implicit %r0
565 ; CHECK: BX_RET 14, _, implicit %r0
566 ...
567 ---
568 name: test_fcmp_olt_s32
569 # CHECK-LABEL: name: test_fcmp_olt_s32
570 legalized: true
571 regBankSelected: true
572 selected: false
573 # CHECK: selected: true
574 registers:
575 - { id: 0, class: fprb }
576 - { id: 1, class: fprb }
577 - { id: 2, class: gprb }
578 - { id: 3, class: gprb }
579 body: |
580 bb.0:
581 liveins: %s0, %s1
582
583 %0(s32) = COPY %s0
584 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
585
586 %1(s32) = COPY %s1
587 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
588
589 %2(s1) = G_FCMP floatpred(olt), %0(s32), %1
590 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
591 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
592 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
593 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 4, %cpsr
594
595 %3(s32) = G_ZEXT %2(s1)
596 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
597
598 %r0 = COPY %3(s32)
599 ; CHECK: %r0 = COPY [[RET]]
600
601 BX_RET 14, _, implicit %r0
602 ; CHECK: BX_RET 14, _, implicit %r0
603 ...
604 ---
605 name: test_fcmp_ole_s32
606 # CHECK-LABEL: name: test_fcmp_ole_s32
607 legalized: true
608 regBankSelected: true
609 selected: false
610 # CHECK: selected: true
611 registers:
612 - { id: 0, class: fprb }
613 - { id: 1, class: fprb }
614 - { id: 2, class: gprb }
615 - { id: 3, class: gprb }
616 body: |
617 bb.0:
618 liveins: %s0, %s1
619
620 %0(s32) = COPY %s0
621 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
622
623 %1(s32) = COPY %s1
624 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
625
626 %2(s1) = G_FCMP floatpred(ole), %0(s32), %1
627 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
628 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
629 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
630 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 9, %cpsr
631
632 %3(s32) = G_ZEXT %2(s1)
633 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
634
635 %r0 = COPY %3(s32)
636 ; CHECK: %r0 = COPY [[RET]]
637
638 BX_RET 14, _, implicit %r0
639 ; CHECK: BX_RET 14, _, implicit %r0
640 ...
641 ---
642 name: test_fcmp_ord_s32
643 # CHECK-LABEL: name: test_fcmp_ord_s32
644 legalized: true
645 regBankSelected: true
646 selected: false
647 # CHECK: selected: true
648 registers:
649 - { id: 0, class: fprb }
650 - { id: 1, class: fprb }
651 - { id: 2, class: gprb }
652 - { id: 3, class: gprb }
653 body: |
654 bb.0:
655 liveins: %s0, %s1
656
657 %0(s32) = COPY %s0
658 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
659
660 %1(s32) = COPY %s1
661 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
662
663 %2(s1) = G_FCMP floatpred(ord), %0(s32), %1
664 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
665 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
666 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
667 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 7, %cpsr
668
669 %3(s32) = G_ZEXT %2(s1)
670 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
671
672 %r0 = COPY %3(s32)
673 ; CHECK: %r0 = COPY [[RET]]
674
675 BX_RET 14, _, implicit %r0
676 ; CHECK: BX_RET 14, _, implicit %r0
677 ...
678 ---
679 name: test_fcmp_ugt_s32
680 # CHECK-LABEL: name: test_fcmp_ugt_s32
681 legalized: true
682 regBankSelected: true
683 selected: false
684 # CHECK: selected: true
685 registers:
686 - { id: 0, class: fprb }
687 - { id: 1, class: fprb }
688 - { id: 2, class: gprb }
689 - { id: 3, class: gprb }
690 body: |
691 bb.0:
692 liveins: %s0, %s1
693
694 %0(s32) = COPY %s0
695 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
696
697 %1(s32) = COPY %s1
698 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
699
700 %2(s1) = G_FCMP floatpred(ugt), %0(s32), %1
701 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
702 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
703 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
704 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 8, %cpsr
705
706 %3(s32) = G_ZEXT %2(s1)
707 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
708
709 %r0 = COPY %3(s32)
710 ; CHECK: %r0 = COPY [[RET]]
711
712 BX_RET 14, _, implicit %r0
713 ; CHECK: BX_RET 14, _, implicit %r0
714 ...
715 ---
716 name: test_fcmp_uge_s32
717 # CHECK-LABEL: name: test_fcmp_uge_s32
718 legalized: true
719 regBankSelected: true
720 selected: false
721 # CHECK: selected: true
722 registers:
723 - { id: 0, class: fprb }
724 - { id: 1, class: fprb }
725 - { id: 2, class: gprb }
726 - { id: 3, class: gprb }
727 body: |
728 bb.0:
729 liveins: %s0, %s1
730
731 %0(s32) = COPY %s0
732 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
733
734 %1(s32) = COPY %s1
735 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
736
737 %2(s1) = G_FCMP floatpred(uge), %0(s32), %1
738 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
739 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
740 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
741 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 5, %cpsr
742
743 %3(s32) = G_ZEXT %2(s1)
744 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
745
746 %r0 = COPY %3(s32)
747 ; CHECK: %r0 = COPY [[RET]]
748
749 BX_RET 14, _, implicit %r0
750 ; CHECK: BX_RET 14, _, implicit %r0
751 ...
752 ---
753 name: test_fcmp_ult_s32
754 # CHECK-LABEL: name: test_fcmp_ult_s32
755 legalized: true
756 regBankSelected: true
757 selected: false
758 # CHECK: selected: true
759 registers:
760 - { id: 0, class: fprb }
761 - { id: 1, class: fprb }
762 - { id: 2, class: gprb }
763 - { id: 3, class: gprb }
764 body: |
765 bb.0:
766 liveins: %s0, %s1
767
768 %0(s32) = COPY %s0
769 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
770
771 %1(s32) = COPY %s1
772 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
773
774 %2(s1) = G_FCMP floatpred(ult), %0(s32), %1
775 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
776 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
777 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
778 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 11, %cpsr
779
780 %3(s32) = G_ZEXT %2(s1)
781 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
782
783 %r0 = COPY %3(s32)
784 ; CHECK: %r0 = COPY [[RET]]
785
786 BX_RET 14, _, implicit %r0
787 ; CHECK: BX_RET 14, _, implicit %r0
788 ...
789 ---
790 name: test_fcmp_ule_s32
791 # CHECK-LABEL: name: test_fcmp_ule_s32
792 legalized: true
793 regBankSelected: true
794 selected: false
795 # CHECK: selected: true
796 registers:
797 - { id: 0, class: fprb }
798 - { id: 1, class: fprb }
799 - { id: 2, class: gprb }
800 - { id: 3, class: gprb }
801 body: |
802 bb.0:
803 liveins: %s0, %s1
804
805 %0(s32) = COPY %s0
806 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
807
808 %1(s32) = COPY %s1
809 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
810
811 %2(s1) = G_FCMP floatpred(ule), %0(s32), %1
812 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
813 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
814 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
815 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 13, %cpsr
816
817 %3(s32) = G_ZEXT %2(s1)
818 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
819
820 %r0 = COPY %3(s32)
821 ; CHECK: %r0 = COPY [[RET]]
822
823 BX_RET 14, _, implicit %r0
824 ; CHECK: BX_RET 14, _, implicit %r0
825 ...
826 ---
827 name: test_fcmp_une_s32
828 # CHECK-LABEL: name: test_fcmp_une_s32
829 legalized: true
830 regBankSelected: true
831 selected: false
832 # CHECK: selected: true
833 registers:
834 - { id: 0, class: fprb }
835 - { id: 1, class: fprb }
836 - { id: 2, class: gprb }
837 - { id: 3, class: gprb }
838 body: |
839 bb.0:
840 liveins: %s0, %s1
841
842 %0(s32) = COPY %s0
843 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
844
845 %1(s32) = COPY %s1
846 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
847
848 %2(s1) = G_FCMP floatpred(une), %0(s32), %1
849 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
850 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
851 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
852 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 1, %cpsr
853
854 %3(s32) = G_ZEXT %2(s1)
855 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
856
857 %r0 = COPY %3(s32)
858 ; CHECK: %r0 = COPY [[RET]]
859
860 BX_RET 14, _, implicit %r0
861 ; CHECK: BX_RET 14, _, implicit %r0
862 ...
863 ---
864 name: test_fcmp_uno_s32
865 # CHECK-LABEL: name: test_fcmp_uno_s32
866 legalized: true
867 regBankSelected: true
868 selected: false
869 # CHECK: selected: true
870 registers:
871 - { id: 0, class: fprb }
872 - { id: 1, class: fprb }
873 - { id: 2, class: gprb }
874 - { id: 3, class: gprb }
875 body: |
876 bb.0:
877 liveins: %s0, %s1
878
879 %0(s32) = COPY %s0
880 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
881
882 %1(s32) = COPY %s1
883 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
884
885 %2(s1) = G_FCMP floatpred(uno), %0(s32), %1
886 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
887 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
888 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
889 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 6, %cpsr
890
891 %3(s32) = G_ZEXT %2(s1)
892 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
893
894 %r0 = COPY %3(s32)
895 ; CHECK: %r0 = COPY [[RET]]
896
897 BX_RET 14, _, implicit %r0
898 ; CHECK: BX_RET 14, _, implicit %r0
899 ...
900 ---
901 name: test_fcmp_one_s32
902 # CHECK-LABEL: name: test_fcmp_one_s32
903 legalized: true
904 regBankSelected: true
905 selected: false
906 # CHECK: selected: true
907 registers:
908 - { id: 0, class: fprb }
909 - { id: 1, class: fprb }
910 - { id: 2, class: gprb }
911 - { id: 3, class: gprb }
912 body: |
913 bb.0:
914 liveins: %s0, %s1
915
916 %0(s32) = COPY %s0
917 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
918
919 %1(s32) = COPY %s1
920 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
921
922 %2(s1) = G_FCMP floatpred(one), %0(s32), %1
923 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
924 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
925 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
926 ; CHECK: [[RES1:%[0-9]+]] = MOVCCi [[ZERO]], 1, 12, %cpsr
927 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
928 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
929 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[RES1]], 1, 4, %cpsr
930
931 %3(s32) = G_ZEXT %2(s1)
932 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
933
934 %r0 = COPY %3(s32)
935 ; CHECK: %r0 = COPY [[RET]]
936
937 BX_RET 14, _, implicit %r0
938 ; CHECK: BX_RET 14, _, implicit %r0
939 ...
940 ---
941 name: test_fcmp_ueq_s32
942 # CHECK-LABEL: name: test_fcmp_ueq_s32
943 legalized: true
944 regBankSelected: true
945 selected: false
946 # CHECK: selected: true
947 registers:
948 - { id: 0, class: fprb }
949 - { id: 1, class: fprb }
950 - { id: 2, class: gprb }
951 - { id: 3, class: gprb }
952 body: |
953 bb.0:
954 liveins: %s0, %s1
955
956 %0(s32) = COPY %s0
957 ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
958
959 %1(s32) = COPY %s1
960 ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
961
962 %2(s1) = G_FCMP floatpred(ueq), %0(s32), %1
963 ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
964 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
965 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
966 ; CHECK: [[RES1:%[0-9]+]] = MOVCCi [[ZERO]], 1, 0, %cpsr
967 ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
968 ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
969 ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[RES1]], 1, 6, %cpsr
970
971 %3(s32) = G_ZEXT %2(s1)
972 ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
973
974 %r0 = COPY %3(s32)
975 ; CHECK: %r0 = COPY [[RET]]
976
977 BX_RET 14, _, implicit %r0
978 ; CHECK: BX_RET 14, _, implicit %r0
979 ...
4848 %r = fadd double %x, %y
4949 ret double %r
5050 }
51
52 define arm_aapcs_vfpcc i32 @test_cmp_float_ogt(float %x, float %y) {
53 ; CHECK-LABEL: test_cmp_float_ogt
54 ; HARD: vcmp.f32
55 ; HARD: vmrs APSR_nzcv, fpscr
56 ; HARD-NEXT: movgt
57 ; SOFT-AEABI: blx __aeabi_fcmpgt
58 ; SOFT-DEFAULT: blx __gtsf2
59 entry:
60 %v = fcmp ogt float %x, %y
61 %r = zext i1 %v to i32
62 ret i32 %r
63 }
64
65 define arm_aapcs_vfpcc i32 @test_cmp_float_one(float %x, float %y) {
66 ; CHECK-LABEL: test_cmp_float_one
67 ; HARD: vcmp.f32
68 ; HARD: vmrs APSR_nzcv, fpscr
69 ; HARD: movgt
70 ; HARD-NOT: vcmp
71 ; HARD: movmi
72 ; SOFT-AEABI-DAG: blx __aeabi_fcmpgt
73 ; SOFT-AEABI-DAG: blx __aeabi_fcmplt
74 ; SOFT-DEFAULT-DAG: blx __gtsf2
75 ; SOFT-DEFAULT-DAG: blx __ltsf2
76 entry:
77 %v = fcmp one float %x, %y
78 %r = zext i1 %v to i32
79 ret i32 %r
80 }