Skip to content

core: Fix location in func block arguments#5690

Open
ZahidWakeel-synthara wants to merge 10 commits intoxdslproject:mainfrom
ZahidWakeel-synthara:zahidw/func_loc_order
Open

core: Fix location in func block arguments#5690
ZahidWakeel-synthara wants to merge 10 commits intoxdslproject:mainfrom
ZahidWakeel-synthara:zahidw/func_loc_order

Conversation

@ZahidWakeel-synthara
Copy link
Contributor

func.func block arguments having locations info are not parsed in xDSL and hence throws parsing errors.

func.func @f_attrs_then_loc(%arg1 : i32 {foo.bar = 2 : i32} loc(unknown)) -> i32 {
      func.return %arg1 : i32
    }

xDSL raises parsing error because it doesn't expect location to be there inside func.func block arguments.

raise ParseError(at_position, msg)
xdsl.utils.exceptions.ParseError: parse_with_location.mlir:20:30
    func.func @f_attrs_then_loc(%arg1 : i32 {foo.bar = 2 : i32} loc(unknown)) -> i32 {
                             ^^^
                             ')' expected

while the same mlir code is parsed by mlir tools without any parsing errors. MLIR also expects the location to be in a specific order like %arg: <type> {attr} loc(...)
mlir supports this kind of location format for instance -

module {
  func.func @f(%arg0: i32 {foo.bar = 1 : i32} loc(unknown)) {
    func.return
  }
}

while if the order of location format is something like %arg: <type> loc(...) {attr} , then it is not supported in MLIR -

module {
  func.func @f(%arg0: i32 loc(unknown) {foo.bar = 1 : i32}) {
    func.return
  }
}

@ZahidWakeel-synthara ZahidWakeel-synthara marked this pull request as ready for review March 2, 2026 08:29
@ZahidWakeel-synthara
Copy link
Contributor Author

@superlopuh @JosseVanDelm @math-fehr Please take a look at this, thanks.

@codecov
Copy link

codecov bot commented Mar 2, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.34%. Comparing base (6c1c5a2) to head (3994a23).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5690      +/-   ##
==========================================
- Coverage   86.34%   86.34%   -0.01%     
==========================================
  Files         406      406              
  Lines       57723    57744      +21     
  Branches     6706     6710       +4     
==========================================
+ Hits        49843    49860      +17     
- Misses       6322     6325       +3     
- Partials     1558     1559       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment on lines +391 to +405
# If a location was parsed, reject attrs that appear after it,
# including empty dictionaries (e.g. `%arg: i32 loc(...) {}`).
if has_loc:
arg_attr_pos = parser.pos
parser.parse_optional_dictionary_attr_dict()
if parser.pos != arg_attr_pos:
parser.raise_error(
"Expected function argument attributes before location."
)

# Reject duplicate locations (e.g. `%arg: i32 ... loc(...) loc(...)`).
if has_loc and parser.parse_optional_location() is not None:
parser.raise_error(
"Expected at most one location in function argument."
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does MLIR have similar errors? I feel like this is a little overkill, as long as a parse error is raised for incorrect format that seems good enough to me, we can't realistically handle all combinations of wrong orders of elements of the IR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@superlopuh I think we can remove the duplicate location check, but should definitely keep the attr before location check as MLIR strictly enforces it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry what I mean is that if this check is removed, it should still raise a parse error, right? Just with a different error message? For the same test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@superlopuh Yes right, but the existing error message is not super clear.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, let's keep the nicer message. I think we're safe testing it with just one test though, as opposed to the current empty and not-empty dictionary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously the empty dict test case was failing, so I had to take care of parser pos before & after parsing attr dict. Hence I added the empty dict test case.

@JosseVanDelm JosseVanDelm self-requested a review March 4, 2026 09:05
@superlopuh superlopuh added the core xDSL core (ir, textual format, ...) label Mar 4, 2026
Copy link
Collaborator

@JosseVanDelm JosseVanDelm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! For me this pull request is good to go, if you address the following points:

  • Please add an extra check test to see if the location information is properly printed. You can do that within the current filecheck tests by using --check-prefix=CHECKPREFIX, see the inline suggestion.
  • Also there are quite a few other users of the print_func_op_like, adding tests for all of them is probably overkill, but could you please also add a test case (+interop test case) for at least one llvm.func operation?

Thank you so much!
Cheers!

@@ -1,2 +1,2 @@
// RUN: xdsl-opt --print-op-generic %s | mlir-opt --mlir-print-op-generic --allow-unregistered-dialect | xdsl-opt | filecheck %s
// RUN: xdsl-opt %s | mlir-opt --mlir-print-op-generic --allow-unregistered-dialect | xdsl-opt | filecheck %s
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add an extra check here to actually check the print with debuginfo, something like:

// RUN: xdsl-opt %s --print-debuginfo | mlir-opt --mlir-print-op-generic --allow-unregistered-dialect | xdsl-opt | filecheck %s --check-prefix=DEBUGINFO

--check-prefix=DEBUGINFO allows you to add extra "check-like" lines like

// DEBUGINFO:  check the debuginfo print here
// DEBUGINFO-NEXT: check the debuginfo print on the next line here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JosseVanDelm @superlopuh In the PR, currently locations attached with func block args are only parsed but not propagated, so applying xdsl-opt driver on such IR results in unknown locations.

builtin.module {
  func.func private @decl_only(%arg0: i32 loc("decl.mlir":1:1))
  func.func @with_body(%arg0: i32 loc("body.mlir":2:3)) {
    func.return
  }
}

On running with xdsl-opt --print-debuginfo

builtin.module {
  func.func private @decl_only(i32) -> ()
  func.func @with_body(%arg0 : i32 loc(unknown)) {
    func.return
  }
}

Function declarations behaviour is similar to how it behaves in MLIR, but function with body should preserve its arg locations which is not the case.
I have implemented a quick fix here: 1436496
Let me know if we can go ahead with this or not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, and looks like it would be good to add as a separate PR before merging this one

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JosseVanDelm @superlopuh

  1. Added this RUN command.
    // RUN: xdsl-opt %s --print-debuginfo | mlir-opt --mlir-print-op-generic --allow-unregistered-dialect | xdsl-opt --print-debuginfo | filecheck %s --check-prefix=DEBUGINFO
  2. I tried to mimic MLIR's behaviour as much as possible except one scenario.
func.func private @f_decl_unnamed_attr_then_loc(i32 {test.arg_name = "x"} loc("model.mlir":7:9))
  // XDSL-CHECK: func.func private @f_decl_unnamed_attr_then_loc(i32) -> ()
  // MLIR-CHECK: func.func private @f_decl_unnamed_attr_then_loc(i32 {test.arg_name = "x"})
  1. Locations are dropped for declarative functions in MLIR, while in xDSL, both attributes & locations are dropped. I don't need this behaviour currently in xDSL hence didn't fix it as this required changes in multiple places.
  2. If this sounds good, we can go for merge and I will push another PR for propagating locations for func block args. Currently known locations turn to unknown locations after parsing. See the func_ops.mlir tests for reference.
func.func private @f_named_attr_then_loc(%arg0: i32 {test.arg_name = "x"} loc("file.mlir":5:7)) {
    func.return
  }
  // DEBUGINFO: func.func private @f_named_attr_then_loc(%{{.*}} : i32 {test.arg_name = "x"} loc(unknown))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how much more code would it be to add it to this PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think at this stage we should probably use this PR to reach the final state that we want to merge, and then either merge it all in one go or pull out independent changes, depending on how the code ends up looking.


func.func private @f(%arg0: i32 loc(unknown) {test.arg_name = "x"})

// CHECK: Expected function argument attributes before location.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get a different error message in MLIR:

➜  snax-mlir git:(main) ✗ mlir-opt test_loc.mlir
test_loc.mlir:5:45: error: expected ')'
func.func private @f(%arg0: i32 loc(unknown) {test.arg_name = "x"})
                                            ^

But I like your implementation

@@ -1 +1 @@
// RUN: XDSL_ROUNDTRIP
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also add an extra line for debuginfo print testing here (see other comment in interop tests)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since mlir-opt doesn't recognize xdsl based dialects like test, I get this error -

<stdin>:13:33: error: unknown type!
func.func @arg_rec(%0 : !test.type<"int"> loc(unknown)) -> !test.type<"int"> {

Hence I added this RUN command:
// RUN: xdsl-opt %s --print-debuginfo | filecheck %s --check-prefix=DEBUGINFO

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add --allow-unregistered-dialect

Signed-off-by: Zahid Wakeel <zahid.wakeel@synthara.ai>
Signed-off-by: Zahid Wakeel <zahid.wakeel@synthara.ai>
Signed-off-by: Zahid Wakeel <zahid.wakeel@synthara.ai>
Signed-off-by: Zahid Wakeel <zahid.wakeel@synthara.ai>
Signed-off-by: Zahid Wakeel <zahid.wakeel@synthara.ai>
Signed-off-by: Zahid Wakeel <zahid.wakeel@synthara.ai>
Signed-off-by: Zahid Wakeel <zahid.wakeel@synthara.ai>
Signed-off-by: Zahid Wakeel <zahid.wakeel@synthara.ai>
Signed-off-by: Zahid Wakeel <zahid.wakeel@synthara.ai>
Signed-off-by: Zahid Wakeel <zahid.wakeel@synthara.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core xDSL core (ir, textual format, ...)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants