ychen created this revision. ychen added reviewers: nikic, efriedma, lebedev.ri. Herald added subscribers: jsji, pengfei, kristof.beyls. Herald added a project: All. ychen requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
GCC inline asm document says that "... the general rule is that the output variable must be a scalar integer, and the value is boolean." Commit e5c37958f901cc9bec50624dbee85d40143e4bca lowers flag output of inline asm on X86 with setcc, hence it is guaranteed that the flag is of boolean value. Clang does not support ARM inline asm flag output yet so nothing need to be worried about ARM. See "Flag Output" section at https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#OutputOperands Fixes https://github.com/llvm/llvm-project/issues/56568 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D129954 Files: clang/lib/CodeGen/CGStmt.cpp clang/test/CodeGen/inline-asm-x86-flag-output.c Index: clang/test/CodeGen/inline-asm-x86-flag-output.c =================================================================== --- clang/test/CodeGen/inline-asm-x86-flag-output.c +++ clang/test/CodeGen/inline-asm-x86-flag-output.c @@ -374,3 +374,18 @@ : "cx"); return b; } + +int test_assume_boolean_flag(long nr, volatile long *addr) { + //CHECK-LABEL: @test_assume_boolean_flag + //CHECK: = tail call i32 asm "cmp $2,$1", "={@cca},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* elementtype(i64) %addr, i64 %nr) + //CHECK: %1 = icmp ult i32 %0, 2 + //CHECK: call void @llvm.assume(i1 %1) + int x; + asm("cmp %2,%1" + : "=@cca"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} Index: clang/lib/CodeGen/CGStmt.cpp =================================================================== --- clang/lib/CodeGen/CGStmt.cpp +++ clang/lib/CodeGen/CGStmt.cpp @@ -2343,6 +2343,7 @@ std::vector<llvm::Type *> ArgElemTypes; std::vector<llvm::Value*> 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 *OneVal = llvm::ConstantInt::get(Tmp->getType(), 1); + llvm::Value *IsBooleanValue = + Builder.CreateCmp(llvm::CmpInst::ICMP_ULE, Tmp, OneVal); + 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]) {
Index: clang/test/CodeGen/inline-asm-x86-flag-output.c =================================================================== --- clang/test/CodeGen/inline-asm-x86-flag-output.c +++ clang/test/CodeGen/inline-asm-x86-flag-output.c @@ -374,3 +374,18 @@ : "cx"); return b; } + +int test_assume_boolean_flag(long nr, volatile long *addr) { + //CHECK-LABEL: @test_assume_boolean_flag + //CHECK: = tail call i32 asm "cmp $2,$1", "={@cca},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* elementtype(i64) %addr, i64 %nr) + //CHECK: %1 = icmp ult i32 %0, 2 + //CHECK: call void @llvm.assume(i1 %1) + int x; + asm("cmp %2,%1" + : "=@cca"(x), "=m"(*(volatile long *)(addr)) + : "r"(nr) + : "cc"); + if (x) + return 0; + return 1; +} Index: clang/lib/CodeGen/CGStmt.cpp =================================================================== --- clang/lib/CodeGen/CGStmt.cpp +++ clang/lib/CodeGen/CGStmt.cpp @@ -2343,6 +2343,7 @@ std::vector<llvm::Type *> ArgElemTypes; std::vector<llvm::Value*> 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 *OneVal = llvm::ConstantInt::get(Tmp->getType(), 1); + llvm::Value *IsBooleanValue = + Builder.CreateCmp(llvm::CmpInst::ICMP_ULE, Tmp, OneVal); + 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]) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits