[Powerpc darwin] AsmParser Base implementation.

This is a base implementation of the powerpc-apple-darwin asm parser dialect.

* Enables infrastructure (essentially isDarwin()) and fixes up the parsing of asm directives to separate out ELF and MachO/Darwin additions.
* Enables parsing of {r,f,v}XX as register identifiers.
* Enables parsing of lo16() hi16() and ha16() as modifiers.

The changes to the test case are from David Fang (fangism).

llvm-svn: 197324
This commit is contained in:
Iain Sandoe 2013-12-14 13:34:02 +00:00
parent db9ee00b59
commit e0b4cb62f5
2 changed files with 157 additions and 40 deletions

View File

@ -177,6 +177,7 @@ class PPCAsmParser : public MCTargetAsmParser {
MCAsmParser &Parser;
const MCInstrInfo &MII;
bool IsPPC64;
bool IsDarwin;
MCAsmParser &getParser() const { return Parser; }
MCAsmLexer &getLexer() const { return Parser.getLexer(); }
@ -185,6 +186,7 @@ class PPCAsmParser : public MCTargetAsmParser {
bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); }
bool isPPC64() const { return IsPPC64; }
bool isDarwin() const { return IsDarwin; }
bool MatchRegisterName(const AsmToken &Tok,
unsigned &RegNo, int64_t &IntVal);
@ -195,12 +197,14 @@ class PPCAsmParser : public MCTargetAsmParser {
PPCMCExpr::VariantKind &Variant);
const MCExpr *FixupVariantKind(const MCExpr *E);
bool ParseExpression(const MCExpr *&EVal);
bool ParseDarwinExpression(const MCExpr *&EVal);
bool ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
bool ParseDirectiveWord(unsigned Size, SMLoc L);
bool ParseDirectiveTC(unsigned Size, SMLoc L);
bool ParseDirectiveMachine(SMLoc L);
bool ParseDarwinDirectiveMachine(SMLoc L);
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
SmallVectorImpl<MCParsedAsmOperand*> &Operands,
@ -227,6 +231,7 @@ public:
Triple TheTriple(STI.getTargetTriple());
IsPPC64 = (TheTriple.getArch() == Triple::ppc64 ||
TheTriple.getArch() == Triple::ppc64le);
IsDarwin = TheTriple.isMacOSX();
// Initialize the set of available features.
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
}
@ -1081,10 +1086,16 @@ FixupVariantKind(const MCExpr *E) {
llvm_unreachable("Invalid expression kind!");
}
/// Parse an expression. This differs from the default "parseExpression"
/// in that it handles complex \code @l/@ha \endcode modifiers.
/// ParseExpression. This differs from the default "parseExpression" in that
/// it handles modifiers.
bool PPCAsmParser::
ParseExpression(const MCExpr *&EVal) {
if (isDarwin())
return ParseDarwinExpression(EVal);
// (ELF Platforms)
// Handle \code @l/@ha \endcode
if (getParser().parseExpression(EVal))
return true;
@ -1098,6 +1109,55 @@ ParseExpression(const MCExpr *&EVal) {
return false;
}
/// ParseDarwinExpression. (MachO Platforms)
/// This differs from the default "parseExpression" in that it handles detection
/// of the \code hi16(), ha16() and lo16() \endcode modifiers. At present,
/// parseExpression() doesn't recognise the modifiers when in the Darwin/MachO
/// syntax form so it is done here. TODO: Determine if there is merit in arranging
/// for this to be done at a higher level.
bool PPCAsmParser::
ParseDarwinExpression(const MCExpr *&EVal) {
PPCMCExpr::VariantKind Variant = PPCMCExpr::VK_PPC_None;
switch (getLexer().getKind()) {
default:
break;
case AsmToken::Identifier:
// Compiler-generated Darwin identifiers begin with L,l,_ or "; thus
// something starting with any other char should be part of the
// asm syntax. If handwritten asm includes an identifier like lo16,
// then all bets are off - but no-one would do that, right?
StringRef poss = Parser.getTok().getString();
if (poss.equals_lower("lo16")) {
Variant = PPCMCExpr::VK_PPC_LO;
} else if (poss.equals_lower("hi16")) {
Variant = PPCMCExpr::VK_PPC_HI;
} else if (poss.equals_lower("ha16")) {
Variant = PPCMCExpr::VK_PPC_HA;
}
if (Variant != PPCMCExpr::VK_PPC_None) {
Parser.Lex(); // Eat the xx16
if (getLexer().isNot(AsmToken::LParen))
return Error(Parser.getTok().getLoc(), "expected '('");
Parser.Lex(); // Eat the '('
}
break;
}
if (getParser().parseExpression(EVal))
return true;
if (Variant != PPCMCExpr::VK_PPC_None) {
if (getLexer().isNot(AsmToken::RParen))
return Error(Parser.getTok().getLoc(), "expected ')'");
Parser.Lex(); // Eat the ')'
EVal = PPCMCExpr::Create(Variant, EVal, false, getParser().getContext());
}
return false;
}
/// ParseOperand
/// This handles registers in the form 'NN', '%rNN' for ELF platforms and
/// rNN for MachO.
bool PPCAsmParser::
ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
@ -1121,12 +1181,27 @@ ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
}
return Error(S, "invalid register name");
case AsmToken::Identifier:
// Note that non-register-name identifiers from the compiler will begin
// with '_', 'L'/'l' or '"'. Of course, handwritten asm could include
// identifiers like r31foo - so we fall through in the event that parsing
// a register name fails.
if (isDarwin()) {
unsigned RegNo;
int64_t IntVal;
if (!MatchRegisterName(Parser.getTok(), RegNo, IntVal)) {
Parser.Lex(); // Eat the identifier token.
Op = PPCOperand::CreateImm(IntVal, S, E, isPPC64());
Operands.push_back(Op);
return false;
}
}
// Fall-through to process non-register-name identifiers as expression.
// All other expressions
case AsmToken::LParen:
case AsmToken::Plus:
case AsmToken::Minus:
case AsmToken::Integer:
case AsmToken::Identifier:
case AsmToken::Dot:
case AsmToken::Dollar:
if (!ParseExpression(EVal))
@ -1177,11 +1252,25 @@ ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
break;
case AsmToken::Integer:
if (getParser().parseAbsoluteExpression(IntVal) ||
if (!isDarwin()) {
if (getParser().parseAbsoluteExpression(IntVal) ||
IntVal < 0 || IntVal > 31)
return Error(S, "invalid register number");
} else {
return Error(S, "unexpected integer value");
}
break;
case AsmToken::Identifier:
if (isDarwin()) {
unsigned RegNo;
if (!MatchRegisterName(Parser.getTok(), RegNo, IntVal)) {
Parser.Lex(); // Eat the identifier token.
break;
}
}
// Fall-through..
default:
return Error(S, "invalid memory operand");
}
@ -1261,14 +1350,19 @@ ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc,
/// ParseDirective parses the PPC specific directives
bool PPCAsmParser::ParseDirective(AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getIdentifier();
if (IDVal == ".word")
return ParseDirectiveWord(2, DirectiveID.getLoc());
if (IDVal == ".llong")
return ParseDirectiveWord(8, DirectiveID.getLoc());
if (IDVal == ".tc")
return ParseDirectiveTC(isPPC64()? 8 : 4, DirectiveID.getLoc());
if (IDVal == ".machine")
return ParseDirectiveMachine(DirectiveID.getLoc());
if (!isDarwin()) {
if (IDVal == ".word")
return ParseDirectiveWord(2, DirectiveID.getLoc());
if (IDVal == ".llong")
return ParseDirectiveWord(8, DirectiveID.getLoc());
if (IDVal == ".tc")
return ParseDirectiveTC(isPPC64()? 8 : 4, DirectiveID.getLoc());
if (IDVal == ".machine")
return ParseDirectiveMachine(DirectiveID.getLoc());
} else {
if (IDVal == ".machine")
return ParseDarwinDirectiveMachine(DirectiveID.getLoc());
}
return true;
}
@ -1314,7 +1408,7 @@ bool PPCAsmParser::ParseDirectiveTC(unsigned Size, SMLoc L) {
return ParseDirectiveWord(Size, L);
}
/// ParseDirectiveMachine
/// ParseDirectiveMachine (ELF platforms)
/// ::= .machine [ cpu | "push" | "pop" ]
bool PPCAsmParser::ParseDirectiveMachine(SMLoc L) {
if (getLexer().isNot(AsmToken::Identifier) &&
@ -1338,6 +1432,33 @@ bool PPCAsmParser::ParseDirectiveMachine(SMLoc L) {
return false;
}
/// ParseDarwinDirectiveMachine (Mach-o platforms)
/// ::= .machine cpu-identifier
bool PPCAsmParser::ParseDarwinDirectiveMachine(SMLoc L) {
if (getLexer().isNot(AsmToken::Identifier) &&
getLexer().isNot(AsmToken::String))
return Error(L, "unexpected token in directive");
StringRef CPU = Parser.getTok().getIdentifier();
Parser.Lex();
// FIXME: this is only the 'default' set of cpu variants.
// However we don't act on this information at present, this is simply
// allowing parsing to proceed with minimal sanity checking.
if (CPU != "ppc7400" && CPU != "ppc" && CPU != "ppc64")
return Error(L, "unrecognized cpu type");
if (isPPC64() && (CPU == "ppc7400" || CPU == "ppc"))
return Error(L, "wrong cpu type specified for 64bit");
if (!isPPC64() && CPU == "ppc64")
return Error(L, "wrong cpu type specified for 32bit");
if (getLexer().isNot(AsmToken::EndOfStatement))
return Error(L, "unexpected token in directive");
return false;
}
/// Force static initialization.
extern "C" void LLVMInitializePowerPCAsmParser() {
RegisterMCAsmParser<PPCAsmParser> A(ThePPC32Target);

View File

@ -1,14 +1,10 @@
; This tests for the basic implementation of PPCMachObjectWriter.cpp,
; which is responsible for writing mach-o relocation entries for (PIC)
; PowerPC objects.
; NOTE: Darwin PPC asm syntax is not yet supported by PPCAsmParser,
; so this test case uses ELF PPC asm syntax to produce a mach-o object.
; Once PPCAsmParser supports darwin asm syntax, this test case should
; be updated accordingly.
; RUN: llvm-mc -filetype=obj -relocation-model=pic -mcpu=g4 -triple=powerpc-apple-darwin8 %s -o - | llvm-readobj -relocations | FileCheck -check-prefix=DARWIN-G4-DUMP %s
; .machine ppc7400
.machine ppc7400
.section __TEXT,__textcoal_nt,coalesced,pure_instructions
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
.section __TEXT,__text,regular,pure_instructions
@ -16,40 +12,40 @@
.align 4
_main: ; @main
; BB#0: ; %entry
mflr 0
stw 31, -4(1)
stw 0, 8(1)
stwu 1, -80(1)
mflr r0
stw r31, -4(r1)
stw r0, 8(r1)
stwu r1, -80(r1)
bl L0$pb
L0$pb:
mr 31, 1
li 5, 0
mr r31, r1
li r5, 0
mflr 2
stw 3, 68(31)
stw 5, 72(31)
stw 4, 64(31)
addis 2, 2, (L_.str-L0$pb)@ha
la 3, (L_.str-L0$pb)@l(2)
stw r3, 68(r31)
stw r5, 72(r31)
stw r4, 64(r31)
addis r2, r2, ha16(L_.str-L0$pb)
la r3, lo16(L_.str-L0$pb)(r2)
bl L_puts$stub
li 3, 0
addi 1, 1, 80
lwz 0, 8(1)
lwz 31, -4(1)
mtlr 0
li r3, 0
addi r1, r1, 80
lwz r0, 8(r1)
lwz r31, -4(r1)
mtlr r0
blr
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
.align 4
L_puts$stub:
.indirect_symbol _puts
mflr 0
mflr r0
bcl 20, 31, L_puts$stub$tmp
L_puts$stub$tmp:
mflr 11
addis 11, 11, (L_puts$lazy_ptr-L_puts$stub$tmp)@ha
mtlr 0
lwzu 12, (L_puts$lazy_ptr-L_puts$stub$tmp)@l(11)
mtctr 12
mflr r11
addis r11, r11, ha16(L_puts$lazy_ptr-L_puts$stub$tmp)
mtlr r0
lwzu r12, lo16(L_puts$lazy_ptr-L_puts$stub$tmp)(r11)
mtctr r12
bctr
.section __DATA,__la_symbol_ptr,lazy_symbol_pointers
L_puts$lazy_ptr: