diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2343,6 +2343,7 @@ std::vector ArgElemTypes; std::vector Args; llvm::BitVector ResultTypeRequiresCast; + llvm::BitVector ResultRegIsFlagReg; // Keep track of inout constraints. std::string InOutConstraints; @@ -2400,6 +2401,9 @@ ResultRegQualTys.push_back(QTy); ResultRegDests.push_back(Dest); + bool IsFlagReg = llvm::StringRef(OutputConstraint).startswith("{@cc"); + ResultRegIsFlagReg.push_back(IsFlagReg); + llvm::Type *Ty = ConvertTypeForMem(QTy); const bool RequiresCast = Info.allowsRegister() && (getTargetHooks().isScalarizableAsmOperand(*this, Ty) || @@ -2717,10 +2721,21 @@ // ResultRegDests can be also populated by addReturnRegisterOutputs() above, // 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]) { diff --git a/clang/test/CodeGen/inline-asm-x86-flag-output.c b/clang/test/CodeGen/inline-asm-x86-flag-output.c --- a/clang/test/CodeGen/inline-asm-x86-flag-output.c +++ b/clang/test/CodeGen/inline-asm-x86-flag-output.c @@ -374,3 +374,22 @@ : "cx"); return b; } + +int test_assume_boolean_flag(long nr, volatile long *addr) { + //CHECK-LABEL: @test_assume_boolean_flag + //CHECK: %0 = tail call { i32, i32 } asm "cmp $2,$1", "={@cca},={@ccae},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* elementtype(i64) %addr, i64 %nr) + //CHECK: [[RES1:%.*]] = extractvalue { i32, i32 } %0, 0 + //CHECK: [[RES2:%.*]] = extractvalue { i32, i32 } %0, 1 + //CHECK: %1 = icmp ult i32 [[RES1]], 2 + //CHECK: tail call void @llvm.assume(i1 %1) + //CHECK: %2 = icmp ult i32 [[RES2]], 2 + //CHECK: tail call void @llvm.assume(i1 %2) + int x,y; + asm("cmp %2,%1" + : "=@cca"(x), "=@ccae"(y), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +}