#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"
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<Intrinsic::abs>(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;
}
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
+}