aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuanfang Chen <yuanfang.chen@sony.com>2022-07-29 14:50:40 -0700
committerTom Stellard <tstellar@redhat.com>2022-08-02 21:51:17 -0700
commit1accfde99a8aac9e7306290575f40c57e525f41b (patch)
treef748685fc0fce88521c37df3b2d4645c90098bf4
parent509569419abd7df44fcaab959d48b574045dc81e (diff)
[CodeGen][inlineasm] assume the flag output of inline asm is boolean value
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 Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D129954 (cherry picked from commit 92c1bc61586c9d6c7bf0c36b1005fe00b4f48cc0)
-rw-r--r--clang/lib/CodeGen/CGStmt.cpp15
-rw-r--r--clang/test/CodeGen/inline-asm-x86-flag-output.c19
2 files changed, 34 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 05ab16668743..481438de0e53 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -2343,6 +2343,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
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 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
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 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// 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
index 4c7e750e6d93..732714388c19 100644
--- a/clang/test/CodeGen/inline-asm-x86-flag-output.c
+++ b/clang/test/CodeGen/inline-asm-x86-flag-output.c
@@ -374,3 +374,22 @@ _Bool check_no_clobber_conflicts(void) {
: "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;
+}