1477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris//===-- ErlangGCPrinter.cpp - Erlang/OTP frametable emitter -----*- C++ -*-===//
2477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris//
3477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris//                     The LLVM Compiler Infrastructure
4477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris//
5477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris// This file is distributed under the University of Illinois Open Source
6477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris// License. See LICENSE.TXT for details.
7477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris//
8477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris//===----------------------------------------------------------------------===//
9477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris//
10477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris// This file implements the compiler plugin that is used in order to emit
11477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris// garbage collection information in a convenient layout for parsing and
12477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris// loading in the Erlang/OTP runtime.
13477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris//
14477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris//===----------------------------------------------------------------------===//
15477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
16477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/CodeGen/AsmPrinter.h"
17477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/CodeGen/GCMetadataPrinter.h"
1836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/CodeGen/GCs.h"
19477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/IR/DataLayout.h"
20477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/IR/Function.h"
21477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/IR/Instruction.h"
22477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/IR/IntrinsicInst.h"
23477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/IR/Metadata.h"
24477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/MC/MCAsmInfo.h"
25477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/MC/MCContext.h"
26477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/MC/MCSectionELF.h"
27477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/MC/MCStreamer.h"
28477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/MC/MCSymbol.h"
29477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/Target/TargetLoweringObjectFile.h"
30477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris#include "llvm/Target/TargetMachine.h"
31477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
32477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiourisusing namespace llvm;
33477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
34477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiourisnamespace {
35477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
36477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris  class ErlangGCPrinter : public GCMetadataPrinter {
37477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris  public:
3836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    void beginAssembly(AsmPrinter &AP) override;
3936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    void finishAssembly(AsmPrinter &AP) override;
40477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris  };
41477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
42477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris}
43477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
44477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiourisstatic GCMetadataPrinterRegistry::Add<ErlangGCPrinter>
45477de3a7859104d7c41a36628169e13e524e980aYiannis TsiourisX("erlang", "erlang-compatible garbage collector");
46477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
47477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiourisvoid llvm::linkErlangGCPrinter() { }
48477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
49477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiourisvoid ErlangGCPrinter::beginAssembly(AsmPrinter &AP) { }
50477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
51477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiourisvoid ErlangGCPrinter::finishAssembly(AsmPrinter &AP) {
52477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris  MCStreamer &OS = AP.OutStreamer;
53477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris  unsigned IntPtrSize = AP.TM.getDataLayout()->getPointerSize();
54477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
55477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris  // Put this in a custom .note section.
56477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris  AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getContext()
57477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    .getELFSection(".note.gc", ELF::SHT_PROGBITS, 0,
58477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris                   SectionKind::getDataRel()));
59477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
60477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris  // For each function...
61477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris  for (iterator FI = begin(), FE = end(); FI != FE; ++FI) {
62477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    GCFunctionInfo &MD = **FI;
63477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
64477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    /** A compact GC layout. Emit this data structure:
65477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris     *
66477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris     * struct {
67477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris     *   int16_t PointCount;
68477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris     *   void *SafePointAddress[PointCount];
69477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris     *   int16_t StackFrameSize; (in words)
70477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris     *   int16_t StackArity;
71477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris     *   int16_t LiveCount;
72477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris     *   int16_t LiveOffsets[LiveCount];
73477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris     * } __gcmap_<FUNCTIONNAME>;
74477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris     **/
75477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
76477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    // Align to address width.
77477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
78477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
79477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    // Emit PointCount.
80477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    OS.AddComment("safe point count");
81477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    AP.EmitInt16(MD.size());
82477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
83477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    // And each safe point...
84477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    for (GCFunctionInfo::iterator PI = MD.begin(), PE = MD.end(); PI != PE;
85477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris         ++PI) {
86477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris      // Emit the address of the safe point.
87477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris      OS.AddComment("safe point address");
88477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris      MCSymbol *Label = PI->Label;
89477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris      AP.EmitLabelPlusOffset(Label/*Hi*/, 0/*Offset*/, 4/*Size*/);
90477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    }
91477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
92477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    // Stack information never change in safe points! Only print info from the
93477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    // first call-site.
94477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    GCFunctionInfo::iterator PI = MD.begin();
95477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
96477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    // Emit the stack frame size.
97477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    OS.AddComment("stack frame size (in words)");
98477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    AP.EmitInt16(MD.getFrameSize() / IntPtrSize);
99477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
100477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    // Emit stack arity, i.e. the number of stacked arguments.
101477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6;
102477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs ?
103477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris                          MD.getFunction().arg_size() - RegisteredArgs : 0;
104477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    OS.AddComment("stack arity");
105477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    AP.EmitInt16(StackArity);
106477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
107477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    // Emit the number of live roots in the function.
108477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    OS.AddComment("live root count");
109477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    AP.EmitInt16(MD.live_size(PI));
110477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris
111477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    // And for each live root...
112477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    for (GCFunctionInfo::live_iterator LI = MD.live_begin(PI),
113477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris                                       LE = MD.live_end(PI);
114477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris                                       LI != LE; ++LI) {
115477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris      // Emit live root's offset within the stack frame.
116477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris      OS.AddComment("stack index (offset / wordsize)");
117477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris      AP.EmitInt16(LI->StackOffset / IntPtrSize);
118477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris    }
119477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris  }
120477de3a7859104d7c41a36628169e13e524e980aYiannis Tsiouris}
121