summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp4
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp97
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td10
3 files changed, 107 insertions, 4 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index 565438d7e0e..7f9d41da397 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -369,6 +369,10 @@ void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
OutStreamer->AddBlankLine();
}
break;
+ case WebAssembly::COMPILER_FENCE:
+ // This is a compiler barrier that prevents instruction reordering during
+ // backend compilation, and should not be emitted.
+ break;
case WebAssembly::EXTRACT_EXCEPTION_I32:
case WebAssembly::EXTRACT_EXCEPTION_I32_S:
// These are pseudo instructions that simulates popping values from stack.
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
index 852e2e72f97..bd699d92f76 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
@@ -77,14 +77,103 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
return;
}
- // Few custom selection stuff. If we need WebAssembly-specific selection,
- // uncomment this block add corresponding case statements.
- /*
+ // Few custom selection stuff.
+ SDLoc DL(Node);
+ MachineFunction &MF = CurDAG->getMachineFunction();
switch (Node->getOpcode()) {
+ case ISD::ATOMIC_FENCE: {
+ if (!MF.getSubtarget<WebAssemblySubtarget>().hasAtomics())
+ break;
+
+ uint64_t SyncScopeID =
+ cast<ConstantSDNode>(Node->getOperand(2).getNode())->getZExtValue();
+ switch (SyncScopeID) {
+ case SyncScope::SingleThread: {
+ // We lower a single-thread fence to a pseudo compiler barrier instruction
+ // preventing instruction reordering. This will not be emitted in final
+ // binary.
+ MachineSDNode *Fence =
+ CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,
+ DL, // debug loc
+ MVT::Other, // outchain type
+ Node->getOperand(0) // inchain
+ );
+ ReplaceNode(Node, Fence);
+ CurDAG->RemoveDeadNode(Node);
+ return;
+ }
+
+ case SyncScope::System: {
+ // For non-emscripten systems, we have not decided on what we should
+ // traslate fences to yet.
+ if (!Subtarget->getTargetTriple().isOSEmscripten())
+ report_fatal_error(
+ "ATOMIC_FENCE is not yet supported in non-emscripten OSes");
+
+ // Wasm does not have a fence instruction, but because all atomic
+ // instructions in wasm are sequentially consistent, we translate a
+ // fence to an idempotent atomic RMW instruction to a linear memory
+ // address. All atomic instructions in wasm are sequentially consistent,
+ // but this is to ensure a fence also prevents reordering of non-atomic
+ // instructions in the VM. Even though LLVM IR's fence instruction does
+ // not say anything about its relationship with non-atomic instructions,
+ // we think this is more user-friendly.
+ //
+ // While any address can work, here we use a value stored in
+ // __stack_pointer wasm global because there's high chance that area is
+ // in cache.
+ //
+ // So the selected instructions will be in the form of:
+ // %addr = get_global $__stack_pointer
+ // %0 = i32.const 0
+ // i32.atomic.rmw.or %addr, %0
+ SDValue StackPtrSym = CurDAG->getTargetExternalSymbol(
+ "__stack_pointer", TLI->getPointerTy(CurDAG->getDataLayout()));
+ MachineSDNode *GetGlobal =
+ CurDAG->getMachineNode(WebAssembly::GLOBAL_GET_I32, // opcode
+ DL, // debug loc
+ MVT::i32, // result type
+ StackPtrSym // __stack_pointer symbol
+ );
+
+ SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i32);
+ auto *MMO = MF.getMachineMemOperand(
+ MachinePointerInfo::getUnknownStack(MF),
+ // FIXME Volatile isn't really correct, but currently all LLVM
+ // atomic instructions are treated as volatiles in the backend, so
+ // we should be consistent.
+ MachineMemOperand::MOVolatile | MachineMemOperand::MOLoad |
+ MachineMemOperand::MOStore,
+ 4, 4, AAMDNodes(), nullptr, SyncScope::System,
+ AtomicOrdering::SequentiallyConsistent);
+ MachineSDNode *Const0 =
+ CurDAG->getMachineNode(WebAssembly::CONST_I32, DL, MVT::i32, Zero);
+ MachineSDNode *AtomicRMW = CurDAG->getMachineNode(
+ WebAssembly::ATOMIC_RMW_OR_I32, // opcode
+ DL, // debug loc
+ MVT::i32, // result type
+ MVT::Other, // outchain type
+ {
+ Zero, // alignment
+ Zero, // offset
+ SDValue(GetGlobal, 0), // __stack_pointer
+ SDValue(Const0, 0), // OR with 0 to make it idempotent
+ Node->getOperand(0) // inchain
+ });
+
+ CurDAG->setNodeMemRefs(AtomicRMW, {MMO});
+ ReplaceUses(SDValue(Node, 0), SDValue(AtomicRMW, 1));
+ CurDAG->RemoveDeadNode(Node);
+ return;
+ }
+ default:
+ llvm_unreachable("Unknown scope!");
+ }
+ }
+
default:
break;
}
- */
// Select the default instruction.
SelectCode(Node);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
index 86ed5eff955..e85aa57efc4 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
@@ -887,3 +887,13 @@ defm : TerRMWTruncExtPattern<
ATOMIC_RMW8_U_CMPXCHG_I32, ATOMIC_RMW16_U_CMPXCHG_I32,
ATOMIC_RMW8_U_CMPXCHG_I64, ATOMIC_RMW16_U_CMPXCHG_I64,
ATOMIC_RMW32_U_CMPXCHG_I64>;
+
+//===----------------------------------------------------------------------===//
+// Atomic fences
+//===----------------------------------------------------------------------===//
+
+// A compiler fence instruction that prevents reordering of instructions.
+let Defs = [ARGUMENTS] in {
+let isPseudo = 1, hasSideEffects = 1 in
+defm COMPILER_FENCE : ATOMIC_NRI<(outs), (ins), [], "compiler_fence">;
+} // Defs = [ARGUMENTS]
OpenPOWER on IntegriCloud