Fix PR8565.
This moves most of the isUsed logic to the MCSymbol itself. With this we get a bit more relaxed about allowing definitions after uses: uses that don't evaluate their argument immediately (jmp foo) are accepted. ddunbar, this was the smallest compromise I could think of that lets us accept gcc (and clang!) assembly. llvm-svn: 119144
This commit is contained in:
parent
99da11cf04
commit
46c79ef113
|
@ -52,15 +52,14 @@ namespace llvm {
|
||||||
/// "Lfoo" or ".foo".
|
/// "Lfoo" or ".foo".
|
||||||
unsigned IsTemporary : 1;
|
unsigned IsTemporary : 1;
|
||||||
|
|
||||||
/// IsUsedInExpr - True if this symbol has been used in an expression and
|
/// IsUsed - True if this symbol has been used.
|
||||||
/// cannot be redefined.
|
mutable unsigned IsUsed : 1;
|
||||||
unsigned IsUsedInExpr : 1;
|
|
||||||
|
|
||||||
private: // MCContext creates and uniques these.
|
private: // MCContext creates and uniques these.
|
||||||
friend class MCContext;
|
friend class MCContext;
|
||||||
MCSymbol(StringRef name, bool isTemporary)
|
MCSymbol(StringRef name, bool isTemporary)
|
||||||
: Name(name), Section(0), Value(0),
|
: Name(name), Section(0), Value(0),
|
||||||
IsTemporary(isTemporary), IsUsedInExpr(false) {}
|
IsTemporary(isTemporary), IsUsed(false) {}
|
||||||
|
|
||||||
MCSymbol(const MCSymbol&); // DO NOT IMPLEMENT
|
MCSymbol(const MCSymbol&); // DO NOT IMPLEMENT
|
||||||
void operator=(const MCSymbol&); // DO NOT IMPLEMENT
|
void operator=(const MCSymbol&); // DO NOT IMPLEMENT
|
||||||
|
@ -74,9 +73,9 @@ namespace llvm {
|
||||||
/// isTemporary - Check if this is an assembler temporary symbol.
|
/// isTemporary - Check if this is an assembler temporary symbol.
|
||||||
bool isTemporary() const { return IsTemporary; }
|
bool isTemporary() const { return IsTemporary; }
|
||||||
|
|
||||||
/// isUsedInExpr - Check if this is an assembler temporary symbol.
|
/// isUsed - Check if this is used.
|
||||||
bool isUsedInExpr() const { return IsUsedInExpr; }
|
bool isUsed() const { return IsUsed; }
|
||||||
void setUsedInExpr(bool Value) { IsUsedInExpr = Value; }
|
void setUsed(bool Value) const { IsUsed = Value; }
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
/// @name Associated Sections
|
/// @name Associated Sections
|
||||||
|
@ -135,6 +134,7 @@ namespace llvm {
|
||||||
/// getValue() - Get the value for variable symbols.
|
/// getValue() - Get the value for variable symbols.
|
||||||
const MCExpr *getVariableValue() const {
|
const MCExpr *getVariableValue() const {
|
||||||
assert(isVariable() && "Invalid accessor!");
|
assert(isVariable() && "Invalid accessor!");
|
||||||
|
IsUsed = true;
|
||||||
return Value;
|
return Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -485,9 +485,6 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) {
|
||||||
std::pair<StringRef, StringRef> Split = Identifier.split('@');
|
std::pair<StringRef, StringRef> Split = Identifier.split('@');
|
||||||
MCSymbol *Sym = getContext().GetOrCreateSymbol(Split.first);
|
MCSymbol *Sym = getContext().GetOrCreateSymbol(Split.first);
|
||||||
|
|
||||||
// Mark the symbol as used in an expression.
|
|
||||||
Sym->setUsedInExpr(true);
|
|
||||||
|
|
||||||
// Lookup the symbol variant if used.
|
// Lookup the symbol variant if used.
|
||||||
MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
|
MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
|
||||||
if (Split.first.size() != Identifier.size()) {
|
if (Split.first.size() != Identifier.size()) {
|
||||||
|
@ -1191,6 +1188,25 @@ void AsmParser::HandleMacroExit() {
|
||||||
ActiveMacros.pop_back();
|
ActiveMacros.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void MarkUsed(const MCExpr *Value) {
|
||||||
|
switch (Value->getKind()) {
|
||||||
|
case MCExpr::Binary:
|
||||||
|
MarkUsed(static_cast<const MCBinaryExpr*>(Value)->getLHS());
|
||||||
|
MarkUsed(static_cast<const MCBinaryExpr*>(Value)->getRHS());
|
||||||
|
break;
|
||||||
|
case MCExpr::Target:
|
||||||
|
case MCExpr::Constant:
|
||||||
|
break;
|
||||||
|
case MCExpr::SymbolRef: {
|
||||||
|
static_cast<const MCSymbolRefExpr*>(Value)->getSymbol().setUsed(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MCExpr::Unary:
|
||||||
|
MarkUsed(static_cast<const MCUnaryExpr*>(Value)->getSubExpr());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool AsmParser::ParseAssignment(StringRef Name) {
|
bool AsmParser::ParseAssignment(StringRef Name) {
|
||||||
// FIXME: Use better location, we should use proper tokens.
|
// FIXME: Use better location, we should use proper tokens.
|
||||||
SMLoc EqualLoc = Lexer.getLoc();
|
SMLoc EqualLoc = Lexer.getLoc();
|
||||||
|
@ -1199,6 +1215,8 @@ bool AsmParser::ParseAssignment(StringRef Name) {
|
||||||
if (ParseExpression(Value))
|
if (ParseExpression(Value))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
MarkUsed(Value);
|
||||||
|
|
||||||
if (Lexer.isNot(AsmToken::EndOfStatement))
|
if (Lexer.isNot(AsmToken::EndOfStatement))
|
||||||
return TokError("unexpected token in assignment");
|
return TokError("unexpected token in assignment");
|
||||||
|
|
||||||
|
@ -1213,7 +1231,7 @@ bool AsmParser::ParseAssignment(StringRef Name) {
|
||||||
//
|
//
|
||||||
// FIXME: Diagnostics. Note the location of the definition as a label.
|
// FIXME: Diagnostics. Note the location of the definition as a label.
|
||||||
// FIXME: Diagnose assignment to protected identifier (e.g., register name).
|
// FIXME: Diagnose assignment to protected identifier (e.g., register name).
|
||||||
if (Sym->isUndefined() && !Sym->isUsedInExpr())
|
if (Sym->isUndefined() && !Sym->isUsed() && !Sym->isVariable())
|
||||||
; // Allow redefinitions of undefined symbols only used in directives.
|
; // Allow redefinitions of undefined symbols only used in directives.
|
||||||
else if (!Sym->isUndefined() && !Sym->isAbsolute())
|
else if (!Sym->isUndefined() && !Sym->isAbsolute())
|
||||||
return Error(EqualLoc, "redefinition of '" + Name + "'");
|
return Error(EqualLoc, "redefinition of '" + Name + "'");
|
||||||
|
@ -1222,13 +1240,14 @@ bool AsmParser::ParseAssignment(StringRef Name) {
|
||||||
else if (!isa<MCConstantExpr>(Sym->getVariableValue()))
|
else if (!isa<MCConstantExpr>(Sym->getVariableValue()))
|
||||||
return Error(EqualLoc, "invalid reassignment of non-absolute variable '" +
|
return Error(EqualLoc, "invalid reassignment of non-absolute variable '" +
|
||||||
Name + "'");
|
Name + "'");
|
||||||
|
|
||||||
|
// Don't count these checks as uses.
|
||||||
|
Sym->setUsed(false);
|
||||||
} else
|
} else
|
||||||
Sym = getContext().GetOrCreateSymbol(Name);
|
Sym = getContext().GetOrCreateSymbol(Name);
|
||||||
|
|
||||||
// FIXME: Handle '.'.
|
// FIXME: Handle '.'.
|
||||||
|
|
||||||
Sym->setUsedInExpr(true);
|
|
||||||
|
|
||||||
// Do the assignment.
|
// Do the assignment.
|
||||||
Out.EmitAssignment(Sym, Value);
|
Out.EmitAssignment(Sym, Value);
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ static bool NameNeedsQuoting(StringRef Str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MCSymbol::setVariableValue(const MCExpr *Value) {
|
void MCSymbol::setVariableValue(const MCExpr *Value) {
|
||||||
|
assert(!IsUsed && "Cannot set a variable that has already been used.");
|
||||||
assert(Value && "Invalid variable value!");
|
assert(Value && "Invalid variable value!");
|
||||||
assert((isUndefined() || (isAbsolute() && isa<MCConstantExpr>(Value))) &&
|
assert((isUndefined() || (isAbsolute() && isa<MCConstantExpr>(Value))) &&
|
||||||
"Invalid redefinition!");
|
"Invalid redefinition!");
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | elf-dump --dump-section-data | FileCheck %s
|
||||||
|
|
||||||
|
// Test that we accept .set of a symbol after it has been used in a statement.
|
||||||
|
|
||||||
|
jmp foo
|
||||||
|
.set foo, bar
|
||||||
|
|
||||||
|
// or a .quad
|
||||||
|
|
||||||
|
.quad foo2
|
||||||
|
.set foo2,bar2
|
||||||
|
|
||||||
|
// Test that there is an undefined reference to bar
|
||||||
|
// CHECK: (('st_name', 0x00000001) # 'bar'
|
||||||
|
// CHECK-NEXT: ('st_bind', 0x00000001)
|
||||||
|
// CHECK-NEXT: ('st_type', 0x00000000)
|
||||||
|
// CHECK-NEXT: ('st_other', 0x00000000)
|
||||||
|
// CHECK-NEXT: ('st_shndx', 0x00000000)
|
||||||
|
// CHECK-NEXT: ('st_value', 0x00000000)
|
||||||
|
// CHECK-NEXT: ('st_size', 0x00000000)
|
||||||
|
// CHECK-NEXT: ),
|
Loading…
Reference in New Issue