From d9b56edcf42232c5331f9ad79aae83ba31e852df Mon Sep 17 00:00:00 2001 From: Chad Rosier Date: Mon, 15 Oct 2012 19:56:10 +0000 Subject: [PATCH] [ms-inline asm] Rework the front-end to use the API introduced in r165946. -The front-end now builds a single assembly string and feeds it to the AsmParser. The front-end iterates on a per statement basis by calling the ParseStatement() function. Please note, the calling of ParseStatement() and and any notion of MCAsmParsedOperands will be sunk into the MC layer in the near future. I plan to expose more basic APIs such as getClobbers, etc. -The enumeration of the AsmString expressions have been reworked to use SMLocs rather than assembly Pieces, which were being parsed in the front-end. -The test case, t8(), was modified due to r129223. I'll have to find a way to work around things such as these. Sorry for the large commit, but breaking this in multiple smaller commits proved too irritating. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165957 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaStmtAsm.cpp | 396 ++++++++++++++++------------------- test/CodeGen/ms-inline-asm.c | 4 +- 2 files changed, 181 insertions(+), 219 deletions(-) diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index 017cdb90f6..339ff7a953 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/lib/Sema/SemaStmtAsm.cpp @@ -331,34 +331,11 @@ static StringRef getSpelling(Sema &SemaRef, Token AsmTok) { return Asm; } -// Break the AsmString into pieces (i.e., mnemonic and operands). -static void buildMSAsmPieces(StringRef Asm, std::vector &Pieces) { - std::pair Split = Asm.split(' '); - - // Mnemonic - Pieces.push_back(Split.first); - Asm = Split.second; - - // Operands - while (!Asm.empty()) { - Split = Asm.split(", "); - Pieces.push_back(Split.first); - Asm = Split.second; - } -} - -static void buildMSAsmPieces(std::vector &AsmStrings, - std::vector > &Pieces) { - for (unsigned i = 0, e = AsmStrings.size(); i != e; ++i) - buildMSAsmPieces(AsmStrings[i], Pieces[i]); -} - -// Build the individual assembly instruction(s) and place them in the AsmStrings -// vector. These strings are fed to the AsmParser. Returns true on error. -static bool buildMSAsmStrings(Sema &SemaRef, - SourceLocation AsmLoc, - ArrayRef AsmToks, - std::vector &AsmStrings) { +// Build the inline assembly string. Returns true on error. +static bool buildMSAsmString(Sema &SemaRef, + SourceLocation AsmLoc, + ArrayRef AsmToks, + std::string &AsmString) { assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!"); SmallString<512> Asm; @@ -366,18 +343,17 @@ static bool buildMSAsmStrings(Sema &SemaRef, bool isNewAsm = ((i == 0) || AsmToks[i].isAtStartOfLine() || AsmToks[i].is(tok::kw_asm)); - if (isNewAsm) { - if (i) { - AsmStrings.push_back(Asm.str()); - Asm.clear(); - } + if (i != 0) + Asm += "\n\t"; + if (AsmToks[i].is(tok::kw_asm)) { i++; // Skip __asm if (i == e) { SemaRef.Diag(AsmLoc, diag::err_asm_empty); return true; } + } } @@ -387,47 +363,59 @@ static bool buildMSAsmStrings(Sema &SemaRef, StringRef Spelling = getSpelling(SemaRef, AsmToks[i]); Asm += Spelling; } - AsmStrings.push_back(Asm.str()); - + AsmString = Asm.str(); return false; } -#define DEF_SIMPLE_MSASM(STR) \ - MSAsmStmt *NS = \ - new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true, \ - /*IsVolatile*/ true, AsmToks, Inputs, Outputs, \ - InputExprs, OutputExprs, STR, Constraints, \ - Clobbers, EndLoc); +namespace { +enum AsmOpRewriteKind { + AOK_Imm, + AOK_Input, + AOK_Output +}; + +struct AsmOpRewrite { + AsmOpRewriteKind Kind; + llvm::SMLoc Loc; + unsigned Len; + +public: + AsmOpRewrite(AsmOpRewriteKind kind, llvm::SMLoc loc, unsigned len) + : Kind(kind), Loc(loc), Len(len) { } +}; + +} StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, ArrayRef AsmToks,SourceLocation EndLoc) { - SmallVector Constraints; - std::vector InputConstraints; - std::vector OutputConstraints; - SmallVector Clobbers; - std::set ClobberRegs; - - // FIXME: Use a struct to hold the various expression information. SmallVector Inputs; SmallVector Outputs; SmallVector InputExprs; SmallVector OutputExprs; - SmallVector InputExprNames; - SmallVector OutputExprNames; - SmallVector InputExprStrIdx; - SmallVector OutputExprStrIdx; + SmallVector Constraints; + SmallVector InputConstraints; + SmallVector OutputConstraints; + + SmallVector Clobbers; + std::set ClobberRegs; + + SmallVector AsmStrRewrites; // Empty asm statements don't need to instantiate the AsmParser, etc. - StringRef EmptyAsmStr; - if (AsmToks.empty()) { DEF_SIMPLE_MSASM(EmptyAsmStr); return Owned(NS); } + if (AsmToks.empty()) { + StringRef EmptyAsmStr; + MSAsmStmt *NS = + new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true, + /*IsVolatile*/ true, AsmToks, Inputs, Outputs, + InputExprs, OutputExprs, EmptyAsmStr, Constraints, + Clobbers, EndLoc); + return Owned(NS); + } - std::vector AsmStrings; - if (buildMSAsmStrings(*this, AsmLoc, AsmToks, AsmStrings)) + std::string AsmString; + if (buildMSAsmString(*this, AsmLoc, AsmToks, AsmString)) return StmtError(); - std::vector > Pieces(AsmStrings.size()); - buildMSAsmPieces(AsmStrings, Pieces); - // Get the target specific parser. std::string Error; const std::string &TT = Context.getTargetInfo().getTriple().getTriple(); @@ -439,113 +427,111 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, OwningPtr STI(TheTarget->createMCSubtargetInfo(TT, "", "")); - for (unsigned StrIdx = 0, e = AsmStrings.size(); StrIdx != e; ++StrIdx) { - llvm::SourceMgr SrcMgr; - llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); - llvm::MemoryBuffer *Buffer = - llvm::MemoryBuffer::getMemBuffer(AsmStrings[StrIdx], ""); - - // Tell SrcMgr about this buffer, which is what the parser will pick up. - SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); - - OwningPtr Str(createNullStreamer(Ctx)); - OwningPtr - Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI)); - OwningPtr - TargetParser(TheTarget->createMCAsmParser(*STI, *Parser)); - // Change to the Intel dialect. - Parser->setAssemblerDialect(1); - Parser->setTargetParser(*TargetParser.get()); + llvm::SourceMgr SrcMgr; + llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); + llvm::MemoryBuffer *Buffer = + llvm::MemoryBuffer::getMemBuffer(AsmString, ""); + + // Tell SrcMgr about this buffer, which is what the parser will pick up. + SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); + + OwningPtr Str(createNullStreamer(Ctx)); + OwningPtr + Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI)); + OwningPtr + TargetParser(TheTarget->createMCAsmParser(*STI, *Parser)); Parser->setParsingInlineAsm(true); - // Prime the lexer. - Parser->Lex(); - - // Parse the opcode. - StringRef IDVal; - Parser->ParseIdentifier(IDVal); - - // Canonicalize the opcode to lower case. - SmallString<128> OpcodeStr; - for (unsigned i = 0, e = IDVal.size(); i != e; ++i) - OpcodeStr.push_back(tolower(IDVal[i])); - // FIXME: Convert to a StmtError. - assert(TargetParser->mnemonicIsValid(OpcodeStr) && "Invalid mnemonic!"); - - // Parse the operands. - llvm::SMLoc IDLoc; - SmallVector Operands; - bool HadError = TargetParser->ParseInstruction(OpcodeStr.str(), IDLoc, - Operands); - // If we had an error parsing the operands, fail gracefully. - if (HadError) { DEF_SIMPLE_MSASM(EmptyAsmStr); return Owned(NS); } - - // Match the MCInstr. - unsigned Opcode; - unsigned ErrorInfo; - HadError = TargetParser->MatchAndEmitInstruction(IDLoc, Opcode, Operands, - *Str.get(), ErrorInfo, - /*MatchingInlineAsm*/ true); - // If we had an error parsing the operands, fail gracefully. - if (HadError) { DEF_SIMPLE_MSASM(EmptyAsmStr); return Owned(NS); } - - // Get the instruction descriptor. - const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo(); - const llvm::MCInstrDesc &Desc = MII->get(Opcode); - llvm::MCInstPrinter *IP = - TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI); - - // Build the list of clobbers, outputs and inputs. - unsigned NumDefs = Desc.getNumDefs(); - for (unsigned i = 1, e = Operands.size(); i != e; ++i) { - // Skip immediates. - if (Operands[i]->isImm()) - continue; - - // Register. - if (Operands[i]->isReg()) { - // Clobber. - if (NumDefs && (Operands[i]->getMCOperandNum() < NumDefs)) { - std::string Reg; - llvm::raw_string_ostream OS(Reg); - IP->printRegName(OS, Operands[i]->getReg()); - StringRef Clobber(OS.str()); - if (!Context.getTargetInfo().isValidClobber(Clobber)) - return StmtError( - Diag(AsmLoc, diag::err_asm_unknown_register_name) << Clobber); - ClobberRegs.insert(Reg); + // Get the instruction descriptor. + const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo(); + llvm::MCInstPrinter *IP = + TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI); + + // Change to the Intel dialect. + Parser->setAssemblerDialect(1); + Parser->setTargetParser(*TargetParser.get()); + Parser->setParsingInlineAsm(true); + + // Prime the lexer. + Parser->Lex(); + + // While we have input, parse each statement. + unsigned InputIdx = 0; + unsigned OutputIdx = 0; + while (Parser->getLexer().isNot(llvm::AsmToken::Eof)) { + if (Parser->ParseStatement()) { + // FIXME: The AsmParser should report errors, but we could potentially be + // more verbose here. + break; + } + + if (Parser->isInstruction()) { + const llvm::MCInstrDesc &Desc = MII->get(Parser->getOpcode()); + + // Build the list of clobbers, outputs and inputs. + for (unsigned i = 1, e = Parser->getNumParsedOperands(); i != e; ++i) { + llvm::MCParsedAsmOperand &Operand = Parser->getParsedOperand(i); + + // Immediate. + if (Operand.isImm()) { + AsmStrRewrites.push_back(AsmOpRewrite(AOK_Imm, + Operand.getStartLoc(), + Operand.getNameLen())); + continue; } - continue; - } - // Expr/Input or Output. - StringRef Name = Pieces[StrIdx][i]; - if (IdentifierInfo *II = &Context.Idents.get(Name)) { - CXXScopeSpec SS; - UnqualifiedId Id; - SourceLocation Loc; - Id.setIdentifier(II, AsmLoc); - ExprResult Result = ActOnIdExpression(getCurScope(), SS, Loc, Id, - false, false); - if (!Result.isInvalid()) { - bool isMemDef = (i == 1) && Desc.mayStore(); - if (isMemDef) { - Outputs.push_back(II); - OutputExprs.push_back(Result.take()); - OutputExprNames.push_back(Name.str()); - OutputExprStrIdx.push_back(StrIdx); - - std::string Constraint = "=" + Operands[i]->getConstraint().str(); - OutputConstraints.push_back(Constraint); - } else { - Inputs.push_back(II); - InputExprs.push_back(Result.take()); - InputExprNames.push_back(Name.str()); - InputExprStrIdx.push_back(StrIdx); - InputConstraints.push_back(Operands[i]->getConstraint()); + + // Register operand. + if (Operand.isReg()) { + unsigned NumDefs = Desc.getNumDefs(); + // Clobber. + if (NumDefs && Operand.getMCOperandNum() < NumDefs) { + std::string Reg; + llvm::raw_string_ostream OS(Reg); + IP->printRegName(OS, Operand.getReg()); + StringRef Clobber(OS.str()); + if (!Context.getTargetInfo().isValidClobber(Clobber)) + return StmtError( + Diag(AsmLoc, diag::err_asm_unknown_register_name) << Clobber); + ClobberRegs.insert(Reg); + } + continue; + } + + + // Expr/Input or Output. + StringRef Name = Operand.getName(); + if (IdentifierInfo *II = &Context.Idents.get(Name)) { + CXXScopeSpec SS; + UnqualifiedId Id; + SourceLocation Loc; + Id.setIdentifier(II, AsmLoc); + ExprResult Result = ActOnIdExpression(getCurScope(), SS, Loc, Id, + false, false); + if (!Result.isInvalid()) { + bool isOutput = (i == 1) && Desc.mayStore(); + if (isOutput) { + std::string Constraint = "="; + ++InputIdx; + Outputs.push_back(II); + OutputExprs.push_back(Result.take()); + Constraint += Operand.getConstraint().str(); + OutputConstraints.push_back(Constraint); + AsmStrRewrites.push_back(AsmOpRewrite(AOK_Output, + Operand.getStartLoc(), + Operand.getNameLen())); + } else { + Inputs.push_back(II); + InputExprs.push_back(Result.take()); + InputConstraints.push_back(Operand.getConstraint().str()); + AsmStrRewrites.push_back(AsmOpRewrite(AOK_Input, + Operand.getStartLoc(), + Operand.getNameLen())); + } } } } + Parser->freeParsedOperands(); } } for (std::set::iterator I = ClobberRegs.begin(), @@ -554,75 +540,51 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, // Merge the output and input constraints. Output constraints are expected // first. - for (std::vector::iterator I = OutputConstraints.begin(), + for (SmallVectorImpl::iterator I = OutputConstraints.begin(), E = OutputConstraints.end(); I != E; ++I) Constraints.push_back(*I); - for (std::vector::iterator I = InputConstraints.begin(), + for (SmallVectorImpl::iterator I = InputConstraints.begin(), E = InputConstraints.end(); I != E; ++I) Constraints.push_back(*I); - // Enumerate the AsmString expressions. - unsigned OpNum = 0; - for (unsigned i = 0, e = OutputExprNames.size(); i != e; ++i, ++OpNum) { - unsigned StrIdx = OutputExprStrIdx[i]; - // Iterate over the assembly instruction pieces, skipping the mnemonic. - for (unsigned j = 1, f = Pieces[StrIdx].size(); j != f; ++j) { - // If the operand and the expression name match, then rewrite the operand. - if (OutputExprNames[i] == Pieces[StrIdx][j]) { - SmallString<32> Res; - llvm::raw_svector_ostream OS(Res); - OS << '$' << OpNum; - OutputExprNames[i] = OS.str(); - Pieces[StrIdx][j] = OutputExprNames[i]; - break; - } - } - } - for (unsigned i = 0, e = InputExprNames.size(); i != e; ++i, ++OpNum) { - unsigned StrIdx = InputExprStrIdx[i]; - // Iterate over the assembly instruction pieces, skipping the mnemonic. - for (unsigned j = 1, f = Pieces[StrIdx].size(); j != f; ++j) { - // If the operand and the expression name match, then rewrite the operand. - if (InputExprNames[i] == Pieces[StrIdx][j]) { - SmallString<32> Res; - llvm::raw_svector_ostream OS(Res); - OS << '$' << OpNum; - InputExprNames[i] = OS.str(); - Pieces[StrIdx][j] = InputExprNames[i]; - break; - } + // Build the IR assembly string. + std::string AsmStringIR; + llvm::raw_string_ostream OS(AsmStringIR); + const char *Start = AsmString.c_str(); + for (SmallVectorImpl::iterator I = AsmStrRewrites.begin(), + E = AsmStrRewrites.end(); I != E; ++I) { + const char *Loc = (*I).Loc.getPointer(); + + // Emit everything up to the immediate/expression. + OS << StringRef(Start, Loc - Start); + + // Rewrite expressions in $N notation. + switch ((*I).Kind) { + case AOK_Imm: + OS << Twine("$$") + StringRef(Loc, (*I).Len); + break; + case AOK_Input: + OS << '$'; + OS << InputIdx++; + break; + case AOK_Output: + OS << '$'; + OS << OutputIdx++; + break; } - } - - // Emit the IR assembly string. - std::string AsmString; - for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { - // Skip empty asm stmts. - if (Pieces[i].empty()) continue; - - if (i > 0) - AsmString += "\n\t"; - // Emit the mnemonic. - AsmString += Pieces[i][0]; - if (Pieces[i].size() > 1) - AsmString += ' '; - - // Emit the operands adding $$ to constants. - for (unsigned j = 1, f = Pieces[i].size(); j != f; ++j) { - if (j > 1) AsmString += ", "; - unsigned Val; - if (!Pieces[i][j].getAsInteger(0, Val)) - AsmString += "$$"; - - AsmString += Pieces[i][j]; - } + // Skip the original expression. + Start = Loc + (*I).Len; } + // Emit the remainder of the asm string. + const char *AsmEnd = AsmString.c_str() + AsmString.size(); + if (Start != AsmEnd) + OS << StringRef(Start, AsmEnd - Start); - bool IsSimple = Inputs.size() != 0 || Outputs.size() != 0; + AsmString = OS.str(); MSAsmStmt *NS = - new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, + new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ false, /*IsVolatile*/ true, AsmToks, Inputs, Outputs, InputExprs, OutputExprs, AsmString, Constraints, Clobbers, EndLoc); diff --git a/test/CodeGen/ms-inline-asm.c b/test/CodeGen/ms-inline-asm.c index 62e466bf7b..387a49cfd2 100644 --- a/test/CodeGen/ms-inline-asm.c +++ b/test/CodeGen/ms-inline-asm.c @@ -59,12 +59,12 @@ void t7() { } int t8() { - __asm int 3 ; } comments for single-line asm + __asm int 4 ; } comments for single-line asm __asm {} __asm int 4 return 10; // CHECK: t8 -// CHECK: call void asm sideeffect inteldialect "int $$3", "~{dirflag},~{fpsr},~{flags}"() nounwind +// CHECK: call void asm sideeffect inteldialect "int $$4", "~{dirflag},~{fpsr},~{flags}"() nounwind // CHECK: call void asm sideeffect inteldialect "", "~{dirflag},~{fpsr},~{flags}"() nounwind // CHECK: call void asm sideeffect inteldialect "int $$4", "~{dirflag},~{fpsr},~{flags}"() nounwind // CHECK: ret i32 10 -- 2.40.0