void OcamlGCMetadataPrinter::beginAssembly(AsmPrinter &AP) { AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getTextSection()); EmitCamlGlobal(getModule(), AP, "code_begin"); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(getModule(), AP, "data_begin"); }
void OcamlGCMetadataPrinter::beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) { AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection()); EmitCamlGlobal(M, AP, "code_begin"); AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(M, AP, "data_begin"); }
void llvm::LowerPPCMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, AsmPrinter &AP, bool isDarwin) { OutMI.setOpcode(MI->getOpcode()); for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); MCOperand MCOp; switch (MO.getType()) { default: MI->dump(); llvm_unreachable("unknown operand type"); case MachineOperand::MO_Register: assert(!MO.getSubReg() && "Subregs should be eliminated!"); assert(MO.getReg() > PPC::NoRegister && MO.getReg() < PPC::NUM_TARGET_REGS && "Invalid register for this target!"); MCOp = MCOperand::createReg(MO.getReg()); break; case MachineOperand::MO_Immediate: MCOp = MCOperand::createImm(MO.getImm()); break; case MachineOperand::MO_MachineBasicBlock: MCOp = MCOperand::createExpr(MCSymbolRefExpr::create( MO.getMBB()->getSymbol(), AP.OutContext)); break; case MachineOperand::MO_GlobalAddress: case MachineOperand::MO_ExternalSymbol: MCOp = GetSymbolRef(MO, GetSymbolFromOperand(MO, AP), AP, isDarwin); break; case MachineOperand::MO_JumpTableIndex: MCOp = GetSymbolRef(MO, AP.GetJTISymbol(MO.getIndex()), AP, isDarwin); break; case MachineOperand::MO_ConstantPoolIndex: MCOp = GetSymbolRef(MO, AP.GetCPISymbol(MO.getIndex()), AP, isDarwin); break; case MachineOperand::MO_BlockAddress: MCOp = GetSymbolRef(MO,AP.GetBlockAddressSymbol(MO.getBlockAddress()),AP, isDarwin); break; case MachineOperand::MO_RegisterMask: continue; } OutMI.addOperand(MCOp); } }
// Emit addresses into the section given. void AddressPool::emit(AsmPrinter &Asm, MCSection *AddrSection) { if (Pool.empty()) return; // Start the dwarf addr section. Asm.OutStreamer->SwitchSection(AddrSection); // Order the address pool entries by ID SmallVector<const MCExpr *, 64> Entries(Pool.size()); for (const auto &I : Pool) Entries[I.second.Number] = I.second.TLS ? Asm.getObjFileLowering().getDebugThreadLocalSymbol(I.first) : MCSymbolRefExpr::Create(I.first, Asm.OutContext); for (const MCExpr *Entry : Entries) Asm.OutStreamer->EmitValue(Entry, Asm.getDataLayout().getPointerSize()); }
bool DebugLocStream::finalizeList(AsmPrinter &Asm) { if (Lists.back().EntryOffset == Entries.size()) { // Empty list. Delete it. Lists.pop_back(); return false; } // Real list. Generate a label for it. Lists.back().Label = Asm.createTempSymbol("debug_loc"); return true; }
bool llvm::LowerRISCVMachineOperandToMCOperand(const MachineOperand &MO, MCOperand &MCOp, const AsmPrinter &AP) { switch (MO.getType()) { default: report_fatal_error("LowerRISCVMachineInstrToMCInst: unknown operand type"); case MachineOperand::MO_Register: // Ignore all implicit register operands. if (MO.isImplicit()) return false; MCOp = MCOperand::createReg(MO.getReg()); break; case MachineOperand::MO_RegisterMask: // Regmasks are like implicit defs. return false; case MachineOperand::MO_Immediate: MCOp = MCOperand::createImm(MO.getImm()); break; case MachineOperand::MO_MachineBasicBlock: MCOp = lowerSymbolOperand(MO, MO.getMBB()->getSymbol(), AP); break; case MachineOperand::MO_GlobalAddress: MCOp = lowerSymbolOperand(MO, AP.getSymbol(MO.getGlobal()), AP); break; case MachineOperand::MO_BlockAddress: MCOp = lowerSymbolOperand( MO, AP.GetBlockAddressSymbol(MO.getBlockAddress()), AP); break; case MachineOperand::MO_ExternalSymbol: MCOp = lowerSymbolOperand( MO, AP.GetExternalSymbolSymbol(MO.getSymbolName()), AP); break; case MachineOperand::MO_ConstantPoolIndex: MCOp = lowerSymbolOperand(MO, AP.GetCPISymbol(MO.getIndex()), AP); break; } return true; }
bool llvm::LowerPPCMachineOperandToMCOperand(const MachineOperand &MO, MCOperand &OutMO, AsmPrinter &AP, bool isDarwin) { switch (MO.getType()) { default: llvm_unreachable("unknown operand type"); case MachineOperand::MO_Register: assert(!MO.getSubReg() && "Subregs should be eliminated!"); assert(MO.getReg() > PPC::NoRegister && MO.getReg() < PPC::NUM_TARGET_REGS && "Invalid register for this target!"); OutMO = MCOperand::createReg(MO.getReg()); return true; case MachineOperand::MO_Immediate: OutMO = MCOperand::createImm(MO.getImm()); return true; case MachineOperand::MO_MachineBasicBlock: OutMO = MCOperand::createExpr( MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), AP.OutContext)); return true; case MachineOperand::MO_GlobalAddress: case MachineOperand::MO_ExternalSymbol: OutMO = GetSymbolRef(MO, GetSymbolFromOperand(MO, AP), AP, isDarwin); return true; case MachineOperand::MO_JumpTableIndex: OutMO = GetSymbolRef(MO, AP.GetJTISymbol(MO.getIndex()), AP, isDarwin); return true; case MachineOperand::MO_ConstantPoolIndex: OutMO = GetSymbolRef(MO, AP.GetCPISymbol(MO.getIndex()), AP, isDarwin); return true; case MachineOperand::MO_BlockAddress: OutMO = GetSymbolRef(MO, AP.GetBlockAddressSymbol(MO.getBlockAddress()), AP, isDarwin); return true; case MachineOperand::MO_RegisterMask: return false; } }
DwarfStringPool::EntryRef DwarfStringPool::getEntry(AsmPrinter &Asm, StringRef Str) { auto I = Pool.insert(std::make_pair(Str, EntryTy())); if (I.second) { auto &Entry = I.first->second; Entry.Index = Pool.size() - 1; Entry.Offset = NumBytes; Entry.Symbol = ShouldCreateSymbols ? Asm.createTempSymbol(Prefix) : nullptr; NumBytes += Str.size() + 1; assert(NumBytes > Entry.Offset && "Unexpected overflow"); } return EntryRef(*I.first); }
static MCOperand LowerSymbolOperand(const MachineInstr *MI, const MachineOperand &MO, AsmPrinter &AP) { SparcMCExpr::VariantKind Kind = (SparcMCExpr::VariantKind)MO.getTargetFlags(); const MCSymbol *Symbol = nullptr; switch(MO.getType()) { default: llvm_unreachable("Unknown type in LowerSymbolOperand"); case MachineOperand::MO_MachineBasicBlock: Symbol = MO.getMBB()->getSymbol(); break; case MachineOperand::MO_GlobalAddress: Symbol = AP.getSymbol(MO.getGlobal()); break; case MachineOperand::MO_BlockAddress: Symbol = AP.GetBlockAddressSymbol(MO.getBlockAddress()); break; case MachineOperand::MO_ExternalSymbol: Symbol = AP.GetExternalSymbolSymbol(MO.getSymbolName()); break; case MachineOperand::MO_ConstantPoolIndex: Symbol = AP.GetCPISymbol(MO.getIndex()); break; } const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Symbol, AP.OutContext); const SparcMCExpr *expr = SparcMCExpr::Create(Kind, MCSym, AP.OutContext); return MCOperand::createExpr(expr); }
/// emitAssembly - Print the frametable. The ocaml frametable format is thus: /// /// extern "C" struct align(sizeof(intptr_t)) { /// uint16_t NumDescriptors; /// struct align(sizeof(intptr_t)) { /// void *ReturnAddress; /// uint16_t FrameSize; /// uint16_t NumLiveOffsets; /// uint16_t LiveOffsets[NumLiveOffsets]; /// } Descriptors[NumDescriptors]; /// } caml${module}__frametable; /// /// Note that this precludes programs from stack frames larger than 64K /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if /// either condition is detected in a function which uses the GC. /// void OcamlGCMetadataPrinter::finishAssembly(AsmPrinter &AP) { unsigned IntPtrSize = AP.TM.getTargetData()->getPointerSize(); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getTextSection()); EmitCamlGlobal(getModule(), AP, "code_end"); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(getModule(), AP, "data_end"); // FIXME: Why does ocaml emit this?? AP.OutStreamer.EmitIntValue(0, IntPtrSize, 0); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(getModule(), AP, "frametable"); for (iterator I = begin(), IE = end(); I != IE; ++I) { GCFunctionInfo &FI = **I; uint64_t FrameSize = FI.getFrameSize(); if (FrameSize >= 1<<16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " "Frame size " + Twine(FrameSize) + ">= 65536.\n" "(" + Twine(uintptr_t(&FI)) + ")"); } AP.OutStreamer.AddComment("live roots for " + Twine(FI.getFunction().getName())); AP.OutStreamer.AddBlankLine(); for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { size_t LiveCount = FI.live_size(J); if (LiveCount >= 1<<16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " "Live root count "+Twine(LiveCount)+" >= 65536."); } AP.OutStreamer.EmitSymbolValue(J->Label, IntPtrSize, 0); AP.EmitInt16(FrameSize); AP.EmitInt16(LiveCount); for (GCFunctionInfo::live_iterator K = FI.live_begin(J), KE = FI.live_end(J); K != KE; ++K) { assert(K->StackOffset < 1<<16 && "GC root stack offset is outside of fixed stack frame and out " "of range for ocaml GC!"); AP.EmitInt32(K->StackOffset); } AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); } } }
void DwarfStringPool::emit(AsmPrinter &Asm, MCSection *StrSection, MCSection *OffsetSection, bool UseRelativeOffsets) { if (Pool.empty()) return; // Start the dwarf str section. Asm.OutStreamer->SwitchSection(StrSection); // Get all of the string pool entries and put them in an array by their ID so // we can sort them. SmallVector<const StringMapEntry<EntryTy> *, 64> Entries(Pool.size()); for (const auto &E : Pool) Entries[E.getValue().Index] = &E; for (const auto &Entry : Entries) { assert(ShouldCreateSymbols == static_cast<bool>(Entry->getValue().Symbol) && "Mismatch between setting and entry"); // Emit a label for reference from debug information entries. if (ShouldCreateSymbols) Asm.OutStreamer->EmitLabel(Entry->getValue().Symbol); // Emit the string itself with a terminating null byte. Asm.OutStreamer->AddComment("string offset=" + Twine(Entry->getValue().Offset)); Asm.OutStreamer->EmitBytes( StringRef(Entry->getKeyData(), Entry->getKeyLength() + 1)); } // If we've got an offset section go ahead and emit that now as well. if (OffsetSection) { Asm.OutStreamer->SwitchSection(OffsetSection); unsigned size = 4; // FIXME: DWARF64 is 8. for (const auto &Entry : Entries) if (UseRelativeOffsets) Asm.emitDwarfStringOffset(Entry->getValue()); else Asm.OutStreamer->EmitIntValue(Entry->getValue().Offset, size); } }
void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) { MCStreamer &OS = *AP.OutStreamer; unsigned IntPtrSize = M.getDataLayout().getPointerSize(); // Put this in a custom .note section. OS.SwitchSection( AP.getObjFileLowering().getContext().getELFSection(".note.gc", ELF::SHT_PROGBITS, 0)); // For each function... for (GCModuleInfo::FuncInfoVec::iterator FI = Info.funcinfo_begin(), IE = Info.funcinfo_end(); FI != IE; ++FI) { GCFunctionInfo &MD = **FI; if (MD.getStrategy().getName() != getStrategy().getName()) // this function is managed by some other GC continue; /** 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); } } }
/// EmitInlineAsm - This method formats and emits the specified machine /// instruction that is an inline asm. void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { #ifndef ANDROID_TARGET_BUILD assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms"); unsigned NumOperands = MI->getNumOperands(); // Count the number of register definitions to find the asm string. unsigned NumDefs = 0; for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef(); ++NumDefs) assert(NumDefs != NumOperands-2 && "No asm string?"); assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?"); // Disassemble the AsmStr, printing out the literal pieces, the operands, etc. const char *AsmStr = MI->getOperand(NumDefs).getSymbolName(); // If this asmstr is empty, just print the #APP/#NOAPP markers. // These are useful to see where empty asm's wound up. if (AsmStr[0] == 0) { // Don't emit the comments if writing to a .o file. if (!OutStreamer.hasRawTextSupport()) return; OutStreamer.EmitRawText(Twine("\t")+MAI->getCommentString()+ MAI->getInlineAsmStart()); OutStreamer.EmitRawText(Twine("\t")+MAI->getCommentString()+ MAI->getInlineAsmEnd()); return; } // Emit the #APP start marker. This has to happen even if verbose-asm isn't // enabled, so we use EmitRawText. if (OutStreamer.hasRawTextSupport()) OutStreamer.EmitRawText(Twine("\t")+MAI->getCommentString()+ MAI->getInlineAsmStart()); // Get the !srcloc metadata node if we have it, and decode the loc cookie from // it. unsigned LocCookie = 0; const MDNode *LocMD = 0; for (unsigned i = MI->getNumOperands(); i != 0; --i) { if (MI->getOperand(i-1).isMetadata() && (LocMD = MI->getOperand(i-1).getMetadata()) && LocMD->getNumOperands() != 0) { if (const ConstantInt *CI = dyn_cast<ConstantInt>(LocMD->getOperand(0))) { LocCookie = CI->getZExtValue(); break; } } } // Emit the inline asm to a temporary string so we can emit it through // EmitInlineAsm. SmallString<256> StringData; raw_svector_ostream OS(StringData); OS << '\t'; // The variant of the current asmprinter. int AsmPrinterVariant = MAI->getAssemblerDialect(); int CurVariant = -1; // The number of the {.|.|.} region we are in. const char *LastEmitted = AsmStr; // One past the last character emitted. while (*LastEmitted) { switch (*LastEmitted) { default: { // Not a special case, emit the string section literally. const char *LiteralEnd = LastEmitted+1; while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' && *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n') ++LiteralEnd; if (CurVariant == -1 || CurVariant == AsmPrinterVariant) OS.write(LastEmitted, LiteralEnd-LastEmitted); LastEmitted = LiteralEnd; break; } case '\n': ++LastEmitted; // Consume newline character. OS << '\n'; // Indent code with newline. break; case '$': { ++LastEmitted; // Consume '$' character. bool Done = true; // Handle escapes. switch (*LastEmitted) { default: Done = false; break; case '$': // $$ -> $ if (CurVariant == -1 || CurVariant == AsmPrinterVariant) OS << '$'; ++LastEmitted; // Consume second '$' character. break; case '(': // $( -> same as GCC's { character. ++LastEmitted; // Consume '(' character. if (CurVariant != -1) report_fatal_error("Nested variants found in inline asm string: '" + Twine(AsmStr) + "'"); CurVariant = 0; // We're in the first variant now. break; case '|': ++LastEmitted; // consume '|' character. if (CurVariant == -1) OS << '|'; // this is gcc's behavior for | outside a variant else ++CurVariant; // We're in the next variant. break; case ')': // $) -> same as GCC's } char. ++LastEmitted; // consume ')' character. if (CurVariant == -1) OS << '}'; // this is gcc's behavior for } outside a variant else CurVariant = -1; break; } if (Done) break; bool HasCurlyBraces = false; if (*LastEmitted == '{') { // ${variable} ++LastEmitted; // Consume '{' character. HasCurlyBraces = true; } // If we have ${:foo}, then this is not a real operand reference, it is a // "magic" string reference, just like in .td files. Arrange to call // PrintSpecial. if (HasCurlyBraces && *LastEmitted == ':') { ++LastEmitted; const char *StrStart = LastEmitted; const char *StrEnd = strchr(StrStart, '}'); if (StrEnd == 0) report_fatal_error("Unterminated ${:foo} operand in inline asm" " string: '" + Twine(AsmStr) + "'"); std::string Val(StrStart, StrEnd); PrintSpecial(MI, OS, Val.c_str()); LastEmitted = StrEnd+1; break; } const char *IDStart = LastEmitted; const char *IDEnd = IDStart; while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd; unsigned Val; if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val)) report_fatal_error("Bad $ operand number in inline asm string: '" + Twine(AsmStr) + "'"); LastEmitted = IDEnd; char Modifier[2] = { 0, 0 }; if (HasCurlyBraces) { // If we have curly braces, check for a modifier character. This // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm. if (*LastEmitted == ':') { ++LastEmitted; // Consume ':' character. if (*LastEmitted == 0) report_fatal_error("Bad ${:} expression in inline asm string: '" + Twine(AsmStr) + "'"); Modifier[0] = *LastEmitted; ++LastEmitted; // Consume modifier character. } if (*LastEmitted != '}') report_fatal_error("Bad ${} expression in inline asm string: '" + Twine(AsmStr) + "'"); ++LastEmitted; // Consume '}' character. } if (Val >= NumOperands-1) report_fatal_error("Invalid $ operand number in inline asm string: '" + Twine(AsmStr) + "'"); // Okay, we finally have a value number. Ask the target to print this // operand! if (CurVariant == -1 || CurVariant == AsmPrinterVariant) { unsigned OpNo = InlineAsm::MIOp_FirstOperand; bool Error = false; // Scan to find the machine operand number for the operand. for (; Val; --Val) { if (OpNo >= MI->getNumOperands()) break; unsigned OpFlags = MI->getOperand(OpNo).getImm(); OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; } // We may have a location metadata attached to the end of the // instruction, and at no point should see metadata at any // other point while processing. It's an error if so. if (OpNo >= MI->getNumOperands() || MI->getOperand(OpNo).isMetadata()) { Error = true; } else { unsigned OpFlags = MI->getOperand(OpNo).getImm(); ++OpNo; // Skip over the ID number. if (Modifier[0] == 'l') // labels are target independent // FIXME: What if the operand isn't an MBB, report error? OS << *MI->getOperand(OpNo).getMBB()->getSymbol(); else { AsmPrinter *AP = const_cast<AsmPrinter*>(this); if (InlineAsm::isMemKind(OpFlags)) { Error = AP->PrintAsmMemoryOperand(MI, OpNo, AsmPrinterVariant, Modifier[0] ? Modifier : 0, OS); } else { Error = AP->PrintAsmOperand(MI, OpNo, AsmPrinterVariant, Modifier[0] ? Modifier : 0, OS); } } } if (Error) { std::string msg; raw_string_ostream Msg(msg); Msg << "invalid operand in inline asm: '" << AsmStr << "'"; MMI->getModule()->getContext().emitError(LocCookie, Msg.str()); } } break; } } } OS << '\n' << (char)0; // null terminate string. EmitInlineAsm(OS.str(), LocMD); // Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't // enabled, so we use EmitRawText. if (OutStreamer.hasRawTextSupport()) OutStreamer.EmitRawText(Twine("\t")+MAI->getCommentString()+ MAI->getInlineAsmEnd()); #endif // ANDROID_TARGET_BUILD }
/// emitAssembly - Print the frametable. The ocaml frametable format is thus: /// /// extern "C" struct align(sizeof(intptr_t)) { /// uint16_t NumDescriptors; /// struct align(sizeof(intptr_t)) { /// void *ReturnAddress; /// uint16_t FrameSize; /// uint16_t NumLiveOffsets; /// uint16_t LiveOffsets[NumLiveOffsets]; /// } Descriptors[NumDescriptors]; /// } caml${module}__frametable; /// /// Note that this precludes programs from stack frames larger than 64K /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if /// either condition is detected in a function which uses the GC. /// void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) { unsigned IntPtrSize = M.getDataLayout().getPointerSize(); AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection()); EmitCamlGlobal(M, AP, "code_end"); AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(M, AP, "data_end"); // FIXME: Why does ocaml emit this?? AP.OutStreamer->EmitIntValue(0, IntPtrSize); AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(M, AP, "frametable"); int NumDescriptors = 0; for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(), IE = Info.funcinfo_end(); I != IE; ++I) { GCFunctionInfo &FI = **I; if (FI.getStrategy().getName() != getStrategy().getName()) // this function is managed by some other GC continue; for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { NumDescriptors++; } } if (NumDescriptors >= 1 << 16) { // Very rude! report_fatal_error(" Too much descriptor for ocaml GC"); } AP.emitInt16(NumDescriptors); AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(), IE = Info.funcinfo_end(); I != IE; ++I) { GCFunctionInfo &FI = **I; if (FI.getStrategy().getName() != getStrategy().getName()) // this function is managed by some other GC continue; uint64_t FrameSize = FI.getFrameSize(); if (FrameSize >= 1 << 16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " "Frame size " + Twine(FrameSize) + ">= 65536.\n" "(" + Twine(uintptr_t(&FI)) + ")"); } AP.OutStreamer->AddComment("live roots for " + Twine(FI.getFunction().getName())); AP.OutStreamer->AddBlankLine(); for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { size_t LiveCount = FI.live_size(J); if (LiveCount >= 1 << 16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " "Live root count " + Twine(LiveCount) + " >= 65536."); } AP.OutStreamer->EmitSymbolValue(J->Label, IntPtrSize); AP.emitInt16(FrameSize); AP.emitInt16(LiveCount); for (GCFunctionInfo::live_iterator K = FI.live_begin(J), KE = FI.live_end(J); K != KE; ++K) { if (K->StackOffset >= 1 << 16) { // Very rude! report_fatal_error( "GC root stack offset is outside of fixed stack frame and out " "of range for ocaml GC!"); } AP.emitInt16(K->StackOffset); } AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); } } }
/// emitAssembly - Print the frametable. The ocaml frametable format is thus: /// /// extern "C" struct align(sizeof(intptr_t)) { /// uint16_t NumDescriptors; /// struct align(sizeof(intptr_t)) { /// void *ReturnAddress; /// uint16_t FrameSize; /// uint16_t NumLiveOffsets; /// uint16_t LiveOffsets[NumLiveOffsets]; /// } Descriptors[NumDescriptors]; /// } caml${module}__frametable; /// /// Note that this precludes programs from stack frames larger than 64K /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if /// either condition is detected in a function which uses the GC. /// void OcamlGCMetadataPrinter::finishAssembly(AsmPrinter &AP) { unsigned IntPtrSize = AP.TM.getTargetData()->getPointerSize(); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getTextSection()); EmitCamlGlobal(getModule(), AP, "code_end"); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(getModule(), AP, "data_end"); // FIXME: Why does ocaml emit this?? AP.OutStreamer.EmitIntValue(0, IntPtrSize, 0); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(getModule(), AP, "frametable"); int NumDescriptors = 0; for (iterator I = begin(), IE = end(); I != IE; ++I) { GCFunctionInfo &FI = **I; for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { NumDescriptors++; } } if (NumDescriptors >= 1<<16) { // Very rude! report_fatal_error(" Too much descriptor for ocaml GC"); } AP.EmitInt16(NumDescriptors); AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); const MCRegisterInfo &MRI = AP.OutStreamer.getContext().getRegisterInfo(); for (iterator I = begin(), IE = end(); I != IE; ++I) { GCFunctionInfo &FI = **I; uint64_t FrameSize = FI.getFrameSize(); if (FrameSize >= 1<<16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " "Frame size " + Twine(FrameSize) + ">= 65536.\n" "(" + Twine(uintptr_t(&FI)) + ")"); } AP.OutStreamer.AddComment("live roots for " + Twine(FI.getFunction().getName())); AP.OutStreamer.AddBlankLine(); for (unsigned PI = 0, PE = FI.size(); PI != PE; ++PI) { size_t LiveCount = FI.live_size(PI); if (LiveCount >= 1<<16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " "Live root count "+Twine(LiveCount)+" >= 65536."); } GCPoint &Point = FI.getPoint(PI); AP.OutStreamer.EmitSymbolValue(Point.Label, IntPtrSize, 0); AP.EmitInt16(FrameSize); AP.EmitInt16(LiveCount); for (GCFunctionInfo::live_iterator K = FI.live_begin(PI), KE = FI.live_end(PI); K != KE; ++K) { if (K->isReg()) { AP.OutStreamer.AddComment("register root at " + Twine(MRI.getName(K->Loc.PhysReg))); AP.OutStreamer.AddBlankLine(); continue; } if (K->Loc.StackOffset >= 1<<16) { // Very rude! report_fatal_error( "GC root stack offset is outside of fixed stack frame and out " "of range for ocaml GC!"); } AP.EmitInt16(K->Loc.StackOffset); } AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); } } }
StoreInitializer::StoreInitializer(Type *EltTy, AsmPrinter &AP) : DL(AP.getDataLayout()), AP(AP), InitEltSize(DL.getTypeAllocSize(EltTy)), IsFPElt(EltTy->isFloatingPointTy()), m_data(), OS(m_data), LE(OS) {}
AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer) : Ctx(ctx), Printer(printer), TargetTriple(printer.getTargetTriple()) {}
void TartGCPrinter::finishAssembly(AsmPrinter &AP) { unsigned nextLabel = 1; SafePointList safePoints; // Set up for emitting addresses. int pointerSize = AP.TM.getTargetData()->getPointerSize(); int addressAlignLog; if (pointerSize == sizeof(int32_t)) { addressAlignLog = 2; } else { addressAlignLog = 3; } MCStreamer & outStream = AP.OutStreamer; // Put this in the data section. outStream.SwitchSection(AP.getObjFileLowering().getDataSection()); // For each function... for (iterator FI = begin(), FE = end(); FI != FE; ++FI) { GCFunctionInfo & gcFn = **FI; // if (optShowGC) { // errs() << "GCStrategy: Function: " << gcFn.getFunction().getName() << "\n"; // } // And each safe point... for (GCFunctionInfo::iterator sp = gcFn.begin(); sp != gcFn.end(); ++sp) { StackTraceTable::FieldOffsetList fieldOffsets; StackTraceTable::TraceMethodList traceMethods; // And for each live root... for (GCFunctionInfo::live_iterator rt = gcFn.live_begin(sp); rt != gcFn.live_end(sp); ++rt) { int64_t offset = rt->StackOffset; const Constant * meta = rt->Metadata; if (meta != NULL && !meta->isNullValue()) { // Meta is non-null, so it's a value type. const ConstantArray * traceArray = cast<ConstantArray>(getGlobalValue(meta)); // For each trace descriptor in thre meta array... for (ConstantArray::const_op_iterator it = traceArray->op_begin(); it != traceArray->op_end(); ++it) { ConstantStruct * descriptor = cast<ConstantStruct>(*it); ConstantInt * fieldCount = cast<ConstantInt>(descriptor->getOperand(1)); int64_t dscOffset = toInt(descriptor->getOperand(2), AP.TM); if (fieldCount->isZero()) { // A zero field count means that this is a trace method descriptor. const Constant * traceMethod = descriptor->getOperand(3); assert(offset > -1000 && offset < 1000); assert(dscOffset > -1000 && dscOffset < 1000); traceMethods.push_back(TraceMethodEntry(offset + dscOffset, traceMethod)); } else { // Otherwise it's a field offset descriptor. const GlobalVariable * fieldOffsetsVar = cast<GlobalVariable>( descriptor->getOperand(3)->getOperand(0)); // Handle case where the array value is just a ConstantAggregateZero, which // can be generated by llvm::ConstantArray::get() if the array values // are all zero. if (const ConstantAggregateZero * zero = dyn_cast<ConstantAggregateZero>(fieldOffsetsVar->getInitializer())) { // Array should never contain duplicate offsets, so an all-zero array // can only have one entry. (void)zero; assert(fieldCount->isOne()); fieldOffsets.push_back(offset + dscOffset); } else { // Get the field offset array and add to field offsets for this // safe point. const ConstantArray * fieldOffsetArray = cast<ConstantArray>( fieldOffsetsVar->getInitializer()); for (ConstantArray::const_op_iterator el = fieldOffsetArray->op_begin(); el != fieldOffsetArray->op_end(); ++el) { fieldOffsets.push_back( offset + dscOffset + toInt(cast<llvm::Constant>(*el), AP.TM)); } } } } } else { // No metadata, so it's an object reference - just add the field offset. fieldOffsets.push_back(offset); } } // Nothing to trace? Then we're done. if (fieldOffsets.empty() && traceMethods.empty()) { continue; } // Create a folding set node and merge with any identical trace tables. std::sort(fieldOffsets.begin(), fieldOffsets.end()); llvm::FoldingSetNodeID id; StackTraceTable::ProfileEntries(id, fieldOffsets, traceMethods); void * insertPos; StackTraceTable * sTable = traceTables.FindNodeOrInsertPos(id, insertPos); if (sTable == NULL) { sTable = new StackTraceTable(fieldOffsets, traceMethods); // Generate the labels for the trace table and field offset table. sTable->fieldOffsetsLabel = AP.GetTempSymbol("gc_stack_offsets", nextLabel); sTable->traceTableLabel = AP.GetTempSymbol("gc_stack", nextLabel++); // Add to folding set traceTables.InsertNode(sTable, insertPos); // Generate the trace table outStream.AddBlankLine(); AP.EmitAlignment(addressAlignLog); // First the field offset descriptor outStream.EmitLabel(sTable->traceTableLabel); size_t traceMethodCount = sTable->traceMethods.size(); if (!sTable->fieldOffsets.empty()) { outStream.EmitIntValue(traceMethodCount == 0 ? 1 : 0, 2, 0); outStream.EmitIntValue(sTable->fieldOffsets.size(), 2, 0); outStream.EmitIntValue(0, 4, 0); outStream.EmitSymbolValue(sTable->fieldOffsetsLabel, pointerSize, 0); } // Next the trace method descriptors for (size_t i = 0; i < traceMethodCount; ++i) { const TraceMethodEntry * tm = &sTable->traceMethods[i]; const Function * method = dyn_cast<Function>(tm->method()); if (method == NULL) { method = cast<Function>(tm->method()->getOperand(0)); } outStream.EmitIntValue((i + 1 == traceMethodCount ? 1 : 0), 2, 0); outStream.EmitIntValue(0, 2, 0); outStream.EmitIntValue(tm->offset(), 4, 0); MCSymbol * methodSym = AP.Mang->getSymbol(method); outStream.EmitSymbolValue(methodSym, pointerSize, 0); } // Now emit the field offset array outStream.AddBlankLine(); AP.EmitAlignment(addressAlignLog); outStream.EmitLabel(sTable->fieldOffsetsLabel); for (StackTraceTable::FieldOffsetList::const_iterator it = fieldOffsets.begin(); it != fieldOffsets.end(); ++it) { outStream.EmitIntValue(*it, pointerSize, 0); } } safePoints.push_back(std::pair<MCSymbol *, MCSymbol *>(sp->Label, sTable->traceTableLabel)); // if (optShowGC) { // if (!sTable->fieldOffsets.empty()) { // errs() << "GCStrategy: Field offset descriptor:"; // for (StackTraceTable::FieldOffsetList::const_iterator it = sTable->fieldOffsets.begin(); // it != sTable->fieldOffsets.end(); ++it) { // errs() << " " << *it; // } // errs() << "\n"; // } // if (!sTable->traceMethods.empty()) { // errs() << "GCStrategy: Trace method descriptor: " << "\n"; // } // } } } // Finally, generate the safe point map. outStream.AddBlankLine(); MCSymbol * gcSafepointSymbol = AP.GetExternalSymbolSymbol("GC_safepoint_map"); outStream.EmitSymbolAttribute(gcSafepointSymbol, MCSA_Global); outStream.EmitLabel(gcSafepointSymbol); outStream.EmitIntValue(safePoints.size(), pointerSize, 0); for (SafePointList::const_iterator it = safePoints.begin(); it != safePoints.end(); ++it) { outStream.EmitSymbolValue(it->first, pointerSize, 0); outStream.EmitSymbolValue(it->second, pointerSize, 0); } }
void RgcPrinter::finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) { MCStreamer &OS = AP.OutStreamer; unsigned IntPtrSize = AP.TM.getSubtargetImpl()->getDataLayout()->getPointerSize(); // Put this in the data section. OS.SwitchSection(AP.getObjFileLowering().getDataSection()); // For each function... for (GCModuleInfo::FuncInfoVec::iterator FI = Info.funcinfo_begin(), FE = Info.funcinfo_end(); FI != FE; ++FI) { GCFunctionInfo &MD = **FI; // A compact GC layout. Emit this data structure: // // struct { // int32_t PointCount; // void *SafePointAddress[PointCount]; // int32_t StackFrameSize; // in words // int32_t StackArity; // int32_t LiveCount; // int32_t LiveOffsets[LiveCount]; // } __gcmap_<FUNCTIONNAME>; // Align to address width. // AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); // Emit PointCount. OS.AddComment("safe point count"); AP.EmitInt32(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.EmitInt32(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.EmitInt32(StackArity); // Emit the number of live roots in the function. OS.AddComment("live root count"); AP.EmitInt32(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.EmitInt32(LI->StackOffset); } } }