Skip to content

Commit

Permalink
rustllvm: Emit a stack map for frames with only static type descriptors
Browse files Browse the repository at this point in the history
  • Loading branch information
pcwalton committed Aug 19, 2011
1 parent d81d864 commit 4a894da
Showing 1 changed file with 159 additions and 3 deletions.
162 changes: 159 additions & 3 deletions src/rustllvm/RustGCMetadataPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
//
//===----------------------------------------------------------------------===//

#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/GCs.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/GCMetadataPrinter.h"
#include "llvm/Module.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCSymbol.h"
Expand All @@ -27,19 +29,173 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
#include <cctype>
#include <map>

using namespace llvm;

namespace {
enum RustGCMetaType {
RGCMT_DestIndex, // Type descriptor index -> type descriptor.
RGCMT_SrcIndex, // Value -> type descriptor index.
RGCMT_Static // Value with static type descriptor.
};

class RustGCMetadataPrinter : public GCMetadataPrinter {
private:
std::pair<RustGCMetaType,const Constant *>
GetGCMetadataForRoot(const GCRoot &Root);
void EmitGCMetadata(AsmPrinter &AP, MCStreamer &Out, GCRoot &Root);
bool HandleDestIndex(const GCRoot &Root);
public:
void beginAssembly(AsmPrinter &AP) {};
void finishAssembly(AsmPrinter &AP) {};
void finishAssembly(AsmPrinter &AP);
};

struct OrderedSymbol {
unsigned Index;
MCSymbol *Sym;

OrderedSymbol(unsigned I, MCSymbol *S) : Index(I), Sym(S) {}

static OrderedSymbol make(unsigned I, MCSymbol *S) {
OrderedSymbol OS(I, S);
return OS;
}
};
}

static GCMetadataPrinterRegistry::Add<RustGCMetadataPrinter>
Y("rust", "Rust GC metadata printer");
X("rust", "Rust GC metadata printer");


typedef std::vector< std::pair< MCSymbol *,std::vector<GCRoot> > > RootMap;

std::pair<RustGCMetaType,const Constant *>
RustGCMetadataPrinter::GetGCMetadataForRoot(const GCRoot &Root) {
const GlobalVariable *GCMetaVar =
cast<const GlobalVariable>(Root.Metadata->stripPointerCasts());

const Constant *GCMetaInit = GCMetaVar->getInitializer();
if (isa<ConstantAggregateZero>(GCMetaInit)) {
// "zeroinitializer": expand to (0, 0).
IntegerType *I32 = IntegerType::get(GCMetaInit->getContext(), 32);
ConstantInt *Zero = ConstantInt::get(I32, 0);
return std::make_pair(RGCMT_DestIndex, Zero);
}

const ConstantStruct *GCMeta =
cast<const ConstantStruct>(GCMetaVar->getInitializer());

RustGCMetaType GCMetaType = (RustGCMetaType)
(cast<const ConstantInt>(GCMeta->getOperand(0))->getZExtValue());
const Constant *Payload = cast<const Constant>(GCMeta->getOperand(1));
return std::make_pair(GCMetaType, Payload);
}

void RustGCMetadataPrinter::EmitGCMetadata(AsmPrinter &AP, MCStreamer &Out,
GCRoot &Root) {
int WordSize = AP.TM.getTargetData()->getPointerSize();

std::pair<RustGCMetaType,const Constant *> Pair =
GetGCMetadataForRoot(Root);
const GlobalValue *Tydesc;

switch (Pair.first) {
case RGCMT_DestIndex: // Dest index.
assert(0 && "Dest index should not be here!");
case RGCMT_SrcIndex:
// TODO: Use the mapping to find the tydesc frame offset.
Out.EmitIntValue(1, WordSize, 0);
Out.EmitIntValue(0, WordSize, 0);
return;
case 2: // Static type descriptor.
Out.EmitIntValue(0, WordSize, 0);
Tydesc = cast<const GlobalValue>(Pair.second);
break;
}

MCSymbol *TydescSym = AP.Mang->getSymbol(Tydesc);
Out.EmitSymbolValue(TydescSym, WordSize, 0);
}

// Records the destination index of a type descriptor in the type descriptor
// map, if this GC root is a destination index. Returns true if the GC root is
// a destination index and false otherwise.
bool RustGCMetadataPrinter::HandleDestIndex(const GCRoot &Root) {
std::pair<RustGCMetaType,const Constant *> Pair =
GetGCMetadataForRoot(Root);
return Pair.first == RGCMT_DestIndex; // TODO
}

void RustGCMetadataPrinter::finishAssembly(AsmPrinter &AP) {
MCStreamer &Out = AP.OutStreamer;

// Use the data section.
Out.SwitchSection(AP.getObjFileLowering().getDataSection());

// Iterate over each function.
RootMap Map;

iterator FI = begin(), FE = end();
while (FI != FE) {
GCFunctionInfo &GCFI = **FI;

// Iterate over each safe point.
GCFunctionInfo::iterator SPI = GCFI.begin(), SPE = GCFI.end();
while (SPI != SPE) {
std::vector<GCRoot> Roots;

// Iterate over each live root.
GCFunctionInfo::live_iterator LI = GCFI.live_begin(SPI);
GCFunctionInfo::live_iterator LE = GCFI.live_end(SPI);
while (LI != LE) {
if (!HandleDestIndex(*LI))
Roots.push_back(*LI);
++LI;
}

Map.push_back(std::make_pair(SPI->Label, Roots));
++SPI;
}
++FI;
}

// Write out the map.
Out.AddBlankLine();

int WordSize = AP.TM.getTargetData()->getPointerSize();

MCSymbol *SafePointSym = AP.GetExternalSymbolSymbol("rust_gc_safe_points");
Out.EmitSymbolAttribute(SafePointSym, MCSA_Global);
Out.EmitLabel(SafePointSym);
Out.EmitIntValue(Map.size(), WordSize, 0);

std::vector<MCSymbol *> FrameMapLabels;

RootMap::iterator MI = Map.begin(), ME = Map.end();
unsigned i = 0;
while (MI != ME) {
Out.EmitSymbolValue(MI->first, WordSize, 0);
MCSymbol *FrameMapLabel = AP.GetTempSymbol("rust_frame_map_label", i);
FrameMapLabels.push_back(FrameMapLabel);
++MI, ++i;
}

MI = Map.begin(), i = 0;
while (MI != ME) {
Out.EmitLabel(FrameMapLabels[i]);

std::vector<GCRoot> &Roots = MI->second;
Out.EmitIntValue(Roots.size(), WordSize, 0);

std::vector<GCRoot>::iterator RI = Roots.begin(), RE = Roots.end();
while (RI != RE) {
Out.EmitIntValue(RI->StackOffset, WordSize, 0);
EmitGCMetadata(AP, Out, *RI);
++RI;
}

++MI, ++i;
}
}

0 comments on commit 4a894da

Please sign in to comment.