forked from OSchip/llvm-project
ARM: Fix cmpxchg O0 expansion
This is the equivalent of r304048 for ARM:
- Rewrite livein calculation to use the computeLiveIns() helper
function. This is slightly less efficient but easier to reason about
and doesn't unnecessarily add pristine and reserved registers[1]
- Zero the status register at the beginning of the loop to make sure it
has a defined value.
- Remove kill flags of values that need to stay alive throughout the loop.
[1] An upcoming commit of mine will tighten the MachineVerifier to catch
these.
llvm-svn: 304267
This commit is contained in:
parent
0dba4e3509
commit
05eeadbfd1
|
|
@ -757,14 +757,9 @@ void ARMExpandPseudo::ExpandMOV32BitImm(MachineBasicBlock &MBB,
|
||||||
MI.eraseFromParent();
|
MI.eraseFromParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addPostLoopLiveIns(MachineBasicBlock *MBB, LivePhysRegs &LiveRegs) {
|
|
||||||
for (auto I = LiveRegs.begin(); I != LiveRegs.end(); ++I)
|
|
||||||
MBB->addLiveIn(*I);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Expand a CMP_SWAP pseudo-inst to an ldrex/strex loop as simply as
|
/// Expand a CMP_SWAP pseudo-inst to an ldrex/strex loop as simply as
|
||||||
/// possible. This only gets used at -O0 so we don't care about efficiency of the
|
/// possible. This only gets used at -O0 so we don't care about efficiency of
|
||||||
/// generated code.
|
/// the generated code.
|
||||||
bool ARMExpandPseudo::ExpandCMP_SWAP(MachineBasicBlock &MBB,
|
bool ARMExpandPseudo::ExpandCMP_SWAP(MachineBasicBlock &MBB,
|
||||||
MachineBasicBlock::iterator MBBI,
|
MachineBasicBlock::iterator MBBI,
|
||||||
unsigned LdrexOp, unsigned StrexOp,
|
unsigned LdrexOp, unsigned StrexOp,
|
||||||
|
|
@ -773,16 +768,15 @@ bool ARMExpandPseudo::ExpandCMP_SWAP(MachineBasicBlock &MBB,
|
||||||
bool IsThumb = STI->isThumb();
|
bool IsThumb = STI->isThumb();
|
||||||
MachineInstr &MI = *MBBI;
|
MachineInstr &MI = *MBBI;
|
||||||
DebugLoc DL = MI.getDebugLoc();
|
DebugLoc DL = MI.getDebugLoc();
|
||||||
MachineOperand &Dest = MI.getOperand(0);
|
const MachineOperand &Dest = MI.getOperand(0);
|
||||||
unsigned StatusReg = MI.getOperand(1).getReg();
|
unsigned StatusReg = MI.getOperand(1).getReg();
|
||||||
MachineOperand &Addr = MI.getOperand(2);
|
bool StatusDead = MI.getOperand(1).isDead();
|
||||||
MachineOperand &Desired = MI.getOperand(3);
|
// Duplicating undef operands into 2 instructions does not guarantee the same
|
||||||
MachineOperand &New = MI.getOperand(4);
|
// value on both; However undef should be replaced by xzr anyway.
|
||||||
|
assert(!MI.getOperand(2).isUndef() && "cannot handle undef");
|
||||||
LivePhysRegs LiveRegs(TII->getRegisterInfo());
|
unsigned AddrReg = MI.getOperand(2).getReg();
|
||||||
LiveRegs.addLiveOuts(MBB);
|
unsigned DesiredReg = MI.getOperand(3).getReg();
|
||||||
for (auto I = std::prev(MBB.end()); I != MBBI; --I)
|
unsigned NewReg = MI.getOperand(4).getReg();
|
||||||
LiveRegs.stepBackward(*I);
|
|
||||||
|
|
||||||
MachineFunction *MF = MBB.getParent();
|
MachineFunction *MF = MBB.getParent();
|
||||||
auto LoadCmpBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
|
auto LoadCmpBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
|
||||||
|
|
@ -795,25 +789,35 @@ bool ARMExpandPseudo::ExpandCMP_SWAP(MachineBasicBlock &MBB,
|
||||||
|
|
||||||
if (UxtOp) {
|
if (UxtOp) {
|
||||||
MachineInstrBuilder MIB =
|
MachineInstrBuilder MIB =
|
||||||
BuildMI(MBB, MBBI, DL, TII->get(UxtOp), Desired.getReg())
|
BuildMI(MBB, MBBI, DL, TII->get(UxtOp), DesiredReg)
|
||||||
.addReg(Desired.getReg(), RegState::Kill);
|
.addReg(DesiredReg, RegState::Kill);
|
||||||
if (!IsThumb)
|
if (!IsThumb)
|
||||||
MIB.addImm(0);
|
MIB.addImm(0);
|
||||||
MIB.add(predOps(ARMCC::AL));
|
MIB.add(predOps(ARMCC::AL));
|
||||||
}
|
}
|
||||||
|
|
||||||
// .Lloadcmp:
|
// .Lloadcmp:
|
||||||
|
// mov wStatus, #0
|
||||||
// ldrex rDest, [rAddr]
|
// ldrex rDest, [rAddr]
|
||||||
// cmp rDest, rDesired
|
// cmp rDest, rDesired
|
||||||
// bne .Ldone
|
// bne .Ldone
|
||||||
LoadCmpBB->addLiveIn(Addr.getReg());
|
if (!StatusDead) {
|
||||||
LoadCmpBB->addLiveIn(Dest.getReg());
|
if (IsThumb) {
|
||||||
LoadCmpBB->addLiveIn(Desired.getReg());
|
BuildMI(LoadCmpBB, DL, TII->get(ARM::tMOVi8), StatusReg)
|
||||||
addPostLoopLiveIns(LoadCmpBB, LiveRegs);
|
.addDef(ARM::CPSR, RegState::Dead)
|
||||||
|
.addImm(0)
|
||||||
|
.add(predOps(ARMCC::AL));
|
||||||
|
} else {
|
||||||
|
BuildMI(LoadCmpBB, DL, TII->get(ARM::MOVi), StatusReg)
|
||||||
|
.addImm(0)
|
||||||
|
.add(predOps(ARMCC::AL))
|
||||||
|
.add(condCodeOp());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MachineInstrBuilder MIB;
|
MachineInstrBuilder MIB;
|
||||||
MIB = BuildMI(LoadCmpBB, DL, TII->get(LdrexOp), Dest.getReg());
|
MIB = BuildMI(LoadCmpBB, DL, TII->get(LdrexOp), Dest.getReg());
|
||||||
MIB.addReg(Addr.getReg());
|
MIB.addReg(AddrReg);
|
||||||
if (LdrexOp == ARM::t2LDREX)
|
if (LdrexOp == ARM::t2LDREX)
|
||||||
MIB.addImm(0); // a 32-bit Thumb ldrex (only) allows an offset.
|
MIB.addImm(0); // a 32-bit Thumb ldrex (only) allows an offset.
|
||||||
MIB.add(predOps(ARMCC::AL));
|
MIB.add(predOps(ARMCC::AL));
|
||||||
|
|
@ -821,7 +825,7 @@ bool ARMExpandPseudo::ExpandCMP_SWAP(MachineBasicBlock &MBB,
|
||||||
unsigned CMPrr = IsThumb ? ARM::tCMPhir : ARM::CMPrr;
|
unsigned CMPrr = IsThumb ? ARM::tCMPhir : ARM::CMPrr;
|
||||||
BuildMI(LoadCmpBB, DL, TII->get(CMPrr))
|
BuildMI(LoadCmpBB, DL, TII->get(CMPrr))
|
||||||
.addReg(Dest.getReg(), getKillRegState(Dest.isDead()))
|
.addReg(Dest.getReg(), getKillRegState(Dest.isDead()))
|
||||||
.add(Desired)
|
.addReg(DesiredReg)
|
||||||
.add(predOps(ARMCC::AL));
|
.add(predOps(ARMCC::AL));
|
||||||
unsigned Bcc = IsThumb ? ARM::tBcc : ARM::Bcc;
|
unsigned Bcc = IsThumb ? ARM::tBcc : ARM::Bcc;
|
||||||
BuildMI(LoadCmpBB, DL, TII->get(Bcc))
|
BuildMI(LoadCmpBB, DL, TII->get(Bcc))
|
||||||
|
|
@ -835,21 +839,16 @@ bool ARMExpandPseudo::ExpandCMP_SWAP(MachineBasicBlock &MBB,
|
||||||
// strex rStatus, rNew, [rAddr]
|
// strex rStatus, rNew, [rAddr]
|
||||||
// cmp rStatus, #0
|
// cmp rStatus, #0
|
||||||
// bne .Lloadcmp
|
// bne .Lloadcmp
|
||||||
StoreBB->addLiveIn(Addr.getReg());
|
MIB = BuildMI(StoreBB, DL, TII->get(StrexOp), StatusReg)
|
||||||
StoreBB->addLiveIn(New.getReg());
|
.addReg(NewReg)
|
||||||
addPostLoopLiveIns(StoreBB, LiveRegs);
|
.addReg(AddrReg);
|
||||||
|
|
||||||
|
|
||||||
MIB = BuildMI(StoreBB, DL, TII->get(StrexOp), StatusReg);
|
|
||||||
MIB.add(New);
|
|
||||||
MIB.add(Addr);
|
|
||||||
if (StrexOp == ARM::t2STREX)
|
if (StrexOp == ARM::t2STREX)
|
||||||
MIB.addImm(0); // a 32-bit Thumb strex (only) allows an offset.
|
MIB.addImm(0); // a 32-bit Thumb strex (only) allows an offset.
|
||||||
MIB.add(predOps(ARMCC::AL));
|
MIB.add(predOps(ARMCC::AL));
|
||||||
|
|
||||||
unsigned CMPri = IsThumb ? ARM::t2CMPri : ARM::CMPri;
|
unsigned CMPri = IsThumb ? ARM::t2CMPri : ARM::CMPri;
|
||||||
BuildMI(StoreBB, DL, TII->get(CMPri))
|
BuildMI(StoreBB, DL, TII->get(CMPri))
|
||||||
.addReg(StatusReg, RegState::Kill)
|
.addReg(StatusReg, getKillRegState(StatusDead))
|
||||||
.addImm(0)
|
.addImm(0)
|
||||||
.add(predOps(ARMCC::AL));
|
.add(predOps(ARMCC::AL));
|
||||||
BuildMI(StoreBB, DL, TII->get(Bcc))
|
BuildMI(StoreBB, DL, TII->get(Bcc))
|
||||||
|
|
@ -861,12 +860,24 @@ bool ARMExpandPseudo::ExpandCMP_SWAP(MachineBasicBlock &MBB,
|
||||||
|
|
||||||
DoneBB->splice(DoneBB->end(), &MBB, MI, MBB.end());
|
DoneBB->splice(DoneBB->end(), &MBB, MI, MBB.end());
|
||||||
DoneBB->transferSuccessors(&MBB);
|
DoneBB->transferSuccessors(&MBB);
|
||||||
addPostLoopLiveIns(DoneBB, LiveRegs);
|
|
||||||
|
|
||||||
MBB.addSuccessor(LoadCmpBB);
|
MBB.addSuccessor(LoadCmpBB);
|
||||||
|
|
||||||
NextMBBI = MBB.end();
|
NextMBBI = MBB.end();
|
||||||
MI.eraseFromParent();
|
MI.eraseFromParent();
|
||||||
|
|
||||||
|
// Recompute livein lists.
|
||||||
|
const MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
|
||||||
|
LivePhysRegs LiveRegs;
|
||||||
|
computeLiveIns(LiveRegs, MRI, *DoneBB);
|
||||||
|
computeLiveIns(LiveRegs, MRI, *StoreBB);
|
||||||
|
computeLiveIns(LiveRegs, MRI, *LoadCmpBB);
|
||||||
|
// Do an extra pass around the loop to get loop carried registers right.
|
||||||
|
StoreBB->clearLiveIns();
|
||||||
|
computeLiveIns(LiveRegs, MRI, *StoreBB);
|
||||||
|
LoadCmpBB->clearLiveIns();
|
||||||
|
computeLiveIns(LiveRegs, MRI, *LoadCmpBB);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -894,19 +905,19 @@ bool ARMExpandPseudo::ExpandCMP_SWAP_64(MachineBasicBlock &MBB,
|
||||||
DebugLoc DL = MI.getDebugLoc();
|
DebugLoc DL = MI.getDebugLoc();
|
||||||
MachineOperand &Dest = MI.getOperand(0);
|
MachineOperand &Dest = MI.getOperand(0);
|
||||||
unsigned StatusReg = MI.getOperand(1).getReg();
|
unsigned StatusReg = MI.getOperand(1).getReg();
|
||||||
MachineOperand &Addr = MI.getOperand(2);
|
bool StatusDead = MI.getOperand(1).isDead();
|
||||||
MachineOperand &Desired = MI.getOperand(3);
|
// Duplicating undef operands into 2 instructions does not guarantee the same
|
||||||
MachineOperand &New = MI.getOperand(4);
|
// value on both; However undef should be replaced by xzr anyway.
|
||||||
|
assert(!MI.getOperand(2).isUndef() && "cannot handle undef");
|
||||||
|
unsigned AddrReg = MI.getOperand(2).getReg();
|
||||||
|
unsigned DesiredReg = MI.getOperand(3).getReg();
|
||||||
|
MachineOperand New = MI.getOperand(4);
|
||||||
|
New.setIsKill(false);
|
||||||
|
|
||||||
unsigned DestLo = TRI->getSubReg(Dest.getReg(), ARM::gsub_0);
|
unsigned DestLo = TRI->getSubReg(Dest.getReg(), ARM::gsub_0);
|
||||||
unsigned DestHi = TRI->getSubReg(Dest.getReg(), ARM::gsub_1);
|
unsigned DestHi = TRI->getSubReg(Dest.getReg(), ARM::gsub_1);
|
||||||
unsigned DesiredLo = TRI->getSubReg(Desired.getReg(), ARM::gsub_0);
|
unsigned DesiredLo = TRI->getSubReg(DesiredReg, ARM::gsub_0);
|
||||||
unsigned DesiredHi = TRI->getSubReg(Desired.getReg(), ARM::gsub_1);
|
unsigned DesiredHi = TRI->getSubReg(DesiredReg, ARM::gsub_1);
|
||||||
|
|
||||||
LivePhysRegs LiveRegs(TII->getRegisterInfo());
|
|
||||||
LiveRegs.addLiveOuts(MBB);
|
|
||||||
for (auto I = std::prev(MBB.end()); I != MBBI; --I)
|
|
||||||
LiveRegs.stepBackward(*I);
|
|
||||||
|
|
||||||
MachineFunction *MF = MBB.getParent();
|
MachineFunction *MF = MBB.getParent();
|
||||||
auto LoadCmpBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
|
auto LoadCmpBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
|
||||||
|
|
@ -922,26 +933,21 @@ bool ARMExpandPseudo::ExpandCMP_SWAP_64(MachineBasicBlock &MBB,
|
||||||
// cmp rDestLo, rDesiredLo
|
// cmp rDestLo, rDesiredLo
|
||||||
// sbcs rStatus<dead>, rDestHi, rDesiredHi
|
// sbcs rStatus<dead>, rDestHi, rDesiredHi
|
||||||
// bne .Ldone
|
// bne .Ldone
|
||||||
LoadCmpBB->addLiveIn(Addr.getReg());
|
|
||||||
LoadCmpBB->addLiveIn(Dest.getReg());
|
|
||||||
LoadCmpBB->addLiveIn(Desired.getReg());
|
|
||||||
addPostLoopLiveIns(LoadCmpBB, LiveRegs);
|
|
||||||
|
|
||||||
unsigned LDREXD = IsThumb ? ARM::t2LDREXD : ARM::LDREXD;
|
unsigned LDREXD = IsThumb ? ARM::t2LDREXD : ARM::LDREXD;
|
||||||
MachineInstrBuilder MIB;
|
MachineInstrBuilder MIB;
|
||||||
MIB = BuildMI(LoadCmpBB, DL, TII->get(LDREXD));
|
MIB = BuildMI(LoadCmpBB, DL, TII->get(LDREXD));
|
||||||
addExclusiveRegPair(MIB, Dest, RegState::Define, IsThumb, TRI);
|
addExclusiveRegPair(MIB, Dest, RegState::Define, IsThumb, TRI);
|
||||||
MIB.addReg(Addr.getReg()).add(predOps(ARMCC::AL));
|
MIB.addReg(AddrReg).add(predOps(ARMCC::AL));
|
||||||
|
|
||||||
unsigned CMPrr = IsThumb ? ARM::tCMPhir : ARM::CMPrr;
|
unsigned CMPrr = IsThumb ? ARM::tCMPhir : ARM::CMPrr;
|
||||||
BuildMI(LoadCmpBB, DL, TII->get(CMPrr))
|
BuildMI(LoadCmpBB, DL, TII->get(CMPrr))
|
||||||
.addReg(DestLo, getKillRegState(Dest.isDead()))
|
.addReg(DestLo, getKillRegState(Dest.isDead()))
|
||||||
.addReg(DesiredLo, getKillRegState(Desired.isDead()))
|
.addReg(DesiredLo)
|
||||||
.add(predOps(ARMCC::AL));
|
.add(predOps(ARMCC::AL));
|
||||||
|
|
||||||
BuildMI(LoadCmpBB, DL, TII->get(CMPrr))
|
BuildMI(LoadCmpBB, DL, TII->get(CMPrr))
|
||||||
.addReg(DestHi, getKillRegState(Dest.isDead()))
|
.addReg(DestHi, getKillRegState(Dest.isDead()))
|
||||||
.addReg(DesiredHi, getKillRegState(Desired.isDead()))
|
.addReg(DesiredHi)
|
||||||
.addImm(ARMCC::EQ).addReg(ARM::CPSR, RegState::Kill);
|
.addImm(ARMCC::EQ).addReg(ARM::CPSR, RegState::Kill);
|
||||||
|
|
||||||
unsigned Bcc = IsThumb ? ARM::tBcc : ARM::Bcc;
|
unsigned Bcc = IsThumb ? ARM::tBcc : ARM::Bcc;
|
||||||
|
|
@ -956,18 +962,14 @@ bool ARMExpandPseudo::ExpandCMP_SWAP_64(MachineBasicBlock &MBB,
|
||||||
// strexd rStatus, rNewLo, rNewHi, [rAddr]
|
// strexd rStatus, rNewLo, rNewHi, [rAddr]
|
||||||
// cmp rStatus, #0
|
// cmp rStatus, #0
|
||||||
// bne .Lloadcmp
|
// bne .Lloadcmp
|
||||||
StoreBB->addLiveIn(Addr.getReg());
|
|
||||||
StoreBB->addLiveIn(New.getReg());
|
|
||||||
addPostLoopLiveIns(StoreBB, LiveRegs);
|
|
||||||
|
|
||||||
unsigned STREXD = IsThumb ? ARM::t2STREXD : ARM::STREXD;
|
unsigned STREXD = IsThumb ? ARM::t2STREXD : ARM::STREXD;
|
||||||
MIB = BuildMI(StoreBB, DL, TII->get(STREXD), StatusReg);
|
MIB = BuildMI(StoreBB, DL, TII->get(STREXD), StatusReg);
|
||||||
addExclusiveRegPair(MIB, New, 0, IsThumb, TRI);
|
addExclusiveRegPair(MIB, New, 0, IsThumb, TRI);
|
||||||
MIB.add(Addr).add(predOps(ARMCC::AL));
|
MIB.addReg(AddrReg).add(predOps(ARMCC::AL));
|
||||||
|
|
||||||
unsigned CMPri = IsThumb ? ARM::t2CMPri : ARM::CMPri;
|
unsigned CMPri = IsThumb ? ARM::t2CMPri : ARM::CMPri;
|
||||||
BuildMI(StoreBB, DL, TII->get(CMPri))
|
BuildMI(StoreBB, DL, TII->get(CMPri))
|
||||||
.addReg(StatusReg, RegState::Kill)
|
.addReg(StatusReg, getKillRegState(StatusDead))
|
||||||
.addImm(0)
|
.addImm(0)
|
||||||
.add(predOps(ARMCC::AL));
|
.add(predOps(ARMCC::AL));
|
||||||
BuildMI(StoreBB, DL, TII->get(Bcc))
|
BuildMI(StoreBB, DL, TII->get(Bcc))
|
||||||
|
|
@ -979,12 +981,24 @@ bool ARMExpandPseudo::ExpandCMP_SWAP_64(MachineBasicBlock &MBB,
|
||||||
|
|
||||||
DoneBB->splice(DoneBB->end(), &MBB, MI, MBB.end());
|
DoneBB->splice(DoneBB->end(), &MBB, MI, MBB.end());
|
||||||
DoneBB->transferSuccessors(&MBB);
|
DoneBB->transferSuccessors(&MBB);
|
||||||
addPostLoopLiveIns(DoneBB, LiveRegs);
|
|
||||||
|
|
||||||
MBB.addSuccessor(LoadCmpBB);
|
MBB.addSuccessor(LoadCmpBB);
|
||||||
|
|
||||||
NextMBBI = MBB.end();
|
NextMBBI = MBB.end();
|
||||||
MI.eraseFromParent();
|
MI.eraseFromParent();
|
||||||
|
|
||||||
|
// Recompute livein lists.
|
||||||
|
const MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
|
||||||
|
LivePhysRegs LiveRegs;
|
||||||
|
computeLiveIns(LiveRegs, MRI, *DoneBB);
|
||||||
|
computeLiveIns(LiveRegs, MRI, *StoreBB);
|
||||||
|
computeLiveIns(LiveRegs, MRI, *LoadCmpBB);
|
||||||
|
// Do an extra pass around the loop to get loop carried registers right.
|
||||||
|
StoreBB->clearLiveIns();
|
||||||
|
computeLiveIns(LiveRegs, MRI, *StoreBB);
|
||||||
|
LoadCmpBB->clearLiveIns();
|
||||||
|
computeLiveIns(LiveRegs, MRI, *LoadCmpBB);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,11 @@ define { i8, i1 } @test_cmpxchg_8(i8* %addr, i8 %desired, i8 %new) nounwind {
|
||||||
; CHECK: dmb ish
|
; CHECK: dmb ish
|
||||||
; CHECK: uxtb [[DESIRED:r[0-9]+]], [[DESIRED]]
|
; CHECK: uxtb [[DESIRED:r[0-9]+]], [[DESIRED]]
|
||||||
; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]:
|
; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]:
|
||||||
|
; CHECK: mov{{s?}} [[STATUS:r[0-9]+]], #0
|
||||||
; CHECK: ldrexb [[OLD:r[0-9]+]], [r0]
|
; CHECK: ldrexb [[OLD:r[0-9]+]], [r0]
|
||||||
; CHECK: cmp [[OLD]], [[DESIRED]]
|
; CHECK: cmp [[OLD]], [[DESIRED]]
|
||||||
; CHECK: bne [[DONE:.LBB[0-9]+_[0-9]+]]
|
; CHECK: bne [[DONE:.LBB[0-9]+_[0-9]+]]
|
||||||
; CHECK: strexb [[STATUS:r[0-9]+]], r2, [r0]
|
; CHECK: strexb [[STATUS]], r2, [r0]
|
||||||
; CHECK: cmp{{(\.w)?}} [[STATUS]], #0
|
; CHECK: cmp{{(\.w)?}} [[STATUS]], #0
|
||||||
; CHECK: bne [[RETRY]]
|
; CHECK: bne [[RETRY]]
|
||||||
; CHECK: [[DONE]]:
|
; CHECK: [[DONE]]:
|
||||||
|
|
@ -29,10 +30,11 @@ define { i16, i1 } @test_cmpxchg_16(i16* %addr, i16 %desired, i16 %new) nounwind
|
||||||
; CHECK: dmb ish
|
; CHECK: dmb ish
|
||||||
; CHECK: uxth [[DESIRED:r[0-9]+]], [[DESIRED]]
|
; CHECK: uxth [[DESIRED:r[0-9]+]], [[DESIRED]]
|
||||||
; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]:
|
; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]:
|
||||||
|
; CHECK: mov{{s?}} [[STATUS:r[0-9]+]], #0
|
||||||
; CHECK: ldrexh [[OLD:r[0-9]+]], [r0]
|
; CHECK: ldrexh [[OLD:r[0-9]+]], [r0]
|
||||||
; CHECK: cmp [[OLD]], [[DESIRED]]
|
; CHECK: cmp [[OLD]], [[DESIRED]]
|
||||||
; CHECK: bne [[DONE:.LBB[0-9]+_[0-9]+]]
|
; CHECK: bne [[DONE:.LBB[0-9]+_[0-9]+]]
|
||||||
; CHECK: strexh [[STATUS:r[0-9]+]], r2, [r0]
|
; CHECK: strexh [[STATUS]], r2, [r0]
|
||||||
; CHECK: cmp{{(\.w)?}} [[STATUS]], #0
|
; CHECK: cmp{{(\.w)?}} [[STATUS]], #0
|
||||||
; CHECK: bne [[RETRY]]
|
; CHECK: bne [[RETRY]]
|
||||||
; CHECK: [[DONE]]:
|
; CHECK: [[DONE]]:
|
||||||
|
|
@ -48,10 +50,11 @@ define { i32, i1 } @test_cmpxchg_32(i32* %addr, i32 %desired, i32 %new) nounwind
|
||||||
; CHECK: dmb ish
|
; CHECK: dmb ish
|
||||||
; CHECK-NOT: uxt
|
; CHECK-NOT: uxt
|
||||||
; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]:
|
; CHECK: [[RETRY:.LBB[0-9]+_[0-9]+]]:
|
||||||
|
; CHECK: mov{{s?}} [[STATUS:r[0-9]+]], #0
|
||||||
; CHECK: ldrex [[OLD:r[0-9]+]], [r0]
|
; CHECK: ldrex [[OLD:r[0-9]+]], [r0]
|
||||||
; CHECK: cmp [[OLD]], [[DESIRED]]
|
; CHECK: cmp [[OLD]], [[DESIRED]]
|
||||||
; CHECK: bne [[DONE:.LBB[0-9]+_[0-9]+]]
|
; CHECK: bne [[DONE:.LBB[0-9]+_[0-9]+]]
|
||||||
; CHECK: strex [[STATUS:r[0-9]+]], r2, [r0]
|
; CHECK: strex [[STATUS]], r2, [r0]
|
||||||
; CHECK: cmp{{(\.w)?}} [[STATUS]], #0
|
; CHECK: cmp{{(\.w)?}} [[STATUS]], #0
|
||||||
; CHECK: bne [[RETRY]]
|
; CHECK: bne [[RETRY]]
|
||||||
; CHECK: [[DONE]]:
|
; CHECK: [[DONE]]:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue