MC: Add MCSpecifierExpr to unify target MCExprs

Many targets define MCTargetExpr subclasses just to encode an expression
with a relocation specifier. Create a generic MCSpecifierExpr to be
inherited instead. Migrate M68k and SPARC as examples.
This commit is contained in:
Fangrui Song
2025-06-07 11:33:40 -07:00
parent b4b86a7a3c
commit 97a32f2ad9
14 changed files with 75 additions and 56 deletions

View File

@@ -38,6 +38,7 @@ public:
Constant, ///< Constant expressions.
SymbolRef, ///< References to labels and assigned expressions.
Unary, ///< Unary expressions.
Specifier, ///< Expression with a relocation specifier.
Target ///< Target specific expression.
};
@@ -502,6 +503,33 @@ public:
}
};
/// Extension point for target-specific MCExpr subclasses with a relocation
/// specifier, serving as a replacement for MCSymbolRefExpr::VariantKind.
/// Limit this to top-level use, avoiding its inclusion as a subexpression.
class LLVM_ABI MCSpecifierExpr : public MCExpr {
protected:
using Spec = uint16_t;
const MCExpr *Expr;
// Target-specific relocation specifier code
const Spec specifier;
protected:
explicit MCSpecifierExpr(const MCExpr *Expr, Spec S)
: MCExpr(Specifier, SMLoc()), Expr(Expr), specifier(S) {}
virtual ~MCSpecifierExpr();
public:
Spec getSpecifier() const { return specifier; }
const MCExpr *getSubExpr() const { return Expr; }
virtual void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const = 0;
bool evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm) const;
static bool classof(const MCExpr *E) {
return E->getKind() == MCExpr::Specifier;
}
};
} // end namespace llvm
#endif // LLVM_MC_MCEXPR_H

View File

@@ -15,6 +15,7 @@
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/Casting.h"
@@ -171,6 +172,9 @@ void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI,
OS << ')';
return;
}
case MCExpr::Specifier:
return cast<MCSpecifierExpr>(this)->printImpl(OS, MAI);
}
llvm_unreachable("Invalid expression kind!");
@@ -207,6 +211,9 @@ bool MCExpr::isSymbolUsedInExpression(const MCSymbol *Sym) const {
static_cast<const MCUnaryExpr *>(this)->getSubExpr();
return SubExpr->isSymbolUsedInExpression(Sym);
}
case MCExpr::Specifier:
return static_cast<const MCSpecifierExpr *>(this)->isSymbolUsedInExpression(
Sym);
}
llvm_unreachable("Unknown expr kind!");
@@ -702,6 +709,8 @@ bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm,
return true;
}
case Specifier:
return cast<MCSpecifierExpr>(this)->evaluateAsRelocatableImpl(Res, Asm);
}
llvm_unreachable("Invalid assembly expression kind!");
@@ -750,7 +759,21 @@ MCFragment *MCExpr::findAssociatedFragment() const {
// Otherwise, return the first non-null fragment.
return LHS_F ? LHS_F : RHS_F;
}
case Specifier:
return cast<MCSpecifierExpr>(this)->getSubExpr()->findAssociatedFragment();
}
llvm_unreachable("Invalid assembly expression kind!");
}
MCSpecifierExpr::~MCSpecifierExpr() {}
bool MCSpecifierExpr::evaluateAsRelocatableImpl(MCValue &Res,
const MCAssembler *Asm) const {
if (!getSubExpr()->evaluateAsRelocatable(Res, Asm))
return false;
Res.setSpecifier(specifier);
return !Res.getSubSym();
}

View File

@@ -1344,6 +1344,8 @@ const MCExpr *MCAsmParser::applySpecifier(const MCExpr *E, uint32_t Spec) {
// Recurse over the given expression, rebuilding it to apply the given variant
// if there is exactly one symbol.
switch (E->getKind()) {
case MCExpr::Specifier:
llvm_unreachable("cannot apply another specifier to MCSpecifierExpr");
case MCExpr::Target:
case MCExpr::Constant:
return nullptr;

View File

@@ -1186,6 +1186,10 @@ void MCStreamer::visitUsedExpr(const MCExpr &Expr) {
case MCExpr::Unary:
visitUsedExpr(*cast<MCUnaryExpr>(Expr).getSubExpr());
break;
case MCExpr::Specifier:
visitUsedExpr(*cast<MCSpecifierExpr>(Expr).getSubExpr());
break;
}
}

View File

@@ -547,6 +547,7 @@ static bool needsPCRel(const MCExpr *Expr) {
}
case MCExpr::Unary:
return needsPCRel(cast<MCUnaryExpr>(Expr)->getSubExpr());
case MCExpr::Specifier:
case MCExpr::Target:
case MCExpr::Constant:
return false;

View File

@@ -557,6 +557,8 @@ static void knownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM,
case MCExpr::ExprKind::Target: {
targetOpKnownBitsMapHelper(Expr, KBM, Depth);
return;
case MCExpr::Specifier:
llvm_unreachable("unused by this backend");
}
}
}

