Skip to content

Commit 635bbd0

Browse files
committed
[Tolk] Refactor: IR generation of complex built-ins like T.toCell
Instead of working by a string name, store a pointer to an ops-generator function inside a symbol
1 parent cac968f commit 635bbd0

File tree

11 files changed

+200
-238
lines changed

11 files changed

+200
-238
lines changed

tolk-tester/tests/pack-unpack-5.tolk

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,34 @@ struct JustMaybeInt32 {
1010
value: MaybeInt32;
1111
}
1212

13+
fun T.estimate(): [int, int, int, int] {
14+
// convert a tensor to a tuple for better output readability
15+
val (minBits, maxBits, minRefs, maxRefs) = T.estimatePackSize();
16+
return [minBits, maxBits, minRefs, maxRefs];
17+
}
1318

1419
@method_id(101)
1520
fun test1() {
1621
return (
17-
int32.estimatePackSize(),
18-
uint64.estimatePackSize(),
19-
int1.estimatePackSize(),
20-
bool.estimatePackSize(),
21-
RemainingBitsAndRefs.estimatePackSize(),
22-
coins.estimatePackSize(),
23-
bits6.estimatePackSize(),
24-
bytes8.estimatePackSize(),
25-
varint32.estimatePackSize(),
22+
int32.estimate(),
23+
uint64.estimate(),
24+
int1.estimate(),
25+
bool.estimate(),
26+
RemainingBitsAndRefs.estimate(),
27+
coins.estimate(),
28+
bits6.estimate(),
29+
bytes8.estimate(),
30+
varint32.estimate(),
2631
);
2732
}
2833

2934
@method_id(102)
3035
fun test2() {
3136
return (
32-
JustInt32.estimatePackSize(),
33-
JustMaybeInt32.estimatePackSize(),
34-
MaybeInt32.estimatePackSize(),
35-
Int16Or32.estimatePackSize(),
37+
JustInt32.estimate(),
38+
JustMaybeInt32.estimate(),
39+
MaybeInt32.estimate(),
40+
Int16Or32.estimate(),
3641
);
3742
}
3843

