Skip to content

Commit e3aa00e

Browse files
fabianmcgjoker-eph
andauthored
[mlir][ptr] Add ptr.ptr_diff operation (#157354)
Thi patch introduces the `ptr.ptr_diff` operation for computing pointer differences. The semantics of the operation are given by: ``` The `ptr_diff` operation computes the difference between two pointers, returning an integer or index value representing the number of bytes between them. The operation supports both scalar and shaped types with value semantics: - When both operands are scalar: produces a single difference value - When both are shaped: performs element-wise subtraction, shapes must be the same The operation also supports the following flags: - `none`: No flags are set. - `nuw`: No Unsigned Wrap, if the subtraction causes an unsigned overflow, the result is a poison value. - `nsw`: No Signed Wrap, if the subtraction causes a signed overflow, the result is a poison value. NOTE: The pointer difference is calculated using an integer type specified by the data layout. The final result will be sign-extended or truncated to fit the result type as necessary. ``` This patch also adds translation to LLVM IR hooks for the `ptr_diff` op. This translation uses the `ptrtoaddr` builder to compute only index bits difference. Example: ```mlir llvm.func @ptr_diff_vector_i32(%ptrs1: vector<8x!ptr.ptr<#llvm.address_space<0>>>, %ptrs2: vector<8x!ptr.ptr<#llvm.address_space<0>>>) -> vector<8xi32> { %diffs = ptr.ptr_diff %ptrs1, %ptrs2 : vector<8x!ptr.ptr<#llvm.address_space<0>>> -> vector<8xi32> llvm.return %diffs : vector<8xi32> } ``` Translation to LLVM IR: ```llvm define <8 x i32> @ptr_diff_vector_i32(<8 x ptr> %0, <8 x ptr> %1) { %3 = ptrtoint <8 x ptr> %0 to <8 x i64> %4 = ptrtoint <8 x ptr> %1 to <8 x i64> %5 = sub <8 x i64> %3, %4 %6 = trunc <8 x i64> %5 to <8 x i32> ret <8 x i32> %6 } ``` --------- Co-authored-by: Mehdi Amini <joker.eph@gmail.com>
1 parent 2bf3748 commit e3aa00e

File tree

7 files changed

+272
-0
lines changed

7 files changed

+272
-0
lines changed

mlir/include/mlir/Dialect/Ptr/IR/PtrEnums.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,14 @@ def Ptr_PtrAddFlags : I32Enum<"PtrAddFlags", "Pointer add flags", [
7979
let cppNamespace = "::mlir::ptr";
8080
}
8181

82+
//===----------------------------------------------------------------------===//
83+
// Ptr diff flags enum properties.
84+
//===----------------------------------------------------------------------===//
85+
86+
def Ptr_PtrDiffFlags : I8BitEnum<"PtrDiffFlags", "Pointer difference flags", [
87+
I8BitEnumCase<"none", 0>, I8BitEnumCase<"nuw", 1>, I8BitEnumCase<"nsw", 2>
88+
]> {
89+
let cppNamespace = "::mlir::ptr";
90+
}
91+
8292
#endif // PTR_ENUMS

mlir/include/mlir/Dialect/Ptr/IR/PtrOps.td

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,63 @@ def Ptr_PtrAddOp : Pointer_Op<"ptr_add", [
415415
}];
416416
}
417417

