Index: include/llvm/BinaryFormat/ELFRelocs/AVR.def =================================================================== --- include/llvm/BinaryFormat/ELFRelocs/AVR.def +++ include/llvm/BinaryFormat/ELFRelocs/AVR.def @@ -38,3 +38,6 @@ ELF_RELOC(R_AVR_LDS_STS_16, 33) ELF_RELOC(R_AVR_PORT6, 34) ELF_RELOC(R_AVR_PORT5, 35) +ELF_RELOC(R_AVR_DIFF8, 36) +ELF_RELOC(R_AVR_DIFF16, 37) +ELF_RELOC(R_AVR_DIFF32, 38) 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) @@ -432,6 +434,11 @@ if (ModifierKind != AVRMCExpr::VK_AVR_None) { Parser.Lex(); Parser.Lex(); // Eat modifier name and parenthesis + // FIXME: Not support gs(foo) so just eat gs. + if (Parser.getTok().getString() == "gs" && + Parser.getTok().getKind() == AsmToken::Identifier) { + Parser.Lex(); + } } else { return Error(Parser.getTok().getLoc(), "unknown modifier"); } @@ -580,7 +587,35 @@ 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) { + const MCExpr *Value; + return Parser.parseExpression(Value); + } + 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 @@ -423,6 +423,9 @@ {"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 @@ -107,6 +107,12 @@ 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 @@ -119,6 +119,9 @@ /// 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: test/MC/AVR/relocations.s =================================================================== --- test/MC/AVR/relocations.s +++ test/MC/AVR/relocations.s @@ -73,3 +73,33 @@ ; CHECK-NEXT: R_AVR_HH8_LDI_PM_NEG 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