passes: add a backend pass to insert a sentinel value to exception table

To determine if a function is a Go function, we insert a sentinel
value to the function's exception table. The runtime will check
the existence of this value (see CL 140518 for the runtime part).

Add "passes" directory, a place to put LLVM backend passes.

Change-Id: I68b38b72682bef433afd5d0de4148a19023525b7
Reviewed-on: https://go-review.googlesource.com/c/137760
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a42d27f..f40aff2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -108,6 +108,9 @@
 # Location of bridge source code.
 set(BRIDGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bridge)
 
+# Location of gollvm specific passes source code.
+set(PASSES_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/passes)
+
 # Location of driver utilities source code.
 set(DRIVER_UTILS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/driver)
 
@@ -115,6 +118,9 @@
 # calls into LLVM IR.
 add_subdirectory(bridge)
 
+# Subdirectory for gollvm specific backend passes.
+add_subdirectory(passes)
+
 # Subdirectory for compiler driver utilities library.
 add_subdirectory(driver)
 
diff --git a/driver-main/CMakeLists.txt b/driver-main/CMakeLists.txt
index a3cc685..c3c59aa 100644
--- a/driver-main/CMakeLists.txt
+++ b/driver-main/CMakeLists.txt
@@ -7,6 +7,7 @@
 set(LLVM_LINK_COMPONENTS
   DriverUtils
   CppGoFrontEnd
+  CppGoPasses
   ${LLVM_TARGETS_TO_BUILD}
   CodeGen
   Core
diff --git a/driver/CMakeLists.txt b/driver/CMakeLists.txt
index 636eba6..3426ce6 100644
--- a/driver/CMakeLists.txt
+++ b/driver/CMakeLists.txt
@@ -18,6 +18,7 @@
 # Include directories needed for this lib.
 include_directories(${GOFRONTEND_SOURCE_DIR})
 include_directories(${BRIDGE_SOURCE_DIR})
+include_directories(${PASSES_SOURCE_DIR})
 
 # Gofrontend headers use headers from these packages.
 include_directories(${EXTINSTALLDIR}/include)
diff --git a/passes/CMakeLists.txt b/passes/CMakeLists.txt
new file mode 100644
index 0000000..7e199ec
--- /dev/null
+++ b/passes/CMakeLists.txt
@@ -0,0 +1,11 @@
+
+# Copyright 2018 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Rules for building LLVMCppGoPasses library, which includes
+# gollvm specific backend passes.
+
+add_llvm_library(LLVMCppGoPasses
+  GoAnnotation.cpp
+)
diff --git a/passes/GoAnnotation.cpp b/passes/GoAnnotation.cpp
new file mode 100644
index 0000000..95f5fe3
--- /dev/null
+++ b/passes/GoAnnotation.cpp
@@ -0,0 +1,87 @@
+//===--- GoAnnotation.cpp -------------------------------------------------===//
+//
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+//===----------------------------------------------------------------------===//
+//
+// LLVM backend pass to attach auxiliary information to the
+// exception table, for the use of Go stack maps.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GoStackMap.h"
+#include "GollvmPasses.h"
+
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/PassRegistry.h"
+#include "llvm/Target/TargetMachine.h"
+
+using namespace llvm;
+
+namespace {
+
+class GoAnnotation : public MachineFunctionPass {
+ public:
+  static char ID;
+
+  GoAnnotation() : MachineFunctionPass(ID) {
+    initializeGoAnnotationPass(*PassRegistry::getPassRegistry());
+  }
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesAll();
+    MachineFunctionPass::getAnalysisUsage(AU);
+  }
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+
+ private:
+};
+
+}  // namespace
+
+char GoAnnotation::ID = 0;
+INITIALIZE_PASS(GoAnnotation, "go-annotation",
+                "Add annotations for Go code", false,
+                false)
+FunctionPass *llvm::createGoAnnotationPass() { return new GoAnnotation(); }
+
+bool
+GoAnnotation::runOnMachineFunction(MachineFunction &MF) {
+  // Create a dummy landing pad entry at the function entry PC,
+  // with a sentinel value, to mark this as a Go function.
+
+  MCContext &Context = MF.getContext();
+  const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+
+  MachineBasicBlock &EntryBB = MF.front();
+  auto MBBI = EntryBB.begin();
+  DebugLoc DL = EntryBB.findDebugLoc(MBBI);
+
+  MCSymbol *EntryLabel = Context.createTempSymbol();
+  BuildMI(EntryBB, MBBI, DL, TII->get(TargetOpcode::EH_LABEL)).addSym(EntryLabel);
+
+  // Besides begin/end labels and typeID, other fields of LPI
+  // does not really matter. We set fields that are required
+  // to make EHStreamer happy.
+  LandingPadInfo &LPI = MF.getOrCreateLandingPadInfo(&EntryBB);
+  LPI.BeginLabels.push_back(EntryLabel);
+  LPI.EndLabels.push_back(EntryLabel); // 0 size, so it doesn't capture any exception.
+  LPI.LandingPadLabel = EntryLabel;
+
+  const Function &F = MF.getFunction();
+  const Module *M = F.getParent();
+  GlobalValue *X = M->getGlobalVariable(GO_FUNC_SYM,
+                                        /* AllowInternal */ true);
+  assert(X);
+  unsigned TypeID = MF.getTypeIDFor(X);
+  LPI.TypeIds.push_back(TypeID);
+
+  return true;
+}
diff --git a/passes/GoStackMap.h b/passes/GoStackMap.h
new file mode 100644
index 0000000..298bd83
--- /dev/null
+++ b/passes/GoStackMap.h
@@ -0,0 +1,25 @@
+//===- GoStatepoints.h - --------------------------------------------------===//
+//
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_GOLLVM_PASSES_GOSTACKMAP_H
+#define LLVM_GOLLVM_PASSES_GOSTACKMAP_H
+
+// Special symbols used for stack maps.
+
+#define GO_FUNC_SYM            "go..func"
+#define GO_STACKMAP_SYM_PREFIX "go..stackmap."
+
+// A sentinel value that will be inserted to the exception table
+// to indicate this is a Go function. The value is known to the
+// runtime.
+#define GO_FUNC_SENTINEL ((uint64_t)'G' | ((uint64_t)'O'<<8) | \
+                          ((uint64_t)'.'<<16) | ((uint64_t)'.'<<24) | \
+                          ((uint64_t)'F'<<32) | ((uint64_t)'U'<<40) | \
+                          ((uint64_t)'N'<<48) | ((uint64_t)'C'<<56))
+
+#endif
diff --git a/passes/GollvmPasses.h b/passes/GollvmPasses.h
new file mode 100644
index 0000000..34eba1b
--- /dev/null
+++ b/passes/GollvmPasses.h
@@ -0,0 +1,23 @@
+//===--- GollvmPasses.h - Gollvm specific backend passes ------------------===//
+//
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_GOLLVM_PASSES_GOLLVMPASSES_H
+#define LLVM_GOLLVM_PASSES_GOLLVMPASSES_H
+
+namespace llvm {
+
+class PassRegistry;
+class FunctionPass;
+
+void initializeGoAnnotationPass(PassRegistry&);
+
+FunctionPass *createGoAnnotationPass();
+
+} // namespace llvm
+
+#endif