Index: include/llvm/BinaryFormat/ELFRelocs/AVR.def =================================================================== --- include/llvm/BinaryFormat/ELFRelocs/AVR.def +++ include/llvm/BinaryFormat/ELFRelocs/AVR.def @@ -33,8 +33,9 @@ ELF_RELOC(R_AVR_8_LO8, 27) ELF_RELOC(R_AVR_8_HI8, 28) ELF_RELOC(R_AVR_8_HLO8, 29) -ELF_RELOC(R_AVR_SYM_DIFF, 30) -ELF_RELOC(R_AVR_16_LDST, 31) +ELF_RELOC(R_AVR_DIFF8, 30) +ELF_RELOC(R_AVR_DIFF16, 31) +ELF_RELOC(R_AVR_DIFF32, 32) ELF_RELOC(R_AVR_LDS_STS_16, 33) ELF_RELOC(R_AVR_PORT6, 34) ELF_RELOC(R_AVR_PORT5, 35) Index: lib/Target/AVR/AsmParser/AVRAsmParser.cpp =================================================================== --- lib/Target/AVR/AsmParser/AVRAsmParser.cpp +++ lib/Target/AVR/AsmParser/AVRAsmParser.cpp @@ -80,6 +80,8 @@ uint64_t const &ErrorInfo); bool missingFeature(SMLoc const &Loc, uint64_t const &ErrorInfo); + bool parseLiteralValues(unsigned Size, SMLoc L); + public: AVRAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, const MCInstrInfo &MII, const MCTargetOptions &Options) @@ -404,11 +406,14 @@ size_t ReadCount = Parser.getLexer().peekTokens(tokens); if (ReadCount == 2) { - if (tokens[0].getKind() == AsmToken::Identifier && - tokens[1].getKind() == AsmToken::LParen) { + if ((tokens[0].getKind() == AsmToken::Identifier && + tokens[1].getKind() == AsmToken::LParen) || + (tokens[0].getKind() == AsmToken::LParen && + tokens[1].getKind() == AsmToken::Minus)) { AsmToken::TokenKind CurTok = Parser.getLexer().getKind(); - if (CurTok == AsmToken::Minus) { + if (CurTok == AsmToken::Minus || + tokens[1].getKind() == AsmToken::Minus) { isNegated = true; } else { assert(CurTok == AsmToken::Plus); @@ -416,7 +421,8 @@ } // Eat the sign - Parser.Lex(); + if (CurTok == AsmToken::Minus || CurTok == AsmToken::Plus) + Parser.Lex(); } } @@ -432,14 +438,32 @@ if (ModifierKind != AVRMCExpr::VK_AVR_None) { Parser.Lex(); Parser.Lex(); // Eat modifier name and parenthesis + if (Parser.getTok().getString() == "gs" && + Parser.getTok().getKind() == AsmToken::Identifier) { + std::string GSModName = ModifierName.str() += "_gs"; + ModifierKind = AVRMCExpr::getKindByName(GSModName.c_str()); + if (ModifierKind != AVRMCExpr::VK_AVR_None) + Parser.Lex(); // Eat gs modifier name + } } else { return Error(Parser.getTok().getLoc(), "unknown modifier"); } + if (tokens[1].getKind() == AsmToken::Minus) { + Parser.Lex(); + assert(Parser.getTok().getKind() == AsmToken::LParen); + Parser.Lex(); // Eat the sign and parenthesis + } + MCExpr const *InnerExpression; if (getParser().parseExpression(InnerExpression)) return true; + if (tokens[1].getKind() == AsmToken::Minus) { + assert(Parser.getTok().getKind() == AsmToken::RParen); + Parser.Lex(); // Eat closing parenthesis + } + // If we have a modifier wrap the inner expression assert(Parser.getTok().getKind() == AsmToken::RParen); Parser.Lex(); // Eat closing parenthesis @@ -580,7 +604,46 @@ return false; } -bool AVRAsmParser::ParseDirective(llvm::AsmToken DirectiveID) { return true; } +bool AVRAsmParser::ParseDirective(llvm::AsmToken DirectiveID) { + StringRef IDVal = DirectiveID.getIdentifier(); + if (IDVal == ".long") + parseLiteralValues(8, DirectiveID.getLoc()); + else if (IDVal == ".word") + parseLiteralValues(4, DirectiveID.getLoc()); + else if (IDVal == ".short") + parseLiteralValues(2, DirectiveID.getLoc()); + else if (IDVal == ".byte") + parseLiteralValues(1, DirectiveID.getLoc()); + return true; +} + +bool AVRAsmParser::parseLiteralValues(unsigned Size, SMLoc L) { + MCAsmParser &Parser = getParser(); + if (Parser.getTok().getKind() == AsmToken::Identifier && + Parser.getLexer().peekTok().getKind() == AsmToken::LParen) { + StringRef ModifierName = Parser.getTok().getString(); + AVRMCExpr::VariantKind ModifierKind = + AVRMCExpr::getKindByName(ModifierName.str().c_str()); + if (ModifierKind != AVRMCExpr::VK_AVR_None) { + Parser.Lex(); + Parser.Lex(); // Eat the modifier and parenthesis + } else { + return Error(Parser.getTok().getLoc(), "unknown modifier"); + } + const MCExpr *InnerExpression; + return Parser.parseExpression(InnerExpression); + // FIXME: not supports .byte lo8(foo) + // Does it need to re-architecture ParseDirective add Operands? + } + auto parseOne = [&]() -> bool { + const MCExpr *Value; + if (Parser.parseExpression(Value)) + return true; + Parser.getStreamer().EmitValue(Value, Size, L); + return false; + }; + return (parseMany(parseOne)); +} extern "C" void LLVMInitializeAVRAsmParser() { RegisterMCAsmParser X(getTheAVRTarget()); Index: lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp =================================================================== --- lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp +++ lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp @@ -266,13 +266,17 @@ break; case AVR::fixup_lo8_ldi: case AVR::fixup_lo8_ldi_pm: - if (Kind == AVR::fixup_lo8_ldi_pm) adjust::pm(Value); + case AVR::fixup_lo8_ldi_gs: + if (Kind == AVR::fixup_lo8_ldi_pm || Kind == AVR::fixup_lo8_ldi_gs) + adjust::pm(Value); adjust::ldi::lo8(Size, Fixup, Value, Ctx); break; case AVR::fixup_hi8_ldi: case AVR::fixup_hi8_ldi_pm: - if (Kind == AVR::fixup_hi8_ldi_pm) adjust::pm(Value); + case AVR::fixup_hi8_ldi_gs: + if (Kind == AVR::fixup_hi8_ldi_pm || Kind == AVR::fixup_hi8_ldi_gs) + adjust::pm(Value); adjust::ldi::hi8(Size, Fixup, Value, Ctx); break; @@ -421,8 +425,9 @@ {"fixup_8_hi8", 0, 8, 0}, {"fixup_8_hlo8", 0, 8, 0}, - {"fixup_sym_diff", 0, 32, 0}, - {"fixup_16_ldst", 0, 16, 0}, + {"fixup_diff8", 0, 8, 0}, + {"fixup_diff16", 0, 16, 0}, + {"fixup_diff32", 0, 32, 0}, {"fixup_lds_sts_16", 0, 16, 0}, Index: lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp =================================================================== --- lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp +++ lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp @@ -39,8 +39,15 @@ const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { + MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); switch ((unsigned) Fixup.getKind()) { case FK_Data_1: + switch (Modifier) { + case MCSymbolRefExpr::VK_None: + return ELF::R_AVR_8; + } + case AVR::fixup_8: + return ELF::R_AVR_8; case FK_Data_4: llvm_unreachable("unsupported relocation type"); case FK_Data_2: @@ -95,18 +102,18 @@ return ELF::R_AVR_LO8_LDI_GS; case AVR::fixup_hi8_ldi_gs: return ELF::R_AVR_HI8_LDI_GS; - case AVR::fixup_8: - return ELF::R_AVR_8; case AVR::fixup_8_lo8: return ELF::R_AVR_8_LO8; case AVR::fixup_8_hi8: return ELF::R_AVR_8_HI8; case AVR::fixup_8_hlo8: return ELF::R_AVR_8_HLO8; - case AVR::fixup_sym_diff: - return ELF::R_AVR_SYM_DIFF; - case AVR::fixup_16_ldst: - return ELF::R_AVR_16_LDST; + case AVR::fixup_diff8: + return ELF::R_AVR_DIFF8; + case AVR::fixup_diff16: + return ELF::R_AVR_DIFF16; + case AVR::fixup_diff32: + return ELF::R_AVR_DIFF32; case AVR::fixup_lds_sts_16: return ELF::R_AVR_LDS_STS_16; case AVR::fixup_port6: Index: lib/Target/AVR/MCTargetDesc/AVRFixupKinds.h =================================================================== --- lib/Target/AVR/MCTargetDesc/AVRFixupKinds.h +++ lib/Target/AVR/MCTargetDesc/AVRFixupKinds.h @@ -117,8 +117,9 @@ /// Fixup to calculate the difference between two symbols. /// Is the only stateful fixup. We do not support it yet. - fixup_sym_diff, - fixup_16_ldst, + fixup_diff8, + fixup_diff16, + fixup_diff32, fixup_lds_sts_16, Index: lib/Target/AVR/MCTargetDesc/AVRMCExpr.h =================================================================== --- lib/Target/AVR/MCTargetDesc/AVRMCExpr.h +++ lib/Target/AVR/MCTargetDesc/AVRMCExpr.h @@ -30,7 +30,10 @@ VK_AVR_PM_LO8, ///< Corresponds to `pm_lo8()`. VK_AVR_PM_HI8, ///< Corresponds to `pm_hi8()`. - VK_AVR_PM_HH8 ///< Corresponds to `pm_hh8()`. + VK_AVR_PM_HH8, ///< Corresponds to `pm_hh8()`. + + VK_AVR_LO8_GS, ///< Corresponds to `lo8(gs())`. + VK_AVR_HI8_GS, ///< Corresponds to `hi8(gs())`. }; public: Index: lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp =================================================================== --- lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp +++ lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp @@ -29,6 +29,8 @@ {"pm_lo8", AVRMCExpr::VK_AVR_PM_LO8}, {"pm_hi8", AVRMCExpr::VK_AVR_PM_HI8}, {"pm_hh8", AVRMCExpr::VK_AVR_PM_HH8}, + + {"lo8_gs", AVRMCExpr::VK_AVR_LO8_GS}, {"hi8_gs", AVRMCExpr::VK_AVR_HI8_GS}, }; } // end of anonymous namespace @@ -118,6 +120,12 @@ case AVRMCExpr::VK_AVR_PM_HH8: Value >>= 17; break; + case AVRMCExpr::VK_AVR_LO8_GS: + Value >>= 1; + break; + case AVRMCExpr::VK_AVR_HI8_GS: + Value >>= 9; + break; case AVRMCExpr::VK_AVR_None: llvm_unreachable("Uninitialized expression."); @@ -151,6 +159,12 @@ case VK_AVR_PM_HH8: Kind = isNegated() ? AVR::fixup_hh8_ldi_pm_neg : AVR::fixup_hh8_ldi_pm; break; + case VK_AVR_LO8_GS: + Kind = AVR::fixup_lo8_ldi_gs; + break; + case VK_AVR_HI8_GS: + Kind = AVR::fixup_hi8_ldi_gs; + break; case VK_AVR_None: llvm_unreachable("Uninitialized expression"); Index: test/MC/AVR/relocations.s =================================================================== --- test/MC/AVR/relocations.s +++ test/MC/AVR/relocations.s @@ -2,6 +2,10 @@ ; CHECK: RELOCATION RECORDS FOR +; CHECK: RELOCATION RECORDS BAR +bar: + jmp bar + ; CHECK-NEXT: R_AVR_LDI SYMBOL+3 ldi r21, SYMBOL+3 @@ -34,27 +38,32 @@ ; CHECK-NEXT: R_AVR_LO8_LDI_NEG abc ldi r16, -lo8(abc) +ldi r16, lo8(-(abc)) ; CHECK-NEXT: R_AVR_HI8_LDI_NEG abc ldi r16, -hi8(abc) +ldi r16, hi8(-(abc)) ; CHECK-NEXT: R_AVR_HH8_LDI foo ldi r16, hh8(foo) ; CHECK-NEXT: R_AVR_HH8_LDI_NEG foo ldi r16, -hh8(foo) +ldi r16, hh8(-(foo)) ; CHECK-NEXT: R_AVR_HH8_LDI foo ldi r24, hlo8(foo) ; CHECK-NEXT: R_AVR_HH8_LDI_NEG foo ldi r24, -hlo8(foo) +ldi r24, hlo8(-(foo)) ; CHECK-NEXT: R_AVR_MS8_LDI bar ldi r24, hhi8(bar) ; CHECK-NEXT: R_AVR_MS8_LDI_NEG bar ldi r24, -hhi8(bar) +ldi r24, hhi8(-(bar)) ; CHECK-NEXT: R_AVR_LO8_LDI_PM foo ldi r17, pm_lo8(foo) @@ -67,9 +76,42 @@ ; CHECK-NEXT: R_AVR_LO8_LDI_PM_NEG ldi r25, -pm_lo8(foo) +ldi r25, pm_lo8(-(foo)) ; CHECK-NEXT: R_AVR_HI8_LDI_PM_NEG ldi r25, -pm_hi8(foo) +ldi r25, pm_hi8(-(foo)) ; CHECK-NEXT: R_AVR_HH8_LDI_PM_NEG ldi r25, -pm_hh8(foo) +ldi r25, pm_hh8(-(foo)) + +; CHECK-NEXT: R_AVR_LO8_LDI_GS +ldi r17, lo8(gs(foo)) + +; CHECK-NEXT: R_AVR_HI8_LDI_GS +ldi r18, hi8(gs(foo)) + +; CHECK-NEXT: R_AVR_16_PM +.short foo + +; CHECK-NEXT: R_AVR_8 +.byte foo + +; CHECK-NEXT: R_AVR_8_LO8 +.byte lo8(foo) + +; CHECK-NEXT: R_AVR_8_HI8 +.byte hi8(foo) + +; CHECK-NEXT: R_AVR_8_HLO8 +.byte hlo8(foo) + +; CHECK-NEXT: R_AVR_DIFF8 +.byte foo - bar + +; CHECK-NEXT: R_AVR_DIFF16 +.word foo - bar + +; CHECK-NEXT: R_AVR_DIFF32 +.long foo - bar