Author: Bill Wendling
Date: 2026-05-29T02:20:53-07:00
New Revision: 0850f6e62ea02a51be9aa465dbc926d30f7ef6a5

URL: 
https://github.com/llvm/llvm-project/commit/0850f6e62ea02a51be9aa465dbc926d30f7ef6a5
DIFF: 
https://github.com/llvm/llvm-project/commit/0850f6e62ea02a51be9aa465dbc926d30f7ef6a5.diff

LOG: [CodeGen][NFC] Refactor EmitAsmStmt to reduce header churn (#199377)

Implement Justin's suggestion, which was far better than what we had.

Added: 
    

Modified: 
    clang/lib/CodeGen/CGStmt.cpp
    clang/lib/CodeGen/CodeGenFunction.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 71f88cdf58954..4f847a5879dc6 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -2605,185 +2605,242 @@ static llvm::MDNode *getAsmSrcLocInfo(const 
StringLiteral *Str,
   return llvm::MDNode::get(CGF.getLLVMContext(), Locs);
 }
 
-void CodeGenFunction::UpdateAsmCallInst(
-    const AsmStmt &S, llvm::CallBase &Result, const AsmConstraintsInfo 
&AsmInfo,
-    bool HasSideEffect, bool HasUnwindClobber, bool NoMerge, bool NoConvergent,
-    std::vector<llvm::Value *> &RegResults) {
-  if (!HasUnwindClobber)
-    Result.addFnAttr(llvm::Attribute::NoUnwind);
+namespace clang {
 
-  if (NoMerge)
-    Result.addFnAttr(llvm::Attribute::NoMerge);
+/// This structure holds the information gathered about the constraints for an
+/// inline assembly statement. It helps in separating the constraint processing
+/// from the code generation.
+class AsmConstraintsInfo {
+  CodeGenFunction &CGF;
+  CodeGenModule &CGM; // Per-module state.
+  const AsmStmt &S;
+  CGBuilderTy &Builder;
 
-  // Attach readnone and readonly attributes.
-  if (!HasSideEffect) {
-    if (AsmInfo.ReadNone)
-      Result.setDoesNotAccessMemory();
-    else if (AsmInfo.ReadOnly)
-      Result.setOnlyReadsMemory();
-  }
+  // The final asm string.
+  std::string AsmString;
 
-  // Add elementtype attribute for indirect constraints.
-  for (auto Pair : llvm::enumerate(AsmInfo.ArgElemTypes)) {
-    if (Pair.value()) {
-      auto Attr = llvm::Attribute::get(
-          getLLVMContext(), llvm::Attribute::ElementType, Pair.value());
-      Result.addParamAttr(Pair.index(), Attr);
-    }
-  }
+  // The output and input constraints.
+  SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
+  SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
 
-  // Slap the source location of the inline asm into a !srcloc metadata on the
-  // call.
-  const StringLiteral *SL;
-  if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S);
-      gccAsmStmt &&
-      (SL = dyn_cast<StringLiteral>(gccAsmStmt->getAsmStringExpr()))) {
-    Result.setMetadata("srcloc", getAsmSrcLocInfo(SL, *this));
-  } else {
-    // At least put the line number on MS inline asm blobs and GCC asm 
constexpr
-    // strings.
-    llvm::Constant *Loc =
-        llvm::ConstantInt::get(Int64Ty, S.getAsmLoc().getRawEncoding());
-    Result.setMetadata("srcloc",
-                       llvm::MDNode::get(getLLVMContext(),
-                                         llvm::ConstantAsMetadata::get(Loc)));
-  }
+  // Constraint strings.
+  std::string Constraints;
+  std::string InOutConstraints;
 
-  // Make inline-asm calls Key for the debug info feature Key Instructions.
-  addInstToNewSourceAtom(&Result, nullptr);
+  // Keep track of out constraints for tied input operand.
+  std::vector<std::string> OutputConstraints;
 
-  if (!NoConvergent && getLangOpts().assumeFunctionsAreConvergent())
-    // Conservatively, mark all inline asm blocks in CUDA or OpenCL as
-    // convergent (meaning, they may call an intrinsically convergent op, such
-    // as bar.sync, and so can't have certain optimizations applied around
-    // them) unless it's explicitly marked 'noconvergent'.
-    Result.addFnAttr(llvm::Attribute::Convergent);
-  // Extract all of the register value results from the asm.
-  if (AsmInfo.ResultRegTypes.size() == 1) {
-    RegResults.push_back(&Result);
-  } else {
-    for (unsigned i = 0, e = AsmInfo.ResultRegTypes.size(); i != e; ++i) {
-      llvm::Value *Tmp = Builder.CreateExtractValue(&Result, i, "asmresult");
-      RegResults.push_back(Tmp);
-    }
-  }
-}
+  // Keep track of argument types.
+  std::vector<llvm::Value *> Args;
+  std::vector<llvm::Type *> ArgTypes;
+  std::vector<llvm::Type *> ArgElemTypes;
 
-void CodeGenFunction::EmitAsmStores(
-    const AsmStmt &S, const llvm::ArrayRef<llvm::Value *> RegResults,
-    const AsmConstraintsInfo &AsmInfo) {
-  llvm::LLVMContext &CTX = getLLVMContext();
+  // Keep track of result register constraints.
+  std::vector<LValue> ResultRegDests;
+  std::vector<QualType> ResultRegQualTys;
+  std::vector<llvm::Type *> ResultRegTypes;
+  std::vector<llvm::Type *> ResultTruncRegTypes;
 
-  assert(RegResults.size() == AsmInfo.ResultRegTypes.size());
-  assert(RegResults.size() == AsmInfo.ResultTruncRegTypes.size());
-  assert(RegResults.size() == AsmInfo.ResultRegDests.size());
+  llvm::BitVector ResultTypeRequiresCast;
 
-  // ResultRegDests can also be populated by addReturnRegisterOutputs() above,
-  // in which case its size may grow.
-  assert(AsmInfo.ResultTypeRequiresCast.size() <=
-         AsmInfo.ResultRegDests.size());
-  assert(AsmInfo.ResultBounds.size() <= AsmInfo.ResultRegDests.size());
+  // Keep track of in/out constraints.
+  std::vector<llvm::Value *> InOutArgs;
+  std::vector<llvm::Type *> InOutArgTypes;
+  std::vector<llvm::Type *> InOutArgElemTypes;
 
-  for (unsigned i = 0, e = RegResults.size(); i != e; ++i) {
-    llvm::Value *Tmp = RegResults[i];
-    llvm::Type *TruncTy = AsmInfo.ResultTruncRegTypes[i];
+  // Destination blocks for 'asm gotos'.
+  llvm::BasicBlock *DefaultDest = nullptr;
+  SmallVector<llvm::BasicBlock *, 3> IndirectDests;
 
-    if (i < AsmInfo.ResultBounds.size() &&
-        AsmInfo.ResultBounds[i].has_value()) {
-      const auto [LowerBound, UpperBound] = AsmInfo.ResultBounds[i].value();
+  std::vector<std::optional<std::pair<unsigned, unsigned>>> ResultBounds;
 
-      // FIXME: Support for nonzero lower bounds not yet implemented.
-      assert(LowerBound == 0 && "Output operand lower bound is not zero.");
+  // An inline asm can be marked readonly if it meets the following
+  // conditions:
+  //
+  //   - it doesn't have any sideeffects
+  //   - it doesn't clobber memory
+  //   - it doesn't return a value by-reference
+  //
+  // It can be marked readnone if it doesn't have any input memory
+  // constraints in addition to meeting the conditions listed above.
+  bool ReadOnly = true;
+  bool ReadNone = true;
+
+  bool GetOutputAndInputConstraints();
+  void HandleOutputConstraints();
+  void HandleMSStyleAsmBlob();
+  void HandleInputConstraints();
+  bool HandleLabels();
+  bool HandleClobbers();
+  void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect,
+                         bool HasUnwindClobber, bool NoMerge, bool 
NoConvergent,
+                         std::vector<llvm::Value *> &RegResults);
+  void EmitAsmStores(const llvm::ArrayRef<llvm::Value *> RegResults);
+
+  void EmitHipStdParUnsupportedAsm() {
+    constexpr auto Name = "__ASM__hipstdpar_unsupported";
+
+    std::string Asm;
+    if (auto GCCAsm = dyn_cast<GCCAsmStmt>(&S))
+      Asm = GCCAsm->getAsmString();
+
+    auto &Ctx = getLLVMContext();
+    auto StrTy = llvm::ConstantDataArray::getString(Ctx, Asm);
+    auto FnTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx),
+                                        {StrTy->getType()}, false);
+    auto UBF = CGM.getModule().getOrInsertFunction(Name, FnTy);
+
+    Builder.CreateCall(UBF, {StrTy});
+  }
+
+  ASTContext &getContext() { return CGF.getContext(); }
+  llvm::LLVMContext &getLLVMContext() { return CGF.getLLVMContext(); }
+  const TargetInfo &getTarget() const { return CGF.getTarget(); }
+  const LangOptions &getLangOpts() const { return CGF.getLangOpts(); }
+  const TargetCodeGenInfo &getTargetHooks() const {
+    return CGM.getTargetCodeGenInfo();
+  }
+
+public:
+  AsmConstraintsInfo(CodeGenFunction &CGF, const AsmStmt &S)
+      : CGF(CGF), CGM(CGF.CGM), S(S), Builder(CGF.Builder),
+        AsmString(S.generateAsmString(CGF.getContext())) {}
+
+  void EmitAsmStmt();
+};
 
