From 9f2ec3c40d9c4f28531e4a18f392703ca16ab2d7 Mon Sep 17 00:00:00 2001 From: kimsh02 Date: Mon, 13 Oct 2025 13:18:28 -0700 Subject: [PATCH 1/9] Copy incubator tests --- clang/test/CIR/CodeGen/ptrdiff.c | 18 ++++++++++++++++++ clang/test/CIR/CodeGen/ptrdiff.cpp | 23 +++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 clang/test/CIR/CodeGen/ptrdiff.c create mode 100644 clang/test/CIR/CodeGen/ptrdiff.cpp diff --git a/clang/test/CIR/CodeGen/ptrdiff.c b/clang/test/CIR/CodeGen/ptrdiff.c new file mode 100644 index 0000000000000..2ccbbb02dddaa --- /dev/null +++ b/clang/test/CIR/CodeGen/ptrdiff.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +int addrcmp(const void* a, const void* b) { + // CIR-LABEL: addrcmp + // CIR: %[[R:.*]] = cir.ptr_diff + // CIR: cir.cast integral %[[R]] : !s64i -> !s32 + + // LLVM-LABEL: addrcmp + // LLVM: %[[PTR_A:.*]] = ptrtoint ptr {{.*}} to i64 + // LLVM: %[[PTR_B:.*]] = ptrtoint ptr {{.*}} to i64 + // LLVM: %[[SUB:.*]] = sub i64 %[[PTR_A]], %[[PTR_B]] + // LLVM-NOT: sdiv + // LLVM: trunc i64 %[[SUB]] to i32 + return *(const void**)a - *(const void**)b; +} diff --git a/clang/test/CIR/CodeGen/ptrdiff.cpp b/clang/test/CIR/CodeGen/ptrdiff.cpp new file mode 100644 index 0000000000000..ba54b7a3b11bf --- /dev/null +++ b/clang/test/CIR/CodeGen/ptrdiff.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +typedef unsigned long size_type; +size_type size(unsigned long *_start, unsigned long *_finish) { + return static_cast(_finish - _start); +} + +// CHECK: cir.func dso_local @_Z4sizePmS_(%arg0: !cir.ptr +// CHECK: %3 = cir.load{{.*}} %1 : !cir.ptr>, !cir.ptr +// CHECK: %4 = cir.load{{.*}} %0 : !cir.ptr>, !cir.ptr +// CHECK: %5 = cir.ptr_diff %3, %4 : !cir.ptr -> !s64i +// CHECK: %6 = cir.cast integral %5 : !s64i -> !u64i + +long add(char *a, char *b) { + return a - b + 1; +} + +// CHECK: cir.func dso_local @_Z3addPcS_(%arg0: !cir.ptr +// %5 = cir.ptr_diff %3, %4 : !cir.ptr -> !s64i +// %6 = cir.const #cir.int<1> : !s32i +// %7 = cir.cast integral %6 : !s32i -> !s64i +// %8 = cir.binop(add, %5, %7) : !s64i From db85047a5f606caad31770219f468f66985b2ed1 Mon Sep 17 00:00:00 2001 From: kimsh02 Date: Mon, 13 Oct 2025 19:05:05 -0700 Subject: [PATCH 2/9] Stash --- clang/include/clang/CIR/MissingFeatures.h | 2 +- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 3 +- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 34 +++++++++++++++++ clang/test/CIR/CodeGen/ptrdiff.c | 14 +++++++ clang/test/CIR/CodeGen/ptrdiff.cpp | 37 +++++++++++++------ 5 files changed, 75 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 4fbae150b587e..8edb4adcf48de 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -321,7 +321,7 @@ struct MissingFeatures { static bool ifOp() { return false; } static bool invokeOp() { return false; } static bool labelOp() { return false; } - static bool ptrDiffOp() { return false; } + static bool ptrDiffOp() { return true; } static bool ptrStrideOp() { return false; } static bool switchOp() { return false; } static bool throwOp() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 637f9ef65c88f..6c6e25c3f6caa 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1735,8 +1735,7 @@ mlir::Value ScalarExprEmitter::emitSub(const BinOpInfo &ops) { // // See more in `EmitSub` in CGExprScalar.cpp. assert(!cir::MissingFeatures::ptrDiffOp()); - cgf.cgm.errorNYI("ptrdiff"); - return {}; + return builder.create(cgf.getLoc(ops.loc), cgf.PtrDiffTy, ops.lhs, ops.rhs); } mlir::Value ScalarExprEmitter::emitShl(const BinOpInfo &ops) { diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index f0d73ac872386..5f4fb2aa5c09d 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1499,6 +1499,40 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMPtrDiffOpLowering::matchAndRewrite( + cir::PtrDiffOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + auto dstTy = mlir::cast(op.getType()); + auto llvmDstTy = getTypeConverter()->convertType(dstTy); + + auto lhs = rewriter.create(op.getLoc(), llvmDstTy, + adaptor.getLhs()); + auto rhs = rewriter.create(op.getLoc(), llvmDstTy, + adaptor.getRhs()); + + auto diff = + rewriter.create(op.getLoc(), llvmDstTy, lhs, rhs); + + cir::PointerType ptrTy = op.getLhs().getType(); + auto typeSize = getTypeSize(ptrTy.getPointee(), *op); + + // Avoid silly division by 1. + auto resultVal = diff.getResult(); + if (typeSize != 1) { + auto typeSizeVal = rewriter.create( + op.getLoc(), llvmDstTy, typeSize); + + if (dstTy.isUnsigned()) + resultVal = + rewriter.create(op.getLoc(), diff, typeSizeVal); + else + resultVal = + rewriter.create(op.getLoc(), diff, typeSizeVal); + } + rewriter.replaceOp(op, resultVal); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMExpectOpLowering::matchAndRewrite( cir::ExpectOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/test/CIR/CodeGen/ptrdiff.c b/clang/test/CIR/CodeGen/ptrdiff.c index 2ccbbb02dddaa..ef37d4b139568 100644 --- a/clang/test/CIR/CodeGen/ptrdiff.c +++ b/clang/test/CIR/CodeGen/ptrdiff.c @@ -16,3 +16,17 @@ int addrcmp(const void* a, const void* b) { // LLVM: trunc i64 %[[SUB]] to i32 return *(const void**)a - *(const void**)b; } + +unsigned long long test_ptr_diff(int *a, int* b) { + // CIR-LABEL: test_ptr_diff + // CIR: %[[D:.*]] = cir.ptr_diff{{.*}} : !cir.ptr -> !u64i + // CIR: cir.return %[[D]] : !u64i + + // LLVM-LABEL: @_Z13test_ptr_diffPiS_ + // LLVM: %[[IA:.*]] = ptrtoint ptr %{{.*}} to i64 + // LLVM: %[[IB:.*]] = ptrtoint ptr %{{.*}} to i64 + // LLVM: %[[SUB:.*]] = sub i64 %[[IA]], %[[IB]] + // LLVM: %[[Q:.*]] = sdiv exact i64 %[[SUB]], 4 + // LLVM: ret i64 %[[Q]] + return a - b; +} diff --git a/clang/test/CIR/CodeGen/ptrdiff.cpp b/clang/test/CIR/CodeGen/ptrdiff.cpp index ba54b7a3b11bf..32a3955807b8f 100644 --- a/clang/test/CIR/CodeGen/ptrdiff.cpp +++ b/clang/test/CIR/CodeGen/ptrdiff.cpp @@ -2,22 +2,35 @@ // RUN: FileCheck --input-file=%t.cir %s typedef unsigned long size_type; + size_type size(unsigned long *_start, unsigned long *_finish) { + // CIR-LABEL: cir.func dso_local @_Z4sizePmS_ + // CIR: %[[D:.*]] = cir.ptr_diff {{.*}} : !cir.ptr -> !s64i + // CIR: %[[U:.*]] = cir.cast integral %[[D]] : !s64i -> !u64i + // CIR: cir.return %[[U]] : !u64i + + // LLVM-LABEL: @_Z4sizePmS_ + // LLVM: ptrtoint ptr {{.*}} to i64 + // LLVM: ptrtoint ptr {{.*}} to i64 + // LLVM: %[[SUB:.*]] = sub i64 {{.*}}, {{.*}} + // LLVM: %[[DIV:.*]] = sdiv exact i64 %[[SUB]], 8 + // LLVM: ret i64 %[[DIV]] return static_cast(_finish - _start); } -// CHECK: cir.func dso_local @_Z4sizePmS_(%arg0: !cir.ptr -// CHECK: %3 = cir.load{{.*}} %1 : !cir.ptr>, !cir.ptr -// CHECK: %4 = cir.load{{.*}} %0 : !cir.ptr>, !cir.ptr -// CHECK: %5 = cir.ptr_diff %3, %4 : !cir.ptr -> !s64i -// CHECK: %6 = cir.cast integral %5 : !s64i -> !u64i - long add(char *a, char *b) { + // CIR-LABEL: cir.func dso_local @_Z3addPcS_ + // CIR: %[[D:.*]] = cir.ptr_diff {{.*}} : !cir.ptr -> !s64i + // CIR: %[[C1:.*]] = cir.const #cir.int<1> : !s32i + // CIR: %[[C1W:.*]] = cir.cast integral %[[C1]] : !s32i -> !s64i + // CIR: %[[S:.*]] = cir.binop(add, %[[D]], %[[C1W]]) : !s64i + // CIR: cir.return %[[S]] : !s64i + + // LLVM-LABEL: @_Z3addPcS_ + // LLVM: ptrtoint ptr {{.*}} to i64 + // LLVM: ptrtoint ptr {{.*}} to i64 + // LLVM: %[[SUB:.*]] = sub i64 {{.*}}, {{.*}} + // LLVM: %[[ADD1:.*]] = add i64 %[[SUB]], 1 + // LLVM: ret i64 %[[ADD1]] return a - b + 1; } - -// CHECK: cir.func dso_local @_Z3addPcS_(%arg0: !cir.ptr -// %5 = cir.ptr_diff %3, %4 : !cir.ptr -> !s64i -// %6 = cir.const #cir.int<1> : !s32i -// %7 = cir.cast integral %6 : !s32i -> !s64i -// %8 = cir.binop(add, %5, %7) : !s64i From a3709f9303d2db3f07b878501bda4ba4f93722ae Mon Sep 17 00:00:00 2001 From: kimsh02 Date: Mon, 13 Oct 2025 19:06:12 -0700 Subject: [PATCH 3/9] Clang-format --- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 6c6e25c3f6caa..ff77c0ef5a540 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1735,7 +1735,8 @@ mlir::Value ScalarExprEmitter::emitSub(const BinOpInfo &ops) { // // See more in `EmitSub` in CGExprScalar.cpp. assert(!cir::MissingFeatures::ptrDiffOp()); - return builder.create(cgf.getLoc(ops.loc), cgf.PtrDiffTy, ops.lhs, ops.rhs); + return builder.create(cgf.getLoc(ops.loc), cgf.PtrDiffTy, + ops.lhs, ops.rhs); } mlir::Value ScalarExprEmitter::emitShl(const BinOpInfo &ops) { From 0ff02185f99e2047f5a73cf691876b6f48a188a5 Mon Sep 17 00:00:00 2001 From: kimsh02 Date: Tue, 14 Oct 2025 12:33:37 -0700 Subject: [PATCH 4/9] Stash --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 31 +++++++++++++++++++ clang/include/clang/CIR/MissingFeatures.h | 3 +- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 2 +- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 9 ++++++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 4c15d9ed0f834..56ff289f91a93 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4044,6 +4044,37 @@ def CIR_ExpectOp : CIR_Op<"expect", [ }]; } +//===----------------------------------------------------------------------===// +// PtrDiffOp +//===----------------------------------------------------------------------===// + +def CIR_PtrDiffOp : CIR_Op<"ptr_diff", [Pure, SameTypeOperands]> { + let summary = "Pointer subtraction arithmetic"; + let description = [{ + The cir.ptr_diff operation computes the difference between two pointers that + have the same element type + + The result reflects the ABI-defined size of the pointed-to type. For example, + subtracting two !cir.ptr values may yield 1, representing an 8-byte + difference. In contrast, for pointers to void or function types, a result of + 8 corresponds to an 8-byte difference. + + Example: + + ```mlir + %7 = cir.ptr_diff %0, %1 : !cir.ptr -> !u64i + ``` + }]; + + let arguments = (ins CIR_PointerType:$lhs, CIR_PointerType:$rhs); + let results = (outs CIR_AnyFundamentalIntType:$result); + + let assemblyFormat = [{ + $lhs `,` $rhs `:` qualified(type($lhs)) `->` qualified(type($result)) + attr-dict + }]; +} + //===----------------------------------------------------------------------===// // Floating Point Ops //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 8edb4adcf48de..d133453c137fb 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -321,7 +321,8 @@ struct MissingFeatures { static bool ifOp() { return false; } static bool invokeOp() { return false; } static bool labelOp() { return false; } - static bool ptrDiffOp() { return true; } + static bool ptrDiffOp() { return false; } + static bool llvmLoweringPtrDiffConsidersPointee() {return false; } static bool ptrStrideOp() { return false; } static bool switchOp() { return false; } static bool throwOp() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index ff77c0ef5a540..8889bbeebe399 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1734,7 +1734,7 @@ mlir::Value ScalarExprEmitter::emitSub(const BinOpInfo &ops) { // LLVM we shall take VLA's, division by element size, etc. // // See more in `EmitSub` in CGExprScalar.cpp. - assert(!cir::MissingFeatures::ptrDiffOp()); + assert(!cir::MissingFeatures::llvmLoweringPtrDiffConsidersPointee()); return builder.create(cgf.getLoc(ops.loc), cgf.PtrDiffTy, ops.lhs, ops.rhs); } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 5f4fb2aa5c09d..19d734df42331 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1499,6 +1499,15 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( return mlir::success(); } +uint64_t CIRToLLVMPtrDiffOpLowering::getTypeSize(mlir::Type type, + mlir::Operation &op) const { + mlir::DataLayout layout(op.getParentOfType()); + // For LLVM purposes we treat void as u8. + if (isa(type)) + type = cir::IntType::get(type.getContext(), 8, /*isSigned=*/false); + return llvm::divideCeil(layout.getTypeSizeInBits(type), 8); +} + mlir::LogicalResult CIRToLLVMPtrDiffOpLowering::matchAndRewrite( cir::PtrDiffOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { From 61bc2569fc4792ddd97d81ddace687b1e10ca451 Mon Sep 17 00:00:00 2001 From: kimsh02 Date: Tue, 14 Oct 2025 13:30:34 -0700 Subject: [PATCH 5/9] Fix testcases --- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 4 +-- clang/test/CIR/CodeGen/ptrdiff.c | 17 +++++++----- clang/test/CIR/CodeGen/ptrdiff.cpp | 27 ++----------------- 3 files changed, 14 insertions(+), 34 deletions(-) diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 19d734df42331..4b8d912409a8e 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1499,8 +1499,8 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( return mlir::success(); } -uint64_t CIRToLLVMPtrDiffOpLowering::getTypeSize(mlir::Type type, - mlir::Operation &op) const { +static uint64_t getTypeSize(mlir::Type type, + mlir::Operation &op) { mlir::DataLayout layout(op.getParentOfType()); // For LLVM purposes we treat void as u8. if (isa(type)) diff --git a/clang/test/CIR/CodeGen/ptrdiff.c b/clang/test/CIR/CodeGen/ptrdiff.c index ef37d4b139568..33a0c3ad4faf4 100644 --- a/clang/test/CIR/CodeGen/ptrdiff.c +++ b/clang/test/CIR/CodeGen/ptrdiff.c @@ -6,9 +6,9 @@ int addrcmp(const void* a, const void* b) { // CIR-LABEL: addrcmp // CIR: %[[R:.*]] = cir.ptr_diff - // CIR: cir.cast integral %[[R]] : !s64i -> !s32 + // CIR: cir.cast integral %[[R]] : !s64i -> !s32i - // LLVM-LABEL: addrcmp + // LLVM-LABEL: define dso_local i32 @addrcmp( // LLVM: %[[PTR_A:.*]] = ptrtoint ptr {{.*}} to i64 // LLVM: %[[PTR_B:.*]] = ptrtoint ptr {{.*}} to i64 // LLVM: %[[SUB:.*]] = sub i64 %[[PTR_A]], %[[PTR_B]] @@ -19,14 +19,17 @@ int addrcmp(const void* a, const void* b) { unsigned long long test_ptr_diff(int *a, int* b) { // CIR-LABEL: test_ptr_diff - // CIR: %[[D:.*]] = cir.ptr_diff{{.*}} : !cir.ptr -> !u64i - // CIR: cir.return %[[D]] : !u64i + // CIR: %[[D:.*]] = cir.ptr_diff {{.*}} : !cir.ptr -> !s64i + // CIR: %[[U:.*]] = cir.cast integral %[[D]] : !s64i -> !u64i + // CIR: cir.return {{.*}} : !u64i - // LLVM-LABEL: @_Z13test_ptr_diffPiS_ + // LLVM-LABEL: define dso_local i64 @test_ptr_diff( // LLVM: %[[IA:.*]] = ptrtoint ptr %{{.*}} to i64 // LLVM: %[[IB:.*]] = ptrtoint ptr %{{.*}} to i64 // LLVM: %[[SUB:.*]] = sub i64 %[[IA]], %[[IB]] - // LLVM: %[[Q:.*]] = sdiv exact i64 %[[SUB]], 4 - // LLVM: ret i64 %[[Q]] + // LLVM: %[[Q:.*]] = sdiv{{( exact)?}} i64 %[[SUB]], 4 + // LLVM: store i64 %[[Q]], ptr %[[RETADDR:.*]], align + // LLVM: %[[RETLOAD:.*]] = load i64, ptr %[[RETADDR]], align + // LLVM: ret i64 %[[RETLOAD]] return a - b; } diff --git a/clang/test/CIR/CodeGen/ptrdiff.cpp b/clang/test/CIR/CodeGen/ptrdiff.cpp index 32a3955807b8f..2c0aed6089816 100644 --- a/clang/test/CIR/CodeGen/ptrdiff.cpp +++ b/clang/test/CIR/CodeGen/ptrdiff.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR typedef unsigned long size_type; @@ -7,30 +7,7 @@ size_type size(unsigned long *_start, unsigned long *_finish) { // CIR-LABEL: cir.func dso_local @_Z4sizePmS_ // CIR: %[[D:.*]] = cir.ptr_diff {{.*}} : !cir.ptr -> !s64i // CIR: %[[U:.*]] = cir.cast integral %[[D]] : !s64i -> !u64i - // CIR: cir.return %[[U]] : !u64i + // CIR: cir.return {{.*}} : !u64i - // LLVM-LABEL: @_Z4sizePmS_ - // LLVM: ptrtoint ptr {{.*}} to i64 - // LLVM: ptrtoint ptr {{.*}} to i64 - // LLVM: %[[SUB:.*]] = sub i64 {{.*}}, {{.*}} - // LLVM: %[[DIV:.*]] = sdiv exact i64 %[[SUB]], 8 - // LLVM: ret i64 %[[DIV]] return static_cast(_finish - _start); } - -long add(char *a, char *b) { - // CIR-LABEL: cir.func dso_local @_Z3addPcS_ - // CIR: %[[D:.*]] = cir.ptr_diff {{.*}} : !cir.ptr -> !s64i - // CIR: %[[C1:.*]] = cir.const #cir.int<1> : !s32i - // CIR: %[[C1W:.*]] = cir.cast integral %[[C1]] : !s32i -> !s64i - // CIR: %[[S:.*]] = cir.binop(add, %[[D]], %[[C1W]]) : !s64i - // CIR: cir.return %[[S]] : !s64i - - // LLVM-LABEL: @_Z3addPcS_ - // LLVM: ptrtoint ptr {{.*}} to i64 - // LLVM: ptrtoint ptr {{.*}} to i64 - // LLVM: %[[SUB:.*]] = sub i64 {{.*}}, {{.*}} - // LLVM: %[[ADD1:.*]] = add i64 %[[SUB]], 1 - // LLVM: ret i64 %[[ADD1]] - return a - b + 1; -} From 50412c36ad1c771b221d6db91fe320df5a9e5c2d Mon Sep 17 00:00:00 2001 From: kimsh02 Date: Tue, 14 Oct 2025 13:31:43 -0700 Subject: [PATCH 6/9] Clang-format --- clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 4b8d912409a8e..70c152f8722b0 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1499,8 +1499,7 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( return mlir::success(); } -static uint64_t getTypeSize(mlir::Type type, - mlir::Operation &op) { +static uint64_t getTypeSize(mlir::Type type, mlir::Operation &op) { mlir::DataLayout layout(op.getParentOfType()); // For LLVM purposes we treat void as u8. if (isa(type)) From 52f0f44f5e58277335a74a6a80c20944ad824ffc Mon Sep 17 00:00:00 2001 From: kimsh02 Date: Tue, 14 Oct 2025 13:32:52 -0700 Subject: [PATCH 7/9] Clang-format --- clang/include/clang/CIR/MissingFeatures.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index d133453c137fb..de3bc9487bc8c 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -322,7 +322,7 @@ struct MissingFeatures { static bool invokeOp() { return false; } static bool labelOp() { return false; } static bool ptrDiffOp() { return false; } - static bool llvmLoweringPtrDiffConsidersPointee() {return false; } + static bool llvmLoweringPtrDiffConsidersPointee() { return false; } static bool ptrStrideOp() { return false; } static bool switchOp() { return false; } static bool throwOp() { return false; } From de497b284130021b1d54d68f160baef3b275a30e Mon Sep 17 00:00:00 2001 From: kimsh02 Date: Wed, 15 Oct 2025 13:06:20 -0700 Subject: [PATCH 8/9] Apply coding style feedback --- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 4 ++-- clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 8889bbeebe399..138082b59fecd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1735,8 +1735,8 @@ mlir::Value ScalarExprEmitter::emitSub(const BinOpInfo &ops) { // // See more in `EmitSub` in CGExprScalar.cpp. assert(!cir::MissingFeatures::llvmLoweringPtrDiffConsidersPointee()); - return builder.create(cgf.getLoc(ops.loc), cgf.PtrDiffTy, - ops.lhs, ops.rhs); + return cir::PtrDiffOp::create(builder, cgf.getLoc(ops.loc), cgf.PtrDiffTy, + ops.lhs, ops.rhs); } mlir::Value ScalarExprEmitter::emitShl(const BinOpInfo &ops) { diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 70c152f8722b0..ebfbbd0c54332 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1511,7 +1511,7 @@ mlir::LogicalResult CIRToLLVMPtrDiffOpLowering::matchAndRewrite( cir::PtrDiffOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { auto dstTy = mlir::cast(op.getType()); - auto llvmDstTy = getTypeConverter()->convertType(dstTy); + mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy); auto lhs = rewriter.create(op.getLoc(), llvmDstTy, adaptor.getLhs()); @@ -1522,10 +1522,11 @@ mlir::LogicalResult CIRToLLVMPtrDiffOpLowering::matchAndRewrite( rewriter.create(op.getLoc(), llvmDstTy, lhs, rhs); cir::PointerType ptrTy = op.getLhs().getType(); - auto typeSize = getTypeSize(ptrTy.getPointee(), *op); + assert(!cir::MissingFeatures::llvmLoweringPtrDiffConsidersPointee()); + uint64_t typeSize = getTypeSize(ptrTy.getPointee(), *op); // Avoid silly division by 1. - auto resultVal = diff.getResult(); + mlir::Value resultVal = diff.getResult(); if (typeSize != 1) { auto typeSizeVal = rewriter.create( op.getLoc(), llvmDstTy, typeSize); From 507edc2eeff7b31d5f485a2ef2b9c090a056c6fc Mon Sep 17 00:00:00 2001 From: kimsh02 Date: Wed, 15 Oct 2025 15:57:32 -0700 Subject: [PATCH 9/9] Apply test and doc feedback --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 8 ++++++- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 13 ++++++---- clang/test/CIR/CodeGen/ptrdiff.c | 24 +++++++++++++++---- clang/test/CIR/CodeGen/ptrdiff.cpp | 22 ++++++++++++++++- 4 files changed, 57 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 56ff289f91a93..c3b320da3a585 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4052,13 +4052,19 @@ def CIR_PtrDiffOp : CIR_Op<"ptr_diff", [Pure, SameTypeOperands]> { let summary = "Pointer subtraction arithmetic"; let description = [{ The cir.ptr_diff operation computes the difference between two pointers that - have the same element type + have the same element type. The result reflects the ABI-defined size of the pointed-to type. For example, subtracting two !cir.ptr values may yield 1, representing an 8-byte difference. In contrast, for pointers to void or function types, a result of 8 corresponds to an 8-byte difference. + For pointers to types whose size are not aligned with the target data + layout, the size is generally rounded to the next power of 2 bits. For + example, subtracting two !cir.ptr values for the _BitInt(24) type may + yield 1, representing a 4-byte difference (as opposed to a 3-byte + difference). + Example: ```mlir diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index ebfbbd0c54332..f5c29bbe8d14a 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1531,12 +1531,17 @@ mlir::LogicalResult CIRToLLVMPtrDiffOpLowering::matchAndRewrite( auto typeSizeVal = rewriter.create( op.getLoc(), llvmDstTy, typeSize); - if (dstTy.isUnsigned()) - resultVal = + if (dstTy.isUnsigned()) { + auto uDiv = rewriter.create(op.getLoc(), diff, typeSizeVal); - else - resultVal = + uDiv.setIsExact(true); + resultVal = uDiv.getResult(); + } else { + auto sDiv = rewriter.create(op.getLoc(), diff, typeSizeVal); + sDiv.setIsExact(true); + resultVal = sDiv.getResult(); + } } rewriter.replaceOp(op, resultVal); return mlir::success(); diff --git a/clang/test/CIR/CodeGen/ptrdiff.c b/clang/test/CIR/CodeGen/ptrdiff.c index 33a0c3ad4faf4..e6a754ebc8d4b 100644 --- a/clang/test/CIR/CodeGen/ptrdiff.c +++ b/clang/test/CIR/CodeGen/ptrdiff.c @@ -1,7 +1,9 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s int addrcmp(const void* a, const void* b) { // CIR-LABEL: addrcmp @@ -14,6 +16,13 @@ int addrcmp(const void* a, const void* b) { // LLVM: %[[SUB:.*]] = sub i64 %[[PTR_A]], %[[PTR_B]] // LLVM-NOT: sdiv // LLVM: trunc i64 %[[SUB]] to i32 + + // OGCG-LABEL: define dso_local i32 @addrcmp( + // OGCG: %[[PTR_A:.*]] = ptrtoint ptr {{.*}} to i64 + // OGCG: %[[PTR_B:.*]] = ptrtoint ptr {{.*}} to i64 + // OGCG: %[[SUB:.*]] = sub i64 %[[PTR_A]], %[[PTR_B]] + // OGCG-NOT: sdiv + // OGCG: trunc i64 %[[SUB]] to i32 return *(const void**)a - *(const void**)b; } @@ -27,9 +36,16 @@ unsigned long long test_ptr_diff(int *a, int* b) { // LLVM: %[[IA:.*]] = ptrtoint ptr %{{.*}} to i64 // LLVM: %[[IB:.*]] = ptrtoint ptr %{{.*}} to i64 // LLVM: %[[SUB:.*]] = sub i64 %[[IA]], %[[IB]] - // LLVM: %[[Q:.*]] = sdiv{{( exact)?}} i64 %[[SUB]], 4 + // LLVM: %[[Q:.*]] = sdiv exact i64 %[[SUB]], 4 // LLVM: store i64 %[[Q]], ptr %[[RETADDR:.*]], align // LLVM: %[[RETLOAD:.*]] = load i64, ptr %[[RETADDR]], align // LLVM: ret i64 %[[RETLOAD]] + + // OGCG-LABEL: define dso_local i64 @test_ptr_diff( + // OGCG: %[[IA:.*]] = ptrtoint ptr %{{.*}} to i64 + // OGCG: %[[IB:.*]] = ptrtoint ptr %{{.*}} to i64 + // OGCG: %[[SUB:.*]] = sub i64 %[[IA]], %[[IB]] + // OGCG: %[[Q:.*]] = sdiv exact i64 %[[SUB]], 4 + // OGCG: ret i64 %[[Q]] return a - b; -} +} \ No newline at end of file diff --git a/clang/test/CIR/CodeGen/ptrdiff.cpp b/clang/test/CIR/CodeGen/ptrdiff.cpp index 2c0aed6089816..34ba0ff725581 100644 --- a/clang/test/CIR/CodeGen/ptrdiff.cpp +++ b/clang/test/CIR/CodeGen/ptrdiff.cpp @@ -1,5 +1,9 @@ // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG typedef unsigned long size_type; @@ -9,5 +13,21 @@ size_type size(unsigned long *_start, unsigned long *_finish) { // CIR: %[[U:.*]] = cir.cast integral %[[D]] : !s64i -> !u64i // CIR: cir.return {{.*}} : !u64i + // LLVM-LABEL: define dso_local {{.*}}i64 @_Z4sizePmS_( + // LLVM: %[[IA:.*]] = ptrtoint ptr %{{.*}} to i64 + // LLVM: %[[IB:.*]] = ptrtoint ptr %{{.*}} to i64 + // LLVM: %[[SUB:.*]] = sub i64 %[[IA]], %[[IB]] + // LLVM: %[[Q:.*]] = sdiv exact i64 %[[SUB]], 8 + // LLVM: store i64 %[[Q]], ptr %[[RETADDR:.*]], align + // LLVM: %[[RET:.*]] = load i64, ptr %[[RETADDR]], align + // LLVM: ret i64 %[[RET]] + + // OGCG-LABEL: define dso_local {{.*}}i64 @_Z4sizePmS_( + // OGCG: %[[IA:.*]] = ptrtoint ptr %{{.*}} to i64 + // OGCG: %[[IB:.*]] = ptrtoint ptr %{{.*}} to i64 + // OGCG: %[[SUB:.*]] = sub i64 %[[IA]], %[[IB]] + // OGCG: %[[Q:.*]] = sdiv exact i64 %[[SUB]], 8 + // OGCG: ret i64 %[[Q]] + return static_cast(_finish - _start); -} +} \ No newline at end of file