Skip to content

Commit 665ba1f

Browse files
alessandrodLucasSte
authored andcommitted
[SOL] add support for (pseudo) atomics to SBF (#23)
Lower atomic operations to their regular non-atomic equivalents. Lowering for all operations except atomic fence is done at DAG legalization time. Fences are removed at instruction emission time.
1 parent 470273a commit 665ba1f

File tree

4 files changed

+470
-12
lines changed

4 files changed

+470
-12
lines changed

llvm/lib/Target/BPF/BPFISelLowering.cpp

Lines changed: 181 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,30 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM,
7979
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
8080
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
8181

82-
// Set unsupported atomic operations as Custom so
83-
// we can emit better error messages than fatal error
84-
// from selectiondag.
85-
for (auto VT : {MVT::i8, MVT::i16, MVT::i32}) {
82+
for (auto VT : {MVT::i8, MVT::i16, MVT::i32, MVT::i32, MVT::i64}) {
83+
if (Subtarget->isSolana()) {
84+
// Implement custom lowering for all atomic operations
85+
setOperationAction(ISD::ATOMIC_SWAP, VT, Custom);
86+
setOperationAction(ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS, VT, Custom);
87+
setOperationAction(ISD::ATOMIC_LOAD_ADD, VT, Custom);
88+
setOperationAction(ISD::ATOMIC_LOAD_AND, VT, Custom);
89+
setOperationAction(ISD::ATOMIC_LOAD_MAX, VT, Custom);
90+
setOperationAction(ISD::ATOMIC_LOAD_MIN, VT, Custom);
91+
setOperationAction(ISD::ATOMIC_LOAD_NAND, VT, Custom);
92+
setOperationAction(ISD::ATOMIC_LOAD_OR, VT, Custom);
93+
setOperationAction(ISD::ATOMIC_LOAD_SUB, VT, Custom);
94+
setOperationAction(ISD::ATOMIC_LOAD_UMAX, VT, Custom);
95+
setOperationAction(ISD::ATOMIC_LOAD_UMIN, VT, Custom);
96+
setOperationAction(ISD::ATOMIC_LOAD_XOR, VT, Custom);
97+
continue;
98+
}
99+
100+
if (VT == MVT::i64) {
101+
continue;
102+
}
103+
104+
// Set unsupported atomic operations as Custom so we can emit better error
105+
// messages than fatal error from selectiondag.
86106
if (VT == MVT::i32) {
87107
if (STI.getHasAlu32())
88108
continue;
@@ -211,7 +231,17 @@ bool BPFTargetLowering::allowsMisalignedMemoryAccesses(
211231
return isSolana;
212232
}
213233

214-
bool BPFTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
234+
bool BPFTargetLowering::lowerAtomicStoreAsStoreSDNode(
235+
const StoreInst &SI) const {
236+
return Subtarget->isSolana();
237+
}
238+
239+
bool BPFTargetLowering::lowerAtomicLoadAsLoadSDNode(const LoadInst &LI) const {
240+
return Subtarget->isSolana();
241+
}
242+
243+
bool BPFTargetLowering::isOffsetFoldingLegal(
244+
const GlobalAddressSDNode *GA) const {
215245
return false;
216246
}
217247

@@ -281,19 +311,31 @@ BPFTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
281311
return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
282312
}
283313

284-
void BPFTargetLowering::ReplaceNodeResults(
285-
SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
314+
void BPFTargetLowering::ReplaceNodeResults(SDNode *N,
315+
SmallVectorImpl<SDValue> &Results,
316+
SelectionDAG &DAG) const {
286317
const char *err_msg;
287318
uint32_t Opcode = N->getOpcode();
288319
switch (Opcode) {
289320
default:
290321
report_fatal_error("Unhandled custom legalization");
322+
case ISD::ATOMIC_SWAP:
323+
case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS:
291324
case ISD::ATOMIC_LOAD_ADD:
292325
case ISD::ATOMIC_LOAD_AND:
326+
case ISD::ATOMIC_LOAD_MAX:
327+
case ISD::ATOMIC_LOAD_MIN:
328+
case ISD::ATOMIC_LOAD_NAND:
293329
case ISD::ATOMIC_LOAD_OR:
330+
case ISD::ATOMIC_LOAD_SUB:
331+
case ISD::ATOMIC_LOAD_UMAX:
332+
case ISD::ATOMIC_LOAD_UMIN:
294333
case ISD::ATOMIC_LOAD_XOR:
295-
case ISD::ATOMIC_SWAP:
296-
case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS:
334+
if (Subtarget->isSolana()) {
335+
// We do lowering during legalization, see LowerOperation()
336+
return;
337+
}
338+
297339
if (HasAlu32 || Opcode == ISD::ATOMIC_LOAD_ADD)
298340
err_msg = "Unsupported atomic operations, please use 32/64 bit version";
299341
else
@@ -313,10 +355,23 @@ SDValue BPFTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
313355
return LowerGlobalAddress(Op, DAG);
314356
case ISD::SELECT_CC:
315357
return LowerSELECT_CC(Op, DAG);
358+
case ISD::ATOMIC_SWAP:
359+
case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS:
360+
case ISD::ATOMIC_LOAD_ADD:
361+
case ISD::ATOMIC_LOAD_AND:
362+
case ISD::ATOMIC_LOAD_MAX:
363+
case ISD::ATOMIC_LOAD_MIN:
364+
case ISD::ATOMIC_LOAD_NAND:
365+
case ISD::ATOMIC_LOAD_OR:
366+
case ISD::ATOMIC_LOAD_SUB:
367+
case ISD::ATOMIC_LOAD_UMAX:
368+
case ISD::ATOMIC_LOAD_UMIN:
369+
case ISD::ATOMIC_LOAD_XOR:
370+
return LowerATOMICRMW(Op, DAG);
316371
case ISD::DYNAMIC_STACKALLOC:
317372
report_fatal_error("Unsupported dynamic stack allocation");
318373
default:
319-
llvm_unreachable("unimplemented operand");
374+
llvm_unreachable("unimplemented atomic operand");
320375
}
321376
}
322377

@@ -412,7 +467,6 @@ SDValue BPFTargetLowering::LowerFormalArguments(
412467
fail(DL, DAG, "functions with VarArgs or StructRet are not supported");
413468
}
414469

415-
416470
return Chain;
417471
}
418472

@@ -740,6 +794,114 @@ SDValue BPFTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
740794
return DAG.getNode(BPFISD::SELECT_CC, DL, VTs, Ops);
741795
}
742796

797+
SDValue BPFTargetLowering::LowerATOMICRMW(SDValue Op, SelectionDAG &DAG) const {
798+
SDLoc DL(Op);
799+
AtomicSDNode *AN = cast<AtomicSDNode>(Op);
800+
assert(AN && "Expected custom lowering of an atomic load node");
801+
802+
SDValue Chain = AN->getChain();
803+
SDValue Ptr = AN->getBasePtr();
804+
EVT PtrVT = AN->getMemoryVT();
805+
EVT RetVT = Op.getValueType();
806+
807+
// Load the current value
808+
SDValue Load =
809+
DAG.getExtLoad(ISD::EXTLOAD, DL, RetVT, Chain, Ptr, MachinePointerInfo(),
810+
PtrVT, AN->getAlignment());
811+
Chain = Load.getValue(1);
812+
813+
// Most ops return the current value, except CMP_SWAP_WITH_SUCCESS see below
814+
SDValue Ret = Load;
815+
SDValue RetFlag;
816+
817+
// Val contains the new value we want to set. For CMP_SWAP, Cmp contains the
818+
// expected current value.
819+
SDValue Cmp, Val;
820+
if (AN->isCompareAndSwap()) {
821+
Cmp = Op.getOperand(2);
822+
Val = Op.getOperand(3);
823+
824+
// The Cmp value must match the pointer type
825+
EVT CmpVT = Cmp->getValueType(0);
826+
if (CmpVT != RetVT) {
827+
Cmp = RetVT.bitsGT(CmpVT) ? DAG.getNode(ISD::SIGN_EXTEND, DL, RetVT, Cmp)
828+
: DAG.getNode(ISD::TRUNCATE, DL, RetVT, Cmp);
829+
}
830+
} else {
831+
Val = AN->getVal();
832+
}
833+
834+
// The new value type must match the pointer type
835+
EVT ValVT = Val->getValueType(0);
836+
if (ValVT != RetVT) {
837+
Val = RetVT.bitsGT(ValVT) ? DAG.getNode(ISD::SIGN_EXTEND, DL, RetVT, Val)
838+
: DAG.getNode(ISD::TRUNCATE, DL, RetVT, Val);
839+
ValVT = Val->getValueType(0);
840+
}
841+
842+
SDValue NewVal;
843+
switch (Op.getOpcode()) {
844+
case ISD::ATOMIC_SWAP:
845+
NewVal = Val;
846+
break;
847+
case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: {
848+
EVT RetFlagVT = AN->getValueType(1);
849+
NewVal = DAG.getSelectCC(DL, Load, Cmp, Val, Load, ISD::SETEQ);
850+
RetFlag = DAG.getSelectCC(
851+
DL, Load, Cmp, DAG.getBoolConstant(true, DL, RetFlagVT, RetFlagVT),
852+
DAG.getBoolConstant(false, DL, RetFlagVT, RetFlagVT), ISD::SETEQ);
853+
break;
854+
}
855+
case ISD::ATOMIC_LOAD_ADD:
856+
NewVal = DAG.getNode(ISD::ADD, DL, ValVT, Load, Val);
857+
break;
858+
case ISD::ATOMIC_LOAD_SUB:
859+
NewVal = DAG.getNode(ISD::SUB, DL, ValVT, Load, Val);
860+
break;
861+
case ISD::ATOMIC_LOAD_AND:
862+
NewVal = DAG.getNode(ISD::AND, DL, ValVT, Load, Val);
863+
break;
864+
case ISD::ATOMIC_LOAD_NAND: {
865+
NewVal =
866+
DAG.getNOT(DL, DAG.getNode(ISD::AND, DL, ValVT, Load, Val), ValVT);
867+
break;
868+
}
869+
case ISD::ATOMIC_LOAD_OR:
870+
NewVal = DAG.getNode(ISD::OR, DL, ValVT, Load, Val);
871+
break;
872+
case ISD::ATOMIC_LOAD_XOR:
873+
NewVal = DAG.getNode(ISD::XOR, DL, ValVT, Load, Val);
874+
break;
875+
case ISD::ATOMIC_LOAD_MIN:
876+
NewVal = DAG.getNode(ISD::SMIN, DL, ValVT, Load, Val);
877+
break;
878+
case ISD::ATOMIC_LOAD_UMIN:
879+
NewVal = DAG.getNode(ISD::UMIN, DL, ValVT, Load, Val);
880+
break;
881+
case ISD::ATOMIC_LOAD_MAX:
882+
NewVal = DAG.getNode(ISD::SMAX, DL, ValVT, Load, Val);
883+
break;
884+
case ISD::ATOMIC_LOAD_UMAX:
885+
NewVal = DAG.getNode(ISD::UMAX, DL, ValVT, Load, Val);
886+
break;
887+
default:
888+
llvm_unreachable("unknown atomicrmw op");
889+
}
890+
891+
Chain =
892+
DAG.getTruncStore(Chain, DL, NewVal, Ptr, MachinePointerInfo(), PtrVT);
893+
894+
if (RetFlag) {
895+
// CMP_SWAP_WITH_SUCCESS returns {value, success, chain}
896+
Ret = DAG.getMergeValues({Ret, RetFlag, Chain}, DL);
897+
} else {
898+
// All the other ops return {value, chain}
899+
Ret = DAG.getMergeValues({Ret, Chain}, DL);
900+
}
901+
902+
return Ret;
903+
}
904+
743905
const char *BPFTargetLowering::getTargetNodeName(unsigned Opcode) const {
744906
switch ((BPFISD::NodeType)Opcode) {
745907
case BPFISD::FIRST_NUMBER:
@@ -843,6 +1005,7 @@ BPFTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
8431005
Opc == BPF::Select_32_64);
8441006

8451007
bool isMemcpyOp = Opc == BPF::MEMCPY;
1008+
bool isAtomicFence = Opc == BPF::ATOMIC_FENCE;
8461009

8471010
#ifndef NDEBUG
8481011
bool isSelectRIOp = (Opc == BPF::Select_Ri ||
@@ -851,13 +1014,19 @@ BPFTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
8511014
Opc == BPF::Select_Ri_32_64);
8521015

8531016

854-
assert((isSelectRROp || isSelectRIOp || isMemcpyOp) &&
1017+
assert((isSelectRROp || isSelectRIOp || isMemcpyOp || isAtomicFence) &&
8551018
"Unexpected instr type to insert");
8561019
#endif
8571020

8581021
if (isMemcpyOp)
8591022
return EmitInstrWithCustomInserterMemcpy(MI, BB);
8601023

1024+
if (isAtomicFence) {
1025+
// this is currently a nop
1026+
MI.eraseFromParent();
1027+
return BB;
1028+
}
1029+
8611030
bool is32BitCmp = (Opc == BPF::Select_32 ||
8621031
Opc == BPF::Select_32_64 ||
8631032
Opc == BPF::Select_Ri_32 ||

llvm/lib/Target/BPF/BPFISelLowering.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ class BPFTargetLowering : public TargetLowering {
7171

7272
MVT getScalarShiftAmountTy(const DataLayout &, EVT) const override;
7373

74+
bool lowerAtomicStoreAsStoreSDNode(const StoreInst &SI) const override;
75+
bool lowerAtomicLoadAsLoadSDNode(const LoadInst &LI) const override;
76+
7477
private:
7578
// Control Instruction Selection Features
7679
bool HasAlu32;
@@ -80,6 +83,7 @@ class BPFTargetLowering : public TargetLowering {
8083
SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;
8184
SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
8285
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
86+
SDValue LowerATOMICRMW(SDValue Op, SelectionDAG &DAG) const;
8387

8488
// Lower the result values of a call, copying them out of physregs into vregs
8589
SDValue LowerCallResult(SDValue Chain, SDValue InGlue,

llvm/lib/Target/BPF/BPFInstrInfo.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def BPFIsLittleEndian : Predicate<"CurDAG->getDataLayout().isLittleEndian()">;
5353
def BPFIsBigEndian : Predicate<"!CurDAG->getDataLayout().isLittleEndian()">;
5454
def BPFHasALU32 : Predicate<"Subtarget->getHasAlu32()">;
5555
def BPFNoALU32 : Predicate<"!Subtarget->getHasAlu32()">;
56+
def BPFSubtargetSolana : Predicate<"Subtarget->isSolana()">;
5657

5758
def brtarget : Operand<OtherVT> {
5859
let PrintMethod = "printBrTargetOperand";
@@ -747,6 +748,14 @@ def : Pat<(atomic_load_sub_32 ADDRri:$addr, GPR32:$val),
747748
def : Pat<(atomic_load_sub_64 ADDRri:$addr, GPR:$val),
748749
(XFADDD ADDRri:$addr, (NEG_64 GPR:$val))>;
749750

751+
let Predicates = [BPFSubtargetSolana], usesCustomInserter = 1, isCodeGenOnly = 1 in {
752+
def ATOMIC_FENCE : Pseudo<
753+
(outs),
754+
(ins),
755+
"#atomic_fence",
756+
[(atomic_fence timm, timm)]>;
757+
}
758+
750759
// Atomic Exchange
751760
class XCHG<BPFWidthModifer SizeOp, string OpcodeStr, PatFrag OpNode>
752761
: TYPE_LD_ST<BPF_ATOMIC.Value, SizeOp.Value,

0 commit comments

Comments
 (0)