418+
//===----------------------------------------------------------------------===//
419+
// PtrDiffOp
420+
//===----------------------------------------------------------------------===//
421+
422+
def Ptr_PtrDiffOp : Pointer_Op<"ptr_diff", [
423+
Pure, AllTypesMatch<["lhs", "rhs"]>, SameOperandsAndResultShape
424+
]> {
425+
let summary = "Pointer difference operation";
426+
let description = [{
427+
The `ptr_diff` operation computes the difference between two pointers,
428+
returning an integer or index value representing the number of bytes
429+
between them.
430+
431+
The operation supports both scalar and shaped types with value semantics:
432+
- When both operands are scalar: produces a single difference value
433+
- When both are shaped: performs element-wise subtraction,
434+
shapes must be the same
435+
436+
The operation also supports the following flags:
437+
- `none`: No flags are set.
438+
- `nuw`: No Unsigned Wrap, if the subtraction causes an unsigned overflow
439+
(that is: the result would be negative), the result is a poison value.
440+
- `nsw`: No Signed Wrap, if the subtraction causes a signed overflow, the
441+
result is a poison value.
442+
443+
NOTE: The pointer difference is calculated using an integer type specified
444+
by the data layout. The final result will be sign-extended or truncated to
445+
fit the result type as necessary.
446+
447+
Example:
448+
449+
```mlir
450+
// Scalar pointers
451+
%diff = ptr.ptr_diff %p1, %p2 : !ptr.ptr<#ptr.generic_space> -> i64
452+
453+
// Shaped pointers
454+
%diffs = ptr.ptr_diff nsw %ptrs1, %ptrs2 :
455+
vector<4x!ptr.ptr<#ptr.generic_space>> -> vector<4xi64>
456+
```
457+
}];
458+
let arguments = (ins
459+
Ptr_PtrLikeType:$lhs, Ptr_PtrLikeType:$rhs,
460+
DefaultValuedProp<EnumProp<Ptr_PtrDiffFlags>, "PtrDiffFlags::none">:$flags
461+
);
462+
let results = (outs Ptr_IntLikeType:$result);
463+
let assemblyFormat = [{
464+
($flags^)? $lhs `,` $rhs attr-dict `:` type($lhs) `->` type($result)
465+
}];
466+
let extraClassDeclaration = [{
467+
/// Returns the operand's ptr type.
468+
ptr::PtrType getPtrType();
469+
/// Returns the result's underlying int type.
470+
Type getIntType();
471+
}];
472+
let hasVerifier = 1;
473+
}
474+
418475
//===----------------------------------------------------------------------===//
419476
// ScatterOp
420477
//===----------------------------------------------------------------------===//

mlir/lib/Dialect/Ptr/IR/PtrDialect.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "mlir/IR/Matchers.h"
1616
#include "mlir/Interfaces/DataLayoutInterfaces.h"
1717
#include "mlir/Transforms/InliningUtils.h"
18+
#include "llvm/ADT/StringExtras.h"
1819
#include "llvm/ADT/TypeSwitch.h"
1920

2021
using namespace mlir;
@@ -391,6 +392,39 @@ LogicalResult PtrAddOp::inferReturnTypes(
391392
return success();
392393
}
393394

395+
//===----------------------------------------------------------------------===//
396+
// PtrDiffOp
397+
//===----------------------------------------------------------------------===//
398+
399+
LogicalResult PtrDiffOp::verify() {
400+
// If the operands are not shaped early exit.
401+
if (!isa<ShapedType>(getLhs().getType()))
402+
return success();
403+
404+
// Just check the container type matches, `SameOperandsAndResultShape` handles
405+
// the actual shape.
406+
if (getResult().getType().getTypeID() != getLhs().getType().getTypeID()) {
407+
return emitError() << "expected the result to have the same container "
408+
"type as the operands when operands are shaped";
409+
}
410+
411+
return success();
412+
}
413+
414+
ptr::PtrType PtrDiffOp::getPtrType() {
415+
Type lhsType = getLhs().getType();
416+
if (auto shapedType = dyn_cast<ShapedType>(lhsType))
417+
return cast<ptr::PtrType>(shapedType.getElementType());
418+
return cast<ptr::PtrType>(lhsType);
419+
}
420+
421+
Type PtrDiffOp::getIntType() {
422+
Type resultType = getResult().getType();
423+
if (auto shapedType = dyn_cast<ShapedType>(resultType))
424+
return shapedType.getElementType();
425+
return resultType;
426+
}
427+
394428
//===----------------------------------------------------------------------===//
395429
// ToPtrOp
396430
//===----------------------------------------------------------------------===//

mlir/lib/Target/LLVMIR/Dialect/Ptr/PtrToLLVMIRTranslation.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,42 @@ translateConstantOp(ConstantOp constantOp, llvm::IRBuilderBase &builder,
351351
return success();
352352
}
353353

354+
/// Translate ptr.ptr_diff operation operation to LLVM IR.
355+
static LogicalResult
356+
translatePtrDiffOp(PtrDiffOp ptrDiffOp, llvm::IRBuilderBase &builder,
357+
LLVM::ModuleTranslation &moduleTranslation) {
358+
llvm::Value *lhs = moduleTranslation.lookupValue(ptrDiffOp.getLhs());
359+
llvm::Value *rhs = moduleTranslation.lookupValue(ptrDiffOp.getRhs());
360+
361+
if (!lhs || !rhs)
362+
return ptrDiffOp.emitError("Failed to lookup operands");
363+
364+
// Translate result type to LLVM type
365+
llvm::Type *resultType =
366+
moduleTranslation.convertType(ptrDiffOp.getResult().getType());
367+
if (!resultType)
368+
return ptrDiffOp.emitError("Failed to translate result type");
369+
370+
PtrDiffFlags flags = ptrDiffOp.getFlags();
371+
372+
// Convert both pointers to integers using ptrtoaddr, and compute the
373+
// difference: lhs - rhs
374+
llvm::Value *llLhs = builder.CreatePtrToAddr(lhs);
375+
llvm::Value *llRhs = builder.CreatePtrToAddr(rhs);
376+
llvm::Value *result = builder.CreateSub(
377+
llLhs, llRhs, /*Name=*/"",
378+
/*HasNUW=*/(flags & PtrDiffFlags::nuw) == PtrDiffFlags::nuw,
379+
/*HasNSW=*/(flags & PtrDiffFlags::nsw) == PtrDiffFlags::nsw);
380+
381+
// Convert the difference to the expected result type by truncating or
382+
// extending.
383+
if (result->getType() != resultType)
384+
result = builder.CreateIntCast(result, resultType, /*isSigned=*/true);
385+
386+
moduleTranslation.mapValue(ptrDiffOp.getResult(), result);
387+
return success();
388+
}
389+
354390
/// Implementation of the dialect interface that translates operations belonging
355391
/// to the `ptr` dialect to LLVM IR.
356392
class PtrDialectLLVMIRTranslationInterface
@@ -371,6 +407,9 @@ class PtrDialectLLVMIRTranslationInterface
371407
.Case([&](PtrAddOp ptrAddOp) {
372408
return translatePtrAddOp(ptrAddOp, builder, moduleTranslation);
373409
})
410+
.Case([&](PtrDiffOp ptrDiffOp) {
411+
return translatePtrDiffOp(ptrDiffOp, builder, moduleTranslation);
412+
})
374413
.Case([&](LoadOp loadOp) {
375414
return translateLoadOp(loadOp, builder, moduleTranslation);
376415
})

mlir/test/Dialect/Ptr/invalid.mlir

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,11 @@ func.func @ptr_add_shape_mismatch(%ptrs: tensor<8x!ptr.ptr<#ptr.generic_space>>,
7070
%res = ptr.ptr_add %ptrs, %offsets : tensor<8x!ptr.ptr<#ptr.generic_space>>, tensor<4xi64>
7171
return %res : tensor<8x!ptr.ptr<#ptr.generic_space>>
7272
}
73+
74+
// -----
75+
76+
func.func @ptr_diff_mismatch(%lhs: tensor<8x!ptr.ptr<#ptr.generic_space>>, %rhs: tensor<8x!ptr.ptr<#ptr.generic_space>>) -> vector<8xi64> {
77+
// expected-error@+1 {{the result to have the same container type as the operands when operands are shaped}}
78+
%res = ptr.ptr_diff %lhs, %rhs : tensor<8x!ptr.ptr<#ptr.generic_space>> -> vector<8xi64>
79+
return %res : vector<8xi64>
80+
}