-      llvm::Constant *UpperBoundConst =
-          llvm::ConstantInt::get(Tmp->getType(), UpperBound);
-      llvm::Value *IsBooleanValue =
-          Builder.CreateCmp(llvm::CmpInst::ICMP_ULT, Tmp, UpperBoundConst);
-      llvm::Function *FnAssume = CGM.getIntrinsic(llvm::Intrinsic::assume);
+} // namespace clang
 
-      Builder.CreateCall(FnAssume, IsBooleanValue);
-    }
+void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
+  // Pop all cleanup blocks at the end of the asm statement.
+  CodeGenFunction::RunCleanupsScope Cleanups(*this);
 
-    // If the result type of the LLVM IR asm doesn't match the result type of
-    // the expression, do the conversion.
-    if (AsmInfo.ResultRegTypes[i] != TruncTy) {
-      // Truncate the integer result to the right size, note that TruncTy can 
be
-      // a pointer.
-      if (TruncTy->isFloatingPointTy())
-        Tmp = Builder.CreateFPTrunc(Tmp, TruncTy);
-      else if (TruncTy->isPointerTy() && Tmp->getType()->isIntegerTy()) {
-        uint64_t ResSize = CGM.getDataLayout().getTypeSizeInBits(TruncTy);
-        Tmp = Builder.CreateTrunc(
-            Tmp, llvm::IntegerType::get(CTX, (unsigned)ResSize));
-        Tmp = Builder.CreateIntToPtr(Tmp, TruncTy);
-      } else if (Tmp->getType()->isPointerTy() && TruncTy->isIntegerTy()) {
-        uint64_t TmpSize =
-            CGM.getDataLayout().getTypeSizeInBits(Tmp->getType());
-        Tmp = Builder.CreatePtrToInt(
-            Tmp, llvm::IntegerType::get(CTX, (unsigned)TmpSize));
-        Tmp = Builder.CreateTrunc(Tmp, TruncTy);
-      } else if (Tmp->getType()->isIntegerTy() && TruncTy->isIntegerTy()) {
-        Tmp = Builder.CreateZExtOrTrunc(Tmp, TruncTy);
-      } else if (Tmp->getType()->isVectorTy() || TruncTy->isVectorTy()) {
-        Tmp = Builder.CreateBitCast(Tmp, TruncTy);
-      }
-    }
+  // Get all the output and input constraints together.
+  AsmConstraintsInfo AsmInfo(*this, S);
+  AsmInfo.EmitAsmStmt();
+}
 
-    ApplyAtomGroup Grp(getDebugInfo());
-    LValue Dest = AsmInfo.ResultRegDests[i];
+void AsmConstraintsInfo::EmitAsmStmt() {
+  if (!GetOutputAndInputConstraints())
+    return EmitHipStdParUnsupportedAsm();
 
-    // ResultTypeRequiresCast elements correspond to the first
-    // ResultTypeRequiresCast.size() elements of RegResults.
-    if (i < AsmInfo.ResultTypeRequiresCast.size() &&
-        AsmInfo.ResultTypeRequiresCast[i]) {
-      unsigned Size = getContext().getTypeSize(AsmInfo.ResultRegQualTys[i]);
-      Address A = Dest.getAddress().withElementType(AsmInfo.ResultRegTypes[i]);
+  // Handle output constraints.
+  HandleOutputConstraints();
 
-      if (getTargetHooks().isScalarizableAsmOperand(*this, TruncTy)) {
-        llvm::StoreInst *S = Builder.CreateStore(Tmp, A);
-        addInstToCurrentSourceAtom(S, S->getValueOperand());
-        continue;
-      }
+  // If this is a Microsoft-style asm blob, store the return registers 
(EAX:EDX)
+  // to the return value slot. Only do this when returning in registers.
+  HandleMSStyleAsmBlob();
 
-      QualType Ty = getContext().getIntTypeForBitwidth(Size, /*Signed=*/false);
-      if (Ty.isNull()) {
-        const Expr *OutExpr = S.getOutputExpr(i);
-        CGM.getDiags().Report(OutExpr->getExprLoc(),
-                              diag::err_store_value_to_reg);
-        return;
-      }
+  // Handle input constraints.
+  HandleInputConstraints();
 
-      Dest = MakeAddrLValue(A, Ty);
-    }
+  // Handle 'asm goto' labels.
+  bool IsGCCAsmGoto = HandleLabels();
 
-    EmitStoreThroughLValue(RValue::get(Tmp), Dest);
+  // Handle any clobbers.
+  bool HasUnwindClobber = HandleClobbers();
+  assert(!(HasUnwindClobber && IsGCCAsmGoto) &&
+         "unwind clobber can't be used with asm goto");
+
+  // Add machine specific clobbers
+  std::string_view MachineClobbers = getTarget().getClobbers();
+  if (!MachineClobbers.empty()) {
+    if (!Constraints.empty())
+      Constraints += ',';
+    Constraints += MachineClobbers;
   }
-}
 
