Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dialects: Add print_int, print_char ops. #1311

Merged
merged 28 commits into from Aug 14, 2023
Merged

Conversation

JosseVanDelm
Copy link
Collaborator

Hi, this is an initial PR for adding more self-contained printing capabilities to the printf dialect.
I'm still unsure about a lot of stuff, and it is not finished yet, some initial help is appreciated!

This PR adds:

Two new ops:

  • A "printf.print_char" op. An operation that prints a single character, that is taken in as a 32-bit integer.
  • A "printf.print_int" op. An operation that prints a 32 bit integer.
    One pass lower-printchar-to-putchar (naming suggestions welcome!) that implements:
  • A rewrite from print_int to a func.func inline_itoa calls. The implementation of inline_itoa is inserted in the pass. Inline_itoa was written in MLIR assembly directly.
  • A rewrite that lowers print_chars to C style put_chars.

Rationale

Some platforms don't ship with printf implementations or are very bad at printing. This implementation allows for printing integers:

  • without relying much on external libraries (besides put_char)
  • at (maybe?) increased performance, since now MLIR-passes can actually perform constant folding and the likes.
    I think we can (if necessary) even write a pass that composes the current printf.format() into print_chars and print_ints if necessary.

Why a print_char op?

  • Because I felt like using putchar directly was a bit ugly (it returns what it puts, which you typically don't really need, I believe, and because some other platforms might implement these calls in a different way than the standard C approach.

Why a print_int op?

  • Some platforms implement this directly. It is for example available as a RISC-V syscall.

Still missing/Questions/Concerns

  • It feels like I'm not implementing signless semantics properly (should I make a signed print and unsigned print instead?). The implementation currently tests if the value is negative, and then prints a minus sign if necessary.
  • I feel like the added itoa routine is not very easy to read and/or review. Any ideas on making this easier?
  • Should I keep this limited to 32-bit integers?
  • Some ops in the conversion seem to be still missing in xdsl (math.log10?), I'll work on these next.

@JosseVanDelm JosseVanDelm added dialects Changes on the dialects convolve labels Jul 20, 2023
@JosseVanDelm JosseVanDelm self-assigned this Jul 20, 2023
@JosseVanDelm JosseVanDelm marked this pull request as draft July 20, 2023 15:00
@codecov
Copy link

codecov bot commented Jul 20, 2023

Codecov Report

Patch coverage: 95.33% and project coverage change: +0.03% 🎉

Comparison is base (23153ed) 90.03% compared to head (0ec51de) 90.06%.
Report is 33 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1311      +/-   ##
==========================================
+ Coverage   90.03%   90.06%   +0.03%     
==========================================
  Files         211      215       +4     
  Lines       26266    26815     +549     
  Branches     3902     3986      +84     
==========================================
+ Hits        23649    24152     +503     
- Misses       2004     2025      +21     
- Partials      613      638      +25     
Files Changed Coverage Δ
xdsl/tools/command_line_tool.py 100.00% <ø> (ø)
xdsl/transforms/printf_to_putchar.py 94.23% <94.23%> (ø)
xdsl/dialects/printf.py 92.64% <95.23%> (+0.98%) ⬆️
tests/dialects/test_arith.py 100.00% <100.00%> (ø)
tests/dialects/test_printf.py 100.00% <100.00%> (ø)
xdsl/dialects/arith.py 91.40% <100.00%> (+0.25%) ⬆️

... and 16 files with indirect coverage changes

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

[
PrintFormatOp,
],
[PrintFormatOp, PrintCharOp, PrintIntOp],
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
[PrintFormatOp, PrintCharOp, PrintIntOp],
[PrintFormatOp, PrintCharOp, PrintIntOp,],

Copy link
Member

Choose a reason for hiding this comment

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

This would be a useful change to minimise spurious git diffs in the future

Copy link
Member

Choose a reason for hiding this comment

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

plz

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sure, but what do you mean with

to minimise spurious git diffs in the future

?

Copy link
Collaborator

@compor compor left a comment

Choose a reason for hiding this comment

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

Thanks for providing such detailed info for this PR, it made the review easier.

I mainly focused on itoa.

As for signless integers, my understanding is that treating them as signed is compatible with their semantics and it's up to the corresponding operation to interpret them as required.
Keeping this working just for 32-bit int sounds good to me for now.

@@ -0,0 +1,15 @@
// RUN: xdsl-opt -p lower-printchar-to-putchar %s | xdsl-opt | filecheck %s

builtin.module {
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: you can omit the builtin.module now and save some indentation space

xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@AntonLydike AntonLydike left a comment

Choose a reason for hiding this comment

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

LGTM with minor corrections!

xdsl/dialects/printf.py Outdated Show resolved Hide resolved
xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
xdsl/dialects/printf.py Show resolved Hide resolved
xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@adutilleul adutilleul left a comment

Choose a reason for hiding this comment

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

Nice!

xdsl/dialects/printf.py Outdated Show resolved Hide resolved
xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
@kingiler
Copy link
Collaborator

kingiler commented Aug 3, 2023

I am happy that printf works and I'm thinking of a way that do not need to use pow.
The following python code looks good despite two while loops:

def reverse(n: int) -> int: # n is absolute value
    m = 0
    while n:
        m = 10 * m + n % 10
        n //= 10
    return m


def print_integer(n: int) -> None:
    m = reverse(n)
    while m:
        print(m % 10, end="") # print single digit as char
        m //= 10


print_integer(123456)

Just some ideas.

@JosseVanDelm
Copy link
Collaborator Author

Thanks for the idea @kingiler, i'm not entirely sure if what you are proposing is strictly necessary though, since the mlir-opt --convert-math-to-funcs seem to already implement this behaviour for us, as it inserts a function to perform powers on integers.

@superlopuh superlopuh changed the title [WIP] dialects: Add print_int, print_char ops. dialects: Add print_int, print_char ops. Aug 8, 2023
xdsl/dialects/printf.py Outdated Show resolved Hide resolved
xdsl/dialects/printf.py Show resolved Hide resolved
xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
)
print_char_walker.rewrite_module(op)
# Add external putchar reference
# TODO Don't insert this if the operation is not there!
Copy link
Member

Choose a reason for hiding this comment

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

Would be good to add this functionality as part of this PR. it should be pretty easy with the symbol table functionality, or just a manual scan of the module op body.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Could you give a reference/example to the symbol table functionality? I don't know it. Thanks!

Copy link
Member

@superlopuh superlopuh Aug 8, 2023

Choose a reason for hiding this comment

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

It might not work here, but in theory can be something like in the get_op_for_symbol function in interpreter.py

    def get_op_for_symbol(self, symbol: str) -> Operation:
        if symbol in self.symbol_table:
            return self.symbol_table[symbol]
        else:
            raise InterpretationError(f'Could not find symbol "{symbol}"')

    @property
    def symbol_table(self) -> dict[str, Operation]:
        if self._symbol_table is None:
            self._symbol_table = {}

            for op in self.module.walk():
                if (symbol_interface := op.get_trait(SymbolOpInterface)) is not None:
                    symbol = symbol_interface.get_sym_attr_name(op)
                    if symbol:
                        self._symbol_table[symbol.data] = op
        return self._symbol_table

Copy link
Member

Choose a reason for hiding this comment

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

Hmm actually maybe just this will work: SymbolTable.lookup_symbol(op, "foo")

Copy link
Member

Choose a reason for hiding this comment

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

If it doesn't work I'd be interested :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Can you doublecheck now

@JosseVanDelm
Copy link
Collaborator Author

As per @AntonLydike's suggestion I've removed the inline_itoa and refactored it to mlir_itoa, which seems to be what mlir-opt does when you lower a math.ipowi with convert-math-to-funcs

xdsl/dialects/printf.py Outdated Show resolved Hide resolved
var_operand_def,
)
from xdsl.parser import Parser
from xdsl.printer import Printer

i8 = builtin.IntegerType(8)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am not sure but i8 seems useful to be put in xdsl/dialect/builtin.py?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Also not sure, I don't think it matters that much though, it would save about one line in code

Copy link
Member

@superlopuh superlopuh left a comment

Choose a reason for hiding this comment

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

Looking good, some minor changes would be nice to make or discuss

xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
xdsl/transforms/printf_to_putchar.py Outdated Show resolved Hide resolved
[
PrintFormatOp,
],
[PrintFormatOp, PrintCharOp, PrintIntOp],
Copy link
Member

Choose a reason for hiding this comment

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

plz

Copy link
Member

@superlopuh superlopuh left a comment

Choose a reason for hiding this comment

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

Looking forward to using this :)

@JosseVanDelm JosseVanDelm merged commit 32a51a7 into main Aug 14, 2023
10 checks passed
@JosseVanDelm JosseVanDelm deleted the Josse/add-print-int branch August 14, 2023 12:51
@JosseVanDelm
Copy link
Collaborator Author

Thank you all for the reviews! I learned a lot while working on this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
convolve dialects Changes on the dialects
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants