[clang] [InstCombine] Add combines/simplifications for `llvm.ptrmask` (PR #67166)

via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 9 10:00:58 PDT 2023


https://github.com/goldsteinn updated https://github.com/llvm/llvm-project/pull/67166

>From 687da51565d93d2b03fbfc9c69f1094e91f60f08 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 22 Sep 2023 08:21:21 -0500
Subject: [PATCH 1/8] [InstSimplify] Add tests for simplify `llvm.ptrmask`; NFC

Differential Revision: https://reviews.llvm.org/D156632
---
 llvm/test/Transforms/InstSimplify/ptrmask.ll | 364 +++++++++++++++++++
 1 file changed, 364 insertions(+)
 create mode 100644 llvm/test/Transforms/InstSimplify/ptrmask.ll

diff --git a/llvm/test/Transforms/InstSimplify/ptrmask.ll b/llvm/test/Transforms/InstSimplify/ptrmask.ll
new file mode 100644
index 000000000000000..0942e8b238140bb
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/ptrmask.ll
@@ -0,0 +1,364 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+declare ptr @llvm.ptrmask.p0.i32(ptr, i32)
+declare ptr @llvm.ptrmask.p0.i64(ptr, i64)
+
+declare <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr>, <2 x i32>)
+declare <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr>, <2 x i64>)
+
+define ptr @ptrmask_simplify_poison_mask(ptr %p) {
+; CHECK-LABEL: define ptr @ptrmask_simplify_poison_mask
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 poison)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 poison)
+  ret ptr %r
+}
+
+define <2 x ptr> @ptrmask_simplify_poison_mask_vec(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_poison_mask_vec
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P]], <2 x i32> poison)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p, <2 x i32> poison)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_simplify_poison_and_zero_i32_vec_fail(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_poison_and_zero_i32_vec_fail
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P]], <2 x i32> <i32 undef, i32 0>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p, <2 x i32> <i32 undef, i32 0>)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_simplify_undef_and_ones_vec(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_undef_and_ones_vec
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 undef, i64 -1>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 undef, i64 -1>)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_simplify_poison_and_ones_vec(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_poison_and_ones_vec
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 poison, i64 -1>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 poison, i64 -1>)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_simplify_ones_vec(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_ones_vec
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -1, i64 -1>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -1, i64 -1>)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_simplify_ones_fail_vec(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_ones_fail_vec
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P]], <2 x i32> <i32 -1, i32 -1>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p, <2 x i32> <i32 -1, i32 -1>)
+  ret <2 x ptr> %r
+}
+
+define ptr @ptrmask_simplify_undef_mask(ptr %p) {
+; CHECK-LABEL: define ptr @ptrmask_simplify_undef_mask
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 undef)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 undef)
+  ret ptr %r
+}
+
+define ptr @ptrmask_simplify_0_mask(ptr %p) {
+; CHECK-LABEL: define ptr @ptrmask_simplify_0_mask
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 0)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 0)
+  ret ptr %r
+}
+
+define ptr @ptrmask_simplify_1s_mask(ptr %p) {
+; CHECK-LABEL: define ptr @ptrmask_simplify_1s_mask
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -1)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -1)
+  ret ptr %r
+}
+
+define ptr @ptrmask_simplify_1s_mask_i32_fail(ptr %p) {
+; CHECK-LABEL: define ptr @ptrmask_simplify_1s_mask_i32_fail
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -1)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -1)
+  ret ptr %r
+}
+
+define ptr @ptrmask_simplify_poison_ptr(i64 %m) {
+; CHECK-LABEL: define ptr @ptrmask_simplify_poison_ptr
+; CHECK-SAME: (i64 [[M:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr poison, i64 [[M]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr poison, i64 %m)
+  ret ptr %r
+}
+
+define ptr @ptrmask_simplify_undef_ptr(i32 %m) {
+; CHECK-LABEL: define ptr @ptrmask_simplify_undef_ptr
+; CHECK-SAME: (i32 [[M:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr undef, i32 [[M]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i32(ptr undef, i32 %m)
+  ret ptr %r
+}
+
+define ptr @ptrmask_simplify_null_ptr(i64 %m) {
+; CHECK-LABEL: define ptr @ptrmask_simplify_null_ptr
+; CHECK-SAME: (i64 [[M:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr null, i64 [[M]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr null, i64 %m)
+  ret ptr %r
+}
+
+define ptr @ptrmask_simplify_ptrmask(ptr %p) {
+; CHECK-LABEL: define ptr @ptrmask_simplify_ptrmask
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[M:%.*]] = ptrtoint ptr [[P]] to i64
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 [[M]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %m = ptrtoint ptr %p to i64
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 %m)
+  ret ptr %r
+}
+
+define ptr @ptrmask_simplify_ptrmask_i32_fail(ptr %p) {
+; CHECK-LABEL: define ptr @ptrmask_simplify_ptrmask_i32_fail
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[M:%.*]] = ptrtoint ptr [[P]] to i32
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 [[M]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %m = ptrtoint ptr %p to i32
+  %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 %m)
+  ret ptr %r
+}
+
+define ptr @ptrmask_simplify_aligned_unused(ptr align 64 %p) {
+; CHECK-LABEL: define ptr @ptrmask_simplify_aligned_unused
+; CHECK-SAME: (ptr align 64 [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -64)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -64)
+  ret ptr %r
+}
+
+define <2 x ptr> @ptrmask_simplify_aligned_unused_vec(<2 x ptr> align 128 %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_aligned_unused_vec
+; CHECK-SAME: (<2 x ptr> align 128 [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -64, i64 -64>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -64, i64 -64>)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_simplify_aligned_unused_vec_todo(<2 x ptr> align 128 %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_aligned_unused_vec_todo
+; CHECK-SAME: (<2 x ptr> align 128 [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -64, i64 -128>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -64, i64 -128>)
+  ret <2 x ptr> %r
+}
+
+define ptr @ptrmask_simplify_aligned_unused_i32_fail(ptr align 64 %p) {
+; CHECK-LABEL: define ptr @ptrmask_simplify_aligned_unused_i32_fail
+; CHECK-SAME: (ptr align 64 [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -64)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -64)
+  ret ptr %r
+}
+
+define ptr @ptrmask_simplify_known_unused(ptr %p) {
+; CHECK-LABEL: define ptr @ptrmask_simplify_known_unused
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[PM0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -64)
+; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, ptr [[PM0]], i64 32
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PGEP]], i64 -32)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %pm0 = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -64)
+  %pgep = getelementptr i8, ptr %pm0, i64 32
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %pgep, i64 -32)
+  ret ptr %r
+}
+
+define <2 x ptr> @ptrmask_simplify_known_unused_vec(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_known_unused_vec
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[PM0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -64, i64 -64>)
+; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, <2 x ptr> [[PM0]], <2 x i64> <i64 32, i64 32>
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[PGEP]], <2 x i64> <i64 -32, i64 -32>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %pm0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -64, i64 -64>)
+  %pgep = getelementptr i8, <2 x ptr> %pm0, <2 x i64> <i64 32, i64 32>
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %pgep, <2 x i64> <i64 -32, i64 -32>)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_simplify_known_unused_vec2(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_known_unused_vec2
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[PM0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -64, i64 -64>)
+; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, <2 x ptr> [[PM0]], <2 x i64> <i64 32, i64 32>
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[PGEP]], <2 x i64> <i64 -32, i64 -16>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %pm0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -64, i64 -64>)
+  %pgep = getelementptr i8, <2 x ptr> %pm0, <2 x i64> <i64 32, i64 32>
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %pgep, <2 x i64> <i64 -32, i64 -16>)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_simplify_known_unused_vec3(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_known_unused_vec3
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[PM0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -64, i64 -128>)
+; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, <2 x ptr> [[PM0]], <2 x i64> <i64 32, i64 32>
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[PGEP]], <2 x i64> <i64 -32, i64 -32>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %pm0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -64, i64 -128>)
+  %pgep = getelementptr i8, <2 x ptr> %pm0, <2 x i64> <i64 32, i64 32>
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %pgep, <2 x i64> <i64 -32, i64 -32>)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_simplify_known_unused_vec4(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_known_unused_vec4
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[PM0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -64, i64 -128>)
+; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, <2 x ptr> [[PM0]], <2 x i64> <i64 32, i64 64>
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[PGEP]], <2 x i64> <i64 -32, i64 -32>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %pm0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -64, i64 -128>)
+  %pgep = getelementptr i8, <2 x ptr> %pm0, <2 x i64> <i64 32, i64 64>
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %pgep, <2 x i64> <i64 -32, i64 -32>)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_simplify_known_unused_vec_fail(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_known_unused_vec_fail
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[PM0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -64, i64 -128>)
+; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, <2 x ptr> [[PM0]], <2 x i64> <i64 16, i64 64>
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[PGEP]], <2 x i64> <i64 -32, i64 -32>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %pm0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -64, i64 -128>)
+  %pgep = getelementptr i8, <2 x ptr> %pm0, <2 x i64> <i64 16, i64 64>
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %pgep, <2 x i64> <i64 -32, i64 -32>)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_simplify_known_unused_vec_fail2(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_known_unused_vec_fail2
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[PM0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -64, i64 -64>)
+; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, <2 x ptr> [[PM0]], <2 x i64> <i64 32, i64 32>
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[PGEP]], <2 x i64> <i64 -32, i64 -64>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %pm0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -64, i64 -64>)
+  %pgep = getelementptr i8, <2 x ptr> %pm0, <2 x i64> <i64 32, i64 32>
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %pgep, <2 x i64> <i64 -32, i64 -64>)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_simplify_known_unused_vec_fail3(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_known_unused_vec_fail3
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[PM0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -64, i64 -16>)
+; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, <2 x ptr> [[PM0]], <2 x i64> <i64 32, i64 32>
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[PGEP]], <2 x i64> <i64 -32, i64 -32>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %pm0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -64, i64 -16>)
+  %pgep = getelementptr i8, <2 x ptr> %pm0, <2 x i64> <i64 32, i64 32>
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %pgep, <2 x i64> <i64 -32, i64 -32>)
+  ret <2 x ptr> %r
+}
+
+define ptr @ptrmask_maintain_provenance_i64(ptr %p0) {
+; CHECK-LABEL: define ptr @ptrmask_maintain_provenance_i64
+; CHECK-SAME: (ptr [[P0:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 0)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 0)
+  ret ptr %r
+}
+
+define ptr @ptrmask_maintain_provenance_i32(ptr %p0) {
+; CHECK-LABEL: define ptr @ptrmask_maintain_provenance_i32
+; CHECK-SAME: (ptr [[P0:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 0)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i32(ptr %p0, i32 0)
+  ret ptr %r
+}
+
+define <2 x ptr> @ptrmask_maintain_provenance_v2i64(<2 x ptr> %p0) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_maintain_provenance_v2i64
+; CHECK-SAME: (<2 x ptr> [[P0:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P0]], <2 x i64> zeroinitializer)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p0, <2 x i64> zeroinitializer)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_maintain_provenance_v2i32(<2 x ptr> %p0) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_maintain_provenance_v2i32
+; CHECK-SAME: (<2 x ptr> [[P0:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P0]], <2 x i32> zeroinitializer)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p0, <2 x i32> zeroinitializer)
+  ret <2 x ptr> %r
+}

>From 0aecd5a91c17952ef1bccf3540eebc732588f5d2 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 22 Sep 2023 08:21:27 -0500
Subject: [PATCH 2/8] [InstSimplify] Add some basic simplifications for
 `llvm.ptrmask`

Mostly the same as `and`. We also have a check for a useless
`llvm.ptrmask` if the ptr is already known aligned.

Differential Revision: https://reviews.llvm.org/D156633
---
 llvm/lib/Analysis/InstructionSimplify.cpp     | 35 +++++++++++++
 .../InferAddressSpaces/AMDGPU/ptrmask.ll      |  5 +-
 .../test/Transforms/InstCombine/align-addr.ll |  8 +--
 llvm/test/Transforms/InstSimplify/ptrmask.ll  | 49 ++++++-------------
 4 files changed, 55 insertions(+), 42 deletions(-)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index b3feb2470e58efd..013f64c899c7c8f 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -6411,6 +6411,41 @@ static Value *simplifyBinaryIntrinsic(Function *F, Value *Op0, Value *Op1,
       return Constant::getNullValue(ReturnType);
     break;
   }
+  case Intrinsic::ptrmask: {
+    if (isa<PoisonValue>(Op0) || isa<PoisonValue>(Op1))
+      return PoisonValue::get(Op0->getType());
+
+    // NOTE: We can't apply this simplifications based on the value of Op1
+    // because we need to preserve provenance.
+    if (Q.isUndefValue(Op0) || match(Op0, m_Zero()))
+      return Constant::getNullValue(Op0->getType());
+
+    if (Op1->getType()->getScalarSizeInBits() ==
+        Q.DL.getPointerTypeSizeInBits(Op0->getType())) {
+      if (match(Op1, m_PtrToInt(m_Specific(Op0))))
+        return Op0;
+
+      // NOTE: We may have attributes associated with the return value of the
+      // llvm.ptrmask intrinsic that will be lost when we just return the
+      // operand. We should try to preserve them.
+      if (match(Op1, m_AllOnes()) || Q.isUndefValue(Op1))
+        return Op0;
+
+      Constant *C;
+      if (match(Op1, m_ImmConstant(C))) {
+        KnownBits PtrKnown =
+            computeKnownBits(Op0, Q.DL, /*Depth=*/0, Q.AC, Q.CxtI, Q.DT);
+        // See if we only masking off bits we know are already zero due to
+        // alignment.
+        C = ConstantFoldBinaryOpOperands(
+            Instruction::Or, C, ConstantInt::get(C->getType(), PtrKnown.Zero),
+            Q.DL);
+        if (C != nullptr && C->isAllOnesValue())
+          return Op0;
+      }
+    }
+    break;
+  }
   case Intrinsic::smax:
   case Intrinsic::smin:
   case Intrinsic::umax:
