sway_ir/
asm.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! An 'asm' block represents an opaque set of Fuel VM assembly instructions, embedded in place and
//! intended to be inserted as is into the assembly code generation.
//!
//! An [`AsmBlock`] has symbols for arguments and an optional return name and contains a list of
//! [`AsmInstruction`].
//!
//! The syntax in Sway for asm blocks is shown by this example, and [`AsmBlock`] represents it
//! symbolically:
//!
//! ```text
//! asm(r1: self, r2: other, r3) {
//!     add r3 r2 r1;
//!     r3: u64
//! }
//! ```

use sway_types::ident::Ident;

use crate::{
    context::Context, irtype::Type, metadata::MetadataIndex, pretty::DebugWithContext, value::Value,
};

#[doc(hidden)]
#[derive(Clone, Debug, DebugWithContext)]
pub struct AsmBlock {
    pub args_names: Vec<Ident>,
    pub body: Vec<AsmInstruction>,
    pub return_type: Type,
    pub return_name: Option<Ident>,
}

#[derive(Clone, Debug)]
pub struct AsmArg {
    pub name: Ident,
    pub initializer: Option<Value>,
}

#[derive(Clone, Debug)]
pub struct AsmInstruction {
    pub op_name: Ident,
    pub args: Vec<Ident>,
    pub immediate: Option<Ident>,
    pub metadata: Option<MetadataIndex>,
}

impl AsmInstruction {
    pub fn log_no_span(
        ra: impl Into<String>,
        rb: impl Into<String>,
        rc: impl Into<String>,
        rd: impl Into<String>,
    ) -> Self {
        AsmInstruction {
            op_name: Ident::new(sway_types::Span::from_string("log".into())),
            args: vec![
                Ident::new_no_span(ra.into()),
                Ident::new_no_span(rb.into()),
                Ident::new_no_span(rc.into()),
                Ident::new_no_span(rd.into()),
            ],
            immediate: None,
            metadata: None,
        }
    }

    pub fn lw_no_span(
        dst: impl Into<String>,
        src: impl Into<String>,
        offset: impl Into<String>,
    ) -> Self {
        AsmInstruction {
            op_name: Ident::new(sway_types::Span::from_string("lw".into())),
            args: vec![
                Ident::new_no_span(dst.into()),
                Ident::new_no_span(src.into()),
            ],
            immediate: Some(Ident::new_no_span(offset.into())),
            metadata: None,
        }
    }

    pub fn mul_no_span(dst: impl Into<String>, a: impl Into<String>, b: impl Into<String>) -> Self {
        AsmInstruction {
            op_name: Ident::new(sway_types::Span::from_string("mul".into())),
            args: vec![
                Ident::new_no_span(dst.into()),
                Ident::new_no_span(a.into()),
                Ident::new_no_span(b.into()),
            ],
            immediate: None,
            metadata: None,
        }
    }

    pub fn add_no_span(dst: impl Into<String>, a: impl Into<String>, b: impl Into<String>) -> Self {
        AsmInstruction {
            op_name: Ident::new(sway_types::Span::from_string("add".into())),
            args: vec![
                Ident::new_no_span(dst.into()),
                Ident::new_no_span(a.into()),
                Ident::new_no_span(b.into()),
            ],
            immediate: None,
            metadata: None,
        }
    }

    pub fn sub_no_span(dst: impl Into<String>, a: impl Into<String>, b: impl Into<String>) -> Self {
        AsmInstruction {
            op_name: Ident::new(sway_types::Span::from_string("sub".into())),
            args: vec![
                Ident::new_no_span(dst.into()),
                Ident::new_no_span(a.into()),
                Ident::new_no_span(b.into()),
            ],
            immediate: None,
            metadata: None,
        }
    }
}

impl AsmBlock {
    /// Create a new [`AsmBlock`] in the passed context and return its handle.
    pub fn new(
        args_names: Vec<Ident>,
        body: Vec<AsmInstruction>,
        return_type: Type,
        return_name: Option<Ident>,
    ) -> Self {
        AsmBlock {
            args_names,
            body,
            return_type,
            return_name,
        }
    }
}