ir_alloc.mx raw

   1  package main
   2  
   3  import (
   4  	. "git.smesh.lol/moxie/pkg/types"
   5  )
   6  
   7  func (e *irEmitter) emitAlloc(a *SSAAlloc) {
   8  	reg := e.regName(a)
   9  	if at, ok := e.allocTypes[a]; ok && len(at) > 0 && at[0] == '[' {
  10  		if a.Heap {
  11  			ipt := e.intptrType()
  12  			e.nextReg++
  13  			sz := "%ha" | irItoa(e.nextReg)
  14  			e.w("  ") ; e.w(sz)
  15  			e.w(" = ptrtoint ptr getelementptr (") ; e.w(at)
  16  			e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
  17  			e.w("  ") ; e.w(reg)
  18  			e.w(" = call ptr @runtime.alloc(") ; e.w(ipt)
  19  			e.w(" ") ; e.w(sz) ; e.w(", ptr null, ptr null)\n")
  20  			e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr")
  21  			e.scopeTrackAlloc(reg)
  22  		} else {
  23  			e.w("  ") ; e.w(reg) ; e.w(" = alloca ") ; e.w(at) ; e.w("\n")
  24  			e.w("  store ") ; e.w(at) ; e.w(" zeroinitializer, ptr ") ; e.w(reg) ; e.w("\n")
  25  		}
  26  		return
  27  	}
  28  	elemType := e.llvmType(a.SSAType())
  29  	nilElem := false
  30  	if p, ok := SafeUnderlying(a.SSAType()).(*Pointer); ok {
  31  		if p.Base != nil {
  32  			elemType = e.llvmType(p.Base)
  33  		} else {
  34  			nilElem = true
  35  		}
  36  	}
  37  	isDoublePtr := false
  38  	if p, ok := SafeUnderlying(a.SSAType()).(*Pointer); ok && p.Base != nil {
  39  		if _, ok2 := SafeUnderlying(p.Base).(*Pointer); ok2 {
  40  			isDoublePtr = true
  41  		}
  42  	}
  43  	if isDoublePtr && elemType == "ptr" {
  44  		e.allocTypes[a] = elemType
  45  	} else if elemType == "void" {
  46  		inferred := e.inferAllocTypeFromStores(a)
  47  		elemType = inferred
  48  		e.allocTypes[a] = elemType
  49  	} else if elemType == "ptr" && nilElem {
  50  		inferred := e.inferAllocTypeFromStores(a)
  51  		if inferred != "ptr" && (len(inferred) == 0 || inferred[0] != '{') {
  52  			elemType = inferred
  53  		}
  54  		e.allocTypes[a] = elemType
  55  	} else {
  56  		isSimple := elemType == "i1" || elemType == "i8" || elemType == "i16" || elemType == "i32" || elemType == "i64" || elemType == "float" || elemType == "double" || elemType == "ptr"
  57  		if !isSimple {
  58  			override := e.inferAllocTypeFromStores(a)
  59  			if override != "ptr" && override != elemType {
  60  				bothScalar := len(elemType) > 0 && elemType[0] == 'i' && len(override) > 0 && override[0] == 'i'
  61  				isFloatToInt := (elemType == "double" || elemType == "float") && len(override) > 0 && override[0] == 'i'
  62  				isScalarToAgg := len(elemType) > 0 && (elemType[0] == 'i' || elemType == "double" || elemType == "float") && len(override) > 0 && override[0] == '{'
  63  				isAggToScalar := len(elemType) > 0 && elemType[0] == '{' && len(override) > 0 && (override[0] == 'i' || override == "double" || override == "float")
  64  				if !bothScalar && !isFloatToInt && !isScalarToAgg && !isAggToScalar {
  65  					elemType = override
  66  					e.allocTypes[a] = elemType
  67  				}
  68  			}
  69  		}
  70  	}
  71  	isSimple2 := elemType == "i1" || elemType == "i8" || elemType == "i16" || elemType == "i32" || elemType == "i64" || elemType == "float" || elemType == "double" || elemType == "ptr"
  72  	if !isDoublePtr && !isSimple2 {
  73  		if faType := e.inferAllocTypeFromFieldAddrs(a, elemType); faType != "" {
  74  			retType := e.inferAllocTypeFromReturn(a)
  75  			callType := e.inferAllocTypeFromCallArgs(a)
  76  			appendType := e.inferAllocTypeFromAppendUsage(a)
  77  			best := faType
  78  			if retType != "" && len(retType) > len(best) {
  79  				best = retType
  80  			}
  81  			if callType != "" && len(callType) > len(best) {
  82  				best = callType
  83  			}
  84  			if appendType != "" && len(appendType) > len(best) {
  85  				best = appendType
  86  			}
  87  			if elemType != best {
  88  				elemType = best
  89  				e.allocTypes[a] = elemType
  90  			}
  91  		}
  92  	}
  93  	if a.Heap {
  94  		ipt := e.intptrType()
  95  		e.nextReg++
  96  		sz := "%ha" | irItoa(e.nextReg)
  97  		e.w("  ") ; e.w(sz)
  98  		e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
  99  		e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
 100  		e.w("  ") ; e.w(reg)
 101  		e.w(" = call ptr @runtime.alloc(") ; e.w(ipt)
 102  		e.w(" ") ; e.w(sz) ; e.w(", ptr null, ptr null)\n")
 103  		e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr")
 104  		e.scopeTrackAlloc(reg)
 105  	} else {
 106  		e.w("  ")
 107  		e.w(reg)
 108  		e.w(" = alloca ")
 109  		e.w(elemType)
 110  		e.w("\n")
 111  		e.w("  store ") ; e.w(elemType) ; e.w(" zeroinitializer, ptr ") ; e.w(reg) ; e.w("\n")
 112  	}
 113  }
 114  
 115  func (e *irEmitter) inferAllocTypeFromStores(a *SSAAlloc) (s string) {
 116  	allocName := a.SSAName()
 117  	for _, b := range e.curFunc.Blocks {
 118  		for _, instr := range b.Instrs {
 119  			if sv, okSv := instr.(*SSAStore); okSv && sv.Addr != nil && sv.Addr.SSAName() == allocName {
 120  				if at, ok2 := e.allocTypes[sv.Val]; ok2 && at != "ptr" && at != "void" {
 121  					return at
 122  				}
 123  				vt := e.llvmType(sv.Val.SSAType())
 124  				if vt != "void" && vt != "" {
 125  					return vt
 126  				}
 127  				if call, ok3 := sv.Val.(*SSACall); ok3 {
 128  					if b2, ok4 := call.Call.Value.(*SSABuiltin); ok4 && b2.SSAName() == "append" {
 129  						return e.sliceType()
 130  					}
 131  				}
 132  				if _, ok4 := sv.Val.(*SSASlice); ok4 {
 133  					return e.sliceType()
 134  				}
 135  				if _, ok5 := sv.Val.(*SSAMakeSlice); ok5 {
 136  					return e.sliceType()
 137  				}
 138  				}
 139  		}
 140  	}
 141  	return "ptr"
 142  }
 143  
 144  func (e *irEmitter) inferAllocTypeFromReturn(a *SSAAlloc) (s string) {
 145  	allocName := a.SSAName()
 146  	for _, b := range e.curFunc.Blocks {
 147  		for _, instr := range b.Instrs {
 148  			ret, ok := instr.(*SSAReturn)
 149  			if !ok {
 150  				continue
 151  			}
 152  			for i, rv := range ret.Results {
 153  				if rv == nil {
 154  					continue
 155  				}
 156  				if uop, ok2 := rv.(*SSAUnOp); ok2 && uop.Op == OpMul && uop.X != nil && uop.X.SSAName() == allocName {
 157  					sig := e.curFunc.Signature
 158  					if sig != nil && sig.Results != nil && i < sig.Results.Len() {
 159  						rt := e.llvmType(sig.Results.At(i).Typ)
 160  						if rt != "void" && rt != "ptr" && rt != "" {
 161  							return rt
 162  						}
 163  					}
 164  					return ""
 165  				}
 166  			}
 167  		}
 168  	}
 169  	return ""
 170  }
 171  
 172  func (e *irEmitter) inferAllocTypeFromCallArgs(a *SSAAlloc) (s string) {
 173  	allocName := a.SSAName()
 174  	loadNames := map[string]bool{}
 175  	for _, b := range e.curFunc.Blocks {
 176  		for _, instr := range b.Instrs {
 177  			if uop, ok := instr.(*SSAUnOp); ok && uop.Op == OpMul && uop.X != nil && uop.X.SSAName() == allocName {
 178  				loadNames[uop.SSAName()] = true
 179  			}
 180  		}
 181  	}
 182  	for _, b := range e.curFunc.Blocks {
 183  		for _, instr := range b.Instrs {
 184  			call, ok := instr.(*SSACall)
 185  			if !ok { continue }
 186  			callee := call.Call.Value
 187  			if callee == nil { continue }
 188  			var sig *Signature
 189  			if cfn, ok2 := callee.(*SSAFunction); ok2 && cfn.Signature != nil {
 190  				sig = cfn.Signature
 191  			} else {
 192  				sig, _ = SafeUnderlying(callee.SSAType()).(*Signature)
 193  			}
 194  			if sig == nil || sig.Params == nil { continue }
 195  			recvOff := 0
 196  			if sig.Recv != nil { recvOff = 1 }
 197  			for i, arg := range call.Call.Args {
 198  				if arg == nil { continue }
 199  				if !loadNames[arg.SSAName()] { continue }
 200  				sigIdx := i - recvOff
 201  				if sigIdx < 0 || sigIdx >= sig.Params.Len() { continue }
 202  				pt := e.llvmType(sig.Params.At(sigIdx).Typ)
 203  				if pt != "void" && pt != "ptr" && pt != "" && len(pt) > 0 && pt[0] == '{' {
 204  					return pt
 205  				}
 206  			}
 207  		}
 208  	}
 209  	return ""
 210  }
 211  
 212  func (e *irEmitter) inferAllocTypeFromAppendUsage(a *SSAAlloc) (s string) {
 213  	allocName := a.SSAName()
 214  	loadNames := map[string]bool{}
 215  	for _, b := range e.curFunc.Blocks {
 216  		for _, instr := range b.Instrs {
 217  			if uop, ok := instr.(*SSAUnOp); ok && uop.Op == OpMul && uop.X != nil && uop.X.SSAName() == allocName {
 218  				loadNames[uop.SSAName()] = true
 219  			}
 220  		}
 221  	}
 222  	if len(loadNames) == 0 {
 223  		return ""
 224  	}
 225  	for _, b := range e.curFunc.Blocks {
 226  		for _, instr := range b.Instrs {
 227  			call, ok := instr.(*SSACall)
 228  			if !ok {
 229  				continue
 230  			}
 231  			bi, ok2 := call.Call.Value.(*SSABuiltin)
 232  			if !ok2 || bi.SSAName() != "append" {
 233  				continue
 234  			}
 235  			if len(call.Call.Args) < 2 {
 236  				continue
 237  			}
 238  			for j := 1; j < len(call.Call.Args); j++ {
 239  				arg := call.Call.Args[j]
 240  				if arg == nil {
 241  					continue
 242  				}
 243  				if !loadNames[arg.SSAName()] {
 244  					continue
 245  				}
 246  				sliceArg := call.Call.Args[0]
 247  				if sl, ok3 := SafeUnderlying(sliceArg.SSAType()).(*Slice); ok3 {
 248  					et := e.llvmType(sl.Elem)
 249  					if et != "" && et != "void" && et != "ptr" && len(et) > 0 && et[0] == '{' {
 250  						return et
 251  					}
 252  				}
 253  				if sl, ok3 := sliceArg.SSAType().(*Slice); ok3 {
 254  					et := e.llvmType(sl.Elem)
 255  					if et != "" && et != "void" && et != "ptr" && len(et) > 0 && et[0] == '{' {
 256  						return et
 257  					}
 258  				}
 259  			}
 260  		}
 261  	}
 262  	return ""
 263  }
 264  
 265  func (e *irEmitter) inferAllocTypeFromFieldAddrs(a *SSAAlloc, baseType string) (s string) {
 266  	allocName := a.SSAName()
 267  	names := map[string]bool{allocName: true}
 268  	for _, b := range e.curFunc.Blocks {
 269  		for _, instr := range b.Instrs {
 270  			if uop, ok := instr.(*SSAUnOp); ok && uop.Op == OpMul && uop.X != nil && uop.X.SSAName() == allocName {
 271  				names[uop.SSAName()] = true
 272  			}
 273  		}
 274  	}
 275  	maxField := -1
 276  	fieldTypes := map[int32]string{}
 277  	for _, b := range e.curFunc.Blocks {
 278  		for _, instr := range b.Instrs {
 279  			fa, ok := instr.(*SSAFieldAddr)
 280  			if !ok || fa.X == nil || !names[fa.X.SSAName()] {
 281  				continue
 282  			}
 283  			if fa.Field > maxField {
 284  				maxField = fa.Field
 285  			}
 286  			faName := fa.SSAName()
 287  			for _, b2 := range e.curFunc.Blocks {
 288  				for _, i2 := range b2.Instrs {
 289  					if sv, ok2 := i2.(*SSAStore); ok2 && sv.Addr != nil && sv.Addr.SSAName() == faName {
 290  						ft := e.llvmType(sv.Val.SSAType())
 291  						if ft != "void" && ft != "" {
 292  							fieldTypes[fa.Field] = ft
 293  						}
 294  					}
 295  					if ld, ok2 := i2.(*SSAUnOp); ok2 && ld.Op == OpMul && ld.X != nil && ld.X.SSAName() == faName {
 296  						ft := e.llvmType(ld.SSAType())
 297  						if ft != "void" && ft != "" && ft != "ptr" {
 298  							if _, exists := fieldTypes[fa.Field]; !exists {
 299  								fieldTypes[fa.Field] = ft
 300  							}
 301  						}
 302  					}
 303  				}
 304  			}
 305  		}
 306  	}
 307  	if maxField < 0 {
 308  		return ""
 309  	}
 310  	baseFields := parseStructFields(baseType)
 311  	top := maxField
 312  	if len(baseFields)-1 > top {
 313  		top = len(baseFields) - 1
 314  	}
 315  	s := "{"
 316  	for i := 0; i <= top; i++ {
 317  		if i > 0 {
 318  			s = s | ", "
 319  		}
 320  		ft, ok := fieldTypes[i]
 321  		if !ok {
 322  			if i < len(baseFields) && baseFields[i] != "" {
 323  				ft = baseFields[i]
 324  			} else {
 325  				ft = "ptr"
 326  			}
 327  		} else if i < len(baseFields) && baseFields[i] != "" {
 328  			bw := irParseIntWidth(baseFields[i])
 329  			fw := irParseIntWidth(ft)
 330  			if bw > 0 && fw > 0 && bw > fw {
 331  				ft = baseFields[i]
 332  			}
 333  		}
 334  		s = s | ft
 335  	}
 336  	return s | "}"
 337  }
 338  
 339  func (e *irEmitter) inferAllocTypeFromUsage(a *SSAAlloc) (s string) {
 340  	allocName := a.SSAName()
 341  	loadNames := map[string]bool{}
 342  	for _, b := range e.curFunc.Blocks {
 343  		for _, instr := range b.Instrs {
 344  			load, ok := instr.(*SSAUnOp)
 345  			if !ok || load.Op != OpMul {
 346  				continue
 347  			}
 348  			if load.X != nil && load.X.SSAName() == allocName {
 349  				loadNames[load.SSAName()] = true
 350  			}
 351  		}
 352  	}
 353  	if len(loadNames) == 0 {
 354  		return "ptr"
 355  	}
 356  	for _, b := range e.curFunc.Blocks {
 357  		for _, instr := range b.Instrs {
 358  			switch u := instr.(type) {
 359  			case *SSASlice:
 360  				if u.X != nil && loadNames[u.X.SSAName()] {
 361  					return e.sliceType()
 362  				}
 363  			case *SSAIndexAddr:
 364  				if u.X != nil && loadNames[u.X.SSAName()] {
 365  					return e.sliceType()
 366  				}
 367  			case *SSACall:
 368  				for _, arg := range u.Call.Args {
 369  					if arg != nil && loadNames[arg.SSAName()] {
 370  						if bi, ok2 := u.Call.Value.(*SSABuiltin); ok2 {
 371  							nm := bi.SSAName()
 372  							if nm == "append" || nm == "copy" || nm == "len" || nm == "cap" {
 373  								return e.sliceType()
 374  							}
 375  						}
 376  					}
 377  				}
 378  			}
 379  		}
 380  	}
 381  	return "ptr"
 382  }
 383  
 384  func (e *irEmitter) emitZeroReg(reg string, typ Type) {
 385  	rt := e.llvmType(typ)
 386  	if rt == "void" || rt == "" {
 387  		rt = "i32"
 388  	}
 389  	if rt == "ptr" {
 390  		e.w("  ") ; e.w(reg) ; e.w(" = inttoptr " | e.intptrType() | " 0 to ptr\n")
 391  	} else if rt == "i1" {
 392  		e.w("  ") ; e.w(reg) ; e.w(" = add i1 false, false\n")
 393  	} else if e.intBits(rt) > 0 {
 394  		e.w("  ") ; e.w(reg) ; e.w(" = add ") ; e.w(rt) ; e.w(" 0, 0\n")
 395  	} else {
 396  		e.w("  ") ; e.w(reg) ; e.w(" = add i32 0, 0\n")
 397  	}
 398  }
 399