[PATCH] D129954: [CodeGen][inlineasm] assume the flag output of inline asm is boolean value

2022-08-02 Thread Yuanfang Chen via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
ychen marked an inline comment as done.
Closed by commit rG92c1bc61586c: [CodeGen][inlineasm] assume the flag output of 
inline asm is boolean value (authored by ychen).

Repository:
  rG LLVM Github Monorepo

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

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,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;
+}
Index: clang/lib/CodeGen/CGStmt.cpp
===
--- clang/lib/CodeGen/CGStmt.cpp
+++ 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]) {


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,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;
+}
Index: clang/lib/CodeGen/CGStmt.cpp
===
--- clang/lib/CodeGen/CGStmt.cpp
+++ 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");
+  

[PATCH] D129954: [CodeGen][inlineasm] assume the flag output of inline asm is boolean value

2022-08-01 Thread Nick Desaulniers via Phabricator via cfe-commits
nickdesaulniers accepted this revision.
nickdesaulniers added a comment.

Thanks for the patch!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D129954

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D129954: [CodeGen][inlineasm] assume the flag output of inline asm is boolean value

2022-07-29 Thread Yuanfang Chen via Phabricator via cfe-commits
ychen marked 2 inline comments as done.
ychen added a comment.

In D129954#3686780 , @nikic wrote:

> LGTM. After some further consideration, implementing this properly in LLVM 
> would probably take more effort than is worthwhile (especially as this is 
> target-specific functionality, so we'd actually have to expose TTI queries 
> for this, etc.)

Agreed. Thanks for the review.




Comment at: clang/test/CodeGen/inline-asm-x86-flag-output.c:378
+
+int test_assume_boolean_flag(long nr, volatile long *addr) {
+  //CHECK-LABEL: @test_assume_boolean_flag

nikic wrote:
> You might want to check that we're doing the right thing if there are 
> multiple output constraints (via extractvalue).
That's a good idea. Done.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D129954

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D129954: [CodeGen][inlineasm] assume the flag output of inline asm is boolean value

2022-07-29 Thread Yuanfang Chen via Phabricator via cfe-commits
ychen updated this revision to Diff 448733.
ychen added a comment.

- update test


Repository:
  rG LLVM Github Monorepo

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

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,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;
+}
Index: clang/lib/CodeGen/CGStmt.cpp
===
--- clang/lib/CodeGen/CGStmt.cpp
+++ 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]) {


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,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;
+}
Index: clang/lib/CodeGen/CGStmt.cpp
===
--- clang/lib/CodeGen/CGStmt.cpp
+++ 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() &&
   

[PATCH] D129954: [CodeGen][inlineasm] assume the flag output of inline asm is boolean value

2022-07-29 Thread Yuanfang Chen via Phabricator via cfe-commits
ychen updated this revision to Diff 448732.
ychen added a comment.

- use < 2
- check multiple flag outputs


Repository:
  rG LLVM Github Monorepo

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

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,22 @@
   : "cx");
   return b;
 }
+
+int test_assume_boolean_flag(long nr, volatile long *addr) {
+  //CHECK-LABEL: @test_assume_boolean_flag
+  //CHECK: = 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;
+}
Index: clang/lib/CodeGen/CGStmt.cpp
===
--- clang/lib/CodeGen/CGStmt.cpp
+++ 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]) {


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,22 @@
   : "cx");
   return b;
 }
+
+int test_assume_boolean_flag(long nr, volatile long *addr) {
+  //CHECK-LABEL: @test_assume_boolean_flag
+  //CHECK: = 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;
+}
Index: clang/lib/CodeGen/CGStmt.cpp
===
--- clang/lib/CodeGen/CGStmt.cpp
+++ 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() &&
   

[PATCH] D129954: [CodeGen][inlineasm] assume the flag output of inline asm is boolean value

2022-07-29 Thread Nikita Popov via Phabricator via cfe-commits
nikic accepted this revision.
nikic added a comment.
This revision is now accepted and ready to land.

LGTM. After some further consideration, implementing this properly in LLVM 
would probably take more effort than is worthwhile (especially as this is 
target-specific functionality, so we'd actually have to expose TTI queries for 
this, etc.)




Comment at: clang/lib/CodeGen/CGStmt.cpp:2734
+  llvm::Value *IsBooleanValue =
+  Builder.CreateCmp(llvm::CmpInst::ICMP_ULE, Tmp, OneVal);
+  llvm::Function *FnAssume = CGM.getIntrinsic(llvm::Intrinsic::assume);

The canonical form of this is `< 2` rather than `<= 1`.



Comment at: clang/test/CodeGen/inline-asm-x86-flag-output.c:378
+
+int test_assume_boolean_flag(long nr, volatile long *addr) {
+  //CHECK-LABEL: @test_assume_boolean_flag

You might want to check that we're doing the right thing if there are multiple 
output constraints (via extractvalue).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D129954

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D129954: [CodeGen][inlineasm] assume the flag output of inline asm is boolean value

2022-07-17 Thread Yuanfang Chen via Phabricator via cfe-commits
ychen added a comment.

In D129954#3658139 , @nikic wrote:

> Hm, might it be better to teach LLVM about this (in some 
> ConstantRange/KnownBits logic)? This doesn't really seem like something the 
> frontend should know about and encode, as that means each frontend has to add 
> this annotation by itself.

Agreed that teaching LLVM about his saves other frontends from doing the same 
thing. The information is inline asm semantic defined by GCC extension though, 
I think putting it in the frontend is a valid choice and makes the 
implementation easy.

I looked into where to put this in LLVM. It seems nontrivial: existing 
ConstantRanges are computed from binary-op/comparsion etc. Inferring range from 
an inline asm call is something passes (LazyValueInfo) need to learn, with some 
kinds of def-use chain walking. That said, I'm definitely new to ConstantRange 
analysis, it may well be that this is not that hard to implement. Could you 
please give some guidance?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D129954

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D129954: [CodeGen][inlineasm] assume the flag output of inline asm is boolean value

2022-07-17 Thread Nikita Popov via Phabricator via cfe-commits
nikic added a comment.

Hm, might it be better to teach LLVM about this (in some 
ConstantRange/KnownBits logic)? This doesn't really seem like something the 
frontend should know about and encode, as that means each frontend has to add 
this annotation by itself.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D129954

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D129954: [CodeGen][inlineasm] assume the flag output of inline asm is boolean value

2022-07-16 Thread Yuanfang Chen via Phabricator via cfe-commits
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 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 *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 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");
+