Skip to content
This repository was archived by the owner on Sep 2, 2018. It is now read-only.

Commit ca5ea80

Browse files
author
Dylan McKay
authored
Merge pull request #211 from avr-llvm/support-atomics-v2
Add atomics support
2 parents a46a0aa + 081b3a6 commit ca5ea80

File tree

11 files changed

+623
-5
lines changed

11 files changed

+623
-5
lines changed

lib/Target/AVR/AVRExpandPseudoInsts.cpp

+194-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "llvm/CodeGen/MachineFunctionPass.h"
1717
#include "llvm/CodeGen/MachineInstrBuilder.h"
18+
#include "llvm/CodeGen/MachineRegisterInfo.h"
1819
#include "llvm/Target/TargetRegisterInfo.h"
1920

2021
#include "AVR.h"
@@ -30,8 +31,15 @@ namespace llvm {
3031
class AVRExpandPseudo : public MachineFunctionPass {
3132
public:
3233
static char ID;
34+
3335
const AVRRegisterInfo *TRI;
3436
const TargetInstrInfo *TII;
37+
38+
/// The register to be used for temporary storage.
39+
const unsigned SCRATCH_REGISTER = AVR::R0;
40+
/// The IO address of the status register.
41+
const unsigned SREG_ADDR = 0x3f;
42+
3543
AVRExpandPseudo() : MachineFunctionPass(ID) {}
3644

3745
bool runOnMachineFunction(MachineFunction &MF) override;
@@ -57,6 +65,21 @@ class AVRExpandPseudo : public MachineFunctionPass {
5765
unsigned DstReg) {
5866
return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode), DstReg);
5967
}
68+
69+
MachineRegisterInfo &getRegInfo(Block &MBB) { return MBB.getParent()->getRegInfo(); }
70+
71+
template<typename Func>
72+
bool expandAtomic(Block &MBB, BlockIt MBBI, Func f);
73+
74+
template<typename Func>
75+
bool expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI, Func f);
76+
77+
bool expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI);
78+
79+
bool expandAtomicArithmeticOp(unsigned MemOpcode,
80+
unsigned ArithOpcode,
81+
Block &MBB,
82+
BlockIt MBBI);
6083
};
6184

6285
char AVRExpandPseudo::ID = 0;
@@ -80,9 +103,20 @@ bool AVRExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
80103
TRI = static_cast<const AVRRegisterInfo*>(TM.getSubtargetImpl()->getRegisterInfo());
81104
TII = TM.getSubtargetImpl()->getInstrInfo();
82105