mlir/test/Dialect/Ptr/ops.mlir

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,31 @@ func.func @constant_large_address_ops() -> (!ptr.ptr<#ptr.generic_space>, !ptr.p
211211
%addr_large = ptr.constant #ptr.address<0x123456789ABCDEF0> : !ptr.ptr<#llvm.address_space<0>>
212212
return %addr_max32, %addr_large : !ptr.ptr<#ptr.generic_space>, !ptr.ptr<#llvm.address_space<0>>
213213
}
214+
215+
/// Test ptr_diff operations with scalar pointers
216+
func.func @ptr_diff_scalar_ops(%ptr1: !ptr.ptr<#ptr.generic_space>, %ptr2: !ptr.ptr<#ptr.generic_space>) -> (i64, index, i32) {
217+
%diff_i64 = ptr.ptr_diff %ptr1, %ptr2 : !ptr.ptr<#ptr.generic_space> -> i64
218+
%diff_index = ptr.ptr_diff %ptr1, %ptr2 : !ptr.ptr<#ptr.generic_space> -> index
219+
%diff_i32 = ptr.ptr_diff nuw %ptr1, %ptr2 : !ptr.ptr<#ptr.generic_space> -> i32
220+
return %diff_i64, %diff_index, %diff_i32 : i64, index, i32
221+
}
222+
223+
/// Test ptr_diff operations with vector pointers
224+
func.func @ptr_diff_vector_ops(%ptrs1: vector<4x!ptr.ptr<#ptr.generic_space>>, %ptrs2: vector<4x!ptr.ptr<#ptr.generic_space>>) -> (vector<4xi64>, vector<4xindex>) {
225+
%diff_i64 = ptr.ptr_diff none %ptrs1, %ptrs2 : vector<4x!ptr.ptr<#ptr.generic_space>> -> vector<4xi64>
226+
%diff_index = ptr.ptr_diff %ptrs1, %ptrs2 : vector<4x!ptr.ptr<#ptr.generic_space>> -> vector<4xindex>
227+
return %diff_i64, %diff_index : vector<4xi64>, vector<4xindex>
228+
}
229+
230+
/// Test ptr_diff operations with tensor pointers
231+
func.func @ptr_diff_tensor_ops(%ptrs1: tensor<8x!ptr.ptr<#ptr.generic_space>>, %ptrs2: tensor<8x!ptr.ptr<#ptr.generic_space>>) -> (tensor<8xi64>, tensor<8xi32>) {
232+
%diff_i64 = ptr.ptr_diff nsw %ptrs1, %ptrs2 : tensor<8x!ptr.ptr<#ptr.generic_space>> -> tensor<8xi64>
233+
%diff_i32 = ptr.ptr_diff nsw | nuw %ptrs1, %ptrs2 : tensor<8x!ptr.ptr<#ptr.generic_space>> -> tensor<8xi32>
234+
return %diff_i64, %diff_i32 : tensor<8xi64>, tensor<8xi32>
235+
}
236+
237+
/// Test ptr_diff operations with 2D tensor pointers
238+
func.func @ptr_diff_tensor_2d_ops(%ptrs1: tensor<4x8x!ptr.ptr<#ptr.generic_space>>, %ptrs2: tensor<4x8x!ptr.ptr<#ptr.generic_space>>) -> tensor<4x8xi64> {
239+
%diff = ptr.ptr_diff %ptrs1, %ptrs2 : tensor<4x8x!ptr.ptr<#ptr.generic_space>> -> tensor<4x8xi64>
240+
return %diff : tensor<4x8xi64>
241+
}