@@ -51,7 +56,7 @@ struct Test3_2 {
5156

5257
@method_id(103)
5358
fun test3() {
54-
return (Test3_1.estimatePackSize(), Test3_2.estimatePackSize());
59+
return (Test3_1.estimate(), Test3_2.estimate());
5560
}
5661

5762
struct Test4_1 {
@@ -71,7 +76,7 @@ struct Test4_3 {
7176

7277
@method_id(104)
7378
fun test4() {
74-
return (Test4_1.estimatePackSize(), Test4_2.estimatePackSize(), Test4_3.estimatePackSize());
79+
return (Test4_1.estimate(), Test4_2.estimate(), Test4_3.estimate());
7580
}
7681

7782
struct Test5_1 {
@@ -99,7 +104,7 @@ struct Test5_3 {
99104

100105
@method_id(105)
101106
fun test5() {
102-
return (Test5_1.estimatePackSize(), Test5_2.estimatePackSize(), Test5_3.estimatePackSize());
107+
return (Test5_1.estimate(), Test5_2.estimate(), Test5_3.estimate());
103108
}
104109

105110
struct(0x00112233) Test6_1 {
@@ -115,7 +120,7 @@ type Test6_or = Test6_1 | Test6_2;
115120

116121
@method_id(106)
117122
fun test6() {
118-
return (Test6_1.estimatePackSize(), Test6_2.estimatePackSize(), Test6_or.estimatePackSize());
123+
return (Test6_1.estimate(), Test6_2.estimate(), Test6_or.estimate());
119124
}
120125

121126
struct(0x1020) Test7_1;
@@ -127,7 +132,7 @@ type Test7_or = | Test7_1 | Test7_2 | Test7_3
127132
@method_id(107)
128133
fun test7() {
129134
assert((Test7_1{} as Test7_or).toCell().beginParse().remainingBitsCount() == Test7_or.estimatePackSize().0, 400);
130-
return (Test7_1.estimatePackSize(), Test7_or.estimatePackSize());
135+
return (Test7_1.estimate(), Test7_or.estimate());
131136
}
132137

133138
struct(0x10) Inner8_1 {
@@ -151,7 +156,7 @@ struct Test8 {
151156

152157
@method_id(108)
153158
fun test8() {
154-
return (Inner8_1.estimatePackSize(), Inner8_2.estimatePackSize(), Test8.estimatePackSize());
159+
return (Inner8_1.estimate(), Inner8_2.estimate(), Test8.estimate());
155160
}
156161

157162
struct Test9_bits2 { f: bits2; }
@@ -164,7 +169,7 @@ type Test9_f4 = bits1 | Test9_bits2 | bits3 | Test9_bits4?; // auto-generate
164169

165170
@method_id(109)
166171
fun test9() {
167-
return (Test9_f1.estimatePackSize(), Test9_f2.estimatePackSize(), Test9_f3.estimatePackSize(), Test9_f4.estimatePackSize());
172+
return (Test9_f1.estimate(), Test9_f2.estimate(), Test9_f3.estimate(), Test9_f4.estimate());
168173
}
169174

170175
struct Test10_1 {
@@ -176,7 +181,7 @@ type Test10_2 = (Test10_1, bool?, RemainingBitsAndRefs);
176181

177182
@method_id(110)
178183
fun test10() {
179-
return (Test10_1.estimatePackSize(), Test10_2.estimatePackSize());
184+
return (Test10_1.estimate(), Test10_2.estimate());
180185
}
181186

182187
struct Test11_1 {
@@ -191,7 +196,7 @@ struct Test11_2 {
191196

192197
@method_id(111)
193198
fun test11() {
194-
return (Test11_1.estimatePackSize(), Test11_2.estimatePackSize());
199+
return (Test11_1.estimate(), Test11_2.estimate());
195200
}
196201

197202
@method_id(120)
@@ -201,7 +206,7 @@ fun test20() {
201206
}
202207

203208
fun main() {
204-
__expect_type(int8.estimatePackSize(), "[int, int, int, int]");
209+
__expect_type(int8.estimatePackSize(), "(int, int, int, int)");
205210
}
206211

207212
/**

tolk/analyzer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
718718
if (arg_order_already_equals_asm()) {
719719
maybe_swap_builtin_args_to_compile();
720720
}
721-
std::get<FunctionBodyBuiltin*>(f_sym->body)->compile(tmp, res, args, loc);
721+
std::get<FunctionBodyBuiltinAsmOp*>(f_sym->body)->compile(tmp, res, args, loc);
722722
if (arg_order_already_equals_asm()) {
723723
maybe_swap_builtin_args_to_compile();
724724
}

tolk/builtins.cpp

Lines changed: 67 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,34 @@ static std::vector<LocalVarData> define_builtin_parameters(const std::vector<Typ
4040
return parameters;
4141
}
4242

43-
static void define_builtin_func(const std::string& name, const std::vector<TypePtr>& params_types, TypePtr return_type, const GenericsDeclaration* genericTs, const simple_compile_func_t& func, int flags) {
44-
auto* f_sym = new FunctionData(name, {}, "", nullptr, return_type, define_builtin_parameters(params_types, flags), flags, FunctionInlineMode::notCalculated, genericTs, nullptr, new FunctionBodyBuiltin(func), nullptr);
43+
static void define_builtin_func(const std::string& name, const std::vector<TypePtr>& params_types, TypePtr return_type, const GenericsDeclaration* genericTs, const std::function<FunctionBodyBuiltinAsmOp::CompileToAsmOpImpl>& func, int flags) {
44+
auto* f_sym = new FunctionData(name, {}, "", nullptr, return_type, define_builtin_parameters(params_types, flags), flags, FunctionInlineMode::notCalculated, genericTs, nullptr, new FunctionBodyBuiltinAsmOp(func), nullptr);
4545
G.symtable.add_function(f_sym);
4646
}
4747

48-
static void define_builtin_method(const std::string& name, TypePtr receiver_type, const std::vector<TypePtr>& params_types, TypePtr return_type, const GenericsDeclaration* genericTs, const simple_compile_func_t& func, int flags,
48+
static void define_builtin_func(const std::string& name, const std::vector<TypePtr>& params_types, TypePtr return_type, const GenericsDeclaration* genericTs, const std::function<FunctionBodyBuiltinGenerateOps::GenerateOpsImpl>& func, int flags) {
49+
auto* f_sym = new FunctionData(name, {}, "", nullptr, return_type, define_builtin_parameters(params_types, flags), flags, FunctionInlineMode::notCalculated, genericTs, nullptr, new FunctionBodyBuiltinGenerateOps(func), nullptr);
50+
G.symtable.add_function(f_sym);
51+
}
52+
53+
static void define_builtin_method(const std::string& name, TypePtr receiver_type, const std::vector<TypePtr>& params_types, TypePtr return_type, const GenericsDeclaration* genericTs, const std::function<FunctionBodyBuiltinAsmOp::CompileToAsmOpImpl>& func, int flags,
4954
std::initializer_list<int> arg_order = {}, std::initializer_list<int> ret_order = {}) {
5055
std::string method_name = name.substr(name.find('.') + 1);
51-
auto* f_sym = new FunctionData(name, {}, std::move(method_name), receiver_type, return_type, define_builtin_parameters(params_types, flags), flags, FunctionInlineMode::notCalculated, genericTs, nullptr, new FunctionBodyBuiltin(func), nullptr);
56+
auto* f_sym = new FunctionData(name, {}, std::move(method_name), receiver_type, return_type, define_builtin_parameters(params_types, flags), flags, FunctionInlineMode::notCalculated, genericTs, nullptr, new FunctionBodyBuiltinAsmOp(func), nullptr);
5257
f_sym->arg_order = arg_order;
5358
f_sym->ret_order = ret_order;
5459
G.symtable.add_function(f_sym);
5560
G.all_methods.push_back(f_sym);
5661
}
5762

58-
void FunctionBodyBuiltin::compile(AsmOpList& dest, std::vector<VarDescr>& out, std::vector<VarDescr>& in,
63+
void define_builtin_method(const std::string& name, TypePtr receiver_type, const std::vector<TypePtr>& params_types, TypePtr return_type, const GenericsDeclaration* genericTs, const std::function<FunctionBodyBuiltinGenerateOps::GenerateOpsImpl>& func, int flags) {
64+
std::string method_name = name.substr(name.find('.') + 1);
65+
auto* f_sym = new FunctionData(name, {}, std::move(method_name), receiver_type, return_type, define_builtin_parameters(params_types, flags), flags, FunctionInlineMode::notCalculated, genericTs, nullptr, new FunctionBodyBuiltinGenerateOps(func), nullptr);
66+
G.symtable.add_function(f_sym);
67+
G.all_methods.push_back(f_sym);
68+
}
69+
70+
void FunctionBodyBuiltinAsmOp::compile(AsmOpList& dest, std::vector<VarDescr>& out, std::vector<VarDescr>& in,
5971
SrcLocation loc) const {
6072
dest << simple_compile(out, in, loc);
6173
}
@@ -1166,7 +1178,7 @@ static AsmOp compile_fetch_slice(std::vector<VarDescr>& res, std::vector<VarDesc
11661178

11671179
// fun slice.tryStripPrefix(mutate self, prefix: int, prefixLen: int): bool
11681180
// constructs "x{...} SDBEGINSQ" for constant arguments
1169-
AsmOp compile_slice_sdbeginsq(std::vector<VarDescr>& res, std::vector<VarDescr>& args, SrcLocation loc) {
1181+
static AsmOp compile_slice_sdbeginsq(std::vector<VarDescr>& res, std::vector<VarDescr>& args, SrcLocation loc) {
11701182
tolk_assert(args.size() == 3 && res.size() == 2);
11711183
auto& prefix = args[1];
11721184
auto& prefix_len = args[2];
@@ -1181,7 +1193,7 @@ AsmOp compile_slice_sdbeginsq(std::vector<VarDescr>& res, std::vector<VarDescr>&
11811193
}
11821194

11831195
// fun slice.skipBits(mutate self, len: int): self "SDSKIPFIRST"
1184-
AsmOp compile_skip_bits_in_slice(std::vector<VarDescr>& res, std::vector<VarDescr>& args, SrcLocation loc) {
1196+
static AsmOp compile_skip_bits_in_slice(std::vector<VarDescr>& res, std::vector<VarDescr>& args, SrcLocation loc) {
11851197
tolk_assert(args.size() == 2 && res.size() == 1);
11861198
auto& len = args[1];
11871199
// same technique as for storeUint:
@@ -1268,7 +1280,7 @@ static AsmOp compile_any_object_sizeof(std::vector<VarDescr>& res, std::vector<V
12681280

12691281
// fun ton(amount: slice): coins; ton("0.05") replaced by 50000000 at compile-time
12701282
// same for stringCrc32(constString: slice) and others
1271-
AsmOp compile_time_only_function(std::vector<VarDescr>&, std::vector<VarDescr>&, SrcLocation loc) {
1283+
static AsmOp compile_time_only_function(std::vector<VarDescr>&, std::vector<VarDescr>&, SrcLocation loc) {
12721284
// all ton() invocations are constants, replaced by integers; no dynamic values allowed, no work at runtime
12731285
tolk_assert(false);
12741286
return AsmOp::Nop(loc);
@@ -1292,6 +1304,24 @@ static AsmOp compile_expect_type(std::vector<VarDescr>&, std::vector<VarDescr>&,
12921304
return AsmOp::Nop(loc);
12931305
}
12941306

1307+
// implemented in dedicated files
1308+
1309+
using GenerateOpsImpl = FunctionBodyBuiltinGenerateOps::GenerateOpsImpl;
1310+
1311+
GenerateOpsImpl generate_T_toCell;
1312+
GenerateOpsImpl generate_builder_storeAny;
1313+
GenerateOpsImpl generate_T_fromSlice;
1314+
GenerateOpsImpl generate_slice_loadAny;
1315+
GenerateOpsImpl generate_T_fromCell;
1316+
GenerateOpsImpl generate_T_forceLoadLazyObject;
1317+
GenerateOpsImpl generate_slice_skipAny;
1318+
GenerateOpsImpl generate_T_estimatePackSize;
1319+
1320+
GenerateOpsImpl generate_createMessage;
1321+
GenerateOpsImpl generate_createExternalLogMessage;
1322+
GenerateOpsImpl generate_address_buildInAnotherShard;
1323+
GenerateOpsImpl generate_AutoDeployAddress_buildAddress;
1324+
GenerateOpsImpl generate_AutoDeployAddress_addressMatches;
12951325

12961326
void define_builtins() {
12971327
using namespace std::placeholders;
@@ -1546,8 +1576,8 @@ void define_builtins() {
15461576
compile_tuple_set_at,
15471577
FunctionData::flagMarkedAsPure | FunctionData::flagHasMutateParams | FunctionData::flagAcceptsSelf);
15481578
define_builtin_method("address.buildSameAddressInAnotherShard", Address, {Address, AddressShardingOptions}, Builder, nullptr,
1549-
compile_time_only_function,
1550-
FunctionData::flagMarkedAsPure | FunctionData::flagAcceptsSelf | FunctionData::flagCompileTimeGen);
1579+
generate_address_buildInAnotherShard,
1580+
FunctionData::flagMarkedAsPure | FunctionData::flagAcceptsSelf);
15511581
define_builtin_method("debug.print", debug, {typeT}, Unit, declGenericT,
15521582
compile_debug_print_to_string,
15531583
FunctionData::flagAllowAnyWidthT);
@@ -1564,51 +1594,51 @@ void define_builtins() {
15641594
// serialization/deserialization methods to/from cells (or, more low-level, slices/builders)
15651595
// they work with structs (or, more low-level, with arbitrary types)
15661596
define_builtin_method("T.toCell", typeT, {typeT, PackOptions}, CellT, declReceiverT,
1567-
compile_time_only_function,
1568-
FunctionData::flagMarkedAsPure | FunctionData::flagCompileTimeGen | FunctionData::flagAcceptsSelf | FunctionData::flagAllowAnyWidthT);
1597+
generate_T_toCell,
1598+
FunctionData::flagMarkedAsPure | FunctionData::flagAcceptsSelf | FunctionData::flagAllowAnyWidthT);
15691599
define_builtin_method("T.fromCell", typeT, {TypeDataCell::create(), UnpackOptions}, typeT, declReceiverT,
1570-
compile_time_only_function,
1571-
FunctionData::flagMarkedAsPure | FunctionData::flagCompileTimeGen | FunctionData::flagAllowAnyWidthT);
1600+
generate_T_fromCell,
1601+
FunctionData::flagMarkedAsPure | FunctionData::flagAllowAnyWidthT);
15721602
define_builtin_method("T.fromSlice", typeT, {Slice, UnpackOptions}, typeT, declReceiverT,
1573-
compile_time_only_function,
1574-
FunctionData::flagMarkedAsPure | FunctionData::flagCompileTimeGen | FunctionData::flagAllowAnyWidthT);
1575-
define_builtin_method("T.estimatePackSize", typeT, {}, TypeDataBrackets::create({TypeDataInt::create(), TypeDataInt::create(), TypeDataInt::create(), TypeDataInt::create()}), declReceiverT,
1576-
compile_time_only_function,
1577-
FunctionData::flagMarkedAsPure | FunctionData::flagCompileTimeGen | FunctionData::flagAllowAnyWidthT);
1603+
generate_T_fromSlice,
1604+
FunctionData::flagMarkedAsPure | FunctionData::flagAllowAnyWidthT);
1605+
define_builtin_method("T.estimatePackSize", typeT, {}, TypeDataTensor::create({TypeDataInt::create(), TypeDataInt::create(), TypeDataInt::create(), TypeDataInt::create()}), declReceiverT,
1606+
generate_T_estimatePackSize,
1607+
FunctionData::flagMarkedAsPure | FunctionData::flagAllowAnyWidthT);
15781608
define_builtin_method("T.getDeclaredPackPrefix", typeT, {}, Int, declReceiverT,
15791609
compile_time_only_function,
15801610
FunctionData::flagMarkedAsPure | FunctionData::flagCompileTimeVal | FunctionData::flagAllowAnyWidthT);
15811611
define_builtin_method("T.getDeclaredPackPrefixLen", typeT, {}, Int, declReceiverT,
15821612
compile_time_only_function,
15831613
FunctionData::flagMarkedAsPure | FunctionData::flagCompileTimeVal | FunctionData::flagAllowAnyWidthT);
15841614
define_builtin_method("T.forceLoadLazyObject", typeT, {typeT}, Slice, declReceiverT,
1585-
compile_time_only_function,
1586-
FunctionData::flagMarkedAsPure | FunctionData::flagCompileTimeGen | FunctionData::flagAcceptsSelf | FunctionData::flagAllowAnyWidthT);
1615+
generate_T_forceLoadLazyObject,
1616+
FunctionData::flagMarkedAsPure | FunctionData::flagAcceptsSelf | FunctionData::flagAllowAnyWidthT);
15871617
define_builtin_method("Cell<T>.load", CellT, {CellT, UnpackOptions}, typeT, declReceiverT,
1588-
compile_time_only_function,
1589-
FunctionData::flagMarkedAsPure | FunctionData::flagCompileTimeGen | FunctionData::flagAcceptsSelf | FunctionData::flagAllowAnyWidthT);
1618+
generate_T_fromCell,
1619+
FunctionData::flagMarkedAsPure | FunctionData::flagAcceptsSelf | FunctionData::flagAllowAnyWidthT);
15901620
define_builtin_method("slice.loadAny", Slice, {Slice, UnpackOptions}, typeT, declGenericT,
1591-
compile_time_only_function,
1592-
FunctionData::flagMarkedAsPure | FunctionData::flagCompileTimeGen | FunctionData::flagAcceptsSelf | FunctionData::flagHasMutateParams | FunctionData::flagAllowAnyWidthT);
1621+
generate_slice_loadAny,
1622+
FunctionData::flagMarkedAsPure | FunctionData::flagAcceptsSelf | FunctionData::flagHasMutateParams | FunctionData::flagAllowAnyWidthT);
15931623
define_builtin_method("slice.skipAny", Slice, {Slice, UnpackOptions}, Slice, declGenericT,
1594-
compile_time_only_function,
1595-
FunctionData::flagMarkedAsPure | FunctionData::flagCompileTimeGen | FunctionData::flagAcceptsSelf | FunctionData::flagReturnsSelf | FunctionData::flagHasMutateParams | FunctionData::flagAllowAnyWidthT);
1624+
generate_slice_skipAny,
1625+
FunctionData::flagMarkedAsPure | FunctionData::flagAcceptsSelf | FunctionData::flagReturnsSelf | FunctionData::flagHasMutateParams | FunctionData::flagAllowAnyWidthT);
15961626
define_builtin_method("builder.storeAny", Builder, {Builder, typeT, PackOptions}, Builder, declGenericT,
1597-
compile_time_only_function,
1598-
FunctionData::flagMarkedAsPure | FunctionData::flagCompileTimeGen | FunctionData::flagAcceptsSelf | FunctionData::flagReturnsSelf | FunctionData::flagHasMutateParams | FunctionData::flagAllowAnyWidthT);
1627+
generate_builder_storeAny,
1628+
FunctionData::flagMarkedAsPure | FunctionData::flagAcceptsSelf | FunctionData::flagReturnsSelf | FunctionData::flagHasMutateParams | FunctionData::flagAllowAnyWidthT);
15991629

16001630
define_builtin_func("createMessage", {CreateMessageOptions}, OutMessage, declTBody,
1601-
compile_time_only_function,
1602-
FunctionData::flagCompileTimeGen | FunctionData::flagAllowAnyWidthT);
1631+
generate_createMessage,
1632+
FunctionData::flagAllowAnyWidthT);
16031633
define_builtin_func("createExternalLogMessage", {CreateExternalLogMessageOptions}, OutMessage, declTBody,
1604-
compile_time_only_function,
1605-
FunctionData::flagCompileTimeGen | FunctionData::flagAllowAnyWidthT);
1634+
generate_createExternalLogMessage,
1635+
FunctionData::flagAllowAnyWidthT);
16061636
define_builtin_method("AutoDeployAddress.buildAddress", AutoDeployAddress, {AutoDeployAddress}, Builder, nullptr,
1607-
compile_time_only_function,
1608-
FunctionData::flagMarkedAsPure | FunctionData::flagAcceptsSelf | FunctionData::flagCompileTimeGen);
1637+
generate_AutoDeployAddress_buildAddress,
1638+
FunctionData::flagMarkedAsPure | FunctionData::flagAcceptsSelf);
16091639
define_builtin_method("AutoDeployAddress.addressMatches", AutoDeployAddress, {AutoDeployAddress, Address}, Bool, nullptr,
1610-
compile_time_only_function,
1611-
FunctionData::flagMarkedAsPure | FunctionData::flagAcceptsSelf | FunctionData::flagCompileTimeGen);
1640+
generate_AutoDeployAddress_addressMatches,
1641+
FunctionData::flagMarkedAsPure | FunctionData::flagAcceptsSelf);
16121642

16131643
// functions not presented in stdlib at all
16141644
// used in tolk-tester to check/expose internal compiler state

0 commit comments

Comments
 (0)