From 6f009492e3476bae63131ce5862f627c7cf0be0e Mon Sep 17 00:00:00 2001 From: Owen Avery Date: Sat, 26 Jul 2025 00:48:54 -0400 Subject: [PATCH] Fix u128 rotate operation on 32 bit targets This tweaks how we handle the right hand side of rotate intrinsics and tweaks how we handle integers so that we can fall back on _BitInt(128) on some targets. gcc/rust/ChangeLog: * backend/rust-compile-intrinsic.cc: Include "convert.h". (rotate_handler): Convert the second parameter into an unsigned int. * rust-backend.h (RUST_INT_TREE_U8): Define macro. (RUST_INT_TREE_U16): Likewise. (RUST_INT_TREE_U32): Likewise. (RUST_INT_TREE_U64): Likewise. (RUST_INT_TREE_U128): Likewise. (RUST_INT_TREE_I8): Likewise. (RUST_INT_TREE_I16): Likewise. (RUST_INT_TREE_I32): Likewise. (RUST_INT_TREE_I64): Likewise. (RUST_INT_TREE_I128): Likewise. (rust_int_trees): Declare extern variable. (rust_int_names): Likewise. * rust-gcc.cc: Include "target.h". (rust_int_trees): Define variable. (rust_int_names): Likewise. (setup_normal_integers): Define static function to set up rust_int_trees. (init): Call setup_normal_integers. * backend/rust-compile-type.cc (TyTyResolveCompile::visit): Use rust_int_trees via macros to obtain integer type trees. * config-lang.in (gtfiles): Add "rust-backend.h". gcc/testsuite/ChangeLog: * rust/execute/torture/sip-hasher.rs: Enable on 32 bit targets. Signed-off-by: Owen Avery --- gcc/rust/backend/rust-compile-intrinsic.cc | 11 ++- gcc/rust/backend/rust-compile-type.cc | 35 ++----- gcc/rust/config-lang.in | 1 + gcc/rust/rust-backend.h | 17 ++++ gcc/rust/rust-gcc.cc | 94 +++++++++++++++++++ .../rust/execute/torture/sip-hasher.rs | 1 - 6 files changed, 132 insertions(+), 27 deletions(-) diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index 7627620c4713..b790c785478a 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -28,6 +28,7 @@ #include "rust-gcc.h" #include "fold-const.h" #include "langhooks.h" +#include "convert.h" #include "rust-constexpr.h" // declaration taken from "stringpool.h" @@ -557,8 +558,16 @@ rotate_handler (Context *ctx, TyTy::FnType *fntype, tree_code op) // BUILTIN rotate FN BODY BEGIN tree x = Backend::var_expression (x_param, UNDEF_LOCATION); tree y = Backend::var_expression (y_param, UNDEF_LOCATION); + + tree y_mask + = build_int_cst (unsigned_type_node, element_precision (TREE_TYPE (x)) - 1); + + tree y_truncated + = fold_build2_loc (BUILTINS_LOCATION, BIT_AND_EXPR, unsigned_type_node, + convert_to_integer (unsigned_type_node, y), y_mask); + tree rotate_expr - = fold_build2_loc (BUILTINS_LOCATION, op, TREE_TYPE (x), x, y); + = fold_build2_loc (BUILTINS_LOCATION, op, TREE_TYPE (x), x, y_truncated); auto return_statement = Backend::return_statement (fndecl, rotate_expr, UNDEF_LOCATION); ctx->add_statement (return_statement); diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc index 8f13bba534b6..56c23b23e7c3 100644 --- a/gcc/rust/backend/rust-compile-type.cc +++ b/gcc/rust/backend/rust-compile-type.cc @@ -504,32 +504,23 @@ TyTyResolveCompile::visit (const TyTy::IntType &type) switch (type.get_int_kind ()) { case TyTy::IntType::I8: - translated = Backend::named_type ("i8", Backend::integer_type (false, 8), - BUILTINS_LOCATION); + translated = RUST_INT_TREE_I8; return; case TyTy::IntType::I16: - translated - = Backend::named_type ("i16", Backend::integer_type (false, 16), - BUILTINS_LOCATION); + translated = RUST_INT_TREE_I16; return; case TyTy::IntType::I32: - translated - = Backend::named_type ("i32", Backend::integer_type (false, 32), - BUILTINS_LOCATION); + translated = RUST_INT_TREE_I32; return; case TyTy::IntType::I64: - translated - = Backend::named_type ("i64", Backend::integer_type (false, 64), - BUILTINS_LOCATION); + translated = RUST_INT_TREE_I64; return; case TyTy::IntType::I128: - translated - = Backend::named_type ("i128", Backend::integer_type (false, 128), - BUILTINS_LOCATION); + translated = RUST_INT_TREE_I128; return; } } @@ -540,29 +531,23 @@ TyTyResolveCompile::visit (const TyTy::UintType &type) switch (type.get_uint_kind ()) { case TyTy::UintType::U8: - translated = Backend::named_type ("u8", Backend::integer_type (true, 8), - BUILTINS_LOCATION); + translated = RUST_INT_TREE_U8; return; case TyTy::UintType::U16: - translated = Backend::named_type ("u16", Backend::integer_type (true, 16), - BUILTINS_LOCATION); + translated = RUST_INT_TREE_U16; return; case TyTy::UintType::U32: - translated = Backend::named_type ("u32", Backend::integer_type (true, 32), - BUILTINS_LOCATION); + translated = RUST_INT_TREE_U32; return; case TyTy::UintType::U64: - translated = Backend::named_type ("u64", Backend::integer_type (true, 64), - BUILTINS_LOCATION); + translated = RUST_INT_TREE_U64; return; case TyTy::UintType::U128: - translated - = Backend::named_type ("u128", Backend::integer_type (true, 128), - BUILTINS_LOCATION); + translated = RUST_INT_TREE_U128; return; } } diff --git a/gcc/rust/config-lang.in b/gcc/rust/config-lang.in index 0ded57052b50..71457cb97901 100644 --- a/gcc/rust/config-lang.in +++ b/gcc/rust/config-lang.in @@ -35,4 +35,5 @@ lang_dirs=libgrust gtfiles="\ \$(srcdir)/rust/rust-lang.cc \$(srcdir)/rust/backend/rust-constexpr.cc \ \$(srcdir)/rust/backend/rust-tree.h \$(srcdir)/rust/backend/rust-tree.cc \ +\$(srcdir)/rust/rust-backend.h \ " diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h index 8a77d96de835..691ca567ef15 100644 --- a/gcc/rust/rust-backend.h +++ b/gcc/rust/rust-backend.h @@ -39,6 +39,23 @@ // The backend representation of a variable. class Bvariable; +// rust integer trees + +#define RUST_INT_TREE_U8 (rust_int_trees[0]) +#define RUST_INT_TREE_U16 (rust_int_trees[1]) +#define RUST_INT_TREE_U32 (rust_int_trees[2]) +#define RUST_INT_TREE_U64 (rust_int_trees[3]) +#define RUST_INT_TREE_U128 (rust_int_trees[4]) + +#define RUST_INT_TREE_I8 (rust_int_trees[5]) +#define RUST_INT_TREE_I16 (rust_int_trees[6]) +#define RUST_INT_TREE_I32 (rust_int_trees[7]) +#define RUST_INT_TREE_I64 (rust_int_trees[8]) +#define RUST_INT_TREE_I128 (rust_int_trees[9]) + +extern GTY (()) tree rust_int_trees[10]; +extern const char *rust_int_names[10]; + // The backend interface. This is a pure abstract class that a // specific backend will implement. diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index c5fda5c7a9ca..305849672399 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -45,6 +45,7 @@ #include "builtins.h" #include "print-tree.h" #include "attribs.h" +#include "target.h" #include "rust-location.h" #include "rust-linemap.h" @@ -83,6 +84,11 @@ Bvariable::error_variable () return new Bvariable (error_mark_node); } +// (u, i) X (8, 16, 32, 64, 128) +tree rust_int_trees[10]; +const char *rust_int_names[10] + = {"u8", "u16", "u32", "u64", "u128", "i8", "i16", "i32", "i64", "i128"}; + // This file implements the interface between the Rust frontend proper // and the gcc IR. This implements specific instantiations of // abstract classes defined by the Rust frontend proper. The Rust @@ -95,9 +101,97 @@ namespace Backend { // Define the built-in functions that are exposed to GCCRust. +static void +setup_normal_integers () +{ + // we should have QImode + RUST_INT_TREE_U8 = make_unsigned_type (8); + RUST_INT_TREE_I8 = make_signed_type (8); + + // look through integer types intended for C + const int normal_int_sizes[4] + = {INT_TYPE_SIZE, SHORT_TYPE_SIZE, LONG_TYPE_SIZE, LONG_LONG_TYPE_SIZE}; + const tree normal_int_trees[8] + = {unsigned_type_node, integer_type_node, + short_unsigned_type_node, short_integer_type_node, + long_unsigned_type_node, long_integer_type_node, + long_long_unsigned_type_node, long_long_integer_type_node}; + + for (size_t i = 0; i < 4; i++) + { + int idx = exact_log2 (normal_int_sizes[i]) - 3; + + // if the size wasn't a power of 2, idx == -4 + + if (idx < 0 || idx > 5) + continue; + + if (rust_int_trees[idx] != NULL_TREE) + continue; + + rust_int_trees[idx] = normal_int_trees[2 * i]; + rust_int_trees[5 + idx] = normal_int_trees[2 * i + 1]; + } + + // look through int_n_data for more integer types + for (size_t i = 0, j = 0; i < 5 && j < NUM_INT_N_ENTS;) + { + if (rust_int_trees[i] != NULL_TREE) + { + i++; + continue; + } + + if (!int_n_enabled_p[j] || int_n_data[j].bitsize < (8u << i)) + { + j++; + } + else if (int_n_data[j].bitsize > (8u << i)) + { + i++; + } + else + { + rust_int_trees[i] = make_unsigned_type (8 << i); + rust_int_trees[5 + i] = make_signed_type (8 << i); + i++; + j++; + } + } + + // use _BitInt where we have to (and can) + for (int i = 0; i < 5; i++) + { + if (rust_int_trees[i] == NULL_TREE) + { + bitint_info b_info; + if (targetm.c.bitint_type_info (8 << i, &b_info)) + { + rust_debug ("filling in integer size %u with _BitInt", 8u << i); + rust_int_trees[i] = build_bitint_type (8 << i, true); + rust_int_trees[5 + i] = build_bitint_type (8 << i, false); + } + } + } + + // TODO: bootleg _BitInt where necessary? + + // not much can be done for now -- fill with error_mark_node + for (size_t i = 0; i < 10; i++) + if (rust_int_trees[i] == NULL_TREE) + rust_int_trees[i] = error_mark_node; + + // name types + for (size_t i = 0; i < 10; i++) + rust_int_trees[i] + = named_type (rust_int_names[i], rust_int_trees[i], BUILTINS_LOCATION); +} + void init () { + setup_normal_integers (); + /* We need to define the fetch_and_add functions, since we use them for ++ and --. */ // tree t = this->integer_type (true, BITS_PER_UNIT)->get_tree (); diff --git a/gcc/testsuite/rust/execute/torture/sip-hasher.rs b/gcc/testsuite/rust/execute/torture/sip-hasher.rs index 60826a3ed012..671f69601c07 100644 --- a/gcc/testsuite/rust/execute/torture/sip-hasher.rs +++ b/gcc/testsuite/rust/execute/torture/sip-hasher.rs @@ -1,4 +1,3 @@ -// { dg-skip-if "" { *-*-* } { "-m32" } { "" } } // { dg-options "-w" } // { dg-output "Hash: 0x63d53fd2170bbb8c\r*\n" } #![feature(intrinsics)]