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