This is a follow up to D141317 which extends the common code to include a target independent pseudo instruction. This is an alternative to (subset of) D92842 which tries to be as close to NFC as possible.
A couple things to call out.
* The test change in X86 is because we loose the scheduling information on the instruction. However, I think this was actually a bug in x86 since no instruction was emitted for a MEMBARRIER. Concluding that a meta instruction has latency just seems wrong?
* I intentionally left some parts of D92842 out. Specifically, several of the changes in the X86 code (data independence and outlining) appear functional, and likely worthy of their own review. Additionally, I'm not handling ARM/AArch64 at all. Those targets need the ordering whereas none of the others do. I want to get this in and tested before retrofitting in ordering to support those targets.
Differential Revision: https://reviews.llvm.org/D141408
void Select_FREEZE(SDNode *N);
void Select_ARITH_FENCE(SDNode *N);
+ void Select_MEMBARRIER(SDNode *N);
void pushStackMapLiveVariable(SmallVectorImpl<SDValue> &Ops, SDValue Operand,
SDLoc DL);
HANDLE_TARGET_OPCODE(ICALL_BRANCH_FUNNEL)
+// This is a fence with the singlethread scope. It represents a compiler memory
+// barrier, but does not correspond to any generated instruction.
+HANDLE_TARGET_OPCODE(MEMBARRIER)
+
/// The following generic opcodes are not supposed to appear after ISel.
/// This is something we might want to relax, but for now, this is convenient
/// to produce diagnostics.
let AsmString = "";
let hasSideEffects = true;
}
+def MEMBARRIER : StandardPseudoInstruction {
+ let OutOperandList = (outs);
+ let InOperandList = (ins);
+ let AsmString = "";
+ let hasSideEffects = true;
+ let Size = 0;
+ let isMeta = true;
+}
// Generic opcodes used in GlobalISel.
include "llvm/Target/GenericOpcodes.td"
if (isVerbose())
OutStreamer->emitRawComment("ARITH_FENCE");
break;
+ case TargetOpcode::MEMBARRIER:
+ OutStreamer->emitRawComment("MEMBARRIER");
+ break;
default:
emitInstruction(&MI);
if (CanDoExtraAnalysis) {
N->getOperand(0));
}
+void SelectionDAGISel::Select_MEMBARRIER(SDNode *N) {
+ CurDAG->SelectNodeTo(N, TargetOpcode::MEMBARRIER, N->getValueType(0),
+ N->getOperand(0));
+}
+
void SelectionDAGISel::pushStackMapLiveVariable(SmallVectorImpl<SDValue> &Ops,
SDValue OpVal, SDLoc DL) {
SDNode *OpNode = OpVal.getNode();
case ISD::ARITH_FENCE:
Select_ARITH_FENCE(NodeToMatch);
return;
+ case ISD::MEMBARRIER:
+ Select_MEMBARRIER(NodeToMatch);
+ return;
case ISD::STACKMAP:
Select_STACKMAP(NodeToMatch);
return;
case RISCV::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
LowerHWASAN_CHECK_MEMACCESS(*MI);
return;
- case RISCV::PseudoMemBarrier:
- OutStreamer->emitRawComment("MEMBARRIER");
- return;
}
MCInst TmpInst;
(AddiPairImmSmall AddiPair:$rs2))>;
}
-let hasSideEffects = 1, isMeta = 1 in
-def PseudoMemBarrier : Pseudo<(outs), (ins), [(membarrier)]>;
-
//===----------------------------------------------------------------------===//
// Standard extensions
//===----------------------------------------------------------------------===//
.addImm(15).addReg(SystemZ::R0D);
break;
- // Emit nothing here but a comment if we can.
- case SystemZ::MemBarrier:
- OutStreamer->emitRawComment("MEMBARRIER");
- return;
-
// We want to emit "j .+2" for traps, jumping to the relative immediate field
// of the jump instruction, which is an illegal instruction. We cannot emit a
// "." symbol, so create and emit a temp label before the instruction and use
let hasSideEffects = 1 in
def Serialize : Alias<2, (outs), (ins), []>;
-// A pseudo instruction that serves as a compiler barrier.
-let hasSideEffects = 1, hasNoSchedulingInfo = 1 in
-def MemBarrier : Pseudo<(outs), (ins), [(membarrier)]>;
-
let Predicates = [FeatureInterlockedAccess1], Defs = [CC] in {
def LAA : LoadAndOpRSY<"laa", 0xEBF8, atomic_load_add_32, GR32>;
def LAAG : LoadAndOpRSY<"laag", 0xEBE8, atomic_load_add_64, GR64>;
assert((Size ||
// These do not have a size:
MI.isDebugOrPseudoInstr() || MI.isPosition() || MI.isKill() ||
- MI.isImplicitDef() || MI.getOpcode() == SystemZ::MemBarrier ||
+ MI.isImplicitDef() || MI.getOpcode() == TargetOpcode::MEMBARRIER ||
// These have a size that may be zero:
MI.isInlineAsm() || MI.getOpcode() == SystemZ::STACKMAP ||
MI.getOpcode() == SystemZ::PATCHPOINT) &&
"# GET STACK TOP",
[(set iPTR:$dst, (GetStackTop))]>;
-// MEMBARRIER
-let hasSideEffects = 1 in
-def MEMBARRIER : Pseudo<(outs), (ins), "# MEMBARRIER", [(membarrier)] >;
-
//===----------------------------------------------------------------------===//
// Other patterns
//===----------------------------------------------------------------------===//
Requires<[Not64BitMode]>, OpSize32, LOCK,
Sched<[WriteALURMW]>;
-let hasSideEffects = 1, isMeta = 1 in
-def Int_MemBarrier : I<0, Pseudo, (outs), (ins),
- "#MEMBARRIER",
- [(membarrier)]>, Sched<[WriteLoad]>;
-
// RegOpc corresponds to the mr version of the instruction
// ImmOpc corresponds to the mi version of the instruction
// ImmOpc8 corresponds to the mi8 version of the instruction
case TargetOpcode::DBG_VALUE:
llvm_unreachable("Should be handled target independently");
- // Emit nothing here but a comment if we can.
- case X86::Int_MemBarrier:
- OutStreamer->emitRawComment("MEMBARRIER");
- return;
-
case X86::EH_RETURN:
case X86::EH_RETURN64: {
// Lower these as normal, but add some comments.
(select GRRegs:$cond, GRRegs:$T, GRRegs:$F))]>;
}
-let hasSideEffects = 1, isMeta = 1 in
-def Int_MemBarrier : PseudoInstXCore<(outs), (ins), "#MEMBARRIER",
- [(membarrier)]>;
-
//===----------------------------------------------------------------------===//
// Instructions
//===----------------------------------------------------------------------===//
; X86-ATOM-NEXT: nop
; X86-ATOM-NEXT: nop
; X86-ATOM-NEXT: nop
+; X86-ATOM-NEXT: nop
+; X86-ATOM-NEXT: nop
; X86-ATOM-NEXT: retl
atomicrmw or ptr %p, i32 0 monotonic
ret void
; X86-ATOM-NEXT: nop
; X86-ATOM-NEXT: nop
; X86-ATOM-NEXT: nop
+; X86-ATOM-NEXT: nop
+; X86-ATOM-NEXT: nop
; X86-ATOM-NEXT: retl
atomicrmw or ptr %p, i32 0 acquire
ret void
; X86-ATOM-NEXT: nop
; X86-ATOM-NEXT: nop
; X86-ATOM-NEXT: nop
+; X86-ATOM-NEXT: nop
+; X86-ATOM-NEXT: nop
; X86-ATOM-NEXT: retl
atomicrmw or ptr %p, i32 0 release
ret void
; X86-ATOM-NEXT: nop
; X86-ATOM-NEXT: nop
; X86-ATOM-NEXT: nop
+; X86-ATOM-NEXT: nop
+; X86-ATOM-NEXT: nop
; X86-ATOM-NEXT: retl
atomicrmw or ptr %p, i32 0 acq_rel
ret void
LIFETIME_END 0
PSEUDO_PROBE 6699318081062747564, 1, 0, 0
$xmm0 = ARITH_FENCE $xmm0
- Int_MemBarrier
+ MEMBARRIER
...
)MIR";