-static void EmitHipStdParUnsupportedAsm(CodeGenFunction *CGF,
-                                        const AsmStmt &S) {
-  constexpr auto Name = "__ASM__hipstdpar_unsupported";
+  llvm::Type *ResultType;
+  if (ResultRegTypes.empty())
+    ResultType = CGF.VoidTy;
+  else if (ResultRegTypes.size() == 1)
+    ResultType = ResultRegTypes[0];
+  else
+    ResultType = llvm::StructType::get(getLLVMContext(), ResultRegTypes);
+
+  llvm::FunctionType *FTy =
+      llvm::FunctionType::get(ResultType, ArgTypes, false);
+
+  bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0;
+
+  llvm::InlineAsm::AsmDialect GnuAsmDialect =
+      CGM.getCodeGenOpts().getInlineAsmDialect() == CodeGenOptions::IAD_ATT
+          ? llvm::InlineAsm::AD_ATT
+          : llvm::InlineAsm::AD_Intel;
+  llvm::InlineAsm::AsmDialect AsmDialect =
+      isa<MSAsmStmt>(&S) ? llvm::InlineAsm::AD_Intel : GnuAsmDialect;
+
+  llvm::InlineAsm *IA = llvm::InlineAsm::get(
+      FTy, AsmString, Constraints, HasSideEffect,
+      /* IsAlignStack */ false, AsmDialect, HasUnwindClobber);
+  std::vector<llvm::Value *> RegResults;
+  llvm::CallBrInst *CBR;
+  llvm::DenseMap<llvm::BasicBlock *, SmallVector<llvm::Value *, 4>>
+      CBRRegResults;
+
+  if (IsGCCAsmGoto) {
+    CBR = Builder.CreateCallBr(IA, DefaultDest, IndirectDests, Args);
+    CGF.EmitBlock(DefaultDest);
+    UpdateAsmCallInst(*CBR, HasSideEffect,
+                      /*HasUnwindClobber=*/false, CGF.InNoMergeAttributedStmt,
+                      CGF.InNoConvergentAttributedStmt, RegResults);
+
+    // Because we are emitting code top to bottom, we don't have enough
+    // information at this point to know precisely whether we have a critical
+    // edge. If we have outputs, split all indirect destinations.
+    if (!RegResults.empty()) {
+      unsigned I = 0;
+      for (llvm::BasicBlock *Dest : CBR->getIndirectDests()) {
+        llvm::Twine SynthName = Dest->getName() + ".split";
+        llvm::BasicBlock *SynthBB = CGF.createBasicBlock(SynthName);
+        llvm::IRBuilderBase::InsertPointGuard IPG(Builder);
+        Builder.SetInsertPoint(SynthBB);
+
+        if (ResultRegTypes.size() == 1) {
+          CBRRegResults[SynthBB].push_back(CBR);
+        } else {
+          for (unsigned J = 0, E = ResultRegTypes.size(); J != E; ++J) {
+            llvm::Value *Tmp = Builder.CreateExtractValue(CBR, J, "asmresult");
+            CBRRegResults[SynthBB].push_back(Tmp);
+          }
+        }
 
-  std::string Asm;
-  if (auto GCCAsm = dyn_cast<GCCAsmStmt>(&S))
-    Asm = GCCAsm->getAsmString();
+        CGF.EmitBranch(Dest);
+        CGF.EmitBlock(SynthBB);
+        CBR->setIndirectDest(I++, SynthBB);
+      }
+    }
+  } else if (HasUnwindClobber) {
+    llvm::CallBase *Result = CGF.EmitCallOrInvoke(IA, Args, "");
+    UpdateAsmCallInst(*Result, HasSideEffect,
+                      /*HasUnwindClobber=*/true, CGF.InNoMergeAttributedStmt,
+                      CGF.InNoConvergentAttributedStmt, RegResults);
+  } else {
+    llvm::CallInst *Result =
+        Builder.CreateCall(IA, Args, CGF.getBundlesForFunclet(IA));
+    UpdateAsmCallInst(*Result, HasSideEffect,
+                      /*HasUnwindClobber=*/false, CGF.InNoMergeAttributedStmt,
+                      CGF.InNoConvergentAttributedStmt, RegResults);
+  }
 
-  auto &Ctx = CGF->CGM.getLLVMContext();
-  auto StrTy = llvm::ConstantDataArray::getString(Ctx, Asm);
-  auto FnTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx),
-                                      {StrTy->getType()}, false);
-  auto UBF = CGF->CGM.getModule().getOrInsertFunction(Name, FnTy);
+  EmitAsmStores(RegResults);
 
-  CGF->Builder.CreateCall(UBF, {StrTy});
+  // If this is an asm goto with outputs, repeat EmitAsmStores, but with a
+  // 
diff erent insertion point; one for each indirect destination and with
+  // CBRRegResults rather than RegResults.
+  if (IsGCCAsmGoto && !CBRRegResults.empty()) {
+    for (llvm::BasicBlock *Succ : CBR->getIndirectDests()) {
+      llvm::IRBuilderBase::InsertPointGuard IPG(Builder);
+      Builder.SetInsertPoint(Succ, --(Succ->end()));
+      EmitAsmStores(CBRRegResults[Succ]);
+    }
+  }
 }
 
 /// Gather and validate the output and input constraints for the given inline
 /// assembly statement. This ensures that the constraints are valid for the
 /// target and prepares them for further processing.
