aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend/rust-compile-asm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/backend/rust-compile-asm.cc')
-rw-r--r--gcc/rust/backend/rust-compile-asm.cc199
1 files changed, 199 insertions, 0 deletions
diff --git a/gcc/rust/backend/rust-compile-asm.cc b/gcc/rust/backend/rust-compile-asm.cc
new file mode 100644
index 0000000..f04a03e
--- /dev/null
+++ b/gcc/rust/backend/rust-compile-asm.cc
@@ -0,0 +1,199 @@
+#include "rust-compile-asm.h"
+#include "rust-compile-expr.h"
+#include "rust-system.h"
+
+namespace Rust {
+namespace Compile {
+
+CompileAsm::CompileAsm (Context *ctx) : HIRCompileBase (ctx) {}
+
+tree
+CompileAsm::tree_codegen_asm (HIR::InlineAsm &expr)
+{
+ auto asm_expr
+ = asm_build_stmt (expr.get_locus (), {asm_construct_string_tree (expr),
+ asm_construct_outputs (expr),
+ asm_construct_inputs (expr),
+ asm_construct_clobber_tree (expr),
+ asm_construct_label_tree (expr)});
+
+ ASM_INPUT_P (asm_expr) = expr.is_simple_asm ();
+ ASM_VOLATILE_P (asm_expr) = false;
+ ASM_INLINE_P (asm_expr) = expr.is_inline_asm ();
+ /*Backend::debug (asm_expr);*/
+ return asm_expr;
+}
+
+tree
+CompileAsm::asm_build_stmt (
+ location_t loc,
+ const std::array<tree, CompileAsm::ASM_TREE_ARRAY_LENGTH> &trees)
+{
+ // Prototype functiion for building an ASM_EXPR tree.
+ tree ret;
+ bool side_effects;
+
+ ret = make_node (ASM_EXPR);
+ TREE_TYPE (ret) = void_type_node;
+ SET_EXPR_LOCATION (ret, loc);
+
+ /* TREE_SIDE_EFFECTS will already be set for statements with
+ implicit side effects. Here we make sure it is set for other
+ expressions by checking whether the parameters have side
+ effects. */
+
+ // This is here because of c-typeck.cc's code
+ // I'm not sure what kind of effects it has
+ side_effects = false;
+ for (size_t i = 0; i < trees.size (); i++)
+ {
+ tree t = trees[i];
+ if (t && !TYPE_P (t))
+ side_effects |= TREE_SIDE_EFFECTS (t);
+ TREE_OPERAND (ret, i) = t;
+ }
+
+ TREE_SIDE_EFFECTS (ret) |= side_effects;
+
+ return ret;
+}
+
+tree
+CompileAsm::asm_construct_string_tree (HIR::InlineAsm &expr)
+{
+ // To construct an ASM_EXPR tree, we need to build a STRING_CST tree.
+ //
+ // We do this by concatenating all the template strings in the InlineAsm
+ // into one big std::string seperated by tabs and newlines. (For easier
+ // debugging and reading)
+ std::stringstream ss;
+ for (const auto &template_str : expr.template_strs)
+ ss << template_str.symbol << "\n";
+
+ std::string result = ss.str ();
+ return Backend::string_constant_expression (result);
+}
+
+tree
+CompileAsm::asm_construct_outputs (HIR::InlineAsm &expr)
+{
+ // TODO: Do i need to do this?
+
+ tree head = NULL_TREE;
+ for (auto &output : expr.get_operands ())
+ {
+ if (output.get_register_type ()
+ == AST::InlineAsmOperand::RegisterType::Out)
+ {
+ auto out = output.get_out ();
+
+ tree out_tree = CompileExpr::Compile (*out.expr, this->ctx);
+ // expects a tree list
+ // TODO: This assumes that the output is a register
+ std::string expr_name = "=r";
+ auto name = build_string (expr_name.size () + 1, expr_name.c_str ());
+ head
+ = chainon (head, build_tree_list (build_tree_list (NULL_TREE, name),
+ out_tree));
+
+ /*Backend::debug (head);*/
+ /*head = chainon (head, out_tree);*/
+ }
+ }
+ return head;
+}
+
+tree
+CompileAsm::asm_construct_inputs (HIR::InlineAsm &expr)
+{
+ // TODO: Do i need to do this?
+ tree head = NULL_TREE;
+ for (auto &input : expr.get_operands ())
+ {
+ if (input.get_register_type () == AST::InlineAsmOperand::RegisterType::In)
+ {
+ auto in = input.get_in ();
+
+ tree in_tree = CompileExpr::Compile (*in.expr, this->ctx);
+ // expects a tree list
+ // TODO: This assumes that the input is a register
+ std::string expr_name = "r";
+ auto name = build_string (expr_name.size () + 1, expr_name.c_str ());
+ head
+ = chainon (head, build_tree_list (build_tree_list (NULL_TREE, name),
+ in_tree));
+
+ /*head = chainon (head, out_tree);*/
+ }
+ }
+ return head;
+}
+
+tree
+CompileAsm::asm_construct_clobber_tree (HIR::InlineAsm &expr)
+{
+ // TODO: Do i need to do this?
+ return NULL_TREE;
+}
+
+tree
+CompileAsm::asm_construct_label_tree (HIR::InlineAsm &expr)
+{
+ // TODO: Do i need to do this?
+ return NULL_TREE;
+}
+
+CompileLlvmAsm::CompileLlvmAsm (Context *ctx) : HIRCompileBase (ctx) {}
+
+tree
+CompileLlvmAsm::construct_operands (std::vector<HIR::LlvmOperand> operands)
+{
+ tree head = NULL_TREE;
+ for (auto &operand : operands)
+ {
+ tree t = CompileExpr::Compile (*operand.expr, this->ctx);
+ auto name = build_string (operand.constraint.size () + 1,
+ operand.constraint.c_str ());
+ head = chainon (head,
+ build_tree_list (build_tree_list (NULL_TREE, name), t));
+ }
+ return head;
+}
+
+tree
+CompileLlvmAsm::construct_clobbers (std::vector<AST::TupleClobber> clobbers)
+{
+ tree head = NULL_TREE;
+ for (auto &clobber : clobbers)
+ {
+ auto name
+ = build_string (clobber.symbol.size () + 1, clobber.symbol.c_str ());
+ head = chainon (head, build_tree_list (NULL_TREE, name));
+ }
+ return head;
+}
+
+tree
+CompileLlvmAsm::tree_codegen_asm (HIR::LlvmInlineAsm &expr)
+{
+ tree ret = make_node (ASM_EXPR);
+ TREE_TYPE (ret) = void_type_node;
+ SET_EXPR_LOCATION (ret, expr.get_locus ());
+ ASM_VOLATILE_P (ret) = expr.options.is_volatile;
+
+ std::stringstream ss;
+ for (const auto &template_str : expr.templates)
+ {
+ ss << template_str.symbol << "\n";
+ }
+
+ ASM_STRING (ret) = Backend::string_constant_expression (ss.str ());
+ ASM_INPUTS (ret) = construct_operands (expr.inputs);
+ ASM_OUTPUTS (ret) = construct_operands (expr.outputs);
+ ASM_CLOBBERS (ret) = construct_clobbers (expr.get_clobbers ());
+
+ return ret;
+}
+
+} // namespace Compile
+} // namespace Rust