diff --git a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/ptrmask.ll b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/ptrmask.ll
index c9db0656c6b7dd4..561a5ff35ba1082 100644
--- a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/ptrmask.ll
+++ b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/ptrmask.ll
@@ -320,8 +320,7 @@ define i8 @ptrmask_cast_local_to_flat_const_mask_fffffffffffffffe(ptr addrspace(
 
 define i8 @ptrmask_cast_local_to_flat_const_mask_ffffffffffffffff(ptr addrspace(3) %src.ptr) {
 ; CHECK-LABEL: @ptrmask_cast_local_to_flat_const_mask_ffffffffffffffff(
-; CHECK-NEXT:    [[TMP1:%.*]] = call ptr addrspace(3) @llvm.ptrmask.p3.i32(ptr addrspace(3) [[SRC_PTR:%.*]], i32 -1)
-; CHECK-NEXT:    [[LOAD:%.*]] = load i8, ptr addrspace(3) [[TMP1]], align 1
+; CHECK-NEXT:    [[LOAD:%.*]] = load i8, ptr addrspace(3) [[SRC_PTR:%.*]], align 1
 ; CHECK-NEXT:    ret i8 [[LOAD]]
 ;
   %cast = addrspacecast ptr addrspace(3) %src.ptr to ptr
@@ -333,7 +332,7 @@ define i8 @ptrmask_cast_local_to_flat_const_mask_ffffffffffffffff(ptr addrspace(
 ; Make sure non-constant masks can also be handled.
 define i8 @ptrmask_cast_local_to_flat_load_range_mask(ptr addrspace(3) %src.ptr, ptr addrspace(1) %mask.ptr) {
 ; CHECK-LABEL: @ptrmask_cast_local_to_flat_load_range_mask(
-; CHECK-NEXT:    [[LOAD_MASK:%.*]] = load i64, ptr addrspace(1) [[MASK_PTR:%.*]], align 8, !range !0
+; CHECK-NEXT:    [[LOAD_MASK:%.*]] = load i64, ptr addrspace(1) [[MASK_PTR:%.*]], align 8, !range [[RNG0:![0-9]+]]
 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[LOAD_MASK]] to i32
 ; CHECK-NEXT:    [[TMP2:%.*]] = call ptr addrspace(3) @llvm.ptrmask.p3.i32(ptr addrspace(3) [[SRC_PTR:%.*]], i32 [[TMP1]])
 ; CHECK-NEXT:    [[LOAD:%.*]] = load i8, ptr addrspace(3) [[TMP2]], align 1
diff --git a/llvm/test/Transforms/InstCombine/align-addr.ll b/llvm/test/Transforms/InstCombine/align-addr.ll
index b944dfef6ec71cb..a1d19df4c5e0607 100644
--- a/llvm/test/Transforms/InstCombine/align-addr.ll
+++ b/llvm/test/Transforms/InstCombine/align-addr.ll
@@ -183,11 +183,9 @@ define <16 x i8> @ptrmask_align8_ptr_align1(ptr align 1 %ptr) {
 }
 
 ; Underlying alignment already the same as forced alignment by ptrmask
-; TODO: Should be able to drop the ptrmask
 define <16 x i8> @ptrmask_align8_ptr_align8(ptr align 8 %ptr) {
 ; CHECK-LABEL: @ptrmask_align8_ptr_align8(
-; CHECK-NEXT:    [[ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR:%.*]], i64 -8)
-; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 1
+; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[PTR:%.*]], align 1
 ; CHECK-NEXT:    ret <16 x i8> [[LOAD]]
 ;
   %aligned = call ptr @llvm.ptrmask.p0.i64(ptr %ptr, i64 -8)
@@ -196,11 +194,9 @@ define <16 x i8> @ptrmask_align8_ptr_align8(ptr align 8 %ptr) {
 }
 
 ; Underlying alignment greater than alignment forced by ptrmask
-; TODO: Should be able to drop the ptrmask
 define <16 x i8> @ptrmask_align8_ptr_align16(ptr align 16 %ptr) {
 ; CHECK-LABEL: @ptrmask_align8_ptr_align16(
-; CHECK-NEXT:    [[ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR:%.*]], i64 -8)
-; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 1
+; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[PTR:%.*]], align 1
 ; CHECK-NEXT:    ret <16 x i8> [[LOAD]]
 ;
   %aligned = call ptr @llvm.ptrmask.p0.i64(ptr %ptr, i64 -8)
diff --git a/llvm/test/Transforms/InstSimplify/ptrmask.ll b/llvm/test/Transforms/InstSimplify/ptrmask.ll
index 0942e8b238140bb..297cd0825ae6336 100644
--- a/llvm/test/Transforms/InstSimplify/ptrmask.ll
+++ b/llvm/test/Transforms/InstSimplify/ptrmask.ll
@@ -10,8 +10,7 @@ declare <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr>, <2 x i64>)
 define ptr @ptrmask_simplify_poison_mask(ptr %p) {
 ; CHECK-LABEL: define ptr @ptrmask_simplify_poison_mask
 ; CHECK-SAME: (ptr [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 poison)
-; CHECK-NEXT:    ret ptr [[R]]
+; CHECK-NEXT:    ret ptr poison
 ;
   %r = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 poison)
   ret ptr %r
@@ -20,8 +19,7 @@ define ptr @ptrmask_simplify_poison_mask(ptr %p) {
 define <2 x ptr> @ptrmask_simplify_poison_mask_vec(<2 x ptr> %p) {
 ; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_poison_mask_vec
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P]], <2 x i32> poison)
-; CHECK-NEXT:    ret <2 x ptr> [[R]]
+; CHECK-NEXT:    ret <2 x ptr> poison
 ;
   %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p, <2 x i32> poison)
   ret <2 x ptr> %r
@@ -40,8 +38,7 @@ define <2 x ptr> @ptrmask_simplify_poison_and_zero_i32_vec_fail(<2 x ptr> %p) {
 define <2 x ptr> @ptrmask_simplify_undef_and_ones_vec(<2 x ptr> %p) {
 ; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_undef_and_ones_vec
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 undef, i64 -1>)
-; CHECK-NEXT:    ret <2 x ptr> [[R]]
+; CHECK-NEXT:    ret <2 x ptr> [[P]]
 ;
   %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 undef, i64 -1>)
   ret <2 x ptr> %r
@@ -50,8 +47,7 @@ define <2 x ptr> @ptrmask_simplify_undef_and_ones_vec(<2 x ptr> %p) {
 define <2 x ptr> @ptrmask_simplify_poison_and_ones_vec(<2 x ptr> %p) {
 ; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_poison_and_ones_vec
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 poison, i64 -1>)
-; CHECK-NEXT:    ret <2 x ptr> [[R]]
+; CHECK-NEXT:    ret <2 x ptr> [[P]]
 ;
   %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 poison, i64 -1>)
   ret <2 x ptr> %r
@@ -60,8 +56,7 @@ define <2 x ptr> @ptrmask_simplify_poison_and_ones_vec(<2 x ptr> %p) {
 define <2 x ptr> @ptrmask_simplify_ones_vec(<2 x ptr> %p) {
 ; CHECK-LABEL: define <2 x ptr> @ptrmask_simplify_ones_vec
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -1, i64 -1>)
-; CHECK-NEXT:    ret <2 x ptr> [[R]]
+; CHECK-NEXT:    ret <2 x ptr> [[P]]
 ;
   %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -1, i64 -1>)
   ret <2 x ptr> %r
@@ -100,8 +95,7 @@ define ptr @ptrmask_simplify_0_mask(ptr %p) {
 define ptr @ptrmask_simplify_1s_mask(ptr %p) {
 ; CHECK-LABEL: define ptr @ptrmask_simplify_1s_mask
 ; CHECK-SAME: (ptr [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -1)
-; CHECK-NEXT:    ret ptr [[R]]
+; CHECK-NEXT:    ret ptr [[P]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -1)
   ret ptr %r
@@ -120,8 +114,7 @@ define ptr @ptrmask_simplify_1s_mask_i32_fail(ptr %p) {
 define ptr @ptrmask_simplify_poison_ptr(i64 %m) {
 ; CHECK-LABEL: define ptr @ptrmask_simplify_poison_ptr
 ; CHECK-SAME: (i64 [[M:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr poison, i64 [[M]])
-; CHECK-NEXT:    ret ptr [[R]]
+; CHECK-NEXT:    ret ptr poison
 ;
   %r = call ptr @llvm.ptrmask.p0.i64(ptr poison, i64 %m)
   ret ptr %r
@@ -130,8 +123,7 @@ define ptr @ptrmask_simplify_poison_ptr(i64 %m) {
 define ptr @ptrmask_simplify_undef_ptr(i32 %m) {
 ; CHECK-LABEL: define ptr @ptrmask_simplify_undef_ptr
 ; CHECK-SAME: (i32 [[M:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr undef, i32 [[M]])
-; CHECK-NEXT:    ret ptr [[R]]
+; CHECK-NEXT:    ret ptr null
 ;
   %r = call ptr @llvm.ptrmask.p0.i32(ptr undef, i32 %m)
   ret ptr %r
@@ -140,8 +132,7 @@ define ptr @ptrmask_simplify_undef_ptr(i32 %m) {
 define ptr @ptrmask_simplify_null_ptr(i64 %m) {
 ; CHECK-LABEL: define ptr @ptrmask_simplify_null_ptr
 ; CHECK-SAME: (i64 [[M:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr null, i64 [[M]])
-; CHECK-NEXT:    ret ptr [[R]]
+; CHECK-NEXT:    ret ptr null
 ;
   %r = call ptr @llvm.ptrmask.p0.i64(ptr null, i64 %m)
   ret ptr %r
@@ -150,9 +141,7 @@ define ptr @ptrmask_simplify_null_ptr(i64 %m) {
 define ptr @ptrmask_simplify_ptrmask(ptr %p) {
 ; CHECK-LABEL: define ptr @ptrmask_simplify_ptrmask
 ; CHECK-SAME: (ptr [[P:%.*]]) {
-; CHECK-NEXT:    [[M:%.*]] = ptrtoint ptr [[P]] to i64
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 [[M]])
-; CHECK-NEXT:    ret ptr [[R]]
+; CHECK-NEXT:    ret ptr [[P]]
 ;
   %m = ptrtoint ptr %p to i64
   %r = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 %m)
@@ -174,8 +163,7 @@ define ptr @ptrmask_simplify_ptrmask_i32_fail(ptr %p) {
 define ptr @ptrmask_simplify_aligned_unused(ptr align 64 %p) {
 ; CHECK-LABEL: define ptr @ptrmask_simplify_aligned_unused
 ; CHECK-SAME: (ptr align 64 [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -64)
-; CHECK-NEXT:    ret ptr [[R]]
+; CHECK-NEXT:    ret ptr [[P]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -64)
   ret ptr %r
@@ -216,8 +204,7 @@ define ptr @ptrmask_simplify_known_unused(ptr %p) {
 ; CHECK-SAME: (ptr [[P:%.*]]) {
 ; CHECK-NEXT:    [[PM0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -64)
 ; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, ptr [[PM0]], i64 32
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PGEP]], i64 -32)
-; CHECK-NEXT:    ret ptr [[R]]
+; CHECK-NEXT:    ret ptr [[PGEP]]
 ;
   %pm0 = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -64)
   %pgep = getelementptr i8, ptr %pm0, i64 32
@@ -230,8 +217,7 @@ define <2 x ptr> @ptrmask_simplify_known_unused_vec(<2 x ptr> %p) {
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
 ; CHECK-NEXT:    [[PM0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -64, i64 -64>)
 ; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, <2 x ptr> [[PM0]], <2 x i64> <i64 32, i64 32>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[PGEP]], <2 x i64> <i64 -32, i64 -32>)
-; CHECK-NEXT:    ret <2 x ptr> [[R]]
+; CHECK-NEXT:    ret <2 x ptr> [[PGEP]]
 ;
   %pm0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -64, i64 -64>)
   %pgep = getelementptr i8, <2 x ptr> %pm0, <2 x i64> <i64 32, i64 32>
@@ -244,8 +230,7 @@ define <2 x ptr> @ptrmask_simplify_known_unused_vec2(<2 x ptr> %p) {
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
 ; CHECK-NEXT:    [[PM0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -64, i64 -64>)
 ; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, <2 x ptr> [[PM0]], <2 x i64> <i64 32, i64 32>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[PGEP]], <2 x i64> <i64 -32, i64 -16>)
-; CHECK-NEXT:    ret <2 x ptr> [[R]]
+; CHECK-NEXT:    ret <2 x ptr> [[PGEP]]
 ;
   %pm0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -64, i64 -64>)
   %pgep = getelementptr i8, <2 x ptr> %pm0, <2 x i64> <i64 32, i64 32>
@@ -258,8 +243,7 @@ define <2 x ptr> @ptrmask_simplify_known_unused_vec3(<2 x ptr> %p) {
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
 ; CHECK-NEXT:    [[PM0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -64, i64 -128>)
 ; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, <2 x ptr> [[PM0]], <2 x i64> <i64 32, i64 32>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[PGEP]], <2 x i64> <i64 -32, i64 -32>)
-; CHECK-NEXT:    ret <2 x ptr> [[R]]
+; CHECK-NEXT:    ret <2 x ptr> [[PGEP]]
 ;
   %pm0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -64, i64 -128>)
   %pgep = getelementptr i8, <2 x ptr> %pm0, <2 x i64> <i64 32, i64 32>
@@ -272,8 +256,7 @@ define <2 x ptr> @ptrmask_simplify_known_unused_vec4(<2 x ptr> %p) {
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
 ; CHECK-NEXT:    [[PM0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -64, i64 -128>)
 ; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, <2 x ptr> [[PM0]], <2 x i64> <i64 32, i64 64>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[PGEP]], <2 x i64> <i64 -32, i64 -32>)
-; CHECK-NEXT:    ret <2 x ptr> [[R]]
+; CHECK-NEXT:    ret <2 x ptr> [[PGEP]]
 ;
   %pm0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -64, i64 -128>)
   %pgep = getelementptr i8, <2 x ptr> %pm0, <2 x i64> <i64 32, i64 64>

>From ccf5eea12bc316eba748f1fb48b52df7663fafba Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 22 Sep 2023 08:21:32 -0500
Subject: [PATCH 3/8] [InstCombine] Add tests for combining `llvm.ptrmask`; NFC

Differential Revision: https://reviews.llvm.org/D156634
---
 .../InstCombine/consecutive-ptrmask.ll        |  61 +++
 llvm/test/Transforms/InstCombine/ptrmask.ll   | 430 ++++++++++++++++++
 2 files changed, 491 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/ptrmask.ll

diff --git a/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll b/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll
index d2da3be3201cfc0..325d0ebe1ebd966 100644
--- a/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll
+++ b/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll
@@ -3,6 +3,7 @@
 
 declare ptr @llvm.ptrmask.p0.i64(ptr, i64)
 declare ptr @llvm.ptrmask.p0.i32(ptr, i32)
+declare <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr>, <2 x i32>)
 declare <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr>, <2 x i64>)
 declare void @use.ptr(ptr)
 
@@ -79,3 +80,63 @@ define <2 x ptr> @fold_2x_vec(<2 x ptr> %p, <2 x i64> %m0, <2 x i64> %m1) {
   %p1 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p0, <2 x i64> %m1)
   ret <2 x ptr> %p1
 }
+
+define ptr @fold_2x_type_mismatch_const0(ptr %p, i32 %m1) {
+; CHECK-LABEL: define ptr @fold_2x_type_mismatch_const0
+; CHECK-SAME: (ptr [[P:%.*]], i32 [[M1:%.*]]) {
+; CHECK-NEXT:    [[P0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -128)
+; CHECK-NEXT:    [[P1:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 [[M1]])
+; CHECK-NEXT:    ret ptr [[P1]]
+;
+  %p0 = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -128)
+  %p1 = call ptr @llvm.ptrmask.p0.i32(ptr %p0, i32 %m1)
+  ret ptr %p1
+}
+
+define ptr @fold_2x_type_mismatch_const1(ptr %p, i64 %m0) {
+; CHECK-LABEL: define ptr @fold_2x_type_mismatch_const1
+; CHECK-SAME: (ptr [[P:%.*]], i64 [[M0:%.*]]) {
+; CHECK-NEXT:    [[P0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 [[M0]])
+; CHECK-NEXT:    [[P1:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 -2)
+; CHECK-NEXT:    ret ptr [[P1]]
+;
+  %p0 = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 %m0)
+  %p1 = call ptr @llvm.ptrmask.p0.i32(ptr %p0, i32 -2)
+  ret ptr %p1
+}
+
+define ptr @fold_2x_type_mismatch_const2(ptr %p) {
+; CHECK-LABEL: define ptr @fold_2x_type_mismatch_const2
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[P0:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -4)
+; CHECK-NEXT:    [[P1:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 -31)
+; CHECK-NEXT:    ret ptr [[P1]]
+;
+  %p0 = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -4)
+  %p1 = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 -31)
+  ret ptr %p1
+}
+
+define <2 x ptr> @fold_2x_type_mismatch_const_vec(<2 x ptr> %p, <2 x i64> %m0) {
+; CHECK-LABEL: define <2 x ptr> @fold_2x_type_mismatch_const_vec
+; CHECK-SAME: (<2 x ptr> [[P:%.*]], <2 x i64> [[M0:%.*]]) {
+; CHECK-NEXT:    [[P0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> [[M0]])
+; CHECK-NEXT:    [[P1:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P0]], <2 x i32> <i32 -2, i32 -2>)
+; CHECK-NEXT:    ret <2 x ptr> [[P1]]
+;
+  %p0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> %m0)
+  %p1 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p0, <2 x i32> <i32 -2, i32 -2>)
+  ret <2 x ptr> %p1
+}
+
+define <2 x ptr> @fold_2x_type_mismatch_const_vec_with_undef(<2 x ptr> %p, <2 x i64> %m0) {
+; CHECK-LABEL: define <2 x ptr> @fold_2x_type_mismatch_const_vec_with_undef
+; CHECK-SAME: (<2 x ptr> [[P:%.*]], <2 x i64> [[M0:%.*]]) {
+; CHECK-NEXT:    [[P0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> [[M0]])
+; CHECK-NEXT:    [[P1:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P0]], <2 x i32> <i32 -2, i32 undef>)
+; CHECK-NEXT:    ret <2 x ptr> [[P1]]
+;
+  %p0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> %m0)
+  %p1 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p0, <2 x i32> <i32 -2, i32 undef>)
+  ret <2 x ptr> %p1
+}
diff --git a/llvm/test/Transforms/InstCombine/ptrmask.ll b/llvm/test/Transforms/InstCombine/ptrmask.ll
new file mode 100644
index 000000000000000..530618af4d1f3f5
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/ptrmask.ll
@@ -0,0 +1,430 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare ptr @llvm.ptrmask.p0.i32(ptr, i32)
+declare ptr @llvm.ptrmask.p0.i64(ptr, i64)
+declare <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr>, <2 x i32>)
+declare <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr>, <2 x i64>)
+
+define ptr @ptrmask_combine_consecutive_preserve_attrs(ptr %p0, i64 %m1) {
+; CHECK-LABEL: define ptr @ptrmask_combine_consecutive_preserve_attrs
+; CHECK-SAME: (ptr [[P0:%.*]], i64 [[M1:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[M1]], 224
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[TMP1]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %pm0 = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 224)
+  %r = call noalias ptr @llvm.ptrmask.p0.i64(ptr %pm0, i64 %m1)
+  ret ptr %r
+}
+
+define <2 x ptr> @ptrmask_combine_consecutive_preserve_attrs_vecs(<2 x ptr> %p0, <2 x i64> %m1) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_combine_consecutive_preserve_attrs_vecs
+; CHECK-SAME: (<2 x ptr> [[P0:%.*]], <2 x i64> [[M1:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i64> [[M1]], <i64 12345, i64 12345>
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P0]], <2 x i64> [[TMP1]])
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %pm0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p0, <2 x i64> <i64 12345, i64 12345>)
+  %r = call align 128 <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %pm0, <2 x i64> %m1)
+  ret <2 x ptr> %r
+}
+
+define ptr @ptrmask_combine_consecutive_preserve_attrs_fail(ptr %p0, i64 %m0) {
+; CHECK-LABEL: define ptr @ptrmask_combine_consecutive_preserve_attrs_fail
+; CHECK-SAME: (ptr [[P0:%.*]], i64 [[M0:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[M0]], 193
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[TMP1]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %pm0 = call noalias ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 %m0)
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %pm0, i64 193)
+  ret ptr %r
+}
+
+define ptr @ptrmask_combine_consecutive_preserve_attrs_todo0(ptr %p0) {
+; CHECK-LABEL: define ptr @ptrmask_combine_consecutive_preserve_attrs_todo0
+; CHECK-SAME: (ptr [[P0:%.*]]) {
+; CHECK-NEXT:    [[PM0:%.*]] = call noalias ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 224)
+; CHECK-NEXT:    ret ptr [[PM0]]
+;
+  %pm0 = call noalias ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 224)
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %pm0, i64 224)
+  ret ptr %r
+}
+
+define ptr @ptrmask_combine_consecutive_preserve_attrs_todo1(ptr %p0) {
+; CHECK-LABEL: define ptr @ptrmask_combine_consecutive_preserve_attrs_todo1
+; CHECK-SAME: (ptr [[P0:%.*]]) {
+; CHECK-NEXT:    [[PM0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 224)
+; CHECK-NEXT:    ret ptr [[PM0]]
+;
+  %pm0 = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 224)
+  %r = call noalias ptr @llvm.ptrmask.p0.i64(ptr %pm0, i64 224)
+  ret ptr %r
+}
+
+define ptr @ptrmask_combine_consecutive_preserve_attrs_todo2(ptr %p0) {
+; CHECK-LABEL: define ptr @ptrmask_combine_consecutive_preserve_attrs_todo2
+; CHECK-SAME: (ptr [[P0:%.*]]) {
+; CHECK-NEXT:    [[PM0:%.*]] = call noalias ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 224)
+; CHECK-NEXT:    ret ptr [[PM0]]
+;
+  %pm0 = call noalias ptr @llvm.ptrmask.p0.i32(ptr %p0, i32 224)
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %pm0, i64 224)
+  ret ptr %r
+}
+
+define ptr @ptrmask_combine_add_nonnull(ptr %p) {
+; CHECK-LABEL: define ptr @ptrmask_combine_add_nonnull
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[PM0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -64)
+; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, ptr [[PM0]], i64 33
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PGEP]], i64 -16)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %pm0 = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -64)
+  %pgep = getelementptr i8, ptr %pm0, i64 33
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %pgep, i64 -16)
+  ret ptr %r
+}
+
+define ptr @ptrmask_combine_add_alignment(ptr %p) {
+; CHECK-LABEL: define ptr @ptrmask_combine_add_alignment
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -64)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -64)
+  ret ptr %r
+}
+
+define ptr @ptrmask_combine_add_alignment2(ptr align 32 %p) {
+; CHECK-LABEL: define ptr @ptrmask_combine_add_alignment2
+; CHECK-SAME: (ptr align 32 [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -64)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -64)
+  ret ptr %r
+}
+
+define <2 x ptr> @ptrmask_combine_add_alignment_vec(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_combine_add_alignment_vec
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -96, i64 -96>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -96, i64 -96>)
+  ret <2 x ptr> %r
+}
+
+define ptr @ptrmask_combine_improve_alignment(ptr %p) {
+; CHECK-LABEL: define ptr @ptrmask_combine_improve_alignment
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call align 32 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -64)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call align 32 ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -64)
+  ret ptr %r
+}
+
+define <2 x ptr> @ptrmask_combine_improve_alignment_vec(<2 x ptr> %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_combine_improve_alignment_vec
+; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call align 32 <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P]], <2 x i32> <i32 -64, i32 -128>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call align 32 <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p, <2 x i32> <i32 -64, i32 -128>)
+  ret <2 x ptr> %r
+}
+
+define ptr @ptrmask_combine_improve_alignment_fail(ptr %p) {
+; CHECK-LABEL: define ptr @ptrmask_combine_improve_alignment_fail
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call align 128 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -64)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call align 128 ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -64)
+  ret ptr %r
+}
+
+define i64 @ptrtoint_of_ptrmask(ptr %p, i64 %m) {
+; CHECK-LABEL: define i64 @ptrtoint_of_ptrmask
+; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) {
+; CHECK-NEXT:    [[PM:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 [[M]])
+; CHECK-NEXT:    [[R:%.*]] = ptrtoint ptr [[PM]] to i64
+; CHECK-NEXT:    ret i64 [[R]]
+;
+  %pm = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 %m)
+  %r = ptrtoint ptr %pm to i64
+  ret i64 %r
+}
+
+; This succeeds because (ptrtoint i32) gets folded to (trunc i32 (ptrtoint i64))
+define i32 @ptrtoint_of_ptrmask2(ptr %p, i64 %m) {
+; CHECK-LABEL: define i32 @ptrtoint_of_ptrmask2
+; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) {
+; CHECK-NEXT:    [[PM:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 [[M]])
+; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[PM]] to i64
+; CHECK-NEXT:    [[R:%.*]] = trunc i64 [[TMP1]] to i32
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %pm = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 %m)
+  %r = ptrtoint ptr %pm to i32
+  ret i32 %r
+}
+
+define <2 x i64> @ptrtoint_of_ptrmask_vec(<2 x ptr> %p, <2 x i64> %m) {
+; CHECK-LABEL: define <2 x i64> @ptrtoint_of_ptrmask_vec
+; CHECK-SAME: (<2 x ptr> [[P:%.*]], <2 x i64> [[M:%.*]]) {
+; CHECK-NEXT:    [[PM:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> [[M]])
+; CHECK-NEXT:    [[R:%.*]] = ptrtoint <2 x ptr> [[PM]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[R]]
+;
+  %pm = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> %m)
+  %r = ptrtoint <2 x ptr> %pm to <2 x i64>
+  ret <2 x i64> %r
+}
+
+define <2 x i32> @ptrtoint_of_ptrmask_vec2(<2 x ptr> %p, <2 x i64> %m) {
+; CHECK-LABEL: define <2 x i32> @ptrtoint_of_ptrmask_vec2
+; CHECK-SAME: (<2 x ptr> [[P:%.*]], <2 x i64> [[M:%.*]]) {
+; CHECK-NEXT:    [[PM:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> [[M]])
+; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint <2 x ptr> [[PM]] to <2 x i64>
+; CHECK-NEXT:    [[R:%.*]] = trunc <2 x i64> [[TMP1]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %pm = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> %m)
+  %r = ptrtoint <2 x ptr> %pm to <2 x i32>
+  ret <2 x i32> %r
+}
+
+define i64 @ptrtoint_of_ptrmask_fail(ptr %p, i32 %m) {
+; CHECK-LABEL: define i64 @ptrtoint_of_ptrmask_fail
+; CHECK-SAME: (ptr [[P:%.*]], i32 [[M:%.*]]) {
+; CHECK-NEXT:    [[PM:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 [[M]])
+; CHECK-NEXT:    [[R:%.*]] = ptrtoint ptr [[PM]] to i64
+; CHECK-NEXT:    ret i64 [[R]]
+;
+  %pm = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 %m)
+  %r = ptrtoint ptr %pm to i64
+  ret i64 %r
+}
+
+define <2 x i32> @ptrtoint_of_ptrmask_vec_fail(<2 x ptr> %p, <2 x i32> %m) {
+; CHECK-LABEL: define <2 x i32> @ptrtoint_of_ptrmask_vec_fail
+; CHECK-SAME: (<2 x ptr> [[P:%.*]], <2 x i32> [[M:%.*]]) {
+; CHECK-NEXT:    [[PM:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P]], <2 x i32> [[M]])
+; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint <2 x ptr> [[PM]] to <2 x i64>
+; CHECK-NEXT:    [[R:%.*]] = trunc <2 x i64> [[TMP1]] to <2 x i32>
+; CHECK-NEXT:    ret <2 x i32> [[R]]
+;
+  %pm = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p, <2 x i32> %m)
+  %r = ptrtoint <2 x ptr> %pm to <2 x i32>
+  ret <2 x i32> %r
+}
+
+define ptr @ptrmask_is_null(ptr align 32 %p) {
+; CHECK-LABEL: define ptr @ptrmask_is_null
+; CHECK-SAME: (ptr align 32 [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 31)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 31)
+  ret ptr %r
+}
+
+define <2 x ptr> @ptrmask_is_null_vec(<2 x ptr> align 64 %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_is_null_vec
+; CHECK-SAME: (<2 x ptr> align 64 [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P]], <2 x i32> <i32 31, i32 63>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p, <2 x i32> <i32 31, i32 63>)
+  ret <2 x ptr> %r
+}
+
+define ptr @ptrmask_is_null_fail(ptr align 16 %p) {
+; CHECK-LABEL: define ptr @ptrmask_is_null_fail
+; CHECK-SAME: (ptr align 16 [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 31)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 31)
+  ret ptr %r
+}
+
+define <2 x ptr> @ptrmask_is_null_vec_fail(<2 x ptr> align 32 %p) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_is_null_vec_fail
+; CHECK-SAME: (<2 x ptr> align 32 [[P:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P]], <2 x i32> <i32 31, i32 63>)
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p, <2 x i32> <i32 31, i32 63>)
+  ret <2 x ptr> %r
+}
+
+define ptr @ptrmask_maintain_provenance_i64(ptr %p0) {
+; CHECK-LABEL: define ptr @ptrmask_maintain_provenance_i64
+; CHECK-SAME: (ptr [[P0:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 0)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 0)
+  ret ptr %r
+}
+
+define ptr @ptrmask_maintain_provenance_i32(ptr %p0) {
+; CHECK-LABEL: define ptr @ptrmask_maintain_provenance_i32
+; CHECK-SAME: (ptr [[P0:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 0)
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %r = call ptr @llvm.ptrmask.p0.i32(ptr %p0, i32 0)
+  ret ptr %r
+}
+
+define ptr @ptrmask_is_useless0(i64 %i, i64 %m) {
+; CHECK-LABEL: define ptr @ptrmask_is_useless0
+; CHECK-SAME: (i64 [[I:%.*]], i64 [[M:%.*]]) {
+; CHECK-NEXT:    [[M0:%.*]] = and i64 [[M]], -4
+; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], -4
+; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %m0 = and i64 %m, -4
+  %i0 = and i64 %i, -4
+  %p0 = inttoptr i64 %i0 to ptr
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 %m0)
+  ret ptr %r
+}
+
+define ptr @ptrmask_is_useless1(i64 %i, i64 %m) {
+; CHECK-LABEL: define ptr @ptrmask_is_useless1
+; CHECK-SAME: (i64 [[I:%.*]], i64 [[M:%.*]]) {
+; CHECK-NEXT:    [[M0:%.*]] = and i64 [[M]], -4
+; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], -8
+; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %m0 = and i64 %m, -4
+  %i0 = and i64 %i, -8
+  %p0 = inttoptr i64 %i0 to ptr
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 %m0)
+  ret ptr %r
+}
+
+define ptr @ptrmask_is_useless2(i64 %i, i64 %m) {
+; CHECK-LABEL: define ptr @ptrmask_is_useless2
+; CHECK-SAME: (i64 [[I:%.*]], i64 [[M:%.*]]) {
+; CHECK-NEXT:    [[M0:%.*]] = and i64 [[M]], 127
+; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], 31
+; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %m0 = and i64 %m, 127
+  %i0 = and i64 %i, 31
+  %p0 = inttoptr i64 %i0 to ptr
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 %m0)
+  ret ptr %r
+}
+
+define ptr @ptrmask_is_useless3(i64 %i, i64 %m) {
+; CHECK-LABEL: define ptr @ptrmask_is_useless3
+; CHECK-SAME: (i64 [[I:%.*]], i64 [[M:%.*]]) {
+; CHECK-NEXT:    [[M0:%.*]] = and i64 [[M]], 127
+; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], 127
+; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %m0 = and i64 %m, 127
+  %i0 = and i64 %i, 127
+  %p0 = inttoptr i64 %i0 to ptr
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 %m0)
+  ret ptr %r
+}
+
+define ptr @ptrmask_is_useless4(i64 %i, i64 %m) {
+; CHECK-LABEL: define ptr @ptrmask_is_useless4
+; CHECK-SAME: (i64 [[I:%.*]], i64 [[M:%.*]]) {
+; CHECK-NEXT:    [[M0:%.*]] = or i64 [[M]], -4
+; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], -4
+; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %m0 = or i64 %m, -4
+  %i0 = and i64 %i, -4
+  %p0 = inttoptr i64 %i0 to ptr
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 %m0)
+  ret ptr %r
+}
+
+define <2 x ptr> @ptrmask_is_useless_vec(<2 x i64> %i, <2 x i64> %m) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_is_useless_vec
+; CHECK-SAME: (<2 x i64> [[I:%.*]], <2 x i64> [[M:%.*]]) {
+; CHECK-NEXT:    [[M0:%.*]] = and <2 x i64> [[M]], <i64 127, i64 127>
+; CHECK-NEXT:    [[I0:%.*]] = and <2 x i64> [[I]], <i64 31, i64 31>
+; CHECK-NEXT:    [[P0:%.*]] = inttoptr <2 x i64> [[I0]] to <2 x ptr>
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P0]], <2 x i64> [[M0]])
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %m0 = and <2 x i64> %m, <i64 127, i64 127>
+  %i0 = and <2 x i64> %i, <i64 31, i64 31>
+  %p0 = inttoptr <2 x i64> %i0 to <2 x ptr>
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p0, <2 x i64> %m0)
+  ret <2 x ptr> %r
+}
+
+define <2 x ptr> @ptrmask_is_useless_vec_todo(<2 x i64> %i, <2 x i64> %m) {
+; CHECK-LABEL: define <2 x ptr> @ptrmask_is_useless_vec_todo
+; CHECK-SAME: (<2 x i64> [[I:%.*]], <2 x i64> [[M:%.*]]) {
+; CHECK-NEXT:    [[M0:%.*]] = and <2 x i64> [[M]], <i64 127, i64 127>
+; CHECK-NEXT:    [[I0:%.*]] = and <2 x i64> [[I]], <i64 31, i64 127>
+; CHECK-NEXT:    [[P0:%.*]] = inttoptr <2 x i64> [[I0]] to <2 x ptr>
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P0]], <2 x i64> [[M0]])
+; CHECK-NEXT:    ret <2 x ptr> [[R]]
+;
+  %m0 = and <2 x i64> %m, <i64 127, i64 127>
+  %i0 = and <2 x i64> %i, <i64 31, i64 127>
+  %p0 = inttoptr <2 x i64> %i0 to <2 x ptr>
+  %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p0, <2 x i64> %m0)
+  ret <2 x ptr> %r
+}
+
+define ptr @ptrmask_is_useless_fail0(i64 %i, i64 %m) {
+; CHECK-LABEL: define ptr @ptrmask_is_useless_fail0
+; CHECK-SAME: (i64 [[I:%.*]], i64 [[M:%.*]]) {
+; CHECK-NEXT:    [[M0:%.*]] = and i64 [[M]], -4
+; CHECK-NEXT:    [[I0:%.*]] = or i64 [[I]], -4
+; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr nonnull [[P0]], i64 [[M0]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %m0 = and i64 %m, -4
+  %i0 = or i64 %i, -4
+  %p0 = inttoptr i64 %i0 to ptr
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 %m0)
+  ret ptr %r
+}
+
+define ptr @ptrmask_is_useless_fail1(i64 %i, i64 %m) {
+; CHECK-LABEL: define ptr @ptrmask_is_useless_fail1
+; CHECK-SAME: (i64 [[I:%.*]], i64 [[M:%.*]]) {
+; CHECK-NEXT:    [[M0:%.*]] = and i64 [[M]], 127
+; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], 511
+; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
+; CHECK-NEXT:    ret ptr [[R]]
+;
+  %m0 = and i64 %m, 127
+  %i0 = and i64 %i, 511
+  %p0 = inttoptr i64 %i0 to ptr
+  %r = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 %m0)
+  ret ptr %r
+}

