@@ -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+
743905const 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 ||
0 commit comments