nickdesaulniers updated this revision to Diff 469764.
nickdesaulniers edited the summary of this revision.
nickdesaulniers added a comment.

- add note to commit message (let's see if phab captures what I wrote, used arc 
diff --verbatim)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136497/new/

https://reviews.llvm.org/D136497

Files:
  clang/lib/CodeGen/CGStmt.cpp
  clang/test/CodeGen/asm-goto.c
  clang/test/CodeGen/asm-goto2.c
  clang/test/Modules/asm-goto.c

Index: clang/test/Modules/asm-goto.c
===================================================================
--- clang/test/Modules/asm-goto.c
+++ clang/test/Modules/asm-goto.c
@@ -5,7 +5,7 @@
 
 // CHECK-LABEL: define {{.*}} @foo(
 // CHECK: callbr {{.*}} "=r,!i{{.*}}()
-// CHECK-NEXT: to label %asm.fallthrough [label %indirect]
+// CHECK-NEXT: to label %asm.fallthrough [label %indirect.split]
 
 int bar(void) {
   return foo();
Index: clang/test/CodeGen/asm-goto2.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/asm-goto2.c
@@ -0,0 +1,156 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O0 -emit-llvm %s -o - | FileCheck %s
+
+// CHECK-LABEL: @test0(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[RET:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i,~{dirflag},~{fpsr},~{flags}"() #[[ATTR1:[0-9]+]]
+// CHECK-NEXT:    to label [[ASM_FALLTHROUGH:%.*]] [label %z.split], !srcloc !2
+// CHECK:       asm.fallthrough:
+// CHECK-NEXT:    store i32 [[TMP0]], ptr [[RET]], align 4
+// CHECK-NEXT:    store i32 42, ptr [[RET]], align 4
+// CHECK-NEXT:    br label [[Z:%.*]]
+// CHECK:       z:
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[RET]], align 4
+// CHECK-NEXT:    ret i32 [[TMP1]]
+// CHECK:       z.split:
+// CHECK-NEXT:    store i32 [[TMP0]], ptr [[RET]], align 4
+// CHECK-NEXT:    br label [[Z]]
+//
+int test0 (void) {
+  int ret;
+  asm goto ("" : "=r"(ret):::z);
+  ret = 42;
+z:
+  return ret;
+}
+
+// CHECK-LABEL: @test1(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[RET:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = callbr { i32, i32 } asm "", "=r,=r,!i,~{dirflag},~{fpsr},~{flags}"() #[[ATTR1]]
+// CHECK-NEXT:    to label [[ASM_FALLTHROUGH:%.*]] [label %z.split], !srcloc !3
+// CHECK:       asm.fallthrough:
+// CHECK-NEXT:    [[ASMRESULT:%.*]] = extractvalue { i32, i32 } [[TMP0]], 0
+// CHECK-NEXT:    [[ASMRESULT1:%.*]] = extractvalue { i32, i32 } [[TMP0]], 1
+// CHECK-NEXT:    store i32 [[ASMRESULT]], ptr [[RET]], align 4
+// CHECK-NEXT:    store i32 [[ASMRESULT1]], ptr [[B]], align 4
+// CHECK-NEXT:    store i32 42, ptr [[RET]], align 4
+// CHECK-NEXT:    br label [[Z:%.*]]
+// CHECK:       z:
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[RET]], align 4
+// CHECK-NEXT:    ret i32 [[TMP1]]
+// CHECK:       z.split:
+// CHECK-NEXT:    [[ASMRESULT2:%.*]] = extractvalue { i32, i32 } [[TMP0]], 0
+// CHECK-NEXT:    [[ASMRESULT3:%.*]] = extractvalue { i32, i32 } [[TMP0]], 1
+// CHECK-NEXT:    store i32 [[ASMRESULT2]], ptr [[RET]], align 4
+// CHECK-NEXT:    store i32 [[ASMRESULT3]], ptr [[B]], align 4
+// CHECK-NEXT:    br label [[Z]]
+//
+int test1 (void) {
+  int ret, b;
+  asm goto ("" : "=r"(ret), "=r"(b):::z);
+  ret = 42;
+z:
+  return ret;
+}
+
+// CHECK-LABEL: @test2(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[RET:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = callbr { i32, i32 } asm "", "=r,=r,!i,~{dirflag},~{fpsr},~{flags}"() #[[ATTR1]]
+// CHECK-NEXT:    to label [[ASM_FALLTHROUGH:%.*]] [label %z.split], !srcloc !4
+// CHECK:       asm.fallthrough:
+// CHECK-NEXT:    [[ASMRESULT:%.*]] = extractvalue { i32, i32 } [[TMP0]], 0
+// CHECK-NEXT:    [[ASMRESULT1:%.*]] = extractvalue { i32, i32 } [[TMP0]], 1
+// CHECK-NEXT:    store i32 [[ASMRESULT]], ptr [[RET]], align 4
+// CHECK-NEXT:    store i32 [[ASMRESULT1]], ptr [[B]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = callbr { i32, i32 } asm "", "=r,=r,!i,~{dirflag},~{fpsr},~{flags}"() #[[ATTR1]]
+// CHECK-NEXT:    to label [[ASM_FALLTHROUGH4:%.*]] [label %z.split9], !srcloc !5
+// CHECK:       asm.fallthrough4:
+// CHECK-NEXT:    [[ASMRESULT5:%.*]] = extractvalue { i32, i32 } [[TMP1]], 0
+// CHECK-NEXT:    [[ASMRESULT6:%.*]] = extractvalue { i32, i32 } [[TMP1]], 1
+// CHECK-NEXT:    store i32 [[ASMRESULT5]], ptr [[RET]], align 4
+// CHECK-NEXT:    store i32 [[ASMRESULT6]], ptr [[B]], align 4
+// CHECK-NEXT:    br label [[Z:%.*]]
+// CHECK:       z:
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[RET]], align 4
+// CHECK-NEXT:    ret i32 [[TMP2]]
+// CHECK:       z.split:
+// CHECK-NEXT:    [[ASMRESULT2:%.*]] = extractvalue { i32, i32 } [[TMP0]], 0
+// CHECK-NEXT:    [[ASMRESULT3:%.*]] = extractvalue { i32, i32 } [[TMP0]], 1
+// CHECK-NEXT:    store i32 [[ASMRESULT2]], ptr [[RET]], align 4
+// CHECK-NEXT:    store i32 [[ASMRESULT3]], ptr [[B]], align 4
+// CHECK-NEXT:    br label [[Z]]
+// CHECK:       z.split9:
+// CHECK-NEXT:    [[ASMRESULT7:%.*]] = extractvalue { i32, i32 } [[TMP1]], 0
+// CHECK-NEXT:    [[ASMRESULT8:%.*]] = extractvalue { i32, i32 } [[TMP1]], 1
+// CHECK-NEXT:    store i32 [[ASMRESULT7]], ptr [[RET]], align 4
+// CHECK-NEXT:    store i32 [[ASMRESULT8]], ptr [[B]], align 4
+// CHECK-NEXT:    br label [[Z]]
+//
+int test2 (void) {
+  int ret, b;
+  asm goto ("" : "=r"(ret), "=r"(b):::z);
+  asm goto ("" : "=r"(ret), "=r"(b):::z);
+z:
+  return ret;
+}
+// CHECK-LABEL: @test3(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[OUT1_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 [[OUT1:%.*]], ptr [[OUT1_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i,!i,~{dirflag},~{fpsr},~{flags}"() #[[ATTR1]]
+// CHECK-NEXT:    to label [[ASM_FALLTHROUGH:%.*]] [label [[LABEL_TRUE_SPLIT:%.*]], label %loop.split], !srcloc !6
+// CHECK:       asm.fallthrough:
+// CHECK-NEXT:    store i32 [[TMP0]], ptr [[OUT1_ADDR]], align 4
+// CHECK-NEXT:    store i32 0, ptr [[RETVAL]], align 4
+// CHECK-NEXT:    br label [[RETURN:%.*]]
+// CHECK:       label_true.split:
+// CHECK-NEXT:    store i32 [[TMP0]], ptr [[OUT1_ADDR]], align 4
+// CHECK-NEXT:    br label [[LABEL_TRUE:%.*]]
+// CHECK:       loop.split:
+// CHECK-NEXT:    store i32 [[TMP0]], ptr [[OUT1_ADDR]], align 4
+// CHECK-NEXT:    br label [[LOOP:%.*]]
+// CHECK:       loop:
+// CHECK-NEXT:    store i32 0, ptr [[RETVAL]], align 4
+// CHECK-NEXT:    br label [[RETURN]]
+// CHECK:       label_true:
+// CHECK-NEXT:    store i32 1, ptr [[RETVAL]], align 4
+// CHECK-NEXT:    br label [[RETURN]]
+// CHECK:       return:
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[RETVAL]], align 4
+// CHECK-NEXT:    ret i32 [[TMP1]]
+//
+int test3 (int out1) {
+  asm goto("" : "=r"(out1)::: label_true, loop);
+  return 0;
+loop:
+  return 0;
+label_true:
+  return 1;
+}
+
+// CHECK-LABEL: @test4(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[X:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    br label [[FOO:%.*]]
+// CHECK:       foo:
+// CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i,~{dirflag},~{fpsr},~{flags}"() #[[ATTR1]]
+// CHECK-NEXT:    to label [[ASM_FALLTHROUGH:%.*]] [label %foo.split], !srcloc !7
+// CHECK:       asm.fallthrough:
+// CHECK-NEXT:    store i32 [[TMP0]], ptr [[X]], align 4
+// CHECK-NEXT:    ret void
+// CHECK:       foo.split:
+// CHECK-NEXT:    store i32 [[TMP0]], ptr [[X]], align 4
+// CHECK-NEXT:    br label [[FOO]]
+//
+void test4 (void) {
+  int x;
+foo:
+  asm goto ("" : "=r"(x):::foo);
+}
Index: clang/test/CodeGen/asm-goto.c
===================================================================
--- clang/test/CodeGen/asm-goto.c
+++ clang/test/CodeGen/asm-goto.c
@@ -22,12 +22,12 @@
 int test2(int cond) {
   // CHECK-LABEL: define{{.*}} i32 @test2(
   // CHECK: callbr i32 asm sideeffect
-  // CHECK: to label %asm.fallthrough [label %label_true, label %loop]
+  // CHECK: to label %asm.fallthrough [label %label_true.split, label %loop.split]
   // CHECK-LABEL: asm.fallthrough:
   asm volatile goto("testl %0, %0; jne %l2;" : "=r"(cond) : "r"(cond) :: label_true, loop);
   asm volatile goto("testl %0, %0; jne %l3;" : "=r"(cond) : "r"(cond) :: label_true, loop);
   // CHECK: callbr i32 asm sideeffect
-  // CHECK: to label %asm.fallthrough1 [label %label_true, label %loop]
+  // CHECK: to label %asm.fallthrough1 [label %label_true.split2, label %loop.split3]
   // CHECK-LABEL: asm.fallthrough1:
   return 0;
 loop:
@@ -39,13 +39,13 @@
 int test3(int out1, int out2) {
   // CHECK-LABEL: define{{.*}} i32 @test3(
   // CHECK: callbr { i32, i32 } asm sideeffect
-  // CHECK: to label %asm.fallthrough [label %label_true, label %loop]
+  // CHECK: to label %asm.fallthrough [label %label_true.split, label %loop.split]
   // CHECK-LABEL: asm.fallthrough:
   asm volatile goto("testl %0, %0; jne %l3;" : "=r"(out1), "=r"(out2) : "r"(out1) :: label_true, loop);
   asm volatile goto("testl %0, %0; jne %l4;" : "=r"(out1), "=r"(out2) : "r"(out1) :: label_true, loop);
   // CHECK: callbr { i32, i32 } asm sideeffect
-  // CHECK: to label %asm.fallthrough2 [label %label_true, label %loop]
-  // CHECK-LABEL: asm.fallthrough2:
+  // CHECK: to label %asm.fallthrough6 [label %label_true.split11, label %loop.split14]
+  // CHECK-LABEL: asm.fallthrough6:
   return 0;
 loop:
   return 0;
@@ -56,15 +56,15 @@
 int test4(int out1, int out2) {
   // CHECK-LABEL: define{{.*}} i32 @test4(
   // CHECK: callbr { i32, i32 } asm sideeffect "jne ${5:l}", "={si},={di},r,0,1,!i,!i
-  // CHECK: to label %asm.fallthrough [label %label_true, label %loop]
+  // CHECK: to label %asm.fallthrough [label %label_true.split, label %loop.split]
   // CHECK-LABEL: asm.fallthrough:
   if (out1 < out2)
     asm volatile goto("jne %l5" : "+S"(out1), "+D"(out2) : "r"(out1) :: label_true, loop);
   else
     asm volatile goto("jne %l7" : "+S"(out1), "+D"(out2) : "r"(out1), "r"(out2) :: label_true, loop);
   // CHECK: callbr { i32, i32 } asm sideeffect "jne ${7:l}", "={si},={di},r,r,0,1,!i,!i
-  // CHECK: to label %asm.fallthrough2 [label %label_true, label %loop]
-  // CHECK-LABEL: asm.fallthrough2:
+  // CHECK: to label %asm.fallthrough6 [label %label_true.split11, label %loop.split14]
+  // CHECK-LABEL: asm.fallthrough6:
   return out1 + out2;
 loop:
   return -1;
@@ -75,7 +75,7 @@
 int test5(int addr, int size, int limit) {
   // CHECK-LABEL: define{{.*}} i32 @test5(
   // CHECK: callbr i32 asm "add $1,$0 ; jc ${4:l} ; cmp $2,$0 ; ja ${4:l} ; ", "=r,imr,imr,0,!i
-  // CHECK: to label %asm.fallthrough [label %t_err]
+  // CHECK: to label %asm.fallthrough [label %t_err.split]
   // CHECK-LABEL: asm.fallthrough:
   asm goto(
       "add %1,%0 ; "
@@ -93,7 +93,7 @@
 int test6(int out1) {
   // CHECK-LABEL: define{{.*}} i32 @test6(
   // CHECK: callbr i32 asm sideeffect "testl $0, $0; testl $1, $1; jne ${3:l}", "={si},r,0,!i,!i,{{.*}}
-  // CHECK: to label %asm.fallthrough [label %label_true, label %landing]
+  // CHECK: to label %asm.fallthrough [label %label_true.split, label %landing.split]
   // CHECK-LABEL: asm.fallthrough:
   // CHECK-LABEL: landing:
   int out2 = 42;
@@ -111,7 +111,7 @@
 void *test7(void) {
   // CHECK-LABEL: define{{.*}} ptr @test7(
   // CHECK: %1 = callbr ptr asm "# $0\0A\09# ${2:l}", "=r,0,!i,~{dirflag},~{fpsr},~{flags}"(ptr %0)
-  // CHECK-NEXT: to label %asm.fallthrough [label %foo]
+  // CHECK-NEXT: to label %asm.fallthrough [label %foo.split]
   void *p = &&foo;
   asm goto ("# %0\n\t# %l2":"+r"(p):::foo);
 foo:
@@ -123,7 +123,7 @@
 void *test8(void) {
   // CHECK-LABEL: define{{.*}} ptr @test8(
   // CHECK: %1 = callbr ptr asm "# $0\0A\09# ${2:l}", "=r,0,!i,~{dirflag},~{fpsr},~{flags}"(ptr %0)
-  // CHECK-NEXT: to label %asm.fallthrough [label %foo]
+  // CHECK-NEXT: to label %asm.fallthrough [label %foo.split]
   void *p = &&foo;
   asm goto ("# %0\n\t# %l[foo]":"+r"(p):::foo);
 foo:
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -24,6 +24,7 @@
 #include "clang/Basic/PrettyStackTrace.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/IR/Assumptions.h"
@@ -2325,6 +2326,84 @@
   }
 }
 
+static void EmitAsmStores(
+    CodeGenFunction &CGF,
+    const AsmStmt &S,
+    const llvm::ArrayRef<llvm::Value *> RegResults,
+    const llvm::ArrayRef<llvm::Type *> ResultRegTypes,
+    const llvm::ArrayRef<llvm::Type *> ResultTruncRegTypes,
+    const llvm::ArrayRef<LValue> ResultRegDests,
+    const llvm::ArrayRef<QualType> ResultRegQualTys,
+    const llvm::BitVector &ResultTypeRequiresCast,
+    const llvm::BitVector &ResultRegIsFlagReg) {
+  CGBuilderTy &Builder = CGF.Builder;
+  CodeGenModule &CGM = CGF.CGM;
+  llvm::LLVMContext &CTX = CGF.getLLVMContext();
+
+  for (unsigned i = 0, e = RegResults.size(); i != e; ++i) {
+    llvm::Value *Tmp = RegResults[i];
+    llvm::Type *TruncTy = ResultTruncRegTypes[i];
+
+    if ((i < ResultRegIsFlagReg.size()) && ResultRegIsFlagReg[i]) {
+      // Target must guarantee the Value `Tmp` here is lowered to a boolean
+      // value.
+      llvm::Constant *Two = llvm::ConstantInt::get(Tmp->getType(), 2);
+      llvm::Value *IsBooleanValue =
+          Builder.CreateCmp(llvm::CmpInst::ICMP_ULT, Tmp, Two);
+      llvm::Function *FnAssume = CGM.getIntrinsic(llvm::Intrinsic::assume);
+      Builder.CreateCall(FnAssume, IsBooleanValue);
+    }
+
+    // If the result type of the LLVM IR asm doesn't match the result type of
+    // the expression, do the conversion.
+    if (ResultRegTypes[i] != ResultTruncRegTypes[i]) {
+
+      // 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 (TruncTy->isIntegerTy()) {
+        Tmp = Builder.CreateZExtOrTrunc(Tmp, TruncTy);
+      } else if (TruncTy->isVectorTy()) {
+        Tmp = Builder.CreateBitCast(Tmp, TruncTy);
+      }
+    }
+
+    LValue Dest = ResultRegDests[i];
+    // ResultTypeRequiresCast elements correspond to the first
+    // ResultTypeRequiresCast.size() elements of RegResults.
+    if ((i < ResultTypeRequiresCast.size()) && ResultTypeRequiresCast[i]) {
+      unsigned Size = CGF.getContext().getTypeSize(ResultRegQualTys[i]);
+      Address A = Builder.CreateElementBitCast(Dest.getAddress(CGF),
+                                               ResultRegTypes[i]);
+      if (CGF.getTargetHooks().isScalarizableAsmOperand(CGF, TruncTy)) {
+        Builder.CreateStore(Tmp, A);
+        continue;
+      }
+
+      QualType Ty = CGF.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;
+      }
+      Dest = CGF.MakeAddrLValue(A, Ty);
+    }
+    CGF.EmitStoreThroughLValue(RValue::get(Tmp), Dest);
+  }
+}
+
 void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
   // Pop all cleanup blocks at the end of the asm statement.
   CodeGenFunction::RunCleanupsScope Cleanups(*this);
@@ -2625,7 +2704,7 @@
   SmallVector<llvm::BasicBlock *, 16> Transfer;
   llvm::BasicBlock *Fallthrough = nullptr;
   bool IsGCCAsmGoto = false;
-  if (const auto *GS =  dyn_cast<GCCAsmStmt>(&S)) {
+  if (const auto *GS = dyn_cast<GCCAsmStmt>(&S)) {
     IsGCCAsmGoto = GS->isAsmGoto();
     if (IsGCCAsmGoto) {
       for (const auto *E : GS->labels()) {
@@ -2719,24 +2798,51 @@
       FTy, AsmString, Constraints, HasSideEffect,
       /* IsAlignStack */ false, AsmDialect, HasUnwindClobber);
   std::vector<llvm::Value*> RegResults;
+  llvm::CallBrInst *CBR;
+  // A 2D vector, indexed by indirect destination, then ResultReg.
+  std::vector<std::vector<llvm::Value*>> CBRRegResults;
   if (IsGCCAsmGoto) {
-    llvm::CallBrInst *Result =
-        Builder.CreateCallBr(IA, Fallthrough, Transfer, Args);
+    CBR = Builder.CreateCallBr(IA, Fallthrough, Transfer, Args);
     EmitBlock(Fallthrough);
-    UpdateAsmCallInst(cast<llvm::CallBase>(*Result), HasSideEffect, false,
-                      ReadOnly, ReadNone, InNoMergeAttributedStmt, S,
-                      ResultRegTypes, ArgElemTypes, *this, RegResults);
+    UpdateAsmCallInst(*CBR, HasSideEffect, false, ReadOnly, ReadNone,
+                      InNoMergeAttributedStmt, S, ResultRegTypes, ArgElemTypes,
+                      *this, 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.size()) {
+      CBRRegResults.resize(CBR->getNumIndirectDests());
+      for (unsigned i = 0, e = CBR->getNumIndirectDests(); i != e; ++i) {
+        CBRRegResults[i].resize(ResultRegTypes.size());
+        llvm::BasicBlock *Dest = CBR->getIndirectDest(i);
+        llvm::Twine SynthName = Dest->getName() + ".split";
+        llvm::BasicBlock *SynthBB = createBasicBlock(SynthName);
+        llvm::IRBuilderBase::InsertPointGuard IPG(Builder);
+        Builder.SetInsertPoint(SynthBB);
+
+        if (ResultRegTypes.size() == 1) {
+          CBRRegResults[i][0] = CBR;
+        } else {
+          for (unsigned j = 0, e = ResultRegTypes.size(); j != e; ++j) {
+            llvm::Value *Tmp = Builder.CreateExtractValue(CBR, j, "asmresult");
+            CBRRegResults[i][j] = Tmp;
+          }
+        }
+        EmitBranch(Dest);
+        EmitBlock(SynthBB);
+        CBR->setIndirectDest(i, SynthBB);
+      }
+    }
   } else if (HasUnwindClobber) {
     llvm::CallBase *Result = EmitCallOrInvoke(IA, Args, "");
     UpdateAsmCallInst(*Result, HasSideEffect, true, ReadOnly, ReadNone,
                       InNoMergeAttributedStmt, S, ResultRegTypes, ArgElemTypes,
                       *this, RegResults);
   } else {
-    llvm::CallInst *Result =
-        Builder.CreateCall(IA, Args, getBundlesForFunclet(IA));
-    UpdateAsmCallInst(cast<llvm::CallBase>(*Result), HasSideEffect, false,
-                      ReadOnly, ReadNone, InNoMergeAttributedStmt, S,
-                      ResultRegTypes, ArgElemTypes, *this, RegResults);
+    llvm::CallInst *Result = Builder.CreateCall(IA, Args, getBundlesForFunclet(IA));
+    UpdateAsmCallInst(*Result, HasSideEffect, false, ReadOnly, ReadNone,
+                      InNoMergeAttributedStmt, S, ResultRegTypes, ArgElemTypes,
+                      *this, RegResults);
   }
 
   assert(RegResults.size() == ResultRegTypes.size());
@@ -2746,67 +2852,26 @@
   // in which case its size may grow.
   assert(ResultTypeRequiresCast.size() <= ResultRegDests.size());
   assert(ResultRegIsFlagReg.size() <= ResultRegDests.size());
-  for (unsigned i = 0, e = RegResults.size(); i != e; ++i) {
-    llvm::Value *Tmp = RegResults[i];
-    llvm::Type *TruncTy = ResultTruncRegTypes[i];
-
-    if ((i < ResultRegIsFlagReg.size()) && ResultRegIsFlagReg[i]) {
-      // Target must guarantee the Value `Tmp` here is lowered to a boolean
-      // value.
-      llvm::Constant *Two = llvm::ConstantInt::get(Tmp->getType(), 2);
-      llvm::Value *IsBooleanValue =
-          Builder.CreateCmp(llvm::CmpInst::ICMP_ULT, Tmp, Two);
-      llvm::Function *FnAssume = CGM.getIntrinsic(llvm::Intrinsic::assume);
-      Builder.CreateCall(FnAssume, IsBooleanValue);
-    }
-
-    // If the result type of the LLVM IR asm doesn't match the result type of
-    // the expression, do the conversion.
-    if (ResultRegTypes[i] != ResultTruncRegTypes[i]) {
-
-      // 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(getLLVMContext(), (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(getLLVMContext(), (unsigned)TmpSize));
-        Tmp = Builder.CreateTrunc(Tmp, TruncTy);
-      } else if (TruncTy->isIntegerTy()) {
-        Tmp = Builder.CreateZExtOrTrunc(Tmp, TruncTy);
-      } else if (TruncTy->isVectorTy()) {
-        Tmp = Builder.CreateBitCast(Tmp, TruncTy);
-      }
-    }
 
-    LValue Dest = ResultRegDests[i];
-    // 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 = Builder.CreateElementBitCast(Dest.getAddress(*this),
-                                               ResultRegTypes[i]);
-      if (getTargetHooks().isScalarizableAsmOperand(*this, TruncTy)) {
-        Builder.CreateStore(Tmp, A);
+  EmitAsmStores(*this, S, RegResults, ResultRegTypes, ResultTruncRegTypes,
+      ResultRegDests, ResultRegQualTys, ResultTypeRequiresCast,
+      ResultRegIsFlagReg);
+
+  if (IsGCCAsmGoto && CBRRegResults.size()) {
+    for (unsigned i = 0, e = CBR->getNumIndirectDests(); i != e; ++i) {
+      assert(CBRRegResults[i].size() == ResultRegTypes.size());
+      // If we happen to share the same indirect and default dest, don't re-add
+      // stores. That was done for the default destination in the above call to
+      // EmitAsmStores.
+      llvm::BasicBlock *Succ = CBR->getIndirectDest(i);
+      if (Succ == CBR->getDefaultDest())
         continue;
-      }
-
-      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;
-      }
-      Dest = MakeAddrLValue(A, Ty);
+      llvm::IRBuilderBase::InsertPointGuard IPG(Builder);
+      Builder.SetInsertPoint(Succ, --(Succ->end()));
+      EmitAsmStores(*this, S, CBRRegResults[i], ResultRegTypes, ResultTruncRegTypes,
+          ResultRegDests, ResultRegQualTys, ResultTypeRequiresCast,
+          ResultRegIsFlagReg);
     }
-    EmitStoreThroughLValue(RValue::get(Tmp), Dest);
   }
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to