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) @@ -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,30 @@ 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"); } + 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 +602,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 @@ -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