diff --git a/SOURCES/gcc8-loop-opt.patch b/SOURCES/gcc8-loop-opt.patch new file mode 100644 index 0000000000000000000000000000000000000000..4a4279efcb07f1410e0cb949c98c5e2a6264914e --- /dev/null +++ b/SOURCES/gcc8-loop-opt.patch @@ -0,0 +1,2015 @@ +diff --git a/gcc/Makefile.in b/gcc/Makefile.in +index d595a504c..3ec6bf7a4 100644 +--- a/gcc/Makefile.in ++++ b/gcc/Makefile.in +@@ -1544,6 +1544,7 @@ OBJS = \ + tree-ssa-ifcombine.o \ + tree-ssa-live.o \ + tree-ssa-loop-ch.o \ ++ tree-ssa-loop-elim.o \ + tree-ssa-loop-im.o \ + tree-ssa-loop-ivcanon.o \ + tree-ssa-loop-ivopts.o \ +diff --git a/gcc/ai-optimizer.c b/gcc/ai-optimizer.c +index 0100577fc..3141e82ab 100644 +--- a/gcc/ai-optimizer.c ++++ b/gcc/ai-optimizer.c +@@ -30,14 +30,14 @@ along with GCC; see the file COPYING3. If not see + #define M_OPTION_SIZE 11 + #define M_MODE_SIZE 6 + #define NATIVE_TUNE_SIZE 128 +-#define CATS_STRINGS_ROW 35 ++#define CATS_STRINGS_ROW 36 + #define CATS_STRINGS_COL 65 + #define CATS_STRINGS1_ROW 10 + #define CATS_STRINGS1_COL 65 + #define OFFSET_ROW 6 + #define SCALE_ROW 6 + #define UNITY_ROW 1 +-#define COEFFICIENT_ROW 366 ++#define COEFFICIENT_ROW 376 + #define COEFFICIENT_COL 10 + #define COEFFICIENT1_ROW 10 + #define COEFFICIENT1_COL 1 +@@ -346,9 +346,9 @@ graph_infer (int argc1, const char **argv1, const char *mops, + the ONNX model. concat_result is a 1 × 18 matrix, and encoder_out is a + 1 × 12 matrix. */ + +- const int concat_out_size = 360; ++ const int concat_out_size = 370; + float concat_result[concat_out_size]; +- const int encoder_out_size = 35; ++ const int encoder_out_size = 36; + const int encoder_last_size = 10; + int concat_size = 0; + const int size = encoder_out_size; +@@ -380,7 +380,7 @@ graph_infer (int argc1, const char **argv1, const char *mops, + /* This requires performing matrix multiplication between a 1 × 356 matrix + and an 356 × 10 matrix */ + +- const int m = 1, k = 366, n = 10; ++ const int m = 1, k = 376, n = 10; + float mul_result[n]; + matmul (transformed_column, coefficient[0], m, k, n, mul_result); + +diff --git a/gcc/common.opt b/gcc/common.opt +index 824210c83..38635a27b 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1149,6 +1149,10 @@ fcompare-elim + Common Report Var(flag_compare_elim_after_reload) Optimization + Perform comparison elimination after register allocation has finished. + ++floop-elim ++Common Report Var(flag_loop_elim) Init(0) Optimization ++Perform redundant loop elimination. ++ + fconserve-stack + Common Var(flag_conserve_stack) Optimization + Do not perform optimizations increasing noticeably stack usage. +@@ -1411,6 +1415,10 @@ ffinite-math-only + Common Report Var(flag_finite_math_only) Optimization SetByCombined + Assume no NaNs or infinities are generated. + ++ffinite-loops ++Common Report Var(flag_finite_loops) Optimization ++Assume that loops with an exit will terminate and not loop indefinitely. ++ + ffixed- + Common Joined RejectNegative Var(common_deferred_options) Defer + -ffixed- Mark as being unavailable to the compiler. +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index d8ff288d2..2cf129269 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -565,7 +565,7 @@ static const struct cpu_vector_cost cortexa57_vector_cost = + 1, /* scalar_store_cost */ + 2, /* vec_int_stmt_cost */ + 2, /* vec_fp_stmt_cost */ +- 3, /* vec_permute_cost */ ++ 6, /* vec_permute_cost */ + 8, /* vec_to_scalar_cost */ + 8, /* scalar_to_vec_cost */ + 4, /* vec_align_load_cost */ +@@ -7687,7 +7687,8 @@ override_CPP_optimize_options (struct gcc_options *opts) + { + opts->x_flag_omit_frame_pointer = 1; + opts->x_flag_sized_deallocation = 0; +- ++ opts->x_flag_finite_loops = 1; ++ opts->x_flag_loop_elim = 1; + maybe_set_param_value (PARAM_MAX_INLINE_INSNS_AUTO, + 128, + opts->x_param_values, +diff --git a/gcc/omp-offload.c b/gcc/omp-offload.c +index 0abf0283c..74c60b5d6 100644 +--- a/gcc/omp-offload.c ++++ b/gcc/omp-offload.c +@@ -300,7 +300,7 @@ oacc_xform_loop (gcall *call) + tree chunk_size = NULL_TREE; + unsigned mask = (unsigned) TREE_INT_CST_LOW (gimple_call_arg (call, 5)); + tree lhs = gimple_call_lhs (call); +- tree type = TREE_TYPE (lhs); ++ tree type = NULL_TREE; + tree diff_type = TREE_TYPE (range); + tree r = NULL_TREE; + gimple_seq seq = NULL; +@@ -308,6 +308,15 @@ oacc_xform_loop (gcall *call) + unsigned outer_mask = mask & (~mask + 1); // Outermost partitioning + unsigned inner_mask = mask & ~outer_mask; // Inner partitioning (if any) + ++ /* Skip lowering if return value of IFN_GOACC_LOOP call is not used. */ ++ if (!lhs) ++ { ++ gsi_replace_with_seq (&gsi, seq, true); ++ return; ++ } ++ ++ type = TREE_TYPE (lhs); ++ + #ifdef ACCEL_COMPILER + chunk_size = gimple_call_arg (call, 4); + if (integer_minus_onep (chunk_size) /* Force static allocation. */ +diff --git a/gcc/optimizer.fdata b/gcc/optimizer.fdata +index adc2f5399..e5d6684c4 100644 +--- a/gcc/optimizer.fdata ++++ b/gcc/optimizer.fdata +@@ -1 +1 @@ +-363632656234393365653936383862396662623134303865623332333461363066633935643264653466326132626331353831633763636239616630353032653233326432366139383465346338376266393132363438333765656463366235613461313434346139333334396265306163333731646537376430643834323664623863366163343363643130313435636565623834363361316133393230363937653835653762353534626439663133633538623062353439646237616630333237666136663433386334626639643465303163653832333062643863333664336630376231643964316231663933656333386338656262303734376137313565643963396535653131303763646533393234333735613333633132353061393531333935623539643834373266303861633739373862366663376365383233326139383939363566373061373361613939336537366631353334346563313061373365663635633332663437653136383235343635623234366430373330366336363237623962656465373233346131343264313137653838643334616430346339363732613237623866636364313232613934343261643231386531356430343965303330306332326266336634626163333461643139653962326566303064343333623037313762303934626336363537616339343637306633633066333231613063623339333539376461316632653234353938616133616463623534356232346135666261616339646638373031356633306161626465643665633066616264623965656138613233353331303236363565616133323131653935643363353832366663633434626236376663386335666364333530336433353234383031636264353761616638663031613263353738326438656265623236653338323232386565626464393034633962373835363264656664616439353336623462376139333134656662373033626135336138333136643032636430653334303861616439333736306363383862306439623962646435383931613161656137356462666463346364333361623035396139323366643262383764363763323530613631653861653634666630333030316562323662346133633566316533346236663132363663663739623565366564343962313033386462653236663864613664303962623535363134336361326534666230613461643036356361623365363830623066373064386262326466363934623535633664373865313164633832393733616432306435663337366633306565386434613131613061636663616630643839623737366361623235653838653366303334613439393362313664373862653234396263323361663762626238373531633765333530666363393132333237616137663336333434326233313735303764323765346238313333393839646334396539663036633034396237393461336263306463333738313939303164393262336465656237616466643562303362333632303838336162666434636265363361333466646564333736303437383432623738636461313736336539396364306164393937313064353136643231663135306364643936646137386434613564373335643430363162623534623133366633353137633236613635643433306239653638666165343231636163376139643564653333336637393138356233633164623465396435396364353031663066643661353130633336303365313365323461343062346266323135653337393561396134306436306138343536666237623633633264313165383137303161323331653835616664346235646238316162633164643536643237313733326564303234356638363931626463356461643334373664366636333536303737623161613164363334613937633431303962353962373335343766393430633164633864323163306631383733383866326433613865656366656537666438363739303266643461633331626131633966646635316261613261343337626663303932613166373332653261386630363637363337343262303737306136653236653332663262653565343761333733303934663366396234313838633834336435633462656135613261346163346262626466376661633763653339623230363235373337373135343130663233646239373035346236656232373065666363666237636234313736663832363831343263656131366532386232316463393539383730306566316462386539616434346537653138343162313462313235636366333561313765386366666138663036383233626434366366383536653461663236336238616166393638626138353062346439616666626563343933666130666530613833336539653436336538376132636365306338633038613133636363613461326134313639623365396134633133666339346337613637616230393963653932636336386561343761626166313638386162386131373230326638646130353133633533353964323735303632336632343431363463396634353338346566303665373533363061373664346462643034663036336636303863636363373830663166313238363531353931346461393730353236373461643039653235366663353938646363643464333835646164353838623664643261303365363139346361393864383734623331623662306231653235333362633134303864306436613862616330613136316136393132323137343831363364646362313231303362316131313733366362386566353536356266663035356633313633323533383133633963343136313330346561336663653535616438303565656331373466386437396361363764323037616334366664653362323562366531643531633464616561653330386532663361613839666339613234623762623864303635363239323732633437313135623561393362653837653361396438373339666232653861316665613661613331383532616631393033383937333463353139343637613931376332666164316634363432366132316638656362363461336166626237613736336638306232313930636165346330323165386264366337316432613138666663393538363731333639396239666362393336373737643238636639643761343231346131333463353261623633343633343866663966663365346237313164613933626232343636366137616430363063643632626237306335353536396233353566633932393964346162636636376563656530396161306664656561626436396635656632346534653861376262386430376664633866626464346666653730326362316232653965343564313031306138623562363130623230313963396265366130303837616232366634326335646531303539353531353137366562353736323737393436626630343433346330356264653562376231356532663139306164303361383836396333393339616236383439363661313661303665643535633961666563613431303466333534346564633533373866306361633035363431646633643837383532663863303765623439623930373061333833633261383932383764356133323539336632353130303266643661643531313731316638343339653162613735393261653833333065316432643865616634333936326236626432663237656439643439633335656534373338313766633338646231316433363030393633613732386331363461303139393161316436323764326235316237613364393537303630633634616137656338386231636561313937653562653562623466633136316330383533636239353561353063623464363362636438656639613233323237373363323039386566366463587754430153274178ab274197be33430e5f1545710254412d9ade3b12f1c13df163bf3d6fc4c73bf7cbb4385e4ed83d0000803f2cb90e3da388cd3cc0d6913df226b13b37ea123df90a1fbdd201113df1081dbcfb240f3d5f280f3dfeddc33cb6dbcc3ca32f563d8f1439bd8f63c43c80ad8abb5381bd3ce8fd2bbc269fcd3cb97ec33c6ec41a3dc386f53c3d5d4d3d6cc298bb9f961a3db4aab0bc95381e3d5729653d44681d3dee941a3d90433fbc70e5923b3d7dbf3cff8520be91bf6dbc27c7c83b5d16f3bcca7df0bc45588fbccd02babc4734773bdea39e3b21d98cbc0efb3bbf915e7f3cbd8a693e81270f3df4800ebcfe88c53c1388723d8111eb3cc873ea3cd5229d3de385e33b7b1ff13c1f0716bde8d4ef3c7d7995bd3a59ef3c01ebed3ca01d9d3e56e4903efb8d87bf0ef454be0ec09f3e0fc3ba3d45b5853e4e5451be51c2933effca853e2089ba3e3c499f3eeca07abfd7e185bed66aba3e803e993c803c9f3e59ad82be5a3aad3e19029e3e40b19a3efa1c8f3e7f218ebf3d244abee2fa9b3e4c9ded3dafba803e967047be2b3c8e3e2442803ee242b13ec290993e4ed57dbf85b277beef3cb13e21ed283de6d4963eb12075be9ca4a43e7c86963e169ca43edf468d3e344288bf0a635fbe2d8da43e240a9a3dfe158b3e4e8862be131a983ede6d8a3e35359e3e6468843e6c3789bf41f853bea7ae9d3e4a86ec3d5b5a843e487c52be8037913e3569843e136ba13eb5b08c3e032d8cbfc8205abe124da13e52e7a33d2958873e76d758bed14e943eef50863e5b649a3e64bd9b3e616e88bfee8256be1afa993ed799e23de378833e478047be97698f3e063d833eefbea03e19e48e3ee8b784bf3e7294be1e05a03e55c5c83dbad5863e94de53bea379943e7209873ef5f9b23e1d759a3ea97e80bf32fb77becb04b33eb3e42b3d4049983e3eab73be7e12a63e9740973ecb00c43eb4cdd7be03fa8fbf8ad246be78a2b63ea3944e3e917d8d3e408b3bbeb9edad3e2c76933ee961ad3e6df49d3ec32481bf59c66ebe9b25ac3e42056c3df161933e17306ebe2feca03e2276923ea226ac3e6864953e869380bfca3a6fbed434ac3e93cf713dc559913e261366be5dcb9e3ecf8c8f3e8308303d1fa8f73c29b77a3d304de5bcc204303dd90991bd8200233dcf8b04bdfd2a2a3d3a5e223da196eb3cd8857e3cae62133d43e191bc3cc4eb3c88b65bbd0ec7d23c208ca8bc9c4ddf3c123fd23c388fd23c0543df3b72d31e3dd47550bc9099d23cb8078fbd9f0aba3c27607fbca930c73cbef0b83c4792f73c5ac3653ccce6d93cbd6898bcc4a1f73c17056dbd3133de3c99d0afbc2a31eb3cc8bfdc3cd64dc63c3223893c15f9053dcda1ceba5355c63cf64b8dbdd8bcac3c21517ebc3385ba3c287dab3cdf90923c831a0c3cc103253d785cd6bb6985923c6b0005bddf89743cc32410bce514873c708b813cd98bfcbbc6f28fbcc4494dbcd18fc53c7a33fcbb31fcc6bb639330bc1387963c4b7115bcbe7831bc34a0ca3cf3eaaa3b8c70263d7d688ebcd3baca3ced9ab2bd1af8bd3ca95b8abcc5dfc03c4e19c33c3e57c33c6d7e153c88ce473dc2c661bd4149c33cec8e39bdbbb4a83c79665bbcb664b63c9306a73ca846bc3c5e51bf3a57a7143d803c5d3b311dbc3c632858bd48fc9d3cdbf91fbcdca2b03c3ff0a33c5ee8143d5b98953c26eba93ce07bc33c9536153d64a087bd8fe1083dffb8dfbc21610f3dd624083d3cca21bcc31ee3bc7851873df730ebbdd9c821bce66076bb12fd52bc0b40943c48e339bc50e855bc7f51a63cf3c6fd3b80c6103d93bb3fbc0340a63cf3e489bdc830913c236b5dbc1a3f9d3ca1b3903cf7b4b23c1cdf853bd0845c3dd0bd8abc58a0b23c3aab2abdf0a89c3c348e66bcdf4ea93cf25a9b3caae50b3d52dd443c2cffa93ce424c03c51d10b3d8acab3bdeb00013d3a51d0bc84f9063d065f003d4303a73c7df79d3bc4fc0b3d804fbd3b0a15a73c82906cbdfd808b3cb7842bbccd80993cbed8893ce798d43c2d2b863cd80e133d73b586bc5ca8d43c09f402bd32ecbc3c383f84bcf163ca3c89e1bc3cb1dad63cd182ed3bdcc55a3de3801ebc1072d63ccba849bd60c8b83cfb299bbcc59fc73caeaeb63c6acc833cc716c9bbef34493d4061b83a43ea833c0617b0bde43c503c90da2cbb06d46e3cb3b3513c783b063d3d5b38bbe97b9d3dc22094bceb19063d1c62c6bdad65f33c0a63bdbc4fe8ff3cacc4f13c930c5d3c8bfe113b84e0443d81407dbb78d25c3c206262bde4282d3c823e5bbbe042483ce69a2b3c3651013d9acd873c07ac0d3d5ba1323bbc47013db7acaebd5359ec3c7a63bbbc53a4f73c704aeb3ce846aa3e5bc5933e155c81bf15296abef633aa3ea748863d5e938f3e088a67be4e479d3e0e278e3e2bb19d3e9d73c43ecbae8cbfd56543be6633a03eb6180b3e27f68c3e98f639be73119c3e9841873e0105a03eae559e3e0be287bfb3ef5dbe5700a03ec1a5a33db862863ed8b558be0436933e5b2d853e25d0b83eb7c09d3e264674bf8ae981beabadb83e10c62b3cf36e9e3ea3a07ebe7779ac3e22e59e3e8849bd3e8fdda23e94197abf5a3b87be853abd3e4d05443c55cea13ec2b984be82e5af3e3a40a03ea7f0bb3eccadb1bde73988bf9c1b6ebe252eb93edc77e13d325e9f3ed03970beefb1ae3e9cf59e3e94a6bb3e6bcaa03eda1f76bf1a6d85bef1a1bb3e080c223c9007a03e8a9482be525dae3e36e99e3eae5f973e822790be10f892bf8f0233be833ca33e112c503e59c27f3e6d2933bea41b943e81d07f3e3a75ac3ef97c943e349b82bfaa346fbe7775ac3e049e3c3d55fe903ed9ba69be0e689f3e9451913e601fa03e984e9d3ecb5988bf948b6cbebd049a3e0f9bd53d10d1853ee89d4ebef969913eefae813ea184923e6f74dc3e613992bf1d5ef2bdb8d27f3e1098493e190a703e826ad7bdf025803ee45d7b3e4e7e9d3ed220883e5c208bbf56964ebe564a9d3e5c20903d36f6823e33b747be0584903e647a813ee3f0a43e3c67903ee40d84bf1f6796becae5a43e7c49963d06228b3e1fbc5fbe1ea6983e68ec893ea15acf3c2013803c957fc13cdb357cbcdb90cf3cce0829bd492fbd3c34ba92bc9e80c63cf106bc3c6b5df43c91ab813c30a6e03c1888a53c5246f43c8d535dbd6205dc3c530ca2bc0127e83c1688da3c2dcef23cc81c2e3c6e022d3dbccf30bc35e3f23c4535a2bd5c38da3ce452a3bcd8bbe73cdc2ed93c5461db3c592fa43c05e8fb3c297c91bca84fdb3c29090fbd0d14c63c39b0a4bc8274d13c64bec43c2556523ddde19c3c3ef5113dc426283dc24c523dd0d6d1bda03f453df5df2fbd2ce44b3dc474443de402d63c672c6e3a61ec333d449869bceef7d53cbde897bd36cbc23cbdc581bc735ecc3c6624c03cdecd76bb47bcac3b9691a33c510366bdc19e7abbd27a2ebc1e2c92bb7c2b45bd98b587bb2bd290bb5c3e963c45a9fd3b00fa2c3d438d63bbaa3d963c3adc24bd32a3783c9c1915bcd75d893cbc5d7b3c52f5a83c1af84a3c82710b3d91790fbc7ae7a83c338218bd88a28f3cef2737bc4d559c3c05508e3c3866d33c6f19a33c670c023d73a51bbb62b1d33c563756bd3d50bb3c8cdf3fbc7f15c83ca09bba3c22478f3ca39fb33b0baa2f3d68addbbb83538f3c1c751bbd3885703c7a6a0abc67ac843ca718723cb056acbce32bd5bc32f9023d116e57bd5083acbcf553963c867cbdbc79a0ff3cb7a2b3bc58bebebca86a783ca906db3bd6f40a3d025f813b8583793cab2f3cbd6e654e3cde6424bbaa50653c6e454c3c17dac43b6bded03a16284f3c34b671bcb01bd73b072529bdd84eae3b97b5f2ba0d11bd3bc523ac3bf743df3ca411a03c7685bb3cc426863c6e17df3cf8c583bdf4aac93c1c18a5bc4531d53c0d47c83c9deec73cd80c4a3cf40eff3c036e8bbc3ccdc73cb3e72fbd17acb13ce69587bc08b4bd3cdf4bb03c175ebd3cd36b493c7c316b3d30ad47bcb786bd3c3f509dbdf735a73cb05d77bc3fa3b23c1b0ca63cc85ce43c75c93e3cf0aa063d232389bcbc4ce43c529f0dbd1305ce3cb8c49ebc869cd93c6eaccc3c4338ae3c12f5883c8666ff3c6addb43c7b2fae3c74fd67bd75b4963cf9f24dbca51ca33ccfcf953cbac4c83cb966b93bcb04103db8775bbc0cb1c83c4ccd56bdf87fb33cb37785bc7b74be3cb042b23cdfd73f3cba0f253bbf531d3d9cb5bcbcc90e403c934dd2bc109c123c63d911bae344293cee1e103c2c318a3c83aed33b4d92203d132343bb04718a3c566e48bdf281683c41df13bc96017f3c14bf653c7dac8f3e97c0763e2cee8dbf6d172cbe18778f3e01e5153ed9746a3e15a32bbe8f9e803e1879633e5496b23ebbcaa63e0f997fbf953778beb389b23ee506f73c824a973e89596fbe1648a53e0a41963ebf0ab63ec04c9b3ef9817abf6bdb7fbe53f6b53eaa16273d362e9c3ee6d079be157aa93e29f49a3ed4eb9c3e83ed9e3e529387bf3d0753be9d199e3e9e24d73d3e05843e214348bedeed8f3e69ef803e0ece983ec72a943e50528abf40573dbe1410983e779c1c3e0c19793e123b3bbe7cb28e3e5067743ecbd5a83e29af8f3e01b983bfa0ac68be68c3a83e1bf84c3d790e8e3efd7763be7adb9b3ea3a28c3ee9f0b93e46afa13eb4917cbfa22386be1cecb93ece69a93c6b029f3e3fb382beace9ac3e66ed9d3e40daae3e8b2ca03e5c6e80bf8af574be0f6eaf3e79c2903d73bd943ea09b70beba6ea13e3b3f933eb147a03e71c4893eadba89bf273f53be558aa03e3acc9f3d8cd3853e94344dbe1402943e1493853eb1f7a53e4927a13ed9e185bf65828ebe7b1fa73eb289bd3d6fb38b3e676860be2248983e7a998b3e7ac0a93e8f79963ed42987bfe8696bbe90e9a93e9c4a823d92e18f3e644868be26679c3e8bd68e3eea77903eeca0ba3e378590bf48673abe1194993eac2f1d3e1581713e01da3cbec9b68a3e15aa783ef257923e07d87c3ebc7e8dbf8e5d3ebef293923eb380cd3dfead6f3e96c53abe4c59853e01616d3e6c22c03ced16bc3b1a9b153dff7a20bdd42ac03c2b694cbd15c4a53cc91a4dbc1a32b33c21d8a33cbd319e3cb3918c3a7c041d3de002593c981a9e3c9854fdbd8432823c08e217bc5a3b913cbac1813cfdc58a3c94e459bb88d9143d612b2ebc45bb8a3c4ac952bd2ef5673c182717bcef037f3cd6356b3c2c2af83c3bd5053c20910d3da175abbc6a37f83c375461bd65abde3c962caebc6132ec3c9511dd3c9a7a8b3c93bcb13b6c3f2c3d4bf800bca5678b3c82b6febc872e683c97be20bccf39803c5689653cebc3cd3c39f40eba331c003dac9987bbc1a5cd3ca3d265bd6ec1b73ccd7b57bc7204c33c9f5bbc3c069fc1bbc6c4ebbc23a0793dd889f2bdbadfc1bbe438d8ba71950fbc4ef8943c1713efbb47f110bca31dc13cd28d1b3cee964f3dbfd759bb3c28c13c699ca0bda0dca43c6a6b3cbcf84fb33c701fa33ca7864c3ddb04fd3c777ef23bdae15a3d689a4c3d447f92bd9ff63f3dddbc2cbddad9463d26963f3dc42a9a3c19e7823b5f281e3d01d30dbc14ab9a3c23d31ebdf063843c9f9e49bc48938f3cdaeb823c5504b63c32e63bbca2e93a3d0c9b29bc4f9fb53cd414b1bde2869b3ca37b46bcf4c7a93c7ca69a3cb914d13cf389f23b3aac033d85e269bc2013d13c031c61bdd747ba3c36e690bc64dec53c3eefb83cac0b933c311910bcd170083dd00ec6ba9022933c069453bd95a1753cafc30fbc3d8c873c0e24763c6f0a2b3c03f36d3b9cb5413daa6320bd12242d3c627eb7bc5996153c05fc58bd2ac5243cc50e133c6d8ea43c0a10ce3a172d2f3d30c81e3cbd80a43c0a997abd28dd8a3ce1fd44bc4e12983c287b893c47c1113d8e2c9f3ce295123d15bde43cbda6113dfec5c1bd9516023d5e06bebce9700a3dde4a013d9886c43c6e20273b3c5ff53cc30e60bc4fc1c43cdf7fe8bcf370ae3c391a7ebca88eba3c1daaad3c6b86903ce290163b03360e3da759fbbbb857903ce37414bd2d0d753c11921cbce514863cdbc7733c3523923cd22736bb60f70c3dbd9dbabb621c923cad34f2bce147703ce156f3bbce1c863cb9796e3ce7da993c4782053c7415213d99f8c9bb2ff6993cbab564bd718f813c0d3f24bc513d8e3cbfd4893c30e5033da286243ca09b733dc912b6bcdce5033d3e2cafbdd645ee3ca92abdbc2c6cfb3ce2d7ec3c22b7ef3c6a973b3ce0d1d63c558b6fbcecdeef3c880274bda28ad73c0d07adbc9fc1e33ccbfcd53cc9f9ae3ede4e893eeeb685bf989567be5e7aae3e0fcb2b3df540933e825563be0dfca13e0951923e36c2ac3e6958b63d81ee89bf51ce64be8d0fad3ed4cfc23da1fb8e3ecd7a5fbe26639e3eda248d3ea1b0a63ee3288f3e21bb82bf69f961bea282a63ec633753dc6108b3e31915cbe40f6983e69b9893e1b37a33e7df58a3e70fa88bfadc060bea237a33eab35993d2582883e808c5abec00c963ebdda873e7cca9f3ea7e08b3efb3e88bfe92457be91ac9f3e76048c3d8794843e740451bed5a3923e9eec833ec662933e9a4d983e07be8dbf040249befff5933e342efa3dbcb2783e430243be8a388a3ed773783e8ff49a3e00aca53e190c8fbfaea851be838c9a3ef21a093efa2d823ef71732be9e66863e835e7b3e0128b23edb7d0bbea3638ebf347061be70deb03ee88ce93d87d7933ec9fb61bec783a23e244c943e7515a73ea5728f3e2e8387bf187f68be690ca73e140d7d3d22ab8c3ed07462be70219a3ece628b3e65eeb03eaf5a923e1df27fbf7e716fbee9b1b03e4371593d10f4953eab676fbe8305a33e6ef8933e4062a13e12cfab3ef2a385bf43fc91bec2e6a03e049bd33de41c8d3e4a1456be3908963e6cc5863e64d2bd3ef2d7a33e33b17dbfd26c88be0fd5bd3ea6e5823c22f1a23e4fc485beb13bb13ea079a23e40e7bb3e08eea03e2d2176bfd80286be2bdabb3ebaf34f3c6e95a13e998e82be5f3eaf3e0456a03ef02fbe3cb7835f3a6190183d0f6801bc7275be3cc390afbd1caca53c2f1975bc5d59b23c7928a73c087b393d96d11b3dc91e893c54fe903dee79393d4d4a9bbd5a392d3df75c16bdd48a333d63962c3d2210b93c7fdf463c94bf383dfa52fcbb3c0ab93c98a223bd39509e3c12295cbc7238ac3c5ab89c3c0a60a93cce1edb3b3cc6fe3cba1932bcd757a93cf7964abd6d40923cef4757bc78229e3cadd3903cf651de3cfee98e3c25dd503d8f2f9dbcc39cde3c76a96ebdeaaac63c995a9ebc5275d33c4531c73cb2150b3d7baf813c0c61903d2eb094bc541b0b3d006468bdd820fc3cabe0c7bc17b2043db0affa3c925b9e3cf9dd063c7c24593d9e9ae9bbb94c9e3c2fbf78bdbdad863cb47a26bcada1923c754c853c409eb63c83d7aa3b1a461b3d947342bc7ec7b63c7d5546bdee109e3cb2176cbc95eaaa3c08ca9c3c5892af3c78e1453c99010f3dc3a163bd22f9af3c00afd6bc4f1f9a3cbd0b50bcf6bba53cb989993ce353983c14be3e3cd90e2a3dff8d8ebdd685983cf087adbc208f833cb53383bdae108e3c97cf823c9607a43ca1a6933bad801b3d7c8894bb1f2aa43c4a9620bd2f8d8d3cbe9a38bc8bdf993c59f28b3c917fc63cbb0e173c7b66153d2a9bf13c2ceec63c2dfca8bd4532ae3c091f82bc2fadbb3cc07bad3c003bc83c5a9fa0bb9b0a183d73412ebcecacc63c6a48adbd0b78ac3c262250bc6f03bc3cf6e2a93ceb04d7bbf183bbbc4b88683dc410d1bdbe01d7bb6aabecbbe56619bcd335793cd9c801bc5b0d1cbc6e5c1a3ddb1ebf3c81c2863cb2ad113dac1b1a3d7d4ba3bde0e50e3dea50d5bc61b9143d43380e3d77d5cf3cdb7d3c3c41bf243d959285bc0ebbcf3ce85ed6bced6bb73c68d185bc4811c53c1d49b73cb3efd13c7733923c3594083d038a81bc98fbd13c502e40bdc842ba3c2b6194bceb3fc63cb3ebb83cc09bdc3c1ccc883c3e62043d22fb39bcc460dc3c6b2086bd90dbc03cd72655bc05e6ce3cfa2dbf3c2c2f8e3cea09d83b275b2f3d0211a8bbc4d88d3c110545bda4d16b3c3016f2bb1a25823c74a9683c341cbe3cd4740f3c67428a3c26b39f3a6c46c23c95a125bd282baf3c5f5b4fbbd274ba3cb679af3cc7829c3ce375df3bab4e313daad3d13a6a119c3c52c75fbd927b7d3c35b519bce6c88d3ca5c6793ca755983ce850843b5dd4043dd22b273c6592973c2fae55bd4b77853c3db180bb75c78e3cb3c4883cc96f9a3e96bc9c3ef0f887bf04d349be18239f3eb887be3d0219833eba374dbe2c38913e64c0843e4995aa3efc07923e30eb80bf49f16cbe5699aa3e489d823d1816903e748b67be8e729d3ee1ed8e3e07f4bb3e40b0a13e69fd7abfd56086be39d8bb3e2915803c10d9a03ee4d083be02ceae3e30e19f3e4797a73e87788f3edf1088bf87ae68bea18fa73e38c07c3dafec8c3eadd362beadfd9a3ec5838d3e38ceb23ea3b6993e14177ebfb09e7bbe3be2b23ed6bcee3cdb4c973e732075be889fa53e4d72963ef6dbb03eb8e29b3e2b527dbf121d8bbe1d24b13ebc1fc33c1b04963ec6b963be597ca33e8872953e8c37a53e42a5983e4e3988bfc6b669be1affa43e0fdfbc3d60978b3eebe361be9a42993e7ba18b3e5a289b3e2a96a33e4d3b87bffbb33ebe81ba973e08d6f63d38a5833e3e3137be80d98b3ea600773e60abab3e33f79a3e72ae86bf3b4b66be418bab3e82ab9b3dde9e8f3ec17767be7bb69c3ee3e68f3e20aaa93eb7a79a3ede4883bf95146bbe393da93e16324a3da3a18e3e003d65beb93c9c3ec4ec8c3ebc33973eee7aa23e73678abfeda138be796d973e070e1d3e66f77a3e644836be89ba8f3e75d6813ee98e9a3e95fa943ef28b87bfe66d4bbe38fc9e3e7f54fe3d5e8a823ea9e045be2fb3913e2676863e2e3c8c3e302aac3eb30b8fbf4df01ebece99833eb8b22c3e41e6593ed6b021be33d77c3eebe4653e64b6dd3c23c1213c08edd43cbf7d66bcddcbdd3c993b3ebdb445c43c3dc492bcf061d13cc981c33cb82ee93c1b7e5b3c7db3f83c503552bac311e93cce7b63bd788fd23ce40aa9bc9c33df3ceabdd03cdef0d43ca2f657b9c07b263d3f6a80bcaed9d43c201f63bd9787b83c338d74bc74d9c63c46b5b63c494aa03c443c7b3a3332fc3c2eecffbb0413a03c8e271ebd661b8b3c8bb044bc8610963c45d7893ce14ff33c1bbfa53a921bfd3c163974bcbafbf23c328f73bde18ada3c3e854abc3701e73cbf0cd93cbb66bd3c159717bb7d640e3d71bd79bbbb68bd3cfb1794bd1dd9a03c7eba3ebc6426af3cc50c9f3ced8b7d3ce15e453a9441f33cf626dcbb35747d3c65b892bda7a6533cbd8407bc7cdf693c950a523cbcc1be3c355c983a62b8443dcfc051bc8ba8be3cc388adbded13a53c791b67bcbf2fb23c7e82a33cc7e3083d3100063c956a093db14284bc4cc8083d18a252bd297cf43cd8a1bdbcbfaf013dc0bdf23c21e9cb3c1da5ea3b4b5b1b3d787a97ba6db7cb3c225c81bd42dbb33c232762bc26dcc23c75f3b13ccb47e5bba1c7c9bc7369843d6fb8d2bd3f8de5bbc2ac69bc6a9627bca1b5823cc3cc0cbc5db226bc39bb36b913854cbc64e94ebbf9b6963c26f937b9761305bce65e56bb1870903cea0de0baf6b063bb33920f3d7c73583c82d3733d0c4cc3bc548d0f3d195d90bdb191023d3f78d4bc301c093db6c5013d7f318a3c2fb774ba2c981e3d6f2a9e3cb4228a3c7c67b6bd21ff613cba810ebcda667b3c59435f3c3015483cab130c39dfff533d03441dbd5a5e473c6233b4bc348b1e3c24773abd800c353c9c1d1f3cf7a3673cc1903ab9f985323d79ba9d3a514a683c45a14abd3c8a393cfa88d3bb6bd5523c7193363c801d9f3c86f2fa3be68d1b3d29ec05bbf9759f3c595b65bd62ca853ccbeb19bcfd31933cf691843ce622953c589be53b8752243d0f6c32bc3536953c2d8242bce09f7c3cac121abc19248b3c75057b3ca00fa83ce060d83a64c5223da97a8abbc459a83c43becfbca5838d3c7c3f07bc22ad9a3c16d88b3c9927b03c4339ab3bea03f83c5f2122bcd312b03c608389bd06f6963cb44f3dbc3bd5a33c263b983cb7e5ce3cc5bb25bcba13393d3ced51bc2a61ce3c3d2781bd3121b83c2d8483bca0f9c33c7fbab63ccec6123d9c6f913cd42fa43c0d5d4e3d43b0123dc4ab98bd2095073d8e66e8bc32490d3dee28073d820c9c3ee5e7883e21d58bbf115e41be6998a63e8851ed3d4fa3823eb1323bbe3b03973eb62b833e9a929a3e9a719b3ef6b091bfd34d19bed30c8d3e09a5383ea0ec683e812e21befbcf8e3ec5e07c3ed040a33e91ef8b3e5e9b84bf75778bbee639a33ee8b2ac3d1d35893e7d095bbe6b60963ececc873e97d3a53ead48913e532387bfd3e364beed95a53e7944933dc5ce8b3e9c415fbe34e1983ed2ad8a3e1927b03ee5cc983e371882bfc65b78be4824b03e1f154b3df0ce953e79de72bea0a8a33e2d9f943e3e56c03ef31ca43e1b6972bf83bf88be0e48c03edc8e833ba500a43ef16385be98c7b23e34f9a23e544ca63e32dc7e3eb13a85bfafc55fbe54e6a53e1712b23d84678b3e234a5dbe45a5983e97808a3e42a3a83ebc55a23e10d084bf46ce64be9d7aa83e1b14a43d60648f3e808565be19669c3e62108e3e56d6a13eb755893e75b487bf84315dbe1bc7a13e3cde703d574f873ea04b56be5aeb943e5df0853e223d933edf64b73e54898bbf43cc20beb317943e6760343e0e13753eb3c526beccd9853efe237c3e591bad3e081d643ecd7b86bf56b86dbeab68ad3e41b2583df740913eaace67be689e9f3e288a8f3e93cea73e83a9923e6b6483bf176e69be48aca73e617c983d43498e3e029265be25fb9a3e87ae8c3e32d8a23ebf44843ef16887bfb02450be4c5fa33e7fecc33d8c718b3e782054be3aed963efd5c893ed197083dcaba823c6113003d1cae0f3cacb5083dd46f9fbda316f83cdbe4ccbc0474023d09acf63cf8a6a83c5da90d3ac2861d3dfc1c47bad185a83cebcf9abd2455903c090e47bc1b9f9c3c726e8f3cad5dbe3ba90d22bb26f5cbbac2f77ebbf18ebe3b8fbe61bccbda5d3b5457a93aa94f9b3b58725c3b8563c53cea9e0f3cdd7cec3c546664bc054cc53caf5188bdbf3caf3cd0847abc8750bb3c382cae3c96589c3c4c5e353bd5f21e3d3ec868bc097d9c3cdd365fbd631c863cb8fa28bc6aca923c92dc863c38d4023d838a433c574ec93c22538e3c5bcc023de06d7dbd2e20e93c2f91b5bc52f4f73c71cce73c4f17753c9c991dbbbba1763d53f09fbd9d567a3c9d630cbc6c514a3cb4e034bdee6c563c1e974c3ccdfd873cb2e7b4bb7f3f483da5fca1bbf09c873c78507bbdd2295f3c5f6b0ebc2687783c5f4c633c704d5c3c304cb33a9edd243d3909ac3add755c3cc30a80bdfd9e2b3c4af28bbb8f92453c8e9e293c339ba23c4f2696bbaa0e013d8d6e8fbbd490a23ce0cb93bd10dd893cd1033fbcebb0953cc9c6933cd4cfbe3c3d45ef3bd61b503d5fa76dbcd091be3cd92976bd2c77a73c6d477ebc56edb33c1d5aa63c3ae62a3d0a49a63c9efba73c13784c3d7a9f2a3d4e4ca7bdcad11e3db19005bd80fb243dde7b213db4ecc33c6c3e6f3bb1b8113d2bb68ebcd3b2c33cdf003fbd2ca4ac3ccd8e73bc81f4b83c7849ab3cd2a2c03cfc709339a2e0043d9f8a02bc674cc03c0e9944bd126bab3cb92c62bc6320b93c78eaaa3cca0b2cbc73e0e2bccd76913d2c9cedbd9d162cbc8d589dbbc6f962bc9c75a43c0cda46bc6fdb65bc15af763c68bd443b2e02223d90eb9c3cfa48763c99de89bd36dc4c3c1a0adfbb84da673ce7a74f3ceefdd93cfa98193cab141c3d4446613a71c4d93c1d159ebd08c2c03c465f82bc8be7ce3cd619bf3c282a963c5267223b7598253d5f769dbba94d963caddeeebc2d6b7d3c791924bc711f8b3c3272853ca4c5283b893cacbb26eeadbcb0603b3c27ad293ba5c885bcef5a083ae687fa3b27d5c93af2ad903a4cc7bc3c922b3d3c99ed353d0af795bb3addbc3c1dee89bd5326a13c16fa39bc0d1faf3cb1729f3cd0c2963cdb520439c743163daface8bb63d8963c72d358bdc0457b3cf4bdd0bb57548a3c9f707b3ce93eb03c516d2f3be5ea483d377824bcfc9ab03c24e597bd7440973cd88540bc90d1a43c7fce953c730ab03e7ed7a03e649b7fbfea7277bef776b23ee665563de5b2973ea9a975be64cea43e75dc963e1318963e01e98d3e0a908abf14b24abe0ada973e6d38cf3dfc3f7c3eab5145be6db48d3e8a187d3ea856aa3e3eeb943e098885bf636f6dbe9845aa3ec25c833d759c903e90d668be010d9e3ec46c8f3edf6ba13e098b973ee31087bf41665cbed9aba03e21aab53d048f863ed47554bed218943e8e2e863e7252a13e0b488c3e1ef985bf1e7a52bed3a0a13e0f0a923dc2ef863e4b774dbe0c93943e5c35863eb193a83e6f21973e641e85bff43869be96d4a83ecd648c3da6e68e3e92f464bec6209c3e80b58d3ea3f1ad3eb81e7e3ec19082bfa91d59be150bb53e0be5be3dc248943ee22866be46f7a23ee39b933e183ca03e868b873e1f0e89bfa7ef57becf28a03e59f58a3db348853eb2f651bed0f7923e290c843e66aaaa3ec9f78b3efe8886bf3ea95dbeadb1aa3e10eca03df3848e3eb8f563be7c409c3e33188e3e5086b83e91d987bedd0c8dbfdd9944be8ad8b13ee3c0353e5f5a953e190947be5457aa3ec113923e6b8d983ed309843e1c9a8cbfb46768be3855983e9869ec3db8227f3e0c164cbed8718c3e141e7e3e6b12be3ed1c9a23e500277bfa39387befff0bd3e2217f63bee7aa23e6d3784be1cdcb03ef3e2a03efebe9f3ec75c873e660a88bf546053be14b69f3e2d29853dfa5e843e830a51beb669923ee522833ed5f47d3c76dc8f3bab3a1f3ded72fdbb3be77d3cf4e503bd9edc4f3c1cf6debbaa59683cf778523c00b3ea3cd168373c2a152d3dc6670e3c4babea3c54a297bd60ffcc3c7c7996bc8041dc3ccf46cd3cd515a23c5d27983b1db9543dd402bcbb583ea23c993a54bd696e873cb54f1bbb634e953cb9c1853c112cf43ca1daba3ce697123d55674dbda931f53c184700bd0ea9dc3c3ca4b5bc630be93c6b22db3c428f083d9b33ca3c588b9b3dc59ebebc94b4083d08b764bdf676f63c7756bdbc0530023dc1fbf43c90ffbb3cc097523b7b69ea3ca90736bc6981bc3c5ab0fdbcd2f0a33c8a5b76bc1caab03c2b6ca43cf022953c81d5a5bac9373e3d626923bb3645953cf4dd58bdfafe7b3c2e1d30bc0dd8893ced6f7d3c6a1bcd3c1ff5543ccbeec83c1834f73caf07cd3cf0065dbdeccab73c856485bc0957c33c806ab63c38359f3c60ba3a3b3042253d8eaa443cc0ca9f3c50463abd6ccf813c26430eba7da2913c09c38a3c6a92b03c1852ce3bbcbae73c768b84bcfcbbb03c7bab71bd17b19b3c5c4068bc4b6da63ce9859a3cdbb3eb3cab0b733b4cbb053d146391bcfe6ceb3ca8806cbd100dd33cfeb3b0bcbf29e03c48f9d33ce397a43cc819043c0102583db3ab2fbc04c4a43c963166bd0319933ce3085abc9d119f3c5e04953cfcd6183d0831663c9cca383d6a098bbc8830193dccdf8fbded6e083dca0eaabca265113d73d9073d33b1373dcc15fb3cc9e0363c1692963df9a7373d8b2993bde8a9293d8abf11bdf1c7303d11d4283df46f653c1aab2bbcdbc1573d40e0e4babece673ccdbc5cbdcca1353c5092b2bb5d8a503c55ce323c0049d43c3a96863c4b83cd3c55c24d3d70b5d43cf82395bd9359bb3c3cd575bc2748c83c06d6ba3cdd90a63cbc29fd3b9fca203d928e5ebcd6d0a63cfc7b61bd96478e3cde524fbca0e99a3c67b18c3cf720153df7f3c63c58cde33c91acc0bc6815153de88348bd93ec073de7c2d7bcede90e3dc719073dfc32dcba0cccd8ba7f520f3b705e9ebdad49f9ba6f3624bc9c576abb2e7a213c846338bbb17f67bb9c86ebbb2e80c1bc7528853dcc27f6bd9108ebbb0db074bcc59127bc06ea863cdc230ebc1aa31fbcaef2f03cbdb8433cf0f3fb3cbc398dbce23df13c294209bd57edd63cd970a3bc5f74e43c5f97d53cc6e0f43b263ca03b333a563df14285bde690f53bfa138abb2adfb13bcf476fbd80ccd43b9cb0b03bdc17a23ef5c88f3efff784bf69036abe752da23e15b0863d8f6e883e32d259be758b953e431d873edc94b13efa2e9a3e72c780bfeb4281be3f9cb13ecf97363d9abb973e3ae279be51f9a43ea3b4983e4b5dab3e1ef4a03e18c185bf09666fbe89a1ac3e4846a63de1ef933e533e6dbe0a45a23e67bb933e7dcfb33efb11623e2b7384bfeebd54be3dd7b73ed5da9a3d0995973e0d055abe6469a93ef0e9993ec156a03eb186a33e1d4586bfd30f4ebe68999f3e821cd73d6ec3883e844d56be4742953e4ecc873e0d9d9a3e034f9c3e8a148cbfae2543bef7979e3e80d30a3e191f7d3e130448bed044903e62cd843e9721ab3ed76b913e2a5b83bf4ea18ebe5221ab3e6ba97a3de55c903e5cf566be3e6b9d3e78ae8e3e118c933e9fe9af3eb02f89bfd9d23cbe0cd9923ee37a073ec27f7c3e629338be808b893ef4c9823eedd4883e646f8d3e256995bfa1c925be98e1883e7eb2193e4e7f693ef5a325be5d467e3e009e6e3e32b4963ea7d58b3e0b758cbfcaa23bbe4b09953e186ae43d63f7783ec1613abe51bf873eee75753e2df1b73e59b59c3e00ed77bf176881be2fcfb73e8aa5023d55fe9b3ec86c7cbe9c84aa3e77be9a3e11f1a53ef114703eace587bf6d174bbe8258ac3e6a80f73db853893ee53154be25599c3e9281913e1a16983ecfd8ae3ecd138cbf996a47beddbb983efc4ff73d81387f3e681e49be65048c3e69b67c3ea8cadf3c28886e3c1307163d12f153bc72f3df3c4a7411bd18b9c53c287593bca1fdd23c4829c73c4a6e863cfaea7fbbdd75153da83e8bbbe749863cebb61dbd4300593c517fddbb0f98733c7af6583c0643e93c9dc787bb7be7553d801e88bc6611e93c8091a3bd098cd13c5bbda5bc684cdf3cc0dbd23c5d2c2c3d69548d3c0781c53c500ba33cc20a2c3d0393bdbda3421c3d70a1e1bc4bb6243dc4751b3d064a9b3c78d86a3a64dc1a3d7659193dfc439b3c5ae2a4bd5235813c4e7c0bbc5bbd8e3cdb707f3c25bcf23c49910b3c7d24253dc8acb4bcf699f23c2d5da7bd31a7d83c2912a2bc5437e73c7852db3c77f0c13cd0691d3b8678fb3c6094a33b33ecc13c4ec984bd3eeba53c14ed72bc013cb53c53b6a53cb0e92abb330ba8bcfb3a653ddc610ebe12dc29bb930b8839d9c7b2bba3eb373ca3787bbb902cb8bb43efd93c352ee83be083123dee1f8fbc66d7d93c57c392bc1001c23c36c58ebc0c95cf3c3e72c03c63b0ae3c889ecd3b4c7f143ddd0d40bccd99ae3cc33668bd25c6943c407656bc44e0a13c7e39933c0b68f83ce7dc593c7010f23cab366dbc4059f83c74bd8dbda48bde3ce4708dbcac03ec3ca118dd3cbb37c43c7473503cda1ded3c38583cbcd168c43cb401d7bc0550ac3cd0107bbc347db83c6ed9b33cca52a7bafadb3fbc4fa884bc8ab8953ccd17a8ba5a4d8fbcdb5694bb8895723c216b3dbb035c9abb1817ae3cd69cef3a4086193d7eae30ba6d33ae3c4dd42cbd0c80923c48ecbdbbf87ca03c7bb1903c1c9e813c68c040bc13403c3d74af21bda092813c584f23bd697d553ced45bbbbe61f6d3c0ed4523ce9d0c43c4944153c78c6103d209eedbb62e7c43c6ce52ebda354a83c510045bc745cb73c0685a73cd8a3823c1a4cb7bb733f333d30f0f13a44ee833c8cb91dbdf4885a3c54a6c0bba98f6f3c5a3a5a3cf714f13c10568f3c19b8393c8e53b83c249cf03ceeb8b8bded0cdc3c046facbceca5e63c59cada3c2dee9f3cb6e7ab3ad28c2d3dbd9f29bce43aa03c6d824dbdb36d883cd7f238bcf200973c8bec883c4dbee53c205f273b946af43cc5fe443b6ca3e53caa017dbdacbfc93ce4f38fbc0a3bd93c34d5c83ce4e46d3cc4784aba4a8e323d779a253b86e76d3c60f15bbd5dd0393c213e9dbbd1ba543c35dc373c6aaa293db865963c2eee063dc46f17bdfcce293df449c7bd8ab91e3d330905bd0985243dc79b1e3d6d82b33effd4973eafb089bf0c185bbed15cb43eab30603d6623993eb08774beee85a73e1581993e172e9d3eda51f53d0d938fbfcdda97bedad49b3eaedbec3d684d803e12de45bee7918e3ef8eb7d3ec828973ebd9f973ea62b8bbfa44749be47d3953e8b70073eefaf863ea4233dbeb66f953e8177843e6f06a83e0861a63ef8d587bff78551be175da93efb5dae3d14258d3efc625fbe2db69c3e688a8b3e2230a33e1a7b8f3e864289bfd23960be6f91a33e8f737c3d14c5893ef3245dbe3cca973e70d1883e5b4d9c3e2066953e4f0c8bbf4f3557be77639e3ea49cac3d9c05833e0d9351bea7b0913e31e1813e3edba43ebfd38d3e262284bf163b6bbe03daa43e878a5c3d3c8e8a3e61395abe780e983e6268893ec55bb33e540d9c3e3b8281bfcaba81beb853b33e40af323d37cc993eb6847dbe41b7a63e78c7983e2414993ef5f892bec46d94bf75fa1bbe10e59a3e7c9a7b3ea53a7f3e354107beed0fa63e1253933e638ba23ed9a78d3e7a8789bf98845fbe9a6ca23e0d587f3dd78e873e0eef53bead09953e26ee853eade2bb3ec607a13e6a437cbff23186bef9e9bb3e1204ed3cd250a03e4b9b82be7d7fae3ef81b9f3e3137b43e0c4d9c3ee8ce81bf636081be0f22b43ebb53263d0f4c9a3eabc37cbec4dda73e52e0993ee3d4b13e9ba9873eb3bd7cbf99a772be6eb7b13e20e7443d66d3953e3bdd6abe492ea43eb922943eb8170d3d72c6a73c9126893dbdc6bfbcdf0d0d3dee9b4fbda53c003d6c50d9bc9dc2063d54ecfe3c0aa2ce3c99dc5f3cd2dfa93c894494bcf151cf3c0b713bbd1753c03c8bc49ebcde53c83cf8bcbf3c827ecd3c8cb95e3caee7f53c00795c3d3d8acd3cb4ef8bbd5002b33c65d719bc3063c43c849cb83c55bdf83c4199863c7347633de43eb2bcfda6f83c79d4acbd9c5fe03c6c1ca1bc0008ed3c818ce03c2a63e23c0cc7a93c2588243d4809e43bf840e23c72d2cfbde883cc3c10eea3bcb72bd83c312ccb3c0449dc3c0f33f93b13cd243d419c45bc51f2db3c1c3d6fbd25b5c13cbc5e80bcf463cf3ce12cc03cd2199f3cb9a19d3b4482163d6c2bd0bbbc039f3cdf3306bd045b873c320a40bc024a933c5054863c9a5f9e3cca664d3bd7d3833d867369bd68de9e3c444a15bd4664863c67ad64bdb24a9b3cd9188d3ccae4a83cf4dbd13b06e4283d8a06fa3890cba83c949384bd2a1e8f3c05734cbc91689f3c96cb903cd1b4a93c94e4b33b7fd80f3d107f1bbcbb3baa3c68f10cbda64b923c592b56bca5849e3ca5de903c0334c13cce18b93b9f3f673dfa8631bca040c13c7daf86bd1ad4a63cf01572bcc302b53c6d42a53c2f36df3c9e22083cb016543d6d4c5cbcde08df3c42599dbdbc80c53c625f6ebc0591d23c4dd9c33cae59aa3cb2fc4e3b762c253d5761d03b7052aa3c3e618ebd4475913c859144bcc44a9e3c8df88f3c09aa863c47492b390b0fad3c17ce0b3d4656863cc1715ebde2766b3ce3cb05bc2905773c2235693c4e8ac63c0b59873c52cac93c5624b0bc8ab7c63cd514e2bc159fb23c646693bc63e9bc3c9409b33cb999833c0c33d93a95c2383df7b702bd367f833c061ddcbc0cca533c9ae4a5bb22fa6c3c695e513ccf92c83c9331823c65f1633dd4252fbc4f91c83cc1dd66bddd28ac3ce66a6abc93b2ba3ce865aa3c7050e33c31e34c3ce11c2c3d588d80bc4780e33c35f740bdd66bca3ca64099bcda44d73cae0ac93c0e3eb13cad4de33bebcc033d0a95b7bbb52fb13cbac576bd6831963ce05f09bca6f7a33c01ba943cc31f8a3cfc90e23bf2b0373dab405d39740b8a3cf67968bdb619603c647ee5bba66b7b3cc13d5d3ccd4ebabbd308b5bce3fe7d3d5385debd4859babb20e1cbbbbeb613bcbe229b3c4e8ae8bb26b811bc5d2fa13c032a2e3c0932063db9098ebcd252a13c6dbe5bbdd1e5903c48455bbc9e599b3cdbec8f3c88a39b3e65cf8a3eab9388bfa45656beb5739c3e26f6d43db006833e655e54be46568f3e0a13823e66d9a23e4a06943e1f0688bf09014bbecca1a23e89d19d3d34e3883e303b46befc1d963e7a31893e5835ad3eda26943e4e2884bfd92171be1235ad3e30d8133d1d47923e18446bbe2469a03ef82b913e26fdab3e23af963ecb9880bfaa8178bedaffab3eeb355f3d2a76913e28fc69be2c9b9e3e75a98f3eb27cb13ee4d1983e6f3581bf45917abe437eb13e3952293dcdbd963e6e1d74bed99ca43ee083953e3643a53e6b4e9f3e76e187bfc68e38be1fb9a23eda5abe3d5585893e977658be86e0963e2ccc8b3e3f47a33e92508d3eba0d88bf421a3abed58ea43e1bc1cd3d1015863e9e263fbeadef973e0f9d863e0875a53e23963a3e15e289bf9e524dbe4068a73e9f73e33d41028a3eaa9b4dbe8f6e973e614c8b3e7aa18a3ec72da33e84148fbfdc6e26beefca8e3eff033a3ef00d6f3eef7d28be002f803ec78c753e9a969b3e7619933e8e1b88bffca361be72929c3e64c3bc3d9dae823e435a4fbe25168f3ef835833e196bb13e6b369b3e198e84bf3d9180bed558b13e1453423d598e963e699974be397aa43e57d2953e5776a63e1be09f3e20ef80bfcda98cbee320a73e78e49a3d3e348f3e8e2964be6b1d9f3e69fd903e5109b93e36f5a03e069f7dbf872683be0203b93ed9d3a33c853a9e3ec0d380be58abab3ecfa79d3eb1eccb3c7bf5c53badcf1b3dfdf334bc3ee4cb3ca96835bd490bb23cf3ed79bc995bbf3c5279b03c5e1cb33cf6fb1e3a396f6b3dea2909bd1332b33c0de8cfbc1db79a3c5c0913bd1a3ca73cd736993ceca63c3c0c594abb63f8113d3d3b67bb14cf3c3c544b1bbd0b6e173c05b17cbb1aa62a3c3daa163cfc91093d7771953c37be013d3301e53b86ae093daa78c6bdd65cfd3c157ed1bccb9d043d5850fc3cb72106bc838eedbcfe987e3dbf3905beab7206bc638e69bbdf963abc6a8b963c04811ebca9ba3cbceae4f33cc580443c506d253d2ff2c1bb67f8f33c21bcb6bdbe22de3c43d8bcbc003ceb3c55aee43c05598b3caf968ebae5445a3d54c920bc2a2c8b3c0db078bd4896663c06d315bcca697f3c6903653c81ba553cbed6e83b2a243c3c5c26fc3b6c514a3c6340f2bc85cd233c9ecfd83954ca433cc67e2a3ce5bbac3c679e803b0900fa3c1a5f3ebc6eb3ac3c6df84ebd5ff5963c71cd6ebc23f9a13c41a5953c27929e3cc454133c9ea5093d77c040bc56ad9e3ce8acebbc2f72883c290a48bc484c943c845a873c91fdc03c46d3513c5b383a3d84fb79bc240ec13cbcf554bd7d10a73ce28d55bca73ab43c7686a53cebbfdb3cfe20e53bd2ff573de6ac73bca6bddb3c21d78ebd3d06bf3c4bba7abcea96cd3c0b54bd3cd449013cb35c20bc98b8023c3963b13bd39f013c04c9dcbcb219a83b37f0823bd29dd53b8b80a23be52df53cb222773b5f5b1d3d6ed672bce134f53c668f85bd5393da3cc44aa9bc9f62e83c1135da3c687a433d84fdf93c422c9f3cf78cac3d6d7f433d6009bdbdf7b0363d29111fbd456e3d3d58a0363d9255dc3ca950523bb778dc3c95428fbc794adc3c68cd46bd5314c13c1e81c0bbd319cf3c808ac03c1c6a8b3c39817e3a474e2e3dfa0f173caa568b3c2f2aaabd9d6c693c61ef07bcbf43803c9fad663c3faabf3c4a3d163c74e3f73c3d8c3dbb84a9bf3c83c79dbdd605a73c4a5e7fbc0c06b43c0cf9a53c2dc4da3cab84673c7056263d788f7dbc85a6da3c275122bd36cdc03cdfab94bc7cdbcd3c7141bf3c6edcf83b0712a6ba17098c3c483a0c3cd2f7fc3b0a50c6bc64deb73b5549193c21b3d83b5f52b43b78dec53c1403173c8fe6053d619053bc4aa0c53cd2bb41bdc518ac3c25ac7bbca3abb93ced81ab3cfda5e63ca2a9483cace2063dc2aa83bc2094e63cbaa92dbd3360cf3c1c7fa4bc9f76db3c3a8dce3c760a00404305a83fd2f79ebe24efc6bf787c004029cbdbbfae13e33f0c8ab3bfcb70f33f5832e13f1ff80140400cac3f9ce15dbea00ec9bf13c10240de3eefbf6f9de93fdb33c1bfe38ff83fce98e83fae8c064079bfac3fa3fc31be2af4c1bfd2ef06400bf0f3bfb7f4eb3f2aeebcbfab92fd3f0814ea3fe37673bfee12e2bed21e0f33fbc90f3f452076bfd3531a3f75943cbf80b40b3f71ef63bf163540bfcb0c8dbf5bde10bfd63996335731d83e56598abfa866263fd2ed4abffbbf0c3f39c278bfea2b5ebf503473bfc52da5be4f8d0837740d063f679f63bfaf30103fb6743fbfe75bfd3eba575dbf9d933abf5ffe77bf4abd08bf68351734e60ed93eb95b6cbfb45b073f8c2940bfbb28f03e49a74fbf0b6b36bf38ed89bfc856a8be7bf03234db750b3f2b707dbfc4831c3f3c3949bff020043faad57cbf11ff5bbf2a1651bf483afcbe862ec633063ce63ec33f55bf22a7083fb47f28bfae94f53e10fe4dbf690c33bfb3aa65bfb58025bf72474e34b17be83e6f5f81bf514a183f88b341bf01df013f36055cbf275a3ebfdf8d8e40dc717140d84d39c1f13b4bc06d6a8e40910d63c0accc7040928e45c01ab483401b416e40865ed3bf71c0a8bf29b7a53f8bcdfd3f034cd8bf4fb7e23f674cc9bf8eb0ff3fa92cd5bfa593cebff54f50bf +\ No newline at end of file ++36363265623439336565393638386239666262313430386562333233346136306663393564326465346632613262633135383163376363623961663035303265323332643236613938346534633837626639313236343833376565646336623561346131343434613933333439626530616333373164653737643064383432363232303538626463633564373833356236633837333136343461363137363731656439386231386135663764333163376438623464623937306666383630643164623863366163343363643130313435636565623834363361316133393230363937653835653762353534626439663133633538623062353439646237616630333237666136663433386334626639643465303163653832333062643863333664336630376231643964316231663933656333386338656262303734376137313565643963396535653131303763646533393234333735613333633132353061393531333935623539643834373266303861633739373862366663376365383233326139383939363566373061373361613939336537366631353334346563313061373365663635633332663437653136383235343635623234366430373330366336363237623962656465373233346131343264313137653838643334616430346339363732613237623866636364313232613934343261643231386531356430343965303330306332326266336634626163333461643139653962326566303064343333623037313762303934626336363537616339343637306633633066333231613063623339333539376461316632653234353938616133616463623534356232346135666261616339646638373031356633306161626465643665633066616264623965656138613233353331303236363565616133323131653935643363353832366663633434626236376663386335666364333530336433353234383031636264353761616638663031613263353738326438656265623236653338323232386565626464393034633962373835363264656664616439353336623462376139333134656662373033626135336138333136643032636430653334303861616439333736306363383862306439623962646435383931613161656137356462666463346364333361623035396139323366643262383764363763323530613631653861653634666630333030316562323662346133633566316533346236663132363663663739623565366564343962313033386462653236663864613664303962623535363134336361326534666230613461643036356361623365363830623066373064386262326466363934623535633664373865313164633832393733616432306435663337366633306565386434613131613061636663616630643839623737366361623235653838653366303334613439393362313664373862653234396263323361663762626238373531633765333530666363393132333237616137663336333434326233313735303764323765346238313333393839646334396539663036633034396237393461336263306463333738313939303164393262336465656237616466643562303362333632303838336162666434636265363361333466646564333736303437383432623738636461313736336539396364306164393937313064353136643231663135306364643936646137386434613564373335643430363162623534623133366633353137633236613635643433306239653638666165343231636163376139643564653333336637393138356233633164623465396435396364353031663066643661353130633336303365313365323461343062346266323135653337393561396134306436306138343536666237623633633264313165383137303161323331653835616664346235646238316162633164643536643237313733326564303234356638363931626463356461643334373664366636333536303737623161613164363334613937633431303962353962373335343766393430633164633864323163306631383733383866326433613865656366656537666438363739303266643461633331626131633966646635316261613261343337626663303932613166373332653261386630363637363337343262303737306136653236653332663262653565343761333733303934663366396234313838633834336435633462656135613261346163346262626466376661633763653339623230363235373337373135343130663233646239373035346236656232373065666363666237636234313736663832363831343263656131366532386232316463393539383730306566316462386539616434346537653138343162313462313235636366333561313765386366666138663036383233626434366366383536653461663236336238616166393638626138353062346439616666626563343933666130666530613833336539653436336538376132636365306338633038613133636363613461326134313639623365396134633133666339346337613637616230393963653932636336386561343761626166313638386162386131373230326638646130353133633533353964323735303632336632343431363463396634353338346566303665373533363061373664346462643034663036336636303863636363373830663166313238363531353931346461393730353236373461643039653235366663353938646363643464333835646164353838623664643261303365363139346361393864383734623331623662306231653235333362633134303864306436613862616330613136316136393132323137343831363364646362313231303362316131313733366362386566353536356266663035356633313633323533383133633963343136313330346561336663653535616438303565656331373466386437396361363764323037616334366664653362323562366531643531633464616561653330386532663361613839666339613234623762623864303635363239323732633437313135623561393362653837653361396438373339666232653861316665613661613331383532616631393033383937333463353139343637613931376332666164316634363432366132316638656362363461336166626237613736336638306232313930636165346330323165386264366337316432613138666663393538363731333639396239666362393336373737643238636639643761343231346131333463353261623633343633343866663966663365346237313164613933626232343636366137616430363063643632626237306335353536396233353566633932393964346162636636376563656530396161306664656561626436396635656632346534653861376262386430376664633866626464346666653730326362316232653965343564313031306138623562363130623230313963396265366130303837616232366634326335646531303539353531353137366562353736323737393436626630343433346330356264653562376231356532663139306164303361383836396333393339616236383439363661313661303665643535633961666563613431303466333534346564633533373866306361633035363431646633643837383532663863303765623439623930373061333833633261383932383764356133323539336632353130303266643661643531313731316638343339653162613735393261653833333065316432643865616634333936326236626432663237656439643439633335656534373338313766633338646231316433363030393633613732386331363461303139393161316436323764326235316237613364393537303630633634616137656338386231636561313937653562653562623466633136316330383533636239353561353063623464363362636438656639613233323237373363323039386566366463292e54431c0d2841d1de274156c13343e6951045f1fd534109c4de3b9f6ebd3ded6cbd3da93ec73b81f3b7383692d73d0000803f44ec4d3bda7fc4bb49ae0c3bbf55223ba662243be961253b7f6ac1bb950824bd01041c3b85c2243bcdfd89bbdce3893b6a136dbb30abd8b983397ab9414576bb75923b3bdaed623cf48a7cbbaad072bb436bb1398a67c6b91a350b3a3fd405bbffd406bb52cb173aff53d8bae8ebdd3ba0472d3abe421a3aecead23b076ae4bbb01aa63bd125173b6b1f2e3b0053b03bc5a18abb6b245fbc8be9c03ba23e863b4fd053bab188153d404ff4baf5796cbcfce45cbc652bd1baeceb893c54963939e9621fbb2e4dd0b923bb3b3ab3f8aabbc88ad4380b2c393bec993d3b1c6d853979dbdfbb7348e8bce2851e39d276ae39f195e33d6f2caa3dcec0e23d3f9876bfe57147bf6e88f13d65efd23dbabdbdbd7518183edcfcfa3d8ee1f03dfef1b13d27b5ef3d6f097abf16014bbf690eff3dec61da3d4bb4cbbd37ea1e3ebd41043edad6f73dbedba63db40df73d835b79bfe9154abf0c15033e1a5dcc3de851d2bdfa98223e58d7073e6879e53d639bbe3d396be43d57f979bf0ed94abf72b8f33de7f1ed3d0455c0bd599f193e4238fd3de2e9e03dc100ab3dd0dce03dc6bb78bf5f7149bfac17ef3db8c3cd3dc776bdbd6b3b163ee44ef83dc30ef03d97e9b03ddd84ee3dbfb178bf947849bf4cf3fd3dd0b9d33d99e3cabddb7b1e3ed2ba033eaa22ed3dfca8bc3d9eb4eb3daca679bf70894abf2a62fb3d6144ea3dcc32c7bd44da1d3e227e023e3ae5fc3d48ceb03deffefa3d05f479bfc0f74abfef69053ebdb9dd3d6ec4d6bdcc81253e3a3c0a3e9409ce3df488d73d4b52cc3da29678bf6e7c49bfd6c8db3d8a6ef93d9cd1a8bd4b8a0d3e6a34e53d754fe83dd1c1c03d3571e73d4db079bfd9a94abf724cf63dcd69e13d98b5c2bd51611a3ebeaeff3d2896eb3d005fbf3d38afe93db8b078bfc4c449bf2f83f93dea62e13d0ab5c4bdd8c11c3e958e013e84eeec3d20c0c03da2f9eb3d2dce79bff0c74abfccdcfa3d87c7e13d0a1ac7bd769a1c3edf1a023e49a1eb3d1e91b53d491cea3d25b978bfad8349bf918ef93dd730df3dee0cc6bdf35c1c3e9087013ed58fd13d471fe83dd9bdcf3d543a7abfae0e4bbf3973df3d7060053ec8aeabbdafa10f3eb0ebe83ded1d363bf444c6bb610a8b3bf725a33b0aae883b49a1813b5f6ababb95d0013cc96ebd3b50808c3b5df8b63a7ae672baa0ab363b90ac2e3bb83f793ba086233b54ad13bb0810193c3b2a833b67df343b08aabd3b621c913b8cefe83b0a14843b5512733b522de23bf3c28ebaf175a43b8449113c0e1cef3b2d12123c7b172dbcc8f6293cf0974b3b2565133bb8d7253c1bd54bbcd2cc023b9404453c16aa2b3c50c2743b82d8babbd296a63b8c86c63b7e84b93bd4d5a03bd5e6ea3a8f4be83b5431eb3b19fdad3b93f4b93b189965bc2386e23bacbbc93b3825cb3b2b51e03b51f591bb9a54b13b8486153c3011ee3b73a01e3cbca45cbb566c353c726914ba0bf85ebad597303cb5eea7bbfe24773a552a4d3cb302363ce93f723b18ca183b1bf3a83be636b63b556faa3b4f839f3b8c24cebaff9eed3bb594db3b9ab6aa3bfc4ea23be97be1bafb2fcd3b3011073c7237d63b7004ca3bd686c8bbad24c63b92fb073cdf78d73bea71fa3bb0adcabb491c123c0c02943be730773b78b20f3c930e87bbc880433b57ec313c51e1153c66b553bb8da117ba5122eeba415c483c284f3c3cd34109bbe7f6b8bb89e9653c54cbd5b9653aeaba42fd7a3ad1a505bb42ed253bab1cb73b3450ab3bc6610b3b219acbbb8a1f1d3c0bc0743baece1e3b7a77d53b38030cbcb774ff3bcd02c03b0e56a43be5c2f93b0a9d0abcbbb28d3bc5821f3cac23033c255ddb3bb25f6cbb6aa0053cea93bb38b8056db998b5013cd42003bc4896693b77f61e3cba2f073c25f9463c45bf05bce5d35b3c9ad2283b024e083bc8d85a3c110ad1bb940970bac9cf803c2ec7613c11b0d93b0d03c63aca5e013cad7fee3b9e6bea3b1751003c5c3fa73acd28933b78f1243c2b1f073ca2cdb93a8b05b2bbd16d383b9494013c57b7f63b2fea2b3b00ba063b5e41153c6a74943b4a22413b7e20283cd071b8bbb3e33e3c8d88153bdd961a3b3b093c3cbe15b0bb84a189391e275f3cabbc423c80d04e3c1af283bb0478633c53eab13a51f7913af867623c2d0ca9bb67c9ecba7b85843cfe79693c7e980db7d54e18bcf75cd83aff46043c679fff3b7fefa63a8b7f15bcb7652c3c2d48483bd9fdd23a7bd19d3b7750eabbd839c63bc5b7003cc817cf3b704ac23bb1d8b6bb325ece3b3f22083c970ad13b9562233bc4a372bb2ff47a3be36f193c67241f3c82a46a3bd1dc46bca22d053ce294b53b9011823b2436f73d6ce3b53dc896f53dd2e179bff2bc4abf938a023e158be03d10a5d1bde576223e894d073ec61be33d50d9b93d0875e23d086379bf9d4c4abf6f10f13dba39d93d514dbebd183f173eca3efa3ddaeef63d15f1b13d748ff53dcd3d7bbfb5274cbf4277023e56ffe53d0dd5d1bd6a2b223e6039073eb7e5fd3d1c5d9f3db32efc3dae0277bf61ee47bf9ae9053e7ff9c23db2f4d7bdeacb253e95a80a3ebee8ef3db626bb3d9293ee3d3cc37abf8bc14bbf08d2fd3dcaebdf3d0985cbbd346f1e3e229c033e4baed83da377c03d5d46d73d33ec75bf312647bfb6b1e63d0855ec3d65d8b1bdb1f9123e462bf03ddf1ad23d4f5ede3daf8bd03de0a079bf64bb4abfd2d9df3d870e013e83c6abbdc87b0f3e7a41e93dac68ec3da820aa3dd633eb3da0ca75bfccfd46bf5c5ffa3d3094cc3d7811c6bdf46c1c3ed4e0013e7f9af73d1189bb3d5e3ff63d664f7cbf38134dbf3ac0023e5b7ce13d89f6d2bd386f223e178a073e6344ed3d28d9b53d2bceeb3d056079bf361d4abfd932fb3d531bda3dbba5c7bd95381d3e8d56023e50b7ec3d3d16af3d8f02ec3d4ec678bfea9f49bface3fa3d671fd93dbdfdc6bd827c1c3e7f11023e38f5d93d3636c03dc5f5d83d440778bfa80549bf33fae73deafee63df176b4bddcde123e5f3df13d26c4e23d9f5de23d5122e13d3ae07bbf31a24cbf019af03d672f033e7b31bebd60e5173e1a15fa3d71edfb3d67bab63d8a47fa3df53a7abf3f474bbfe4fb043ed2d3df3d3ecfd5bd5aa4243eccb8093e6484bc3b30987bbb19eaed3b7c7cd93b2cbdba3b9662e13bbacd1abc23629c3b7ebf0e3c4aafed3b1abcf23bc84e1e3b440b0f3c07bb8d3a72a8d7393d020c3cb2b6d6b993885f3b569e2a3c0691113cc555b0bb3857a2ba3ef680bb3568733c4415753c38cb8abb189b0abb0254843cb8e823bbfbbb80bba47a8f3bc407dbba66c4c13b19323b3b6746403b217bb43b9fbe9cbb00a0bd3b8008e73b3d3bbf3bd24fe53a777b4dbbf8f2513bb632ed3bc87fda3b5e3d413bb3cd573a618e0d3c08df953b0c27573b3941193c5f420aba71ff2c3cb93d323a87a9b3b911ff2b3c9cc669bb8741ef3aab8a533ca325333cb57cab3bd1e900bb7741d63b11077e3b8470723bd04ad03bcf4b72bbadafb73bb7130b3c9e69de3b0f5a0d3c945559bb2cc9253cf286023b05c85f3a7b2c213ca5559d3ab5e2033b192f423cdb50273c1139db3ae36a3fbcbaa64c3bd4b42f3c858d2f3c64c0373b3d0611bce4e10e3cd931983ba3674f3ba3f9babab6eab7bbbff15d379d75433c9ef0373c0a9b9eb9d45dd03a15b04b3c0cd9d43a8af382389bf39f3b4b97d3bb2d70c83b93ddff3bfd01f43b3f02c63b46fc96bb6149d63b2491093caec5d33b56d4683aab55e9b970d40d3b0ba01c3c5e431b3c2c1d043be490c4bbd47e1b3c10117f3b993c1b3be4d49c3b9af7dcbb4598c73bbaa99b3b74748c3b7486c33b6718903b7509cd3be90c023cbf7acf3bab9d073cfd5590bac3251e3c7d903a3b4631143bf3f81a3c366f12bcc2460b3bac113c3ce1fe203cf360f33ba4d22bbccad9113c8d75a83a101df239d5ee0d3c6dd479bb7c0b4a3b917a2c3c4a84133c1c32da3b0e48103aab2d043cc0f72e3add290739fcd4ff3bfa1e523b2f4e873b561b203c0253063ca091613b7b9cb1bb80f39e3bb3c9f93b72a1063cff02973bb03ecbbb264bf53bb36cd43bb01ba23b8fded33b3d1a683ac0ff003c3853ad3a3f3b9f3a94d1fa3b83eb07bb4e9b933baff31e3cc0e1033c2b3c153c2a7e71bb38092c3ce31a59394360b4384676273c984b14bb70e0d83a4102433c1f8a2c3c6421e53b0b6f6abb27130b3c73517d3b9982543b6774063cb2a505bc27a86b3b97e9273c32950c3c31dfee3b10ad5bbb124d0e3c8559993b547f883b313f0a3c539707bc24da5a3bd2df263caba50f3cb1a2d33b2d4f90bb0043fe3b7aa5653ad10c803a2202f83b2a0bcd398e2d803b0cf41a3c547e013c1a6be23dcd6cbd3d3837e13d500479bf3add49bf1e41f03dd318e33d5ee3bdbd9636173e1a80f93d23e2f43d1e8fac3da867f33d8b4f7abf63244bbf7e52013ea844d83ddb2acfbd838c203e12ff053e1fc7003e7087b23d8470ff3df8957abf5d764bbf9bbd073ee2e1d53d9075dbbdae06283e168b0c3e2523f13de319a93dc4b5ef3d626b77bf112d48bf7d34ff3dc4cfcd3dc87acbbd392f1f3e0053043efc25e23d13d7ba3d3a2fe13dc99676bff07147bf272bf03d67edda3d5919bcbdf668173e4b94f93de944ff3d4d8db33d3d2bfe3de8967bbf973c4cbf56d1063ed4fad83da190dabdbc49263e8d8e0b3e48eff03d08dca83da2b7ef3d398e76bf3b3c47bf920eff3dfaf9c93d4176cbbdbef91e3e4645043e4953ea3df3f5b33d820be93dda4978bf000449bf9b3bf83def13dc3dd0dec3bd15781b3e65cd003e7831f83db4e1ad3dd85ef63d4deb79bf37bf4abf8927033e3718d53d2ee6d2bdfd18233ed3f7073ee1dcf03d4b0ba43da373ef3d9bd677bf3bb748bf88ebfe3d6709d23de020cbbd8b241f3e2036043efacaf33d7903be3de2c1f13df4a17abf944b4bbf0cda003e26b2e33decc7cdbd61e6203ea49d053e68e3ce3def77d43d83e0cd3d2db578bff13e49bfa5c1dc3dd15dfa3dedbba9bdbd990d3ed512e63d0545ea3d11cbbf3d31fee83d58a779bfbcdf4abf6707f83d8b03e93dbd6ec4bd06471b3e4fb0003e071dc33dc47dd63d98cbc13d59ed77bf79ba48bfa2f8d03d2e2ef83d90a99dbd62dc073ea85dda3d3e2104bb7d7abbb901521bba9e3f5d3c6550593cf67457ba8497aabb6d57573c88fda43aaf84e3b9f76bae3b8726fcbbbac9d73bc492493b3287013b5484d43b2b2899bbf6bfbf3b97de0a3cc31ae03baf56623aca5409bc36dd1e3b04b21b3c192a1e3c91c4063bf9c751bb44b7213cca27803b90b61d3b970e6f3be149d3bb3783a53b10caf33bbe2ae03b7f509e3bfb10c8baf193de3b5db9dc3b2285a93bbf98db3b86a998ba0e70043c2cc36a3bbc2a493b22e6ff3b316cedbb44be893b8bd1203cd81c063caabc4f3c27bf9b3a1eb4653c1dda26bb306030bb7998623c35b51abc37a705bb65d4813ce42d693cde02a33b821ca43b9c0dd13bb4b8843b2236463be921c93bae992b3a5eacb83b21f6033c3801d53b1dde593cbf052dbb40176f3c528564bb23096abb022e6c3c6e93dcbbbfb21bbb134f863c90dc723c5549053ca29b22bcb3111e3c59833b3a314e083a5ea0193c077e10bcb08f093b9b81373c1e1e1f3c54a3083c7326bcb9b9b11f3ce12927ba7f2886bac6fb1a3c0825df3a878bfe3adf873a3c4dda203c1bb9d63ad32eaaba55834e3b6429323c8da61c3c806b3b3b90abb0bb6c99173cb0fa9b3b6a5b533bd6fa803a899ab2394221213b76e3f83b9958d23bca3d073b212e823aeb3a213c6cc56f3b1c411d3b13e227bb2c0d56bb324394bad082623c0454543cfb38baba0e927aba44a4543c83811b3a828086ba7ef1f8ba3f49d7ba3454beb9a359183ce4e9023cf57a37ba767b1c3b2f484f3c32ea8b3ae144bab9c5eb8f3b08c5b9ba9918be3b8386fe39dce20e39eeaeb23b81df0f3b86f5c13bebeeec3b774bbe3b409b44bbe2a6a2b985b2dbba5a61583cffc0513c2632f6ba676ad5bacfac643c23779938e194c9babac5f43ba7c853bc42c10f3c68de143b0ba61d3b8b600d3c20aab9bba1d9553bc9792e3c17a4133c19be433ca58a45bbb0b05a3c05b47ab9e929ccba2ee2573c62fdd5bb552b81ba28237b3c235f5e3c9e98743b5b58d5397442a83bb0bb523b58db453bef83a13b8414bdbb6d96e93bae14de3be5a2ac3b2a77113c3d9921bc04c0283ce9a6393b4f0ae03a9299253c319af2bb2ab7f03a97e9473cf4e82b3c287cf43b1c97bcb9aec3113c90f7893bffde343bcb070e3cbc789dba88fe503baeac2f3cfd17143c3d0aaa3b6d3b09ba0ee1d23b4c2a983bd19f993b064cce3b4b70d5bb234eb43bc56a0a3c3281db3bcbbee73db5e3a93d64e0e63dfaf378bf7d9449bfe2ecf53d685bcd3de0e2c2bdf6561a3ee257ff3d1a51de3da575c63d23cadc3d002b78bfa6c048bff336ec3d607fef3d4879b8bd50d5153e30c0f53d642be83d9eafb43dbac3e63d3c6578bfd9a049bf621ff63d6256d63d5a26c3bdf4471a3e306fff3d70d3ea3d822eb13d6a56e93dc0a478bf6e7649bf81aef83d253bd73d37fcc4bdaed91b3e5711013e9e91ee3d4b12be3d9d17ed3df6c67abf35d84bbf4385fc3da5fde23da566c8bd80f51d3e7a0e033e5203f13d8a8baf3d24dfef3d8f2379bfa8fd49bfc40dff3de99dd03d38c2cabd4afb1e3efe37043e9ef2f03d0a23b13d2d2aef3de60878bfda0149bfd5eafe3d51fcd13de847cbbdb3951f3ed843043eb636f23dbc7caa3dfbc9f03d2afe78bfbecc49bfe40c003e1958d93d7149ccbd91811f3e20c0043e696ccf3da11ee13da627ce3dd47178bf114249bf3368dd3d3707023ed3eea7bdec1e0e3e40d4e63df5f9ea3d7c49c83da99be93d5d5779bf1be849bfed19f93d0be7e83d1800c5bd9f211c3eee49013ebb34f23d30a1aa3dcc38f03dad1678bfacf348bf6803003ea4e9ce3d670bccbd49a61f3e64b6043ee31dd53d20dfec3de4add33d63cc7bbf7d5d4cbfa4e0e23d42d1033e313bafbd4ffb103e7c5bec3d829d053e98efb53db1bc043e6f3c7cbf90fa4cbf7baf0c3e88fdd43dcfb5e4bd69972c3e8070113e3fbbe83de825b83d5941e73d918c79bfb4784abfb096f63dd90adc3dff7ec2bd3cdc1a3eee01003e2031573b89a748bcc2b9963b41dd023c0ed7da3bc7e1903bd74e0fbc0a42f53b495fd63b923d9d3b8ae2d93b99aad7b9e31e033c62d6a43b0148873bf8ffff3b0df2cdb8fdf9833b1c00213cad15063c1090473b08dd29bba607913b71687f3b2b025c3b627c893b0a7286bb9537f63b9278c93bdaf2943bc536c23b43847cb8f24df43b68e82a3bedd4193b4afbeb3bfe4727baef8f9b3bc19f163c75e7f73b959deb3b8b3e8e3851cc0d3cdf93493bb01d303b53ce093cf04a71b9911e623b55aa293c20fc0f3c3848503c8128943a09b2663c4e8b2dbb80e86bbb5909643cd56ac3ba449a0dbbf40b813c0bf4693c272138ba195946bc7b1a293aa58c433c49ef403c2fc6fa392280f5bbc458423c54382c3b28da663a9be56f3bfba7073a90caa93b0041b23b3ccb943b73b49f3beeac5d3afe49dc3b0bfddb3b4717ab3bb207573bbec588bb76bd9a3ba068b73b92357f3b426e923b2dce9fbb6b3af43bb770d23b72239e3b2cb4a03b48ab25bc150cd23b7143de3a1b8a4d3add3dc83b16d3f5bbcd00bd3b567b043c7fdbd43bed37373b44eecdbb6a528b3b696e0f3c6f48f93b0c9f823be260dabbce5d013cc3debf3b19ad8e3bfc3e473b2cbf13bc6198943b71bd073c89a40e3c9d3d8b3b802f78bb030def3ba3e6c43b6033973b9bd50ebad06ef1bb5b0d933aa718443c1579393cd37e3e3a9e14363b1387383ce226193b2a51883a2da5143c86f00bbc45a62b3c757e8c3aff36d3b878fc263c969456bcbb12be3a6d5b453c74c22c3c001ac8b9a45c903b0a7e6c3af7ee143ca0a3113c979c393a0a4f88bb81e5363c1458443b36b49a3ab1bb82b90db7edbb6875a13a39bd4d3c1a0e383ca199783a1a7bb5bbc215383cb209393b3b0fad3a6c8d5f3c0c7195bb898d743ce8395fbb22ab86bb6902733c6a81dfbbc54f61bbbee28b3c48d3793c0c4ac53b3e389cbbd9eef73b9ec7b13b6985a43b1a4bef3b6d0822bc1fc7963b56b0133c9471fa3b649bf63bfa84e8bbc27f0e3cc1412d3b4f70ce3acff90e3ccf3758bb5b8d593be01d353ce3f3153cd5f9993a0a3857bb0d99243bdc9b353c68da3a3c78a61a3baa634dbbb12b193cdd43933b5f8b343b90b17b3b4b9b7b3b89a8ac3bb5c0453b46193f3b1dfea13b7974943bcac6ed3b00c9e03b00acad3ba0656d3c545830bbccdf803cd8226eb9bae485bafaa77e3cd4b001bc2cc261bb2256923cbe6d823cbe32e13df62cb23d09c9df3dca1177bf3ad747bf12f3ee3d0061d13d90f9bbbd529b163e4754f83d8fece93dd091ad3d13abe83dbd8476bf7dea47bfd1cff73d0fc3d53d5612c4bded801b3e70ae003ed3caeb3d7d58a53d4ec9ea3dc30c77bf0bf347bf48bcf93daab8c53d62ffc7bdcad31b3e6884013e62aff23dc829af3df8a0f03d360a78bf5b6349bf4731003eab36cf3d7d09ccbd5d48203ece06053ee962cb3d4781dd3d3548ca3d0dc378bf19c849bf2776d93df987fe3d4012a6bda1050c3e5fc3e23da13de93d6b3bb83d10ede73d9cc277bf17a648bfbb1bf73dafb6db3d4e2fc3bde51c1b3ea64c003e3b5ef63d4e14b83ddacbf43d29c97abfee384bbff127023e89f7d53d5738d0bd59d8213e3fde063e4f5be63d4d97b23dc945e53d9c9077bf1ed948bfcf4ef43d8795d63dfef5c0bd6b38193e03a1fd3df1c2f33dc7b3ad3d3a8bf23d799079bf03a64abf88de003e8ac0d53da075cebd35ff1f3ed789053e70acdd3d3747bb3d89eddc3d8b4877bf8e5c48bfd4eaeb3da35ee63d1a66b8bd841a153e9728f53d550ece3df42fe13dab60cc3d444e7abf19f44abff2c7db3d50aa043e99aaa7bd62580d3e5b21e53dc4c6ee3d6321bc3de327ed3dd4367abf28ed4abf209bfc3d4b86e33d42c7c8bda4de1d3ea107033ea46ef73d0cf6ae3d7816f63df6a378bfbf5949bfacc1023e37ffd53d1972d2bd8162223e5582073e72b2d63d3b42ca3d167bd53dc0a679bf5f684abf12abe43da529f23d9d72b1bde9cd113e961fee3d9eceea3a337e72baf8c6513b04f2023cd31d043c7a3f3f3b399987bbc21a193c98349d3bf142563bcd8d19baf485e0bb2b28453ac2f8273cb0c5283c8d6f183afd8a26bb32f6393c64652e3b58437a3a29d857bbfe8596bb885af3ba5edc843c0bd56f3c4b3c0cbb5b764e3b3998663c1e1f7fb9121be9ba87c7f93bab7eb0bb703b143c3ab6933bdb76643be601103c29668ebbe774463b13ff2e3c6ee5153cad19443b5099cab7f610943bc7c68f3b3a45ad3bf763883b7f1c1cbbe482fd3ba5a2c13b4c76933b26ebca3b6d7fb7bb1584f73b8e758e3b40cd5c3b9a39f13bfc2ba8bb1b199b3b6d43193c25e2fb3b5f130e3c8322d2ba487f243c46102d3b5fc13e3b6a29213ccb42cabb85142f3b3861433c72eb273cf6fb1d3ce159f0bb0432333cb8539d3a0582ab3924b1303ce785aabb2d35a13a7323553c8b89373c06da223b0c68d7bb0df0793bb0feda3b206cbf3bd5746e3b617ea93aae350d3ce5cebd3b1527843ba8b6f23bd19fbf39f6dc0f3c5105b93bb0d1b83beb830c3ca9dcc0bb3e88483b6a6b2c3c2037123cc9f8aa3bac712bbc6b57da3bdabb963bf35c953bfd61d03b28d1b0bb5aa7a03bcfb5013ccdf7d93b3de2c63b3d76c0ba1a95f63bbee3c43b76e1a83b1f52ee3b97e194bb6e77933bad53173c87a8fa3b2aa18737f8cce3bb20bab63af39c4c3c7353453cbeaf9a3acd892bbbafbb323c22db483b9f60c83afc5f503cbc6c8c3aa2e3673cda384fbb79b943bb6b9e633cd54083bab7c024bb481f813ce461693c8919463bb6e2c9bb9dde933b66b4193cf31a0f3c4ff1893ba03838bc7280ff3b25f6c53ba1fa953b8a4bdf397e6c8dbbc59eea3a1967283cd9861e3c8b59c43a981f803a5094263cdeea583b73b9f33aeaac1f3aea2ae33853d2013bad92ef3badfebf3b702ce53a70a4523b2bd5233c91f8633b9589063b85d0bf3b6e0b03bc9e94ef3bda01253b5b39083bb458e73b2388dbbbbf289c3b0ff4103cd73df33b858d393b53153a39eac78d3b4a09e93bf303b73b9a26813b9b17a4bbba26ef3bf0b3b33b4e6b8a3bbdfb4b3a6ea8a0bb05b3053b8a39ff3b6020f63bdd88f63a09b785bba018253c031c833bc5bb123bda37d53bb5ada53b2087fd3be3da243b08b8ec3ad843f93b4ae1b3bb210d973bbf361e3ce0b2023c73c74d3b8e62493b316a953ba0a8dd3af2859e3a6a4e8a3bcf69a7b9fde4e23b2038bf3b39be943b1b70f43d31fea33d0b85f23d320377bfe5e847bf414c013efb45cb3d4d03cdbdbbc9213e4035063ec3c9e83d3df2ae3dd8cde73d350179bfdedb49bf6f02f73df0dad73d9335c3bd91f41a3e1836003ee180e23dbd79bb3d3dcbe03d7a1878bfe40249bf6121f03d2b35e23de90bbebd1394173e5b81f93d17a1fb3db839b03df74bfa3d86e37bbf921e4dbfdbc2043e4e74d33d0e53d6bd4254243e3b79093e2a2ce63d8fb1b53dfb71e43d923d78bf530949bf8e21f43de508de3da297c0bdd1e3193e17a1fd3df591f33d7fe1b43df3bbf13d41ff79bf25bd4abf78cf003ec28ddc3dd240cdbdb2ac203ebf99053eb87ee93dd9c4ce3d2bc8e73da6707abf674e4bbf5124f73dd1a8ed3d10a2c3bdcba41b3ed45a003e9fa2d03d6bd6cf3da842cf3d78e177bf318f48bf9e77de3dd6daf63d6309aabdea7d0e3e36cae73d52eedf3d8b33c13d150ddf3d28ef77bffd0749bf89f7ed3ddd93e23d07aebabd73ee153e4d48f73d21fbf53d2750a53d1639f43daa4178bf76be48bf47f8013ecde2d03d3a49cfbdd1e4213ef2b8063e3cf7de3d016bdb3dc93fde3d86157cbfbcc54cbf5b01ed3d9023003ec7bfb9bd0674153e8b3af63d3db6e43d9257be3d613de33dc10979bf1de649bf9382f23d3c34e13d5209bfbdf0d7183ea9eefb3da662f13d5896bb3dfcc3ef3d28427abff3524bbfd559ff3db72de03de252ccbd2d2a1f3e5d64043e10adee3d6503b13d4d88ed3d1a5578bfc29149bfaba3fc3dc576d53d0f7cc9bd74e71d3e020b033e018ded3b34be51bb544e0d3c15bc39b97ad426babd32093caeb8a53ad98b5b3ba803243c058b0e3cd1b3bf39ad1cf3bb9fbeda3ad6e82a3ccbe3223cb4f9bf3af03905bc57a3293c5581633ba8a6f23a7fc4de3a453d403b977f4e3b029f163cbe6c0d3c161d3c3b40ef02ba01a7133c61639f3bd762543b274e8f3b88191ebce5d9bb3b6bc3e43ba827e63b45ecb23bd8edffbbc6e8cf3b3262f33b8d61be3bb047b93b0e18f2390919ea3b4acd4a3bd7e2183baecae23b89b4183b3d97ad3b0976113c3570ef3b6cd0ee3bb0c9dc3b48f90f3c8b02ed3a2cf8283b38240b3c6255f63b1165633b65872b3c31a8113cdab5ae3b043edebb53d8db3b5207183b172eca3ab3b1d33bfa71a3bace24b83ba43c093c17b5df3b3d74e73a2809883a4b864c3b5e40fe3b0d89f13b0e5d403b14d9e33bc5681c3c59b0a53b0ca25b3b2021b33b6598a3bb0dd7e33bf4cc353b7115323b8cdada3b0b89e6bbf0f4b13be8a70c3c74f7e63ba911e13b10ead7bb9af1053c595f023bfeab223bb05c033cb2f0b0bbbe787b3bf8cd273c39c60a3cc29be239b093813a5d53e33a24d61f3c8634113ccd7dc83ad78ae9baeff6253c6283633b2430f73a2137653b77c5fbbb3b97a43b8152b73b3926bd3b3e17993bca690bbc869fe23b1dadc93bc2a3a23bed8a573b868919bc3a80993b4065143ce720023c22d6913b81d1a5bb91eee33b53cccc3b3b0e9c3bbcd591bb41b28a3a35dc47bb82a53d3c80a9293cbdb355bbcf96423c44c57c3cb6d9a2ba65773dbb8cad19bbece888bb2c214eba2e00293c754a1b3cb22894bab9c0e8bbd24e583c5f36433a662c50ba576f033ce41bc93967db1b3cdde4573a263527386c1d183ccf4dadb979f6193b3fd0353c59eb1d3c86e62f3c1533ebbba9e0443c3f32663b8e38423be523433c16580fbc599e083a4c81683c43bf493c8a802b3b6d40c3bb913d863bb3c6233cc4aa0d3cd8577b3b41d0a1bbaffc003c628fc13b232a8a3bf987fc3bb5c02cbc21f8143cc6219d3b667e803ba0a4113c006753bc10493a3bbfdf333c7edf173c65602b3c280610bc3c31423ca35edb3a7030153ab78b3d3c33466bbbc3a01738937d5a3c6ca0433c2ecbcc3beaa6823a5664fc3b3335b33aa332153a47eaf43be2242dbbfc63983b1ff61c3c5766003c56eda73bf54b0ebcc183d63bb6664a3ba303f63a1487ce3bb3a4d9bb0231ae3b3c8d033c0f83d93b6e0de83d35f9b73d49b7e63d8fb178bf9d6c49bfaef4f53defe0da3dc1dfc1bd20641a3ea870ff3ddd7dee3d5d0da73dfad9ec3df5c376bf8f8347bf6bb3fc3dc206ca3da2f7c8bd25371e3e9f16033e184adf3dfc17ca3d41ecdd3d25ec79bf9eb54abfd61ced3d2cc2f23d96d1b9bd3521163e3180f63df646de3df01cc53d7672dd3dc89b7abf116a4bbf3d02ec3d38faea3dbb70b9bdeec5143e9b47f53d2f34e53d18c6b73d18cae33defea76bfd9f347bfc14bf33db628dc3d9d70bfbd5578193e50d8fc3d079cdf3d9e6ab63db3b8de3dbd0076bf281947bf0da4ed3daf58e23d510ab9bd0123163e4216f73d4a5bfe3d8477c33d657cfc3debb57bbfa6824cbf8226063e39ebe63daeacd9bde435263e18f60a3ef4e1b33d17bde83dda0fb23d9b1b76bf560147bf1982c13d566d093e4bcf8dbd9034003eece5ca3dabc8f33d176dc23debeaf13d92187bbf7f1b4cbfc1d6003e3e82e43d8d9ccdbda9b4203eaa91053e4c39ea3d688fc23d3099e83da9e679bfaef84abf5af9f73d88e7e83dda25c5bd65911b3e37b2003e15d7e63d9e9db03dd826e63de22a79bfbbf749bff617f53d5a82d83d4d5dc2bdbbb2193e6271fe3d8259d73d4ce9d83d04f6d53dc2e578bf69a649bffe62e53dd92ffd3d5d7eb1bd5f2b123e2cc7ee3d627e013e61cfad3d816e003e79307bbfc20c4cbf456b083e7207d63d88badbbda9be283ed2450d3e5d03e63de2f4ae3d1a6fe43db11276bf122a47bfe3f0f33d4806cd3d4a0abfbdc8ea193ed78cfd3d081c2c3ba4e8babb29ad843b22c2433ce1ea353c18157a3bcbafe3bb9f7e083c8425c23b1091893b9e27903b60f11ebc2ec0be3b7f5ea43bc341aa3b5dacb63bde1024bcbdd8cc3b65eaeb3b8fe5c03b7dfa2f3cf58d21bb941e463cbd2ac6baa2d33dbb20e3423cf5b522bcf72b21b9400d643c09ea483c04734c3c5fc1b1bba88d613cf56c7e3a709d6bb98316603c39182bbc1caeafba9ea9823ceb07673c8c3d803bf98404bc098eaf3b3b25133c86b8023c9b6da83bc3a7cdbb6e4dda3b39f4eb3b11c6b53b9368593a6320153b68ca0a3b0d51cb3b115eb83b9667003b7ab717bc7d271f3c0e19813b2480183b3d0914bb39043dbbf7bc6dbaac7d4a3cbbbc3e3c5d438cbae12eabbb4b535b3c9b08873a57ea33ba0f27c93b458ecd3aaf47f83b8bdc873bc03e4c3b9264ef3b7be611bbf97f923bfe74153c446cfb3b238fc63b186f26bc3deff43b8a1d893bb98f473bda40ed3bb8829ebb0e5c943bfd18183c5adcf93b0562063afd9eabb9a4e8f73a8545ed3b9a4de93b43b1dd3ac9fdc3ba5fb02a3c7179763b43ae073b48f2e03b317211bc9be0073c3565613b51c22b3b6bfe033c44e632bc446c773b3bdb223c3b380a3c5485283ccad388bbc610413c6d950cbac49bdfba44823c3c2ba181bbe457233a95805e3ccad4423c46bee839ba4694bc89a7fc3a767bff3bbc40063c420cd53a1bdf09bce80b253cba9d5a3b6437013b3be1cd3b17ac44bc647bf83b4eb48d3bf0e47d3be9e5f33b14d8c8bb642d953b60f81b3ccaf0ff3b5d4a113cd28c1fbcfd3e2b3cb16c973bde438a3b6024253c724663bc7170e83a133b443c48fb2a3c65f29dbac1e351bb815cc4390a67233c8e412b3cc2e20a382cb2fabaec32413c430bd03a06ecb339e5968339f63b9bbb0966e43a1f740b3c2e85063ccb9cb73aa3f83dbc7fec203cdb6b4a3b5a8ce33a74cf943b3f0b42bc815dc53b722fcb3b2184c23ba589b93b681f1cbcdb27d23bac20f63b6f5cc53b2480013a2d6424bc4852003baca10e3c5817053c08dbe13ac26455bb18672b3cf369723b11150a3be255073c700417bce4601c3ceb8a583a50cca539f2b51b3ca56e8dbb6e383f3b595b423c7261223cab427f3bd6b6f1bbacf8b13b78a9283bd5b4443b1724a83bb7b1ccbb6c7bd73be1f9e03b986cb23b2b2e7f3b410e07bc80c9ab3b6f558c3b304d5c3b2006a33b3e44043bab4fd93bd058e03b7267ae3b4422dc3dd8aec33d59e1da3d294778bf5b3f49bffff3e93dd3a0e33de538b7bd3980143eff63f33d0e7a003ea83eab3df5b9ff3daa947bbf53744cbf7a9c073e5072d23df5b1dbbde260273ee4580c3e1a5ee03dce55b33d6323df3d10bd76bfd09c47bffa81ee3d1e1edd3d1d91babd81c0163ef2f1f73db680f93d683bb83d5fcdf73d88657abfe4314bbfe4b1033e12c0db3d4081d3bdfd69233eb673083e53c4e53de6e0c13d8ca3e43d3acf78bf319549bf9dc5f33d83f5e43da180bfbdba1f193ea622fd3d8a44e73db037b63d010ce63df6ca77bf4ab648bfd73ff53d6225db3d1564c1bd3f111a3e1fb0fe3dbff7e73d2eabb83d0d1ee63da9f677bf2f7e48bf1ed6f53d07bfdc3d6300c2bd16b51a3e5c60ff3d603fef3d8c82ab3dc001ee3d5cca78bfad3849bf6551fd3d01a7d63d6248c9bd21221e3ec553033ee2c0cc3dcbdee03dd5e8cb3d3ce978bf1aa749bf3e87da3d9b63043e7896a7bdf1f70b3e2cc4e33d917df63dd68d9f3dff05f53de5a176bf1d9247bfb646023ee6c5c23de563d0bde22c223eed0c073e4884fd3d8f8bb03d02f4fb3d274a7bbfc6c24bbf46ba053e6bafe13d7343d7bdc164253eea7a0a3ec9f4e93d4f0eb83d6297e83df1f378bf03d249bf48d6f73dab38e63d9d44c5bdb33e1b3ea295003efa3df13deab6af3dfeccef3d9a8778bf19ac49bfee5cff3d76cdd63d8c1ccabd7a7f1f3e276d043ead12d13d6902d93d9be8cf3dab6579bf941e4abfbdebde3de995f73d7a91abbd1bc00e3e4556e83daaf2b93bf7c00fbce431e73bf1fe893bb82f783b45cedf3bc58d94bbd35aa23b543d113cbdceeb3b5b52863b33db24bcc829b83b1b88893b140f8b3b15c3ad3ba7770ebc58d9ce3bd759e63b9702b83b271d203c61c989bc4d2e383c344c053b4488ae3ab268333ca92c1ebc940ff33905fd4d3ca83d383ccd29af3a4f03b5b98f912a3bbc21dd3bbee9d33beccd233be8cf91bb5e7b1f3cc3519a3bb4553c3b0eb0dd3b597c05bc378b043c9958663b3fd0fe3a5c17013cfb24dabb3a04643b3509223c782d073cc13caebb8424493baa2382bb6de9643c65d5523ca7f189bb2dd41d3b7952833c21c50bbb6b737bbb4374e0b91b0b2abbb8d56e3a13271f3cfd4d163c5441383aaf2d3aba7d1d343cabcd333b08888f3a8e03fc3b31cc353b9051133c0b180f3a4c5233baed93103c23482f3b751e513b4b34323c59ee163ca1eb193ccecc7abbf6ab2f3cd1103cb9d701a1b8148c2c3c3e6084b95b5ac23a82444f3c13fb323ce7b55d3bb23991bab4919e3bf00cc23be853af3b2cb1953b394005bcdec7ed3b8af2d03bc777a13b7b48e53b8c759a390f140e3ceb9c26bb24b72bbb58d7063cf8f226baa3e8703b9b60203cb9d10b3c5682e939818d1aba161bf83acabe1d3c436c0b3c8038d33a020092bbdd572a3ca2d7653b4122023b3532033ba4e437ba56a5573b57130f3c274d0d3cda5a523b3abb863bad13163c40e9ae3bf8f86a3b5d90973b14d0b83a32f3c33b2111df3bb623e73b5bcbb93b3512debbc0add23b2357f03be01dc43b9a4abf3bc5af62bb29a2ed3bc16e5d3bb6d8d53a3e70e43bee6d613be809973bbd23123cf529f03b411eeab671d3453b9d2ea63a3fdbce3b6312e93b7c0e8d3a4fb996b91dd52f3cbf974b3b2088c03af8f3963b21af41393124cb3b2920843b58cf6b3b0670be3b4f72f0bb504bbb3bbe70f63b553dca3b3be771ba6f7541bb81b90c3a21163a3cfaac2d3c680eac3909e2c4bbdff4403c9a1e103b6081323afac8fc3b4336caba8323153c2fe4973b5883953bce64123cd93d12bb6aa1543beb1f383cd0c5193c0085f03bb72e4ebcfe35113cc41b653a3d395a39628a0b3c79fed9bb02a23b3bedca2a3c42cb113cb11bba3b9c6c5ebb23d7e13bbe0fca3bb39ac33b58d8e13b299d72bb00ffb13baf24183cea1bf03b02631d3c45731fbaa20f323c62c96a3ad641913ab8c12f3cc1a39abb0601723a143f523c3c19363cee99f13d15ffb83d38e9ef3d74c078bf3b9449bf18b1ff3de0d0da3db811ccbde6c61f3e1ea2043e9736d03dc0e1d63d2ecace3d63a378bfc6b149bf3d19de3dc66a003ed689a9bd108f0e3e698fe73d4eb0f43d1923b13d37bcf33d16bf7abf5aa54bbfd37a013e6e33d63de94ecfbdc6d5203ea527063e7a09fd3dccdab03d7c7dfb3d6f4f79bf05394abf7e9e053e4c4fd53d7dc9d6bd7bc8253e716d0a3e6917f73dc537b43d3b5cf53d14e979bfa8b34abf178c023e3ee8d93dd18cd1bdb668223e1752073e5676e73d5525ba3d3fe0e53d7d067abfa2d64abfe860f53d6102e33d692dc2bdb9261a3effd3fe3d5797e13d6010cb3daabedf3d481f78bfe5e248bfa475ef3d7a5bf53d8148bbbd9999173e9bfbf83d248aed3d8ecaad3d4180ec3d181779bf089a49bf6eb1fb3de08fd03dd50ec8bd4a181d3eb887023ebd73ed3dddecad3ddda9eb3d9df377bf979548bf9369fb3d3071d53d4208c8bd97961d3e107a023e9842e33da7a0b83d8b99e13da7b879bf1a444abf8e04f13d9d5de13d7306bebdbe33183ed276fa3dc598e23d75d6c63dbd6ee13d71ad7abf06754bbf3a8ff03db98bed3dc8f5bcbd288a173ebcf9f93d69b1df3d689bb93d18b3de3d404c77bf9f2048bf72afed3d85dddd3d8ff3b9bda2f7153e1bf3f63d929cea3dad3cb13de7f1e83dad9976bfca4d47bfc095f83d3881d63d9f2cc3bde2131c3e2f07013ee483e73d1751b63d9f32e73d0dda79bf05a84abf518bf53d843ed93d6cdfc3bd4743193eb7b5fe3d0b2f253b3a1642bc37bc793bf4718f3b2884963bded06f3b5c9992bbeef9013c7aaabf3ba44e853b170cc13bed7062bb1c89f53b1a5a213b48fe143b3781e83bc83c32bbf0b49a3bd0ac113c038bf33b62041e3c985decbb2ebc363c4fe734398342d53879eb313cb7bad9bb28a2093a05fc4d3c2e9d373cc959983b649cfabbf943c33bdd9baa3b0384a03bf74fbe3baace14bbc2b7c93bcdd2013c3289cb3bb144123cbda014bba25a293c59d60a3ac31e1c373583253c78ed0c3bfe2bf93ac9db453c9a9a2b3c765b053c106d4bbbb9051c3cb9401e3b68dc493b912e183cc215f9bb7459383b7f6e353c65971d3c41ea3b3ceac23ebbf529533c39a337bb5f0074bb2a1d503c83d71ebb55c897ba683b733c25a9563c8715013c27593d37506e123c4917ce3b15d6923b6712143cde2f7e392394583b26de403c3a0c1c3c0dc5c03bfca4cfbb2130ee3b2c756d3b3628563b7026e53b5b96bcbafba79f3b85de123cedd0f13b765ea5ba902bd1bbae7acd39a935423ce372333ce312f8371c7b44bc1272443c67acd93aabf4b53915e6e23b1beb4339889d063c77a7bb3bf456a23b24f5033cd205bbb846126a3ba3dc273c77f40a3c6352893aca8302bb57b21f3b492f203c3eb5093c444d103bf1ce5ebbdb71243cb90f873bf72d273b0a03133cf7f450baa9312b3c7d1681baa65884ba708a263c5a712cbb75eadf3ab35a433c5e3e2c3ca35d303add13c8bada310b3b40dd053c6b9afd3bfdcbf23af4e21ebbf9f7243cd8e2793bd366123b36b3793a0cc62c3bb5531b3b1df3263c6b6d173cd67b073b7dfc0b3b7132263c4c7f843b5339203bcaa8cf3b678c16ba30c0fe3bb2e66a3b0256f53ae415f83b1fc2a23b109a8b3bde081c3cb5af013c4ad0d03b9148bcba9063ff3be820ef3a0da6ea3ad461f83b3cb5a13a4d7a933b83971f3cefcd023c64d5fb3ba6fa03bc0817133c168f013bf56f8a3a508f0f3caa5834bc18ab4d3b6c28303c014f153ceb35bb3bdec5d9bb6a52e83bfba7b03b92e3903b04b4de3bd28b94baffcfa83ba3290f3c2ea5ea3b5c1bcc3beb6eacbbae39fa3b5c3e7f3b523c5e3bd04af23bb610d3b9b464873bfd97183c37b0fd3bbddf0b3c19841cbbf36b223c5dcd4e3b0d51193b43ca1e3cbb9737bb393d073bb376403cdeb6253cb28d373c9926233bf5cc4e3cc3e1e73a1dfdeb3aa3924b3ca3d3a3bbff4bc6b9ff686d3ce3e7513c2ef1d73de5f6da3daef9d53de37678bfe76549bf3ed8e53d15a6fc3dc493b0bd9b00133e9080ef3d2904f23d04d6ad3dc45af03d08e079bf15e34abfbe16003e8964d33de5dbcbbd5d4d203e2ddc043ee4c8e63d8afeb53d2601e53d96c775bf51c946bff7daf43dbb49d73daa2bc0bdca911a3e7b88fe3d1ac6ef3d7993a73dd7baee3d3af478bf5d444abfd8dafd3dc403d43da22acabdee611e3ea99f033e700bf03dece4b73d53a5ee3dafeb78bf1ddb49bf9721fe3d5327dd3da838cabd48de1e3e2adb033e6315f23d0c40ad3d6749f03dd63979bfb3f049bfb20c003e2d9fd43d0dfdcbbd374b203eb4e5043e3fdbe93da1abb13d03c9e83d235778bf304649bf8ac5f73d2565d33d8edcc3bd54dc1a3ec67f003e7084f13d4cf4aa3dd7e3ef3d968d76bf626047bf6c84ff3d0a63cd3d9aedcabd68c31f3e9188043e2813d33d8f76bb3dd400d23de76175bf47c745bf7318e13da75ede3d1cdbadbdb2c10f3e8468ea3d2d90d83d2d9cef3d0fbdd63d8fc87abfd1824bbf5a70e63dac5c0b3ebab5b2bdda11133ef501f03de8e0df3d5527c33df2bede3d2b7078bfda5549bf9bcded3dd5c6e03d26c7b9bde37b163ec554f73da0c6f43d0171b63daeb5f23d23667abfe3374bbf0a43013e8247dc3dc0f9cebd2154213eac14063e12adea3da7ceb33df959ea3d116e7abf3f914bbfe1fdf83da9dfdb3d083ac6bdfc481b3e291e013eabc0ee3dd6f5b53d669ded3d2b507abf8afe4abf97c4fc3d52fbda3d58f7c8bdda181e3eba28033e4221f63ba34469bba759133c255f96ba1b13e2ba0cd90e3cb361e9bbb2f5533bc8552e3c3b06153c6de4563b00639ebbed75993b90df673b61b01d3bb773943b1da97cbb0bc2e13bdbead63b418ba03b4d22873be036b8bb8dd9b03b8d2e053ccece003c2cdaac3b85b7fbbb5282d83bba31f13bd8a8b93bab8214ba9edf67bb42067f3aecd9103c94f9073c6158383a364af2ba54623b3c1d332c3b113a8c3abc78063c1e6db7ba66d11d3c04be6a3819bc74bab7871a3cc183a8bb0b89233b8d023f3cd012213c6b66a63b5c247dbb8375d23bf1f1963b67369b3bbff8ce3bda8dbbbb2b94c13b59d90b3c69ddda3b0b520e3c3ca211bc9cb1213cbe6c403bb0bf0f3b8fd4213cec1b5bbcb976263b72c9463cce28283cf181b13b1567e2bb78a0de3b0174073ceaf3e53b5566d83b279a2fbb0591b53b83be0c3c9bcee33b653ff43b7cb43b3b8696133cac16dc39146a11ba53ab0e3c26a8e23a79ac5b3b335f2b3cc823143ce830e93a1752223a6fd14d3bc242d13b28e6c83b9c513c3b561e173ba452143cd246a03b6594543bbd210f3c32e0d7bb823e253c68d151b958bb40bac4f5203cd01982bb0e2f0b3b04ce413c1a66273c2529573ba6b7b0ba79bc983b3d95093cb6d7fe3b83f6913b39a5b9bb868af13bc88ad33b3d899e3b2abcac3befd370bb2a5adf3b00c38e3b57c55d3bfa72d43b4c8e6fbbced7a53b5bbb053c7d91e03bef251a3c11b8e7bb3efb303c940048b98f7f75ba3a5b2d3c4021a7bb0f87ba3a84774b3c0e1b333c8e6ca83bb5f505bcbfd9d93b78e1fd3baec8dc3bbb8bd13b600ecabb4137b13b8a860b3c4617de3b1fe41f3bfb9122bc18ad763bf486133ccf150a3caa366c3be25081bb432d053ca790b93bf7ad823b697d3dbbd85f7abba600bcba46c12b3c74651a3cac0adfbadec2bfbacbca623cea3d06391b7bb5baab2f0a3c093fe4bb7461213cf9820e3be905ed3a4c161d3cd524193af44e243bc9d63a3cf2df223c03f1bb3b0ad068bc3a05ee3bbc1e233bb43f243bbe14e53b42b535bb3dcda13bc170153c514bf23bb415103b85d433bbbf16633b71852a3c85e7243c74735b3b3bc677bb5d190a3c2947b63b32fe753bacd1e53bde189cbb3e3a083c06ef8f3b0a29833be4bc053c2c51e3bba1fc753b00cd283c21360c3cc03baf3b465122bafc7edf3b6d5bbd3b79b7913be56dd73b70e73cba7fa0a93b98530d3c865de43bd013723fd8a884bff99f6e3fed6549bd8bc402bedede7e3fb91f9fbfb0af47bfbc059e3f1d06843fc40e743f24a785bf358a703fec290bbdf743e8bd997d803fdd2ba0bf071b49bfdf789f3f3a21853f38a0763ff46186bf6cef723f8b8a0bbd7125e9bdb6cd813f5181a0bfaf7f4bbf3444a13f087d863f38b6c4be6434e43e66e8bdbe95464e3b1d27273b0ae0ccbee5cb083fecb9c43e4209febe21f7d3be598fc3bea4a3e13e05ccbcbe18d91b3b12fcf93a6cc6cbbefb50073f16bdc23ee2e4fcbea4dad2be4aa2bfbe6692de3e912bb9be767c583b9cbf8b3b33f5c7beffc4053ffcccbf3efef8f8be2c0ecfbec649d2bef8dbf13ea969cbbe79d61a3b569a2d3b9a5cdabe5eb70f3fb3bad23edcde05bf3983e1be1998c2be8c9de13e140fbcbead77543b97542c3b6be5cabeff61073fa2a0c23e9e2efcbed407d2bec751c3be4650e13ec2c6bcbefa8b0a3b9089df3a0a9ccbbee83f073fd645c23ee2f1fcbe5dbdd2be1eb7c3be20c3e23ea6e8bcbec5ab453b4419213b2bc7cbbe8f02083fb354c33ef1fcfcbe59d7d2befe3f15404fd919c039b01240cabc37c1c8c614c1cb161d404a6d38c0ce7f05c0732c444081dd22405f5a91bd6463723f1596e6bda459813f653a683f5ac4d8bdaf7a903fa4460340f8ca18be4a14eabd3d2e14bf +\ No newline at end of file +diff --git a/gcc/opts-global.c b/gcc/opts-global.c +index 9ca3680a6..a89b88844 100644 +--- a/gcc/opts-global.c ++++ b/gcc/opts-global.c +@@ -325,7 +325,7 @@ decode_options (struct gcc_options *opts, struct gcc_options *opts_set, + void handle_lto_options(struct gcc_options *opts, char* compiler) + { + const char *model_infer_level = getenv ("AI_INFER_LEVEL"); +- if (model_infer_level) ++ if (BUILDING_GCC_MAJOR <= 8 && model_infer_level) + { + char *lan = strrchr (compiler, '/'); + if (lan != NULL) +diff --git a/gcc/params.def b/gcc/params.def +index 82c833b94..d6a7ae94b 100644 +--- a/gcc/params.def ++++ b/gcc/params.def +@@ -354,6 +354,12 @@ DEFPARAM(PARAM_MAX_UNSWITCH_LEVEL, + "The maximum number of unswitchings in a single loop.", + 3, 0, 0) + ++DEFPARAM(PARAM_MIN_LOOP_COND_SPLIT_PROB, ++ "min-loop-cond-split-prob", ++ "The minimum threshold for probability of semi-invariant condition " ++ "statement to trigger loop split.", ++ 30, 0, 100) ++ + /* The maximum number of insns in loop header duplicated by the copy loop + headers pass. */ + DEFPARAM(PARAM_MAX_LOOP_HEADER_INSNS, +diff --git a/gcc/passes.def b/gcc/passes.def +index 7d9645c0e..1a9cf767d 100644 +--- a/gcc/passes.def ++++ b/gcc/passes.def +@@ -238,6 +238,7 @@ along with GCC; see the file COPYING3. If not see + NEXT_PASS (pass_tree_ifcombine); + NEXT_PASS (pass_merge_phi); + NEXT_PASS (pass_phiopt); ++ NEXT_PASS (pass_loop_elim); + NEXT_PASS (pass_tail_recursion); + NEXT_PASS (pass_ch); + NEXT_PASS (pass_lower_complex); +diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h +index 72176e97d..6f0f023ff 100644 +--- a/gcc/tree-pass.h ++++ b/gcc/tree-pass.h +@@ -438,6 +438,7 @@ extern gimple_opt_pass *make_pass_warn_function_return (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_warn_function_noreturn (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_cselim (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_phiopt (gcc::context *ctxt); ++extern gimple_opt_pass *make_pass_loop_elim (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_forwprop (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_phiprop (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_array_widen_compare (gcc::context *ctxt); +diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c +index 7ec3cc158..914a01427 100644 +--- a/gcc/tree-ssa-dce.c ++++ b/gcc/tree-ssa-dce.c +@@ -246,6 +246,17 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive) + mark_stmt_necessary (stmt, true); + return; + } ++ /* IFN_GOACC_LOOP calls are necessary in that they are used to ++ represent parameter (i.e. step, bound) of a lowered OpenACC ++ partitioned loop. But this kind of partitioned loop might not ++ survive from aggressive loop removal for it has loop exit and ++ is assumed to be finite. Therefore, we need to explicitly mark ++ these calls. (An example is libgomp.oacc-c-c++-common/pr84955.c) */ ++ if (gimple_call_internal_p (stmt, IFN_GOACC_LOOP)) ++ { ++ mark_stmt_necessary (stmt, true); ++ return; ++ } + if (!gimple_call_lhs (stmt)) + return; + break; +diff --git a/gcc/tree-ssa-loop-elim.c b/gcc/tree-ssa-loop-elim.c +new file mode 100644 +index 000000000..8675d8be6 +--- /dev/null ++++ b/gcc/tree-ssa-loop-elim.c +@@ -0,0 +1,653 @@ ++/* Optimization of redundant loop elimination. ++ Copyright (C) 2025-2025 Free Software Foundation, Inc. ++ ++This file is part of GCC. ++ ++GCC is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 3, or (at your option) any ++later version. ++ ++GCC is distributed in the hope that it will be useful, but WITHOUT ++ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GCC; see the file COPYING3. If not see ++. */ ++ ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "backend.h" ++#include "insn-codes.h" ++#include "rtl.h" ++#include "tree.h" ++#include "gimple.h" ++#include "cfghooks.h" ++#include "tree-pass.h" ++#include "ssa.h" ++#include "optabs-tree.h" ++#include "insn-config.h" ++#include "gimple-pretty-print.h" ++#include "fold-const.h" ++#include "stor-layout.h" ++#include "cfganal.h" ++#include "gimplify.h" ++#include "gimple-iterator.h" ++#include "gimplify-me.h" ++#include "tree-cfg.h" ++#include "tree-dfa.h" ++#include "domwalk.h" ++#include "cfgloop.h" ++#include "tree-data-ref.h" ++#include "tree-scalar-evolution.h" ++#include "tree-inline.h" ++#include "params.h" ++ ++static gimple *hint_g01; ++static gimple *hint_g02; ++static gimple *hint_g1; ++static gimple *hint_g2; ++static gimple *hint_g3; ++ ++static bool check_uses (tree, hash_set *); ++ ++/* Check SSA_NAME is used in ++ if (SSA_NAME == 0) ++ ... ++ or ++ if (SSA_NAME != 0) ++ ... ++*/ ++static bool ++check_uses_cond (const_tree ssa_name, gimple *stmt, ++ hash_set *hset ATTRIBUTE_UNUSED) ++{ ++ tree_code code = gimple_cond_code (stmt); ++ if (code != EQ_EXPR && code != NE_EXPR) ++ { ++ return false; ++ } ++ ++ tree lhs = gimple_cond_lhs (stmt); ++ tree rhs = gimple_cond_rhs (stmt); ++ if ((lhs == ssa_name && integer_zerop (rhs)) ++ || (rhs == ssa_name && integer_zerop (lhs))) ++ { ++ return true; ++ } ++ ++ return false; ++} ++ ++/* Check SSA_NAME is used in ++ _tmp = SSA_NAME == 0; ++ or ++ _tmp = SSA_NAME != 0; ++ or ++ _tmp = SSA_NAME | _tmp2; ++*/ ++static bool ++check_uses_assign (const_tree ssa_name, gimple *stmt, hash_set *hset) ++{ ++ tree_code code = gimple_assign_rhs_code (stmt); ++ tree lhs, rhs1, rhs2; ++ ++ switch (code) ++ { ++ case EQ_EXPR: ++ case NE_EXPR: ++ rhs1 = gimple_assign_rhs1 (stmt); ++ rhs2 = gimple_assign_rhs2 (stmt); ++ if ((rhs1 == ssa_name && integer_zerop (rhs2)) ++ || (rhs2 == ssa_name && integer_zerop (rhs1))) ++ { ++ return true; ++ } ++ break; ++ ++ case BIT_IOR_EXPR: ++ lhs = gimple_assign_lhs (stmt); ++ if (hset->contains (lhs)) ++ { ++ return false; ++ } ++ /* We should check the use of _tmp further. */ ++ return check_uses (lhs, hset); ++ ++ default: ++ break; ++ } ++ return false; ++} ++ ++/* Check SSA_NAME is used in ++ # result = PHI ++*/ ++static bool ++check_uses_phi (const_tree ssa_name, gimple *stmt, hash_set *hset) ++{ ++ for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++) ++ { ++ tree arg = gimple_phi_arg_def (stmt, i); ++ if (!integer_zerop (arg) && arg != ssa_name) ++ { ++ return false; ++ } ++ } ++ ++ tree result = gimple_phi_result (stmt); ++ ++ /* It is used to avoid infinite recursion, ++ ++ if (cond) ++ goto ++ else ++ goto ++ ++ ++ # _tmp2 = PHI <0 (bb 1), _tmp3 (bb 3)> ++ {BODY} ++ if (cond) ++ goto ++ else ++ goto ++ ++ ++ # _tmp3 = PHI <0 (bb 1), _tmp2 (bb 2)> ++ {BODY} ++ if (cond) ++ goto ++ else ++ goto ++ ++ ++ ... ++ */ ++ if (hset->contains (result)) ++ { ++ return false; ++ } ++ ++ return check_uses (result, hset); ++} ++ ++/* Check the use of SSA_NAME, it should only be used in comparison ++ operation and PHI node. HSET is used to record the ssa_names ++ that have been already checked. */ ++static bool ++check_uses (tree ssa_name, hash_set *hset) ++{ ++ imm_use_iterator imm_iter; ++ use_operand_p use_p; ++ ++ if (TREE_CODE (ssa_name) != SSA_NAME) ++ { ++ return false; ++ } ++ ++ if (SSA_NAME_VAR (ssa_name) ++ && is_global_var (SSA_NAME_VAR (ssa_name))) ++ { ++ return false; ++ } ++ ++ hset->add (ssa_name); ++ ++ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, ssa_name) ++ { ++ gimple *stmt = USE_STMT (use_p); ++ ++ /* Ignore debug gimple statements. */ ++ if (is_gimple_debug (stmt)) ++ { ++ continue; ++ } ++ ++ switch (gimple_code (stmt)) ++ { ++ case GIMPLE_COND: ++ if (!check_uses_cond (ssa_name, stmt, hset)) ++ { ++ return false; ++ } ++ break; ++ ++ case GIMPLE_ASSIGN: ++ if (!check_uses_assign (ssa_name, stmt, hset)) ++ { ++ return false; ++ } ++ break; ++ ++ case GIMPLE_PHI: ++ if (!check_uses_phi (ssa_name, stmt, hset)) ++ { ++ return false; ++ } ++ break; ++ ++ default: ++ return false; ++ } ++ } ++ return true; ++} ++ ++static bool ++check_def_gimple (gimple *def1, gimple *def2, const_tree result) ++{ ++ /* def1 and def2 should be POINTER_PLUS_EXPR. */ ++ if (!is_gimple_assign (def1) || !is_gimple_assign (def2) ++ || gimple_assign_rhs_code (def1) != POINTER_PLUS_EXPR ++ || gimple_assign_rhs_code (def2) != POINTER_PLUS_EXPR) ++ { ++ return false; ++ } ++ ++ tree rhs12 = gimple_assign_rhs2 (def1); ++ ++ tree rhs21 = gimple_assign_rhs1 (def2); ++ tree rhs22 = gimple_assign_rhs2 (def2); ++ ++ if (rhs21 != result) ++ { ++ return false; ++ } ++ ++ /* We should have a positive pointer-plus constant to ensure ++ that the pointer value is continuously increasing. */ ++ if (TREE_CODE (rhs12) != INTEGER_CST || TREE_CODE (rhs22) != INTEGER_CST ++ || compare_tree_int (rhs12, 0) <= 0 || compare_tree_int (rhs22, 0) <= 0) ++ { ++ return false; ++ } ++ ++ return true; ++} ++ ++static bool ++check_loop_body (basic_block bb0, basic_block bb2, const_tree result) ++{ ++ gimple *g01 = first_stmt (bb0); ++ if (!g01 || !is_gimple_assign (g01) ++ || gimple_assign_rhs_code (g01) != MEM_REF ++ || TREE_OPERAND (gimple_assign_rhs1 (g01), 0) != result) ++ { ++ return false; ++ } ++ hint_g01 = g01; ++ ++ gimple *g02 = g01->next; ++ /* GIMPLE_COND would be the last gimple in a basic block, ++ and have no other side effects on RESULT. */ ++ if (!g02 || gimple_code (g02) != GIMPLE_COND) ++ { ++ return false; ++ } ++ hint_g02 = g02; ++ ++ if (first_stmt (bb2) != last_stmt (bb2)) ++ { ++ return false; ++ } ++ ++ return true; ++} ++ ++/* Pattern is like ++
++   arg1 = base (rhs11) + cst (rhs12); [def1]
++   goto 
++
++   
++   arg2 = result (rhs21) + cst (rhs22); [def2]
++
++   
++   # result = PHI 
++   _v = *result;  [g01]
++   if (_v == 0)   [g02]
++     goto 
++   else
++     goto 
++
++   
++   _1 = result - base;     [g1]
++   _2 = _1 /[ex] cst;      [g2]
++   _3 = (unsigned int) _2; [g3]
++   if (_3 == 0)
++   ...
++*/
++static bool
++check_bb_order (basic_block bb0, basic_block &bb1, basic_block &bb2,
++		gphi *phi_stmt, gimple *&output)
++{
++  /* Start check from PHI node in BB0.  */
++  if (gimple_phi_num_args (phi_stmt) != 2
++      || virtual_operand_p (gimple_phi_result (phi_stmt)))
++    {
++      return false;
++    }
++
++  tree result = gimple_phi_result (phi_stmt);
++  tree arg1 = gimple_phi_arg_def (phi_stmt, 0);
++  tree arg2 = gimple_phi_arg_def (phi_stmt, 1);
++
++  if (TREE_CODE (arg1) != SSA_NAME
++      || TREE_CODE (arg2) != SSA_NAME
++      || SSA_NAME_IS_DEFAULT_DEF (arg1)
++      || SSA_NAME_IS_DEFAULT_DEF (arg2))
++    {
++      return false;
++    }
++
++  gimple *def1 = SSA_NAME_DEF_STMT (arg1);
++  gimple *def2 = SSA_NAME_DEF_STMT (arg2);
++
++  /* Swap bb1 and bb2 if pattern is like
++     if (_v != 0)
++       goto 
++     else
++       goto 
++  */
++  if (gimple_bb (def2) == bb1 && EDGE_SUCC (bb1, 0)->dest == bb0)
++    {
++      std::swap (bb1, bb2);
++    }
++
++  /* prebb[def1] --> bb0 <-- bb2[def2] */
++  if (!gimple_bb (def1)
++      || EDGE_SUCC (gimple_bb (def1), 0)->dest != bb0
++      || gimple_bb (def2) != bb2 || EDGE_SUCC (bb2, 0)->dest != bb0)
++    {
++      return false;
++    }
++
++  /* Check whether define gimple meets the pattern requirements.  */
++  if (!check_def_gimple (def1, def2, result))
++    {
++      return false;
++    }
++
++  if (!check_loop_body (bb0, bb2, result))
++    {
++      return false;
++    }
++
++  output = def1;
++  return true;
++}
++
++/* Check pattern
++   
++   _1 = result - base;     [g1]
++   _2 = _1 /[ex] cst;      [g2]
++   _3 = (unsigned int) _2; [g3]
++   if (_3 == 0)
++   ...
++*/
++static bool
++check_gimple_order (basic_block bb1, const_tree base, const_tree cst,
++		    const_tree result, gimple *&output)
++{
++  gimple *g1 = first_stmt (bb1);
++  if (!g1 || !is_gimple_assign (g1)
++      || gimple_assign_rhs_code (g1) != POINTER_DIFF_EXPR
++      || gimple_assign_rhs1 (g1) != result
++      || gimple_assign_rhs2 (g1) != base)
++    {
++      return false;
++    }
++  hint_g1 = g1;
++
++  gimple *g2 = g1->next;
++  if (!g2 || !is_gimple_assign (g2)
++      || gimple_assign_rhs_code (g2) != EXACT_DIV_EXPR
++      || gimple_assign_lhs (g1) != gimple_assign_rhs1 (g2)
++      || TREE_CODE (gimple_assign_rhs2 (g2)) != INTEGER_CST)
++    {
++      return false;
++    }
++  hint_g2 = g2;
++
++  /* INTEGER_CST cst in gimple def1.  */
++  HOST_WIDE_INT num1 = TREE_INT_CST_LOW (cst);
++  /* INTEGER_CST cst in gimple g2.  */
++  HOST_WIDE_INT num2 = TREE_INT_CST_LOW (gimple_assign_rhs2 (g2));
++  /* _2 must be at least a positive number.  */
++  if (num2 == 0 || num1 / num2 <= 0)
++    {
++      return false;
++    }
++
++  gimple *g3 = g2->next;
++  if (!g3 || !is_gimple_assign (g3)
++      || gimple_assign_rhs_code (g3) != NOP_EXPR
++      || gimple_assign_lhs (g2) != gimple_assign_rhs1 (g3)
++      || TREE_CODE (gimple_assign_lhs (g3)) != SSA_NAME)
++    {
++      return false;
++    }
++  hint_g3 = g3;
++
++  /* _3 should only be used in comparison operation or PHI node.  */
++  hash_set *hset = new hash_set;
++  if (!check_uses (gimple_assign_lhs (g3), hset))
++    {
++      delete hset;
++      return false;
++    }
++  delete hset;
++
++  output = g3;
++  return true;
++}
++
++static int
++get_ssa_num_uses (tree ssa)
++{
++  imm_use_iterator imm_iter;
++  use_operand_p use_p;
++  int num = 0;
++
++  FOR_EACH_IMM_USE_FAST (use_p, imm_iter, ssa)
++    {
++      num++;
++    }
++
++  return num;
++}
++
++static bool
++do_phiopt_pattern (basic_block bb0, basic_block bb1, basic_block bb2)
++{
++  gphi_iterator gsi;
++
++  for (gsi = gsi_start_phis (bb0); !gsi_end_p (gsi); gsi_next (&gsi))
++    {
++      /* Initialize hint variables.  */
++      hint_g01 = NULL;
++      hint_g02 = NULL;
++      hint_g1 = NULL;
++      hint_g2 = NULL;
++      hint_g3 = NULL;
++
++      gphi *phi_stmt = gsi.phi ();
++      gimple *def1 = NULL;
++      tree base, cst, result;
++
++      if (!check_bb_order (bb0, bb1, bb2, phi_stmt, def1))
++	{
++	  continue;
++	}
++
++      base = gimple_assign_rhs1 (def1);
++      cst = gimple_assign_rhs2 (def1);
++      result = gimple_phi_result (phi_stmt);
++
++      gimple *stmt = NULL;
++      if (!check_gimple_order (bb1, base, cst, result, stmt))
++	{
++	  continue;
++	}
++
++      gcc_assert (stmt);
++
++      if (dump_file && (dump_flags & TDF_DETAILS))
++	{
++	  fprintf (dump_file, "PHIOPT pattern optimization (1) - Rewrite:\n");
++	  print_gimple_stmt (dump_file, stmt, 0);
++	  print_gimple_stmt (dump_file, hint_g01, 0);
++	  fprintf (dump_file, "to\n");
++	}
++
++      /* Rewrite statement
++	   _3 = (unsigned int) _2;
++	 to
++	   _3 = (unsigned int) 1;
++      */
++      tree type = TREE_TYPE (gimple_assign_rhs1 (stmt));
++      gimple_assign_set_rhs1 (stmt, build_int_cst (type, 1));
++      update_stmt (stmt);
++
++
++      if (get_ssa_num_uses (gimple_assign_lhs (hint_g1)) == 1
++	  /* We optimize the only use place above.  */
++	  && get_ssa_num_uses (gimple_assign_lhs (hint_g2)) == 0)
++	{
++	  /* Force to eliminate loop by setting condition to false.  */
++	  tree type_g01 = TREE_TYPE (gimple_assign_lhs (hint_g01));
++	  gimple_assign_set_rhs1 (hint_g01, build_int_cst (type_g01, 0));
++	  if (gimple_vuse (hint_g01))
++	    gimple_set_vuse (hint_g01, NULL_TREE);
++	  update_stmt (hint_g01);
++	}
++
++      if (dump_file && (dump_flags & TDF_DETAILS))
++	{
++	  print_gimple_stmt (dump_file, stmt, 0);
++	  print_gimple_stmt (dump_file, hint_g01, 0);
++	  fprintf (dump_file, "\n");
++	}
++
++      return true;
++    }
++  return false;
++}
++
++static unsigned int
++loop_elim_worker ()
++{
++  basic_block bb;
++  basic_block *bb_order;
++  unsigned n, i;
++
++  /* Search every basic block for COND_EXPR we may be able to optimize.
++
++     We walk the blocks in order that guarantees that a block with
++     a single predecessor is processed before the predecessor.
++     This ensures that we collapse inner ifs before visiting the
++     outer ones, and also that we do not try to visit a removed
++     block.  */
++  bb_order = single_pred_before_succ_order ();
++  n = n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS;
++
++  for (i = 0; i < n; i++)
++    {
++      gimple *cond_stmt;
++      basic_block bb1, bb2;
++      edge e1, e2;
++
++      bb = bb_order[i];
++
++      cond_stmt = last_stmt (bb);
++      /* Check to see if the last statement is a GIMPLE_COND.  */
++      if (!cond_stmt
++	  || gimple_code (cond_stmt) != GIMPLE_COND)
++	continue;
++
++      e1 = EDGE_SUCC (bb, 0);
++      bb1 = e1->dest;
++      e2 = EDGE_SUCC (bb, 1);
++      bb2 = e2->dest;
++
++      /* We cannot do the optimization on abnormal edges.  */
++      if ((e1->flags & EDGE_ABNORMAL) != 0
++	  || (e2->flags & EDGE_ABNORMAL) != 0)
++	continue;
++
++      /* If either bb1's succ or bb2 or bb2's succ is non NULL.  */
++      if (EDGE_COUNT (bb1->succs) == 0
++	  || bb2 == NULL
++	  || EDGE_COUNT (bb2->succs) == 0)
++	continue;
++
++      /* Find the bb which is the fall through to the other.  */
++      if (EDGE_SUCC (bb1, 0)->dest == bb2)
++	;
++      else if (EDGE_SUCC (bb2, 0)->dest == bb1)
++	{
++	  std::swap (bb1, bb2);
++	  std::swap (e1, e2);
++	}
++      else if (do_phiopt_pattern (bb, bb1, bb2))
++	continue;
++      else
++	continue;
++    }
++
++  free (bb_order);
++  return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals;
++}
++
++/* Redundant Loop Elimination Pass.  */
++
++namespace {
++
++const pass_data pass_data_tree_loop_elim =
++{
++  GIMPLE_PASS,
++  "loopelim",
++  OPTGROUP_LOOP,
++  TV_TREE_LOOP,
++  ( PROP_cfg | PROP_ssa ),
++  0,
++  0,
++  0,
++  0,
++};
++
++class pass_loop_elim : public gimple_opt_pass
++{
++public:
++  pass_loop_elim (gcc::context *ctxt)
++    : gimple_opt_pass (pass_data_tree_loop_elim, ctxt)
++  {}
++
++  /* opt_pass methods: */
++  virtual bool gate (function *);
++  virtual unsigned int execute (function *);
++
++}; // class pass_loop_elim
++
++bool
++pass_loop_elim::gate (function *)
++{
++  return (flag_loop_elim && optimize >= 2);
++}
++
++unsigned int
++pass_loop_elim::execute (function *)
++{
++  return loop_elim_worker ();
++}
++
++} // anon namespace
++
++gimple_opt_pass *
++make_pass_loop_elim (gcc::context *ctxt)
++{
++  return new pass_loop_elim (ctxt);
++}
+diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
+index 7a54c5f1e..e90b7c38c 100644
+--- a/gcc/tree-ssa-loop-niter.c
++++ b/gcc/tree-ssa-loop-niter.c
+@@ -2544,6 +2544,27 @@ finite_loop_p (struct loop *loop)
+ 		 loop->num);
+       return true;
+     }
++
++  if (flag_finite_loops)
++    {
++      unsigned i;
++      vec exits = get_loop_exit_edges (loop);
++      edge ex;
++
++      /* If the loop has a normal exit, we can assume it will terminate.  */
++      FOR_EACH_VEC_ELT (exits, i, ex)
++	if (!(ex->flags & (EDGE_EH | EDGE_ABNORMAL | EDGE_FAKE)))
++	  {
++	    exits.release ();
++	    if (dump_file)
++	      fprintf (dump_file, "Assume loop %i to be finite: it has an exit "
++		       "and -ffinite-loops is on.\n", loop->num);
++	    return true;
++	  }
++
++      exits.release ();
++    }
++
+   return false;
+ }
+ 
+diff --git a/gcc/tree-ssa-loop-split.c b/gcc/tree-ssa-loop-split.c
+index 238e0f580..e49d77478 100644
+--- a/gcc/tree-ssa-loop-split.c
++++ b/gcc/tree-ssa-loop-split.c
+@@ -32,7 +32,10 @@ along with GCC; see the file COPYING3.  If not see
+ #include "tree-ssa-loop.h"
+ #include "tree-ssa-loop-manip.h"
+ #include "tree-into-ssa.h"
++#include "tree-inline.h"
++#include "tree-cfgcleanup.h"
+ #include "cfgloop.h"
++#include "params.h"
+ #include "tree-scalar-evolution.h"
+ #include "gimple-iterator.h"
+ #include "gimple-pretty-print.h"
+@@ -40,7 +43,9 @@ along with GCC; see the file COPYING3.  If not see
+ #include "gimple-fold.h"
+ #include "gimplify-me.h"
+ 
+-/* This file implements loop splitting, i.e. transformation of loops like
++/* This file implements two kinds of loop splitting.
++
++   One transformation of loops like:
+ 
+    for (i = 0; i < 100; i++)
+      {
+@@ -487,8 +492,9 @@ compute_new_first_bound (gimple_seq *stmts, struct tree_niter_desc *niter,
+    single exit of LOOP.  */
+ 
+ static bool
+-split_loop (struct loop *loop1, struct tree_niter_desc *niter)
++split_loop (struct loop *loop1)
+ {
++  struct tree_niter_desc niter;
+   basic_block *bbs;
+   unsigned i;
+   bool changed = false;
+@@ -496,8 +502,28 @@ split_loop (struct loop *loop1, struct tree_niter_desc *niter)
+   tree border = NULL_TREE;
+   affine_iv iv;
+ 
++  if (!single_exit (loop1)
++      /* ??? We could handle non-empty latches when we split the latch edge
++	 (not the exit edge), and put the new exit condition in the new block.
++	 OTOH this executes some code unconditionally that might have been
++	 skipped by the original exit before.  */
++      || !empty_block_p (loop1->latch)
++      || !easy_exit_values (loop1)
++      || !number_of_iterations_exit (loop1, single_exit (loop1), &niter,
++				     false, true)
++      || niter.cmp == ERROR_MARK
++      /* We can't yet handle loops controlled by a != predicate.  */
++      || niter.cmp == NE_EXPR)
++    return false;
++
+   bbs = get_loop_body (loop1);
+ 
++  if (!can_copy_bbs_p (bbs, loop1->num_nodes))
++    {
++      free (bbs);
++      return false;
++    }
++
+   /* Find a splitting opportunity.  */
+   for (i = 0; i < loop1->num_nodes; i++)
+     if ((guard_iv = split_at_bb_p (loop1, bbs[i], &border, &iv)))
+@@ -505,8 +531,8 @@ split_loop (struct loop *loop1, struct tree_niter_desc *niter)
+ 	/* Handling opposite steps is not implemented yet.  Neither
+ 	   is handling different step sizes.  */
+ 	if ((tree_int_cst_sign_bit (iv.step)
+-	     != tree_int_cst_sign_bit (niter->control.step))
+-	    || !tree_int_cst_equal (iv.step, niter->control.step))
++	     != tree_int_cst_sign_bit (niter.control.step))
++	    || !tree_int_cst_equal (iv.step, niter.control.step))
+ 	  continue;
+ 
+ 	/* Find a loop PHI node that defines guard_iv directly,
+@@ -575,7 +601,7 @@ split_loop (struct loop *loop1, struct tree_niter_desc *niter)
+ 	   Compute the new bound for the guarding IV and patch the
+ 	   loop exit to use it instead of original IV and bound.  */
+ 	gimple_seq stmts = NULL;
+-	tree newend = compute_new_first_bound (&stmts, niter, border,
++	tree newend = compute_new_first_bound (&stmts, &niter, border,
+ 					       guard_code, guard_init);
+ 	if (stmts)
+ 	  gsi_insert_seq_on_edge_immediate (loop_preheader_edge (loop1),
+@@ -612,6 +638,956 @@ split_loop (struct loop *loop1, struct tree_niter_desc *niter)
+   return changed;
+ }
+ 
++/* Another transformation of loops like:
++
++   for (i = INIT (); CHECK (i); i = NEXT ())
++     {
++       if (expr (a_1, a_2, ..., a_n))  // expr is pure
++         a_j = ...;  // change at least one a_j
++       else
++         S;          // not change any a_j
++     }
++
++   into:
++
++   for (i = INIT (); CHECK (i); i = NEXT ())
++     {
++       if (expr (a_1, a_2, ..., a_n))
++         a_j = ...;
++       else
++         {
++           S;
++           i = NEXT ();
++           break;
++         }
++     }
++
++   for (; CHECK (i); i = NEXT ())
++     {
++       S;
++     }
++
++   */
++
++/* Data structure to hold temporary information during loop split upon
++   semi-invariant conditional statement.  */
++class split_info {
++public:
++  /* Array of all basic blocks in a loop, returned by get_loop_body().  */
++  basic_block *bbs;
++
++  /* All memory store/clobber statements in a loop.  */
++  auto_vec memory_stores;
++
++  /* Whether above memory stores vector has been filled.  */
++  int need_init;
++
++  /* Control dependencies of basic blocks in a loop.  */
++  auto_vec *> control_deps;
++
++  split_info () : bbs (NULL),  need_init (true) { }
++
++  ~split_info ()
++    {
++      if (bbs)
++	free (bbs);
++
++      for (unsigned i = 0; i < control_deps.length (); i++)
++	delete control_deps[i];
++    }
++};
++
++/* Find all statements with memory-write effect in LOOP, including memory
++   store and non-pure function call, and keep those in a vector.  This work
++   is only done one time, for the vector should be constant during analysis
++   stage of semi-invariant condition.  */
++
++static void
++find_vdef_in_loop (struct loop *loop)
++{
++  split_info *info = (split_info *) loop->aux;
++  gphi *vphi = get_virtual_phi (loop->header);
++
++  /* Indicate memory store vector has been filled.  */
++  info->need_init = false;
++
++  /* If loop contains memory operation, there must be a virtual PHI node in
++     loop header basic block.  */
++  if (vphi == NULL)
++    return;
++
++  /* All virtual SSA names inside the loop are connected to be a cyclic
++     graph via virtual PHI nodes.  The virtual PHI node in loop header just
++     links the first and the last virtual SSA names, by using the last as
++     PHI operand to define the first.  */
++  const edge latch = loop_latch_edge (loop);
++  const tree first = gimple_phi_result (vphi);
++  const tree last = PHI_ARG_DEF_FROM_EDGE (vphi, latch);
++
++  /* The virtual SSA cyclic graph might consist of only one SSA name, who
++     is defined by itself.
++
++       .MEM_1 = PHI <.MEM_2(loop entry edge), .MEM_1(latch edge)>
++
++     This means the loop contains only memory loads, so we can skip it.  */
++  if (first == last)
++    return;
++
++  auto_vec other_stores;
++  auto_vec worklist;
++  auto_bitmap visited;
++
++  bitmap_set_bit (visited, SSA_NAME_VERSION (first));
++  bitmap_set_bit (visited, SSA_NAME_VERSION (last));
++  worklist.safe_push (last);
++
++  do
++    {
++      tree vuse = worklist.pop ();
++      gimple *stmt = SSA_NAME_DEF_STMT (vuse);
++
++      /* We mark the first and last SSA names as visited at the beginning,
++	 and reversely start the process from the last SSA name towards the
++	 first, which ensures that this do-while will not touch SSA names
++	 defined outside the loop.  */
++      gcc_assert (gimple_bb (stmt)
++		  && flow_bb_inside_loop_p (loop, gimple_bb (stmt)));
++
++      if (gimple_code (stmt) == GIMPLE_PHI)
++	{
++	  gphi *phi = as_a  (stmt);
++
++	  for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
++	    {
++	      tree arg = gimple_phi_arg_def (stmt, i);
++
++	      if (bitmap_set_bit (visited, SSA_NAME_VERSION (arg)))
++		worklist.safe_push (arg);
++	    }
++	}
++      else
++	{
++	  tree prev = gimple_vuse (stmt);
++
++	  /* Non-pure call statement is conservatively assumed to impact all
++	     memory locations.  So place call statements ahead of other memory
++	     stores in the vector with an idea of of using them as shortcut
++	     terminators to memory alias analysis.  */
++	  if (gimple_code (stmt) == GIMPLE_CALL)
++	    info->memory_stores.safe_push (stmt);
++	  else
++	    other_stores.safe_push (stmt);
++
++	  if (bitmap_set_bit (visited, SSA_NAME_VERSION (prev)))
++	    worklist.safe_push (prev);
++	}
++    } while (!worklist.is_empty ());
++
++    info->memory_stores.safe_splice (other_stores);
++}
++
++/* Two basic blocks have equivalent control dependency if one dominates to
++   the other, and it is post-dominated by the latter.  Given a basic block
++   BB in LOOP, find farest equivalent dominating basic block.  For BB, there
++   is a constraint that BB does not post-dominate loop header of LOOP, this
++   means BB is control-dependent on at least one basic block in LOOP.  */
++
++static basic_block
++get_control_equiv_head_block (struct loop *loop, basic_block bb)
++{
++  while (!bb->aux)
++    {
++      basic_block dom_bb = get_immediate_dominator (CDI_DOMINATORS, bb);
++
++      gcc_checking_assert (dom_bb && flow_bb_inside_loop_p (loop, dom_bb));
++
++      if (!dominated_by_p (CDI_POST_DOMINATORS, dom_bb, bb))
++	break;
++
++      bb = dom_bb;
++    }
++  return bb;
++}
++
++/* Given a BB in LOOP, find out all basic blocks in LOOP that BB is control-
++   dependent on.  */
++
++static hash_set *
++find_control_dep_blocks (struct loop *loop, basic_block bb)
++{
++  /* BB has same control dependency as loop header, then it is not control-
++     dependent on any basic block in LOOP.  */
++  if (dominated_by_p (CDI_POST_DOMINATORS, loop->header, bb))
++    return NULL;
++
++  basic_block equiv_head = get_control_equiv_head_block (loop, bb);
++
++  if (equiv_head->aux)
++    {
++      /* There is a basic block containing control dependency equivalent
++	 to BB.  No need to recompute that, and also set this information
++	 to other equivalent basic blocks.  */
++      for (; bb != equiv_head;
++	   bb = get_immediate_dominator (CDI_DOMINATORS, bb))
++	bb->aux = equiv_head->aux;
++      return (hash_set *) equiv_head->aux;
++    }
++
++  /* A basic block X is control-dependent on another Y iff there exists
++     a path from X to Y, in which every basic block other than X and Y
++     is post-dominated by Y, but X is not post-dominated by Y.
++
++     According to this rule, traverse basic blocks in the loop backwards
++     starting from BB, if a basic block is post-dominated by BB, extend
++     current post-dominating path to this block, otherwise it is another
++     one that BB is control-dependent on.  */
++
++  auto_vec pdom_worklist;
++  hash_set pdom_visited;
++  hash_set *dep_bbs = new hash_set;
++
++  pdom_worklist.safe_push (equiv_head);
++
++  do
++    {
++      basic_block pdom_bb = pdom_worklist.pop ();
++      edge_iterator ei;
++      edge e;
++
++      if (pdom_visited.add (pdom_bb))
++	continue;
++
++      FOR_EACH_EDGE (e, ei, pdom_bb->preds)
++	{
++	  basic_block pred_bb = e->src;
++
++	  if (!dominated_by_p (CDI_POST_DOMINATORS, pred_bb, bb))
++	    {
++	      dep_bbs->add (pred_bb);
++	      continue;
++	    }
++
++	  pred_bb = get_control_equiv_head_block (loop, pred_bb);
++
++	  if (pdom_visited.contains (pred_bb))
++	    continue;
++
++	  if (!pred_bb->aux)
++	    {
++	      pdom_worklist.safe_push (pred_bb);
++	      continue;
++	    }
++
++	  /* If control dependency of basic block is available, fast extend
++	     post-dominating path using the information instead of advancing
++	     forward step-by-step.  */
++	  hash_set *pred_dep_bbs
++			= (hash_set *) pred_bb->aux;
++
++	  for (hash_set::iterator iter = pred_dep_bbs->begin ();
++	       iter != pred_dep_bbs->end (); ++iter)
++	    {
++	      basic_block pred_dep_bb = *iter;
++
++	      /* Basic blocks can either be in control dependency of BB, or
++		 must be post-dominated by BB, if so, extend the path from
++		 these basic blocks.  */
++	      if (!dominated_by_p (CDI_POST_DOMINATORS, pred_dep_bb, bb))
++		dep_bbs->add (pred_dep_bb);
++	      else if (!pdom_visited.contains (pred_dep_bb))
++		pdom_worklist.safe_push (pred_dep_bb);
++	    }
++	}
++    } while (!pdom_worklist.is_empty ());
++
++  /* Record computed control dependencies in loop so that we can reach them
++     when reclaiming resources.  */
++  ((split_info *) loop->aux)->control_deps.safe_push (dep_bbs);
++
++  /* Associate control dependence with related equivalent basic blocks.  */
++  for (equiv_head->aux = dep_bbs; bb != equiv_head;
++       bb = get_immediate_dominator (CDI_DOMINATORS, bb))
++    bb->aux = dep_bbs;
++
++  return dep_bbs;
++}
++
++/* Forward declaration */
++
++static bool
++stmt_semi_invariant_p_1 (struct loop *loop, gimple *stmt,
++			 const_basic_block skip_head,
++			 hash_map &stmt_stat);
++
++/* Given STMT, memory load or pure call statement, check whether it is impacted
++   by some memory store in LOOP, excluding trace starting from SKIP_HEAD (the
++   trace is composed of SKIP_HEAD and those basic block dominated by it, always
++   corresponds to one branch of a conditional statement).  If SKIP_HEAD is
++   NULL, all basic blocks of LOOP are checked.  */
++
++static bool
++vuse_semi_invariant_p (struct loop *loop, gimple *stmt,
++		       const_basic_block skip_head)
++{
++  split_info *info = (split_info *) loop->aux;
++  tree rhs = NULL_TREE;
++  ao_ref ref;
++  gimple *store;
++  unsigned i;
++
++  /* Collect memory store/clobber statements if haven't done that.  */
++  if (info->need_init)
++    find_vdef_in_loop (loop);
++
++  if (is_gimple_assign (stmt))
++    rhs = gimple_assign_rhs1 (stmt);
++
++  ao_ref_init (&ref, rhs);
++
++  FOR_EACH_VEC_ELT (info->memory_stores, i, store)
++    {
++      /* Skip basic blocks dominated by SKIP_HEAD, if non-NULL.  */
++      if (skip_head
++	  && dominated_by_p (CDI_DOMINATORS, gimple_bb (store), skip_head))
++	continue;
++
++      if (!ref.ref || stmt_may_clobber_ref_p_1 (store, &ref))
++	return false;
++    }
++
++  return true;
++}
++
++/* Suppose one condition branch, led by SKIP_HEAD, is not executed since
++   certain iteration of LOOP, check whether an SSA name (NAME) remains
++   unchanged in next iteration.  We call this characteristic semi-
++   invariantness.  SKIP_HEAD might be NULL, if so, nothing excluded, all basic
++   blocks and control flows in the loop will be considered.  Semi-invariant
++   state of checked statement is cached in hash map STMT_STAT to avoid
++   redundant computation in possible following re-check.  */
++
++static inline bool
++ssa_semi_invariant_p (struct loop *loop, tree name,
++		      const_basic_block skip_head,
++		      hash_map &stmt_stat)
++{
++  gimple *def = SSA_NAME_DEF_STMT (name);
++  const_basic_block def_bb = gimple_bb (def);
++
++  /* An SSA name defined outside loop is definitely semi-invariant.  */
++  if (!def_bb || !flow_bb_inside_loop_p (loop, def_bb))
++    return true;
++
++  return stmt_semi_invariant_p_1 (loop, def, skip_head, stmt_stat);
++}
++
++/* Check whether a loop iteration PHI node (LOOP_PHI) defines a value that is
++   semi-invariant in LOOP.  Basic blocks dominated by SKIP_HEAD (if non-NULL),
++   are excluded from LOOP.  */
++
++static bool
++loop_iter_phi_semi_invariant_p (struct loop *loop, gphi *loop_phi,
++				const_basic_block skip_head)
++{
++  const_edge latch = loop_latch_edge (loop);
++  tree name = gimple_phi_result (loop_phi);
++  tree from = PHI_ARG_DEF_FROM_EDGE (loop_phi, latch);
++
++  gcc_checking_assert (from);
++
++  /* Loop iteration PHI node locates in loop header, and it has two source
++     operands, one is an initial value coming from outside the loop, the other
++     is a value through latch of the loop, which is derived in last iteration,
++     we call the latter latch value.  From the PHI node to definition of latch
++     value, if excluding branch trace starting from SKIP_HEAD, except copy-
++     assignment or likewise, there is no other kind of value redefinition, SSA
++     name defined by the PHI node is semi-invariant.
++
++                         loop entry
++                              |     .--- latch ---.
++                              |     |             |
++                              v     v             |
++                  x_1 = PHI            |
++                           |                      |
++                           v                      |
++              .------- if (cond) -------.         |
++              |                         |         |
++              |                     [ SKIP ]      |
++              |                         |         |
++              |                     x_2 = ...     |
++              |                         |         |
++              '---- T ---->.<---- F ----'         |
++                           |                      |
++                           v                      |
++                  x_3 = PHI             |
++                           |                      |
++                           '----------------------'
++
++     Suppose in certain iteration, execution flow in above graph goes through
++     true branch, which means that one source value to define x_3 in false
++     branch (x_2) is skipped, x_3 only comes from x_1, and x_1 in next
++     iterations is defined by x_3, we know that x_1 will never changed if COND
++     always chooses true branch from then on.  */
++
++  while (from != name)
++    {
++      /* A new value comes from a CONSTANT.  */
++      if (TREE_CODE (from) != SSA_NAME)
++	return false;
++
++      gimple *stmt = SSA_NAME_DEF_STMT (from);
++      const_basic_block bb = gimple_bb (stmt);
++
++      /* A new value comes from outside the loop.  */
++      if (!bb || !flow_bb_inside_loop_p (loop, bb))
++	return false;
++
++      from = NULL_TREE;
++
++      if (gimple_code (stmt) == GIMPLE_PHI)
++	{
++	  gphi *phi = as_a  (stmt);
++
++	  for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
++	    {
++	      if (skip_head)
++		{
++		  const_edge e = gimple_phi_arg_edge (phi, i);
++
++		  /* Don't consider redefinitions in excluded basic blocks.  */
++		  if (dominated_by_p (CDI_DOMINATORS, e->src, skip_head))
++		    continue;
++		}
++
++	      tree arg = gimple_phi_arg_def (phi, i);
++
++	      if (!from)
++		from = arg;
++	      else if (!operand_equal_p (from, arg, 0))
++		/* There are more than one source operands that provide
++		   different values to the SSA name, it is variant.  */
++		return false;
++	    }
++	}
++      else if (gimple_code (stmt) == GIMPLE_ASSIGN)
++	{
++	  /* For simple value copy, check its rhs instead.  */
++	  if (gimple_assign_ssa_name_copy_p (stmt))
++	    from = gimple_assign_rhs1 (stmt);
++	}
++
++      /* Any other kind of definition is deemed to introduce a new value
++	 to the SSA name.  */
++      if (!from)
++	return false;
++    }
++  return true;
++}
++
++/* Check whether conditional predicates that BB is control-dependent on, are
++   semi-invariant in LOOP.  Basic blocks dominated by SKIP_HEAD (if non-NULL),
++   are excluded from LOOP.  Semi-invariant state of checked statement is cached
++   in hash map STMT_STAT.  */
++
++static bool
++control_dep_semi_invariant_p (struct loop *loop, basic_block bb,
++			      const_basic_block skip_head,
++			      hash_map &stmt_stat)
++{
++  hash_set *dep_bbs = find_control_dep_blocks (loop, bb);
++
++  if (!dep_bbs)
++    return true;
++
++  for (hash_set::iterator iter = dep_bbs->begin ();
++       iter != dep_bbs->end (); ++iter)
++    {
++      gimple *last = last_stmt (*iter);
++
++      if (!last)
++	return false;
++
++      /* Only check condition predicates.  */
++      if (gimple_code (last) != GIMPLE_COND
++	  && gimple_code (last) != GIMPLE_SWITCH)
++	return false;
++
++      if (!stmt_semi_invariant_p_1 (loop, last, skip_head, stmt_stat))
++	return false;
++    }
++
++  return true;
++}
++
++/* Check whether STMT is semi-invariant in LOOP, iff all its operands are
++   semi-invariant, consequently, all its defined values are semi-invariant.
++   Basic blocks dominated by SKIP_HEAD (if non-NULL), are excluded from LOOP.
++   Semi-invariant state of checked statement is cached in hash map
++   STMT_STAT.  */
++
++static bool
++stmt_semi_invariant_p_1 (struct loop *loop, gimple *stmt,
++			 const_basic_block skip_head,
++			 hash_map &stmt_stat)
++{
++  bool existed;
++  bool &invar = stmt_stat.get_or_insert (stmt, &existed);
++
++  if (existed)
++    return invar;
++
++  /* A statement might depend on itself, which is treated as variant.  So set
++     state of statement under check to be variant to ensure that.  */
++  invar = false;
++
++  if (gimple_code (stmt) == GIMPLE_PHI)
++    {
++      gphi *phi = as_a  (stmt);
++
++      if (gimple_bb (stmt) == loop->header)
++	{
++	  invar = loop_iter_phi_semi_invariant_p (loop, phi, skip_head);
++	  return invar;
++	}
++
++      /* For a loop PHI node that does not locate in loop header, it is semi-
++	 invariant only if two conditions are met.  The first is its source
++	 values are derived from CONSTANT (including loop-invariant value), or
++	 from SSA name defined by semi-invariant loop iteration PHI node.  The
++	 second is its source incoming edges are control-dependent on semi-
++	 invariant conditional predicates.  */
++      for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
++	{
++	  const_edge e = gimple_phi_arg_edge (phi, i);
++	  tree arg = gimple_phi_arg_def (phi, i);
++
++	  if (TREE_CODE (arg) == SSA_NAME)
++	    {
++	      if (!ssa_semi_invariant_p (loop, arg, skip_head, stmt_stat))
++		return false;
++
++	      /* If source value is defined in location from where the source
++		 edge comes in, no need to check control dependency again
++		 since this has been done in above SSA name check stage.  */
++	      if (e->src == gimple_bb (SSA_NAME_DEF_STMT (arg)))
++		continue;
++	    }
++
++	  if (!control_dep_semi_invariant_p (loop, e->src, skip_head,
++					     stmt_stat))
++	    return false;
++	}
++    }
++  else
++    {
++      ssa_op_iter iter;
++      tree use;
++
++      /* Volatile memory load or return of normal (non-const/non-pure) call
++	 should not be treated as constant in each iteration of loop.  */
++      if (gimple_has_side_effects (stmt))
++	return false;
++
++      /* Check if any memory store may kill memory load at this place.  */
++      if (gimple_vuse (stmt) && !vuse_semi_invariant_p (loop, stmt, skip_head))
++	return false;
++
++      /* Although operand of a statement might be SSA name, CONSTANT or
++	 VARDECL, here we only need to check SSA name operands.  This is
++	 because check on VARDECL operands, which involve memory loads,
++	 must have been done prior to invocation of this function in
++	 vuse_semi_invariant_p.  */
++      FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
++	if (!ssa_semi_invariant_p (loop, use, skip_head, stmt_stat))
++	  return false;
++    }
++
++  if (!control_dep_semi_invariant_p (loop, gimple_bb (stmt), skip_head,
++				     stmt_stat))
++    return false;
++
++  /* Here we SHOULD NOT use invar = true, since hash map might be changed due
++     to new insertion, and thus invar may point to invalid memory.  */
++  stmt_stat.put (stmt, true);
++  return true;
++}
++
++/* A helper function to check whether STMT is semi-invariant in LOOP.  Basic
++   blocks dominated by SKIP_HEAD (if non-NULL), are excluded from LOOP.  */
++
++static bool
++stmt_semi_invariant_p (struct loop *loop, gimple *stmt,
++		       const_basic_block skip_head)
++{
++  hash_map stmt_stat;
++  return stmt_semi_invariant_p_1 (loop, stmt, skip_head, stmt_stat);
++}
++
++/* Determine when conditional statement never transfers execution to one of its
++   branch, whether we can remove the branch's leading basic block (BRANCH_BB)
++   and those basic blocks dominated by BRANCH_BB.  */
++
++static bool
++branch_removable_p (basic_block branch_bb)
++{
++  edge_iterator ei;
++  edge e;
++
++  if (single_pred_p (branch_bb))
++    return true;
++
++  FOR_EACH_EDGE (e, ei, branch_bb->preds)
++    {
++      if (dominated_by_p (CDI_DOMINATORS, e->src, branch_bb))
++	continue;
++
++      if (dominated_by_p (CDI_DOMINATORS, branch_bb, e->src))
++	continue;
++
++       /* The branch can be reached from opposite branch, or from some
++	  statement not dominated by the conditional statement.  */
++      return false;
++    }
++
++  return true;
++}
++
++/* Find out which branch of a conditional statement (COND) is invariant in the
++   execution context of LOOP.  That is: once the branch is selected in certain
++   iteration of the loop, any operand that contributes to computation of the
++   conditional statement remains unchanged in all following iterations.  */
++
++static edge
++get_cond_invariant_branch (struct loop *loop, gcond *cond)
++{
++  basic_block cond_bb = gimple_bb (cond);
++  basic_block targ_bb[2];
++  bool invar[2];
++  unsigned invar_checks = 0;
++
++  for (unsigned i = 0; i < 2; i++)
++    {
++      targ_bb[i] = EDGE_SUCC (cond_bb, i)->dest;
++
++      /* One branch directs to loop exit, no need to perform loop split upon
++	 this conditional statement.  Firstly, it is trivial if the exit branch
++	 is semi-invariant, for the statement is just to break loop.  Secondly,
++	 if the opposite branch is semi-invariant, it means that the statement
++	 is real loop-invariant, which is covered by loop unswitch.  */
++      if (!flow_bb_inside_loop_p (loop, targ_bb[i]))
++	return NULL;
++    }
++
++  for (unsigned i = 0; i < 2; i++)
++    {
++      invar[!i] = false;
++
++      if (!branch_removable_p (targ_bb[i]))
++	continue;
++
++      /* Given a semi-invariant branch, if its opposite branch dominates
++	 loop latch, it and its following trace will only be executed in
++	 final iteration of loop, namely it is not part of repeated body
++	 of the loop.  Similar to the above case that the branch is loop
++	 exit, no need to split loop.  */
++      if (dominated_by_p (CDI_DOMINATORS, loop->latch, targ_bb[i]))
++	continue;
++
++      invar[!i] = stmt_semi_invariant_p (loop, cond, targ_bb[i]);
++      invar_checks++;
++    }
++
++  /* With both branches being invariant (handled by loop unswitch) or
++     variant is not what we want.  */
++  if (invar[0] ^ !invar[1])
++    return NULL;
++
++  /* Found a real loop-invariant condition, do nothing.  */
++  if (invar_checks < 2 && stmt_semi_invariant_p (loop, cond, NULL))
++    return NULL;
++
++  return EDGE_SUCC (cond_bb, invar[0] ? 0 : 1);
++}
++
++/* Calculate increased code size measured by estimated insn number if applying
++   loop split upon certain branch (BRANCH_EDGE) of a conditional statement.  */
++
++static int
++compute_added_num_insns (struct loop *loop, const_edge branch_edge)
++{
++  basic_block cond_bb = branch_edge->src;
++  unsigned branch = EDGE_SUCC (cond_bb, 1) == branch_edge;
++  basic_block opposite_bb = EDGE_SUCC (cond_bb, !branch)->dest;
++  basic_block *bbs = ((split_info *) loop->aux)->bbs;
++  int num = 0;
++
++  for (unsigned i = 0; i < loop->num_nodes; i++)
++    {
++      /* Do no count basic blocks only in opposite branch.  */
++      if (dominated_by_p (CDI_DOMINATORS, bbs[i], opposite_bb))
++	continue;
++
++      num += estimate_num_insns_seq (bb_seq (bbs[i]), &eni_size_weights);
++    }
++
++  /* It is unnecessary to evaluate expression of the conditional statement
++     in new loop that contains only invariant branch.  This expression should
++     be constant value (either true or false).  Exclude code size of insns
++     that contribute to computation of the expression.  */
++
++  auto_vec worklist;
++  hash_set removed;
++  gimple *stmt = last_stmt (cond_bb);
++
++  worklist.safe_push (stmt);
++  removed.add (stmt);
++  num -= estimate_num_insns (stmt, &eni_size_weights);
++
++  do
++    {
++      ssa_op_iter opnd_iter;
++      use_operand_p opnd_p;
++
++      stmt = worklist.pop ();
++      FOR_EACH_PHI_OR_STMT_USE (opnd_p, stmt, opnd_iter, SSA_OP_USE)
++	{
++	  tree opnd = USE_FROM_PTR (opnd_p);
++
++	  if (TREE_CODE (opnd) != SSA_NAME || SSA_NAME_IS_DEFAULT_DEF (opnd))
++	    continue;
++
++	  gimple *opnd_stmt = SSA_NAME_DEF_STMT (opnd);
++	  use_operand_p use_p;
++	  imm_use_iterator use_iter;
++
++	  if (removed.contains (opnd_stmt)
++	      || !flow_bb_inside_loop_p (loop, gimple_bb (opnd_stmt)))
++	    continue;
++
++	  FOR_EACH_IMM_USE_FAST (use_p, use_iter, opnd)
++	    {
++	      gimple *use_stmt = USE_STMT (use_p);
++
++	      if (!is_gimple_debug (use_stmt) && !removed.contains (use_stmt))
++		{
++		  opnd_stmt = NULL;
++		  break;
++		}
++	    }
++
++	  if (opnd_stmt)
++	    {
++	      worklist.safe_push (opnd_stmt);
++	      removed.add (opnd_stmt);
++	      num -= estimate_num_insns (opnd_stmt, &eni_size_weights);
++	    }
++	}
++    } while (!worklist.is_empty ());
++
++  gcc_assert (num >= 0);
++  return num;
++}
++
++/* Find out loop-invariant branch of a conditional statement (COND) if it has,
++   and check whether it is eligible and profitable to perform loop split upon
++   this branch in LOOP.  */
++
++static edge
++get_cond_branch_to_split_loop (struct loop *loop, gcond *cond)
++{
++  edge invar_branch = get_cond_invariant_branch (loop, cond);
++  if (!invar_branch)
++    return NULL;
++
++  /* When accurate profile information is available, and execution
++     frequency of the branch is too low, just let it go.  */
++  profile_probability prob = invar_branch->probability;
++  if (prob.reliable_p ())
++    {
++      int thres = PARAM_VALUE (PARAM_MIN_LOOP_COND_SPLIT_PROB);
++
++      if (prob < profile_probability::always ().apply_scale (thres, 100))
++	return NULL;
++    }
++
++  /* Add a threshold for increased code size to disable loop split.  */
++  if (compute_added_num_insns (loop, invar_branch)
++      > PARAM_VALUE (PARAM_MAX_PEELED_INSNS))
++    return NULL;
++
++  return invar_branch;
++}
++
++/* Given a loop (LOOP1) with a loop-invariant branch (INVAR_BRANCH) of some
++   conditional statement, perform loop split transformation illustrated
++   as the following graph.
++
++               .-------T------ if (true) ------F------.
++               |                    .---------------. |
++               |                    |               | |
++               v                    |               v v
++          pre-header                |            pre-header
++               | .------------.     |                 | .------------.
++               | |            |     |                 | |            |
++               | v            |     |                 | v            |
++             header           |     |               header           |
++               |              |     |                 |              |
++      .--- if (cond) ---.     |     |        .--- if (true) ---.     |
++      |                 |     |     |        |                 |     |
++  invariant             |     |     |    invariant             |     |
++      |                 |     |     |        |                 |     |
++      '---T--->.<---F---'     |     |        '---T--->.<---F---'     |
++               |              |    /                  |              |
++             stmts            |   /                 stmts            |
++               |              F  T                    |              |
++              / \             | /                    / \             |
++     .-------*   *      [ if (cond) ]       .-------*   *            |
++     |           |            |             |           |            |
++     |         latch          |             |         latch          |
++     |           |            |             |           |            |
++     |           '------------'             |           '------------'
++     '------------------------. .-----------'
++             loop1            | |                   loop2
++                              v v
++                             exits
++
++   In the graph, loop1 represents the part derived from original one, and
++   loop2 is duplicated using loop_version (), which corresponds to the part
++   of original one being splitted out.  In original latch edge of loop1, we
++   insert a new conditional statement duplicated from the semi-invariant cond,
++   and one of its branch goes back to loop1 header as a latch edge, and the
++   other branch goes to loop2 pre-header as an entry edge.  And also in loop2,
++   we abandon the variant branch of the conditional statement by setting a
++   constant bool condition, based on which branch is semi-invariant.  */
++
++static bool
++do_split_loop_on_cond (struct loop *loop1, edge invar_branch)
++{
++  basic_block cond_bb = invar_branch->src;
++  bool true_invar = !!(invar_branch->flags & EDGE_TRUE_VALUE);
++  gcond *cond = as_a  (last_stmt (cond_bb));
++
++  gcc_assert (cond_bb->loop_father == loop1);
++
++  if (dump_enabled_p ())
++    dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, gimple_location (cond),
++		     "loop split on semi-invariant condition at %s branch\n",
++		     true_invar ? "true" : "false");
++
++  initialize_original_copy_tables ();
++
++  struct loop *loop2 = loop_version (loop1, boolean_true_node, NULL,
++				     profile_probability::always (),
++				     profile_probability::never (),
++				     profile_probability::always (),
++				     profile_probability::always (),
++				     true);
++  if (!loop2)
++    {
++      free_original_copy_tables ();
++      return false;
++    }
++
++  basic_block cond_bb_copy = get_bb_copy (cond_bb);
++  gcond *cond_copy = as_a (last_stmt (cond_bb_copy));
++
++  /* Replace the condition in loop2 with a bool constant to let PassManager
++     remove the variant branch after current pass completes.  */
++  if (true_invar)
++    gimple_cond_make_true (cond_copy);
++  else
++    gimple_cond_make_false (cond_copy);
++
++  update_stmt (cond_copy);
++
++  /* Insert a new conditional statement on latch edge of loop1, its condition
++     is duplicated from the semi-invariant.  This statement acts as a switch
++     to transfer execution from loop1 to loop2, when loop1 enters into
++     invariant state.  */
++  basic_block latch_bb = split_edge (loop_latch_edge (loop1));
++  basic_block break_bb = split_edge (single_pred_edge (latch_bb));
++  gimple *break_cond = gimple_build_cond (gimple_cond_code(cond),
++					  gimple_cond_lhs (cond),
++					  gimple_cond_rhs (cond),
++					  NULL_TREE, NULL_TREE);
++
++  gimple_stmt_iterator gsi = gsi_last_bb (break_bb);
++  gsi_insert_after (&gsi, break_cond, GSI_NEW_STMT);
++
++  edge to_loop1 = single_succ_edge (break_bb);
++  edge to_loop2 = make_edge (break_bb, loop_preheader_edge (loop2)->src, 0);
++
++  to_loop1->flags &= ~EDGE_FALLTHRU;
++  to_loop1->flags |= true_invar ? EDGE_FALSE_VALUE : EDGE_TRUE_VALUE;
++  to_loop2->flags |= true_invar ? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE;
++
++  update_ssa (TODO_update_ssa);
++
++  /* Due to introduction of a control flow edge from loop1 latch to loop2
++     pre-header, we should update PHIs in loop2 to reflect this connection
++     between loop1 and loop2.  */
++  connect_loop_phis (loop1, loop2, to_loop2);
++
++  free_original_copy_tables ();
++
++  rewrite_into_loop_closed_ssa_1 (NULL, 0, SSA_OP_USE, loop1);
++
++  return true;
++}
++
++/* Traverse all conditional statements in LOOP, to find out a good candidate
++   upon which we can do loop split.  */
++
++static bool
++split_loop_on_cond (struct loop *loop)
++{
++  split_info *info = new split_info ();
++  basic_block *bbs = info->bbs = get_loop_body (loop);
++  bool do_split = false;
++
++  /* Allocate an area to keep temporary info, and associate its address
++     with loop aux field.  */
++  loop->aux = info;
++
++  for (unsigned i = 0; i < loop->num_nodes; i++)
++    bbs[i]->aux = NULL;
++
++  for (unsigned i = 0; i < loop->num_nodes; i++)
++    {
++      basic_block bb = bbs[i];
++
++      /* We only consider conditional statement, which be executed at most once
++	 in each iteration of the loop.  So skip statements in inner loops.  */
++      if ((bb->loop_father != loop) || (bb->flags & BB_IRREDUCIBLE_LOOP))
++	continue;
++
++      /* Actually this check is not a must constraint.  With it, we can ensure
++	 conditional statement will always be executed in each iteration.  */
++      if (!dominated_by_p (CDI_DOMINATORS, loop->latch, bb))
++	continue;
++
++      gimple *last = last_stmt (bb);
++
++      if (!last || gimple_code (last) != GIMPLE_COND)
++	continue;
++
++      gcond *cond = as_a  (last);
++      edge branch_edge = get_cond_branch_to_split_loop (loop, cond);
++
++      if (branch_edge)
++	{
++	  do_split_loop_on_cond (loop, branch_edge);
++	  do_split = true;
++	  break;
++	}
++    }
++
++  delete info;
++  loop->aux = NULL;
++
++  return do_split;
++}
++
+ /* Main entry point.  Perform loop splitting on all suitable loops.  */
+ 
+ static unsigned int
+@@ -621,13 +1597,15 @@ tree_ssa_split_loops (void)
+   bool changed = false;
+ 
+   gcc_assert (scev_initialized_p ());
++
++  calculate_dominance_info (CDI_POST_DOMINATORS);
++
+   FOR_EACH_LOOP (loop, LI_INCLUDE_ROOT)
+     loop->aux = NULL;
+ 
+   /* Go through all loops starting from innermost.  */
+   FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+     {
+-      struct tree_niter_desc niter;
+       if (loop->aux)
+ 	{
+ 	  /* If any of our inner loops was split, don't split us,
+@@ -636,35 +1614,24 @@ tree_ssa_split_loops (void)
+ 	  continue;
+ 	}
+ 
+-      if (single_exit (loop)
+-	  /* ??? We could handle non-empty latches when we split
+-	     the latch edge (not the exit edge), and put the new
+-	     exit condition in the new block.  OTOH this executes some
+-	     code unconditionally that might have been skipped by the
+-	     original exit before.  */
+-	  && empty_block_p (loop->latch)
+-	  && !optimize_loop_for_size_p (loop)
+-	  && easy_exit_values (loop)
+-	  && number_of_iterations_exit (loop, single_exit (loop), &niter,
+-					false, true)
+-	  && niter.cmp != ERROR_MARK
+-	  /* We can't yet handle loops controlled by a != predicate.  */
+-	  && niter.cmp != NE_EXPR
+-	  && can_duplicate_loop_p (loop))
++      if (optimize_loop_for_size_p (loop))
++	continue;
++
++      if (split_loop (loop) || split_loop_on_cond (loop))
+ 	{
+-	  if (split_loop (loop, &niter))
+-	    {
+-	      /* Mark our containing loop as having had some split inner
+-	         loops.  */
+-	      loop_outer (loop)->aux = loop;
+-	      changed = true;
+-	    }
++	  /* Mark our containing loop as having had some split inner loops.  */
++	  loop_outer (loop)->aux = loop;
++	  changed = true;
+ 	}
+     }
+ 
+   FOR_EACH_LOOP (loop, LI_INCLUDE_ROOT)
+     loop->aux = NULL;
+ 
++  clear_aux_for_blocks ();
++
++  free_dominance_info (CDI_POST_DOMINATORS);
++
+   if (changed)
+     return TODO_cleanup_cfg;
+   return 0;
diff --git a/SPECS/gcc.spec b/SPECS/gcc.spec
index 19eae0955641c997b89fda9d1954e17a04bd0267..1c402dce6ee57812b22f4d32cd8f89219e1b22c3 100644
--- a/SPECS/gcc.spec
+++ b/SPECS/gcc.spec
@@ -105,7 +105,7 @@
 Summary: Various compilers (C, C++, Objective-C, ...)
 Name: gcc
 Version: %{gcc_version}