mlir/test/Target/LLVMIR/ptr.mlir

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,99 @@ llvm.func @ptr_add_cst() -> !ptr.ptr<#llvm.address_space<0>> {
281281
%res = ptr.ptr_add %ptr, %off : !ptr.ptr<#llvm.address_space<0>>, i32
282282
llvm.return %res : !ptr.ptr<#llvm.address_space<0>>
283283
}
284+
285+
// CHECK-LABEL: define i64 @ptr_diff_scalar
286+
// CHECK-SAME: (ptr %[[PTR1:.*]], ptr %[[PTR2:.*]]) {
287+
// CHECK-NEXT: %[[P1INT:.*]] = ptrtoint ptr %[[PTR1]] to i64
288+
// CHECK-NEXT: %[[P2INT:.*]] = ptrtoint ptr %[[PTR2]] to i64
289+
// CHECK-NEXT: %[[DIFF:.*]] = sub i64 %[[P1INT]], %[[P2INT]]
290+
// CHECK-NEXT: ret i64 %[[DIFF]]
291+
// CHECK-NEXT: }
292+
llvm.func @ptr_diff_scalar(%ptr1: !ptr.ptr<#llvm.address_space<0>>, %ptr2: !ptr.ptr<#llvm.address_space<0>>) -> i64 {
293+
%diff = ptr.ptr_diff %ptr1, %ptr2 : !ptr.ptr<#llvm.address_space<0>> -> i64
294+
llvm.return %diff : i64
295+
}
296+
297+
// CHECK-LABEL: define i32 @ptr_diff_scalar_i32
298+
// CHECK-SAME: (ptr %[[PTR1:.*]], ptr %[[PTR2:.*]]) {
299+
// CHECK-NEXT: %[[P1INT:.*]] = ptrtoint ptr %[[PTR1]] to i64
300+
// CHECK-NEXT: %[[P2INT:.*]] = ptrtoint ptr %[[PTR2]] to i64
301+
// CHECK-NEXT: %[[DIFF:.*]] = sub i64 %[[P1INT]], %[[P2INT]]
302+
// CHECK-NEXT: %[[TRUNC:.*]] = trunc i64 %[[DIFF]] to i32
303+
// CHECK-NEXT: ret i32 %[[TRUNC]]
304+
// CHECK-NEXT: }
305+
llvm.func @ptr_diff_scalar_i32(%ptr1: !ptr.ptr<#llvm.address_space<0>>, %ptr2: !ptr.ptr<#llvm.address_space<0>>) -> i32 {
306+
%diff = ptr.ptr_diff %ptr1, %ptr2 : !ptr.ptr<#llvm.address_space<0>> -> i32
307+
llvm.return %diff : i32
308+
}
309+
310+
// CHECK-LABEL: define <4 x i64> @ptr_diff_vector
311+
// CHECK-SAME: (<4 x ptr> %[[PTRS1:.*]], <4 x ptr> %[[PTRS2:.*]]) {
312+
// CHECK-NEXT: %[[P1INT:.*]] = ptrtoint <4 x ptr> %[[PTRS1]] to <4 x i64>
313+
// CHECK-NEXT: %[[P2INT:.*]] = ptrtoint <4 x ptr> %[[PTRS2]] to <4 x i64>
314+
// CHECK-NEXT: %[[DIFF:.*]] = sub <4 x i64> %[[P1INT]], %[[P2INT]]
315+
// CHECK-NEXT: ret <4 x i64> %[[DIFF]]
316+
// CHECK-NEXT: }
317+
llvm.func @ptr_diff_vector(%ptrs1: vector<4x!ptr.ptr<#llvm.address_space<0>>>, %ptrs2: vector<4x!ptr.ptr<#llvm.address_space<0>>>) -> vector<4xi64> {
318+
%diffs = ptr.ptr_diff %ptrs1, %ptrs2 : vector<4x!ptr.ptr<#llvm.address_space<0>>> -> vector<4xi64>
319+
llvm.return %diffs : vector<4xi64>
320+
}
321+
322+
// CHECK-LABEL: define <8 x i32> @ptr_diff_vector_i32
323+
// CHECK-SAME: (<8 x ptr> %[[PTRS1:.*]], <8 x ptr> %[[PTRS2:.*]]) {
324+
// CHECK-NEXT: %[[P1INT:.*]] = ptrtoint <8 x ptr> %[[PTRS1]] to <8 x i64>
325+
// CHECK-NEXT: %[[P2INT:.*]] = ptrtoint <8 x ptr> %[[PTRS2]] to <8 x i64>
326+
// CHECK-NEXT: %[[DIFF:.*]] = sub <8 x i64> %[[P1INT]], %[[P2INT]]
327+
// CHECK-NEXT: %[[TRUNC:.*]] = trunc <8 x i64> %[[DIFF]] to <8 x i32>
328+
// CHECK-NEXT: ret <8 x i32> %[[TRUNC]]
329+
// CHECK-NEXT: }
330+
llvm.func @ptr_diff_vector_i32(%ptrs1: vector<8x!ptr.ptr<#llvm.address_space<0>>>, %ptrs2: vector<8x!ptr.ptr<#llvm.address_space<0>>>) -> vector<8xi32> {
331+
%diffs = ptr.ptr_diff %ptrs1, %ptrs2 : vector<8x!ptr.ptr<#llvm.address_space<0>>> -> vector<8xi32>
332+
llvm.return %diffs : vector<8xi32>
333+
}
334+
335+
// CHECK-LABEL: define i64 @ptr_diff_with_constants() {
336+
// CHECK-NEXT: ret i64 4096
337+
// CHECK-NEXT: }
338+
llvm.func @ptr_diff_with_constants() -> i64 {
339+
%ptr1 = ptr.constant #ptr.address<0x2000> : !ptr.ptr<#llvm.address_space<0>>
340+
%ptr2 = ptr.constant #ptr.address<0x1000> : !ptr.ptr<#llvm.address_space<0>>
341+
%diff = ptr.ptr_diff %ptr1, %ptr2 : !ptr.ptr<#llvm.address_space<0>> -> i64
342+
llvm.return %diff : i64
343+
}
344+
345+
// CHECK-LABEL: define i64 @ptr_diff_with_flags_nsw
346+
// CHECK-SAME: (ptr %[[PTR1:.*]], ptr %[[PTR2:.*]]) {
347+
// CHECK-NEXT: %[[P1INT:.*]] = ptrtoint ptr %[[PTR1]] to i64
348+
// CHECK-NEXT: %[[P2INT:.*]] = ptrtoint ptr %[[PTR2]] to i64
349+
// CHECK-NEXT: %[[DIFF:.*]] = sub nsw i64 %[[P1INT]], %[[P2INT]]
350+
// CHECK-NEXT: ret i64 %[[DIFF]]
351+
// CHECK-NEXT: }
352+
llvm.func @ptr_diff_with_flags_nsw(%ptr1: !ptr.ptr<#llvm.address_space<0>>, %ptr2: !ptr.ptr<#llvm.address_space<0>>) -> i64 {
353+
%diff = ptr.ptr_diff nsw %ptr1, %ptr2 : !ptr.ptr<#llvm.address_space<0>> -> i64
354+
llvm.return %diff : i64
355+
}
356+
357+
// CHECK-LABEL: define i64 @ptr_diff_with_flags_nuw
358+
// CHECK-SAME: (ptr %[[PTR1:.*]], ptr %[[PTR2:.*]]) {
359+
// CHECK-NEXT: %[[P1INT:.*]] = ptrtoint ptr %[[PTR1]] to i64
360+
// CHECK-NEXT: %[[P2INT:.*]] = ptrtoint ptr %[[PTR2]] to i64
361+
// CHECK-NEXT: %[[DIFF:.*]] = sub nuw i64 %[[P1INT]], %[[P2INT]]
362+
// CHECK-NEXT: ret i64 %[[DIFF]]
363+
// CHECK-NEXT: }
364+
llvm.func @ptr_diff_with_flags_nuw(%ptr1: !ptr.ptr<#llvm.address_space<0>>, %ptr2: !ptr.ptr<#llvm.address_space<0>>) -> i64 {
365+
%diff = ptr.ptr_diff nuw %ptr1, %ptr2 : !ptr.ptr<#llvm.address_space<0>> -> i64
366+
llvm.return %diff : i64
367+
}
368+
369+
// CHECK-LABEL: define i64 @ptr_diff_with_flags_nsw_nuw
370+
// CHECK-SAME: (ptr %[[PTR1:.*]], ptr %[[PTR2:.*]]) {
371+
// CHECK-NEXT: %[[P1INT:.*]] = ptrtoint ptr %[[PTR1]] to i64
372+
// CHECK-NEXT: %[[P2INT:.*]] = ptrtoint ptr %[[PTR2]] to i64
373+
// CHECK-NEXT: %[[DIFF:.*]] = sub nuw nsw i64 %[[P1INT]], %[[P2INT]]
374+
// CHECK-NEXT: ret i64 %[[DIFF]]
375+
// CHECK-NEXT: }
376+
llvm.func @ptr_diff_with_flags_nsw_nuw(%ptr1: !ptr.ptr<#llvm.address_space<0>>, %ptr2: !ptr.ptr<#llvm.address_space<0>>) -> i64 {
377+
%diff = ptr.ptr_diff nsw | nuw %ptr1, %ptr2 : !ptr.ptr<#llvm.address_space<0>> -> i64
378+
llvm.return %diff : i64
379+
}

0 commit comments

Comments
 (0)