diff options
| author | Craig Topper <craig.topper@intel.com> | 2019-02-08 20:48:56 +0000 | 
|---|---|---|
| committer | Craig Topper <craig.topper@intel.com> | 2019-02-08 20:48:56 +0000 | 
| commit | 784929d0454c4df6a98ef6fbbd1d30a6f71f9c16 (patch) | |
| tree | ee2091fd647c20c3279800a14f7ce36c85b8c00b /llvm/lib/AsmParser | |
| parent | 0e5dd512aae057aeceb34089c93a380f8edd37da (diff) | |
| download | bcm5719-llvm-784929d0454c4df6a98ef6fbbd1d30a6f71f9c16.tar.gz bcm5719-llvm-784929d0454c4df6a98ef6fbbd1d30a6f71f9c16.zip  | |
Implementation of asm-goto support in LLVM
This patch accompanies the RFC posted here:
http://lists.llvm.org/pipermail/llvm-dev/2018-October/127239.html
This patch adds a new CallBr IR instruction to support asm-goto
inline assembly like gcc as used by the linux kernel. This
instruction is both a call instruction and a terminator
instruction with multiple successors. Only inline assembly
usage is supported today.
This also adds a new INLINEASM_BR opcode to SelectionDAG and
MachineIR to represent an INLINEASM block that is also
considered a terminator instruction.
There will likely be more bug fixes and optimizations to follow
this, but we felt it had reached a point where we would like to
switch to an incremental development model.
Patch by Craig Topper, Alexander Ivchenko, Mikhail Dvoretckii
Differential Revision: https://reviews.llvm.org/D53765
llvm-svn: 353563
Diffstat (limited to 'llvm/lib/AsmParser')
| -rw-r--r-- | llvm/lib/AsmParser/LLLexer.cpp | 1 | ||||
| -rw-r--r-- | llvm/lib/AsmParser/LLParser.cpp | 127 | ||||
| -rw-r--r-- | llvm/lib/AsmParser/LLParser.h | 1 | ||||
| -rw-r--r-- | llvm/lib/AsmParser/LLToken.h | 1 | 
4 files changed, 130 insertions, 0 deletions
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index b543115a88e..461117c92b8 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -858,6 +858,7 @@ lltok::Kind LLLexer::LexIdentifier() {    INSTKEYWORD(invoke,      Invoke);    INSTKEYWORD(resume,      Resume);    INSTKEYWORD(unreachable, Unreachable); +  INSTKEYWORD(callbr,      CallBr);    INSTKEYWORD(alloca,      Alloca);    INSTKEYWORD(load,        Load); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 855c5d26500..2a36bb18984 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -163,6 +163,14 @@ bool LLParser::ValidateEndOfModule() {        AS = AS.addAttributes(Context, AttributeList::FunctionIndex,                              AttributeSet::get(Context, FnAttrs));        II->setAttributes(AS); +    } else if (CallBrInst *CBI = dyn_cast<CallBrInst>(V)) { +      AttributeList AS = CBI->getAttributes(); +      AttrBuilder FnAttrs(AS.getFnAttributes()); +      AS = AS.removeAttributes(Context, AttributeList::FunctionIndex); +      FnAttrs.merge(B); +      AS = AS.addAttributes(Context, AttributeList::FunctionIndex, +                            AttributeSet::get(Context, FnAttrs)); +      CBI->setAttributes(AS);      } else if (auto *GV = dyn_cast<GlobalVariable>(V)) {        AttrBuilder Attrs(GV->getAttributes());        Attrs.merge(B); @@ -5566,6 +5574,7 @@ int LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB,    case lltok::kw_catchswitch: return ParseCatchSwitch(Inst, PFS);    case lltok::kw_catchpad:    return ParseCatchPad(Inst, PFS);    case lltok::kw_cleanuppad:  return ParseCleanupPad(Inst, PFS); +  case lltok::kw_callbr:      return ParseCallBr(Inst, PFS);    // Unary Operators.    case lltok::kw_fneg: {      FastMathFlags FMF = EatFastMathFlagsIfPresent(); @@ -6184,6 +6193,124 @@ bool LLParser::ParseUnaryOp(Instruction *&Inst, PerFunctionState &PFS,    return false;  } +/// ParseCallBr +///   ::= 'callbr' OptionalCallingConv OptionalAttrs Type Value ParamList +///       OptionalAttrs OptionalOperandBundles 'to' TypeAndValue +///       '[' LabelList ']' +bool LLParser::ParseCallBr(Instruction *&Inst, PerFunctionState &PFS) { +  LocTy CallLoc = Lex.getLoc(); +  AttrBuilder RetAttrs, FnAttrs; +  std::vector<unsigned> FwdRefAttrGrps; +  LocTy NoBuiltinLoc; +  unsigned CC; +  Type *RetType = nullptr; +  LocTy RetTypeLoc; +  ValID CalleeID; +  SmallVector<ParamInfo, 16> ArgList; +  SmallVector<OperandBundleDef, 2> BundleList; + +  BasicBlock *DefaultDest; +  if (ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) || +      ParseType(RetType, RetTypeLoc, true /*void allowed*/) || +      ParseValID(CalleeID) || ParseParameterList(ArgList, PFS) || +      ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false, +                                 NoBuiltinLoc) || +      ParseOptionalOperandBundles(BundleList, PFS) || +      ParseToken(lltok::kw_to, "expected 'to' in callbr") || +      ParseTypeAndBasicBlock(DefaultDest, PFS) || +      ParseToken(lltok::lsquare, "expected '[' in callbr")) +    return true; + +  // Parse the destination list. +  SmallVector<BasicBlock *, 16> IndirectDests; + +  if (Lex.getKind() != lltok::rsquare) { +    BasicBlock *DestBB; +    if (ParseTypeAndBasicBlock(DestBB, PFS)) +      return true; +    IndirectDests.push_back(DestBB); + +    while (EatIfPresent(lltok::comma)) { +      if (ParseTypeAndBasicBlock(DestBB, PFS)) +        return true; +      IndirectDests.push_back(DestBB); +    } +  } + +  if (ParseToken(lltok::rsquare, "expected ']' at end of block list")) +    return true; + +  // If RetType is a non-function pointer type, then this is the short syntax +  // for the call, which means that RetType is just the return type.  Infer the +  // rest of the function argument types from the arguments that are present. +  FunctionType *Ty = dyn_cast<FunctionType>(RetType); +  if (!Ty) { +    // Pull out the types of all of the arguments... +    std::vector<Type *> ParamTypes; +    for (unsigned i = 0, e = ArgList.size(); i != e; ++i) +      ParamTypes.push_back(ArgList[i].V->getType()); + +    if (!FunctionType::isValidReturnType(RetType)) +      return Error(RetTypeLoc, "Invalid result type for LLVM function"); + +    Ty = FunctionType::get(RetType, ParamTypes, false); +  } + +  CalleeID.FTy = Ty; + +  // Look up the callee. +  Value *Callee; +  if (ConvertValIDToValue(PointerType::getUnqual(Ty), CalleeID, Callee, &PFS, +                          /*IsCall=*/true)) +    return true; + +  if (isa<InlineAsm>(Callee) && !Ty->getReturnType()->isVoidTy()) +    return Error(RetTypeLoc, "asm-goto outputs not supported"); + +  // Set up the Attribute for the function. +  SmallVector<Value *, 8> Args; +  SmallVector<AttributeSet, 8> ArgAttrs; + +  // Loop through FunctionType's arguments and ensure they are specified +  // correctly.  Also, gather any parameter attributes. +  FunctionType::param_iterator I = Ty->param_begin(); +  FunctionType::param_iterator E = Ty->param_end(); +  for (unsigned i = 0, e = ArgList.size(); i != e; ++i) { +    Type *ExpectedTy = nullptr; +    if (I != E) { +      ExpectedTy = *I++; +    } else if (!Ty->isVarArg()) { +      return Error(ArgList[i].Loc, "too many arguments specified"); +    } + +    if (ExpectedTy && ExpectedTy != ArgList[i].V->getType()) +      return Error(ArgList[i].Loc, "argument is not of expected type '" + +                                       getTypeString(ExpectedTy) + "'"); +    Args.push_back(ArgList[i].V); +    ArgAttrs.push_back(ArgList[i].Attrs); +  } + +  if (I != E) +    return Error(CallLoc, "not enough parameters specified for call"); + +  if (FnAttrs.hasAlignmentAttr()) +    return Error(CallLoc, "callbr instructions may not have an alignment"); + +  // Finish off the Attribute and check them +  AttributeList PAL = +      AttributeList::get(Context, AttributeSet::get(Context, FnAttrs), +                         AttributeSet::get(Context, RetAttrs), ArgAttrs); + +  CallBrInst *CBI = +      CallBrInst::Create(Ty, Callee, DefaultDest, IndirectDests, Args, +                         BundleList); +  CBI->setCallingConv(CC); +  CBI->setAttributes(PAL); +  ForwardRefAttrGroups[CBI] = FwdRefAttrGrps; +  Inst = CBI; +  return false; +} +  //===----------------------------------------------------------------------===//  // Binary Operators.  //===----------------------------------------------------------------------===// diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h index d8efbb1cf10..95aea0c775a 100644 --- a/llvm/lib/AsmParser/LLParser.h +++ b/llvm/lib/AsmParser/LLParser.h @@ -570,6 +570,7 @@ namespace llvm {      bool ParseCatchSwitch(Instruction *&Inst, PerFunctionState &PFS);      bool ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS);      bool ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS); +    bool ParseCallBr(Instruction *&Inst, PerFunctionState &PFS);      bool ParseUnaryOp(Instruction *&Inst, PerFunctionState &PFS, unsigned Opc,                        unsigned OperandType); diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h index 41899b29ce5..88eeae11a4b 100644 --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -327,6 +327,7 @@ enum Kind {    kw_catchret,    kw_catchpad,    kw_cleanuppad, +  kw_callbr,    kw_alloca,    kw_load,  | 

