forked from OSchip/llvm-project
[ms-inline asm] Move most of the AsmParsing logic in clang back into the MC
layer. Use the new ParseMSInlineAsm() API and add an implementation of the MCAsmParserSemaCallback interface. llvm-svn: 166184
This commit is contained in:
parent
8bce664144
commit
ce2bcbf8c0
|
@ -2601,6 +2601,7 @@ public:
|
||||||
Expr *AsmString, MultiExprArg Clobbers,
|
Expr *AsmString, MultiExprArg Clobbers,
|
||||||
SourceLocation RParenLoc);
|
SourceLocation RParenLoc);
|
||||||
|
|
||||||
|
NamedDecl *LookupInlineAsmIdentifier(StringRef Name, SourceLocation Loc);
|
||||||
StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
|
StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
|
||||||
ArrayRef<Token> AsmToks, SourceLocation EndLoc);
|
ArrayRef<Token> AsmToks, SourceLocation EndLoc);
|
||||||
|
|
||||||
|
|
|
@ -24,19 +24,12 @@
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
#include "llvm/MC/MCAsmInfo.h"
|
#include "llvm/MC/MCAsmInfo.h"
|
||||||
#include "llvm/MC/MCContext.h"
|
#include "llvm/MC/MCContext.h"
|
||||||
#include "llvm/MC/MCExpr.h"
|
|
||||||
#include "llvm/MC/MCInst.h"
|
|
||||||
#include "llvm/MC/MCInstPrinter.h"
|
|
||||||
#include "llvm/MC/MCInstrInfo.h"
|
|
||||||
#include "llvm/MC/MCObjectFileInfo.h"
|
#include "llvm/MC/MCObjectFileInfo.h"
|
||||||
#include "llvm/MC/MCRegisterInfo.h"
|
#include "llvm/MC/MCRegisterInfo.h"
|
||||||
#include "llvm/MC/MCStreamer.h"
|
#include "llvm/MC/MCStreamer.h"
|
||||||
#include "llvm/MC/MCSubtargetInfo.h"
|
#include "llvm/MC/MCSubtargetInfo.h"
|
||||||
#include "llvm/MC/MCSymbol.h"
|
|
||||||
#include "llvm/MC/MCTargetAsmParser.h"
|
#include "llvm/MC/MCTargetAsmParser.h"
|
||||||
#include "llvm/MC/MCParser/MCAsmLexer.h"
|
|
||||||
#include "llvm/MC/MCParser/MCAsmParser.h"
|
#include "llvm/MC/MCParser/MCAsmParser.h"
|
||||||
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
|
||||||
#include "llvm/Support/SourceMgr.h"
|
#include "llvm/Support/SourceMgr.h"
|
||||||
#include "llvm/Support/TargetRegistry.h"
|
#include "llvm/Support/TargetRegistry.h"
|
||||||
#include "llvm/Support/TargetSelect.h"
|
#include "llvm/Support/TargetSelect.h"
|
||||||
|
@ -367,55 +360,73 @@ static bool buildMSAsmString(Sema &SemaRef,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
class MCAsmParserSemaCallbackImpl : public llvm::MCAsmParserSemaCallback {
|
||||||
enum AsmOpRewriteKind {
|
Sema *SemaRef;
|
||||||
AOK_Imm,
|
|
||||||
AOK_Input,
|
|
||||||
AOK_Output
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AsmOpRewrite {
|
|
||||||
AsmOpRewriteKind Kind;
|
|
||||||
llvm::SMLoc Loc;
|
|
||||||
unsigned Len;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AsmOpRewrite(AsmOpRewriteKind kind, llvm::SMLoc loc, unsigned len)
|
MCAsmParserSemaCallbackImpl(class Sema *Ref) { SemaRef = Ref; }
|
||||||
: Kind(kind), Loc(loc), Len(len) { }
|
~MCAsmParserSemaCallbackImpl() {}
|
||||||
|
|
||||||
|
void *LookupInlineAsmIdentifier(StringRef Name, void *SrcLoc,
|
||||||
|
void **IdentifierInfoPtr) {
|
||||||
|
SourceLocation Loc = SourceLocation::getFromPtrEncoding(SrcLoc);
|
||||||
|
NamedDecl *OpDecl = SemaRef->LookupInlineAsmIdentifier(Name, Loc);
|
||||||
|
DeclarationNameInfo NameInfo(OpDecl->getDeclName(), Loc);
|
||||||
|
ExprResult OpExpr = SemaRef->BuildDeclarationNameExpr(CXXScopeSpec(),
|
||||||
|
NameInfo,
|
||||||
|
OpDecl);
|
||||||
|
if (OpExpr.isInvalid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*IdentifierInfoPtr = static_cast<void*>(OpDecl->getIdentifier());
|
||||||
|
return static_cast<void *>(OpExpr.take());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NamedDecl *Sema::LookupInlineAsmIdentifier(StringRef Name, SourceLocation Loc) {
|
||||||
|
LookupResult Result(*this, &Context.Idents.get(Name), Loc,
|
||||||
|
Sema::LookupOrdinaryName);
|
||||||
|
|
||||||
|
if (!LookupName(Result, getCurScope())) {
|
||||||
|
// If we don't find anything, return null; the AsmParser will assume
|
||||||
|
// it is a label of some sort.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Result.isSingleResult()) {
|
||||||
|
// FIXME: Diagnose result.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedDecl *ND = Result.getFoundDecl();
|
||||||
|
if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) {
|
||||||
|
return ND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Handle other kinds of results? (FieldDecl, etc.)
|
||||||
|
// FIXME: Diagnose if we find something we can't handle, like a typedef.
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
|
StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
|
||||||
ArrayRef<Token> AsmToks,SourceLocation EndLoc) {
|
ArrayRef<Token> AsmToks,SourceLocation EndLoc) {
|
||||||
SmallVector<IdentifierInfo*, 4> Inputs;
|
|
||||||
SmallVector<IdentifierInfo*, 4> Outputs;
|
|
||||||
SmallVector<IdentifierInfo*, 4> Names;
|
SmallVector<IdentifierInfo*, 4> Names;
|
||||||
SmallVector<std::string, 4> InputConstraints;
|
SmallVector<StringRef, 4> ConstraintRefs;
|
||||||
SmallVector<std::string, 4> OutputConstraints;
|
|
||||||
SmallVector<StringRef, 4> Constraints;
|
|
||||||
unsigned NumOutputs;
|
|
||||||
unsigned NumInputs;
|
|
||||||
SmallVector<Expr*, 4> InputExprs;
|
|
||||||
SmallVector<Expr*, 4> OutputExprs;
|
|
||||||
SmallVector<Expr*, 4> Exprs;
|
SmallVector<Expr*, 4> Exprs;
|
||||||
SmallVector<StringRef, 4> Clobbers;
|
SmallVector<StringRef, 4> ClobberRefs;
|
||||||
std::set<std::string> ClobberRegs;
|
|
||||||
|
|
||||||
SmallVector<struct AsmOpRewrite, 4> AsmStrRewrites;
|
|
||||||
|
|
||||||
// Empty asm statements don't need to instantiate the AsmParser, etc.
|
// Empty asm statements don't need to instantiate the AsmParser, etc.
|
||||||
if (AsmToks.empty()) {
|
if (AsmToks.empty()) {
|
||||||
StringRef EmptyAsmStr;
|
StringRef EmptyAsmStr;
|
||||||
MSAsmStmt *NS =
|
MSAsmStmt *NS =
|
||||||
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
|
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
|
||||||
/*IsVolatile*/ true, AsmToks, /*NumOutputs*/ 0,
|
/*IsVolatile*/ true, AsmToks, /*NumOutputs*/ 0,
|
||||||
/*NumInputs*/ 0, Names, Constraints, Exprs, EmptyAsmStr,
|
/*NumInputs*/ 0, Names, ConstraintRefs, Exprs,
|
||||||
Clobbers, EndLoc);
|
EmptyAsmStr, ClobberRefs, EndLoc);
|
||||||
return Owned(NS);
|
return Owned(NS);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AsmString;
|
std::string AsmString;
|
||||||
if (buildMSAsmString(*this, AsmLoc, AsmToks, AsmString))
|
if (buildMSAsmString(*this, AsmLoc, AsmToks, AsmString))
|
||||||
return StmtError();
|
return StmtError();
|
||||||
|
|
||||||
|
@ -443,7 +454,6 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
|
||||||
Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
|
Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
|
||||||
OwningPtr<llvm::MCTargetAsmParser>
|
OwningPtr<llvm::MCTargetAsmParser>
|
||||||
TargetParser(TheTarget->createMCAsmParser(*STI, *Parser));
|
TargetParser(TheTarget->createMCAsmParser(*STI, *Parser));
|
||||||
Parser->setParsingInlineAsm(true);
|
|
||||||
|
|
||||||
// Get the instruction descriptor.
|
// Get the instruction descriptor.
|
||||||
const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
|
const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
|
||||||
|
@ -455,152 +465,43 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
|
||||||
Parser->setTargetParser(*TargetParser.get());
|
Parser->setTargetParser(*TargetParser.get());
|
||||||
Parser->setParsingInlineAsm(true);
|
Parser->setParsingInlineAsm(true);
|
||||||
|
|
||||||
// Prime the lexer.
|
unsigned NumOutputs;
|
||||||
Parser->Lex();
|
unsigned NumInputs;
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the number of Outputs and Inputs.
|
|
||||||
NumOutputs = Outputs.size();
|
|
||||||
NumInputs = Inputs.size();
|
|
||||||
|
|
||||||
// Set the unique clobbers.
|
|
||||||
for (std::set<std::string>::iterator I = ClobberRegs.begin(),
|
|
||||||
E = ClobberRegs.end(); I != E; ++I)
|
|
||||||
Clobbers.push_back(*I);
|
|
||||||
|
|
||||||
// Merge the various outputs and inputs. Output are expected first.
|
|
||||||
Names.resize(NumOutputs + NumInputs);
|
|
||||||
Constraints.resize(NumOutputs + NumInputs);
|
|
||||||
Exprs.resize(NumOutputs + NumInputs);
|
|
||||||
for (unsigned i = 0; i < NumOutputs; ++i) {
|
|
||||||
Names[i] = Outputs[i];
|
|
||||||
Constraints[i] = OutputConstraints[i];
|
|
||||||
Exprs[i] = OutputExprs[i];
|
|
||||||
}
|
|
||||||
for (unsigned i = 0, j = NumOutputs; i < NumInputs; ++i, ++j) {
|
|
||||||
Names[j] = Inputs[i];
|
|
||||||
Constraints[j] = InputConstraints[i];
|
|
||||||
Exprs[j] = InputExprs[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the IR assembly string.
|
|
||||||
std::string AsmStringIR;
|
std::string AsmStringIR;
|
||||||
llvm::raw_string_ostream OS(AsmStringIR);
|
SmallVector<void *, 4> VoidNames;
|
||||||
const char *Start = AsmString.c_str();
|
SmallVector<std::string, 4> Constraints;
|
||||||
for (SmallVectorImpl<struct AsmOpRewrite>::iterator I = AsmStrRewrites.begin(),
|
SmallVector<void *, 4> VoidExprs;
|
||||||
E = AsmStrRewrites.end(); I != E; ++I) {
|
SmallVector<std::string, 4> Clobbers;
|
||||||
const char *Loc = (*I).Loc.getPointer();
|
MCAsmParserSemaCallbackImpl MCAPSI(this);
|
||||||
|
if (Parser->ParseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR,
|
||||||
|
NumOutputs, NumInputs, VoidNames, Constraints,
|
||||||
|
VoidExprs, Clobbers, MII, IP, MCAPSI))
|
||||||
|
return StmtError();
|
||||||
|
|
||||||
// Emit everything up to the immediate/expression.
|
// Build the vector of clobber StringRefs.
|
||||||
OS << StringRef(Start, Loc - Start);
|
unsigned NumClobbers = Clobbers.size();
|
||||||
|
ClobberRefs.resize(NumClobbers);
|
||||||
|
for (unsigned i = 0; i != NumClobbers; ++i)
|
||||||
|
ClobberRefs[i] = StringRef(Clobbers[i]);
|
||||||
|
|
||||||
// Rewrite expressions in $N notation.
|
// Recast the void pointers and build the vector of constraint StringRefs.
|
||||||
switch ((*I).Kind) {
|
unsigned NumExprs = NumOutputs + NumInputs;
|
||||||
case AOK_Imm:
|
assert (VoidNames.size() == NumExprs && "Unexpected number of names!");
|
||||||
OS << Twine("$$") + StringRef(Loc, (*I).Len);
|
assert (VoidExprs.size() == NumExprs && "Unexpected number of exprs!");
|
||||||
break;
|
Names.resize(NumExprs);
|
||||||
case AOK_Input:
|
ConstraintRefs.resize(NumExprs);
|
||||||
OS << '$';
|
Exprs.resize(NumExprs);
|
||||||
OS << InputIdx++;
|
for (unsigned i = 0, e = NumExprs; i != e; ++i) {
|
||||||
break;
|
Names[i] = static_cast<IdentifierInfo *>(VoidNames[i]);
|
||||||
case AOK_Output:
|
ConstraintRefs[i] = StringRef(Constraints[i]);
|
||||||
OS << '$';
|
Exprs[i] = static_cast<Expr *>(VoidExprs[i]);
|
||||||
OS << OutputIdx++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
AsmString = OS.str();
|
bool IsSimple = NumExprs > 0;
|
||||||
MSAsmStmt *NS =
|
MSAsmStmt *NS =
|
||||||
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
|
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
|
||||||
/*IsVolatile*/ true, AsmToks, NumOutputs,
|
/*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs,
|
||||||
NumInputs, Names, Constraints, Exprs, AsmString,
|
Names, ConstraintRefs, Exprs, AsmStringIR,
|
||||||
Clobbers, EndLoc);
|
ClobberRefs, EndLoc);
|
||||||
return Owned(NS);
|
return Owned(NS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,3 +114,20 @@ unsigned t12(void) {
|
||||||
// CHECK: t12
|
// CHECK: t12
|
||||||
// CHECK: call void asm sideeffect inteldialect "mov eax, $2\0A\09mov $0, eax\0A\09mov eax, $3\0A\09mov $1, eax", "=*m,=*m,*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}) nounwind
|
// CHECK: call void asm sideeffect inteldialect "mov eax, $2\0A\09mov $0, eax\0A\09mov eax, $3\0A\09mov $1, eax", "=*m,=*m,*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}) nounwind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void t13() {
|
||||||
|
unsigned i = 1, j = 2;
|
||||||
|
// __asm mov eax, [ebx]
|
||||||
|
// __asm mov eax, [4*ecx]
|
||||||
|
// __asm mov eax, [4]
|
||||||
|
// __asm mov eax, [ebx + 4*ecx]
|
||||||
|
// __asm mov eax, [ebx + 4*ecx + 4]
|
||||||
|
__asm mov eax, [i]
|
||||||
|
__asm mov eax, [i + 4*ecx]
|
||||||
|
__asm mov eax, [i + 4*ecx + 4]
|
||||||
|
__asm mov eax, [4*i]
|
||||||
|
__asm mov eax, [ebx + 4*i]
|
||||||
|
__asm mov eax, [ebx + 4*i + 4]
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue