aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--test/MC/AsmParser/conditional_asm.s12
-rw-r--r--tools/llvm-mc/AsmCond.h38
-rw-r--r--tools/llvm-mc/AsmParser.cpp159
-rw-r--r--tools/llvm-mc/AsmParser.h16
4 files changed, 223 insertions, 2 deletions
diff --git a/test/MC/AsmParser/conditional_asm.s b/test/MC/AsmParser/conditional_asm.s
new file mode 100644
index 0000000..f619ef9
--- /dev/null
+++ b/test/MC/AsmParser/conditional_asm.s
@@ -0,0 +1,12 @@
+# RUN: llvm-mc -triple i386-unknown-unknown %s -I %p | FileCheck %s
+
+# CHECK: .byte 2
+.if 1+2
+ .if 1-1
+ .byte 1
+ .elseif 2+2
+ .byte 1+1
+ .else
+ .byte 0
+ .endif
+.endif
diff --git a/tools/llvm-mc/AsmCond.h b/tools/llvm-mc/AsmCond.h
new file mode 100644
index 0000000..17201b9
--- /dev/null
+++ b/tools/llvm-mc/AsmCond.h
@@ -0,0 +1,38 @@
+//===- AsmCond.h - Assembly file conditional assembly ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ASMCOND_H
+#define ASMCOND_H
+
+namespace llvm {
+
+/// AsmCond - Class to support conditional assembly
+///
+/// The conditional assembly feature (.if, .else, .elseif and .endif) is
+/// implemented with AsmCond that tells us what we are in the middle of
+/// processing. Ignore can be either true or false. When true we are ignoring
+/// the block of code in the middle of a conditional.
+
+class AsmCond {
+public:
+ enum ConditionalAssemblyType {
+ NoCond, // no conditional is being processed
+ IfCond, // inside if conditional
+ ElseIfCond, // inside elseif conditional
+ ElseCond // inside else conditional
+ };
+
+ ConditionalAssemblyType TheCond;
+ bool CondMet;
+ bool Ignore;
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/tools/llvm-mc/AsmParser.cpp b/tools/llvm-mc/AsmParser.cpp
index 5bb1ae4..4d6fac1 100644
--- a/tools/llvm-mc/AsmParser.cpp
+++ b/tools/llvm-mc/AsmParser.cpp
@@ -45,18 +45,62 @@ bool AsmParser::Run() {
bool HadError = false;
+ AsmCond StartingCondState = TheCondState;
+
// While we have input, parse each statement.
while (Lexer.isNot(AsmToken::Eof)) {
+ // Handle conditional assembly here before calling ParseStatement()
+ if (Lexer.getKind() == AsmToken::Identifier) {
+ // If we have an identifier, handle it as the key symbol.
+ AsmToken ID = Lexer.getTok();
+ SMLoc IDLoc = ID.getLoc();
+ StringRef IDVal = ID.getString();
+
+ if (IDVal == ".if" ||
+ IDVal == ".elseif" ||
+ IDVal == ".else" ||
+ IDVal == ".endif") {
+ if (!ParseConditionalAssemblyDirectives(IDVal, IDLoc))
+ continue;
+ HadError = true;
+ EatToEndOfStatement();
+ continue;
+ }
+ }
+ if (TheCondState.Ignore) {
+ EatToEndOfStatement();
+ continue;
+ }
+
if (!ParseStatement()) continue;
- // If we had an error, remember it and recover by skipping to the next line.
+ // We had an error, remember it and recover by skipping to the next line.
HadError = true;
EatToEndOfStatement();
}
+
+ if (TheCondState.TheCond != StartingCondState.TheCond ||
+ TheCondState.Ignore != StartingCondState.Ignore)
+ return TokError("unmatched .ifs or .elses");
return HadError;
}
+/// ParseConditionalAssemblyDirectives - parse the conditional assembly
+/// directives
+bool AsmParser::ParseConditionalAssemblyDirectives(StringRef Directive,
+ SMLoc DirectiveLoc) {
+ if (Directive == ".if")
+ return ParseDirectiveIf(DirectiveLoc);
+ if (Directive == ".elseif")
+ return ParseDirectiveElseIf(DirectiveLoc);
+ if (Directive == ".else")
+ return ParseDirectiveElse(DirectiveLoc);
+ if (Directive == ".endif")
+ return ParseDirectiveEndIf(DirectiveLoc);
+ return true;
+}
+
/// EatToEndOfStatement - Throw away the rest of the line for testing purposes.
void AsmParser::EatToEndOfStatement() {
while (Lexer.isNot(AsmToken::EndOfStatement) &&
@@ -1264,3 +1308,116 @@ bool AsmParser::ParseDirectiveDarwinDumpOrLoad(SMLoc IDLoc, bool IsDump) {
return false;
}
+
+/// ParseDirectiveIf
+/// ::= .if expression
+bool AsmParser::ParseDirectiveIf(SMLoc DirectiveLoc) {
+ // Consume the identifier that was the .if directive
+ Lexer.Lex();
+
+ TheCondStack.push_back(TheCondState);
+ TheCondState.TheCond = AsmCond::IfCond;
+ if(TheCondState.Ignore) {
+ EatToEndOfStatement();
+ }
+ else {
+ int64_t ExprValue;
+ if (ParseAbsoluteExpression(ExprValue))
+ return true;
+
+ if (Lexer.isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.if' directive");
+
+ Lexer.Lex();
+
+ TheCondState.CondMet = ExprValue;
+ TheCondState.Ignore = !TheCondState.CondMet;
+ }
+
+ return false;
+}
+
+/// ParseDirectiveElseIf
+/// ::= .elseif expression
+bool AsmParser::ParseDirectiveElseIf(SMLoc DirectiveLoc) {
+ if (TheCondState.TheCond != AsmCond::IfCond &&
+ TheCondState.TheCond != AsmCond::ElseIfCond)
+ Error(DirectiveLoc, "Encountered a .elseif that doesn't follow a .if or "
+ " an .elseif");
+ TheCondState.TheCond = AsmCond::ElseIfCond;
+
+ // Consume the identifier that was the .elseif directive
+ Lexer.Lex();
+
+ bool LastIgnoreState = false;
+ if (!TheCondStack.empty())
+ LastIgnoreState = TheCondStack.back().Ignore;
+ if (LastIgnoreState || TheCondState.CondMet) {
+ TheCondState.Ignore = true;
+ EatToEndOfStatement();
+ }
+ else {
+ int64_t ExprValue;
+ if (ParseAbsoluteExpression(ExprValue))
+ return true;
+
+ if (Lexer.isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.elseif' directive");
+
+ Lexer.Lex();
+ TheCondState.CondMet = ExprValue;
+ TheCondState.Ignore = !TheCondState.CondMet;
+ }
+
+ return false;
+}
+
+/// ParseDirectiveElse
+/// ::= .else
+bool AsmParser::ParseDirectiveElse(SMLoc DirectiveLoc) {
+ // Consume the identifier that was the .else directive
+ Lexer.Lex();
+
+ if (Lexer.isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.else' directive");
+
+ Lexer.Lex();
+
+ if (TheCondState.TheCond != AsmCond::IfCond &&
+ TheCondState.TheCond != AsmCond::ElseIfCond)
+ Error(DirectiveLoc, "Encountered a .else that doesn't follow a .if or an "
+ ".elseif");
+ TheCondState.TheCond = AsmCond::ElseCond;
+ bool LastIgnoreState = false;
+ if (!TheCondStack.empty())
+ LastIgnoreState = TheCondStack.back().Ignore;
+ if (LastIgnoreState || TheCondState.CondMet)
+ TheCondState.Ignore = true;
+ else
+ TheCondState.Ignore = false;
+
+ return false;
+}
+
+/// ParseDirectiveEndIf
+/// ::= .endif
+bool AsmParser::ParseDirectiveEndIf(SMLoc DirectiveLoc) {
+ // Consume the identifier that was the .endif directive
+ Lexer.Lex();
+
+ if (Lexer.isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.endif' directive");
+
+ Lexer.Lex();
+
+ if ((TheCondState.TheCond == AsmCond::NoCond) ||
+ TheCondStack.empty())
+ Error(DirectiveLoc, "Encountered a .endif that doesn't follow a .if or "
+ ".else");
+ if (!TheCondStack.empty()) {
+ TheCondState = TheCondStack.back();
+ TheCondStack.pop_back();
+ }
+
+ return false;
+}
diff --git a/tools/llvm-mc/AsmParser.h b/tools/llvm-mc/AsmParser.h
index 7a4c832..c6f6f63 100644
--- a/tools/llvm-mc/AsmParser.h
+++ b/tools/llvm-mc/AsmParser.h
@@ -14,12 +14,15 @@
#ifndef ASMPARSER_H
#define ASMPARSER_H
+#include <vector>
#include "AsmLexer.h"
+#include "AsmCond.h"
#include "llvm/MC/MCAsmParser.h"
#include "llvm/MC/MCStreamer.h"
namespace llvm {
class AsmExpr;
+class AsmCond;
class MCContext;
class MCInst;
class MCStreamer;
@@ -33,7 +36,10 @@ private:
MCContext &Ctx;
MCStreamer &Out;
TargetAsmParser *TargetParser;
-
+
+ AsmCond TheCondState;
+ std::vector<AsmCond> TheCondStack;
+
public:
AsmParser(SourceMgr &_SM, MCContext &_Ctx, MCStreamer &_Out)
: Lexer(_SM), Ctx(_Ctx), Out(_Out), TargetParser(0) {}
@@ -67,6 +73,8 @@ private:
bool TokError(const char *Msg);
+ bool ParseConditionalAssemblyDirectives(StringRef Directive,
+ SMLoc DirectiveLoc);
void EatToEndOfStatement();
bool ParseAssignment(const StringRef &Name, bool IsDotSet);
@@ -118,6 +126,12 @@ private:
bool ParseDirectiveAbort(); // ".abort"
bool ParseDirectiveInclude(); // ".include"
+
+ bool ParseDirectiveIf(SMLoc DirectiveLoc); // ".if"
+ bool ParseDirectiveElseIf(SMLoc DirectiveLoc); // ".elseif"
+ bool ParseDirectiveElse(SMLoc DirectiveLoc); // ".else"
+ bool ParseDirectiveEndIf(SMLoc DirectiveLoc); // .endif
+
};
} // end namespace llvm