@@ -917,55 +917,75 @@ RewriterVar* Rewriter::loadConst(int64_t val, Location dest) {
917917}
918918
919919RewriterVar* Rewriter::call (bool has_side_effects, void * func_addr, llvm::ArrayRef<RewriterVar*> args,
920- llvm::ArrayRef<RewriterVar*> args_xmm) {
920+ llvm::ArrayRef<RewriterVar*> args_xmm, llvm::ArrayRef<RewriterVar*> additional_uses ) {
921921 STAT_TIMER (t0, " us_timer_rewriter" , 10 );
922922 RewriterVar* result = createNewVar ();
923- RewriterVar::SmallVector uses;
924- for (RewriterVar* v : args) {
925- assert (v != NULL );
926- uses.push_back (v);
927- }
928- for (RewriterVar* v : args_xmm) {
929- assert (v != NULL );
930- uses.push_back (v);
931- }
932923
933924 ActionType type;
934925 if (has_side_effects)
935926 type = ActionType::MUTATION;
936927 else
937928 type = ActionType::NORMAL;
938929
939- // It's not nice to pass llvm::SmallVectors through a closure, especially with our SmallFunction
940- // optimization, so just regionAlloc them and copy the data in:
941- RewriterVar** _args = (RewriterVar**)this ->regionAlloc (sizeof (RewriterVar*) * args.size ());
942- memcpy (_args, args.begin (), sizeof (RewriterVar*) * args.size ());
943- RewriterVar** _args_xmm = (RewriterVar**)this ->regionAlloc (sizeof (RewriterVar*) * args_xmm.size ());
944- memcpy (_args_xmm, args_xmm.begin (), sizeof (RewriterVar*) * args_xmm.size ());
945-
946- int args_size = args.size ();
947- assert (args_xmm.size () <= 0x7fff );
948- // Hack: pack this into a short to make sure it fits in the closure
949- short xmm_args_size = args_xmm.size ();
950930
951931 // TODO: we don't need to generate the decref info for calls which can't throw
952932 bool can_throw = true ;
933+ auto args_array_ref = regionAllocArgs (args, args_xmm, additional_uses);
953934
954935 // Hack: explicitly order the closure arguments so they pad nicer
955- addAction ([args_size, xmm_args_size, has_side_effects, can_throw, this , result, func_addr, _args, _args_xmm]() {
956- this ->_call (result, has_side_effects, can_throw, func_addr, llvm::ArrayRef<RewriterVar*>(_args, args_size),
957- llvm::ArrayRef<RewriterVar*>(_args_xmm, xmm_args_size));
958- for (int i = 0 ; i < args_size; i++)
959- _args[i]->bumpUse ();
960- for (int i = 0 ; i < xmm_args_size; i++)
961- _args_xmm[i]->bumpUse ();
962- }, uses, type);
936+ struct LambdaClosure {
937+ RewriterVar** args_array;
938+
939+ struct {
940+ unsigned int has_side_effects : 1 ;
941+ unsigned int can_throw : 1 ;
942+ unsigned int num_args : 16 ;
943+ unsigned int num_args_xmm : 16 ;
944+ unsigned int num_additional_uses : 16 ;
945+ };
946+
947+ llvm::ArrayRef<RewriterVar*> allArgs () const {
948+ return llvm::makeArrayRef (args_array, num_args + num_args_xmm + num_additional_uses);
949+ }
950+
951+ llvm::ArrayRef<RewriterVar*> args () const { return allArgs ().slice (0 , num_args); }
952+
953+ llvm::ArrayRef<RewriterVar*> argsXmm () const { return allArgs ().slice (num_args, num_args_xmm); }
954+
955+ llvm::ArrayRef<RewriterVar*> additionalUses () const {
956+ return allArgs ().slice ((int )num_args + (int )num_args_xmm, num_additional_uses);
957+ }
958+
959+ LambdaClosure (llvm::MutableArrayRef<RewriterVar*> args_array_ref, llvm::ArrayRef<RewriterVar*> _args,
960+ llvm::ArrayRef<RewriterVar*> _args_xmm, llvm::ArrayRef<RewriterVar*> _addition_uses,
961+ bool has_side_effects, bool can_throw)
962+ : args_array(args_array_ref.data()),
963+ has_side_effects (has_side_effects),
964+ can_throw(can_throw),
965+ num_args(_args.size()),
966+ num_args_xmm(_args_xmm.size()),
967+ num_additional_uses(_addition_uses.size()) {
968+ assert (_args.size () < 1 << 16 );
969+ assert (_args_xmm.size () < 1 << 16 );
970+ assert (_addition_uses.size () < 1 << 16 );
971+ }
972+
973+ } lambda_closure(args_array_ref, args, args_xmm, additional_uses, has_side_effects, can_throw);
974+ assert (lambda_closure.args().size() == args.size());
975+ assert (lambda_closure.argsXmm().size() == args_xmm.size());
976+ assert (lambda_closure.additionalUses().size() == additional_uses.size());
977+
978+ addAction ([this , result, func_addr, lambda_closure]() {
979+ this ->_call (result, lambda_closure.has_side_effects , lambda_closure.can_throw , func_addr, lambda_closure.args (),
980+ lambda_closure.argsXmm (), lambda_closure.allArgs ());
981+ }, lambda_closure.allArgs(), type);
963982
964983 return result;
965984}
966985
967986void Rewriter::_setupCall (bool has_side_effects, llvm::ArrayRef<RewriterVar*> args,
968- llvm::ArrayRef<RewriterVar*> args_xmm, Location preserve) {
987+ llvm::ArrayRef<RewriterVar*> args_xmm, Location preserve,
988+ llvm::ArrayRef<RewriterVar*> stuff_to_bump) {
969989 if (has_side_effects)
970990 assert (done_guarding);
971991
@@ -1052,6 +1072,10 @@ void Rewriter::_setupCall(bool has_side_effects, llvm::ArrayRef<RewriterVar*> ar
10521072 }
10531073#endif
10541074
1075+ for (auto && use : stuff_to_bump) {
1076+ use->bumpUseEarlyIfPossible ();
1077+ }
1078+
10551079 // Spill caller-saved registers:
10561080 for (auto check_reg : caller_save_registers) {
10571081 // check_reg.dump();
@@ -1114,7 +1138,8 @@ void Rewriter::_setupCall(bool has_side_effects, llvm::ArrayRef<RewriterVar*> ar
11141138}
11151139
11161140void Rewriter::_call (RewriterVar* result, bool has_side_effects, bool can_throw, void * func_addr,
1117- llvm::ArrayRef<RewriterVar*> args, llvm::ArrayRef<RewriterVar*> args_xmm) {
1141+ llvm::ArrayRef<RewriterVar*> args, llvm::ArrayRef<RewriterVar*> args_xmm,
1142+ llvm::ArrayRef<RewriterVar*> stuff_to_bump) {
11181143 if (LOG_IC_ASSEMBLY)
11191144 assembler->comment (" _call" );
11201145
@@ -1123,17 +1148,7 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, bool can_throw,
11231148 if (failed)
11241149 return ;
11251150
1126- _setupCall (has_side_effects, args, args_xmm, assembler::R11);
1127-
1128- // This duty is now on the caller:
1129- /*
1130- for (RewriterVar* arg : args) {
1131- arg->bumpUse();
1132- }
1133- for (RewriterVar* arg_xmm : args_xmm) {
1134- arg_xmm->bumpUse();
1135- }
1136- */
1151+ _setupCall (has_side_effects, args, args_xmm, assembler::R11, stuff_to_bump);
11371152
11381153 assertConsistent ();
11391154
@@ -1164,6 +1179,10 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, bool can_throw,
11641179
11651180 if (result)
11661181 result->releaseIfNoUses ();
1182+
1183+ for (RewriterVar* arg : stuff_to_bump) {
1184+ arg->bumpUseLateIfNecessary ();
1185+ }
11671186}
11681187
11691188std::vector<Location> Rewriter::getDecrefLocations () {
@@ -1286,12 +1305,7 @@ void RewriterVar::refConsumed(RewriterAction* action) {
12861305 last_refconsumed_numuses = uses.size ();
12871306 if (!action)
12881307 action = rewriter->getLastAction ();
1289- action->consumed_refs .emplace_back (this );
1290- }
1291-
1292- void RewriterVar::refUsed () {
1293- // TODO: This is a pretty silly implementation that might prevent other optimizations?
1294- rewriter->addAction ([=]() { this ->bumpUse (); }, { this }, ActionType::NORMAL);
1308+ action->consumed_refs .push_front (this );
12951309}
12961310
12971311bool RewriterVar::needsDecref () {
@@ -1893,7 +1907,7 @@ void Rewriter::_checkAndThrowCAPIException(RewriterVar* r, int64_t exc_val, asse
18931907 } else
18941908 assembler->cmp (var_reg, assembler::Immediate (exc_val), type);
18951909
1896- _setupCall (false , RewriterVar::SmallVector (), RewriterVar::SmallVector () );
1910+ _setupCall (false , {} );
18971911 {
18981912 assembler::ForwardJump jnz (*assembler, assembler::COND_NOT_ZERO);
18991913 assembler->mov (assembler::Immediate ((void *)throwCAPIException), assembler::R11);
0 commit comments