Mercurial > hg > truffle
comparison src/share/vm/opto/compile.cpp @ 368:36ccc817fca4
6747051: Improve code and implicit null check generation for compressed oops
Summary: Push DecodeN node below the Null check to the non-null path to use the mach node without 0 test.
Reviewed-by: rasbold, never
author | kvn |
---|---|
date | Tue, 23 Sep 2008 12:29:06 -0700 |
parents | 194b8e3a2fc4 |
children | f4fe12e429a4 |
comparison
equal
deleted
inserted
replaced
367:194b8e3a2fc4 | 368:36ccc817fca4 |
---|---|
2073 #endif | 2073 #endif |
2074 break; | 2074 break; |
2075 } | 2075 } |
2076 | 2076 |
2077 #ifdef _LP64 | 2077 #ifdef _LP64 |
2078 case Op_CastPP: | |
2079 if (n->in(1)->is_DecodeN() && UseImplicitNullCheckForNarrowOop) { | |
2080 Compile* C = Compile::current(); | |
2081 Node* in1 = n->in(1); | |
2082 const Type* t = n->bottom_type(); | |
2083 Node* new_in1 = in1->clone(); | |
2084 new_in1->as_DecodeN()->set_type(t); | |
2085 | |
2086 if (!Matcher::clone_shift_expressions) { | |
2087 // | |
2088 // x86, ARM and friends can handle 2 adds in addressing mode | |
2089 // and Matcher can fold a DecodeN node into address by using | |
2090 // a narrow oop directly and do implicit NULL check in address: | |
2091 // | |
2092 // [R12 + narrow_oop_reg<<3 + offset] | |
2093 // NullCheck narrow_oop_reg | |
2094 // | |
2095 // On other platforms (Sparc) we have to keep new DecodeN node and | |
2096 // use it to do implicit NULL check in address: | |
2097 // | |
2098 // decode_not_null narrow_oop_reg, base_reg | |
2099 // [base_reg + offset] | |
2100 // NullCheck base_reg | |
2101 // | |
2102 // Pin the new DecodeN node to non-null path on these patforms (Sparc) | |
2103 // to keep the information to which NULL check the new DecodeN node | |
2104 // corresponds to use it as value in implicit_null_check(). | |
2105 // | |
2106 new_in1->set_req(0, n->in(0)); | |
2107 } | |
2108 | |
2109 n->subsume_by(new_in1); | |
2110 if (in1->outcnt() == 0) { | |
2111 in1->disconnect_inputs(NULL); | |
2112 } | |
2113 } | |
2114 break; | |
2115 | |
2078 case Op_CmpP: | 2116 case Op_CmpP: |
2079 // Do this transformation here to preserve CmpPNode::sub() and | 2117 // Do this transformation here to preserve CmpPNode::sub() and |
2080 // other TypePtr related Ideal optimizations (for example, ptr nullness). | 2118 // other TypePtr related Ideal optimizations (for example, ptr nullness). |
2081 if (n->in(1)->is_DecodeN() || n->in(2)->is_DecodeN()) { | 2119 if (n->in(1)->is_DecodeN() || n->in(2)->is_DecodeN()) { |
2082 Node* in1 = n->in(1); | 2120 Node* in1 = n->in(1); |
2092 if (in2->is_DecodeN()) { | 2130 if (in2->is_DecodeN()) { |
2093 new_in2 = in2->in(1); | 2131 new_in2 = in2->in(1); |
2094 } else if (in2->Opcode() == Op_ConP) { | 2132 } else if (in2->Opcode() == Op_ConP) { |
2095 const Type* t = in2->bottom_type(); | 2133 const Type* t = in2->bottom_type(); |
2096 if (t == TypePtr::NULL_PTR && UseImplicitNullCheckForNarrowOop) { | 2134 if (t == TypePtr::NULL_PTR && UseImplicitNullCheckForNarrowOop) { |
2097 if (Matcher::clone_shift_expressions) { | 2135 new_in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR); |
2098 // x86, ARM and friends can handle 2 adds in addressing mode. | 2136 // |
2099 // Decode a narrow oop and do implicit NULL check in address | 2137 // This transformation together with CastPP transformation above |
2100 // [R12 + narrow_oop_reg<<3 + offset] | 2138 // will generated code for implicit NULL checks for compressed oops. |
2101 new_in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR); | 2139 // |
2102 } else { | 2140 // The original code after Optimize() |
2103 // Don't replace CmpP(o ,null) if 'o' is used in AddP | 2141 // |
2104 // to generate implicit NULL check on Sparc where | 2142 // LoadN memory, narrow_oop_reg |
2105 // narrow oops can't be used in address. | 2143 // decode narrow_oop_reg, base_reg |
2106 uint i = 0; | 2144 // CmpP base_reg, NULL |
2107 for (; i < in1->outcnt(); i++) { | 2145 // CastPP base_reg // NotNull |
2108 if (in1->raw_out(i)->is_AddP()) | 2146 // Load [base_reg + offset], val_reg |
2109 break; | 2147 // |
2110 } | 2148 // after these transformations will be |
2111 if (i >= in1->outcnt()) { | 2149 // |
2112 new_in2 = ConNode::make(C, TypeNarrowOop::NULL_PTR); | 2150 // LoadN memory, narrow_oop_reg |
2113 } | 2151 // CmpN narrow_oop_reg, NULL |
2114 } | 2152 // decode_not_null narrow_oop_reg, base_reg |
2153 // Load [base_reg + offset], val_reg | |
2154 // | |
2155 // and the uncommon path (== NULL) will use narrow_oop_reg directly | |
2156 // since narrow oops can be used in debug info now (see the code in | |
2157 // final_graph_reshaping_walk()). | |
2158 // | |
2159 // At the end the code will be matched to | |
2160 // on x86: | |
2161 // | |
2162 // Load_narrow_oop memory, narrow_oop_reg | |
2163 // Load [R12 + narrow_oop_reg<<3 + offset], val_reg | |
2164 // NullCheck narrow_oop_reg | |
2165 // | |
2166 // and on sparc: | |
2167 // | |
2168 // Load_narrow_oop memory, narrow_oop_reg | |
2169 // decode_not_null narrow_oop_reg, base_reg | |
2170 // Load [base_reg + offset], val_reg | |
2171 // NullCheck base_reg | |
2172 // | |
2115 } else if (t->isa_oopptr()) { | 2173 } else if (t->isa_oopptr()) { |
2116 new_in2 = ConNode::make(C, t->make_narrowoop()); | 2174 new_in2 = ConNode::make(C, t->make_narrowoop()); |
2117 } | 2175 } |
2118 } | 2176 } |
2119 if (new_in2 != NULL) { | 2177 if (new_in2 != NULL) { |
2126 in2->disconnect_inputs(NULL); | 2184 in2->disconnect_inputs(NULL); |
2127 } | 2185 } |
2128 } | 2186 } |
2129 } | 2187 } |
2130 break; | 2188 break; |
2189 | |
2190 case Op_DecodeN: | |
2191 assert(!n->in(1)->is_EncodeP(), "should be optimized out"); | |
2192 break; | |
2193 | |
2194 case Op_EncodeP: { | |
2195 Node* in1 = n->in(1); | |
2196 if (in1->is_DecodeN()) { | |
2197 n->subsume_by(in1->in(1)); | |
2198 } else if (in1->Opcode() == Op_ConP) { | |
2199 Compile* C = Compile::current(); | |
2200 const Type* t = in1->bottom_type(); | |
2201 if (t == TypePtr::NULL_PTR) { | |
2202 n->subsume_by(ConNode::make(C, TypeNarrowOop::NULL_PTR)); | |
2203 } else if (t->isa_oopptr()) { | |
2204 n->subsume_by(ConNode::make(C, t->make_narrowoop())); | |
2205 } | |
2206 } | |
2207 if (in1->outcnt() == 0) { | |
2208 in1->disconnect_inputs(NULL); | |
2209 } | |
2210 break; | |
2211 } | |
2212 | |
2213 case Op_Phi: | |
2214 if (n->as_Phi()->bottom_type()->isa_narrowoop()) { | |
2215 // The EncodeP optimization may create Phi with the same edges | |
2216 // for all paths. It is not handled well by Register Allocator. | |
2217 Node* unique_in = n->in(1); | |
2218 assert(unique_in != NULL, ""); | |
2219 uint cnt = n->req(); | |
2220 for (uint i = 2; i < cnt; i++) { | |
2221 Node* m = n->in(i); | |
2222 assert(m != NULL, ""); | |
2223 if (unique_in != m) | |
2224 unique_in = NULL; | |
2225 } | |
2226 if (unique_in != NULL) { | |
2227 n->subsume_by(unique_in); | |
2228 } | |
2229 } | |
2230 break; | |
2231 | |
2131 #endif | 2232 #endif |
2132 | 2233 |
2133 case Op_ModI: | 2234 case Op_ModI: |
2134 if (UseDivMod) { | 2235 if (UseDivMod) { |
2135 // Check if a%b and a/b both exist | 2236 // Check if a%b and a/b both exist |