Support maps bigger than 8 elements in .data
Этот коммит содержится в:
		
							родитель
							
								
									4ef271d4c6
								
							
						
					
					
						коммит
						68b1100c89
					
				
					 1 изменённых файлов: 67 добавлений и 22 удалений
				
			
		
							
								
								
									
										89
									
								
								compiler.go
									
										
									
									
									
								
							
							
						
						
									
										89
									
								
								compiler.go
									
										
									
									
									
								
							| 
						 | 
					@ -687,32 +687,14 @@ func (c *Compiler) parseInitFunc(frame *Frame) error {
 | 
				
			||||||
			case *ssa.FieldAddr, *ssa.IndexAddr:
 | 
								case *ssa.FieldAddr, *ssa.IndexAddr:
 | 
				
			||||||
				// Ignore: handled below with *ssa.Store.
 | 
									// Ignore: handled below with *ssa.Store.
 | 
				
			||||||
			case *ssa.MakeMap:
 | 
								case *ssa.MakeMap:
 | 
				
			||||||
				mapType := instr.Type().Underlying().(*types.Map)
 | 
					 | 
				
			||||||
				llvmKeyType, err := c.getLLVMType(mapType.Key().Underlying())
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					return err
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				llvmValueType, err := c.getLLVMType(mapType.Elem().Underlying())
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					return err
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				// TODO: use the initial map size
 | 
									// TODO: use the initial map size
 | 
				
			||||||
				bucketType := llvm.StructType([]llvm.Type{
 | 
									mapType := instr.Type().Underlying().(*types.Map)
 | 
				
			||||||
					llvm.ArrayType(llvm.Int8Type(), 8), // tophash
 | 
									bucket, keySize, valueSize, err := c.initMapNewBucket(mapType)
 | 
				
			||||||
					c.i8ptrType,                        // next bucket
 | 
					 | 
				
			||||||
					llvm.ArrayType(llvmKeyType, 8),     // key type
 | 
					 | 
				
			||||||
					llvm.ArrayType(llvmValueType, 8),   // value type
 | 
					 | 
				
			||||||
				}, false)
 | 
					 | 
				
			||||||
				bucket := llvm.AddGlobal(c.mod, bucketType, ".hashmap.bucket")
 | 
					 | 
				
			||||||
				bucketValue, err := getZeroValue(bucketType)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return err
 | 
										return err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				bucket.SetInitializer(bucketValue)
 | 
					 | 
				
			||||||
				zero := llvm.ConstInt(llvm.Int32Type(), 0, false)
 | 
									zero := llvm.ConstInt(llvm.Int32Type(), 0, false)
 | 
				
			||||||
				bucketPtr := llvm.ConstInBoundsGEP(bucket, []llvm.Value{zero})
 | 
									bucketPtr := llvm.ConstInBoundsGEP(bucket, []llvm.Value{zero})
 | 
				
			||||||
				keySize := c.targetData.TypeAllocSize(llvmKeyType)
 | 
					 | 
				
			||||||
				valueSize := c.targetData.TypeAllocSize(llvmValueType)
 | 
					 | 
				
			||||||
				hashmapType := c.mod.GetTypeByName("runtime.hashmap")
 | 
									hashmapType := c.mod.GetTypeByName("runtime.hashmap")
 | 
				
			||||||
				hashmap := llvm.ConstNamedStruct(hashmapType, []llvm.Value{
 | 
									hashmap := llvm.ConstNamedStruct(hashmapType, []llvm.Value{
 | 
				
			||||||
					llvm.ConstPointerNull(llvm.PointerType(hashmapType, 0)), // next
 | 
										llvm.ConstPointerNull(llvm.PointerType(hashmapType, 0)), // next
 | 
				
			||||||
| 
						 | 
					@ -768,9 +750,30 @@ func (c *Compiler) parseInitFunc(frame *Frame) error {
 | 
				
			||||||
						bucket = llvm.ConstInsertValue(bucket, llvmValue, []uint32{3, i})
 | 
											bucket = llvm.ConstInsertValue(bucket, llvmValue, []uint32{3, i})
 | 
				
			||||||
						bucketGlobal.SetInitializer(bucket)
 | 
											bucketGlobal.SetInitializer(bucket)
 | 
				
			||||||
						done = true
 | 
											done = true
 | 
				
			||||||
 | 
											break
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					if !done {
 | 
										if !done {
 | 
				
			||||||
						return errors.New("init: todo: allocate a new bucket")
 | 
											nextBucket := llvm.ConstExtractValue(bucket, []uint32{1})
 | 
				
			||||||
 | 
											if nextBucket.IsNull() {
 | 
				
			||||||
 | 
												// create new bucket
 | 
				
			||||||
 | 
												newBucketGlobal, _, _, err := c.initMapNewBucket(instr.Map.Type().Underlying().(*types.Map))
 | 
				
			||||||
 | 
												if err != nil {
 | 
				
			||||||
 | 
													return err
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												zero := llvm.ConstInt(llvm.Int32Type(), 0, false)
 | 
				
			||||||
 | 
												newBucketPtr := llvm.ConstInBoundsGEP(newBucketGlobal, []llvm.Value{zero})
 | 
				
			||||||
 | 
												newBucketPtrCast := llvm.ConstBitCast(newBucketPtr, c.i8ptrType)
 | 
				
			||||||
 | 
												newBucket := newBucketGlobal.Initializer()
 | 
				
			||||||
 | 
												// insert pointer into old bucket
 | 
				
			||||||
 | 
												bucket = llvm.ConstInsertValue(bucket, newBucketPtrCast, []uint32{1})
 | 
				
			||||||
 | 
												bucketGlobal.SetInitializer(bucket)
 | 
				
			||||||
 | 
												// switch to next bucket
 | 
				
			||||||
 | 
												bucketGlobal = newBucketGlobal
 | 
				
			||||||
 | 
												bucket = newBucket
 | 
				
			||||||
 | 
											} else {
 | 
				
			||||||
 | 
												bucketGlobal = nextBucket.Operand(0)
 | 
				
			||||||
 | 
												bucket = bucketGlobal.Initializer()
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			case *ssa.Slice:
 | 
								case *ssa.Slice:
 | 
				
			||||||
| 
						 | 
					@ -822,7 +825,9 @@ func (c *Compiler) parseInitFunc(frame *Frame) error {
 | 
				
			||||||
					if err != nil {
 | 
										if err != nil {
 | 
				
			||||||
						return err
 | 
											return err
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					if _, ok := instr.Val.Type().Underlying().(*types.Map); ok {
 | 
										switch valType := instr.Val.Type().Underlying().(type) {
 | 
				
			||||||
 | 
										case *types.Basic:
 | 
				
			||||||
 | 
										case *types.Map:
 | 
				
			||||||
						// Store pointer to map instead of the map itself. It is
 | 
											// Store pointer to map instead of the map itself. It is
 | 
				
			||||||
						// a reference type, so every access goes through a
 | 
											// a reference type, so every access goes through a
 | 
				
			||||||
						// pointer to the real value. Note that this has to be a
 | 
											// pointer to the real value. Note that this has to be a
 | 
				
			||||||
| 
						 | 
					@ -832,6 +837,19 @@ func (c *Compiler) parseInitFunc(frame *Frame) error {
 | 
				
			||||||
						hashmap.SetInitializer(val)
 | 
											hashmap.SetInitializer(val)
 | 
				
			||||||
						zero := llvm.ConstInt(llvm.Int32Type(), 0, false)
 | 
											zero := llvm.ConstInt(llvm.Int32Type(), 0, false)
 | 
				
			||||||
						val = llvm.ConstInBoundsGEP(hashmap, []llvm.Value{zero})
 | 
											val = llvm.ConstInBoundsGEP(hashmap, []llvm.Value{zero})
 | 
				
			||||||
 | 
										case *types.Pointer:
 | 
				
			||||||
 | 
											// Turn this into a pointer to a global object if it
 | 
				
			||||||
 | 
											// isn't already.
 | 
				
			||||||
 | 
											if val.IsConstant() && val.IsAGlobalVariable().IsNil() {
 | 
				
			||||||
 | 
												obj := llvm.AddGlobal(c.mod, val.Type(), ".obj")
 | 
				
			||||||
 | 
												obj.SetInitializer(val)
 | 
				
			||||||
 | 
												zero := llvm.ConstInt(llvm.Int32Type(), 0, false)
 | 
				
			||||||
 | 
												val = llvm.ConstInBoundsGEP(obj, []llvm.Value{zero})
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										case *types.Slice:
 | 
				
			||||||
 | 
										case *types.Struct:
 | 
				
			||||||
 | 
										default:
 | 
				
			||||||
 | 
											return errors.New("init: unknown store type: " + valType.String())
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					llvmAddr := c.ir.GetGlobal(addr).llvmGlobal
 | 
										llvmAddr := c.ir.GetGlobal(addr).llvmGlobal
 | 
				
			||||||
					llvmAddr.SetInitializer(val)
 | 
										llvmAddr.SetInitializer(val)
 | 
				
			||||||
| 
						 | 
					@ -878,6 +896,33 @@ func (c *Compiler) initParseValue(val ssa.Value, allocs map[ssa.Value]llvm.Value
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Create a new global hashmap bucket, for map initialization.
 | 
				
			||||||
 | 
					func (c *Compiler) initMapNewBucket(mapType *types.Map) (llvm.Value, uint64, uint64, error) {
 | 
				
			||||||
 | 
						llvmKeyType, err := c.getLLVMType(mapType.Key().Underlying())
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return llvm.Value{}, 0, 0, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						llvmValueType, err := c.getLLVMType(mapType.Elem().Underlying())
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return llvm.Value{}, 0, 0, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						keySize := c.targetData.TypeAllocSize(llvmKeyType)
 | 
				
			||||||
 | 
						valueSize := c.targetData.TypeAllocSize(llvmValueType)
 | 
				
			||||||
 | 
						bucketType := llvm.StructType([]llvm.Type{
 | 
				
			||||||
 | 
							llvm.ArrayType(llvm.Int8Type(), 8), // tophash
 | 
				
			||||||
 | 
							c.i8ptrType,                        // next bucket
 | 
				
			||||||
 | 
							llvm.ArrayType(llvmKeyType, 8),     // key type
 | 
				
			||||||
 | 
							llvm.ArrayType(llvmValueType, 8),   // value type
 | 
				
			||||||
 | 
						}, false)
 | 
				
			||||||
 | 
						bucket := llvm.AddGlobal(c.mod, bucketType, ".hashmap.bucket")
 | 
				
			||||||
 | 
						bucketValue, err := getZeroValue(bucketType)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return llvm.Value{}, 0, 0, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bucket.SetInitializer(bucketValue)
 | 
				
			||||||
 | 
						return bucket, keySize, valueSize, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Compiler) initStore(addr ssa.Value, val llvm.Value, allocs map[ssa.Value]llvm.Value) error {
 | 
					func (c *Compiler) initStore(addr ssa.Value, val llvm.Value, allocs map[ssa.Value]llvm.Value) error {
 | 
				
			||||||
	switch addr := addr.(type) {
 | 
						switch addr := addr.(type) {
 | 
				
			||||||
	case *ssa.FieldAddr:
 | 
						case *ssa.FieldAddr:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче