Skip to content

Commit

Permalink
Use user-inaccessible chars for encoding :: in feature variables.
Browse files Browse the repository at this point in the history
When setting up feature tracking variables for the optimizer we
previously would normalize `:` as `_`, e.g., `mod::Unit` would lead to
feature variables `__feat%mod__Unit%...`. In various places in the
optimizer we would then use that knowledge to extract module and unit
ID. Since user-specified identifiers can contain literal `_` or `__`
this could confuse the optimizer.

With this patch we now normalize `:` as `@` which is not
user-accessible. We add a new codegen normalization so `@` becomes
`0x40`. This gives a more reliable encoding.

Closes #1504.
  • Loading branch information
bbannier committed Aug 28, 2023
1 parent a3669f9 commit 6aba0f1
Show file tree
Hide file tree
Showing 19 changed files with 1,229 additions and 1,218 deletions.
1 change: 1 addition & 0 deletions hilti/toolchain/src/compiler/cxx/elements.cc
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ std::string cxx::normalize_id(std::string id) {
id.append("_");

id = util::replace(id, "%", "0x25");
id = util::replace(id, "@", "0x40");
id = util::replace(id, "~", "_0x7e_"); // we expect to see this only at the beginning (for "~finally")
return id;
};
Expand Down
2 changes: 1 addition & 1 deletion hilti/toolchain/src/compiler/optimizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ auto idFeatureFromConstant(const ID& featureConstant) -> std::optional<std::pair
const auto& tokens = util::split(id, "%");
assert(tokens.size() == 3);

auto type_id = ID(util::replace(tokens[1], "__", "::"));
auto type_id = ID(util::replace(tokens[1], "@@", "::"));
const auto& feature = tokens[2];

return {{type_id, feature}};
Expand Down
6 changes: 3 additions & 3 deletions spicy/toolchain/src/compiler/codegen/parser-builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ struct ProductionVisitor
pushState(std::move(pstate));

// Disable trimming for random-access units.
const auto id = hilti::util::replace(*unit->id(), ":", "_");
const auto id = hilti::util::replace(*unit->id(), ":", "@");
pushBuilder(builder()->addIf(
builder::id(ID(hilti::rt::fmt("__feat%%%s%%%s", id, "uses_random_access")))),
[&]() { builder()->addAssign(state().trim, builder::bool_(false)); });
Expand Down Expand Up @@ -2327,7 +2327,7 @@ Expression _filters(const ParserState& state) {
if ( ! typeID )
return member;

const auto id = hilti::util::replace(*typeID, ":", "_");
const auto id = hilti::util::replace(*typeID, ":", "@");
const auto flag = builder::id(ID(hilti::rt::fmt("__feat%%%s%%%s", id, "supports_filters")));

return builder::ternary(flag, std::move(member), builder::strong_reference(builder::typeByID("spicy_rt::Filters")));
Expand Down Expand Up @@ -2480,7 +2480,7 @@ void ParserBuilder::guardFeatureCode(const type::Unit& unit, const std::vector<s
return;
}

const auto id = hilti::util::replace(*typeID, ":", "_");
const auto id = hilti::util::replace(*typeID, ":", "@");
auto flags = hilti::util::transform(features, [&](const auto& feature) {
return builder::id(ID(hilti::rt::fmt("__feat%%%s%%%s", id, feature)));
});
Expand Down
2 changes: 1 addition & 1 deletion spicy/toolchain/src/compiler/codegen/unit-builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ Type CodeGen::compileUnit(const type::Unit& unit, bool declare_only) {
add_hook("0x25_synced", {}, attr_sync);

if ( unit.id() ) {
ID typeID = ID(hilti::rt::replace(*unit.id(), ":", "_"));
ID typeID = ID(hilti::rt::replace(*unit.id(), ":", "@"));

addDeclaration(builder::constant(ID(fmt("__feat%%%s%%uses_random_access", typeID)), builder::bool_(true)));
addDeclaration(builder::constant(ID(fmt("__feat%%%s%%is_filter", typeID)), builder::bool_(unit.isFilter())));
Expand Down
128 changes: 64 additions & 64 deletions tests/Baseline/spicy.optimization.default-parser-functions/log
Original file line number Diff line number Diff line change
Expand Up @@ -11,70 +11,70 @@
[debug/optimizer] disabling feature 'uses_random_access' of type 'foo::P0' since it is not used
[debug/optimizer] disabling feature 'uses_random_access' of type 'foo::P1' since it is not used
[debug/optimizer] disabling feature 'uses_random_access' of type 'foo::P2' since it is not used
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%is_filter'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%supports_sinks'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo__P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%is_filter'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%supports_sinks'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P0%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P1%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%supports_filters'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] inlining constant 'foo::__feat%foo@@P2%uses_random_access'
[debug/optimizer] removing declaration for unused function foo::P0::__parse_foo_P0_stage2
[debug/optimizer] removing declaration for unused function foo::P0::__parse_stage1
[debug/optimizer] removing declaration for unused function foo::P0::parse1
Expand Down
Loading

0 comments on commit 6aba0f1

Please sign in to comment.