Skip to content

Commit a08ac0c

Browse files
committed
Add support for the rust offset intrinsic
This patch adds the initial support for generic intrinsics these are do not map directly to GCC builtins and need to be substited with their specificed types. This patch allows for custom implementation body for these functions by specifying handler functions which will generate the applicable intrinsic when asked for. Addresses #658
1 parent 865b609 commit a08ac0c

File tree

7 files changed

+163
-28
lines changed

7 files changed

+163
-28
lines changed

gcc/rust/backend/rust-compile-fnparam.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ class CompileFnParam : public HIRCompileBase, public HIR::HIRPatternVisitor
3636
return compiler.compiled_param;
3737
}
3838

39+
static Bvariable *compile (Context *ctx, tree fndecl, HIR::Pattern *param,
40+
tree decl_type, Location locus)
41+
{
42+
CompileFnParam compiler (ctx, fndecl, decl_type, locus);
43+
param->accept_vis (compiler);
44+
return compiler.compiled_param;
45+
}
46+
3947
void visit (HIR::IdentifierPattern &pattern) override
4048
{
4149
if (!pattern.is_mut ())

gcc/rust/backend/rust-compile-intrinsic.cc

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,20 @@
1515
// <http://www.gnu.org/licenses/>.
1616

1717
#include "rust-compile-intrinsic.h"
18+
#include "rust-compile-type.h"
19+
#include "rust-compile-fnparam.h"
20+
#include "rust-tree.h"
1821

1922
namespace Rust {
2023
namespace Compile {
2124

25+
static tree
26+
offset_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype);
27+
28+
static const std::map<std::string,
29+
std::function<tree (Context *, TyTy::BaseType *)>>
30+
generic_intrinsics = {{"offset", &offset_intrinsic_handler}};
31+
2232
Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}
2333

2434
tree
@@ -82,11 +92,123 @@ Intrinsics::compile (TyTy::FnType *fntype)
8292
if (builtin != nullptr)
8393
return builtin;
8494

95+
// is it an generic builtin?
96+
auto it = generic_intrinsics.find (fntype->get_identifier ());
97+
if (it != generic_intrinsics.end ())
98+
return it->second (ctx, fntype);
99+
85100
Location locus = ctx->get_mappings ()->lookup_location (fntype->get_ref ());
86-
rust_error_at (locus, "unknown builtin");
101+
rust_error_at (locus, "unknown builtin intrinsic: %s",
102+
fntype->get_identifier ().c_str ());
87103

88104
return error_mark_node;
89105
}
90106

107+
static tree
108+
offset_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype_tyty)
109+
{
110+
rust_assert (fntype_tyty->get_kind () == TyTy::TypeKind::FNDEF);
111+
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (fntype_tyty);
112+
const Resolver::CanonicalPath &canonical_path = fntype->get_ident ().path;
113+
114+
// items can be forward compiled which means we may not need to invoke this
115+
// code. We might also have already compiled this generic function as well.
116+
tree lookup = NULL_TREE;
117+
if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup,
118+
fntype->get_id (), fntype))
119+
{
120+
// has this been added to the list then it must be finished
121+
if (ctx->function_completed (lookup))
122+
{
123+
tree dummy = NULL_TREE;
124+
if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy))
125+
{
126+
ctx->insert_function_decl (fntype, lookup);
127+
}
128+
return lookup;
129+
}
130+
}
131+
132+
if (fntype->has_subsititions_defined ())
133+
{
134+
// override the Hir Lookups for the substituions in this context
135+
fntype->override_context ();
136+
}
137+
138+
// offset intrinsic has two params dst pointer and offset isize
139+
if (fntype->get_params ().size () != 2)
140+
{
141+
rust_error_at (fntype->get_ident ().locus,
142+
"invalid number of parameters for offset intrinsic");
143+
return error_mark_node;
144+
}
145+
146+
tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
147+
std::string ir_symbol_name
148+
= canonical_path.get () + fntype->subst_as_string ();
149+
std::string asm_name = ctx->mangle_item (fntype, canonical_path);
150+
151+
unsigned int flags = 0;
152+
tree fndecl
153+
= ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name, asm_name,
154+
flags, fntype->get_ident ().locus);
155+
TREE_PUBLIC (fndecl) = 0;
156+
TREE_READONLY (fndecl) = 1;
157+
DECL_ARTIFICIAL (fndecl) = 1;
158+
DECL_EXTERNAL (fndecl) = 0;
159+
DECL_DECLARED_INLINE_P (fndecl) = 1;
160+
161+
// setup the params
162+
std::vector<Bvariable *> param_vars;
163+
for (auto &parm : fntype->get_params ())
164+
{
165+
auto &referenced_param = parm.first;
166+
auto &param_tyty = parm.second;
167+
auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty);
168+
169+
Location param_locus = referenced_param->get_locus ();
170+
Bvariable *compiled_param_var
171+
= CompileFnParam::compile (ctx, fndecl, referenced_param,
172+
compiled_param_type, param_locus);
173+
174+
param_vars.push_back (compiled_param_var);
175+
}
176+
177+
auto &dst_param = param_vars.at (0);
178+
auto &size_param = param_vars.at (1);
179+
rust_assert (param_vars.size () == 2);
180+
if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
181+
return error_mark_node;
182+
183+
tree enclosing_scope = NULL_TREE;
184+
Location start_location = Location ();
185+
Location end_location = Location ();
186+
187+
tree code_block = ctx->get_backend ()->block (fndecl, enclosing_scope, {},
188+
start_location, end_location);
189+
ctx->push_block (code_block);
190+
191+
// BUILTIN offset FN BODY BEGIN
192+
tree dst = ctx->get_backend ()->var_expression (dst_param, Location ());
193+
tree size = ctx->get_backend ()->var_expression (size_param, Location ());
194+
tree pointer_offset_expr
195+
= pointer_offset_expression (dst, size, BUILTINS_LOCATION);
196+
auto return_statement
197+
= ctx->get_backend ()->return_statement (fndecl, {pointer_offset_expr},
198+
Location ());
199+
ctx->add_statement (return_statement);
200+
// BUILTIN offset FN BODY END
201+
202+
tree bind_tree = ctx->pop_block ();
203+
204+
gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
205+
DECL_SAVED_TREE (fndecl) = bind_tree;
206+
207+
ctx->pop_fn ();
208+
ctx->push_function (fndecl);
209+
210+
return fndecl;
211+
}
212+
91213
} // namespace Compile
92214
} // namespace Rust

gcc/rust/backend/rust-compile-resolve-path.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// <http://www.gnu.org/licenses/>.
1818

1919
#include "rust-compile-resolve-path.h"
20+
#include "rust-compile-intrinsic.h"
2021
#include "rust-compile-item.h"
2122
#include "rust-compile-implitem.h"
2223
#include "rust-compile-expr.h"
@@ -142,6 +143,13 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
142143
TREE_USED (fn) = 1;
143144
return address_expression (fn, expr_locus);
144145
}
146+
else if (fntype->get_abi () == ABI::INTRINSIC)
147+
{
148+
Intrinsics compile (ctx);
149+
fn = compile.compile (fntype);
150+
TREE_USED (fn) = 1;
151+
return address_expression (fn, expr_locus);
152+
}
145153
}
146154

147155
// let the query system figure it out

gcc/rust/backend/rust-tree.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// <http://www.gnu.org/licenses/>.
1818

1919
#include "rust-tree.h"
20+
#include "fold-const.h"
2021
#include "stringpool.h"
2122
#include "attribs.h"
2223
#include "escaped_string.h"
@@ -656,4 +657,21 @@ get_fndecl_from_callee (tree fn)
656657
return NULL_TREE;
657658
}
658659

660+
tree
661+
pointer_offset_expression (tree base_tree, tree index_tree, location_t location)
662+
{
663+
tree element_type_tree = TREE_TYPE (TREE_TYPE (base_tree));
664+
if (base_tree == error_mark_node || TREE_TYPE (base_tree) == error_mark_node
665+
|| index_tree == error_mark_node || element_type_tree == error_mark_node)
666+
return error_mark_node;
667+
668+
tree element_size = TYPE_SIZE_UNIT (element_type_tree);
669+
index_tree = fold_convert_loc (location, sizetype, index_tree);
670+
tree offset
671+
= fold_build2_loc (location, MULT_EXPR, sizetype, index_tree, element_size);
672+
673+
return fold_build2_loc (location, POINTER_PLUS_EXPR, TREE_TYPE (base_tree),
674+
base_tree, offset);
675+
}
676+
659677
} // namespace Rust

gcc/rust/backend/rust-tree.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ expr_loc_or_input_loc (const_tree t);
177177
extern tree
178178
get_fndecl_from_callee (tree fn);
179179

180+
// FIXME some helpers from HIRCompileBase could probably be moved here over time
181+
182+
// Return an expression for the address of BASE[INDEX], used in offset intrinsic
183+
extern tree
184+
pointer_offset_expression (tree base_tree, tree index_tree, location_t locus);
185+
180186
} // namespace Rust
181187

182188
#endif // RUST_TREE

gcc/rust/rust-backend.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,10 +275,6 @@ class Backend
275275
const std::vector<tree> &vals, Location)
276276
= 0;
277277

278-
// Return an expression for the address of BASE[INDEX].
279-
// BASE has a pointer type. This is used for slice indexing.
280-
virtual tree pointer_offset_expression (tree base, tree index, Location) = 0;
281-
282278
// Return an expression for ARRAY[INDEX] as an l-value. ARRAY is a valid
283279
// fixed-length array, not a slice.
284280
virtual tree array_index_expression (tree array, tree index, Location) = 0;

gcc/rust/rust-gcc.cc

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,6 @@ class Gcc_backend : public Backend
246246
tree array_constructor_expression (tree, const std::vector<unsigned long> &,
247247
const std::vector<tree> &, Location);
248248

249-
tree pointer_offset_expression (tree base, tree offset, Location);
250-
251249
tree array_index_expression (tree array, tree index, Location);
252250

253251
tree call_expression (tree caller, tree fn, const std::vector<tree> &args,
@@ -1717,27 +1715,6 @@ Gcc_backend::array_constructor_expression (
17171715
return ret;
17181716
}
17191717

1720-
// Return an expression for the address of BASE[INDEX].
1721-
1722-
tree
1723-
Gcc_backend::pointer_offset_expression (tree base_tree, tree index_tree,
1724-
Location location)
1725-
{
1726-
tree element_type_tree = TREE_TYPE (TREE_TYPE (base_tree));
1727-
if (base_tree == error_mark_node || TREE_TYPE (base_tree) == error_mark_node
1728-
|| index_tree == error_mark_node || element_type_tree == error_mark_node)
1729-
return error_mark_node;
1730-
1731-
tree element_size = TYPE_SIZE_UNIT (element_type_tree);
1732-
index_tree
1733-
= fold_convert_loc (location.gcc_location (), sizetype, index_tree);
1734-
tree offset = fold_build2_loc (location.gcc_location (), MULT_EXPR, sizetype,
1735-
index_tree, element_size);
1736-
tree ptr = fold_build2_loc (location.gcc_location (), POINTER_PLUS_EXPR,
1737-
TREE_TYPE (base_tree), base_tree, offset);
1738-
return ptr;
1739-
}
1740-
17411718
// Return an expression representing ARRAY[INDEX]
17421719

17431720
tree

0 commit comments

Comments
 (0)