-Release: %{gcc_release}%{?dist}.ap.1
+Release: %{gcc_release}%{?dist}.ap.2
 # libgcc, libgfortran, libgomp, libstdc++ and crtstuff have
 # GCC Runtime Exception.
 License: GPLv3+ and GPLv3+ with exceptions and GPLv2+ with exceptions and LGPLv2+ and BSD
@@ -336,6 +336,7 @@ Patch5010: gcc8-support-for-hip12.patch
 Patch5011: gcc8-fix-build-error.patch
 Patch5012: gcc8-Improve-non-loop-disambiguation.patch
 Patch5013: gcc8-fix-model-param-reading-bug.patch
+Patch5014: gcc8-loop-opt.patch
 
 # On ARM EABI systems, we do want -gnueabi to be part of the
 # target triple.
@@ -978,6 +979,7 @@ so that there cannot be any synchronization problems.
 %patch5011 -p1 -b .fix-build-error~
 %patch5012 -p1 -b .Improve-non-loop~
 %patch5013 -p1 -b .fix-model-param~
+%patch5014 -p1 -b .loop-opt~
 
 cd nvptx-tools-%{nvptx_tools_gitrev}
 %patch2000 -p1 -b .nvptx-tools-no-ptxas~
@@ -3392,6 +3394,9 @@ fi
 %{ANNOBIN_GCC_PLUGIN_DIR}/gcc-annobin.so.0.0.0
 
 %changelog
+* Mon Sep 22 2025 huzife <634763349@qq.com> - 8.5.0-28.ap.2
+- Applied loop-elim optimization
+
 * Tue Sep 02 2025 TencentOS Team  - 8.5.0-28.ap.1
 - Applied Autopatch for ts3