diff --git a/llvm/test/Transforms/InstCombine/to-ptrmask.ll b/llvm/test/Transforms/InstCombine/to-ptrmask.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/to-ptrmask.ll @@ -0,0 +1,250 @@ +; 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(ptr, i64) +declare void @use.i64(i64) + +define ptr @intoptr_mask(ptr noundef %p, i64 %m) { +; CHECK-LABEL: define ptr @intoptr_mask +; CHECK-SAME: (ptr noundef [[P:%.*]], i64 [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 +; CHECK-NEXT: [[PI_MASKED:%.*]] = and i64 [[PI]], [[M]] +; CHECK-NEXT: [[PM:%.*]] = inttoptr i64 [[PI_MASKED]] to ptr +; CHECK-NEXT: ret ptr [[PM]] +; + %pi = ptrtoint ptr %p to i64 + %pi_masked = and i64 %pi, %m + %pm = inttoptr i64 %pi_masked to ptr + ret ptr %pm +} + +define <2 x ptr> @intoptr_mask_fail_vec(<2 x ptr> noundef %p, <2 x i64> %m) { +; CHECK-LABEL: define <2 x ptr> @intoptr_mask_fail_vec +; CHECK-SAME: (<2 x ptr> noundef [[P:%.*]], <2 x i64> [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint <2 x ptr> [[P]] to <2 x i64> +; CHECK-NEXT: [[PI_MASKED:%.*]] = and <2 x i64> [[PI]], [[M]] +; CHECK-NEXT: [[PM:%.*]] = inttoptr <2 x i64> [[PI_MASKED]] to <2 x ptr> +; CHECK-NEXT: ret <2 x ptr> [[PM]] +; + %pi = ptrtoint <2 x ptr> %p to <2 x i64> + %pi_masked = and <2 x i64> %pi, %m + %pm = inttoptr <2 x i64> %pi_masked to <2 x ptr> + ret <2 x ptr> %pm +} + +define ptr @intoptr_mask_fail_i32(ptr noundef %p, i32 %m) { +; CHECK-LABEL: define ptr @intoptr_mask_fail_i32 +; CHECK-SAME: (ptr noundef [[P:%.*]], i32 [[M:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[P]] to i64 +; CHECK-NEXT: [[PI:%.*]] = trunc i64 [[TMP1]] to i32 +; CHECK-NEXT: [[PI_MASKED:%.*]] = and i32 [[PI]], [[M]] +; CHECK-NEXT: [[TMP2:%.*]] = zext i32 [[PI_MASKED]] to i64 +; CHECK-NEXT: [[PM:%.*]] = inttoptr i64 [[TMP2]] to ptr +; CHECK-NEXT: ret ptr [[PM]] +; + %pi = ptrtoint ptr %p to i32 + %pi_masked = and i32 %pi, %m + %pm = inttoptr i32 %pi_masked to ptr + ret ptr %pm +} + +define ptr @intoptr_mask_fail_multiuse(ptr noundef %p, i64 %m) { +; CHECK-LABEL: define ptr @intoptr_mask_fail_multiuse +; CHECK-SAME: (ptr noundef [[P:%.*]], i64 [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 +; CHECK-NEXT: [[PI_MASKED:%.*]] = and i64 [[PI]], [[M]] +; CHECK-NEXT: call void @use.i64(i64 [[PI_MASKED]]) +; CHECK-NEXT: [[PM:%.*]] = inttoptr i64 [[PI_MASKED]] to ptr +; CHECK-NEXT: ret ptr [[PM]] +; + %pi = ptrtoint ptr %p to i64 + %pi_masked = and i64 %pi, %m + call void @use.i64(i64 %pi_masked) + %pm = inttoptr i64 %pi_masked to ptr + ret ptr %pm +} + +define ptr @inttoptr_mask_fail_missing_noundef(ptr %p, i64 %m) { +; CHECK-LABEL: define ptr @inttoptr_mask_fail_missing_noundef +; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 +; CHECK-NEXT: [[PI_MASKED:%.*]] = and i64 [[PI]], [[M]] +; CHECK-NEXT: [[PM:%.*]] = inttoptr i64 [[PI_MASKED]] to ptr +; CHECK-NEXT: ret ptr [[PM]] +; + %pi = ptrtoint ptr %p to i64 + %pi_masked = and i64 %pi, %m + %pm = inttoptr i64 %pi_masked to ptr + ret ptr %pm +} + +define i64 @pattern_missing_inttoptr_fail(ptr noundef %p, i64 %m) { +; CHECK-LABEL: define i64 @pattern_missing_inttoptr_fail +; CHECK-SAME: (ptr noundef [[P:%.*]], i64 [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 +; CHECK-NEXT: [[PI_MASKED:%.*]] = and i64 [[PI]], [[M]] +; CHECK-NEXT: ret i64 [[PI_MASKED]] +; + %pi = ptrtoint ptr %p to i64 + %pi_masked = and i64 %pi, %m + ret i64 %pi_masked +} + + +define ptr @GEP_inttoptr_complex_to_simple(ptr %p, i64 %m) { +; CHECK-LABEL: define ptr @GEP_inttoptr_complex_to_simple +; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 +; CHECK-NEXT: [[PI_M:%.*]] = xor i64 [[PI]], [[M]] +; CHECK-NEXT: [[PI_OFF:%.*]] = sub i64 [[PI_M]], [[PI]] +; CHECK-NEXT: [[PM:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 [[PI_OFF]] +; CHECK-NEXT: ret ptr [[PM]] +; + %pi = ptrtoint ptr %p to i64 + %pi_m = xor i64 %pi, %m + %pi_off = sub i64 %pi_m, %pi + %pm = getelementptr inbounds i8, ptr %p, i64 %pi_off + ret ptr %pm +} + +define ptr @GEP_inttoptr_complex_pattern(ptr %p, i64 %m) { +; CHECK-LABEL: define ptr @GEP_inttoptr_complex_pattern +; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 +; CHECK-NEXT: [[PI_M:%.*]] = and i64 [[PI]], [[M]] +; CHECK-NEXT: [[PI_OFF:%.*]] = sub i64 [[PI_M]], [[PI]] +; CHECK-NEXT: [[PM:%.*]] = getelementptr i8, ptr [[P]], i64 [[PI_OFF]] +; CHECK-NEXT: ret ptr [[PM]] +; + %pi = ptrtoint ptr %p to i64 + %pi_m = and i64 %pi, %m + %pi_off = sub i64 %pi_m, %pi + %pm = getelementptr i8, ptr %p, i64 %pi_off + ret ptr %pm +} + +define <2 x ptr> @GEP_inttoptr_complex_pattern_fail_vec(<2 x ptr> %p, <2 x i64> %m) { +; CHECK-LABEL: define <2 x ptr> @GEP_inttoptr_complex_pattern_fail_vec +; CHECK-SAME: (<2 x ptr> [[P:%.*]], <2 x i64> [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint <2 x ptr> [[P]] to <2 x i64> +; CHECK-NEXT: [[PI_M:%.*]] = and <2 x i64> [[PI]], [[M]] +; CHECK-NEXT: [[PI_OFF:%.*]] = sub <2 x i64> [[PI_M]], [[PI]] +; CHECK-NEXT: [[PM:%.*]] = getelementptr i8, <2 x ptr> [[P]], <2 x i64> [[PI_OFF]] +; CHECK-NEXT: ret <2 x ptr> [[PM]] +; + %pi = ptrtoint <2 x ptr> %p to <2 x i64> + %pi_m = and <2 x i64> %pi, %m + %pi_off = sub <2 x i64> %pi_m, %pi + %pm = getelementptr i8, <2 x ptr> %p, <2 x i64> %pi_off + ret <2 x ptr> %pm +} + +define ptr @GEP_inttoptr_complex_pattern_with_multiuse(ptr %p, i64 %m) { +; CHECK-LABEL: define ptr @GEP_inttoptr_complex_pattern_with_multiuse +; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 +; CHECK-NEXT: [[PI_M:%.*]] = and i64 [[PI]], [[M]] +; CHECK-NEXT: [[PI_OFF:%.*]] = sub i64 [[PI_M]], [[PI]] +; CHECK-NEXT: call void @use.i64(i64 [[PI_OFF]]) +; CHECK-NEXT: [[PM:%.*]] = getelementptr i8, ptr [[P]], i64 [[PI_OFF]] +; CHECK-NEXT: ret ptr [[PM]] +; + %pi = ptrtoint ptr %p to i64 + %pi_m = and i64 %pi, %m + %pi_off = sub i64 %pi_m, %pi + call void @use.i64(i64 %pi_off) + %pm = getelementptr i8, ptr %p, i64 %pi_off + ret ptr %pm +} + +define ptr @GEP_inttoptr_complex_pattern_fail_i32(ptr %p, i32 %m) { +; CHECK-LABEL: define ptr @GEP_inttoptr_complex_pattern_fail_i32 +; CHECK-SAME: (ptr [[P:%.*]], i32 [[M:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[P]] to i64 +; CHECK-NEXT: [[PI:%.*]] = trunc i64 [[TMP1]] to i32 +; CHECK-NEXT: [[PI_M:%.*]] = and i32 [[PI]], [[M]] +; CHECK-NEXT: [[PI_OFF:%.*]] = sub i32 [[PI_M]], [[PI]] +; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[PI_OFF]] to i64 +; CHECK-NEXT: [[PM:%.*]] = getelementptr i8, ptr [[P]], i64 [[TMP2]] +; CHECK-NEXT: ret ptr [[PM]] +; + %pi = ptrtoint ptr %p to i32 + %pi_m = and i32 %pi, %m + %pi_off = sub i32 %pi_m, %pi + %pm = getelementptr i8, ptr %p, i32 %pi_off + ret ptr %pm +} + +define ptr @GEP_inttoptr_simple_pattern(ptr %p, i64 %m) { +; CHECK-LABEL: define ptr @GEP_inttoptr_simple_pattern +; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 +; CHECK-NEXT: [[PI_M:%.*]] = and i64 [[PI]], [[M]] +; CHECK-NEXT: [[PM:%.*]] = getelementptr i8, ptr null, i64 [[PI_M]] +; CHECK-NEXT: ret ptr [[PM]] +; + %pi = ptrtoint ptr %p to i64 + %pi_m = and i64 %pi, %m + %pm = getelementptr i8, ptr null, i64 %pi_m + ret ptr %pm +} + +define <2 x ptr> @GEP_inttoptr_simple_pattern_fail_vec(<2 x ptr> %p, <2 x i64> %m) { +; CHECK-LABEL: define <2 x ptr> @GEP_inttoptr_simple_pattern_fail_vec +; CHECK-SAME: (<2 x ptr> [[P:%.*]], <2 x i64> [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint <2 x ptr> [[P]] to <2 x i64> +; CHECK-NEXT: [[PI_M:%.*]] = and <2 x i64> [[PI]], [[M]] +; CHECK-NEXT: [[PM:%.*]] = getelementptr i8, <2 x ptr> zeroinitializer, <2 x i64> [[PI_M]] +; CHECK-NEXT: ret <2 x ptr> [[PM]] +; + %pi = ptrtoint <2 x ptr> %p to <2 x i64> + %pi_m = and <2 x i64> %pi, %m + %pm = getelementptr i8, <2 x ptr> zeroinitializer, <2 x i64> %pi_m + ret <2 x ptr> %pm +} + +define ptr @GEP_inttoptr_simple_pattern_fail_multiuse(ptr %p, i64 %m) { +; CHECK-LABEL: define ptr @GEP_inttoptr_simple_pattern_fail_multiuse +; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 +; CHECK-NEXT: [[PI_M:%.*]] = and i64 [[PI]], [[M]] +; CHECK-NEXT: call void @use.i64(i64 [[PI_M]]) +; CHECK-NEXT: [[PM:%.*]] = getelementptr i8, ptr null, i64 [[PI_M]] +; CHECK-NEXT: ret ptr [[PM]] +; + %pi = ptrtoint ptr %p to i64 + %pi_m = and i64 %pi, %m + call void @use.i64(i64 %pi_m) + %pm = getelementptr i8, ptr null, i64 %pi_m + ret ptr %pm +} + +define ptr @GEP_inttoptr_complex_pattern_fail_not_i8(ptr %p, i64 %m) { +; CHECK-LABEL: define ptr @GEP_inttoptr_complex_pattern_fail_not_i8 +; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 +; CHECK-NEXT: [[PI_M:%.*]] = and i64 [[PI]], [[M]] +; CHECK-NEXT: [[PI_OFF:%.*]] = sub i64 [[PI_M]], [[PI]] +; CHECK-NEXT: [[PM:%.*]] = getelementptr i16, ptr [[P]], i64 [[PI_OFF]] +; CHECK-NEXT: ret ptr [[PM]] +; + %pi = ptrtoint ptr %p to i64 + %pi_m = and i64 %pi, %m + %pi_off = sub i64 %pi_m, %pi + %pm = getelementptr i16, ptr %p, i64 %pi_off + ret ptr %pm +} + +define ptr @GEP_inttoptr_simple_pattern_fail_not_i8(ptr %p, i64 %m) { +; CHECK-LABEL: define ptr @GEP_inttoptr_simple_pattern_fail_not_i8 +; CHECK-SAME: (ptr [[P:%.*]], i64 [[M:%.*]]) { +; CHECK-NEXT: [[PI:%.*]] = ptrtoint ptr [[P]] to i64 +; CHECK-NEXT: [[PI_M:%.*]] = and i64 [[PI]], [[M]] +; CHECK-NEXT: [[PM:%.*]] = getelementptr <2 x i8>, ptr null, i64 [[PI_M]] +; CHECK-NEXT: ret ptr [[PM]] +; + %pi = ptrtoint ptr %p to i64 + %pi_m = and i64 %pi, %m + %pm = getelementptr <2 x i8>, ptr null, i64 %pi_m + ret ptr %pm +}