forked from OSchip/llvm-project
[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 e5c37958f9
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
This commit is contained in:
parent
9921ef73c8
commit
92c1bc6158
|
@ -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]) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue