mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-14 15:39:06 +00:00
Add a GC plugin for Erlang
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@177867 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2269c56a3c
commit
477de3a785
@ -26,6 +26,12 @@ namespace llvm {
|
||||
|
||||
/// Creates an ocaml-compatible metadata printer.
|
||||
void linkOcamlGCPrinter();
|
||||
|
||||
/// Creates an erlang-compatible garbage collector.
|
||||
void linkErlangGC();
|
||||
|
||||
/// Creates an erlang-compatible metadata printer.
|
||||
void linkErlangGCPrinter();
|
||||
|
||||
/// Creates a shadow stack garbage collector. This collector requires no code
|
||||
/// generator support.
|
||||
|
@ -29,6 +29,7 @@ namespace {
|
||||
return;
|
||||
|
||||
llvm::linkOcamlGCPrinter();
|
||||
llvm::linkErlangGCPrinter();
|
||||
|
||||
}
|
||||
} ForceAsmWriterLinking; // Force link by creating a global definition.
|
||||
|
@ -37,6 +37,7 @@ namespace {
|
||||
(void) llvm::createDefaultPBQPRegisterAllocator();
|
||||
|
||||
llvm::linkOcamlGC();
|
||||
llvm::linkErlangGC();
|
||||
llvm::linkShadowStackGC();
|
||||
|
||||
(void) llvm::createBURRListDAGScheduler(NULL, llvm::CodeGenOpt::Default);
|
||||
|
120
lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp
Normal file
120
lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
//===-- ErlangGCPrinter.cpp - Erlang/OTP frametable emitter -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the compiler plugin that is used in order to emit
|
||||
// garbage collection information in a convenient layout for parsing and
|
||||
// loading in the Erlang/OTP runtime.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/GCs.h"
|
||||
#include "llvm/CodeGen/GCMetadataPrinter.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCSectionELF.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Target/TargetLoweringObjectFile.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class ErlangGCPrinter : public GCMetadataPrinter {
|
||||
public:
|
||||
void beginAssembly(AsmPrinter &AP);
|
||||
void finishAssembly(AsmPrinter &AP);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static GCMetadataPrinterRegistry::Add<ErlangGCPrinter>
|
||||
X("erlang", "erlang-compatible garbage collector");
|
||||
|
||||
void llvm::linkErlangGCPrinter() { }
|
||||
|
||||
void ErlangGCPrinter::beginAssembly(AsmPrinter &AP) { }
|
||||
|
||||
void ErlangGCPrinter::finishAssembly(AsmPrinter &AP) {
|
||||
MCStreamer &OS = AP.OutStreamer;
|
||||
unsigned IntPtrSize = AP.TM.getDataLayout()->getPointerSize();
|
||||
|
||||
// Put this in a custom .note section.
|
||||
AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getContext()
|
||||
.getELFSection(".note.gc", ELF::SHT_PROGBITS, 0,
|
||||
SectionKind::getDataRel()));
|
||||
|
||||
// For each function...
|
||||
for (iterator FI = begin(), FE = end(); FI != FE; ++FI) {
|
||||
GCFunctionInfo &MD = **FI;
|
||||
|
||||
/** A compact GC layout. Emit this data structure:
|
||||
*
|
||||
* struct {
|
||||
* int16_t PointCount;
|
||||
* void *SafePointAddress[PointCount];
|
||||
* int16_t StackFrameSize; (in words)
|
||||
* int16_t StackArity;
|
||||
* int16_t LiveCount;
|
||||
* int16_t LiveOffsets[LiveCount];
|
||||
* } __gcmap_<FUNCTIONNAME>;
|
||||
**/
|
||||
|
||||
// Align to address width.
|
||||
AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
|
||||
|
||||
// Emit PointCount.
|
||||
OS.AddComment("safe point count");
|
||||
AP.EmitInt16(MD.size());
|
||||
|
||||
// And each safe point...
|
||||
for (GCFunctionInfo::iterator PI = MD.begin(), PE = MD.end(); PI != PE;
|
||||
++PI) {
|
||||
// Emit the address of the safe point.
|
||||
OS.AddComment("safe point address");
|
||||
MCSymbol *Label = PI->Label;
|
||||
AP.EmitLabelPlusOffset(Label/*Hi*/, 0/*Offset*/, 4/*Size*/);
|
||||
}
|
||||
|
||||
// Stack information never change in safe points! Only print info from the
|
||||
// first call-site.
|
||||
GCFunctionInfo::iterator PI = MD.begin();
|
||||
|
||||
// Emit the stack frame size.
|
||||
OS.AddComment("stack frame size (in words)");
|
||||
AP.EmitInt16(MD.getFrameSize() / IntPtrSize);
|
||||
|
||||
// Emit stack arity, i.e. the number of stacked arguments.
|
||||
unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6;
|
||||
unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs ?
|
||||
MD.getFunction().arg_size() - RegisteredArgs : 0;
|
||||
OS.AddComment("stack arity");
|
||||
AP.EmitInt16(StackArity);
|
||||
|
||||
// Emit the number of live roots in the function.
|
||||
OS.AddComment("live root count");
|
||||
AP.EmitInt16(MD.live_size(PI));
|
||||
|
||||
// And for each live root...
|
||||
for (GCFunctionInfo::live_iterator LI = MD.live_begin(PI),
|
||||
LE = MD.live_end(PI);
|
||||
LI != LE; ++LI) {
|
||||
// Emit live root's offset within the stack frame.
|
||||
OS.AddComment("stack index (offset / wordsize)");
|
||||
AP.EmitInt16(LI->StackOffset / IntPtrSize);
|
||||
}
|
||||
}
|
||||
}
|
81
lib/CodeGen/ErlangGC.cpp
Normal file
81
lib/CodeGen/ErlangGC.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
//===-- ErlangGC.cpp - Erlang/OTP GC strategy -------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the Erlang/OTP runtime-compatible garbage collector
|
||||
// (e.g. defines safe points, root initialization etc.)
|
||||
//
|
||||
// The frametable emitter is in ErlangGCPrinter.cpp.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/GCs.h"
|
||||
#include "llvm/CodeGen/GCStrategy.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class ErlangGC : public GCStrategy {
|
||||
MCSymbol *InsertLabel(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
DebugLoc DL) const;
|
||||
public:
|
||||
ErlangGC();
|
||||
bool findCustomSafePoints(GCFunctionInfo &FI, MachineFunction &MF);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static GCRegistry::Add<ErlangGC>
|
||||
X("erlang", "erlang-compatible garbage collector");
|
||||
|
||||
void llvm::linkErlangGC() { }
|
||||
|
||||
ErlangGC::ErlangGC() {
|
||||
InitRoots = false;
|
||||
NeededSafePoints = 1 << GC::PostCall;
|
||||
UsesMetadata = true;
|
||||
CustomRoots = false;
|
||||
CustomSafePoints = true;
|
||||
}
|
||||
|
||||
MCSymbol *ErlangGC::InsertLabel(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
DebugLoc DL) const {
|
||||
const TargetInstrInfo* TII = MBB.getParent()->getTarget().getInstrInfo();
|
||||
MCSymbol *Label = MBB.getParent()->getContext().CreateTempSymbol();
|
||||
BuildMI(MBB, MI, DL, TII->get(TargetOpcode::GC_LABEL)).addSym(Label);
|
||||
return Label;
|
||||
}
|
||||
|
||||
bool ErlangGC::findCustomSafePoints(GCFunctionInfo &FI, MachineFunction &MF) {
|
||||
for (MachineFunction::iterator BBI = MF.begin(), BBE = MF.end(); BBI != BBE;
|
||||
++BBI)
|
||||
for (MachineBasicBlock::iterator MI = BBI->begin(), ME = BBI->end();
|
||||
MI != ME; ++MI)
|
||||
|
||||
if (MI->getDesc().isCall()) {
|
||||
|
||||
// Do not treat tail call sites as safe points.
|
||||
if (MI->getDesc().isTerminator())
|
||||
continue;
|
||||
|
||||
/* Code copied from VisitCallPoint(...) */
|
||||
MachineBasicBlock::iterator RAI = MI; ++RAI;
|
||||
MCSymbol* Label = InsertLabel(*MI->getParent(), RAI, MI->getDebugLoc());
|
||||
FI.addSafePoint(GC::PostCall, Label, MI->getDebugLoc());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
25
test/CodeGen/X86/GC/erlang-gc.ll
Normal file
25
test/CodeGen/X86/GC/erlang-gc.ll
Normal file
@ -0,0 +1,25 @@
|
||||
; RUN: llc -mtriple=x86_64-linux-gnu < %s | FileCheck %s --check-prefix=CHECK64
|
||||
; RUN: llc -mtriple=i686-linux-gnu < %s | FileCheck %s --check-prefix=CHECK32
|
||||
|
||||
define i32 @main(i32 %x) nounwind gc "erlang" {
|
||||
%puts = tail call i32 @foo(i32 %x)
|
||||
ret i32 0
|
||||
|
||||
; CHECK64: .section .note.gc,"",@progbits
|
||||
; CHECK64-NEXT: .align 8
|
||||
; CHECK64-NEXT: .short 1 # safe point count
|
||||
; CHECK64-NEXT: .long .Ltmp0 # safe point address
|
||||
; CHECK64-NEXT: .short 1 # stack frame size (in words)
|
||||
; CHECK64-NEXT: .short 0 # stack arity
|
||||
; CHECK64-NEXT: .short 0 # live root count
|
||||
|
||||
; CHECK32: .section .note.gc,"",@progbits
|
||||
; CHECK32-NEXT: .align 4
|
||||
; CHECK32-NEXT: .short 1 # safe point count
|
||||
; CHECK32-NEXT: .long .Ltmp0 # safe point address
|
||||
; CHECK32-NEXT: .short 3 # stack frame size (in words)
|
||||
; CHECK32-NEXT: .short 0 # stack arity
|
||||
; CHECK32-NEXT: .short 0 # live root count
|
||||
}
|
||||
|
||||
declare i32 @foo(i32)
|
Loading…
Reference in New Issue
Block a user