@@ -79,10 +79,30 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM,
79
79
setOperationAction (ISD::STACKSAVE, MVT::Other, Expand);
80
80
setOperationAction (ISD::STACKRESTORE, MVT::Other, Expand);
81
81
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.
86
106
if (VT == MVT::i32) {
87
107
if (STI.getHasAlu32 ())
88
108
continue ;
@@ -210,7 +230,17 @@ bool BPFTargetLowering::allowsMisalignedMemoryAccesses(
210
230
return isSolana;
211
231
}
212
232
213
- bool BPFTargetLowering::isOffsetFoldingLegal (const GlobalAddressSDNode *GA) const {
233
+ bool BPFTargetLowering::lowerAtomicStoreAsStoreSDNode (
234
+ const StoreInst &SI) const {
235
+ return Subtarget->isSolana ();
236
+ }
237
+
238
+ bool BPFTargetLowering::lowerAtomicLoadAsLoadSDNode (const LoadInst &LI) const {
239
+ return Subtarget->isSolana ();
240
+ }
241
+
242
+ bool BPFTargetLowering::isOffsetFoldingLegal (
243
+ const GlobalAddressSDNode *GA) const {
214
244
return false ;
215
245
}
216
246
@@ -280,19 +310,31 @@ BPFTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
280
310
return TargetLowering::getRegForInlineAsmConstraint (TRI, Constraint, VT);
281
311
}
282
312
283
- void BPFTargetLowering::ReplaceNodeResults (
284
- SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
313
+ void BPFTargetLowering::ReplaceNodeResults (SDNode *N,
314
+ SmallVectorImpl<SDValue> &Results,
315
+ SelectionDAG &DAG) const {
285
316
const char *err_msg;
286
317
uint32_t Opcode = N->getOpcode ();
287
318
switch (Opcode) {
288
319
default :
289
320
report_fatal_error (" Unhandled custom legalization" );
321
+ case ISD::ATOMIC_SWAP:
322
+ case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS:
290
323
case ISD::ATOMIC_LOAD_ADD:
291
324
case ISD::ATOMIC_LOAD_AND:
325
+ case ISD::ATOMIC_LOAD_MAX:
326
+ case ISD::ATOMIC_LOAD_MIN:
327
+ case ISD::ATOMIC_LOAD_NAND:
292
328
case ISD::ATOMIC_LOAD_OR:
329
+ case ISD::ATOMIC_LOAD_SUB:
330
+ case ISD::ATOMIC_LOAD_UMAX:
331
+ case ISD::ATOMIC_LOAD_UMIN:
293
332
case ISD::ATOMIC_LOAD_XOR:
294
- case ISD::ATOMIC_SWAP:
295
- case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS:
333
+ if (Subtarget->isSolana ()) {
334
+ // We do lowering during legalization, see LowerOperation()
335
+ return ;
336
+ }
337
+
296
338
if (HasAlu32 || Opcode == ISD::ATOMIC_LOAD_ADD)
297
339
err_msg = " Unsupported atomic operations, please use 32/64 bit version" ;
298
340
else
@@ -312,10 +354,23 @@ SDValue BPFTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
312
354
return LowerGlobalAddress (Op, DAG);
313
355
case ISD::SELECT_CC:
314
356
return LowerSELECT_CC (Op, DAG);
357
+ case ISD::ATOMIC_SWAP:
358
+ case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS:
359
+ case ISD::ATOMIC_LOAD_ADD:
360
+ case ISD::ATOMIC_LOAD_AND:
361
+ case ISD::ATOMIC_LOAD_MAX:
362
+ case ISD::ATOMIC_LOAD_MIN:
363
+ case ISD::ATOMIC_LOAD_NAND:
364
+ case ISD::ATOMIC_LOAD_OR:
365
+ case ISD::ATOMIC_LOAD_SUB:
366
+ case ISD::ATOMIC_LOAD_UMAX:
367
+ case ISD::ATOMIC_LOAD_UMIN:
368
+ case ISD::ATOMIC_LOAD_XOR:
369
+ return LowerATOMICRMW (Op, DAG);
315
370
case ISD::DYNAMIC_STACKALLOC:
316
371
report_fatal_error (" Unsupported dynamic stack allocation" );
317
372
default :
318
- llvm_unreachable (" unimplemented operand" );
373
+ llvm_unreachable (" unimplemented atomic operand" );
319
374
}
320
375
}
321
376
@@ -411,7 +466,6 @@ SDValue BPFTargetLowering::LowerFormalArguments(
411
466
fail (DL, DAG, " functions with VarArgs or StructRet are not supported" );
412
467
}
413
468
414
-
415
469
return Chain;
416
470
}
417
471
@@ -738,6 +792,114 @@ SDValue BPFTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
738
792
return DAG.getNode (BPFISD::SELECT_CC, DL, VTs, Ops);
739
793
}
740
794
795
+ SDValue BPFTargetLowering::LowerATOMICRMW (SDValue Op, SelectionDAG &DAG) const {
796
+ SDLoc DL (Op);
797
+ AtomicSDNode *AN = cast<AtomicSDNode>(Op);
798
+ assert (AN && " Expected custom lowering of an atomic load node" );
799
+
800
+ SDValue Chain = AN->getChain ();
801
+ SDValue Ptr = AN->getBasePtr ();
802
+ EVT PtrVT = AN->getMemoryVT ();
803
+ EVT RetVT = Op.getValueType ();
804
+
805
+ // Load the current value
806
+ SDValue Load =
807
+ DAG.getExtLoad (ISD::EXTLOAD, DL, RetVT, Chain, Ptr , MachinePointerInfo (),
808
+ PtrVT, AN->getAlignment ());
809
+ Chain = Load.getValue (1 );
810
+
811
+ // Most ops return the current value, except CMP_SWAP_WITH_SUCCESS see below
812
+ SDValue Ret = Load;
813
+ SDValue RetFlag;
814
+
815
+ // Val contains the new value we want to set. For CMP_SWAP, Cmp contains the
816
+ // expected current value.
817
+ SDValue Cmp, Val;
818
+ if (AN->isCompareAndSwap ()) {
819
+ Cmp = Op.getOperand (2 );
820
+ Val = Op.getOperand (3 );
821
+
822
+ // The Cmp value must match the pointer type
823
+ EVT CmpVT = Cmp->getValueType (0 );
824
+ if (CmpVT != RetVT) {
825
+ Cmp = RetVT.bitsGT (CmpVT) ? DAG.getNode (ISD::SIGN_EXTEND, DL, RetVT, Cmp)
826
+ : DAG.getNode (ISD::TRUNCATE, DL, RetVT, Cmp);
827
+ }
828
+ } else {
829
+ Val = AN->getVal ();
830
+ }
831
+
832
+ // The new value type must match the pointer type
833
+ EVT ValVT = Val->getValueType (0 );
834
+ if (ValVT != RetVT) {
835
+ Val = RetVT.bitsGT (ValVT) ? DAG.getNode (ISD::SIGN_EXTEND, DL, RetVT, Val)
836
+ : DAG.getNode (ISD::TRUNCATE, DL, RetVT, Val);
837
+ ValVT = Val->getValueType (0 );
838
+ }
839
+
840
+ SDValue NewVal;
841
+ switch (Op.getOpcode ()) {
842
+ case ISD::ATOMIC_SWAP:
843
+ NewVal = Val;
844
+ break ;
845
+ case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: {
846
+ EVT RetFlagVT = AN->getValueType (1 );
847
+ NewVal = DAG.getSelectCC (DL, Load, Cmp, Val, Load, ISD::SETEQ);
848
+ RetFlag = DAG.getSelectCC (
849
+ DL, Load, Cmp, DAG.getBoolConstant (true , DL, RetFlagVT, RetFlagVT),
850
+ DAG.getBoolConstant (false , DL, RetFlagVT, RetFlagVT), ISD::SETEQ);
851
+ break ;
852
+ }
853
+ case ISD::ATOMIC_LOAD_ADD:
854
+ NewVal = DAG.getNode (ISD::ADD, DL, ValVT, Load, Val);
855
+ break ;
856
+ case ISD::ATOMIC_LOAD_SUB:
857
+ NewVal = DAG.getNode (ISD::SUB, DL, ValVT, Load, Val);
858
+ break ;
859
+ case ISD::ATOMIC_LOAD_AND:
860
+ NewVal = DAG.getNode (ISD::AND, DL, ValVT, Load, Val);
861
+ break ;
862
+ case ISD::ATOMIC_LOAD_NAND: {
863
+ NewVal =
864
+ DAG.getNOT (DL, DAG.getNode (ISD::AND, DL, ValVT, Load, Val), ValVT);
865
+ break ;
866
+ }
867
+ case ISD::ATOMIC_LOAD_OR:
868
+ NewVal = DAG.getNode (ISD::OR, DL, ValVT, Load, Val);
869
+ break ;
870
+ case ISD::ATOMIC_LOAD_XOR:
871
+ NewVal = DAG.getNode (ISD::XOR, DL, ValVT, Load, Val);
872
+ break ;
873
+ case ISD::ATOMIC_LOAD_MIN:
874
+ NewVal = DAG.getNode (ISD::SMIN, DL, ValVT, Load, Val);
875
+ break ;
876
+ case ISD::ATOMIC_LOAD_UMIN:
877
+ NewVal = DAG.getNode (ISD::UMIN, DL, ValVT, Load, Val);
878
+ break ;
879
+ case ISD::ATOMIC_LOAD_MAX:
880
+ NewVal = DAG.getNode (ISD::SMAX, DL, ValVT, Load, Val);
881
+ break ;
882
+ case ISD::ATOMIC_LOAD_UMAX:
883
+ NewVal = DAG.getNode (ISD::UMAX, DL, ValVT, Load, Val);
884
+ break ;
885
+ default :
886
+ llvm_unreachable (" unknown atomicrmw op" );
887
+ }
888
+
889
+ Chain =
890
+ DAG.getTruncStore (Chain, DL, NewVal, Ptr , MachinePointerInfo (), PtrVT);
891
+
892
+ if (RetFlag) {
893
+ // CMP_SWAP_WITH_SUCCESS returns {value, success, chain}
894
+ Ret = DAG.getMergeValues ({Ret, RetFlag, Chain}, DL);
895
+ } else {
896
+ // All the other ops return {value, chain}
897
+ Ret = DAG.getMergeValues ({Ret, Chain}, DL);
898
+ }
899
+
900
+ return Ret;
901
+ }
902
+
741
903
const char *BPFTargetLowering::getTargetNodeName (unsigned Opcode) const {
742
904
switch ((BPFISD::NodeType)Opcode) {
743
905
case BPFISD::FIRST_NUMBER:
@@ -841,6 +1003,7 @@ BPFTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
841
1003
Opc == BPF::Select_32_64);
842
1004
843
1005
bool isMemcpyOp = Opc == BPF::MEMCPY;
1006
+ bool isAtomicFence = Opc == BPF::ATOMIC_FENCE;
844
1007
845
1008
#ifndef NDEBUG
846
1009
bool isSelectRIOp = (Opc == BPF::Select_Ri ||
@@ -849,13 +1012,19 @@ BPFTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
849
1012
Opc == BPF::Select_Ri_32_64);
850
1013
851
1014
852
- assert ((isSelectRROp || isSelectRIOp || isMemcpyOp) &&
1015
+ assert ((isSelectRROp || isSelectRIOp || isMemcpyOp || isAtomicFence ) &&
853
1016
" Unexpected instr type to insert" );
854
1017
#endif
855
1018
856
1019
if (isMemcpyOp)
857
1020
return EmitInstrWithCustomInserterMemcpy (MI, BB);
858
1021
1022
+ if (isAtomicFence) {
1023
+ // this is currently a nop
1024
+ MI.eraseFromParent ();
1025
+ return BB;
1026
+ }
1027
+
859
1028
bool is32BitCmp = (Opc == BPF::Select_32 ||
860
1029
Opc == BPF::Select_32_64 ||
861
1030
Opc == BPF::Select_Ri_32 ||
0 commit comments