blob: b7143a817af5005b4b8a04ff2f50907303c57c31 [file] [log] [blame]
#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_BASIC_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);
}
tl::optional<std::reference_wrapper<HIR::Expr>>
get_out_expr (HIR::InlineAsmOperand &operand)
{
switch (operand.get_register_type ())
{
case HIR::InlineAsmOperand::RegisterType::Out:
return *operand.get_out ().expr;
case HIR::InlineAsmOperand::RegisterType::InOut:
return *operand.get_in_out ().expr;
case HIR::InlineAsmOperand::RegisterType::SplitInOut:
return *operand.get_split_in_out ().out_expr;
case HIR::InlineAsmOperand::RegisterType::Const:
case HIR::InlineAsmOperand::RegisterType::Sym:
case HIR::InlineAsmOperand::RegisterType::Label:
case HIR::InlineAsmOperand::RegisterType::In:
break;
}
return tl::nullopt;
}
tree
CompileAsm::asm_construct_outputs (HIR::InlineAsm &expr)
{
// TODO: Do i need to do this?
tree head = NULL_TREE;
for (auto &operand : expr.get_operands ())
{
tl::optional<std::reference_wrapper<HIR::Expr>> out_expr
= get_out_expr (operand);
if (!out_expr.has_value ())
continue;
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;
}
tl::optional<std::reference_wrapper<HIR::Expr>>
get_in_expr (HIR::InlineAsmOperand &operand)
{
switch (operand.get_register_type ())
{
case HIR::InlineAsmOperand::RegisterType::In:
return *operand.get_in ().expr;
case HIR::InlineAsmOperand::RegisterType::InOut:
return *operand.get_in_out ().expr;
case HIR::InlineAsmOperand::RegisterType::SplitInOut:
return *operand.get_split_in_out ().in_expr;
case HIR::InlineAsmOperand::RegisterType::Const:
case HIR::InlineAsmOperand::RegisterType::Sym:
case HIR::InlineAsmOperand::RegisterType::Label:
case HIR::InlineAsmOperand::RegisterType::Out:
break;
}
return tl::nullopt;
}
tree
CompileAsm::asm_construct_inputs (HIR::InlineAsm &expr)
{
// TODO: Do i need to do this?
tree head = NULL_TREE;
for (auto &operand : expr.get_operands ())
{
tl::optional<std::reference_wrapper<HIR::Expr>> in_expr
= get_in_expr (operand);
if (!in_expr.has_value ())
continue;
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