package emit import ( "git.smesh.lol/moxie/pkg/syntax" "git.smesh.lol/moxie/pkg/ssa" "git.smesh.lol/moxie/pkg/types" ) func (e *irEmitter) emitFieldAddr(f *ssa.SSAFieldAddr) { reg := e.regName(f) baseType := e.llvmType(f.X.SSAType()) if p, ok := types.SafeUnderlying(f.X.SSAType()).(*types.Pointer); ok && p.Elem() != nil { elem := p.Elem() if p2, ok2 := types.SafeUnderlying(elem).(*types.Pointer); ok2 && p2.Elem() != nil { baseType = e.llvmType(p2.Elem()) } else { baseType = e.llvmType(elem) } } if at, ok := e.allocTypes[f.X]; ok && at != "ptr" && at != "void" { baseType = at } base := e.operand(f.X) if uop, ok := f.X.(*ssa.SSAUnOp); ok { _, isFreeVar := uop.X.(*ssa.SSAFreeVar) addrType := e.llvmType(uop.X.SSAType()) useSource := false if p, ok2 := types.SafeUnderlying(uop.X.SSAType()).(*types.Pointer); ok2 && p.Elem() != nil { elem := p.Elem() if _, ok3 := types.SafeUnderlying(elem).(*types.Pointer); ok3 { // double-pointer: alloca holds **T, keep the loaded *T as base } else { baseType = e.llvmType(elem) useSource = true } } if useSource && !isFreeVar && addrType == "ptr" && baseType != "ptr" && baseType != "void" { base = e.operand(uop.X) } } if baseType == "ptr" || baseType == "void" { e.w(" ") ; e.w(reg) ; e.w(" = getelementptr inbounds i8, ptr ") ; e.w(base) e.w(", i32 0\n") return } _, isCall := f.X.(*ssa.SSACall) _, isPhi := f.X.(*ssa.SSAPhi) isExtract := false if _, ok := f.X.(*ssa.SSAExtract); ok { isExtract = true } needsAlloca := (isCall || isPhi || isExtract) && len(baseType) > 0 && baseType[0] == '{' if !needsAlloca { if _, isAlloc := f.X.(*ssa.SSAAlloc); !isAlloc { if _, isGlobal := f.X.(*ssa.SSAGlobal); !isGlobal { if _, isUop := f.X.(*ssa.SSAUnOp); !isUop { if _, isIdxAddr := f.X.(*ssa.SSAIndexAddr); !isIdxAddr { if _, isFA := f.X.(*ssa.SSAFieldAddr); !isFA { if _, isFV := f.X.(*ssa.SSAFreeVar); !isFV { if len(baseType) > 0 && (baseType[0] == '{' || baseType[0] == '[') { needsAlloca = true } } } } } } } } if needsAlloca { actualType := e.resolvedType(f.X, e.llvmType(f.X.SSAType())) if actualType == "ptr" { needsAlloca = false } else { e.nextReg++ tmp := "%fa" | irItoa(e.nextReg) e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(baseType) ; e.w("\n") e.w(" store ") ; e.w(baseType) ; e.w(" ") ; e.w(base) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n") base = tmp } } e.w(" ") e.w(reg) e.w(" = getelementptr inbounds ") e.w(baseType) e.w(", ptr ") e.w(base) e.w(", i32 0, i32 ") e.w(irItoa(f.Field)) e.w("\n") } func (e *irEmitter) emitIndexAddr(idx *ssa.SSAIndexAddr) { reg := e.regName(idx) elemType := e.llvmType(idx.SSAType()) if p, ok := types.SafeUnderlying(idx.SSAType()).(*types.Pointer); ok { elemType = e.llvmType(p.Elem()) } base := e.operand(idx.X) index := e.operand(idx.Index) baseType := e.llvmType(idx.X.SSAType()) resolvedBase := e.resolvedType(idx.X, baseType) _, isSlice := types.SafeUnderlying(idx.X.SSAType()).(*types.Slice) if !isSlice { if b, ok := types.SafeUnderlying(idx.X.SSAType()).(*types.Basic); ok && b.Info()&types.IsString != 0 { isSlice = true } } if at, ok4 := e.allocTypes[idx.X]; ok4 && len(at) > 0 && at[0] == '[' { isSlice = false } else if !isSlice && (baseType == e.sliceType() || resolvedBase == e.sliceType()) { isSlice = true } if isSlice && elemType == "void" { elemType = "i8" } idxType := e.resolvedType(idx.Index, e.llvmType(idx.Index.SSAType())) if e.intBits(idxType) == 0 && idxType != "ptr" { if idxType == e.ifaceType() || (len(idxType) > 0 && idxType[0] == '{') { fieldType := extractTupleField(idxType, 1) if fieldType == "" { fieldType = "i64" } e.nextReg++ valPtr := "%idxv" | irItoa(e.nextReg) e.w(" ") ; e.w(valPtr) ; e.w(" = extractvalue ") ; e.w(idxType) ; e.w(" ") ; e.w(index) ; e.w(", 1\n") e.nextReg++ intVal := "%idxi" | irItoa(e.nextReg) if fieldType == "ptr" { e.w(" ") ; e.w(intVal) ; e.w(" = ptrtoint ptr ") ; e.w(valPtr) ; e.w(" to i32\n") } else if fieldType == "i32" { intVal = valPtr } else { e.w(" ") ; e.w(intVal) ; e.w(" = trunc ") ; e.w(fieldType) ; e.w(" ") ; e.w(valPtr) ; e.w(" to i32\n") } index = intVal idxType = "i32" } } if isSlice { e.nextReg++ dataPtr := "%sp" | irItoa(e.nextReg) e.w(" ") e.w(dataPtr) e.w(" = extractvalue ") e.w(e.sliceType()) e.w(" ") e.w(base) e.w(", 0\n") e.w(" ") e.w(reg) e.w(" = getelementptr inbounds ") e.w(elemType) e.w(", ptr ") e.w(dataPtr) e.w(", ") e.w(idxType) e.w(" ") e.w(index) e.w("\n") e.setRegType(idx, reg, elemType) return } arr, isArray := types.SafeUnderlying(idx.X.SSAType()).(*types.Array) if !isArray { if at, ok4 := e.allocTypes[idx.X]; ok4 && len(at) > 0 && at[0] == '[' { isArray = true } } if !isArray { if alloc, ok4 := idx.X.(*ssa.SSAAlloc); ok4 { if p, ok5 := types.SafeUnderlying(alloc.SSAType()).(*types.Pointer); ok5 && p.Elem() != nil { if ar, ok6 := types.SafeUnderlying(p.Elem()).(*types.Array); ok6 && ar.Len() > 0 { isArray = true arrT := e.llvmType(p.Elem()) if len(arrT) > 0 && arrT[0] == '[' { e.allocTypes[alloc] = arrT } } } } } if !isArray { if load, ok4 := idx.X.(*ssa.SSAUnOp); ok4 && load.Op == ssa.OpMul { if at, ok5 := e.allocTypes[load.X]; ok5 && len(at) > 0 && at[0] == '[' { isArray = true e.allocTypes[idx.X] = at allocBase := e.operand(load.X) e.w(" ") ; e.w(reg) ; e.w(" = getelementptr inbounds ") e.w(at) ; e.w(", ptr ") ; e.w(allocBase) ; e.w(", i32 0, ") e.w(e.llvmType(idx.Index.SSAType())) ; e.w(" ") ; e.w(index) ; e.w("\n") aet := e.arrayElemType(at) if aet != "" { e.setRegType(idx, reg, aet) } return } } } if isArray { arrType := e.llvmType(idx.X.SSAType()) if at, ok4 := e.allocTypes[idx.X]; ok4 && len(at) > 0 && at[0] == '[' { arrType = at } if arrType == "ptr" || arrType == "void" { if p, ok4 := types.SafeUnderlying(idx.X.SSAType()).(*types.Pointer); ok4 && p.Elem() != nil { arrType = e.llvmType(p.Elem()) } } _, isGlobal := idx.X.(*ssa.SSAGlobal) _, isAlloc := idx.X.(*ssa.SSAAlloc) if isGlobal || isAlloc { _ = arr e.w(" ") ; e.w(reg) ; e.w(" = getelementptr inbounds ") e.w(arrType) ; e.w(", ptr ") ; e.w(base) ; e.w(", i32 0, ") e.w(idxType) ; e.w(" ") ; e.w(index) ; e.w("\n") return } e.nextReg++ arrPtr := "%ai" | irItoa(e.nextReg) e.w(" ") ; e.w(arrPtr) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n") e.w(" store ") ; e.w(arrType) ; e.w(" ") ; e.w(base) ; e.w(", ptr ") ; e.w(arrPtr) ; e.w("\n") e.w(" ") ; e.w(reg) ; e.w(" = getelementptr inbounds ") e.w(arrType) ; e.w(", ptr ") ; e.w(arrPtr) ; e.w(", i32 0, ") e.w(idxType) ; e.w(" ") ; e.w(index) ; e.w("\n") aet := e.arrayElemType(arrType) if aet != "" { e.setRegType(idx, reg, aet) } return } if p, ok := types.SafeUnderlying(idx.X.SSAType()).(*types.Pointer); ok && p.Elem() != nil { if _, ok2 := types.SafeUnderlying(p.Elem()).(*types.Array); ok2 { arrType := e.llvmType(p.Elem()) if len(arrType) > 0 && arrType[0] == '[' { e.w(" ") ; e.w(reg) ; e.w(" = getelementptr inbounds ") e.w(arrType) ; e.w(", ptr ") ; e.w(base) ; e.w(", i32 0, ") e.w(idxType) ; e.w(" ") ; e.w(index) ; e.w("\n") return } } } if len(elemType) > 0 && elemType[0] == '[' { aet := e.arrayElemType(elemType) e.w(" ") ; e.w(reg) ; e.w(" = getelementptr inbounds ") e.w(elemType) ; e.w(", ptr ") ; e.w(base) ; e.w(", i32 0, ") e.w(idxType) ; e.w(" ") ; e.w(index) ; e.w("\n") e.setRegType(idx, reg, aet) return } e.w(" ") e.w(reg) e.w(" = getelementptr inbounds ") e.w(elemType) e.w(", ptr ") e.w(base) e.w(", ") e.w(idxType) e.w(" ") e.w(index) e.w("\n") } func (e *irEmitter) emitExtract(ex *ssa.SSAExtract) { reg := e.regName(ex) tupType := e.llvmType(ex.Tuple.SSAType()) allocFound := false if at, ok := e.allocTypes[ex.Tuple]; ok { tupType = at allocFound = true } if n, ok := ex.Tuple.(*ssa.SSANext); ok && !allocFound { rangeInstr := n.Iter.(*ssa.SSARange) if mt, ok2 := types.SafeUnderlying(rangeInstr.X.SSAType()).(*types.TCMap); ok2 { tupType = "{i1, " | e.llvmType(mt.Key()) | ", " | e.llvmType(mt.Elem()) | "}" } else if arr, ok2 := types.SafeUnderlying(rangeInstr.X.SSAType()).(*types.Array); ok2 { tupType = "{i1, i32, " | e.llvmType(arr.Elem()) | "}" } else if p, ok2 := types.SafeUnderlying(rangeInstr.X.SSAType()).(*types.Pointer); ok2 && p.Elem() != nil { if arr2, ok3 := types.SafeUnderlying(p.Elem()).(*types.Array); ok3 { tupType = "{i1, i32, " | e.llvmType(arr2.Elem()) | "}" } } else if n.IsString { tupType = "{i1, i32, i8}" } else { et := "i8" if sl, ok2 := types.SafeUnderlying(rangeInstr.X.SSAType()).(*types.Slice); ok2 { et = e.llvmType(sl.Elem()) } else if tup, ok2 := n.SSAType().(*types.Tuple); ok2 && tup.Len() >= 3 { vt := tup.At(2).Type() if vt != nil { vlt := e.llvmType(vt) if vlt != "void" { et = vlt } } } tupType = "{i1, i32, " | et | "}" } } val := e.operand(ex.Tuple) // Track extracted element type for downstream alloc/store consistency extractedType := extractTupleField(tupType, ex.Index) if extractedType != "" { ssaType := e.llvmType(ex.SSAType()) if extractedType != ssaType { e.allocTypes[ex] = extractedType } } if tupType == "ptr" || tupType == "void" { elemType := e.llvmType(ex.SSAType()) if elemType == "void" { elemType = "ptr" } e.nextReg++ castReg := "%ev" | irItoa(e.nextReg) e.w(" ") ; e.w(castReg) ; e.w(" = getelementptr inbounds i8, ptr ") ; e.w(val) ; e.w(", i32 0\n") e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(castReg) ; e.w("\n") e.allocTypes[ex] = elemType return } e.w(" ") e.w(reg) e.w(" = extractvalue ") e.w(tupType) e.w(" ") e.w(val) e.w(", ") e.w(irItoa(ex.Index)) e.w("\n") } func extractTupleField(tupType string, index int32) string { if len(tupType) < 3 || tupType[0] != '{' { return "" } inner := tupType[1 : len(tupType)-1] depth := 0 field := 0 start := 0 for i := 0; i < len(inner); i++ { c := inner[i] if c == '{' { depth++ } else if c == '}' { depth-- } else if c == ',' && depth == 0 { if field == index { s := inner[start:i] for len(s) > 0 && s[0] == ' ' { s = s[1:] } for len(s) > 0 && s[len(s)-1] == ' ' { s = s[:len(s)-1] } return s } field++ start = i + 1 } } if field == index { s := inner[start:] for len(s) > 0 && s[0] == ' ' { s = s[1:] } for len(s) > 0 && s[len(s)-1] == ' ' { s = s[:len(s)-1] } return s } return "" } func (e *irEmitter) sextToIpt(val ssa.SSAValue, op string) string { ipt := e.intptrType() if val == nil { return op } valType := e.llvmType(val.SSAType()) if valType == ipt { return op } e.nextReg++ ext := "%sx" | irItoa(e.nextReg) srcBits := llvmTypeBits(valType) dstBits := llvmTypeBits(ipt) if srcBits > dstBits { e.w(" ") ; e.w(ext) ; e.w(" = trunc ") ; e.w(valType) ; e.w(" ") ; e.w(op) ; e.w(" to ") ; e.w(ipt) ; e.w("\n") } else { extOp := "sext" if b, ok := types.SafeUnderlying(val.SSAType()).(*types.Basic); ok && b.Info()&types.IsUnsigned != 0 { extOp = "zext" } e.w(" ") ; e.w(ext) ; e.w(" = ") ; e.w(extOp) ; e.w(" ") ; e.w(valType) ; e.w(" ") ; e.w(op) ; e.w(" to ") ; e.w(ipt) ; e.w("\n") } return ext } func (e *irEmitter) emitMakeChan(m *ssa.SSAMakeChan) { reg := e.regName(m) ipt := e.intptrType() elemType := "i8" if ch, ok := types.SafeUnderlying(m.SSAType()).(*types.TCChan); ok && ch.Elem() != nil { et := e.llvmType(ch.Elem()) if et != "void" && et != "" { elemType = et } } e.nextReg++ elemSz := "%mc" | irItoa(e.nextReg) e.w(" ") ; e.w(elemSz) ; e.w(" = ptrtoint ptr getelementptr (") e.w(elemType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n") bufSz := "0" if m.Size != nil { bufSz = e.sextToIpt(m.Size, e.operand(m.Size)) } e.w(" ") ; e.w(reg) ; e.w(" = call ptr @runtime.chanMake(") e.w(ipt) ; e.w(" ") ; e.w(elemSz) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(bufSz) ; e.w(")\n") e.declareRuntime("runtime.chanMake", "ptr", ipt | ", " | ipt) e.scopeTrackAlloc(reg) } func (e *irEmitter) chanElemType(chanType syntax.Type) string { if ch, ok := types.SafeUnderlying(chanType).(*types.TCChan); ok && ch.Elem() != nil { et := e.llvmType(ch.Elem()) if et != "void" && et != "" { return et } } return "i8" } func (e *irEmitter) emitChanRecv(u *ssa.SSAUnOp) { reg := e.regName(u) elemType := e.chanElemType(u.X.SSAType()) ch := e.operand(u.X) opType := "{ptr, ptr, i32, ptr}" e.nextReg++ valAlloca := "%chanrv" | irItoa(e.nextReg) e.w(" ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n") e.w(" store ") ; e.w(elemType) ; e.w(" zeroinitializer, ptr ") ; e.w(valAlloca) ; e.w("\n") e.nextReg++ opAlloca := "%chanrop" | irItoa(e.nextReg) e.w(" ") ; e.w(opAlloca) ; e.w(" = alloca ") ; e.w(opType) ; e.w("\n") e.w(" store ") ; e.w(opType) ; e.w(" zeroinitializer, ptr ") ; e.w(opAlloca) ; e.w("\n") e.nextReg++ okReg := "%chanrok" | irItoa(e.nextReg) e.w(" ") ; e.w(okReg) ; e.w(" = call i1 @runtime.chanRecv(ptr ") ; e.w(ch) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w(", ptr ") ; e.w(opAlloca) ; e.w(")\n") e.declareRuntime("runtime.chanRecv", "i1", "ptr, ptr, ptr") if u.CommaOk { e.nextReg++ loadedVal := "%chanrlv" | irItoa(e.nextReg) e.w(" ") ; e.w(loadedVal) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n") tupleType := "{" | elemType | ", i1}" e.nextReg++ t1 := "%chanrt1_" | irItoa(e.nextReg) e.w(" ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupleType) ; e.w(" zeroinitializer, ") ; e.w(elemType) ; e.w(" ") ; e.w(loadedVal) ; e.w(", 0\n") e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(tupleType) ; e.w(" ") ; e.w(t1) ; e.w(", i1 ") ; e.w(okReg) ; e.w(", 1\n") } else { e.w(" ") ; e.w(reg) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n") } } func (e *irEmitter) emitChanSend(s *ssa.SSASend) { elemType := e.chanElemType(s.Chan.SSAType()) ch := e.operand(s.Chan) val := e.operand(s.X) opType := "{ptr, ptr, i32, ptr}" e.nextReg++ valAlloca := "%chansv" | irItoa(e.nextReg) e.w(" ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n") valSrcType := e.llvmType(s.X.SSAType()) resolved := e.resolvedType(s.X, valSrcType) if resolved != valSrcType { valSrcType = resolved } if valSrcType == elemType { e.w(" store ") ; e.w(elemType) ; e.w(" ") ; e.w(val) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n") } else { e.w(" store ") ; e.w(valSrcType) ; e.w(" ") ; e.w(val) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n") } e.nextReg++ opAlloca := "%chansop" | irItoa(e.nextReg) e.w(" ") ; e.w(opAlloca) ; e.w(" = alloca ") ; e.w(opType) ; e.w("\n") e.w(" store ") ; e.w(opType) ; e.w(" zeroinitializer, ptr ") ; e.w(opAlloca) ; e.w("\n") e.w(" call void @runtime.chanSend(ptr ") ; e.w(ch) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w(", ptr ") ; e.w(opAlloca) ; e.w(")\n") e.declareRuntime("runtime.chanSend", "void", "ptr, ptr, ptr") } func (e *irEmitter) emitMakeSlice(m *ssa.SSAMakeSlice) { reg := e.regName(m) ipt := e.intptrType() sty := e.sliceType() lenOp := e.sextToIpt(m.Len, e.operand(m.Len)) capOp := lenOp if m.Cap != nil { capOp = e.sextToIpt(m.Cap, e.operand(m.Cap)) } var dataPtr string if m.Data != nil { dataPtr = e.operand(m.Data) } else { elemType := "i8" if sl, ok := types.SafeUnderlying(m.SSAType()).(*types.Slice); ok { elemType = e.llvmType(sl.Elem()) } e.nextReg++ elemSz := "%ms" | irItoa(e.nextReg) e.w(" ") e.w(elemSz) e.w(" = ptrtoint ptr getelementptr (") e.w(elemType) e.w(", ptr null, i32 1) to ") e.w(ipt) e.w("\n") e.nextReg++ allocSz := "%ms" | irItoa(e.nextReg) e.w(" ") e.w(allocSz) e.w(" = mul ") e.w(ipt) e.w(" ") e.w(elemSz) e.w(", ") e.w(capOp) e.w("\n") e.nextReg++ dataPtr = "%ms" | irItoa(e.nextReg) e.w(" ") e.w(dataPtr) e.w(" = call ptr @runtime.alloc(") e.w(ipt) e.w(" ") e.w(allocSz) e.w(", ptr null, ptr undef)\n") e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr") e.scopeTrackAlloc(dataPtr) } e.nextReg++ s1 := "%ms" | irItoa(e.nextReg) e.w(" ") e.w(s1) e.w(" = insertvalue ") e.w(sty) e.w(" undef, ptr ") e.w(dataPtr) e.w(", 0\n") e.nextReg++ s2 := "%ms" | irItoa(e.nextReg) e.w(" ") e.w(s2) e.w(" = insertvalue ") e.w(sty) e.w(" ") e.w(s1) e.w(", ") e.w(ipt) e.w(" ") e.w(lenOp) e.w(", 1\n") e.w(" ") e.w(reg) e.w(" = insertvalue ") e.w(sty) e.w(" ") e.w(s2) e.w(", ") e.w(ipt) e.w(" ") e.w(capOp) e.w(", 2\n") } func (e *irEmitter) emitSliceOp(s *ssa.SSASlice) { reg := e.regName(s) ipt := e.intptrType() sty := e.sliceType() src := e.operand(s.X) var oldPtr, oldLen, oldCap string srcType := types.SafeUnderlying(s.X.SSAType()) if p, ok := srcType.(*types.Pointer); ok && p.Elem() != nil { if arr, ok2 := types.SafeUnderlying(p.Elem()).(*types.Array); ok2 { oldPtr = src oldLen = irItoa64(arr.Len()) oldCap = oldLen srcType = nil } } if arr, ok := srcType.(*types.Array); ok { if uop, ok2 := s.X.(*ssa.SSAUnOp); ok2 && uop.Op == ssa.OpMul { oldPtr = e.operand(uop.X) } else { arrType := e.llvmType(s.X.SSAType()) e.nextReg++ tmp := "%sl" | irItoa(e.nextReg) e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n") e.w(" store ") ; e.w(arrType) ; e.w(" ") ; e.w(src) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n") oldPtr = tmp } oldLen = irItoa64(arr.Len()) oldCap = oldLen } else if oldPtr == "" { e.nextReg++ oldPtr = "%sl" | irItoa(e.nextReg) e.w(" ") e.w(oldPtr) e.w(" = extractvalue ") e.w(sty) e.w(" ") e.w(src) e.w(", 0\n") e.nextReg++ oldLen = "%sl" | irItoa(e.nextReg) e.w(" ") e.w(oldLen) e.w(" = extractvalue ") e.w(sty) e.w(" ") e.w(src) e.w(", 1\n") e.nextReg++ oldCap = "%sl" | irItoa(e.nextReg) e.w(" ") e.w(oldCap) e.w(" = extractvalue ") e.w(sty) e.w(" ") e.w(src) e.w(", 2\n") } low := "0" if s.Low != nil { low = e.sliceIdxToIpt(s.Low, ipt) } high := oldLen if s.High != nil { high = e.sliceIdxToIpt(s.High, ipt) } maxCap := oldCap if s.Max != nil { maxCap = e.sliceIdxToIpt(s.Max, ipt) } elemType := "i8" if sl, ok := types.SafeUnderlying(s.X.SSAType()).(*types.Slice); ok { elemType = e.llvmType(sl.Elem()) } else if ar, ok := types.SafeUnderlying(s.X.SSAType()).(*types.Array); ok { elemType = e.llvmType(ar.Elem()) } else if p, ok := types.SafeUnderlying(s.X.SSAType()).(*types.Pointer); ok && p.Elem() != nil { if ar, ok2 := types.SafeUnderlying(p.Elem()).(*types.Array); ok2 { elemType = e.llvmType(ar.Elem()) } } srcOff := e.nextReg2("sl") e.w(" ") ; e.w(srcOff) ; e.w(" = getelementptr inbounds ") ; e.w(elemType) e.w(", ptr ") ; e.w(oldPtr) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(low) ; e.w("\n") newLen := e.nextReg2("sl") e.w(" ") ; e.w(newLen) ; e.w(" = sub ") ; e.w(ipt) ; e.w(" ") ; e.w(high) ; e.w(", ") ; e.w(low) ; e.w("\n") elemSz := e.nextReg2("sl") e.w(" ") ; e.w(elemSz) ; e.w(" = ptrtoint ptr getelementptr (") e.w(elemType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n") totalBytes := e.nextReg2("sl") e.w(" ") ; e.w(totalBytes) ; e.w(" = mul ") ; e.w(ipt) ; e.w(" ") ; e.w(newLen) ; e.w(", ") ; e.w(elemSz) ; e.w("\n") freshPtr := e.nextReg2("sl") e.w(" ") ; e.w(freshPtr) ; e.w(" = call ptr @runtime.alloc(") ; e.w(ipt) e.w(" ") ; e.w(totalBytes) ; e.w(", ptr null, ptr null)\n") e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr") cpReg := e.nextReg2("sl") e.w(" ") ; e.w(cpReg) ; e.w(" = call ") ; e.w(ipt) ; e.w(" @runtime.sliceCopy(ptr ") ; e.w(freshPtr) e.w(", ptr ") ; e.w(srcOff) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newLen) e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newLen) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemSz) ; e.w(")\n") e.declareRuntime("runtime.sliceCopy", ipt, "ptr, ptr, " | ipt | ", " | ipt | ", " | ipt) s1 := e.nextReg2("sl") e.w(" ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(freshPtr) ; e.w(", 0\n") s2 := e.nextReg2("sl") e.w(" ") ; e.w(s2) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s1) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newLen) ; e.w(", 1\n") e.w(" ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s2) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newLen) ; e.w(", 2\n") } func (e *irEmitter) sliceIdxToIpt(val ssa.SSAValue, ipt string) string { operandStr := e.operand(val) valType := e.llvmType(val.SSAType()) if valType == "void" || valType == "ptr" { if at, ok := e.allocTypes[val]; ok && at != "ptr" && at != "void" { valType = at } else { valType = "i32" } } if valType == ipt { return operandStr } e.nextReg++ ext := "%sl" | irItoa(e.nextReg) srcBits := llvmTypeBits(valType) dstBits := llvmTypeBits(ipt) if srcBits > dstBits { e.w(" ") ; e.w(ext) ; e.w(" = trunc ") ; e.w(valType) ; e.w(" ") ; e.w(operandStr) ; e.w(" to ") ; e.w(ipt) ; e.w("\n") } else { op := "sext" if b, ok2 := types.SafeUnderlying(val.SSAType()).(*types.Basic); ok2 && b.Info()&types.IsUnsigned != 0 { op = "zext" } e.w(" ") ; e.w(ext) ; e.w(" = ") ; e.w(op) ; e.w(" ") ; e.w(valType) ; e.w(" ") ; e.w(operandStr) ; e.w(" to ") ; e.w(ipt) ; e.w("\n") } return ext }