View File

@@ -19,14 +19,3 @@ const M68kMCExpr *M68kMCExpr::create(const MCExpr *Expr, Specifier S,
}
void M68kMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {}
bool M68kMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
const MCAssembler *Asm) const {
if (!getSubExpr()->evaluateAsRelocatable(Res, Asm))
return false;
Res.setSpecifier(specifier);
return !Res.getSubSym();
}
void M68kMCExpr::visitUsedExpr(MCStreamer &S) const { S.visitUsedExpr(*Expr); }

View File

@@ -18,7 +18,7 @@
namespace llvm {
class M68kMCExpr : public MCTargetExpr {
class M68kMCExpr : public MCSpecifierExpr {
public:
enum Specifier {
VK_None,
@@ -34,27 +34,14 @@ public:
VK_TPOFF,
};
private:
const MCExpr *Expr;
const Specifier specifier;
protected:
explicit M68kMCExpr(const MCExpr *Expr, Specifier S)
: Expr(Expr), specifier(S) {}
: MCSpecifierExpr(Expr, S) {}
public:
static const M68kMCExpr *create(const MCExpr *, Specifier, MCContext &);
Specifier getSpecifier() const { return specifier; }
const MCExpr *getSubExpr() const { return Expr; }
void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
bool evaluateAsRelocatableImpl(MCValue &Res,
const MCAssembler *Asm) const override;
void visitUsedExpr(MCStreamer &Streamer) const override;
MCFragment *findAssociatedFragment() const override {
return getSubExpr()->findAssociatedFragment();
}
};
} // namespace llvm

View File

@@ -1783,6 +1783,8 @@ static bool isEvaluated(const MCExpr *Expr) {
}
case MCExpr::Unary:
return isEvaluated(cast<MCUnaryExpr>(Expr)->getSubExpr());
case MCExpr::Specifier:
llvm_unreachable("unused by this backend");
case MCExpr::Target:
return true;
}

View File

@@ -87,6 +87,8 @@ EvaluateCRExpr(const MCExpr *E) {
return Res < 0 ? -1 : Res;
}
case MCExpr::Specifier:
llvm_unreachable("unused by this backend");
}
llvm_unreachable("Invalid expression kind!");
@@ -1420,6 +1422,8 @@ const MCExpr *PPCAsmParser::extractSpecifier(const MCExpr *E,
return MCBinaryExpr::create(BE->getOpcode(), LHS, RHS, Context);
break;
}
case MCExpr::Specifier:
llvm_unreachable("unused by this backend");
}
return E;

View File

@@ -1661,6 +1661,9 @@ static bool hasGOTReference(const MCExpr *Expr) {
case MCExpr::Unary:
return hasGOTReference(cast<MCUnaryExpr>(Expr)->getSubExpr());
case MCExpr::Specifier:
llvm_unreachable("unused by this backend");
}
return false;
}

View File

@@ -133,16 +133,3 @@ uint16_t SparcMCExpr::getFixupKind() const {
assert(uint16_t(specifier) < FirstTargetFixupKind);
return specifier;
}
bool SparcMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
const MCAssembler *Asm) const {
if (!getSubExpr()->evaluateAsRelocatable(Res, Asm))
return false;
Res.setSpecifier(specifier);
return true;
}
void SparcMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
Streamer.visitUsedExpr(*getSubExpr());
}

View File

@@ -20,32 +20,17 @@
namespace llvm {
class StringRef;
class SparcMCExpr : public MCTargetExpr {
class SparcMCExpr : public MCSpecifierExpr {
private:
const uint16_t specifier;
const MCExpr *Expr;
explicit SparcMCExpr(uint16_t S, const MCExpr *Expr)
: specifier(S), Expr(Expr) {}
: MCSpecifierExpr(Expr, S) {}
public:
static const SparcMCExpr *create(uint16_t S, const MCExpr *Expr,
MCContext &Ctx);
uint16_t getSpecifier() const { return specifier; }
const MCExpr *getSubExpr() const { return Expr; }
uint16_t getFixupKind() const;
void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
bool evaluateAsRelocatableImpl(MCValue &Res,
const MCAssembler *Asm) const override;
void visitUsedExpr(MCStreamer &Streamer) const override;
MCFragment *findAssociatedFragment() const override {
return getSubExpr()->findAssociatedFragment();
}
static bool classof(const MCExpr *E) {
return E->getKind() == MCExpr::Target;
}
static uint16_t parseSpecifier(StringRef name);
static StringRef getSpecifierName(uint16_t S);

View File

@@ -1048,6 +1048,8 @@ const MCExpr *VEAsmParser::extractSpecifier(const MCExpr *E,
case MCExpr::Target:
case MCExpr::Constant:
return nullptr;
case MCExpr::Specifier:
llvm_unreachable("unused by this backend");
case MCExpr::SymbolRef: {
const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(E);