mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-13 09:33:50 +00:00
Rough first pass at compare_and_swap atomic builtins for ARM mode. Work in progress.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@91090 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
da920fa4f9
commit
5278eb802f
@ -92,6 +92,8 @@ namespace ARMII {
|
||||
StMiscFrm = 9 << FormShift,
|
||||
LdStMulFrm = 10 << FormShift,
|
||||
|
||||
LdStExFrm = 28 << FormShift,
|
||||
|
||||
// Miscellaneous arithmetic instructions
|
||||
ArithMiscFrm = 11 << FormShift,
|
||||
|
||||
|
@ -3042,6 +3042,77 @@ void ARMTargetLowering::ReplaceNodeResults(SDNode *N,
|
||||
// ARM Scheduler Hooks
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
MachineBasicBlock *
|
||||
ARMTargetLowering::EmitAtomicCmpSwap(unsigned Size, MachineInstr *MI,
|
||||
MachineBasicBlock *BB) const {
|
||||
unsigned dest = MI->getOperand(0).getReg();
|
||||
unsigned ptr = MI->getOperand(1).getReg();
|
||||
unsigned oldval = MI->getOperand(2).getReg();
|
||||
unsigned newval = MI->getOperand(3).getReg();
|
||||
unsigned scratch = BB->getParent()->getRegInfo()
|
||||
.createVirtualRegister(ARM::GPRRegisterClass);
|
||||
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
|
||||
DebugLoc dl = MI->getDebugLoc();
|
||||
|
||||
unsigned ldrOpc, strOpc;
|
||||
switch (Size) {
|
||||
default: llvm_unreachable("unsupported size for AtomicCmpSwap!");
|
||||
case 1: ldrOpc = ARM::LDREXB; strOpc = ARM::STREXB; break;
|
||||
case 2: ldrOpc = ARM::LDREXH; strOpc = ARM::STREXH; break;
|
||||
case 4: ldrOpc = ARM::LDREX; strOpc = ARM::STREX; break;
|
||||
}
|
||||
|
||||
MachineFunction *MF = BB->getParent();
|
||||
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
||||
MachineFunction::iterator It = BB;
|
||||
++It; // insert the new blocks after the current block
|
||||
|
||||
MachineBasicBlock *loop1MBB = MF->CreateMachineBasicBlock(LLVM_BB);
|
||||
MachineBasicBlock *loop2MBB = MF->CreateMachineBasicBlock(LLVM_BB);
|
||||
MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB);
|
||||
MF->insert(It, loop1MBB);
|
||||
MF->insert(It, loop2MBB);
|
||||
MF->insert(It, exitMBB);
|
||||
exitMBB->transferSuccessors(BB);
|
||||
|
||||
// thisMBB:
|
||||
// ...
|
||||
// fallthrough --> loop1MBB
|
||||
BB->addSuccessor(loop1MBB);
|
||||
|
||||
// loop1MBB:
|
||||
// ldrex dest, [ptr]
|
||||
// cmp dest, oldval
|
||||
// bne exitMBB
|
||||
BB = loop1MBB;
|
||||
AddDefaultPred(BuildMI(BB, dl, TII->get(ldrOpc), dest).addReg(ptr));
|
||||
AddDefaultPred(BuildMI(BB, dl, TII->get(ARM::CMPrr))
|
||||
.addReg(dest).addReg(oldval));
|
||||
BuildMI(BB, dl, TII->get(ARM::Bcc)).addMBB(exitMBB).addImm(ARMCC::NE)
|
||||
.addReg(ARM::CPSR);
|
||||
BB->addSuccessor(loop2MBB);
|
||||
BB->addSuccessor(exitMBB);
|
||||
|
||||
// loop2MBB:
|
||||
// strex scratch, newval, [ptr]
|
||||
// cmp scratch, #0
|
||||
// bne loop1MBB
|
||||
BB = loop2MBB;
|
||||
AddDefaultPred(BuildMI(BB, dl, TII->get(strOpc), scratch).addReg(newval)
|
||||
.addReg(ptr));
|
||||
AddDefaultPred(BuildMI(BB, dl, TII->get(ARM::CMPri))
|
||||
.addReg(scratch).addImm(0));
|
||||
BuildMI(BB, dl, TII->get(ARM::Bcc)).addMBB(loop1MBB).addImm(ARMCC::NE)
|
||||
.addReg(ARM::CPSR);
|
||||
BB->addSuccessor(loop1MBB);
|
||||
BB->addSuccessor(exitMBB);
|
||||
|
||||
// exitMBB:
|
||||
// ...
|
||||
BB = exitMBB;
|
||||
return BB;
|
||||
}
|
||||
|
||||
MachineBasicBlock *
|
||||
ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
|
||||
MachineBasicBlock *BB,
|
||||
@ -3050,7 +3121,16 @@ ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
|
||||
DebugLoc dl = MI->getDebugLoc();
|
||||
switch (MI->getOpcode()) {
|
||||
default:
|
||||
MI->dump();
|
||||
llvm_unreachable("Unexpected instr type to insert");
|
||||
|
||||
|
||||
|
||||
|
||||
case ARM::ATOMIC_CMP_SWAP_I8: return EmitAtomicCmpSwap(1, MI, BB);
|
||||
case ARM::ATOMIC_CMP_SWAP_I16: return EmitAtomicCmpSwap(2, MI, BB);
|
||||
case ARM::ATOMIC_CMP_SWAP_I32: return EmitAtomicCmpSwap(4, MI, BB);
|
||||
|
||||
case ARM::tMOVCCr_pseudo: {
|
||||
// To "insert" a SELECT_CC instruction, we actually have to insert the
|
||||
// diamond control-flow pattern. The incoming instruction knows the
|
||||
|
@ -331,6 +331,10 @@ namespace llvm {
|
||||
|
||||
SDValue getARMCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
|
||||
SDValue &ARMCC, SelectionDAG &DAG, DebugLoc dl);
|
||||
|
||||
MachineBasicBlock *EmitAtomicCmpSwap(unsigned Size, MachineInstr *MI,
|
||||
MachineBasicBlock *BB) const;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,8 @@ def LdMiscFrm : Format<8>;
|
||||
def StMiscFrm : Format<9>;
|
||||
def LdStMulFrm : Format<10>;
|
||||
|
||||
def LdStExFrm : Format<28>;
|
||||
|
||||
def ArithMiscFrm : Format<11>;
|
||||
def ExtFrm : Format<12>;
|
||||
|
||||
@ -264,6 +266,28 @@ class JTI<dag oops, dag iops, InstrItinClass itin,
|
||||
: XI<oops, iops, AddrModeNone, SizeSpecial, IndexModeNone, BrMiscFrm, itin,
|
||||
asm, "", pattern>;
|
||||
|
||||
|
||||
// Atomic load/store instructions
|
||||
|
||||
class AIldrex<bits<2> opcod, dag oops, dag iops, InstrItinClass itin,
|
||||
string opc, string asm, list<dag> pattern>
|
||||
: I<oops, iops, AddrModeNone, Size4Bytes, IndexModeNone, LdStExFrm, itin,
|
||||
opc, asm, "", pattern> {
|
||||
let Inst{27-23} = 0b00011;
|
||||
let Inst{22-21} = opcod;
|
||||
let Inst{20} = 1;
|
||||
let Inst{11-0} = 0b111110011111;
|
||||
}
|
||||
class AIstrex<bits<2> opcod, dag oops, dag iops, InstrItinClass itin,
|
||||
string opc, string asm, list<dag> pattern>
|
||||
: I<oops, iops, AddrModeNone, Size4Bytes, IndexModeNone, LdStExFrm, itin,
|
||||
opc, asm, "", pattern> {
|
||||
let Inst{27-23} = 0b00011;
|
||||
let Inst{22-21} = opcod;
|
||||
let Inst{20} = 0;
|
||||
let Inst{11-0} = 0b111110011111;
|
||||
}
|
||||
|
||||
// addrmode1 instructions
|
||||
class AI1<bits<4> opcod, dag oops, dag iops, Format f, InstrItinClass itin,
|
||||
string opc, string asm, list<dag> pattern>
|
||||
|
@ -1596,6 +1596,48 @@ def Int_SyncBarrierV7 : AI<(outs), (ins),
|
||||
}
|
||||
}
|
||||
|
||||
let usesCustomInserter = 1, mayLoad = 1, mayStore = 1 in {
|
||||
def ATOMIC_CMP_SWAP_I8 : PseudoInst<
|
||||
(outs GPR:$dst), (ins GPR:$ptr, GPR:$old, GPR:$new), NoItinerary,
|
||||
"${:comment} ATOMIC_CMP_SWAP_I8 PSEUDO!",
|
||||
[(set GPR:$dst, (atomic_cmp_swap_8 GPR:$ptr, GPR:$old, GPR:$new))]>;
|
||||
def ATOMIC_CMP_SWAP_I16 : PseudoInst<
|
||||
(outs GPR:$dst), (ins GPR:$ptr, GPR:$old, GPR:$new), NoItinerary,
|
||||
"${:comment} ATOMIC_CMP_SWAP_I16 PSEUDO!",
|
||||
[(set GPR:$dst, (atomic_cmp_swap_16 GPR:$ptr, GPR:$old, GPR:$new))]>;
|
||||
def ATOMIC_CMP_SWAP_I32 : PseudoInst<
|
||||
(outs GPR:$dst), (ins GPR:$ptr, GPR:$old, GPR:$new), NoItinerary,
|
||||
"${:comment} ATOMIC_CMP_SWAP_I32 PSEUDO!",
|
||||
[(set GPR:$dst, (atomic_cmp_swap_32 GPR:$ptr, GPR:$old, GPR:$new))]>;
|
||||
}
|
||||
|
||||
let mayLoad = 1 in {
|
||||
def LDREXB : AIldrex<0b10, (outs GPR:$dest), (ins GPR:$ptr), NoItinerary,
|
||||
"ldrexb", "\t$dest, [$ptr]",
|
||||
[]>;
|
||||
def LDREXH : AIldrex<0b11, (outs GPR:$dest), (ins GPR:$ptr), NoItinerary,
|
||||
"ldrexh", "\t$dest, [$ptr]",
|
||||
[]>;
|
||||
def LDREX : AIldrex<0b00, (outs GPR:$dest), (ins GPR:$ptr), NoItinerary,
|
||||
"ldrex", "\t$dest, [$ptr]",
|
||||
[]>;
|
||||
}
|
||||
|
||||
let mayStore = 1 in {
|
||||
def STREXB : AIstrex<0b10, (outs GPR:$success), (ins GPR:$src, GPR:$ptr),
|
||||
NoItinerary,
|
||||
"strexb", "\t$success, $src, [$ptr]",
|
||||
[]>;
|
||||
def STREXH : AIstrex<0b11, (outs GPR:$success), (ins GPR:$src, GPR:$ptr),
|
||||
NoItinerary,
|
||||
"strexh", "\t$success, $src, [$ptr]",
|
||||
[]>;
|
||||
def STREX : AIstrex<0b00, (outs GPR:$success), (ins GPR:$src, GPR:$ptr),
|
||||
NoItinerary,
|
||||
"strex", "\t$success, $src, [$ptr]",
|
||||
[]>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TLS Instructions
|
||||
//
|
||||
|
Loading…
x
Reference in New Issue
Block a user