Line data Source code
1 : #include "rust-compile-asm.h"
2 : #include "rust-compile-expr.h"
3 : #include "rust-system.h"
4 :
5 : namespace Rust {
6 : namespace Compile {
7 :
8 : static tree
9 31 : chain_asm_operand (tree head, const char *constraint, tree value)
10 : {
11 31 : auto name = build_string (strlen (constraint) + 1, constraint);
12 31 : return chainon (head,
13 31 : build_tree_list (build_tree_list (NULL_TREE, name), value));
14 : }
15 :
16 26 : CompileAsm::CompileAsm (Context *ctx) : HIRCompileBase (ctx) {}
17 :
18 : tree
19 26 : CompileAsm::tree_codegen_asm (HIR::InlineAsm &expr)
20 : {
21 26 : auto asm_expr
22 52 : = asm_build_stmt (expr.get_locus (), {asm_construct_string_tree (expr),
23 26 : asm_construct_outputs (expr),
24 26 : asm_construct_inputs (expr),
25 26 : asm_construct_clobber_tree (expr),
26 26 : asm_construct_label_tree (expr)});
27 :
28 26 : ASM_BASIC_P (asm_expr) = expr.is_simple_asm ();
29 26 : ASM_VOLATILE_P (asm_expr) = false;
30 26 : ASM_INLINE_P (asm_expr) = expr.is_inline_asm ();
31 : /*Backend::debug (asm_expr);*/
32 26 : return asm_expr;
33 : }
34 :
35 : tree
36 26 : CompileAsm::asm_build_stmt (
37 : location_t loc,
38 : const std::array<tree, CompileAsm::ASM_TREE_ARRAY_LENGTH> &trees)
39 : {
40 : // Prototype functiion for building an ASM_EXPR tree.
41 26 : tree ret;
42 26 : bool side_effects;
43 :
44 26 : ret = make_node (ASM_EXPR);
45 26 : TREE_TYPE (ret) = void_type_node;
46 26 : SET_EXPR_LOCATION (ret, loc);
47 :
48 : /* TREE_SIDE_EFFECTS will already be set for statements with
49 : implicit side effects. Here we make sure it is set for other
50 : expressions by checking whether the parameters have side
51 : effects. */
52 :
53 : // This is here because of c-typeck.cc's code
54 : // I'm not sure what kind of effects it has
55 26 : side_effects = false;
56 156 : for (size_t i = 0; i < trees.size (); i++)
57 : {
58 130 : tree t = trees[i];
59 130 : if (t && !TYPE_P (t))
60 56 : side_effects |= TREE_SIDE_EFFECTS (t);
61 130 : TREE_OPERAND (ret, i) = t;
62 : }
63 :
64 26 : TREE_SIDE_EFFECTS (ret) |= side_effects;
65 :
66 26 : return ret;
67 : }
68 :
69 : tree
70 26 : CompileAsm::asm_construct_string_tree (HIR::InlineAsm &expr)
71 : {
72 : // To construct an ASM_EXPR tree, we need to build a STRING_CST tree.
73 : //
74 : // We do this by concatenating all the template strings in the InlineAsm
75 : // into one big std::string seperated by tabs and newlines. (For easier
76 : // debugging and reading)
77 26 : std::stringstream ss;
78 52 : for (const auto &template_str : expr.template_strs)
79 52 : ss << template_str.symbol << "\n";
80 :
81 26 : std::string result = ss.str ();
82 26 : return Backend::string_constant_expression (result);
83 26 : }
84 :
85 : tl::optional<std::reference_wrapper<HIR::Expr>>
86 29 : get_out_expr (HIR::InlineAsmOperand &operand)
87 : {
88 29 : switch (operand.get_register_type ())
89 : {
90 17 : case HIR::InlineAsmOperand::RegisterType::Out:
91 17 : return *operand.get_out ().expr;
92 0 : case HIR::InlineAsmOperand::RegisterType::InOut:
93 0 : return *operand.get_in_out ().expr;
94 2 : case HIR::InlineAsmOperand::RegisterType::SplitInOut:
95 2 : return *operand.get_split_in_out ().out_expr;
96 : case HIR::InlineAsmOperand::RegisterType::Const:
97 : case HIR::InlineAsmOperand::RegisterType::Sym:
98 : case HIR::InlineAsmOperand::RegisterType::Label:
99 : case HIR::InlineAsmOperand::RegisterType::In:
100 : break;
101 : }
102 10 : return tl::nullopt;
103 : }
104 :
105 : tree
106 26 : CompileAsm::asm_construct_outputs (HIR::InlineAsm &expr)
107 : {
108 : // TODO: Do i need to do this?
109 :
110 26 : tree head = NULL_TREE;
111 55 : for (auto &operand : expr.get_operands ())
112 : {
113 29 : tl::optional<std::reference_wrapper<HIR::Expr>> out_expr
114 29 : = get_out_expr (operand);
115 29 : if (!out_expr.has_value ())
116 10 : continue;
117 :
118 19 : tree out_tree = CompileExpr::Compile (*out_expr, this->ctx);
119 : // expects a tree list
120 : // TODO: This assumes that the output is a register
121 19 : head = chain_asm_operand (head, "=r", out_tree);
122 : }
123 26 : return head;
124 : }
125 :
126 : tl::optional<std::reference_wrapper<HIR::Expr>>
127 29 : get_in_expr (HIR::InlineAsmOperand &operand)
128 : {
129 29 : switch (operand.get_register_type ())
130 : {
131 10 : case HIR::InlineAsmOperand::RegisterType::In:
132 10 : return *operand.get_in ().expr;
133 0 : case HIR::InlineAsmOperand::RegisterType::InOut:
134 0 : return *operand.get_in_out ().expr;
135 2 : case HIR::InlineAsmOperand::RegisterType::SplitInOut:
136 2 : return *operand.get_split_in_out ().in_expr;
137 : case HIR::InlineAsmOperand::RegisterType::Const:
138 : case HIR::InlineAsmOperand::RegisterType::Sym:
139 : case HIR::InlineAsmOperand::RegisterType::Label:
140 : case HIR::InlineAsmOperand::RegisterType::Out:
141 : break;
142 : }
143 17 : return tl::nullopt;
144 : }
145 :
146 : tree
147 26 : CompileAsm::asm_construct_inputs (HIR::InlineAsm &expr)
148 : {
149 : // TODO: Do i need to do this?
150 26 : tree head = NULL_TREE;
151 55 : for (auto &operand : expr.get_operands ())
152 : {
153 29 : tl::optional<std::reference_wrapper<HIR::Expr>> in_expr
154 29 : = get_in_expr (operand);
155 29 : if (!in_expr.has_value ())
156 17 : continue;
157 :
158 12 : tree in_tree = CompileExpr::Compile (*in_expr, this->ctx);
159 : // expects a tree list
160 : // TODO: This assumes that the input is a register
161 12 : head = chain_asm_operand (head, "r", in_tree);
162 : }
163 26 : return head;
164 : }
165 :
166 : tree
167 26 : CompileAsm::asm_construct_clobber_tree (HIR::InlineAsm &expr)
168 : {
169 : // TODO: Do i need to do this?
170 26 : return NULL_TREE;
171 : }
172 :
173 : tree
174 26 : CompileAsm::asm_construct_label_tree (HIR::InlineAsm &expr)
175 : {
176 : // TODO: Do i need to do this?
177 26 : return NULL_TREE;
178 : }
179 :
180 2 : CompileLlvmAsm::CompileLlvmAsm (Context *ctx) : HIRCompileBase (ctx) {}
181 :
182 : tree
183 4 : CompileLlvmAsm::construct_operands (std::vector<HIR::LlvmOperand> operands)
184 : {
185 4 : tree head = NULL_TREE;
186 6 : for (auto &operand : operands)
187 : {
188 2 : tree t = CompileExpr::Compile (*operand.expr, this->ctx);
189 2 : auto name = build_string (operand.constraint.size () + 1,
190 : operand.constraint.c_str ());
191 2 : head = chainon (head,
192 : build_tree_list (build_tree_list (NULL_TREE, name), t));
193 : }
194 4 : return head;
195 : }
196 :
197 : tree
198 2 : CompileLlvmAsm::construct_clobbers (std::vector<AST::TupleClobber> clobbers)
199 : {
200 2 : tree head = NULL_TREE;
201 4 : for (auto &clobber : clobbers)
202 : {
203 2 : auto name
204 2 : = build_string (clobber.symbol.size () + 1, clobber.symbol.c_str ());
205 2 : head = chainon (head, build_tree_list (NULL_TREE, name));
206 : }
207 2 : return head;
208 : }
209 :
210 : tree
211 2 : CompileLlvmAsm::tree_codegen_asm (HIR::LlvmInlineAsm &expr)
212 : {
213 2 : tree ret = make_node (ASM_EXPR);
214 2 : TREE_TYPE (ret) = void_type_node;
215 2 : SET_EXPR_LOCATION (ret, expr.get_locus ());
216 2 : ASM_VOLATILE_P (ret) = expr.options.is_volatile;
217 :
218 2 : std::stringstream ss;
219 4 : for (const auto &template_str : expr.templates)
220 : {
221 4 : ss << template_str.symbol << "\n";
222 : }
223 :
224 2 : ASM_STRING (ret) = Backend::string_constant_expression (ss.str ());
225 2 : ASM_INPUTS (ret) = construct_operands (expr.inputs);
226 2 : ASM_OUTPUTS (ret) = construct_operands (expr.outputs);
227 2 : ASM_CLOBBERS (ret) = construct_clobbers (expr.get_clobbers ());
228 :
229 4 : return ret;
230 2 : }
231 :
232 : } // namespace Compile
233 : } // namespace Rust
|