-
Notifications
You must be signed in to change notification settings - Fork 80
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
[WIP] dialects (arm): add cf instructions #3744
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// RUN: XDSL_ROUNDTRIP | ||
// RUN: XDSL_GENERIC_ROUNDTRIP | ||
// RUN: xdsl-opt -t arm-asm %s | filecheck %s --check-prefix=CHECK-ASM | ||
|
||
module { | ||
// CHECK: %x1 = arm.get_register : !arm.reg<x1> | ||
%x1 = arm.get_register : !arm.reg<x1> | ||
|
||
// CHECK: %x2 = arm.get_register : !arm.reg<x2> | ||
%x2 = arm.get_register : !arm.reg<x2> | ||
|
||
// CHECK: arm_func.beq %x1, %x2, ^loop {"comment" = "branch if equal"} | ||
// CHECK-ASM: beq %x1, %x2, ^loop # branch if equal | ||
|
||
arm_cf.beq %x1, %x2, ^loop {"comment" = "branch if equal"} : (!arm.reg<x1>, !arm.reg<x2>) -> () | ||
|
||
// Define the loop block | ||
^loop: | ||
arm.label "loop" | ||
|
||
// CHECK-GENERIC: "arm_cf.beq"(%x1, %x2, ^loop) {"comment" = "branch if equal"} : (!arm.register, !arm.register) -> () | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,7 @@ | |
from xdsl.dialects.builtin import ModuleOp | ||
from xdsl.ir import Dialect | ||
|
||
from .ops import ARMOperation, DSMovOp, DSSMulOp, GetRegisterOp | ||
from .ops import ARMOperation, DSMovOp, DSSMulOp, GetRegisterOp, LabelOp | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feels like this could be its own PR There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is actually its own PR now (#3749), and I think all of your other comments are resolved in that one. apologies for the confusion, I will clearly mark WIP PRs from now on |
||
from .register import IntRegisterType | ||
|
||
|
||
|
@@ -26,6 +26,7 @@ def print_assembly(module: ModuleOp, output: IO[str]) -> None: | |
GetRegisterOp, | ||
DSMovOp, | ||
DSSMulOp, | ||
LabelOp, | ||
], | ||
[ | ||
IntRegisterType, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,36 @@ | ||
from typing import TypeAlias | ||
|
||
from xdsl.dialects.arm.register import ARMRegisterType | ||
from xdsl.dialects.builtin import StringAttr | ||
from xdsl.ir import SSAValue | ||
from xdsl.dialects.builtin import ( | ||
AnyIntegerAttr, | ||
StringAttr, | ||
) | ||
from xdsl.ir import ( | ||
Data, | ||
SSAValue, | ||
) | ||
from xdsl.irdl import irdl_attr_definition | ||
from xdsl.parser import AttrParser | ||
from xdsl.printer import Printer | ||
|
||
AssemblyInstructionArg: TypeAlias = SSAValue | ||
|
||
@irdl_attr_definition | ||
class LabelAttr(Data[str]): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not just use a StringAttr here? |
||
name = "arm.label" | ||
|
||
@classmethod | ||
def parse_parameter(cls, parser: AttrParser) -> str: | ||
with parser.in_angle_brackets(): | ||
return parser.parse_str_literal() | ||
|
||
def print_parameter(self, printer: Printer) -> None: | ||
with printer.in_angle_brackets(): | ||
printer.print_string_literal(self.data) | ||
|
||
|
||
AssemblyInstructionArg: TypeAlias = ( | ||
AnyIntegerAttr | LabelAttr | SSAValue | ARMRegisterType | str | int | ||
) | ||
|
||
|
||
def append_comment(line: str, comment: StringAttr | None) -> str: | ||
|
@@ -17,11 +43,10 @@ def append_comment(line: str, comment: StringAttr | None) -> str: | |
|
||
|
||
def assembly_arg_str(arg: AssemblyInstructionArg) -> str: | ||
if isinstance(arg.type, ARMRegisterType): | ||
reg = arg.type.register_name | ||
return reg | ||
if isinstance(arg, ARMRegisterType): | ||
return arg.name | ||
else: | ||
raise ValueError(f"Unexpected register type {arg.type}") | ||
raise ValueError(f"Unexpected register type {type(arg)}") | ||
|
||
|
||
def assembly_line( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,13 +4,14 @@ | |
from xdsl.ir import Operation, SSAValue | ||
from xdsl.irdl import ( | ||
IRDLOperation, | ||
attr_def, | ||
irdl_op_definition, | ||
operand_def, | ||
opt_attr_def, | ||
result_def, | ||
) | ||
|
||
from .assembly import AssemblyInstructionArg, assembly_arg_str, assembly_line | ||
from .assembly import AssemblyInstructionArg, LabelAttr, assembly_arg_str, assembly_line | ||
from .register import IntRegisterType | ||
|
||
|
||
|
@@ -154,3 +155,43 @@ def __init__( | |
|
||
def assembly_line_args(self): | ||
return (self.d, self.s1, self.s2) | ||
|
||
|
||
@irdl_op_definition | ||
class LabelOp(ARMOperation): | ||
""" | ||
The label operation is used to emit text labels (e.g. loop:) that are used | ||
as branch, unconditional jump targets and symbol offsets. | ||
|
||
https://developer.arm.com/documentation/dui0801/l/Symbols--Literals--Expressions--and-Operators/Labels | ||
""" | ||
|
||
name = "arm.label" | ||
label = attr_def(LabelAttr) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any reason this isn't a property? |
||
comment = opt_attr_def(StringAttr) | ||
|
||
assembly_format = "attr-dict" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this not have |
||
|
||
def __init__( | ||
self, | ||
label: str | LabelAttr, | ||
*, | ||
comment: str | StringAttr | None = None, | ||
): | ||
if isinstance(label, str): | ||
label = LabelAttr(label) | ||
if isinstance(comment, str): | ||
comment = StringAttr(comment) | ||
|
||
super().__init__( | ||
attributes={ | ||
"label": label, | ||
"comment": comment, | ||
}, | ||
) | ||
|
||
def assembly_line_args(self): | ||
return () | ||
|
||
def assembly_instruction_name(self) -> str: | ||
return self.label.data |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
from xdsl.dialects import arm | ||
from xdsl.dialects.arm.assembly import AssemblyInstructionArg | ||
from xdsl.dialects.arm.ops import LabelOp | ||
from xdsl.dialects.arm.register import IntRegisterType | ||
from xdsl.dialects.builtin import StringAttr | ||
from xdsl.ir import Dialect, Operation, SSAValue | ||
from xdsl.irdl import ( | ||
Successor, | ||
irdl_op_definition, | ||
operand_def, | ||
successor_def, | ||
traits_def, | ||
) | ||
from xdsl.traits import IsTerminator | ||
|
||
|
||
@irdl_op_definition | ||
class BEqOp(arm.ops.ARMInstruction): | ||
""" | ||
Branch if equal. | ||
""" | ||
|
||
name = "arm_cf.beq" | ||
|
||
s1 = operand_def(IntRegisterType) | ||
s2 = operand_def(IntRegisterType) | ||
|
||
then_block = successor_def() | ||
|
||
assembly_format = ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm aware that this is not correct, but I'm not sure how exactly to fix it. In arm, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I'd add the Let me know if you have more questions on this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not 100% sure, if the constraint is so hard-coded, then maybe we could get away with a single op. Probably worth a discussion. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, it depends on the CPSR AFAIU, and I'm not sure how to model that fully, e.g., when these are cleared, as the specification phrases this as "set by the last flag-setting instruction... etc.". For example, the |
||
"$s1 `,` $s2 `,` $then_block attr-dict `:` `(` type($s1) `,` type($s2) `)`" | ||
) | ||
|
||
traits = traits_def(IsTerminator()) | ||
|
||
def __init__( | ||
self, | ||
s1: Operation | SSAValue, | ||
s2: Operation | SSAValue, | ||
then_block: Successor, | ||
*, | ||
comment: str | StringAttr | None = None, | ||
): | ||
if isinstance(comment, str): | ||
comment = StringAttr(comment) | ||
|
||
super().__init__( | ||
operands=[s1, s2], | ||
attributes={ | ||
"comment": comment, | ||
}, | ||
successors=(then_block,), | ||
) | ||
|
||
def assembly_line_args(self) -> tuple[AssemblyInstructionArg, ...]: | ||
then_label = self.then_block.first_op | ||
assert isinstance(then_label, LabelOp) | ||
return self.s1, self.s2, then_label.label | ||
|
||
|
||
ARM_CF = Dialect( | ||
"arm_cf", | ||
[ | ||
BEqOp, | ||
], | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It surprises me that this verifies, as
ModuleOp
is tagged as being single_block