>From af986ccba1f3f5704b86b198b5c2ad2a80424276 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 22 Sep 2023 08:21:43 -0500
Subject: [PATCH 4/8] [InstCombine] Deduce `align` and `nonnull` return
 attributes for `llvm.ptrmask`

We can deduce the former based on the mask / incoming pointer
alignment.  We can set the latter based if know the result in non-zero
(this is essentially just caching our analysis result).

Differential Revision: https://reviews.llvm.org/D156636
---
 clang/test/CodeGen/arm64_32-vaarg.c           |  2 +-
 .../InstCombine/InstCombineCalls.cpp          | 24 ++++++++++++
 .../test/Transforms/InstCombine/align-addr.ll | 12 +++---
 .../InstCombine/consecutive-ptrmask.ll        | 12 +++---
 llvm/test/Transforms/InstCombine/ptrmask.ll   | 38 +++++++++----------
 5 files changed, 56 insertions(+), 32 deletions(-)

diff --git a/clang/test/CodeGen/arm64_32-vaarg.c b/clang/test/CodeGen/arm64_32-vaarg.c
index 9fbcf88ecfdcc33..3f1f4443436da15 100644
--- a/clang/test/CodeGen/arm64_32-vaarg.c
+++ b/clang/test/CodeGen/arm64_32-vaarg.c
@@ -29,7 +29,7 @@ long long test_longlong(OneLongLong input, va_list *mylist) {
   // CHECK-LABEL: define{{.*}} i64 @test_longlong(i64 %input
   // CHECK: [[STARTPTR:%.*]] = load ptr, ptr %mylist
   // CHECK: [[ALIGN_TMP:%.+]] = getelementptr inbounds i8, ptr [[STARTPTR]], i32 7
-  // CHECK: [[ALIGNED_ADDR:%.+]] = tail call ptr @llvm.ptrmask.p0.i32(ptr nonnull [[ALIGN_TMP]], i32 -8)
+  // CHECK: [[ALIGNED_ADDR:%.+]] = tail call align 8 ptr @llvm.ptrmask.p0.i32(ptr nonnull [[ALIGN_TMP]], i32 -8)
   // CHECK: [[NEXT:%.*]] = getelementptr inbounds i8, ptr [[ALIGNED_ADDR]], i32 8
   // CHECK: store ptr [[NEXT]], ptr %mylist
 
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index e29fb869686ca0b..7289545d453bfc1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1962,6 +1962,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     break;
   }
   case Intrinsic::ptrmask: {
+    unsigned BitWidth = DL.getPointerTypeSizeInBits(II->getType());
     Value *InnerPtr, *InnerMask;
     if (match(II->getArgOperand(0),
               m_OneUse(m_Intrinsic<Intrinsic::ptrmask>(m_Value(InnerPtr),
@@ -1974,6 +1975,29 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
                                     {InnerPtr, NewMask}));
       }
     }
+    bool Changed = false;
+    KnownBits Known = computeKnownBits(II, /*Depth*/ 0, II);
+    // See if we can deduce non-null.
+    if (!CI.hasRetAttr(Attribute::NonNull) &&
+        (Known.isNonZero() ||
+         isKnownNonZero(II, DL, /*Depth*/ 0, &AC, II, &DT))) {
+      CI.addRetAttr(Attribute::NonNull);
+      Changed = true;
+    }
+
+    unsigned NewAlignmentLog =
+        std::min(Value::MaxAlignmentExponent,
+                 std::min(BitWidth - 1, Known.countMinTrailingZeros()));
+    // Known bits will capture if we had alignment information associated with
+    // the pointer argument.
+    if (NewAlignmentLog > Log2(CI.getRetAlign().valueOrOne())) {
+      CI.removeRetAttr(Attribute::Alignment);
+      CI.addRetAttr(Attribute::getWithAlignment(
+          CI.getContext(), Align(uint64_t(1) << NewAlignmentLog)));
+      Changed = true;
+    }
+    if (Changed)
+      return &CI;
     break;
   }
   case Intrinsic::uadd_with_overflow:
