diff --git a/include/llvm/MC/MCDwarf.h b/include/llvm/MC/MCDwarf.h index 0c0a22eb8ab..d528ac5f737 100644 --- a/include/llvm/MC/MCDwarf.h +++ b/include/llvm/MC/MCDwarf.h @@ -209,7 +209,6 @@ namespace llvm { // This emits the Dwarf file and the line tables. // static void Emit(MCStreamer *MCOS, const MCSection *DwarfLineSection, - MCSectionData *DLS, int PointerSize, const MCSection *TextSection = NULL); }; diff --git a/include/llvm/MC/MCExpr.h b/include/llvm/MC/MCExpr.h index fc9d18bf3a3..e953a111868 100644 --- a/include/llvm/MC/MCExpr.h +++ b/include/llvm/MC/MCExpr.h @@ -16,6 +16,7 @@ namespace llvm { class MCAsmInfo; class MCAsmLayout; +class MCAssembler; class MCContext; class MCSymbol; class MCValue; @@ -43,7 +44,8 @@ private: protected: explicit MCExpr(ExprKind _Kind) : Kind(_Kind) {} - bool EvaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, + bool EvaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, + const MCAsmLayout *Layout, bool InSet) const; public: /// @name Accessors @@ -69,7 +71,11 @@ public: /// values. If not given, then only non-symbolic expressions will be /// evaluated. /// @result - True on success. - bool EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout = 0) const; + bool EvaluateAsAbsolute(int64_t &Res) const; + bool EvaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const; + bool EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout) const; + bool EvaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, + const MCAsmLayout *Layout) const; /// EvaluateAsRelocatable - Try to evaluate the expression to a relocatable /// value, i.e. an expression of the fixed form (a - b + constant). diff --git a/include/llvm/MC/MCObjectStreamer.h b/include/llvm/MC/MCObjectStreamer.h index 092bc847039..a3f532d8c00 100644 --- a/include/llvm/MC/MCObjectStreamer.h +++ b/include/llvm/MC/MCObjectStreamer.h @@ -69,6 +69,9 @@ public: virtual void EmitInstruction(const MCInst &Inst); virtual void EmitInstToFragment(const MCInst &Inst); virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value); + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label); virtual void Finish(); /// @} diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index 4c96b2fce52..03fd011418c 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -351,6 +351,13 @@ namespace llvm { unsigned Isa, unsigned Discriminator); + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) = 0; + + void EmitDwarfSetLineAddr(int64_t LineDelta, const MCSymbol *Label, + int PointerSize); + virtual bool EmitCFIStartProc(); virtual bool EmitCFIEndProc(); virtual bool EmitCFIDefCfaOffset(int64_t Offset); diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 49bcc936f7a..217daed7fe0 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -121,6 +121,9 @@ public: virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); @@ -298,6 +301,12 @@ void MCAsmStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { EmitEOL(); } +void MCAsmStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) { + EmitDwarfSetLineAddr(LineDelta, Label, PointerSize); +} + void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { switch (Attribute) { @@ -885,10 +894,9 @@ void MCAsmStreamer::EmitRawText(StringRef String) { void MCAsmStreamer::Finish() { // Dump out the dwarf file & directory tables and line tables. - if (getContext().hasDwarfFiles() && TLOF) { - MCDwarfFileTable::Emit(this, TLOF->getDwarfLineSection(), NULL, - PointerSize, TLOF->getTextSection()); - } + if (getContext().hasDwarfFiles() && TLOF) + MCDwarfFileTable::Emit(this, TLOF->getDwarfLineSection(), + TLOF->getTextSection()); } MCStreamer *llvm::createAsmStreamer(MCContext &Context, diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index 5fe73e2810a..0916b054eb8 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -117,21 +117,6 @@ static inline const MCExpr *MakeStartMinusEndExpr(MCStreamer *MCOS, return Res3; } -// -// This emits an "absolute" address used in the start of a dwarf line number -// table. This will result in a relocatation entry for the address. -// -static inline void EmitDwarfSetAddress(MCStreamer *MCOS, - MCSymbol *Symbol, - int PointerSize) { - MCOS->EmitIntValue(dwarf::DW_LNS_extended_op, 1); - - MCOS->EmitULEB128IntValue(PointerSize + 1); - - MCOS->EmitIntValue(dwarf::DW_LNE_set_address, 1); - MCOS->EmitSymbolValue(Symbol, PointerSize); -} - // // This emits the Dwarf line table for the specified section from the entries // in the LineSection. @@ -139,9 +124,7 @@ static inline void EmitDwarfSetAddress(MCStreamer *MCOS, static inline void EmitDwarfLineTable(MCStreamer *MCOS, const MCSection *Section, const MCLineSection *LineSection, - const MCSection *DwarfLineSection, - MCSectionData *DLS, - int PointerSize) { + const MCSection *DwarfLineSection) { unsigned FileNum = 1; unsigned LastLine = 1; unsigned Column = 0; @@ -186,19 +169,7 @@ static inline void EmitDwarfLineTable(MCStreamer *MCOS, // At this point we want to emit/create the sequence to encode the delta in // line numbers and the increment of the address from the previous Label // and the current Label. - if (LastLabel == NULL || DLS == NULL) { - // emit the sequence to set the address - EmitDwarfSetAddress(MCOS, Label, PointerSize); - // emit the sequence for the LineDelta (from 1) and a zero address delta. - MCDwarfLineAddr::Emit(MCOS, LineDelta, 0); - } - else { - // Create an expression for the address delta from the LastLabel and - // this Label (plus 0). - const MCExpr *AddrDelta = MakeStartMinusEndExpr(MCOS, LastLabel, Label,0); - // Create a Dwarf Line fragment for the LineDelta and AddrDelta. - new MCDwarfLineAddrFragment(LineDelta, *AddrDelta, DLS); - } + MCOS->EmitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label); LastLine = it->getLine(); LastLabel = Label; @@ -220,19 +191,7 @@ static inline void EmitDwarfLineTable(MCStreamer *MCOS, // Switch back the the dwarf line section. MCOS->SwitchSection(DwarfLineSection); - if (DLS == NULL) { - // emit the sequence to set the address - EmitDwarfSetAddress(MCOS, SectionEnd, PointerSize); - // emit the sequence for the LineDelta (from 1) and a zero address delta. - MCDwarfLineAddr::Emit(MCOS, INT64_MAX, 0); - } else { - // Create an expression for the address delta from the LastLabel and this - // SectionEnd label. - const MCExpr *AddrDelta = MakeStartMinusEndExpr(MCOS, LastLabel, SectionEnd, - 0); - // Create a Dwarf Line fragment for the LineDelta and AddrDelta. - new MCDwarfLineAddrFragment(INT64_MAX, *AddrDelta, DLS); - } + MCOS->EmitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd); } // @@ -240,8 +199,6 @@ static inline void EmitDwarfLineTable(MCStreamer *MCOS, // void MCDwarfFileTable::Emit(MCStreamer *MCOS, const MCSection *DwarfLineSection, - MCSectionData *DLS, - int PointerSize, const MCSection *TextSection) { // Switch to the section where the table will be emitted into. MCOS->SwitchSection(DwarfLineSection); @@ -332,8 +289,7 @@ void MCDwarfFileTable::Emit(MCStreamer *MCOS, ++it) { const MCSection *Sec = *it; const MCLineSection *Line = MCLineSections.lookup(Sec); - EmitDwarfLineTable(MCOS, Sec, Line, DwarfLineSection, DLS, - PointerSize); + EmitDwarfLineTable(MCOS, Sec, Line, DwarfLineSection); // Now delete the MCLineSections that were created in MCLineEntry::Make() // and used to emit the line table. @@ -351,10 +307,7 @@ void MCDwarfFileTable::Emit(MCStreamer *MCOS, // Switch back the the dwarf line section. MCOS->SwitchSection(DwarfLineSection); - // emit the sequence to set the address - EmitDwarfSetAddress(MCOS, SectionEnd, PointerSize); - // emit the sequence for the LineDelta (from 1) and a zero address delta. - MCDwarfLineAddr::Emit(MCOS, INT64_MAX, 0); + MCOS->EmitDwarfAdvanceLineAddr(INT64_MAX, NULL, SectionEnd); } // This is the end of the section, so set the value of the symbol at the end diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index d98c9ef79e2..f18c420cb9b 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -484,10 +484,7 @@ void MCELFStreamer::Finish() { const MCSection *DwarfLineSection = getContext().getELFSection(".debug_line", 0, 0, SectionKind::getDataRelLocal()); - MCSectionData &DLS = - getAssembler().getOrCreateSectionData(*DwarfLineSection); - int PointerSize = getAssembler().getBackend().getPointerSize(); - MCDwarfFileTable::Emit(this, DwarfLineSection, &DLS, PointerSize); + MCDwarfFileTable::Emit(this, DwarfLineSection); } for (std::vector::const_iterator i = LocalCommons.begin(), diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index 64c57b335ce..3d476086e4c 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -237,7 +237,24 @@ void MCTargetExpr::Anchor() {} /* *** */ -bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout) const { +bool MCExpr::EvaluateAsAbsolute(int64_t &Res) const { + return EvaluateAsAbsolute(Res, 0, 0); +} + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, + const MCAsmLayout *Layout) const { + if (Layout) + return EvaluateAsAbsolute(Res, &Layout->getAssembler(), Layout); + else + return EvaluateAsAbsolute(Res, 0, 0); +} + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const { + return EvaluateAsAbsolute(Res, Asm, 0); +} + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, + const MCAsmLayout *Layout) const { MCValue Value; // Fast path constants. @@ -246,7 +263,8 @@ bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout) const { return true; } - if (!EvaluateAsRelocatable(Value, Layout) || !Value.isAbsolute()) { + if (!EvaluateAsRelocatableImpl(Value, Asm, Layout, false) || + !Value.isAbsolute()) { // EvaluateAsAbsolute is defined to return the "current value" of // the expression if we are given a Layout object, even in cases // when the value is not fixed. @@ -268,7 +286,9 @@ bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout) const { return true; } -static bool EvaluateSymbolicAdd(const MCAsmLayout *Layout, bool InSet, +static bool EvaluateSymbolicAdd(const MCAsmLayout *Layout, + const MCAssembler *Asm, + bool InSet, const MCValue &LHS,const MCSymbolRefExpr *RHS_A, const MCSymbolRefExpr *RHS_B, int64_t RHS_Cst, MCValue &Res) { @@ -291,14 +311,15 @@ static bool EvaluateSymbolicAdd(const MCAsmLayout *Layout, bool InSet, // Absolutize symbol differences between defined symbols when we have a // layout object and the target requests it. - if (Layout && A && B) { + assert(!(Layout && !Asm)); + + if ((Layout || Asm) && A && B) { const MCSymbol &SA = A->getSymbol(); const MCSymbol &SB = B->getSymbol(); - const MCAssembler &Asm = Layout->getAssembler(); - const MCObjectFormat &F = Asm.getBackend().getObjectFormat(); + const MCObjectFormat &F = Asm->getBackend().getObjectFormat(); if (SA.isDefined() && SB.isDefined() && F.isAbsolute(InSet, SA, SB)) { - MCSymbolData &AD = Asm.getSymbolData(A->getSymbol()); - MCSymbolData &BD = Asm.getSymbolData(B->getSymbol()); + MCSymbolData &AD = Asm->getSymbolData(A->getSymbol()); + MCSymbolData &BD = Asm->getSymbolData(B->getSymbol()); if (AD.getFragment() == BD.getFragment()) { Res = MCValue::get(+ AD.getOffset() @@ -308,25 +329,31 @@ static bool EvaluateSymbolicAdd(const MCAsmLayout *Layout, bool InSet, return true; } - Res = MCValue::get(+ Layout->getSymbolAddress(&AD) - - Layout->getSymbolAddress(&BD) - + LHS.getConstant() - + RHS_Cst); - return true; + if (Layout) { + Res = MCValue::get(+ Layout->getSymbolAddress(&AD) + - Layout->getSymbolAddress(&BD) + + LHS.getConstant() + + RHS_Cst); + return true; + } } } - Res = MCValue::get(A, B, LHS.getConstant() + RHS_Cst); return true; } bool MCExpr::EvaluateAsRelocatable(MCValue &Res, const MCAsmLayout *Layout) const { - return EvaluateAsRelocatableImpl(Res, Layout, false); + if (Layout) + return EvaluateAsRelocatableImpl(Res, &Layout->getAssembler(), Layout, + false); + else + return EvaluateAsRelocatableImpl(Res, 0, 0, false); } bool MCExpr::EvaluateAsRelocatableImpl(MCValue &Res, + const MCAssembler *Asm, const MCAsmLayout *Layout, bool InSet) const { ++stats::MCExprEvaluate; @@ -345,7 +372,8 @@ bool MCExpr::EvaluateAsRelocatableImpl(MCValue &Res, // Evaluate recursively if this is a variable. if (Sym.isVariable() && SRE->getKind() == MCSymbolRefExpr::VK_None) { - bool Ret = Sym.getVariableValue()->EvaluateAsRelocatableImpl(Res, Layout, + bool Ret = Sym.getVariableValue()->EvaluateAsRelocatableImpl(Res, Asm, + Layout, true); // If we failed to simplify this to a constant, let the target // handle it. @@ -361,7 +389,8 @@ bool MCExpr::EvaluateAsRelocatableImpl(MCValue &Res, const MCUnaryExpr *AUE = cast(this); MCValue Value; - if (!AUE->getSubExpr()->EvaluateAsRelocatableImpl(Value, Layout, InSet)) + if (!AUE->getSubExpr()->EvaluateAsRelocatableImpl(Value, Asm, Layout, + InSet)) return false; switch (AUE->getOpcode()) { @@ -394,8 +423,10 @@ bool MCExpr::EvaluateAsRelocatableImpl(MCValue &Res, const MCBinaryExpr *ABE = cast(this); MCValue LHSValue, RHSValue; - if (!ABE->getLHS()->EvaluateAsRelocatableImpl(LHSValue, Layout, InSet) || - !ABE->getRHS()->EvaluateAsRelocatableImpl(RHSValue, Layout, InSet)) + if (!ABE->getLHS()->EvaluateAsRelocatableImpl(LHSValue, Asm, Layout, + InSet) || + !ABE->getRHS()->EvaluateAsRelocatableImpl(RHSValue, Asm, Layout, + InSet)) return false; // We only support a few operations on non-constant expressions, handle @@ -406,13 +437,13 @@ bool MCExpr::EvaluateAsRelocatableImpl(MCValue &Res, return false; case MCBinaryExpr::Sub: // Negate RHS and add. - return EvaluateSymbolicAdd(Layout, InSet, LHSValue, + return EvaluateSymbolicAdd(Layout, Asm, InSet, LHSValue, RHSValue.getSymB(), RHSValue.getSymA(), -RHSValue.getConstant(), Res); case MCBinaryExpr::Add: - return EvaluateSymbolicAdd(Layout, InSet, LHSValue, + return EvaluateSymbolicAdd(Layout, Asm, InSet, LHSValue, RHSValue.getSymA(), RHSValue.getSymB(), RHSValue.getConstant(), Res); diff --git a/lib/MC/MCLoggingStreamer.cpp b/lib/MC/MCLoggingStreamer.cpp index 5191ac4a72c..6cbef0b0250 100644 --- a/lib/MC/MCLoggingStreamer.cpp +++ b/lib/MC/MCLoggingStreamer.cpp @@ -84,6 +84,13 @@ public: return Child->EmitWeakReference(Alias, Symbol); } + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) { + LogCall("EmitDwarfAdvanceLineAddr"); + return Child->EmitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label); + } + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { LogCall("EmitSymbolAttribute"); return Child->EmitSymbolAttribute(Symbol, Attribute); diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 71bd4076ade..1ee2d482602 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -357,10 +357,7 @@ void MCMachOStreamer::Finish() { "__debug_line", MCSectionMachO::S_ATTR_DEBUG, 0, SectionKind::getDataRelLocal()); - MCSectionData &DLS = - getAssembler().getOrCreateSectionData(*DwarfLineSection); - int PointerSize = getAssembler().getBackend().getPointerSize(); - MCDwarfFileTable::Emit(this, DwarfLineSection, &DLS, PointerSize); + MCDwarfFileTable::Emit(this, DwarfLineSection); } // We have to set the fragment atom associations so we can relax properly for diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp index c79793ceed1..86ab628e602 100644 --- a/lib/MC/MCNullStreamer.cpp +++ b/lib/MC/MCNullStreamer.cpp @@ -44,6 +44,9 @@ namespace { virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {} virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol){} + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) {} virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute){} diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index a514858545a..506c963c591 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -179,6 +179,30 @@ void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst) { getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, IF->getFixups()); } +void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) { + if (!LastLabel) { + int PointerSize = getAssembler().getBackend().getPointerSize(); + EmitDwarfSetLineAddr(LineDelta, Label, PointerSize); + return; + } + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + const MCExpr *LabelRef = + MCSymbolRefExpr::Create(Label, Variant, getContext()); + const MCExpr *LastLabelRef = + MCSymbolRefExpr::Create(LastLabel, Variant, getContext()); + const MCExpr *AddrDelta = + MCBinaryExpr::Create(MCBinaryExpr::Sub, LabelRef, LastLabelRef, + getContext()); + int64_t Res; + if (AddrDelta->EvaluateAsAbsolute(Res, &getAssembler())) { + MCDwarfLineAddr::Emit(this, LineDelta, Res); + return; + } + new MCDwarfLineAddrFragment(LineDelta, *AddrDelta, getCurrentSectionData()); +} + void MCObjectStreamer::EmitValueToOffset(const MCExpr *Offset, unsigned char Value) { new MCOrgFragment(*Offset, Value, getCurrentSectionData()); diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp index 7921957f542..9fe719a7fa7 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -30,6 +30,17 @@ raw_ostream &MCStreamer::GetCommentOS() { return nulls(); } +void MCStreamer::EmitDwarfSetLineAddr(int64_t LineDelta, + const MCSymbol *Label, int PointerSize) { + // emit the sequence to set the address + EmitIntValue(dwarf::DW_LNS_extended_op, 1); + EmitULEB128IntValue(PointerSize + 1); + EmitIntValue(dwarf::DW_LNE_set_address, 1); + EmitSymbolValue(Label, PointerSize); + + // emit the sequence for the LineDelta (from 1) and a zero address delta. + MCDwarfLineAddr::Emit(this, LineDelta, 0); +} /// EmitIntValue - Special case of EmitValue that avoids the client having to /// pass in a MCExpr for constant integers. diff --git a/lib/Target/PTX/PTXMCAsmStreamer.cpp b/lib/Target/PTX/PTXMCAsmStreamer.cpp index 0b49bcc43f6..8043baf8cfc 100644 --- a/lib/Target/PTX/PTXMCAsmStreamer.cpp +++ b/lib/Target/PTX/PTXMCAsmStreamer.cpp @@ -118,6 +118,10 @@ public: virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label); + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); @@ -263,6 +267,12 @@ void PTXMCAsmStreamer::EmitWeakReference(MCSymbol *Alias, EmitEOL(); } +void PTXMCAsmStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) { + report_fatal_error("Unimplemented."); +} + void PTXMCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) {}