-bool CodeGenFunction::GetOutputAndInputConstraints(
-    const AsmStmt &S,
-    SmallVectorImpl<TargetInfo::ConstraintInfo> &OutputConstraintInfos,
-    SmallVectorImpl<TargetInfo::ConstraintInfo> &InputConstraintInfos) {
+bool AsmConstraintsInfo::GetOutputAndInputConstraints() {
   bool IsValidTargetAsm = true;
   bool IsHipStdPar = getLangOpts().HIPStdPar && getLangOpts().CUDAIsDevice;
   for (unsigned I = 0, E = S.getNumOutputs(); I != E && IsValidTargetAsm; I++) 
{
@@ -2826,18 +2883,17 @@ bool CodeGenFunction::GetOutputAndInputConstraints(
 /// handles the complexity of determining whether an output should be a
 /// register or memory operand, manages tied operands, and prepares the
 /// necessary arguments for the LLVM inline asm call.
-void CodeGenFunction::HandleOutputConstraints(const AsmStmt &S,
-                                              AsmConstraintsInfo &AsmInfo) {
+void AsmConstraintsInfo::HandleOutputConstraints() {
   // Keep track of defined physregs.
   llvm::SmallSet<std::string, 8> PhysRegOutputs;
 
   for (unsigned I = 0, E = S.getNumOutputs(); I != E; I++) {
-    TargetInfo::ConstraintInfo &Info = AsmInfo.OutputConstraintInfos[I];
+    TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[I];
 
     // Simplify the output constraint.
     std::string OutputConstraint(S.getOutputConstraint(I));
     OutputConstraint = getTarget().simplifyConstraint(
-        StringRef(OutputConstraint).substr(1), &AsmInfo.OutputConstraintInfos);
+        StringRef(OutputConstraint).substr(1), &OutputConstraintInfos);
 
     const Expr *OutExpr = S.getOutputExpr(I);
     OutExpr = OutExpr->IgnoreParenNoopCasts(getContext());
@@ -2854,32 +2910,33 @@ void CodeGenFunction::HandleOutputConstraints(const 
AsmStmt &S,
     if (!GCCReg.empty() && !PhysRegOutputs.insert(GCCReg).second)
       CGM.Error(S.getAsmLoc(), "multiple outputs to hard register: " + GCCReg);
 
-    AsmInfo.OutputConstraints.push_back(OutputConstraint);
-    LValue Dest = EmitLValue(OutExpr);
-    if (!AsmInfo.Constraints.empty())
-      AsmInfo.Constraints += ',';
+    OutputConstraints.push_back(OutputConstraint);
+    LValue Dest = CGF.EmitLValue(OutExpr);
+    if (!Constraints.empty())
+      Constraints += ',';
 
     // If this is a register output, then make the inline asm return it
     // by-value.  If this is a memory result, return the value by-reference.
     QualType QTy = OutExpr->getType();
     const bool IsScalarOrAggregate =
-        hasScalarEvaluationKind(QTy) || hasAggregateEvaluationKind(QTy);
+        CodeGenFunction::hasScalarEvaluationKind(QTy) ||
+        CodeGenFunction::hasAggregateEvaluationKind(QTy);
 
     if (!Info.allowsMemory() && IsScalarOrAggregate) {
-      AsmInfo.Constraints += "=" + OutputConstraint;
-      AsmInfo.ResultRegQualTys.push_back(QTy);
-      AsmInfo.ResultRegDests.push_back(Dest);
+      Constraints += "=" + OutputConstraint;
+      ResultRegQualTys.push_back(QTy);
+      ResultRegDests.push_back(Dest);
 
-      AsmInfo.ResultBounds.emplace_back(Info.getOutputOperandBounds());
+      ResultBounds.emplace_back(Info.getOutputOperandBounds());
 
-      llvm::Type *Ty = ConvertTypeForMem(QTy);
+      llvm::Type *Ty = CGF.ConvertTypeForMem(QTy);
       const bool RequiresCast =
           Info.allowsRegister() &&
-          (getTargetHooks().isScalarizableAsmOperand(*this, Ty) ||
+          (getTargetHooks().isScalarizableAsmOperand(CGF, Ty) ||
            Ty->isAggregateType());
 
-      AsmInfo.ResultTruncRegTypes.push_back(Ty);
-      AsmInfo.ResultTypeRequiresCast.push_back(RequiresCast);
+      ResultTruncRegTypes.push_back(Ty);
+      ResultTypeRequiresCast.push_back(RequiresCast);
 
       if (RequiresCast) {
         if (unsigned Size = getContext().getTypeSize(QTy))
@@ -2888,7 +2945,7 @@ void CodeGenFunction::HandleOutputConstraints(const 
AsmStmt &S,
           CGM.Error(OutExpr->getExprLoc(), "output size should not be zero");
       }
 
-      AsmInfo.ResultRegTypes.push_back(Ty);
+      ResultRegTypes.push_back(Ty);
 
       // If this output is tied to an input, and if the input is larger, then
       // we need to set the actual result type of the inline asm node to be the
@@ -2896,8 +2953,7 @@ void CodeGenFunction::HandleOutputConstraints(const 
AsmStmt &S,
       if (Info.hasMatchingInput()) {
         unsigned InputNo;
         for (InputNo = 0; InputNo != S.getNumInputs(); ++InputNo) {
-          TargetInfo::ConstraintInfo &Input =
-              AsmInfo.InputConstraintInfos[InputNo];
+          TargetInfo::ConstraintInfo &Input = InputConstraintInfos[InputNo];
           if (Input.hasTiedOperand() && Input.getTiedOperand() == I)
             break;
         }
@@ -2909,21 +2965,21 @@ void CodeGenFunction::HandleOutputConstraints(const 
AsmStmt &S,
         uint64_t InputSize = getContext().getTypeSize(InputTy);
         if (getContext().getTypeSize(OutputType) < InputSize)
           // Form the asm to return the value as a larger integer or fp type.
-          AsmInfo.ResultRegTypes.back() = ConvertType(InputTy);
+          ResultRegTypes.back() = CGF.ConvertType(InputTy);
       }
 
       if (llvm::Type *AdjTy = getTargetHooks().adjustInlineAsmType(
-              *this, OutputConstraint, AsmInfo.ResultRegTypes.back()))
-        AsmInfo.ResultRegTypes.back() = AdjTy;
+              CGF, OutputConstraint, ResultRegTypes.back()))
+        ResultRegTypes.back() = AdjTy;
       else
         CGM.getDiags().Report(S.getAsmLoc(),
                               diag::err_asm_invalid_type_in_input)
             << OutExpr->getType() << OutputConstraint;
 
       // Update largest vector width for any vector types.
-      if (auto *VT = dyn_cast<llvm::VectorType>(AsmInfo.ResultRegTypes.back()))
-        LargestVectorWidth =
-            std::max((uint64_t)LargestVectorWidth,
+      if (auto *VT = dyn_cast<llvm::VectorType>(ResultRegTypes.back()))
+        CGF.LargestVectorWidth =
+            std::max((uint64_t)CGF.LargestVectorWidth,
                      VT->getPrimitiveSizeInBits().getKnownMinValue());
     } else {
       Address DestAddr = Dest.getAddress();
@@ -2934,94 +2990,92 @@ void CodeGenFunction::HandleOutputConstraints(const 
AsmStmt &S,
       // Otherwise there will be a mis-match if the matrix is also an
       // input-argument which is represented as vector.
       if (isa<MatrixType>(OutExpr->getType().getCanonicalType()))
-        DestAddr = DestAddr.withElementType(ConvertType(OutExpr->getType()));
+        DestAddr =
+            DestAddr.withElementType(CGF.ConvertType(OutExpr->getType()));
 
-      AsmInfo.ArgTypes.push_back(DestAddr.getType());
-      AsmInfo.ArgElemTypes.push_back(DestAddr.getElementType());
-      AsmInfo.Args.push_back(DestAddr.emitRawPointer(*this));
+      ArgTypes.push_back(DestAddr.getType());
+      ArgElemTypes.push_back(DestAddr.getElementType());
+      Args.push_back(DestAddr.emitRawPointer(CGF));
 
-      AsmInfo.Constraints += "=*" + OutputConstraint;
-      AsmInfo.ReadOnly = false;
-      AsmInfo.ReadNone = false;
+      Constraints += "=*" + OutputConstraint;
+      ReadOnly = false;
+      ReadNone = false;
     }
 
     if (!Info.isReadWrite())
       continue;
 
-    AsmInfo.InOutConstraints += ',';
+    InOutConstraints += ',';
 
     const Expr *InputExpr = S.getOutputExpr(I);
     llvm::Value *Arg;
     llvm::Type *ArgElemType;
     std::tie(Arg, ArgElemType) =
-        EmitAsmInputLValue(Info, Dest, InputExpr->getType(),
-                           AsmInfo.InOutConstraints, InputExpr->getExprLoc());
+        CGF.EmitAsmInputLValue(Info, Dest, InputExpr->getType(),
+                               InOutConstraints, InputExpr->getExprLoc());
 
     if (llvm::Type *AdjTy = getTargetHooks().adjustInlineAsmType(
-            *this, OutputConstraint, Arg->getType()))
+            CGF, OutputConstraint, Arg->getType()))
       Arg = Builder.CreateBitCast(Arg, AdjTy);
 
     // Update largest vector width for any vector types.
     if (auto *VT = dyn_cast<llvm::VectorType>(Arg->getType()))
-      LargestVectorWidth =
-          std::max((uint64_t)LargestVectorWidth,
+      CGF.LargestVectorWidth =
+          std::max((uint64_t)CGF.LargestVectorWidth,
                    VT->getPrimitiveSizeInBits().getKnownMinValue());
 
     // Only tie earlyclobber physregs.
     if (Info.allowsRegister() && (GCCReg.empty() || Info.earlyClobber()))
-      AsmInfo.InOutConstraints += llvm::utostr(I);
+      InOutConstraints += llvm::utostr(I);
     else
-      AsmInfo.InOutConstraints += OutputConstraint;
+      InOutConstraints += OutputConstraint;
 
-    AsmInfo.InOutArgTypes.push_back(Arg->getType());
-    AsmInfo.InOutArgElemTypes.push_back(ArgElemType);
-    AsmInfo.InOutArgs.push_back(Arg);
+    InOutArgTypes.push_back(Arg->getType());
+    InOutArgElemTypes.push_back(ArgElemType);
+    InOutArgs.push_back(Arg);
   }
 }
 
 /// Special handling for Microsoft-style inline assembly blocks. This ensures
 /// that return registers (like EAX:EDX) are correctly mapped to the function's
 /// return value slot when necessary.
-void CodeGenFunction::HandleMSStyleAsmBlob(const AsmStmt &S,
-                                           std::string &AsmString,
-                                           AsmConstraintsInfo &AsmInfo) {
+void AsmConstraintsInfo::HandleMSStyleAsmBlob() {
   if (!isa<MSAsmStmt>(&S))
     return;
 
-  const ABIArgInfo &RetAI = CurFnInfo->getReturnInfo();
+  const ABIArgInfo &RetAI = CGF.CurFnInfo->getReturnInfo();
   if (!RetAI.isDirect() && !RetAI.isExtend())
     return;
 
   // Make a fake lvalue for the return value slot.
-  LValue ReturnSlot = MakeAddrLValueWithoutTBAA(ReturnValue, FnRetTy);
+  LValue ReturnSlot =
+      CGF.MakeAddrLValueWithoutTBAA(CGF.ReturnValue, CGF.FnRetTy);
   CGM.getTargetCodeGenInfo().addReturnRegisterOutputs(
-      *this, ReturnSlot, AsmInfo.Constraints, AsmInfo.ResultRegTypes,
-      AsmInfo.ResultTruncRegTypes, AsmInfo.ResultRegDests, AsmString,
-      S.getNumOutputs());
-  SawAsmBlock = true;
+      CGF, ReturnSlot, Constraints, ResultRegTypes, ResultTruncRegTypes,
+      ResultRegDests, AsmString, S.getNumOutputs());
+  CGF.SawAsmBlock = true;
 }
 
 /// Process the input constraints of an inline assembly statement. It handles
 /// type conversions, extensions for tied operands, and collects the necessary
 /// LLVM values to be passed to the inline assembly call.
-void CodeGenFunction::HandleInputConstraints(const AsmStmt &S,
-                                             AsmConstraintsInfo &AsmInfo) {
+void AsmConstraintsInfo::HandleInputConstraints() {
   ASTContext &Ctx = getContext();
 
   for (unsigned I = 0, E = S.getNumInputs(); I != E; I++) {
-    TargetInfo::ConstraintInfo &Info = AsmInfo.InputConstraintInfos[I];
+    TargetInfo::ConstraintInfo &Info = InputConstraintInfos[I];
     const Expr *InputExpr = S.getInputExpr(I);
 
     if (Info.allowsMemory())
-      AsmInfo.ReadNone = false;
+      ReadNone = false;
 
-    if (!AsmInfo.Constraints.empty())
-      AsmInfo.Constraints += ',';
+    if (!Constraints.empty())
+      Constraints += ',';
 
     // Simplify the input constraint.
     std::string InputConstraint(S.getInputConstraint(I));
-    InputConstraint = getTarget().simplifyConstraint(
-        InputConstraint, &AsmInfo.OutputConstraintInfos);
+    InputConstraint =
+        getTarget().simplifyConstraint(InputConstraint, 
&OutputConstraintInfos);
 
     InputConstraint = S.addVariableConstraints(
         InputConstraint, *InputExpr->IgnoreParenNoopCasts(Ctx), getTarget(),
@@ -3033,8 +3087,7 @@ void CodeGenFunction::HandleInputConstraints(const 
AsmStmt &S,
     std::string ReplaceConstraint(InputConstraint);
     llvm::Value *Arg;
     llvm::Type *ArgElemType;
-    std::tie(Arg, ArgElemType) =
-        EmitAsmInput(Info, InputExpr, AsmInfo.Constraints);
+    std::tie(Arg, ArgElemType) = CGF.EmitAsmInput(Info, InputExpr, 
Constraints);
 
     // If this input argument is tied to a larger output result, extend the
     // input to be the same size as the output.  The LLVM backend wants to see
@@ -3049,23 +3102,23 @@ void CodeGenFunction::HandleInputConstraints(const 
AsmStmt &S,
       if (Ctx.getTypeSize(OutputType) > Ctx.getTypeSize(InputTy)) {
         // Use ptrtoint as appropriate so that we can do our extension.
         if (isa<llvm::PointerType>(Arg->getType()))
-          Arg = Builder.CreatePtrToInt(Arg, IntPtrTy);
+          Arg = Builder.CreatePtrToInt(Arg, CGF.IntPtrTy);
 
-        llvm::Type *OutputTy = ConvertType(OutputType);
+        llvm::Type *OutputTy = CGF.ConvertType(OutputType);
         if (isa<llvm::IntegerType>(OutputTy))
           Arg = Builder.CreateZExt(Arg, OutputTy);
         else if (isa<llvm::PointerType>(OutputTy))
-          Arg = Builder.CreateZExt(Arg, IntPtrTy);
+          Arg = Builder.CreateZExt(Arg, CGF.IntPtrTy);
         else if (OutputTy->isFloatingPointTy())
           Arg = Builder.CreateFPExt(Arg, OutputTy);
       }
 
       // Deal with the tied operands' constraint code in adjustInlineAsmType.
-      ReplaceConstraint = AsmInfo.OutputConstraints[Output];
+      ReplaceConstraint = OutputConstraints[Output];
     }
 
     if (llvm::Type *AdjTy = getTargetHooks().adjustInlineAsmType(
-            *this, ReplaceConstraint, Arg->getType()))
+            CGF, ReplaceConstraint, Arg->getType()))
       Arg = Builder.CreateBitCast(Arg, AdjTy);
     else
       CGM.getDiags().Report(S.getAsmLoc(), diag::err_asm_invalid_type_in_input)
@@ -3073,44 +3126,43 @@ void CodeGenFunction::HandleInputConstraints(const 
AsmStmt &S,
 
     // Update largest vector width for any vector types.
     if (auto *VT = dyn_cast<llvm::VectorType>(Arg->getType()))
-      LargestVectorWidth =
-          std::max((uint64_t)LargestVectorWidth,
+      CGF.LargestVectorWidth =
+          std::max((uint64_t)CGF.LargestVectorWidth,
                    VT->getPrimitiveSizeInBits().getKnownMinValue());
 
-    AsmInfo.ArgTypes.push_back(Arg->getType());
-    AsmInfo.ArgElemTypes.push_back(ArgElemType);
-    AsmInfo.Args.push_back(Arg);
+    ArgTypes.push_back(Arg->getType());
+    ArgElemTypes.push_back(ArgElemType);
+    Args.push_back(Arg);
 
-    AsmInfo.Constraints += InputConstraint;
+    Constraints += InputConstraint;
   }
 
   // Append the "input" part of in/out constraints.
-  for (unsigned I = 0, E = AsmInfo.InOutArgs.size(); I != E; I++) {
-    AsmInfo.ArgTypes.push_back(AsmInfo.InOutArgTypes[I]);
-    AsmInfo.ArgElemTypes.push_back(AsmInfo.InOutArgElemTypes[I]);
-    AsmInfo.Args.push_back(AsmInfo.InOutArgs[I]);
+  for (unsigned I = 0, E = InOutArgs.size(); I != E; I++) {
+    ArgTypes.push_back(InOutArgTypes[I]);
+    ArgElemTypes.push_back(InOutArgElemTypes[I]);
+    Args.push_back(InOutArgs[I]);
   }
 
-  AsmInfo.Constraints += AsmInfo.InOutConstraints;
+  Constraints += InOutConstraints;
 }
 
 /// Handle labels in an 'asm goto' statement. This method resolves the symbolic
 /// labels to LLVM basic blocks and updates the constraint string to reflect
 /// the indirect jump targets.
-bool CodeGenFunction::HandleLabels(const AsmStmt &S,
-                                   AsmConstraintsInfo &AsmInfo) {
+bool AsmConstraintsInfo::HandleLabels() {
   if (const auto *GS = dyn_cast<GCCAsmStmt>(&S); GS && GS->isAsmGoto()) {
     for (const auto *E : GS->labels()) {
-      CodeGenFunction::JumpDest Dest = getJumpDestForLabel(E->getLabel());
-      AsmInfo.IndirectDests.push_back(Dest.getBlock());
+      CodeGenFunction::JumpDest Dest = CGF.getJumpDestForLabel(E->getLabel());
+      IndirectDests.push_back(Dest.getBlock());
 
-      if (!AsmInfo.Constraints.empty())
-        AsmInfo.Constraints += ',';
+      if (!Constraints.empty())
+        Constraints += ',';
 
-      AsmInfo.Constraints += "!i";
+      Constraints += "!i";
     }
 
-    AsmInfo.DefaultDest = createBasicBlock("asm.fallthrough");
+    DefaultDest = CGF.createBasicBlock("asm.fallthrough");
     return true;
   }
 
@@ -3121,9 +3173,7 @@ bool CodeGenFunction::HandleLabels(const AsmStmt &S,
 /// identifies which registers or system state (like "memory" or "cc") are
 /// modified by the assembly block, which is crucial for correct optimization
 /// and side-effect modeling.
-bool CodeGenFunction::HandleClobbers(const AsmStmt &S,
-                                     AsmConstraintsInfo &AsmInfo) {
-  std::string &Constraints = AsmInfo.Constraints;
+bool AsmConstraintsInfo::HandleClobbers() {
   bool HasUnwindClobber = false;
   for (unsigned I = 0, E = S.getNumClobbers(); I != E; I++) {
     std::string Clobber = S.getClobber(I);
@@ -3134,8 +3184,8 @@ bool CodeGenFunction::HandleClobbers(const AsmStmt &S,
     }
 
     if (Clobber == "memory") {
-      AsmInfo.ReadOnly = false;
-      AsmInfo.ReadNone = false;
+      ReadOnly = false;
+      ReadNone = false;
     } else if (Clobber != "cc") {
       Clobber = getTarget().getNormalizedGCCRegisterName(Clobber);
       if (CGM.getCodeGenOpts().StackClashProtector &&
@@ -3174,142 +3224,155 @@ bool CodeGenFunction::HandleClobbers(const AsmStmt &S,
   return HasUnwindClobber;
 }
 
-void CodeGenFunction::EmitAsmStmt(
-    const AsmStmt &S,
-    SmallVectorImpl<TargetInfo::ConstraintInfo> &OutputConstraintInfos,
-    SmallVectorImpl<TargetInfo::ConstraintInfo> &InputConstraintInfos) {
-  // Assemble the final asm string.
-  std::string AsmString = S.generateAsmString(getContext());
+void AsmConstraintsInfo::UpdateAsmCallInst(
+    llvm::CallBase &Result, bool HasSideEffect, bool HasUnwindClobber,
+    bool NoMerge, bool NoConvergent, std::vector<llvm::Value *> &RegResults) {
+  if (!HasUnwindClobber)
+    Result.addFnAttr(llvm::Attribute::NoUnwind);
 
-  AsmConstraintsInfo AsmInfo(OutputConstraintInfos, InputConstraintInfos);
+  if (NoMerge)
+    Result.addFnAttr(llvm::Attribute::NoMerge);
 
-  // Handle output constraints.
-  HandleOutputConstraints(S, AsmInfo);
+  // Attach readnone and readonly attributes.
+  if (!HasSideEffect) {
+    if (ReadNone)
+      Result.setDoesNotAccessMemory();
+    else if (ReadOnly)
+      Result.setOnlyReadsMemory();
+  }
 
-  // If this is a Microsoft-style asm blob, store the return registers 
(EAX:EDX)
-  // to the return value slot. Only do this when returning in registers.
-  HandleMSStyleAsmBlob(S, AsmString, AsmInfo);
+  // Add elementtype attribute for indirect constraints.
+  for (auto Pair : llvm::enumerate(ArgElemTypes)) {
+    if (Pair.value()) {
+      auto Attr = llvm::Attribute::get(
+          getLLVMContext(), llvm::Attribute::ElementType, Pair.value());
+      Result.addParamAttr(Pair.index(), Attr);
+    }
+  }
 
-  // Handle input constraints.
-  HandleInputConstraints(S, AsmInfo);
+  // Slap the source location of the inline asm into a !srcloc metadata on the
+  // call.
+  const StringLiteral *SL;
+  if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S);
+      gccAsmStmt &&
+      (SL = dyn_cast<StringLiteral>(gccAsmStmt->getAsmStringExpr()))) {
+    Result.setMetadata("srcloc", getAsmSrcLocInfo(SL, CGF));
+  } else {
+    // At least put the line number on MS inline asm blobs and GCC asm 
constexpr
+    // strings.
+    llvm::Constant *Loc =
+        llvm::ConstantInt::get(CGF.Int64Ty, S.getAsmLoc().getRawEncoding());
+    Result.setMetadata("srcloc",
+                       llvm::MDNode::get(getLLVMContext(),
+                                         llvm::ConstantAsMetadata::get(Loc)));
+  }
 
-  // Handle 'asm goto' labels.
-  bool IsGCCAsmGoto = HandleLabels(S, AsmInfo);
+  // Make inline-asm calls Key for the debug info feature Key Instructions.
+  CGF.addInstToNewSourceAtom(&Result, nullptr);
 
-  // Handle any clobbers.
-  bool HasUnwindClobber = HandleClobbers(S, AsmInfo);
-  assert(!(HasUnwindClobber && IsGCCAsmGoto) &&
-         "unwind clobber can't be used with asm goto");
+  if (!NoConvergent && getLangOpts().assumeFunctionsAreConvergent())
+    // Conservatively, mark all inline asm blocks in CUDA or OpenCL as
+    // convergent (meaning, they may call an intrinsically convergent op, such
+    // as bar.sync, and so can't have certain optimizations applied around
+    // them) unless it's explicitly marked 'noconvergent'.
+    Result.addFnAttr(llvm::Attribute::Convergent);
 
-  // Add machine specific clobbers
-  std::string_view MachineClobbers = getTarget().getClobbers();
-  if (!MachineClobbers.empty()) {
-    if (!AsmInfo.Constraints.empty())
-      AsmInfo.Constraints += ',';
-    AsmInfo.Constraints += MachineClobbers;
+  // Extract all of the register value results from the asm.
+  if (ResultRegTypes.size() == 1) {
+    RegResults.push_back(&Result);
+  } else {
+    for (unsigned i = 0, e = ResultRegTypes.size(); i != e; ++i) {
+      llvm::Value *Tmp = Builder.CreateExtractValue(&Result, i, "asmresult");
+      RegResults.push_back(Tmp);
+    }
   }
+}
 
-  llvm::Type *ResultType;
-  if (AsmInfo.ResultRegTypes.empty())
-    ResultType = VoidTy;
-  else if (AsmInfo.ResultRegTypes.size() == 1)
-    ResultType = AsmInfo.ResultRegTypes[0];
-  else
-    ResultType =
-        llvm::StructType::get(getLLVMContext(), AsmInfo.ResultRegTypes);
+void AsmConstraintsInfo::EmitAsmStores(
+    const llvm::ArrayRef<llvm::Value *> RegResults) {
+  llvm::LLVMContext &CTX = getLLVMContext();
 
-  llvm::FunctionType *FTy =
-      llvm::FunctionType::get(ResultType, AsmInfo.ArgTypes, false);
+  assert(RegResults.size() == ResultRegTypes.size());
+  assert(RegResults.size() == ResultTruncRegTypes.size());
+  assert(RegResults.size() == ResultRegDests.size());
 
-  bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0;
+  // ResultRegDests can also be populated by addReturnRegisterOutputs() above,
+  // in which case its size may grow.
+  assert(ResultTypeRequiresCast.size() <= ResultRegDests.size());
+  assert(ResultBounds.size() <= ResultRegDests.size());
 
-  llvm::InlineAsm::AsmDialect GnuAsmDialect =
-      CGM.getCodeGenOpts().getInlineAsmDialect() == CodeGenOptions::IAD_ATT
-          ? llvm::InlineAsm::AD_ATT
-          : llvm::InlineAsm::AD_Intel;
-  llvm::InlineAsm::AsmDialect AsmDialect =
-      isa<MSAsmStmt>(&S) ? llvm::InlineAsm::AD_Intel : GnuAsmDialect;
+  for (unsigned i = 0, e = RegResults.size(); i != e; ++i) {
+    llvm::Value *Tmp = RegResults[i];
+    llvm::Type *TruncTy = ResultTruncRegTypes[i];
 
-  llvm::InlineAsm *IA = llvm::InlineAsm::get(
-      FTy, AsmString, AsmInfo.Constraints, HasSideEffect,
-      /* IsAlignStack */ false, AsmDialect, HasUnwindClobber);
-  std::vector<llvm::Value*> RegResults;
-  llvm::CallBrInst *CBR;
-  llvm::DenseMap<llvm::BasicBlock *, SmallVector<llvm::Value *, 4>>
-      CBRRegResults;
+    if (i < ResultBounds.size() && ResultBounds[i].has_value()) {
+      const auto [LowerBound, UpperBound] = ResultBounds[i].value();
 
-  if (IsGCCAsmGoto) {
-    CBR = Builder.CreateCallBr(IA, AsmInfo.DefaultDest, AsmInfo.IndirectDests,
-                               AsmInfo.Args);
-    EmitBlock(AsmInfo.DefaultDest);
-    UpdateAsmCallInst(S, *CBR, AsmInfo, HasSideEffect,
-                      /*HasUnwindClobber=*/false, InNoMergeAttributedStmt,
-                      InNoConvergentAttributedStmt, RegResults);
+      // FIXME: Support for nonzero lower bounds not yet implemented.
+      assert(LowerBound == 0 && "Output operand lower bound is not zero.");
 
-    // Because we are emitting code top to bottom, we don't have enough
-    // information at this point to know precisely whether we have a critical
-    // edge. If we have outputs, split all indirect destinations.
-    if (!RegResults.empty()) {
-      unsigned I = 0;
-      for (llvm::BasicBlock *Dest : CBR->getIndirectDests()) {
-        llvm::Twine SynthName = Dest->getName() + ".split";
-        llvm::BasicBlock *SynthBB = createBasicBlock(SynthName);
-        llvm::IRBuilderBase::InsertPointGuard IPG(Builder);
-        Builder.SetInsertPoint(SynthBB);
+      llvm::Constant *UpperBoundConst =
+          llvm::ConstantInt::get(Tmp->getType(), UpperBound);
+      llvm::Value *IsBooleanValue =
+          Builder.CreateCmp(llvm::CmpInst::ICMP_ULT, Tmp, UpperBoundConst);
+      llvm::Function *FnAssume = CGM.getIntrinsic(llvm::Intrinsic::assume);
 
-        if (AsmInfo.ResultRegTypes.size() == 1) {
-          CBRRegResults[SynthBB].push_back(CBR);
-        } else {
-          for (unsigned J = 0, E = AsmInfo.ResultRegTypes.size(); J != E; ++J) 
{
-            llvm::Value *Tmp = Builder.CreateExtractValue(CBR, J, "asmresult");
-            CBRRegResults[SynthBB].push_back(Tmp);
-          }
-        }
+      Builder.CreateCall(FnAssume, IsBooleanValue);
+    }
 
-        EmitBranch(Dest);
-        EmitBlock(SynthBB);
-        CBR->setIndirectDest(I++, SynthBB);
+    // If the result type of the LLVM IR asm doesn't match the result type of
+    // the expression, do the conversion.
+    if (ResultRegTypes[i] != TruncTy) {
+      // Truncate the integer result to the right size, note that TruncTy can 
be
+      // a pointer.
+      if (TruncTy->isFloatingPointTy())
+        Tmp = Builder.CreateFPTrunc(Tmp, TruncTy);
+      else if (TruncTy->isPointerTy() && Tmp->getType()->isIntegerTy()) {
+        uint64_t ResSize = CGM.getDataLayout().getTypeSizeInBits(TruncTy);
+        Tmp = Builder.CreateTrunc(
+            Tmp, llvm::IntegerType::get(CTX, (unsigned)ResSize));
+        Tmp = Builder.CreateIntToPtr(Tmp, TruncTy);
+      } else if (Tmp->getType()->isPointerTy() && TruncTy->isIntegerTy()) {
+        uint64_t TmpSize =
+            CGM.getDataLayout().getTypeSizeInBits(Tmp->getType());
+        Tmp = Builder.CreatePtrToInt(
+            Tmp, llvm::IntegerType::get(CTX, (unsigned)TmpSize));
+        Tmp = Builder.CreateTrunc(Tmp, TruncTy);
+      } else if (Tmp->getType()->isIntegerTy() && TruncTy->isIntegerTy()) {
+        Tmp = Builder.CreateZExtOrTrunc(Tmp, TruncTy);
+      } else if (Tmp->getType()->isVectorTy() || TruncTy->isVectorTy()) {
+        Tmp = Builder.CreateBitCast(Tmp, TruncTy);
       }
     }
-  } else if (HasUnwindClobber) {
-    llvm::CallBase *Result = EmitCallOrInvoke(IA, AsmInfo.Args, "");
-    UpdateAsmCallInst(S, *Result, AsmInfo, HasSideEffect,
-                      /*HasUnwindClobber=*/true, InNoMergeAttributedStmt,
-                      InNoConvergentAttributedStmt, RegResults);
-  } else {
-    llvm::CallInst *Result =
-        Builder.CreateCall(IA, AsmInfo.Args, getBundlesForFunclet(IA));
-    UpdateAsmCallInst(S, *Result, AsmInfo, HasSideEffect,
-                      /*HasUnwindClobber=*/false, InNoMergeAttributedStmt,
-                      InNoConvergentAttributedStmt, RegResults);
-  }
 
-  EmitAsmStores(S, RegResults, AsmInfo);
+    ApplyAtomGroup Grp(CGF.getDebugInfo());
+    LValue Dest = ResultRegDests[i];
 
-  // If this is an asm goto with outputs, repeat EmitAsmStores, but with a
-  // 
diff erent insertion point; one for each indirect destination and with
-  // CBRRegResults rather than RegResults.
-  if (IsGCCAsmGoto && !CBRRegResults.empty()) {
-    for (llvm::BasicBlock *Succ : CBR->getIndirectDests()) {
-      llvm::IRBuilderBase::InsertPointGuard IPG(Builder);
-      Builder.SetInsertPoint(Succ, --(Succ->end()));
-      EmitAsmStores(S, CBRRegResults[Succ], AsmInfo);
-    }
-  }
-}
+    // ResultTypeRequiresCast elements correspond to the first
+    // ResultTypeRequiresCast.size() elements of RegResults.
+    if (i < ResultTypeRequiresCast.size() && ResultTypeRequiresCast[i]) {
+      unsigned Size = getContext().getTypeSize(ResultRegQualTys[i]);
+      Address A = Dest.getAddress().withElementType(ResultRegTypes[i]);
 
-void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
-  // Pop all cleanup blocks at the end of the asm statement.
-  CodeGenFunction::RunCleanupsScope Cleanups(*this);
+      if (getTargetHooks().isScalarizableAsmOperand(CGF, TruncTy)) {
+        llvm::StoreInst *S = Builder.CreateStore(Tmp, A);
+        CGF.addInstToCurrentSourceAtom(S, S->getValueOperand());
+        continue;
+      }
 
-  // Get all the output and input constraints together.
-  SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
-  SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
-  if (!GetOutputAndInputConstraints(S, OutputConstraintInfos,
-                                    InputConstraintInfos))
-    return EmitHipStdParUnsupportedAsm(this, S);
+      QualType Ty = getContext().getIntTypeForBitwidth(Size, /*Signed=*/false);
+      if (Ty.isNull()) {
+        const Expr *OutExpr = S.getOutputExpr(i);
+        CGM.getDiags().Report(OutExpr->getExprLoc(),
+                              diag::err_store_value_to_reg);
+        return;
+      }
 
-  EmitAsmStmt(S, OutputConstraintInfos, InputConstraintInfos);
+      Dest = CGF.MakeAddrLValue(A, Ty);
+    }
+
+    CGF.EmitStoreThroughLValue(RValue::get(Tmp), Dest);
+  }
 }
 
 LValue CodeGenFunction::InitCapturedStruct(const CapturedStmt &S) {

diff  --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index 777017f90d428..721ef6a64e7f9 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -58,6 +58,7 @@ class CanonicalLoopInfo;
 
 namespace clang {
 class ASTContext;
+class AsmConstraintsInfo;
 class CXXDestructorDecl;
 class CXXForRangeStmt;
 class CXXTryStmt;
@@ -259,6 +260,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   void operator=(const CodeGenFunction &) = delete;
 
   friend class CGCXXABI;
+  friend class clang::AsmConstraintsInfo;
 
 public:
   /// A jump destination is an abstract label, branching to which may
@@ -5497,86 +5499,6 @@ class CodeGenFunction : public CodeGenTypeCache {
                      QualType InputType, std::string &ConstraintStr,
                      SourceLocation Loc);
 
-  /// This structure holds the information gathered about the constraints for 
an
-  /// inline assembly statement. It helps in separating the constraint
-  /// processing from the code generation.
-  struct AsmConstraintsInfo {
-    // The output and input constraints.
-    SmallVectorImpl<TargetInfo::ConstraintInfo> &OutputConstraintInfos;
-    SmallVectorImpl<TargetInfo::ConstraintInfo> &InputConstraintInfos;
-
-    // Constraint strings.
-    std::string Constraints;
-    std::string InOutConstraints;
-
-    // Keep track of out constraints for tied input operand.
-    std::vector<std::string> OutputConstraints;
-
-    // Keep track of argument types.
-    std::vector<llvm::Value *> Args;
-    std::vector<llvm::Type *> ArgTypes;
-    std::vector<llvm::Type *> ArgElemTypes;
-
-    // Keep track of result register constraints.
-    std::vector<LValue> ResultRegDests;
-    std::vector<QualType> ResultRegQualTys;
-    std::vector<llvm::Type *> ResultRegTypes;
-    std::vector<llvm::Type *> ResultTruncRegTypes;
-
-    llvm::BitVector ResultTypeRequiresCast;
-
-    // Keep track of in/out constraints.
-    std::vector<llvm::Value *> InOutArgs;
-    std::vector<llvm::Type *> InOutArgTypes;
-    std::vector<llvm::Type *> InOutArgElemTypes;
-
-    // Destination blocks for 'asm gotos'.
-    llvm::BasicBlock *DefaultDest = nullptr;
-    SmallVector<llvm::BasicBlock *, 3> IndirectDests;
-
-    std::vector<std::optional<std::pair<unsigned, unsigned>>> ResultBounds;
-
-    // An inline asm can be marked readonly if it meets the following
-    // conditions:
-    //
-    //   - it doesn't have any sideeffects
-    //   - it doesn't clobber memory
-    //   - it doesn't return a value by-reference
-    //
-    // It can be marked readnone if it doesn't have any input memory
-    // constraints in addition to meeting the conditions listed above.
-    bool ReadOnly = true;
-    bool ReadNone = true;
-
-    AsmConstraintsInfo(
-        SmallVectorImpl<TargetInfo::ConstraintInfo> &OutputConstraintInfos,
-        SmallVectorImpl<TargetInfo::ConstraintInfo> &InputConstraintInfos)
-        : OutputConstraintInfos(OutputConstraintInfos),
-          InputConstraintInfos(InputConstraintInfos) {}
-  };
-
-  void EmitAsmStmt(
-      const AsmStmt &S,
-      SmallVectorImpl<TargetInfo::ConstraintInfo> &OutputConstraintInfos,
-      SmallVectorImpl<TargetInfo::ConstraintInfo> &InputConstraintInfos);
-  void EmitAsmStores(const AsmStmt &S,
-                     const llvm::ArrayRef<llvm::Value *> RegResults,
-                     const AsmConstraintsInfo &AsmInfo);
-  void UpdateAsmCallInst(const AsmStmt &S, llvm::CallBase &Result,
-                         const AsmConstraintsInfo &AsmInfo, bool HasSideEffect,
-                         bool HasUnwindClobber, bool NoMerge, bool 
NoConvergent,
-                         std::vector<llvm::Value *> &RegResults);
-  bool GetOutputAndInputConstraints(
-      const AsmStmt &S,
-      SmallVectorImpl<TargetInfo::ConstraintInfo> &OutputConstraintInfos,
-      SmallVectorImpl<TargetInfo::ConstraintInfo> &InputConstraintInfos);
-  void HandleOutputConstraints(const AsmStmt &S, AsmConstraintsInfo &AsmInfo);
-  void HandleMSStyleAsmBlob(const AsmStmt &S, std::string &AsmString,
-                            AsmConstraintsInfo &AsmInfo);
-  void HandleInputConstraints(const AsmStmt &S, AsmConstraintsInfo &AsmInfo);
-  bool HandleLabels(const AsmStmt &S, AsmConstraintsInfo &AsmInfo);
-  bool HandleClobbers(const AsmStmt &S, AsmConstraintsInfo &AsmInfo);
-
   /// Attempts to statically evaluate the object size of E. If that
   /// fails, emits code to figure the size of E out for us. This is
   /// pass_object_size aware.


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to