diff --git a/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp b/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp --- a/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp +++ b/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/PatternMatch.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" @@ -81,6 +82,20 @@ return true; } + // Convert (zext (abs(i32 X, i1 1))) -> (sext (abs(i32 X, i1 1))). If abs of + // INT_MIN is poison, the sign bit is zero. + using namespace PatternMatch; + if (match(Src, m_Intrinsic(m_Value(), m_One()))) { + auto *SExt = new SExtInst(Src, ZExt->getType(), "", ZExt); + SExt->takeName(ZExt); + SExt->setDebugLoc(ZExt->getDebugLoc()); + + ZExt->replaceAllUsesWith(SExt); + ZExt->eraseFromParent(); + ++NumZExtToSExt; + return true; + } + return false; } diff --git a/llvm/test/CodeGen/RISCV/iabs.ll b/llvm/test/CodeGen/RISCV/iabs.ll --- a/llvm/test/CodeGen/RISCV/iabs.ll +++ b/llvm/test/CodeGen/RISCV/iabs.ll @@ -694,3 +694,51 @@ ret i128 %3 } +define i64 @zext_abs32(i32 %x) { +; RV32I-LABEL: zext_abs32: +; RV32I: # %bb.0: +; RV32I-NEXT: srai a1, a0, 31 +; RV32I-NEXT: xor a0, a0, a1 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: li a1, 0 +; RV32I-NEXT: ret +; +; RV32ZBB-LABEL: zext_abs32: +; RV32ZBB: # %bb.0: +; RV32ZBB-NEXT: neg a1, a0 +; RV32ZBB-NEXT: max a0, a0, a1 +; RV32ZBB-NEXT: li a1, 0 +; RV32ZBB-NEXT: ret +; +; RV32ZBT-LABEL: zext_abs32: +; RV32ZBT: # %bb.0: +; RV32ZBT-NEXT: srai a1, a0, 31 +; RV32ZBT-NEXT: xor a0, a0, a1 +; RV32ZBT-NEXT: sub a0, a0, a1 +; RV32ZBT-NEXT: li a1, 0 +; RV32ZBT-NEXT: ret +; +; RV64I-LABEL: zext_abs32: +; RV64I: # %bb.0: +; RV64I-NEXT: sraiw a1, a0, 31 +; RV64I-NEXT: xor a0, a0, a1 +; RV64I-NEXT: subw a0, a0, a1 +; RV64I-NEXT: ret +; +; RV64ZBB-LABEL: zext_abs32: +; RV64ZBB: # %bb.0: +; RV64ZBB-NEXT: sext.w a0, a0 +; RV64ZBB-NEXT: negw a1, a0 +; RV64ZBB-NEXT: max a0, a0, a1 +; RV64ZBB-NEXT: ret +; +; RV64ZBT-LABEL: zext_abs32: +; RV64ZBT: # %bb.0: +; RV64ZBT-NEXT: sraiw a1, a0, 31 +; RV64ZBT-NEXT: xor a0, a0, a1 +; RV64ZBT-NEXT: subw a0, a0, a1 +; RV64ZBT-NEXT: ret + %abs = tail call i32 @llvm.abs.i32(i32 %x, i1 true) + %zext = zext i32 %abs to i64 + ret i64 %zext +}