diff --git a/llvm/include/llvm/MC/MCExpr.h b/llvm/include/llvm/MC/MCExpr.h --- a/llvm/include/llvm/MC/MCExpr.h +++ b/llvm/include/llvm/MC/MCExpr.h @@ -327,6 +327,21 @@ VK_AMDGPU_ABS32_LO, // symbol@abs32@lo VK_AMDGPU_ABS32_HI, // symbol@abs32@hi + VK_VE_HI32, // symbol@hi + VK_VE_LO32, // symbol@lo + VK_VE_PC_HI32, // symbol@pc_hi + VK_VE_PC_LO32, // symbol@pc_lo + VK_VE_GOT_HI32, // symbol@got_hi + VK_VE_GOT_LO32, // symbol@got_lo + VK_VE_GOTOFF_HI32, // symbol@gotoff_hi + VK_VE_GOTOFF_LO32, // symbol@gotoff_lo + VK_VE_PLT_HI32, // symbol@plt_hi + VK_VE_PLT_LO32, // symbol@plt_lo + VK_VE_TLS_GD_HI32, // symbol@tls_gd_hi + VK_VE_TLS_GD_LO32, // symbol@tls_gd_lo + VK_VE_TPOFF_HI32, // symbol@tpoff_hi + VK_VE_TPOFF_LO32, // symbol@tpoff_lo + VK_TPREL, VK_DTPREL }; diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -342,6 +342,20 @@ case VK_AMDGPU_REL64: return "rel64"; case VK_AMDGPU_ABS32_LO: return "abs32@lo"; case VK_AMDGPU_ABS32_HI: return "abs32@hi"; + case VK_VE_HI32: return "hi"; + case VK_VE_LO32: return "lo"; + case VK_VE_PC_HI32: return "pc_hi"; + case VK_VE_PC_LO32: return "pc_lo"; + case VK_VE_GOT_HI32: return "got_hi"; + case VK_VE_GOT_LO32: return "got_lo"; + case VK_VE_GOTOFF_HI32: return "gotoff_hi"; + case VK_VE_GOTOFF_LO32: return "gotoff_lo"; + case VK_VE_PLT_HI32: return "plt_hi"; + case VK_VE_PLT_LO32: return "plt_lo"; + case VK_VE_TLS_GD_HI32: return "tls_gd_hi"; + case VK_VE_TLS_GD_LO32: return "tls_gd_lo"; + case VK_VE_TPOFF_HI32: return "tpoff_hi"; + case VK_VE_TPOFF_LO32: return "tpoff_lo"; } llvm_unreachable("Invalid variant kind"); } @@ -463,6 +477,20 @@ .Case("rel64", VK_AMDGPU_REL64) .Case("abs32@lo", VK_AMDGPU_ABS32_LO) .Case("abs32@hi", VK_AMDGPU_ABS32_HI) + .Case("hi", VK_VE_HI32) + .Case("lo", VK_VE_LO32) + .Case("pc_hi", VK_VE_PC_HI32) + .Case("pc_lo", VK_VE_PC_LO32) + .Case("got_hi", VK_VE_GOT_HI32) + .Case("got_lo", VK_VE_GOT_LO32) + .Case("gotoff_hi", VK_VE_GOTOFF_HI32) + .Case("gotoff_lo", VK_VE_GOTOFF_LO32) + .Case("plt_hi", VK_VE_PLT_HI32) + .Case("plt_lo", VK_VE_PLT_LO32) + .Case("tls_gd_hi", VK_VE_TLS_GD_HI32) + .Case("tls_gd_lo", VK_VE_TLS_GD_LO32) + .Case("tpoff_hi", VK_VE_TPOFF_HI32) + .Case("tpoff_lo", VK_VE_TPOFF_LO32) .Default(VK_Invalid); } diff --git a/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp b/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp --- a/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp +++ b/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp @@ -65,8 +65,6 @@ unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) override; - // Helper function to parse and generate identifier with relocation. - const MCExpr *parseIdentifier(StringRef Identifier); // Custom parse functions for VE specific operands. OperandMatchResultTy parseMEMOperand(OperandVector &Operands); OperandMatchResultTy parseMEMAsOperand(OperandVector &Operands); @@ -75,6 +73,13 @@ OperandMatchResultTy parseMImmOperand(OperandVector &Operands); OperandMatchResultTy parseOperand(OperandVector &Operands, StringRef Name); OperandMatchResultTy parseVEAsmOperand(std::unique_ptr &Operand); + + // Helper function to parse expression with a symbol. + const MCExpr *extractModifierFromExpr(const MCExpr *E, + VEMCExpr::VariantKind &Variant); + const MCExpr *fixupVariantKind(const MCExpr *E); + bool parseExpression(const MCExpr *&EVal); + // Split the mnemonic stripping conditional code and quantifiers StringRef splitMnemonic(StringRef Name, SMLoc NameLoc, OperandVector *Operands); @@ -948,27 +953,163 @@ return true; } -const MCExpr *VEAsmParser::parseIdentifier(StringRef Identifier) { - StringRef Modifier; - // Search @modifiers like "symbol@hi". - size_t at = Identifier.rfind('@'); - if (at != 0 || at != StringRef::npos) { - std::pair Pair = Identifier.rsplit("@"); - if (!Pair.first.empty() && !Pair.second.empty()) { - Identifier = Pair.first; - Modifier = Pair.second; +/// Extract \code @lo32/@hi32/etc \endcode modifier from expression. +/// Recursively scan the expression and check for VK_VE_HI32/LO32/etc +/// symbol variants. If all symbols with modifier use the same +/// variant, return the corresponding VEMCExpr::VariantKind, +/// and a modified expression using the default symbol variant. +/// Otherwise, return NULL. +const MCExpr * +VEAsmParser::extractModifierFromExpr(const MCExpr *E, + VEMCExpr::VariantKind &Variant) { + MCContext &Context = getParser().getContext(); + Variant = VEMCExpr::VK_VE_None; + + switch (E->getKind()) { + case MCExpr::Target: + case MCExpr::Constant: + return nullptr; + + case MCExpr::SymbolRef: { + const MCSymbolRefExpr *SRE = cast(E); + + switch (SRE->getKind()) { + case MCSymbolRefExpr::VK_None: + // Use VK_VE_REFLONG to a symbol without modifiers. + Variant = VEMCExpr::VK_VE_REFLONG; + break; + case MCSymbolRefExpr::VK_VE_HI32: + Variant = VEMCExpr::VK_VE_HI32; + break; + case MCSymbolRefExpr::VK_VE_LO32: + Variant = VEMCExpr::VK_VE_LO32; + break; + case MCSymbolRefExpr::VK_VE_PC_HI32: + Variant = VEMCExpr::VK_VE_PC_HI32; + break; + case MCSymbolRefExpr::VK_VE_PC_LO32: + Variant = VEMCExpr::VK_VE_PC_LO32; + break; + case MCSymbolRefExpr::VK_VE_GOT_HI32: + Variant = VEMCExpr::VK_VE_GOT_HI32; + break; + case MCSymbolRefExpr::VK_VE_GOT_LO32: + Variant = VEMCExpr::VK_VE_GOT_LO32; + break; + case MCSymbolRefExpr::VK_VE_GOTOFF_HI32: + Variant = VEMCExpr::VK_VE_GOTOFF_HI32; + break; + case MCSymbolRefExpr::VK_VE_GOTOFF_LO32: + Variant = VEMCExpr::VK_VE_GOTOFF_LO32; + break; + case MCSymbolRefExpr::VK_VE_PLT_HI32: + Variant = VEMCExpr::VK_VE_PLT_HI32; + break; + case MCSymbolRefExpr::VK_VE_PLT_LO32: + Variant = VEMCExpr::VK_VE_PLT_LO32; + break; + case MCSymbolRefExpr::VK_VE_TLS_GD_HI32: + Variant = VEMCExpr::VK_VE_TLS_GD_HI32; + break; + case MCSymbolRefExpr::VK_VE_TLS_GD_LO32: + Variant = VEMCExpr::VK_VE_TLS_GD_LO32; + break; + case MCSymbolRefExpr::VK_VE_TPOFF_HI32: + Variant = VEMCExpr::VK_VE_TPOFF_HI32; + break; + case MCSymbolRefExpr::VK_VE_TPOFF_LO32: + Variant = VEMCExpr::VK_VE_TPOFF_LO32; + break; + default: + return nullptr; } + + return MCSymbolRefExpr::create(&SRE->getSymbol(), Context); } - MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); - const MCExpr *Res = - MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); - VEMCExpr::VariantKind VK = VEMCExpr::parseVariantKind(Modifier); - if (VK == VEMCExpr::VK_VE_None) { - // Create identifier using default variant kind - VEMCExpr::VariantKind Kind = VEMCExpr::VK_VE_REFLONG; - return VEMCExpr::create(Kind, Res, getContext()); + + case MCExpr::Unary: { + const MCUnaryExpr *UE = cast(E); + const MCExpr *Sub = extractModifierFromExpr(UE->getSubExpr(), Variant); + if (!Sub) + return nullptr; + return MCUnaryExpr::create(UE->getOpcode(), Sub, Context); } - return VEMCExpr::create(VK, Res, getContext()); + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast(E); + VEMCExpr::VariantKind LHSVariant, RHSVariant; + const MCExpr *LHS = extractModifierFromExpr(BE->getLHS(), LHSVariant); + const MCExpr *RHS = extractModifierFromExpr(BE->getRHS(), RHSVariant); + + if (!LHS && !RHS) + return nullptr; + + if (!LHS) + LHS = BE->getLHS(); + if (!RHS) + RHS = BE->getRHS(); + + if (LHSVariant == VEMCExpr::VK_VE_None) + Variant = RHSVariant; + else if (RHSVariant == VEMCExpr::VK_VE_None) + Variant = LHSVariant; + else if (LHSVariant == RHSVariant) + Variant = LHSVariant; + else + return nullptr; + + return MCBinaryExpr::create(BE->getOpcode(), LHS, RHS, Context); + } + } + + llvm_unreachable("Invalid expression kind!"); +} + +const MCExpr *VEAsmParser::fixupVariantKind(const MCExpr *E) { + MCContext &Context = getParser().getContext(); + + switch (E->getKind()) { + case MCExpr::Target: + case MCExpr::Constant: + case MCExpr::SymbolRef: + return E; + + case MCExpr::Unary: { + const MCUnaryExpr *UE = cast(E); + const MCExpr *Sub = fixupVariantKind(UE->getSubExpr()); + if (Sub == UE->getSubExpr()) + return E; + return MCUnaryExpr::create(UE->getOpcode(), Sub, Context); + } + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast(E); + const MCExpr *LHS = fixupVariantKind(BE->getLHS()); + const MCExpr *RHS = fixupVariantKind(BE->getRHS()); + if (LHS == BE->getLHS() && RHS == BE->getRHS()) + return E; + return MCBinaryExpr::create(BE->getOpcode(), LHS, RHS, Context); + } + } + + llvm_unreachable("Invalid expression kind!"); +} + +/// ParseExpression. This differs from the default "parseExpression" in that +/// it handles modifiers. +bool VEAsmParser::parseExpression(const MCExpr *&EVal) { + // Handle \code symbol @lo32/@hi32/etc \endcode. + if (getParser().parseExpression(EVal)) + return true; + + // Convert MCSymbolRefExpr with VK_* to MCExpr with VK_*. + EVal = fixupVariantKind(EVal); + VEMCExpr::VariantKind Variant; + const MCExpr *E = extractModifierFromExpr(EVal, Variant); + if (E) + EVal = VEMCExpr::create(Variant, E, getParser().getContext()); + + return false; } OperandMatchResultTy VEAsmParser::parseMEMOperand(OperandVector &Operands) { @@ -992,27 +1133,16 @@ case AsmToken::Minus: case AsmToken::Integer: - case AsmToken::Dot: { + case AsmToken::Dot: + case AsmToken::Identifier: { const MCExpr *EVal; - if (!getParser().parseExpression(EVal, E)) + if (!parseExpression(EVal)) Offset = VEOperand::CreateImm(EVal, S, E); else return MatchOperand_NoMatch; break; } - case AsmToken::Identifier: { - StringRef Identifier; - if (!getParser().parseIdentifier(Identifier)) { - E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - const MCExpr *EVal = parseIdentifier(Identifier); - - E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - Offset = VEOperand::CreateImm(EVal, S, E); - } - break; - } - case AsmToken::LParen: // empty disp (= 0) Offset = @@ -1110,9 +1240,10 @@ case AsmToken::Minus: case AsmToken::Integer: - case AsmToken::Dot: { + case AsmToken::Dot: + case AsmToken::Identifier: { const MCExpr *EVal; - if (!getParser().parseExpression(EVal, E)) + if (!parseExpression(EVal)) Offset = VEOperand::CreateImm(EVal, S, E); else return MatchOperand_NoMatch; @@ -1275,22 +1406,10 @@ case AsmToken::Minus: case AsmToken::Integer: case AsmToken::Dot: - if (!getParser().parseExpression(EVal, E)) + case AsmToken::Identifier: + if (!parseExpression(EVal)) Op = VEOperand::CreateImm(EVal, S, E); break; - - case AsmToken::Identifier: { - StringRef Identifier; - if (!getParser().parseIdentifier(Identifier)) { - E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); - - const MCExpr *Res = - MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); - Op = VEOperand::CreateImm(Res, S, E); - } - break; - } } return (Op) ? MatchOperand_Success : MatchOperand_ParseFail; } diff --git a/llvm/test/MC/VE/sym-br.s b/llvm/test/MC/VE/sym-br.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/VE/sym-br.s @@ -0,0 +1,10 @@ +# RUN: llvm-mc -triple=ve %s -o - | FileCheck %s +# RUN: llvm-mc -triple=ve -filetype=obj %s -o - | llvm-objdump -r - | FileCheck %s --check-prefix=CHECK-OBJ + + b.l.t tgt(, %s1) + b.l.t tgt+24(, %s1) +# CHECK: b.l.t tgt(, %s1) +# CHECK-NEXT: b.l.t tgt+24(, %s1) + +# CHECK-OBJ: 0 R_VE_REFLONG tgt +# CHECK-OBJ-NEXT: 8 R_VE_REFLONG tgt+0x18 diff --git a/llvm/test/MC/VE/symbols.s b/llvm/test/MC/VE/symbols.s --- a/llvm/test/MC/VE/symbols.s +++ b/llvm/test/MC/VE/symbols.s @@ -5,11 +5,19 @@ lea %s1, var@lo and %s1, %s1, (32)0 lea.sl %s1, var@hi(, %s1) + lea %s1, var+8@lo + and %s1, %s1, (32)0 + lea.sl %s1, var+8@hi(, %s1) # CHECK: lea %s0, var # CHECK-NEXT: lea %s1, var@lo # CHECK-NEXT: and %s1, %s1, (32)0 # CHECK-NEXT: lea.sl %s1, var@hi(, %s1) +# CHECK-NEXT: lea %s1, var+8@lo +# CHECK-NEXT: and %s1, %s1, (32)0 +# CHECK-NEXT: lea.sl %s1, var+8@hi(, %s1) # CHECK-OBJ: 0 R_VE_REFLONG var # CHECK-OBJ-NEXT: 8 R_VE_LO32 var # CHECK-OBJ-NEXT: 18 R_VE_HI32 var +# CHECK-OBJ-NEXT: 20 R_VE_LO32 var+0x8 +# CHECK-OBJ-NEXT: 30 R_VE_HI32 var+0x8