&& isDirectIface(itab)
&& clobber(v)
=> (MakeResult (EqPtr x y) mem)
+
+// If we use the result of slicebytetostring in a map lookup operation,
+// then we don't need to actually do the []byte->string conversion.
+// We can just use the ptr/len of the byte slice directly as a (temporary) string.
+//
+// Note that this does not handle some obscure cases like
+// m[[2]string{string(b1), string(b2)}]. There is code in ../walk/order.go
+// which handles some of those cases.
+(StaticLECall {f} [argsize] typ_ map_ key:(SelectN [0] sbts:(StaticLECall {g} _ ptr len mem)) m:(SelectN [1] sbts))
+ && (isSameCall(f, "runtime.mapaccess1_faststr")
+ || isSameCall(f, "runtime.mapaccess2_faststr")
+ || isSameCall(f, "runtime.mapdelete_faststr"))
+ && isSameCall(g, "runtime.slicebytetostring")
+ && key.Uses == 1
+ && sbts.Uses == 2
+ && resetCopy(m, mem)
+ && clobber(sbts)
+ && clobber(key)
+=> (StaticLECall {f} [argsize] typ_ map_ (StringMake <typ.String> ptr len) mem)
return true
}
+// resetCopy resets v to be a copy of arg.
+// Always returns true.
+func resetCopy(v *Value, arg *Value) bool {
+ v.reset(OpCopy)
+ v.AddArg(arg)
+ return true
+}
+
// clobberIfDead resets v when use count is 1. Returns true.
// clobberIfDead is used by rewrite rules to decrement
// use counts of v's args when v is dead and never used.
v.AddArg2(v0, mem)
return true
}
+ // match: (StaticLECall {f} [argsize] typ_ map_ key:(SelectN [0] sbts:(StaticLECall {g} _ ptr len mem)) m:(SelectN [1] sbts))
+ // cond: (isSameCall(f, "runtime.mapaccess1_faststr") || isSameCall(f, "runtime.mapaccess2_faststr") || isSameCall(f, "runtime.mapdelete_faststr")) && isSameCall(g, "runtime.slicebytetostring") && key.Uses == 1 && sbts.Uses == 2 && resetCopy(m, mem) && clobber(sbts) && clobber(key)
+ // result: (StaticLECall {f} [argsize] typ_ map_ (StringMake <typ.String> ptr len) mem)
+ for {
+ if len(v.Args) != 4 {
+ break
+ }
+ argsize := auxIntToInt32(v.AuxInt)
+ f := auxToCall(v.Aux)
+ _ = v.Args[3]
+ typ_ := v.Args[0]
+ map_ := v.Args[1]
+ key := v.Args[2]
+ if key.Op != OpSelectN || auxIntToInt64(key.AuxInt) != 0 {
+ break
+ }
+ sbts := key.Args[0]
+ if sbts.Op != OpStaticLECall || len(sbts.Args) != 4 {
+ break
+ }
+ g := auxToCall(sbts.Aux)
+ mem := sbts.Args[3]
+ ptr := sbts.Args[1]
+ len := sbts.Args[2]
+ m := v.Args[3]
+ if m.Op != OpSelectN || auxIntToInt64(m.AuxInt) != 1 || sbts != m.Args[0] || !((isSameCall(f, "runtime.mapaccess1_faststr") || isSameCall(f, "runtime.mapaccess2_faststr") || isSameCall(f, "runtime.mapdelete_faststr")) && isSameCall(g, "runtime.slicebytetostring") && key.Uses == 1 && sbts.Uses == 2 && resetCopy(m, mem) && clobber(sbts) && clobber(key)) {
+ break
+ }
+ v.reset(OpStaticLECall)
+ v.AuxInt = int32ToAuxInt(argsize)
+ v.Aux = callToAux(f)
+ v0 := b.NewValue0(v.Pos, OpStringMake, typ.String)
+ v0.AddArg2(ptr, len)
+ v.AddArg4(typ_, map_, v0, mem)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpStore(v *Value) bool {
// It would be nice to handle these generally, but because
// []byte keys are not allowed in maps, the use of string(k)
// comes up in important cases in practice. See issue 3512.
+//
+// Note that this code does not handle the case:
+//
+// s := string(k)
+// x = m[s]
+//
+// Cases like this are handled during SSA, search for slicebytetostring
+// in ../ssa/_gen/generic.rules.
func mapKeyReplaceStrConv(n ir.Node) bool {
var replaced bool
switch n.Op() {
return m[[2]string{0: string(bytes)}]
}
+func LookupStringConversion1(m map[string]int, bytes []byte) int {
+ // amd64:-`.*runtime\.slicebytetostring\(`
+ s := string(bytes)
+ return m[s]
+}
+func LookupStringConversion2(m *map[string]int, bytes []byte) int {
+ // amd64:-`.*runtime\.slicebytetostring\(`
+ s := string(bytes)
+ return (*m)[s]
+}
+func LookupStringConversion3(m map[string]int, bytes []byte) (int, bool) {
+ // amd64:-`.*runtime\.slicebytetostring\(`
+ s := string(bytes)
+ r, ok := m[s]
+ return r, ok
+}
+func DeleteStringConversion(m map[string]int, bytes []byte) {
+ // amd64:-`.*runtime\.slicebytetostring\(`
+ s := string(bytes)
+ delete(m, s)
+}
+
// ------------------- //
// Map Clear //
// ------------------- //