diff --git a/llvm/test/Transforms/InstCombine/align-addr.ll b/llvm/test/Transforms/InstCombine/align-addr.ll
index a1d19df4c5e0607..57bb8a2df03ef09 100644
--- a/llvm/test/Transforms/InstCombine/align-addr.ll
+++ b/llvm/test/Transforms/InstCombine/align-addr.ll
@@ -137,7 +137,7 @@ define <16 x i8> @ptrmask_align_unknown_ptr_align1(ptr align 1 %ptr, i64 %mask)
 
 define <16 x i8> @ptrmask_align_unknown_ptr_align8(ptr align 8 %ptr, i64 %mask) {
 ; CHECK-LABEL: @ptrmask_align_unknown_ptr_align8(
-; CHECK-NEXT:    [[ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR:%.*]], i64 [[MASK:%.*]])
+; CHECK-NEXT:    [[ALIGNED:%.*]] = call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[PTR:%.*]], i64 [[MASK:%.*]])
 ; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 1
 ; CHECK-NEXT:    ret <16 x i8> [[LOAD]]
 ;
@@ -149,7 +149,7 @@ define <16 x i8> @ptrmask_align_unknown_ptr_align8(ptr align 8 %ptr, i64 %mask)
 ; Increase load align from 1 to 2
 define <16 x i8> @ptrmask_align2_ptr_align1(ptr align 1 %ptr) {
 ; CHECK-LABEL: @ptrmask_align2_ptr_align1(
-; CHECK-NEXT:    [[ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR:%.*]], i64 -2)
+; CHECK-NEXT:    [[ALIGNED:%.*]] = call align 2 ptr @llvm.ptrmask.p0.i64(ptr [[PTR:%.*]], i64 -2)
 ; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 1
 ; CHECK-NEXT:    ret <16 x i8> [[LOAD]]
 ;
@@ -161,7 +161,7 @@ define <16 x i8> @ptrmask_align2_ptr_align1(ptr align 1 %ptr) {
 ; Increase load align from 1 to 4
 define <16 x i8> @ptrmask_align4_ptr_align1(ptr align 1 %ptr) {
 ; CHECK-LABEL: @ptrmask_align4_ptr_align1(
-; CHECK-NEXT:    [[ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR:%.*]], i64 -4)
+; CHECK-NEXT:    [[ALIGNED:%.*]] = call align 4 ptr @llvm.ptrmask.p0.i64(ptr [[PTR:%.*]], i64 -4)
 ; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 1
 ; CHECK-NEXT:    ret <16 x i8> [[LOAD]]
 ;
@@ -173,7 +173,7 @@ define <16 x i8> @ptrmask_align4_ptr_align1(ptr align 1 %ptr) {
 ; Increase load align from 1 to 8
 define <16 x i8> @ptrmask_align8_ptr_align1(ptr align 1 %ptr) {
 ; CHECK-LABEL: @ptrmask_align8_ptr_align1(
-; CHECK-NEXT:    [[ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR:%.*]], i64 -8)
+; CHECK-NEXT:    [[ALIGNED:%.*]] = call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[PTR:%.*]], i64 -8)
 ; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 1
 ; CHECK-NEXT:    ret <16 x i8> [[LOAD]]
 ;
@@ -208,7 +208,7 @@ define <16 x i8> @ptrmask_align8_ptr_align16(ptr align 16 %ptr) {
 ; than the pointer size.
 define <16 x i8> @ptrmask_align8_ptr_align1_smallmask(ptr align 1 %ptr) {
 ; CHECK-LABEL: @ptrmask_align8_ptr_align1_smallmask(
-; CHECK-NEXT:    [[ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[PTR:%.*]], i32 -8)
+; CHECK-NEXT:    [[ALIGNED:%.*]] = call align 8 ptr @llvm.ptrmask.p0.i32(ptr [[PTR:%.*]], i32 -8)
 ; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 1
 ; CHECK-NEXT:    ret <16 x i8> [[LOAD]]
 ;
@@ -221,7 +221,7 @@ define <16 x i8> @ptrmask_align8_ptr_align1_smallmask(ptr align 1 %ptr) {
 ; than the pointer size.
 define <16 x i8> @ptrmask_align8_ptr_align1_bigmask(ptr align 1 %ptr) {
 ; CHECK-LABEL: @ptrmask_align8_ptr_align1_bigmask(
-; CHECK-NEXT:    [[ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i128(ptr [[PTR:%.*]], i128 -8)
+; CHECK-NEXT:    [[ALIGNED:%.*]] = call align 8 ptr @llvm.ptrmask.p0.i128(ptr [[PTR:%.*]], i128 -8)
 ; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 1
 ; CHECK-NEXT:    ret <16 x i8> [[LOAD]]
 ;
diff --git a/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll b/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll
index 325d0ebe1ebd966..c714516b34aa297 100644
--- a/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll
+++ b/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll
@@ -84,8 +84,8 @@ define <2 x ptr> @fold_2x_vec(<2 x ptr> %p, <2 x i64> %m0, <2 x i64> %m1) {
 define ptr @fold_2x_type_mismatch_const0(ptr %p, i32 %m1) {
 ; CHECK-LABEL: define ptr @fold_2x_type_mismatch_const0
 ; CHECK-SAME: (ptr [[P:%.*]], i32 [[M1:%.*]]) {
-; CHECK-NEXT:    [[P0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -128)
-; CHECK-NEXT:    [[P1:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 [[M1]])
+; CHECK-NEXT:    [[P0:%.*]] = call align 128 ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -128)
+; CHECK-NEXT:    [[P1:%.*]] = call align 128 ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 [[M1]])
 ; CHECK-NEXT:    ret ptr [[P1]]
 ;
   %p0 = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -128)
@@ -97,7 +97,7 @@ define ptr @fold_2x_type_mismatch_const1(ptr %p, i64 %m0) {
 ; CHECK-LABEL: define ptr @fold_2x_type_mismatch_const1
 ; CHECK-SAME: (ptr [[P:%.*]], i64 [[M0:%.*]]) {
 ; CHECK-NEXT:    [[P0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 [[M0]])
-; CHECK-NEXT:    [[P1:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 -2)
+; CHECK-NEXT:    [[P1:%.*]] = call align 2 ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 -2)
 ; CHECK-NEXT:    ret ptr [[P1]]
 ;
   %p0 = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 %m0)
@@ -108,8 +108,8 @@ define ptr @fold_2x_type_mismatch_const1(ptr %p, i64 %m0) {
 define ptr @fold_2x_type_mismatch_const2(ptr %p) {
 ; CHECK-LABEL: define ptr @fold_2x_type_mismatch_const2
 ; CHECK-SAME: (ptr [[P:%.*]]) {
-; CHECK-NEXT:    [[P0:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -4)
-; CHECK-NEXT:    [[P1:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 -31)
+; CHECK-NEXT:    [[P0:%.*]] = call align 4 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -4)
+; CHECK-NEXT:    [[P1:%.*]] = call align 32 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 -31)
 ; CHECK-NEXT:    ret ptr [[P1]]
 ;
   %p0 = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -4)
@@ -121,7 +121,7 @@ define <2 x ptr> @fold_2x_type_mismatch_const_vec(<2 x ptr> %p, <2 x i64> %m0) {
 ; CHECK-LABEL: define <2 x ptr> @fold_2x_type_mismatch_const_vec
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]], <2 x i64> [[M0:%.*]]) {
 ; CHECK-NEXT:    [[P0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> [[M0]])
-; CHECK-NEXT:    [[P1:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P0]], <2 x i32> <i32 -2, i32 -2>)
+; CHECK-NEXT:    [[P1:%.*]] = call align 2 <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P0]], <2 x i32> <i32 -2, i32 -2>)
 ; CHECK-NEXT:    ret <2 x ptr> [[P1]]
 ;
   %p0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> %m0)
diff --git a/llvm/test/Transforms/InstCombine/ptrmask.ll b/llvm/test/Transforms/InstCombine/ptrmask.ll
index 530618af4d1f3f5..865e6581f4eb41a 100644
--- a/llvm/test/Transforms/InstCombine/ptrmask.ll
+++ b/llvm/test/Transforms/InstCombine/ptrmask.ll
@@ -10,7 +10,7 @@ define ptr @ptrmask_combine_consecutive_preserve_attrs(ptr %p0, i64 %m1) {
 ; CHECK-LABEL: define ptr @ptrmask_combine_consecutive_preserve_attrs
 ; CHECK-SAME: (ptr [[P0:%.*]], i64 [[M1:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[M1]], 224
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[TMP1]])
+; CHECK-NEXT:    [[R:%.*]] = call align 32 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[TMP1]])
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %pm0 = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 224)
@@ -45,7 +45,7 @@ define ptr @ptrmask_combine_consecutive_preserve_attrs_fail(ptr %p0, i64 %m0) {
 define ptr @ptrmask_combine_consecutive_preserve_attrs_todo0(ptr %p0) {
 ; CHECK-LABEL: define ptr @ptrmask_combine_consecutive_preserve_attrs_todo0
 ; CHECK-SAME: (ptr [[P0:%.*]]) {
-; CHECK-NEXT:    [[PM0:%.*]] = call noalias ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 224)
+; CHECK-NEXT:    [[PM0:%.*]] = call noalias align 32 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 224)
 ; CHECK-NEXT:    ret ptr [[PM0]]
 ;
   %pm0 = call noalias ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 224)
@@ -56,7 +56,7 @@ define ptr @ptrmask_combine_consecutive_preserve_attrs_todo0(ptr %p0) {
 define ptr @ptrmask_combine_consecutive_preserve_attrs_todo1(ptr %p0) {
 ; CHECK-LABEL: define ptr @ptrmask_combine_consecutive_preserve_attrs_todo1
 ; CHECK-SAME: (ptr [[P0:%.*]]) {
-; CHECK-NEXT:    [[PM0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 224)
+; CHECK-NEXT:    [[PM0:%.*]] = call align 32 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 224)
 ; CHECK-NEXT:    ret ptr [[PM0]]
 ;
   %pm0 = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 224)
@@ -67,7 +67,7 @@ define ptr @ptrmask_combine_consecutive_preserve_attrs_todo1(ptr %p0) {
 define ptr @ptrmask_combine_consecutive_preserve_attrs_todo2(ptr %p0) {
 ; CHECK-LABEL: define ptr @ptrmask_combine_consecutive_preserve_attrs_todo2
 ; CHECK-SAME: (ptr [[P0:%.*]]) {
-; CHECK-NEXT:    [[PM0:%.*]] = call noalias ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 224)
+; CHECK-NEXT:    [[PM0:%.*]] = call noalias align 32 ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 224)
 ; CHECK-NEXT:    ret ptr [[PM0]]
 ;
   %pm0 = call noalias ptr @llvm.ptrmask.p0.i32(ptr %p0, i32 224)
@@ -78,9 +78,9 @@ define ptr @ptrmask_combine_consecutive_preserve_attrs_todo2(ptr %p0) {
 define ptr @ptrmask_combine_add_nonnull(ptr %p) {
 ; CHECK-LABEL: define ptr @ptrmask_combine_add_nonnull
 ; CHECK-SAME: (ptr [[P:%.*]]) {
-; CHECK-NEXT:    [[PM0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -64)
+; CHECK-NEXT:    [[PM0:%.*]] = call align 64 ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -64)
 ; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, ptr [[PM0]], i64 33
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PGEP]], i64 -16)
+; CHECK-NEXT:    [[R:%.*]] = call nonnull align 32 ptr @llvm.ptrmask.p0.i64(ptr [[PGEP]], i64 -16)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %pm0 = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -64)
@@ -92,7 +92,7 @@ define ptr @ptrmask_combine_add_nonnull(ptr %p) {
 define ptr @ptrmask_combine_add_alignment(ptr %p) {
 ; CHECK-LABEL: define ptr @ptrmask_combine_add_alignment
 ; CHECK-SAME: (ptr [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -64)
+; CHECK-NEXT:    [[R:%.*]] = call align 64 ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -64)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -64)
@@ -102,7 +102,7 @@ define ptr @ptrmask_combine_add_alignment(ptr %p) {
 define ptr @ptrmask_combine_add_alignment2(ptr align 32 %p) {
 ; CHECK-LABEL: define ptr @ptrmask_combine_add_alignment2
 ; CHECK-SAME: (ptr align 32 [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -64)
+; CHECK-NEXT:    [[R:%.*]] = call align 64 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -64)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -64)
@@ -112,7 +112,7 @@ define ptr @ptrmask_combine_add_alignment2(ptr align 32 %p) {
 define <2 x ptr> @ptrmask_combine_add_alignment_vec(<2 x ptr> %p) {
 ; CHECK-LABEL: define <2 x ptr> @ptrmask_combine_add_alignment_vec
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -96, i64 -96>)
+; CHECK-NEXT:    [[R:%.*]] = call align 32 <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 -96, i64 -96>)
 ; CHECK-NEXT:    ret <2 x ptr> [[R]]
 ;
   %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> <i64 -96, i64 -96>)
@@ -122,7 +122,7 @@ define <2 x ptr> @ptrmask_combine_add_alignment_vec(<2 x ptr> %p) {
 define ptr @ptrmask_combine_improve_alignment(ptr %p) {
 ; CHECK-LABEL: define ptr @ptrmask_combine_improve_alignment
 ; CHECK-SAME: (ptr [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call align 32 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -64)
+; CHECK-NEXT:    [[R:%.*]] = call align 64 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -64)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call align 32 ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -64)
@@ -132,7 +132,7 @@ define ptr @ptrmask_combine_improve_alignment(ptr %p) {
 define <2 x ptr> @ptrmask_combine_improve_alignment_vec(<2 x ptr> %p) {
 ; CHECK-LABEL: define <2 x ptr> @ptrmask_combine_improve_alignment_vec
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call align 32 <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P]], <2 x i32> <i32 -64, i32 -128>)
+; CHECK-NEXT:    [[R:%.*]] = call align 64 <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P]], <2 x i32> <i32 -64, i32 -128>)
 ; CHECK-NEXT:    ret <2 x ptr> [[R]]
 ;
   %r = call align 32 <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p, <2 x i32> <i32 -64, i32 -128>)
@@ -228,7 +228,7 @@ define <2 x i32> @ptrtoint_of_ptrmask_vec_fail(<2 x ptr> %p, <2 x i32> %m) {
 define ptr @ptrmask_is_null(ptr align 32 %p) {
 ; CHECK-LABEL: define ptr @ptrmask_is_null
 ; CHECK-SAME: (ptr align 32 [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 31)
+; CHECK-NEXT:    [[R:%.*]] = call align 4294967296 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 31)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 31)
@@ -248,7 +248,7 @@ define <2 x ptr> @ptrmask_is_null_vec(<2 x ptr> align 64 %p) {
 define ptr @ptrmask_is_null_fail(ptr align 16 %p) {
 ; CHECK-LABEL: define ptr @ptrmask_is_null_fail
 ; CHECK-SAME: (ptr align 16 [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 31)
+; CHECK-NEXT:    [[R:%.*]] = call align 16 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 31)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 31)
@@ -268,7 +268,7 @@ define <2 x ptr> @ptrmask_is_null_vec_fail(<2 x ptr> align 32 %p) {
 define ptr @ptrmask_maintain_provenance_i64(ptr %p0) {
 ; CHECK-LABEL: define ptr @ptrmask_maintain_provenance_i64
 ; CHECK-SAME: (ptr [[P0:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 0)
+; CHECK-NEXT:    [[R:%.*]] = call align 4294967296 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 0)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 0)
@@ -278,7 +278,7 @@ define ptr @ptrmask_maintain_provenance_i64(ptr %p0) {
 define ptr @ptrmask_maintain_provenance_i32(ptr %p0) {
 ; CHECK-LABEL: define ptr @ptrmask_maintain_provenance_i32
 ; CHECK-SAME: (ptr [[P0:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 0)
+; CHECK-NEXT:    [[R:%.*]] = call align 4294967296 ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 0)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i32(ptr %p0, i32 0)
@@ -291,7 +291,7 @@ define ptr @ptrmask_is_useless0(i64 %i, i64 %m) {
 ; CHECK-NEXT:    [[M0:%.*]] = and i64 [[M]], -4
 ; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], -4
 ; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
+; CHECK-NEXT:    [[R:%.*]] = call align 4 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %m0 = and i64 %m, -4
@@ -307,7 +307,7 @@ define ptr @ptrmask_is_useless1(i64 %i, i64 %m) {
 ; CHECK-NEXT:    [[M0:%.*]] = and i64 [[M]], -4
 ; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], -8
 ; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
+; CHECK-NEXT:    [[R:%.*]] = call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %m0 = and i64 %m, -4
@@ -355,7 +355,7 @@ define ptr @ptrmask_is_useless4(i64 %i, i64 %m) {
 ; CHECK-NEXT:    [[M0:%.*]] = or i64 [[M]], -4
 ; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], -4
 ; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
+; CHECK-NEXT:    [[R:%.*]] = call align 4 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %m0 = or i64 %m, -4
@@ -403,7 +403,7 @@ define ptr @ptrmask_is_useless_fail0(i64 %i, i64 %m) {
 ; CHECK-NEXT:    [[M0:%.*]] = and i64 [[M]], -4
 ; CHECK-NEXT:    [[I0:%.*]] = or i64 [[I]], -4
 ; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr nonnull [[P0]], i64 [[M0]])
+; CHECK-NEXT:    [[R:%.*]] = call align 4 ptr @llvm.ptrmask.p0.i64(ptr nonnull [[P0]], i64 [[M0]])
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %m0 = and i64 %m, -4

>From 47763aff527d345d9b07b2ed7ed942c521afcc61 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 22 Sep 2023 08:21:48 -0500
Subject: [PATCH 5/8] [InstCombine] Implement `SimplifyDemandedBits` for
 `llvm.ptrmask`

Logic basically copies 'and' but we can't return a constant if the
result == `rhs` (mask) so that case is skipped.

Differential Revision: https://reviews.llvm.org/D156637
---
 .../InstCombine/InstCombineCalls.cpp          |  5 +-
 .../InstCombine/InstCombineInternal.h         |  1 +
 .../InstCombineSimplifyDemanded.cpp           | 71 +++++++++++++++++--
 .../test/Transforms/InstCombine/align-addr.ll |  2 +-
 .../InstCombine/consecutive-ptrmask.ll        |  2 +-
 llvm/test/Transforms/InstCombine/ptrmask.ll   | 28 +++-----
 6 files changed, 81 insertions(+), 28 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 7289545d453bfc1..bca90f4a8f8a2e4 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1963,6 +1963,10 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
   }
   case Intrinsic::ptrmask: {
     unsigned BitWidth = DL.getPointerTypeSizeInBits(II->getType());
+    KnownBits Known(BitWidth);
+    if (SimplifyDemandedInstructionBits(*II, Known))
+      return II;
+
     Value *InnerPtr, *InnerMask;
     if (match(II->getArgOperand(0),
               m_OneUse(m_Intrinsic<Intrinsic::ptrmask>(m_Value(InnerPtr),
@@ -1976,7 +1980,6 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       }
     }
     bool Changed = false;
-    KnownBits Known = computeKnownBits(II, /*Depth*/ 0, II);
     // See if we can deduce non-null.
     if (!CI.hasRetAttr(Attribute::NonNull) &&
         (Known.isNonZero() ||
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 7337cd7caec99c0..9fa24746a06abc5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -543,6 +543,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
   /// Tries to simplify operands to an integer instruction based on its
   /// demanded bits.
   bool SimplifyDemandedInstructionBits(Instruction &Inst);
+  bool SimplifyDemandedInstructionBits(Instruction &Inst, KnownBits &Known);
 
   Value *SimplifyDemandedVectorElts(Value *V, APInt DemandedElts,
                                     APInt &UndefElts, unsigned Depth = 0,
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 5b5d2da041f1447..c4fe1ed4abdf178 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -48,15 +48,20 @@ static bool ShrinkDemandedConstant(Instruction *I, unsigned OpNo,
   return true;
 }
 
+/// Returns the bitwidth of the given scalar or pointer type. For vector types,
+/// returns the element type's bitwidth.
+static unsigned getBitWidth(Type *Ty, const DataLayout &DL) {
+  if (unsigned BitWidth = Ty->getScalarSizeInBits())
+    return BitWidth;
 
+  return DL.getPointerTypeSizeInBits(Ty);
+}
 
 /// Inst is an integer instruction that SimplifyDemandedBits knows about. See if
 /// the instruction has any properties that allow us to simplify its operands.
-bool InstCombinerImpl::SimplifyDemandedInstructionBits(Instruction &Inst) {
-  unsigned BitWidth = Inst.getType()->getScalarSizeInBits();
-  KnownBits Known(BitWidth);
-  APInt DemandedMask(APInt::getAllOnes(BitWidth));
-
+bool InstCombinerImpl::SimplifyDemandedInstructionBits(Instruction &Inst,
+                                                       KnownBits &Known) {
+  APInt DemandedMask(APInt::getAllOnes(Known.getBitWidth()));
   Value *V = SimplifyDemandedUseBits(&Inst, DemandedMask, Known,
                                      0, &Inst);
   if (!V) return false;
@@ -65,6 +70,13 @@ bool InstCombinerImpl::SimplifyDemandedInstructionBits(Instruction &Inst) {
   return true;
 }
 
+/// Inst is an integer instruction that SimplifyDemandedBits knows about. See if
+/// the instruction has any properties that allow us to simplify its operands.
+bool InstCombinerImpl::SimplifyDemandedInstructionBits(Instruction &Inst) {
+  KnownBits Known(getBitWidth(Inst.getType(), DL));
+  return SimplifyDemandedInstructionBits(Inst, Known);
+}
+
 /// This form of SimplifyDemandedBits simplifies the specified instruction
 /// operand if possible, updating it in place. It returns true if it made any
 /// change and false otherwise.
@@ -143,7 +155,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
     return SimplifyMultipleUseDemandedBits(I, DemandedMask, Known, Depth, CxtI);
 
   KnownBits LHSKnown(BitWidth), RHSKnown(BitWidth);
-
+  bool MaySimplifyAsConstant = true;
   // If this is the root being simplified, allow it to have multiple uses,
   // just set the DemandedMask to all bits so that we can try to simplify the
   // operands.  This allows visitTruncInst (for example) to simplify the
@@ -900,6 +912,51 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
         }
         break;
       }
+      case Intrinsic::ptrmask: {
+        // We can't simplify `llvm.ptrmask` as a constant because of pointer
+        // provanance.
+        MaySimplifyAsConstant = false;
+
+        unsigned MaskWidth = I->getOperand(1)->getType()->getScalarSizeInBits();
+        RHSKnown = KnownBits(MaskWidth);
+        // If either the LHS or the RHS are Zero, the result is zero.
+        if (SimplifyDemandedBits(I, 0, DemandedMask, LHSKnown, Depth + 1) ||
+            SimplifyDemandedBits(
+                I, 1, (DemandedMask & ~LHSKnown.Zero).zextOrTrunc(MaskWidth),
+                RHSKnown, Depth + 1))
+          return I;
+
+        RHSKnown = RHSKnown.zextOrTrunc(BitWidth);
+        assert(!RHSKnown.hasConflict() && "Bits known to be one AND zero?");
+        assert(!LHSKnown.hasConflict() && "Bits known to be one AND zero?");
+
+        Known = LHSKnown & RHSKnown;
+        KnownBitsComputed = true;
+
+        // If the client is only demanding bits we know to be zero, return
+        // `llvm.ptrmask(p, 0)`. We can't return `null` here due to pointer
+        // provenance, but making the mask zero will be easily optimizable in
+        // the backend.
+        if (DemandedMask.isSubsetOf(Known.Zero) &&
+            !match(I->getOperand(1), m_Zero()))
+          return replaceOperand(
+              *I, 1, Constant::getNullValue(I->getOperand(1)->getType()));
+
+        // Mask in demanded space does nothing.
+        // NOTE: We may have attributes associated with the return value of the
+        // llvm.ptrmask intrinsic that will be lost when we just return the
+        // operand. We should try to preserve them.
+        if (DemandedMask.isSubsetOf(RHSKnown.One | LHSKnown.Zero))
+          return I->getOperand(0);
+
+        // If the RHS is a constant, see if we can simplify it.
+        if (ShrinkDemandedConstant(
+                I, 1, (DemandedMask & ~LHSKnown.Zero).zextOrTrunc(MaskWidth)))
+          return I;
+
+        break;
+      }
+
       case Intrinsic::fshr:
       case Intrinsic::fshl: {
         const APInt *SA;
@@ -986,7 +1043,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
 
   // If the client is only demanding bits that we know, return the known
   // constant.
-  if (DemandedMask.isSubsetOf(Known.Zero|Known.One))
+  if (MaySimplifyAsConstant && DemandedMask.isSubsetOf(Known.Zero | Known.One))
     return Constant::getIntegerValue(VTy, Known.One);
   return nullptr;
 }
diff --git a/llvm/test/Transforms/InstCombine/align-addr.ll b/llvm/test/Transforms/InstCombine/align-addr.ll
index 57bb8a2df03ef09..753dc065abc46f3 100644
--- a/llvm/test/Transforms/InstCombine/align-addr.ll
+++ b/llvm/test/Transforms/InstCombine/align-addr.ll
@@ -221,7 +221,7 @@ define <16 x i8> @ptrmask_align8_ptr_align1_smallmask(ptr align 1 %ptr) {
 ; than the pointer size.
 define <16 x i8> @ptrmask_align8_ptr_align1_bigmask(ptr align 1 %ptr) {
 ; CHECK-LABEL: @ptrmask_align8_ptr_align1_bigmask(
-; CHECK-NEXT:    [[ALIGNED:%.*]] = call align 8 ptr @llvm.ptrmask.p0.i128(ptr [[PTR:%.*]], i128 -8)
+; CHECK-NEXT:    [[ALIGNED:%.*]] = call align 8 ptr @llvm.ptrmask.p0.i128(ptr [[PTR:%.*]], i128 18446744073709551608)
 ; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 1
 ; CHECK-NEXT:    ret <16 x i8> [[LOAD]]
 ;
diff --git a/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll b/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll
index c714516b34aa297..5ff0d48e8175ddc 100644
--- a/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll
+++ b/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll
@@ -109,7 +109,7 @@ define ptr @fold_2x_type_mismatch_const2(ptr %p) {
 ; CHECK-LABEL: define ptr @fold_2x_type_mismatch_const2
 ; CHECK-SAME: (ptr [[P:%.*]]) {
 ; CHECK-NEXT:    [[P0:%.*]] = call align 4 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -4)
-; CHECK-NEXT:    [[P1:%.*]] = call align 32 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 -31)
+; CHECK-NEXT:    [[P1:%.*]] = call align 32 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 4294967264)
 ; CHECK-NEXT:    ret ptr [[P1]]
 ;
   %p0 = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -4)
diff --git a/llvm/test/Transforms/InstCombine/ptrmask.ll b/llvm/test/Transforms/InstCombine/ptrmask.ll
index 865e6581f4eb41a..d7977d9835e1e11 100644
--- a/llvm/test/Transforms/InstCombine/ptrmask.ll
+++ b/llvm/test/Transforms/InstCombine/ptrmask.ll
@@ -80,7 +80,7 @@ define ptr @ptrmask_combine_add_nonnull(ptr %p) {
 ; CHECK-SAME: (ptr [[P:%.*]]) {
 ; CHECK-NEXT:    [[PM0:%.*]] = call align 64 ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -64)
 ; CHECK-NEXT:    [[PGEP:%.*]] = getelementptr i8, ptr [[PM0]], i64 33
-; CHECK-NEXT:    [[R:%.*]] = call nonnull align 32 ptr @llvm.ptrmask.p0.i64(ptr [[PGEP]], i64 -16)
+; CHECK-NEXT:    [[R:%.*]] = call nonnull align 32 ptr @llvm.ptrmask.p0.i64(ptr [[PGEP]], i64 -32)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %pm0 = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -64)
@@ -228,7 +228,7 @@ define <2 x i32> @ptrtoint_of_ptrmask_vec_fail(<2 x ptr> %p, <2 x i32> %m) {
 define ptr @ptrmask_is_null(ptr align 32 %p) {
 ; CHECK-LABEL: define ptr @ptrmask_is_null
 ; CHECK-SAME: (ptr align 32 [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call align 4294967296 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 31)
+; CHECK-NEXT:    [[R:%.*]] = call align 4294967296 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 0)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 31)
@@ -248,7 +248,7 @@ define <2 x ptr> @ptrmask_is_null_vec(<2 x ptr> align 64 %p) {
 define ptr @ptrmask_is_null_fail(ptr align 16 %p) {
 ; CHECK-LABEL: define ptr @ptrmask_is_null_fail
 ; CHECK-SAME: (ptr align 16 [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call align 16 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 31)
+; CHECK-NEXT:    [[R:%.*]] = call align 16 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 16)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 31)
@@ -288,10 +288,9 @@ define ptr @ptrmask_maintain_provenance_i32(ptr %p0) {
 define ptr @ptrmask_is_useless0(i64 %i, i64 %m) {
 ; CHECK-LABEL: define ptr @ptrmask_is_useless0
 ; CHECK-SAME: (i64 [[I:%.*]], i64 [[M:%.*]]) {
-; CHECK-NEXT:    [[M0:%.*]] = and i64 [[M]], -4
 ; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], -4
 ; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
-; CHECK-NEXT:    [[R:%.*]] = call align 4 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
+; CHECK-NEXT:    [[R:%.*]] = call align 4 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M]])
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %m0 = and i64 %m, -4
@@ -304,10 +303,9 @@ define ptr @ptrmask_is_useless0(i64 %i, i64 %m) {
 define ptr @ptrmask_is_useless1(i64 %i, i64 %m) {
 ; CHECK-LABEL: define ptr @ptrmask_is_useless1
 ; CHECK-SAME: (i64 [[I:%.*]], i64 [[M:%.*]]) {
-; CHECK-NEXT:    [[M0:%.*]] = and i64 [[M]], -4
 ; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], -8
 ; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
-; CHECK-NEXT:    [[R:%.*]] = call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
+; CHECK-NEXT:    [[R:%.*]] = call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M]])
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %m0 = and i64 %m, -4
@@ -320,10 +318,9 @@ define ptr @ptrmask_is_useless1(i64 %i, i64 %m) {
 define ptr @ptrmask_is_useless2(i64 %i, i64 %m) {
 ; CHECK-LABEL: define ptr @ptrmask_is_useless2
 ; CHECK-SAME: (i64 [[I:%.*]], i64 [[M:%.*]]) {
-; CHECK-NEXT:    [[M0:%.*]] = and i64 [[M]], 127
 ; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], 31
 ; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M]])
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %m0 = and i64 %m, 127
@@ -336,10 +333,9 @@ define ptr @ptrmask_is_useless2(i64 %i, i64 %m) {
 define ptr @ptrmask_is_useless3(i64 %i, i64 %m) {
 ; CHECK-LABEL: define ptr @ptrmask_is_useless3
 ; CHECK-SAME: (i64 [[I:%.*]], i64 [[M:%.*]]) {
-; CHECK-NEXT:    [[M0:%.*]] = and i64 [[M]], 127
 ; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], 127
 ; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
-; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
+; CHECK-NEXT:    [[R:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M]])
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %m0 = and i64 %m, 127
@@ -352,11 +348,9 @@ define ptr @ptrmask_is_useless3(i64 %i, i64 %m) {
 define ptr @ptrmask_is_useless4(i64 %i, i64 %m) {
 ; CHECK-LABEL: define ptr @ptrmask_is_useless4
 ; CHECK-SAME: (i64 [[I:%.*]], i64 [[M:%.*]]) {
-; CHECK-NEXT:    [[M0:%.*]] = or i64 [[M]], -4
 ; CHECK-NEXT:    [[I0:%.*]] = and i64 [[I]], -4
 ; CHECK-NEXT:    [[P0:%.*]] = inttoptr i64 [[I0]] to ptr
-; CHECK-NEXT:    [[R:%.*]] = call align 4 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[M0]])
-; CHECK-NEXT:    ret ptr [[R]]
+; CHECK-NEXT:    ret ptr [[P0]]
 ;
   %m0 = or i64 %m, -4
   %i0 = and i64 %i, -4
@@ -368,10 +362,9 @@ define ptr @ptrmask_is_useless4(i64 %i, i64 %m) {
 define <2 x ptr> @ptrmask_is_useless_vec(<2 x i64> %i, <2 x i64> %m) {
 ; CHECK-LABEL: define <2 x ptr> @ptrmask_is_useless_vec
 ; CHECK-SAME: (<2 x i64> [[I:%.*]], <2 x i64> [[M:%.*]]) {
-; CHECK-NEXT:    [[M0:%.*]] = and <2 x i64> [[M]], <i64 127, i64 127>
 ; CHECK-NEXT:    [[I0:%.*]] = and <2 x i64> [[I]], <i64 31, i64 31>
 ; CHECK-NEXT:    [[P0:%.*]] = inttoptr <2 x i64> [[I0]] to <2 x ptr>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P0]], <2 x i64> [[M0]])
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P0]], <2 x i64> [[M]])
 ; CHECK-NEXT:    ret <2 x ptr> [[R]]
 ;
   %m0 = and <2 x i64> %m, <i64 127, i64 127>
@@ -384,10 +377,9 @@ define <2 x ptr> @ptrmask_is_useless_vec(<2 x i64> %i, <2 x i64> %m) {
 define <2 x ptr> @ptrmask_is_useless_vec_todo(<2 x i64> %i, <2 x i64> %m) {
 ; CHECK-LABEL: define <2 x ptr> @ptrmask_is_useless_vec_todo
 ; CHECK-SAME: (<2 x i64> [[I:%.*]], <2 x i64> [[M:%.*]]) {
-; CHECK-NEXT:    [[M0:%.*]] = and <2 x i64> [[M]], <i64 127, i64 127>
 ; CHECK-NEXT:    [[I0:%.*]] = and <2 x i64> [[I]], <i64 31, i64 127>
 ; CHECK-NEXT:    [[P0:%.*]] = inttoptr <2 x i64> [[I0]] to <2 x ptr>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P0]], <2 x i64> [[M0]])
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P0]], <2 x i64> [[M]])
 ; CHECK-NEXT:    ret <2 x ptr> [[R]]
 ;
   %m0 = and <2 x i64> %m, <i64 127, i64 127>

>From 17b9abe67416bc1c2390d21edbd2b99cecfe2ade Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Sun, 24 Sep 2023 12:30:05 -0500
Subject: [PATCH 6/8] [InstCombine] Canonicalize `ptrmask(p,C)` ->
 `ptrmask(p,(zext/trunc C))` if Width(C) != Width(P)

This enables more merging and generally its convenient to have same
width for mask/ptr.
---
 .../InstCombine/InstCombineCalls.cpp          | 15 ++++++++++++++
 .../test/Transforms/InstCombine/align-addr.ll |  4 ++--
 .../InstCombine/consecutive-ptrmask.ll        | 15 +++++++-------
 llvm/test/Transforms/InstCombine/ptrmask.ll   | 20 +++++++++----------
 4 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index bca90f4a8f8a2e4..c0a1e3f06364beb 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1967,6 +1967,21 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     if (SimplifyDemandedInstructionBits(*II, Known))
       return II;
 
+    Value *Op0 = II->getArgOperand(0);
+    Value *Op1 = II->getArgOperand(1);
+
+    if (BitWidth != Op1->getType()->getScalarSizeInBits() &&
+        match(Op1, m_ImmConstant())) {
+
+      Value *NewMask = Builder.CreateZExtOrTrunc(
+          Op1, Op1->getType()->getWithNewBitWidth(BitWidth));
+      CallBase *NewCI = cast<CallBase>(replaceInstUsesWith(
+          *II, Builder.CreateIntrinsic(II->getType(), Intrinsic::ptrmask,
+                                       {Op0, NewMask})));
+      NewCI->setAttributes(CI.getAttributes());
+      return NewCI;
+    }
+
     Value *InnerPtr, *InnerMask;
     if (match(II->getArgOperand(0),
               m_OneUse(m_Intrinsic<Intrinsic::ptrmask>(m_Value(InnerPtr),
diff --git a/llvm/test/Transforms/InstCombine/align-addr.ll b/llvm/test/Transforms/InstCombine/align-addr.ll
index 753dc065abc46f3..15a22560ba30c5e 100644
--- a/llvm/test/Transforms/InstCombine/align-addr.ll
+++ b/llvm/test/Transforms/InstCombine/align-addr.ll
@@ -208,7 +208,7 @@ define <16 x i8> @ptrmask_align8_ptr_align16(ptr align 16 %ptr) {
 ; than the pointer size.
 define <16 x i8> @ptrmask_align8_ptr_align1_smallmask(ptr align 1 %ptr) {
 ; CHECK-LABEL: @ptrmask_align8_ptr_align1_smallmask(
-; CHECK-NEXT:    [[ALIGNED:%.*]] = call align 8 ptr @llvm.ptrmask.p0.i32(ptr [[PTR:%.*]], i32 -8)
+; CHECK-NEXT:    [[ALIGNED:%.*]] = call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[PTR:%.*]], i64 4294967288)
 ; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 1
 ; CHECK-NEXT:    ret <16 x i8> [[LOAD]]
 ;
@@ -221,7 +221,7 @@ define <16 x i8> @ptrmask_align8_ptr_align1_smallmask(ptr align 1 %ptr) {
 ; than the pointer size.
 define <16 x i8> @ptrmask_align8_ptr_align1_bigmask(ptr align 1 %ptr) {
 ; CHECK-LABEL: @ptrmask_align8_ptr_align1_bigmask(
-; CHECK-NEXT:    [[ALIGNED:%.*]] = call align 8 ptr @llvm.ptrmask.p0.i128(ptr [[PTR:%.*]], i128 18446744073709551608)
+; CHECK-NEXT:    [[ALIGNED:%.*]] = call align 8 ptr @llvm.ptrmask.p0.i64(ptr [[PTR:%.*]], i64 -8)
 ; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 1
 ; CHECK-NEXT:    ret <16 x i8> [[LOAD]]
 ;
diff --git a/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll b/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll
index 5ff0d48e8175ddc..ca4d6b16d929753 100644
--- a/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll
+++ b/llvm/test/Transforms/InstCombine/consecutive-ptrmask.ll
@@ -96,8 +96,8 @@ define ptr @fold_2x_type_mismatch_const0(ptr %p, i32 %m1) {
 define ptr @fold_2x_type_mismatch_const1(ptr %p, i64 %m0) {
 ; CHECK-LABEL: define ptr @fold_2x_type_mismatch_const1
 ; CHECK-SAME: (ptr [[P:%.*]], i64 [[M0:%.*]]) {
-; CHECK-NEXT:    [[P0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 [[M0]])
-; CHECK-NEXT:    [[P1:%.*]] = call align 2 ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 -2)
+; CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[M0]], 4294967294
+; CHECK-NEXT:    [[P1:%.*]] = call align 2 ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 [[TMP1]])
 ; CHECK-NEXT:    ret ptr [[P1]]
 ;
   %p0 = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 %m0)
@@ -108,8 +108,7 @@ define ptr @fold_2x_type_mismatch_const1(ptr %p, i64 %m0) {
 define ptr @fold_2x_type_mismatch_const2(ptr %p) {
 ; CHECK-LABEL: define ptr @fold_2x_type_mismatch_const2
 ; CHECK-SAME: (ptr [[P:%.*]]) {
-; CHECK-NEXT:    [[P0:%.*]] = call align 4 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -4)
-; CHECK-NEXT:    [[P1:%.*]] = call align 32 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 4294967264)
+; CHECK-NEXT:    [[P1:%.*]] = call align 32 ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 4294967264)
 ; CHECK-NEXT:    ret ptr [[P1]]
 ;
   %p0 = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -4)
@@ -120,8 +119,8 @@ define ptr @fold_2x_type_mismatch_const2(ptr %p) {
 define <2 x ptr> @fold_2x_type_mismatch_const_vec(<2 x ptr> %p, <2 x i64> %m0) {
 ; CHECK-LABEL: define <2 x ptr> @fold_2x_type_mismatch_const_vec
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]], <2 x i64> [[M0:%.*]]) {
-; CHECK-NEXT:    [[P0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> [[M0]])
-; CHECK-NEXT:    [[P1:%.*]] = call align 2 <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P0]], <2 x i32> <i32 -2, i32 -2>)
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i64> [[M0]], <i64 4294967294, i64 4294967294>
+; CHECK-NEXT:    [[P1:%.*]] = call align 2 <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> [[TMP1]])
 ; CHECK-NEXT:    ret <2 x ptr> [[P1]]
 ;
   %p0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> %m0)
@@ -132,8 +131,8 @@ define <2 x ptr> @fold_2x_type_mismatch_const_vec(<2 x ptr> %p, <2 x i64> %m0) {
 define <2 x ptr> @fold_2x_type_mismatch_const_vec_with_undef(<2 x ptr> %p, <2 x i64> %m0) {
 ; CHECK-LABEL: define <2 x ptr> @fold_2x_type_mismatch_const_vec_with_undef
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]], <2 x i64> [[M0:%.*]]) {
-; CHECK-NEXT:    [[P0:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> [[M0]])
-; CHECK-NEXT:    [[P1:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P0]], <2 x i32> <i32 -2, i32 undef>)
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i64> [[M0]], <i64 4294967294, i64 0>
+; CHECK-NEXT:    [[P1:%.*]] = call align 2 <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> [[TMP1]])
 ; CHECK-NEXT:    ret <2 x ptr> [[P1]]
 ;
   %p0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> %m0)
diff --git a/llvm/test/Transforms/InstCombine/ptrmask.ll b/llvm/test/Transforms/InstCombine/ptrmask.ll
index d7977d9835e1e11..0bb63d096dd8004 100644
--- a/llvm/test/Transforms/InstCombine/ptrmask.ll
+++ b/llvm/test/Transforms/InstCombine/ptrmask.ll
@@ -67,7 +67,7 @@ define ptr @ptrmask_combine_consecutive_preserve_attrs_todo1(ptr %p0) {
 define ptr @ptrmask_combine_consecutive_preserve_attrs_todo2(ptr %p0) {
 ; CHECK-LABEL: define ptr @ptrmask_combine_consecutive_preserve_attrs_todo2
 ; CHECK-SAME: (ptr [[P0:%.*]]) {
-; CHECK-NEXT:    [[PM0:%.*]] = call noalias align 32 ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 224)
+; CHECK-NEXT:    [[PM0:%.*]] = call align 32 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 224)
 ; CHECK-NEXT:    ret ptr [[PM0]]
 ;
   %pm0 = call noalias ptr @llvm.ptrmask.p0.i32(ptr %p0, i32 224)
@@ -102,7 +102,7 @@ define ptr @ptrmask_combine_add_alignment(ptr %p) {
 define ptr @ptrmask_combine_add_alignment2(ptr align 32 %p) {
 ; CHECK-LABEL: define ptr @ptrmask_combine_add_alignment2
 ; CHECK-SAME: (ptr align 32 [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call align 64 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -64)
+; CHECK-NEXT:    [[R:%.*]] = call align 64 ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 4294967232)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -64)
@@ -122,7 +122,7 @@ define <2 x ptr> @ptrmask_combine_add_alignment_vec(<2 x ptr> %p) {
 define ptr @ptrmask_combine_improve_alignment(ptr %p) {
 ; CHECK-LABEL: define ptr @ptrmask_combine_improve_alignment
 ; CHECK-SAME: (ptr [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call align 64 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -64)
+; CHECK-NEXT:    [[R:%.*]] = call align 64 ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 4294967232)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call align 32 ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -64)
@@ -132,7 +132,7 @@ define ptr @ptrmask_combine_improve_alignment(ptr %p) {
 define <2 x ptr> @ptrmask_combine_improve_alignment_vec(<2 x ptr> %p) {
 ; CHECK-LABEL: define <2 x ptr> @ptrmask_combine_improve_alignment_vec
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call align 64 <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P]], <2 x i32> <i32 -64, i32 -128>)
+; CHECK-NEXT:    [[R:%.*]] = call align 64 <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 4294967232, i64 4294967168>)
 ; CHECK-NEXT:    ret <2 x ptr> [[R]]
 ;
   %r = call align 32 <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p, <2 x i32> <i32 -64, i32 -128>)
@@ -142,7 +142,7 @@ define <2 x ptr> @ptrmask_combine_improve_alignment_vec(<2 x ptr> %p) {
 define ptr @ptrmask_combine_improve_alignment_fail(ptr %p) {
 ; CHECK-LABEL: define ptr @ptrmask_combine_improve_alignment_fail
 ; CHECK-SAME: (ptr [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call align 128 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 -64)
+; CHECK-NEXT:    [[R:%.*]] = call align 64 ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 4294967232)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call align 128 ptr @llvm.ptrmask.p0.i32(ptr %p, i32 -64)
@@ -228,7 +228,7 @@ define <2 x i32> @ptrtoint_of_ptrmask_vec_fail(<2 x ptr> %p, <2 x i32> %m) {
 define ptr @ptrmask_is_null(ptr align 32 %p) {
 ; CHECK-LABEL: define ptr @ptrmask_is_null
 ; CHECK-SAME: (ptr align 32 [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call align 4294967296 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 0)
+; CHECK-NEXT:    [[R:%.*]] = call align 4294967296 ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 0)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 31)
@@ -238,7 +238,7 @@ define ptr @ptrmask_is_null(ptr align 32 %p) {
 define <2 x ptr> @ptrmask_is_null_vec(<2 x ptr> align 64 %p) {
 ; CHECK-LABEL: define <2 x ptr> @ptrmask_is_null_vec
 ; CHECK-SAME: (<2 x ptr> align 64 [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P]], <2 x i32> <i32 31, i32 63>)
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 31, i64 63>)
 ; CHECK-NEXT:    ret <2 x ptr> [[R]]
 ;
   %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p, <2 x i32> <i32 31, i32 63>)
@@ -248,7 +248,7 @@ define <2 x ptr> @ptrmask_is_null_vec(<2 x ptr> align 64 %p) {
 define ptr @ptrmask_is_null_fail(ptr align 16 %p) {
 ; CHECK-LABEL: define ptr @ptrmask_is_null_fail
 ; CHECK-SAME: (ptr align 16 [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call align 16 ptr @llvm.ptrmask.p0.i32(ptr [[P]], i32 16)
+; CHECK-NEXT:    [[R:%.*]] = call align 16 ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 16)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i32(ptr %p, i32 31)
@@ -258,7 +258,7 @@ define ptr @ptrmask_is_null_fail(ptr align 16 %p) {
 define <2 x ptr> @ptrmask_is_null_vec_fail(<2 x ptr> align 32 %p) {
 ; CHECK-LABEL: define <2 x ptr> @ptrmask_is_null_vec_fail
 ; CHECK-SAME: (<2 x ptr> align 32 [[P:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> [[P]], <2 x i32> <i32 31, i32 63>)
+; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> <i64 31, i64 63>)
 ; CHECK-NEXT:    ret <2 x ptr> [[R]]
 ;
   %r = call <2 x ptr> @llvm.ptrmask.v2p0.v2i32(<2 x ptr> %p, <2 x i32> <i32 31, i32 63>)
@@ -278,7 +278,7 @@ define ptr @ptrmask_maintain_provenance_i64(ptr %p0) {
 define ptr @ptrmask_maintain_provenance_i32(ptr %p0) {
 ; CHECK-LABEL: define ptr @ptrmask_maintain_provenance_i32
 ; CHECK-SAME: (ptr [[P0:%.*]]) {
-; CHECK-NEXT:    [[R:%.*]] = call align 4294967296 ptr @llvm.ptrmask.p0.i32(ptr [[P0]], i32 0)
+; CHECK-NEXT:    [[R:%.*]] = call align 4294967296 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 0)
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %r = call ptr @llvm.ptrmask.p0.i32(ptr %p0, i32 0)

>From 63fb763dadf5b26dd6fa4e6c08ee82b5125d370f Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 22 Sep 2023 08:21:53 -0500
Subject: [PATCH 7/8] [InstCombine] Preserve return attributes when merging
 `llvm.ptrmask`

If we have assosiated attributes i.e `([ret_attrs] (ptrmask (ptrmask
p0, m0), m1))` we should preserve `[ret_attrs]` when combining the two
`llvm.ptrmask`s.

Differential Revision: https://reviews.llvm.org/D156638
---
 .../InstCombine/InstCombineCalls.cpp          | 24 +++++++++++--------
 llvm/test/Transforms/InstCombine/ptrmask.ll   |  4 ++--
 2 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index c0a1e3f06364beb..54d715970156893 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1983,18 +1983,22 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     }
 
     Value *InnerPtr, *InnerMask;
-    if (match(II->getArgOperand(0),
-              m_OneUse(m_Intrinsic<Intrinsic::ptrmask>(m_Value(InnerPtr),
-                                                       m_Value(InnerMask))))) {
-      if (II->getArgOperand(1)->getType() == InnerMask->getType()) {
-        Value *NewMask = Builder.CreateAnd(II->getArgOperand(1), InnerMask);
-        return replaceInstUsesWith(
-            *II,
-            Builder.CreateIntrinsic(InnerPtr->getType(), Intrinsic::ptrmask,
-                                    {InnerPtr, NewMask}));
+    bool Changed = false;
+    // Combine:
+    // (ptrmask (ptrmask p, A), B)
+    //    -> (ptrmask p, (and A, B))
+    if (match(Op0, m_OneUse(m_Intrinsic<Intrinsic::ptrmask>(
+                       m_Value(InnerPtr), m_Value(InnerMask))))) {
+      if (InnerMask->getType() == Op1->getType()) {
+        // TODO: If InnerMask == Op1, we could copy attributes from inner
+        // callsite -> outer callsite.
+        Value *NewMask = Builder.CreateAnd(Op1, InnerMask);
+        replaceOperand(CI, 0, InnerPtr);
+        replaceOperand(CI, 1, NewMask);
+        Changed = true;
       }
     }
-    bool Changed = false;
+
     // See if we can deduce non-null.
     if (!CI.hasRetAttr(Attribute::NonNull) &&
         (Known.isNonZero() ||
diff --git a/llvm/test/Transforms/InstCombine/ptrmask.ll b/llvm/test/Transforms/InstCombine/ptrmask.ll
index 0bb63d096dd8004..413c790bc1faec3 100644
--- a/llvm/test/Transforms/InstCombine/ptrmask.ll
+++ b/llvm/test/Transforms/InstCombine/ptrmask.ll
@@ -10,7 +10,7 @@ define ptr @ptrmask_combine_consecutive_preserve_attrs(ptr %p0, i64 %m1) {
 ; CHECK-LABEL: define ptr @ptrmask_combine_consecutive_preserve_attrs
 ; CHECK-SAME: (ptr [[P0:%.*]], i64 [[M1:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[M1]], 224
-; CHECK-NEXT:    [[R:%.*]] = call align 32 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[TMP1]])
+; CHECK-NEXT:    [[R:%.*]] = call noalias align 32 ptr @llvm.ptrmask.p0.i64(ptr [[P0]], i64 [[TMP1]])
 ; CHECK-NEXT:    ret ptr [[R]]
 ;
   %pm0 = call ptr @llvm.ptrmask.p0.i64(ptr %p0, i64 224)
@@ -22,7 +22,7 @@ define <2 x ptr> @ptrmask_combine_consecutive_preserve_attrs_vecs(<2 x ptr> %p0,
 ; CHECK-LABEL: define <2 x ptr> @ptrmask_combine_consecutive_preserve_attrs_vecs
 ; CHECK-SAME: (<2 x ptr> [[P0:%.*]], <2 x i64> [[M1:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i64> [[M1]], <i64 12345, i64 12345>
-; CHECK-NEXT:    [[R:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P0]], <2 x i64> [[TMP1]])
+; CHECK-NEXT:    [[R:%.*]] = call align 128 <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P0]], <2 x i64> [[TMP1]])
 ; CHECK-NEXT:    ret <2 x ptr> [[R]]
 ;
   %pm0 = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p0, <2 x i64> <i64 12345, i64 12345>)

>From a0f2ce22e11534c5a498149e5d139194baf5a51a Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 22 Sep 2023 08:22:01 -0500
Subject: [PATCH 8/8] [InstCombine] Fold `(ptrtoint (ptrmask p0, m0))` -> `(and
 (ptrtoint p0), m0)`

`and` is generally more supported so if we have a `ptrmask` anyways
might as well use `and`.

Differential Revision: https://reviews.llvm.org/D156640
---
 .../InstCombine/InstCombineCasts.cpp          |  9 +++++++++
 llvm/test/Transforms/InstCombine/ptrmask.ll   | 20 +++++++++----------
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 20c13de33f8189d..7f5d851693a1dd9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1957,6 +1957,15 @@ Instruction *InstCombinerImpl::visitPtrToInt(PtrToIntInst &CI) {
     return CastInst::CreateIntegerCast(P, Ty, /*isSigned=*/false);
   }
 
+  // (ptrtoint (ptrmask P, M))
+  //    -> (and (ptrtoint P), M)
+  // This is generally beneficial as `and` is better supported than `ptrmask`.
+  Value *Ptr, *Mask;
+  if (match(SrcOp, m_OneUse(m_Intrinsic<Intrinsic::ptrmask>(m_Value(Ptr),
+                                                            m_Value(Mask)))) &&
+      Mask->getType() == Ty)
+    return BinaryOperator::CreateAnd(Builder.CreatePtrToInt(Ptr, Ty), Mask);
+
   if (auto *GEP = dyn_cast<GetElementPtrInst>(SrcOp)) {
     // Fold ptrtoint(gep null, x) to multiply + constant if the GEP has one use.
     // While this can increase the number of instructions it doesn't actually
diff --git a/llvm/test/Transforms/InstCombine/ptrmask.ll b/llvm/test/Transforms/InstCombine/ptrmask.ll
index 413c790bc1faec3..304fd69e91926ea 100644
--- a/llvm/test/Transforms/InstCombine/ptrmask.ll
+++ b/llvm/test/Transforms/InstCombine/ptrmask.ll
@@ -152,8 +152,8 @@ define ptr @ptrmask_combine_improve_alignment_fail(ptr %p) {
 define i64 @ptrtoint_of_ptrmask(ptr %p, i64 %m) {
 ; CHECK-LABEL: define i64 @ptrtoint_of_ptrmask
 ; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) {
-; CHECK-NEXT:    [[PM:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 [[M]])
-; CHECK-NEXT:    [[R:%.*]] = ptrtoint ptr [[PM]] to i64
+; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[P]] to i64
+; CHECK-NEXT:    [[R:%.*]] = and i64 [[TMP1]], [[M]]
 ; CHECK-NEXT:    ret i64 [[R]]
 ;
   %pm = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 %m)
@@ -165,9 +165,9 @@ define i64 @ptrtoint_of_ptrmask(ptr %p, i64 %m) {
 define i32 @ptrtoint_of_ptrmask2(ptr %p, i64 %m) {
 ; CHECK-LABEL: define i32 @ptrtoint_of_ptrmask2
 ; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) {
-; CHECK-NEXT:    [[PM:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 [[M]])
-; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[PM]] to i64
-; CHECK-NEXT:    [[R:%.*]] = trunc i64 [[TMP1]] to i32
+; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[P]] to i64
+; CHECK-NEXT:    [[TMP2:%.*]] = and i64 [[TMP1]], [[M]]
+; CHECK-NEXT:    [[R:%.*]] = trunc i64 [[TMP2]] to i32
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %pm = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 %m)
@@ -178,8 +178,8 @@ define i32 @ptrtoint_of_ptrmask2(ptr %p, i64 %m) {
 define <2 x i64> @ptrtoint_of_ptrmask_vec(<2 x ptr> %p, <2 x i64> %m) {
 ; CHECK-LABEL: define <2 x i64> @ptrtoint_of_ptrmask_vec
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]], <2 x i64> [[M:%.*]]) {
-; CHECK-NEXT:    [[PM:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> [[M]])
-; CHECK-NEXT:    [[R:%.*]] = ptrtoint <2 x ptr> [[PM]] to <2 x i64>
+; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint <2 x ptr> [[P]] to <2 x i64>
+; CHECK-NEXT:    [[R:%.*]] = and <2 x i64> [[TMP1]], [[M]]
 ; CHECK-NEXT:    ret <2 x i64> [[R]]
 ;
   %pm = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> %m)
@@ -190,9 +190,9 @@ define <2 x i64> @ptrtoint_of_ptrmask_vec(<2 x ptr> %p, <2 x i64> %m) {
 define <2 x i32> @ptrtoint_of_ptrmask_vec2(<2 x ptr> %p, <2 x i64> %m) {
 ; CHECK-LABEL: define <2 x i32> @ptrtoint_of_ptrmask_vec2
 ; CHECK-SAME: (<2 x ptr> [[P:%.*]], <2 x i64> [[M:%.*]]) {
-; CHECK-NEXT:    [[PM:%.*]] = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> [[P]], <2 x i64> [[M]])
-; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint <2 x ptr> [[PM]] to <2 x i64>
-; CHECK-NEXT:    [[R:%.*]] = trunc <2 x i64> [[TMP1]] to <2 x i32>
+; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint <2 x ptr> [[P]] to <2 x i64>
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i64> [[TMP1]], [[M]]
+; CHECK-NEXT:    [[R:%.*]] = trunc <2 x i64> [[TMP2]] to <2 x i32>
 ; CHECK-NEXT:    ret <2 x i32> [[R]]
 ;
   %pm = call <2 x ptr> @llvm.ptrmask.v2p0.v2i64(<2 x ptr> %p, <2 x i64> %m)



More information about the cfe-commits mailing list