2222#include < cctype>
2323
2424#include " pass.h"
25+ #include " support/file.h"
2526#include " wasm-builder.h"
2627#include " wasm.h"
27- #include " support/file.h"
2828
2929namespace wasm {
3030
31- static std::vector<Name> parseFunctionList (const IString &functionList, Module *module ) {
32- std::vector<Name> functions;
33- std::string input = functionList.toString ().c_str ();
34-
35- // If --remove-functions=* is passed, remove everything possible. (track this as an empty function list)
36- if (functionList == " *" ) {
37- return functions;
38- }
39-
40- // Read function list from a file if prefixed with '@'
41- if (functionList.startsWith (IString (" @" ))) {
42- input = read_file<std::string>(input.substr (1 ), Flags::Text);
43- }
44-
45- // Split string to a string list, delimited by ; and \n
46- size_t begin = 0 ;
47- for (size_t end = 1 ; end <= input.length (); ++end) {
48- if (input[end] == ' ;' || input[end] == ' \n ' || end == input.length ()) {
49- // Trim \r and whitespace
50- size_t trimEnd = end;
51- while (trimEnd > 0 && input[trimEnd-1 ] <= 32 ) --trimEnd;
52- size_t trimBegin = begin;
53- while (trimBegin < input.length () && input[trimBegin] <= 32 ) ++trimBegin;
54- if (trimBegin < trimEnd) {
55- std::string name = input.substr (trimBegin, trimEnd - trimBegin);
56- if (std::isdigit (name[0 ])) {
57- Index i = std::stoi (name);
58- if (i >= module ->functions .size ()) {
59- Fatal () << " Out of bounds function index " << i << " ! (module has only " << module ->functions .size () << " functions)" ;
60- }
61- // Assumes imports are at the beginning
62- functions.push_back (module ->functions [i]->name );
63- } else {
64- functions.push_back (name);
65- }
66- }
67- begin = end + 1 ;
31+ static std::vector<Name> parseFunctionList (const IString& functionList,
32+ Module* module ) {
33+ std::vector<Name> functions;
34+ std::string input = functionList.toString ().c_str ();
35+
36+ // If --remove-functions=* is passed, remove everything possible. (track this
37+ // as an empty function list)
38+ if (functionList == " *" ) {
39+ return functions;
40+ }
41+
42+ // Read function list from a file if prefixed with '@'
43+ if (functionList.startsWith (IString (" @" ))) {
44+ input = read_file<std::string>(input.substr (1 ), Flags::Text);
45+ }
46+
47+ // Split string to a string list, delimited by ; and \n
48+ size_t begin = 0 ;
49+ for (size_t end = 1 ; end <= input.length (); ++end) {
50+ if (input[end] == ' ;' || input[end] == ' \n ' || end == input.length ()) {
51+ // Trim \r and whitespace
52+ size_t trimEnd = end;
53+ while (trimEnd > 0 && input[trimEnd - 1 ] <= 32 ) {
54+ --trimEnd;
55+ }
56+ size_t trimBegin = begin;
57+ while (trimBegin < input.length () && input[trimBegin] <= 32 ) {
58+ ++trimBegin;
6859 }
69- }
70- if (functions.empty ()) {
71- Fatal () << " Unable to parse argument --remove-functions=" << functionList;
72- }
73- return functions;
60+ if (trimBegin < trimEnd) {
61+ std::string name = input.substr (trimBegin, trimEnd - trimBegin);
62+ if (std::isdigit (name[0 ])) {
63+ Index i = std::stoi (name);
64+ if (i >= module ->functions .size ()) {
65+ Fatal () << " Out of bounds function index " << i
66+ << " ! (module has only " << module ->functions .size ()
67+ << " functions)" ;
68+ }
69+ // Assumes imports are at the beginning
70+ functions.push_back (module ->functions [i]->name );
71+ } else {
72+ functions.push_back (name);
73+ }
74+ }
75+ begin = end + 1 ;
76+ }
77+ }
78+ if (functions.empty ()) {
79+ Fatal () << " Unable to parse argument --remove-functions=" << functionList;
80+ }
81+ return functions;
7482}
7583
76- static void remove (PassRunner* runner, Module* module , std::vector<Name> functionsToRemove) {
84+ static void remove (PassRunner* runner,
85+ Module* module ,
86+ std::vector<Name> functionsToRemove) {
7787
7888 Builder builder (*module );
7989
8090 for (auto & func : module ->functions ) {
81- if (!func->imported () && (functionsToRemove.empty () || std::find (functionsToRemove.begin (), functionsToRemove.end (), func->name ) != functionsToRemove.end ())) {
82- const Type returns = func->getResults ();
83- if (returns == Type::none) {
84- std::cerr << " removing void function " << func->name << " \n " ;
85- func->vars .clear ();
86- func->body = builder.makeReturn ();
87- }
88- else if (returns == Type::i32 || returns == Type::i64 || returns == Type::f32 || returns == Type::f64 ) {
89- std::cerr << " removing i32/i64/f32/f64 function " << func->name << " \n " ;
90- func->vars .clear ();
91- func->body = builder.makeConst (Literal (int32_t (0 )));
92- }
93- else {
94- std::cerr << " unable to remove function " << func->name << " since it returns a " << returns << " \n " ;
95- }
96- }
91+ if (!func->imported () &&
92+ (functionsToRemove.empty () ||
93+ std::find (functionsToRemove.begin (),
94+ functionsToRemove.end (),
95+ func->name ) != functionsToRemove.end ())) {
96+ const Type returns = func->getResults ();
97+
98+ if (returns == Type::unreachable) {
99+ std::cerr << " removing unreachable function " << func->name << " \n " ;
100+ func->vars .clear ();
101+ func->body = builder.makeUnreachable ();
102+ } else if (returns == Type::none) {
103+ std::cerr << " removing void function " << func->name << " \n " ;
104+ func->vars .clear ();
105+ func->body = builder.makeReturn ();
106+ } else if (returns == Type::i32 ) {
107+ std::cerr << " removing i32 function " << func->name << " \n " ;
108+ func->vars .clear ();
109+ func->body = builder.makeConst (Literal (int32_t (0 )));
110+ } else if (returns == Type::i64 ) {
111+ std::cerr << " removing i64 function " << func->name << " \n " ;
112+ func->vars .clear ();
113+ func->body = builder.makeConst (Literal (int64_t (0 )));
114+ } else if (returns == Type::f32 ) {
115+ std::cerr << " removing f32 function " << func->name << " \n " ;
116+ func->vars .clear ();
117+ func->body = builder.makeConst (Literal (float (0 .0f )));
118+ } else if (returns == Type::f64 ) {
119+ std::cerr << " removing f64 function " << func->name << " \n " ;
120+ func->vars .clear ();
121+ func->body = builder.makeConst (Literal (double (0.0 )));
122+ } else if (returns == Type::v128) {
123+ std::cerr << " removing v128 function " << func->name << " \n " ;
124+ func->vars .clear ();
125+ std::array<uint8_t , 16 > bytes;
126+ bytes.fill (0 );
127+ func->body = builder.makeConst (Literal (bytes.data ()));
128+ } else {
129+ std::cerr << " unable to remove function " << func->name
130+ << " since it returns a " << returns << " \n " ;
131+ }
132+ }
97133 }
98134
99135 // Remove unneeded things.
100136 PassRunner postRunner (runner);
101- // postRunner.add("inlining-optimizing");
137+ // postRunner.add("inlining-optimizing");
102138 postRunner.add (" remove-unused-module-elements" );
103139 postRunner.setIsNested (true );
104140 postRunner.run ();
@@ -108,7 +144,11 @@ struct RemoveFunctions : public Pass {
108144 void run (Module* module ) override {
109145 Name name = getPassRunner ()->options .getArgument (
110146 " remove-functions" ,
111- " RemoveFunctions usage: wasm-opt --remove-functions=FUNCTION_NAME" );
// todo: multiple functions via --remove-functions=name1;name2;index3;... or [email protected] 147+ " RemoveFunctions usage: wasm-opt "
148+ " --remove-functions=FUNCTION_NAME" ); // todo: multiple functions via
149+ // --remove-functions=name1;name2;index3;...
150+ // or
151+ 112152 std::vector<Name> functionsToRemove = parseFunctionList (name, module );
113153 remove (getPassRunner (), module , functionsToRemove);
114154 }
0 commit comments