LLVM API Documentation
00001 //===-- ErlangGCPrinter.cpp - Erlang/OTP frametable emitter -----*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements the compiler plugin that is used in order to emit 00011 // garbage collection information in a convenient layout for parsing and 00012 // loading in the Erlang/OTP runtime. 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #include "llvm/CodeGen/AsmPrinter.h" 00017 #include "llvm/CodeGen/GCMetadataPrinter.h" 00018 #include "llvm/CodeGen/GCs.h" 00019 #include "llvm/IR/DataLayout.h" 00020 #include "llvm/IR/Function.h" 00021 #include "llvm/IR/Instruction.h" 00022 #include "llvm/IR/IntrinsicInst.h" 00023 #include "llvm/IR/Metadata.h" 00024 #include "llvm/MC/MCAsmInfo.h" 00025 #include "llvm/MC/MCContext.h" 00026 #include "llvm/MC/MCSectionELF.h" 00027 #include "llvm/MC/MCStreamer.h" 00028 #include "llvm/MC/MCSymbol.h" 00029 #include "llvm/Target/TargetLoweringObjectFile.h" 00030 #include "llvm/Target/TargetMachine.h" 00031 #include "llvm/Target/TargetSubtargetInfo.h" 00032 00033 using namespace llvm; 00034 00035 namespace { 00036 00037 class ErlangGCPrinter : public GCMetadataPrinter { 00038 public: 00039 void beginAssembly(AsmPrinter &AP) override; 00040 void finishAssembly(AsmPrinter &AP) override; 00041 }; 00042 00043 } 00044 00045 static GCMetadataPrinterRegistry::Add<ErlangGCPrinter> 00046 X("erlang", "erlang-compatible garbage collector"); 00047 00048 void llvm::linkErlangGCPrinter() { } 00049 00050 void ErlangGCPrinter::beginAssembly(AsmPrinter &AP) { } 00051 00052 void ErlangGCPrinter::finishAssembly(AsmPrinter &AP) { 00053 MCStreamer &OS = AP.OutStreamer; 00054 unsigned IntPtrSize = 00055 AP.TM.getSubtargetImpl()->getDataLayout()->getPointerSize(); 00056 00057 // Put this in a custom .note section. 00058 AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getContext() 00059 .getELFSection(".note.gc", ELF::SHT_PROGBITS, 0, 00060 SectionKind::getDataRel())); 00061 00062 // For each function... 00063 for (iterator FI = begin(), FE = end(); FI != FE; ++FI) { 00064 GCFunctionInfo &MD = **FI; 00065 00066 /** A compact GC layout. Emit this data structure: 00067 * 00068 * struct { 00069 * int16_t PointCount; 00070 * void *SafePointAddress[PointCount]; 00071 * int16_t StackFrameSize; (in words) 00072 * int16_t StackArity; 00073 * int16_t LiveCount; 00074 * int16_t LiveOffsets[LiveCount]; 00075 * } __gcmap_<FUNCTIONNAME>; 00076 **/ 00077 00078 // Align to address width. 00079 AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); 00080 00081 // Emit PointCount. 00082 OS.AddComment("safe point count"); 00083 AP.EmitInt16(MD.size()); 00084 00085 // And each safe point... 00086 for (GCFunctionInfo::iterator PI = MD.begin(), PE = MD.end(); PI != PE; 00087 ++PI) { 00088 // Emit the address of the safe point. 00089 OS.AddComment("safe point address"); 00090 MCSymbol *Label = PI->Label; 00091 AP.EmitLabelPlusOffset(Label/*Hi*/, 0/*Offset*/, 4/*Size*/); 00092 } 00093 00094 // Stack information never change in safe points! Only print info from the 00095 // first call-site. 00096 GCFunctionInfo::iterator PI = MD.begin(); 00097 00098 // Emit the stack frame size. 00099 OS.AddComment("stack frame size (in words)"); 00100 AP.EmitInt16(MD.getFrameSize() / IntPtrSize); 00101 00102 // Emit stack arity, i.e. the number of stacked arguments. 00103 unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6; 00104 unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs ? 00105 MD.getFunction().arg_size() - RegisteredArgs : 0; 00106 OS.AddComment("stack arity"); 00107 AP.EmitInt16(StackArity); 00108 00109 // Emit the number of live roots in the function. 00110 OS.AddComment("live root count"); 00111 AP.EmitInt16(MD.live_size(PI)); 00112 00113 // And for each live root... 00114 for (GCFunctionInfo::live_iterator LI = MD.live_begin(PI), 00115 LE = MD.live_end(PI); 00116 LI != LE; ++LI) { 00117 // Emit live root's offset within the stack frame. 00118 OS.AddComment("stack index (offset / wordsize)"); 00119 AP.EmitInt16(LI->StackOffset / IntPtrSize); 00120 } 00121 } 00122 }