83-
typedef MachineFunction::iterator FuncIt;
84-
for (FuncIt MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
85-
Modified |= expandMBB(*MFI);
106+
for(Block &MBB : MF) {
107+
bool ContinueExpanding = true;
108+
unsigned ExpandCount = 0;
109+
110+
// Continue expanding the block until all pseudos are expanded.
111+
do {
112+
assert(ExpandCount < 10 && "pseudo expand limit reached");
113+
114+
bool BlockModified = expandMBB(MBB);
115+
Modified |= BlockModified;
116+
ExpandCount++;
117+
118+
ContinueExpanding = BlockModified;
119+
} while(ContinueExpanding);
86120
}
87121

88122
return Modified;
@@ -799,6 +833,146 @@ bool AVRExpandPseudo::expand<AVR::LDDWRdPtrQ>(Block &MBB, BlockIt MBBI) {
799833
return true;
800834
}
801835

836+
template<typename Func>
837+
bool AVRExpandPseudo::expandAtomic(Block &MBB, BlockIt MBBI, Func f) {
838+
// Remove the pseudo instruction.
839+
MachineInstr &MI = *MBBI;
840+
841+
// Store the SREG.
842+
buildMI(MBB, MBBI, AVR::INRdA)
843+
.addReg(SCRATCH_REGISTER, RegState::Define)
844+
.addImm(SREG_ADDR);
845+
846+
// Disable exceptions.
847+
buildMI(MBB, MBBI, AVR::BCLRs).addImm(7); // CLI
848+
849+
f(MI);
850+
851+
// Restore the status reg.
852+
buildMI(MBB, MBBI, AVR::OUTARr)
853+
.addImm(SREG_ADDR)
854+
.addReg(SCRATCH_REGISTER);
855+
856+
MI.eraseFromParent();
857+
return true;
858+
}
859+
860+
template<typename Func>
861+
bool AVRExpandPseudo::expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI, Func f) {
862+
return expandAtomic(MBB, MBBI, [&](MachineInstr &MI) {
863+
auto Op1 = MI.getOperand(0);
864+
auto Op2 = MI.getOperand(1);
865+
866+
MachineInstr &NewInst = *buildMI(MBB, MBBI, Opcode).addOperand(Op1).addOperand(Op2).getInstr();
867+
868+
f(NewInst);
869+
});
870+
}
871+
872+
bool AVRExpandPseudo::expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI) {
873+
return expandAtomicBinaryOp(Opcode, MBB, MBBI, [](MachineInstr &MI) {});
874+
}
875+
876+
bool AVRExpandPseudo::expandAtomicArithmeticOp(unsigned Width,
877+
unsigned ArithOpcode,
878+
Block &MBB,
879+
BlockIt MBBI) {
880+
881+
return expandAtomic(MBB, MBBI, [&](MachineInstr &MI) {
882+
auto Op1 = MI.getOperand(0);
883+
auto Op2 = MI.getOperand(1);
884+
885+
unsigned LoadOpcode = (Width == 8) ? AVR::LDRdPtr : AVR::LDWRdPtr;
886+
unsigned StoreOpcode = (Width == 8) ? AVR::STPtrRr : AVR::STWPtrRr;
887+
888+
// Create the load
889+
buildMI(MBB, MBBI, LoadOpcode).addOperand(Op1).addOperand(Op2);
890+
891+
// Create the arithmetic op
892+
buildMI(MBB, MBBI, ArithOpcode).addOperand(Op1).addOperand(Op1).addOperand(Op2);
893+
894+
// Create the store
895+
buildMI(MBB, MBBI, StoreOpcode).addOperand(Op2).addOperand(Op1);
896+
});
897+
}
898+
899+
template<>
900+
bool AVRExpandPseudo::expand<AVR::AtomicLoad8>(Block &MBB, BlockIt MBBI) {
901+
return expandAtomicBinaryOp(AVR::LDRdPtr, MBB, MBBI);
902+
}
903+
904+
template<>
905+
bool AVRExpandPseudo::expand<AVR::AtomicLoad16>(Block &MBB, BlockIt MBBI) {
906+
return expandAtomicBinaryOp(AVR::LDWRdPtr, MBB, MBBI);
907+
}
908+
909+
template<>
910+
bool AVRExpandPseudo::expand<AVR::AtomicStore8>(Block &MBB, BlockIt MBBI) {
911+
return expandAtomicBinaryOp(AVR::STPtrRr, MBB, MBBI);
912+
}
913+
914+
template<>
915+
bool AVRExpandPseudo::expand<AVR::AtomicStore16>(Block &MBB, BlockIt MBBI) {
916+
return expandAtomicBinaryOp(AVR::STWPtrRr, MBB, MBBI);
917+
}
918+
919+
template<>
920+
bool AVRExpandPseudo::expand<AVR::AtomicLoadAdd8>(Block &MBB, BlockIt MBBI) {
921+
return expandAtomicArithmeticOp(8, AVR::ADDRdRr, MBB, MBBI);
922+
}
923+
924+
template<>
925+
bool AVRExpandPseudo::expand<AVR::AtomicLoadAdd16>(Block &MBB, BlockIt MBBI) {
926+
return expandAtomicArithmeticOp(16, AVR::ADDWRdRr, MBB, MBBI);
927+
}
928+
929+
template<>
930+
bool AVRExpandPseudo::expand<AVR::AtomicLoadSub8>(Block &MBB, BlockIt MBBI) {
931+
return expandAtomicArithmeticOp(8, AVR::SUBRdRr, MBB, MBBI);
932+
}
933+
934+
template<>
935+
bool AVRExpandPseudo::expand<AVR::AtomicLoadSub16>(Block &MBB, BlockIt MBBI) {
936+
return expandAtomicArithmeticOp(16, AVR::SUBWRdRr, MBB, MBBI);
937+
}
938+
939+
template<>
940+
bool AVRExpandPseudo::expand<AVR::AtomicLoadAnd8>(Block &MBB, BlockIt MBBI) {
941+
return expandAtomicArithmeticOp(8, AVR::ANDRdRr, MBB, MBBI);
942+
}
943+
944+
template<>
945+
bool AVRExpandPseudo::expand<AVR::AtomicLoadAnd16>(Block &MBB, BlockIt MBBI) {
946+
return expandAtomicArithmeticOp(16, AVR::ANDWRdRr, MBB, MBBI);
947+
}
948+
949+
template<>
950+
bool AVRExpandPseudo::expand<AVR::AtomicLoadOr8>(Block &MBB, BlockIt MBBI) {
951+
return expandAtomicArithmeticOp(8, AVR::ORRdRr, MBB, MBBI);
952+
}
953+
954+
template<>
955+
bool AVRExpandPseudo::expand<AVR::AtomicLoadOr16>(Block &MBB, BlockIt MBBI) {
956+
return expandAtomicArithmeticOp(16, AVR::ORWRdRr, MBB, MBBI);
957+
}
958+
959+
template<>
960+
bool AVRExpandPseudo::expand<AVR::AtomicLoadXor8>(Block &MBB, BlockIt MBBI) {
961+
return expandAtomicArithmeticOp(8, AVR::EORRdRr, MBB, MBBI);
962+
}
963+
964+
template<>
965+
bool AVRExpandPseudo::expand<AVR::AtomicLoadXor16>(Block &MBB, BlockIt MBBI) {
966+
return expandAtomicArithmeticOp(16, AVR::EORWRdRr, MBB, MBBI);
967+
}
968+
969+
template<>
970+
bool AVRExpandPseudo::expand<AVR::AtomicFence>(Block &MBB, BlockIt MBBI) {
971+
// On AVR, there is only one core and so atomic fences do nothing.
972+
MBBI->eraseFromParent();
973+
return true;
974+
}
975+
802976
template <>
803977
bool AVRExpandPseudo::expand<AVR::STSWKRr>(Block &MBB, BlockIt MBBI) {
804978
MachineInstr &MI = *MBBI;
@@ -1305,7 +1479,7 @@ bool AVRExpandPseudo::expand<AVR::SPWRITE>(Block &MBB, BlockIt MBBI) {
13051479

13061480
buildMI(MBB, MBBI, AVR::INRdA)
13071481
.addReg(AVR::R0, RegState::Define)
1308-
.addImm(0x3f)
1482+
.addImm(SREG_ADDR)
13091483
.setMIFlags(Flags);
13101484

13111485
buildMI(MBB, MBBI, AVR::BCLRs).addImm(0x07).setMIFlags(Flags);
@@ -1316,7 +1490,7 @@ bool AVRExpandPseudo::expand<AVR::SPWRITE>(Block &MBB, BlockIt MBBI) {
13161490
.setMIFlags(Flags);
13171491

13181492
buildMI(MBB, MBBI, AVR::OUTARr)
1319-
.addImm(0x3f)
1493+
.addImm(SREG_ADDR)
13201494
.addReg(AVR::R0, RegState::Kill)
13211495
.setMIFlags(Flags);
13221496

@@ -1359,6 +1533,21 @@ bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
13591533
EXPAND(AVR::LDWRdPtrPd);
13601534
case AVR::LDDWRdYQ: //:FIXME: remove this once PR13375 gets fixed
13611535
EXPAND(AVR::LDDWRdPtrQ);
1536+
EXPAND(AVR::AtomicLoad8);
1537+
EXPAND(AVR::AtomicLoad16);
1538+
EXPAND(AVR::AtomicStore8);
1539+
EXPAND(AVR::AtomicStore16);
1540+
EXPAND(AVR::AtomicLoadAdd8);
1541+
EXPAND(AVR::AtomicLoadAdd16);
1542+
EXPAND(AVR::AtomicLoadSub8);
1543+
EXPAND(AVR::AtomicLoadSub16);
1544+
EXPAND(AVR::AtomicLoadAnd8);
1545+
EXPAND(AVR::AtomicLoadAnd16);
1546+
EXPAND(AVR::AtomicLoadOr8);
1547+
EXPAND(AVR::AtomicLoadOr16);
1548+
EXPAND(AVR::AtomicLoadXor8);
1549+
EXPAND(AVR::AtomicLoadXor16);
1550+
EXPAND(AVR::AtomicFence);
13621551
EXPAND(AVR::STSWKRr);
13631552
EXPAND(AVR::STWPtrRr);
13641553
EXPAND(AVR::STWPtrPiRr);

lib/Target/AVR/AVRISelLowering.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,17 @@ AVRTargetLowering::AVRTargetLowering(AVRTargetMachine &tm)
114114
setOperationAction(ISD::VAARG, MVT::Other, Expand);
115115
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
116116

117+
// Atomic operations which must be lowered to rtlib calls
118+
for (MVT VT : MVT::integer_valuetypes()) {
119+
setOperationAction(ISD::ATOMIC_SWAP, VT, Expand);
120+
setOperationAction(ISD::ATOMIC_CMP_SWAP, VT, Expand);
121+
setOperationAction(ISD::ATOMIC_LOAD_NAND, VT, Expand);
122+
setOperationAction(ISD::ATOMIC_LOAD_MAX, VT, Expand);
123+
setOperationAction(ISD::ATOMIC_LOAD_MIN, VT, Expand);
124+
setOperationAction(ISD::ATOMIC_LOAD_UMAX, VT, Expand);
125+
setOperationAction(ISD::ATOMIC_LOAD_UMIN, VT, Expand);
126+
}
127+
117128
// Division/remainder
118129
setOperationAction(ISD::UDIV, MVT::i8, Expand);
119130
setOperationAction(ISD::UDIV, MVT::i16, Expand);

lib/Target/AVR/AVRInstrInfo.td

+32
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,38 @@ isReMaterializable = 1 in
12371237
Requires<[HasSRAM]>;
12381238
}
12391239

1240+
class AtomicLoad<PatFrag Op, RegisterClass DRC> :
1241+
Pseudo<(outs DRC:$rd), (ins PTRREGS:$rr), "atomic_op",
1242+
[(set DRC:$rd, (Op i16:$rr))]>;
1243+
1244+
class AtomicStore<PatFrag Op, RegisterClass DRC> :
1245+
Pseudo<(outs), (ins LDSTPtrReg:$rd, DRC:$rr), "atomic_op",
1246+
[(Op i16:$rd, DRC:$rr)]>;
1247+
1248+
class AtomicLoadOp<PatFrag Op, RegisterClass DRC> :
1249+
Pseudo<(outs DRC:$rd), (ins PTRREGS:$rr, DRC:$operand),
1250+
"atomic_op",
1251+
[(set DRC:$rd, (Op i16:$rr, DRC:$operand))]>;
1252+
1253+
def AtomicLoad8 : AtomicLoad<atomic_load_8, GPR8>;
1254+
def AtomicLoad16 : AtomicLoad<atomic_load_16, DREGS>;
1255+
1256+
def AtomicStore8 : AtomicStore<atomic_store_8, GPR8>;
1257+
def AtomicStore16 : AtomicStore<atomic_store_16, DREGS>;
1258+
1259+
def AtomicLoadAdd8 : AtomicLoadOp<atomic_load_add_8, GPR8>;
1260+
def AtomicLoadAdd16 : AtomicLoadOp<atomic_load_add_16, DREGS>;
1261+
def AtomicLoadSub8 : AtomicLoadOp<atomic_load_sub_8, GPR8>;
1262+
def AtomicLoadSub16 : AtomicLoadOp<atomic_load_sub_16, DREGS>;
1263+
def AtomicLoadAnd8 : AtomicLoadOp<atomic_load_and_8, GPR8>;
1264+
def AtomicLoadAnd16 : AtomicLoadOp<atomic_load_and_16, DREGS>;
1265+
def AtomicLoadOr8 : AtomicLoadOp<atomic_load_or_8, GPR8>;
1266+
def AtomicLoadOr16 : AtomicLoadOp<atomic_load_or_16, DREGS>;
1267+
def AtomicLoadXor8 : AtomicLoadOp<atomic_load_xor_8, GPR8>;
1268+
def AtomicLoadXor16 : AtomicLoadOp<atomic_load_xor_16, DREGS>;
1269+
def AtomicFence : Pseudo<(outs), (ins), "atomic_fence",
1270+
[(atomic_fence imm, imm)]>;
1271+
12401272
// Indirect store from register to data space.
12411273
def STSKRr : F32DM<0b1,
12421274
(outs),

test/CodeGen/AVR/atomics/fence.ll

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
; RUN: llc -mattr=avr6 < %s -march=avr | FileCheck %s
2+
3+
; Checks that atomic fences are simply removed from IR.
4+
; AVR is always singlethreaded so fences do nothing.
5+
6+
; CHECK_LABEL: atomic_fence8
7+
; CHECK: ; BB#0:
8+
; CHECK-NEXT: ret
9+
define void @atomic_fence8() {
10+
fence acquire
11+
ret void
12+
}
13+

0 commit comments

Comments
 (0)