avr: support ThinLTO
ThinLTO results in a small code size reduction, which is nice (especially on these very small chips). It also brings us one step closer to using ThinLTO everywhere.
Этот коммит содержится в:
		
							родитель
							
								
									5c622cfc43
								
							
						
					
					
						коммит
						4d14d3cd54
					
				
					 6 изменённых файлов: 38 добавлений и 18 удалений
				
			
		| 
						 | 
					@ -200,11 +200,6 @@ func (c *Config) UseThinLTO() bool {
 | 
				
			||||||
		// wasm-ld doesn't seem to support ThinLTO yet.
 | 
							// wasm-ld doesn't seem to support ThinLTO yet.
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if parts[0] == "avr" {
 | 
					 | 
				
			||||||
		// These use external (GNU) linkers which might perhaps support ThinLTO
 | 
					 | 
				
			||||||
		// through a plugin, but it's too much hassle to set up.
 | 
					 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// Other architectures support ThinLTO.
 | 
						// Other architectures support ThinLTO.
 | 
				
			||||||
	return true
 | 
						return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -196,21 +196,31 @@ func SplitBasicBlock(builder llvm.Builder, afterInst llvm.Value, insertAfter llv
 | 
				
			||||||
	return newBlock
 | 
						return newBlock
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Append the given values to the llvm.used array. The values can be any pointer
 | 
					// Append the given values to a global array like llvm.used. The global might
 | 
				
			||||||
// type, they will be bitcast to i8*.
 | 
					// not exist yet. The values can be any pointer type, they will be cast to i8*.
 | 
				
			||||||
func AppendToUsedGlobals(mod llvm.Module, values ...llvm.Value) {
 | 
					func AppendToGlobal(mod llvm.Module, globalName string, values ...llvm.Value) {
 | 
				
			||||||
	if !mod.NamedGlobal("llvm.used").IsNil() {
 | 
						// Read the existing values in the llvm.used array (if it exists).
 | 
				
			||||||
		// Sanity check. TODO: we don't emit such a global at the moment, but
 | 
						var usedValues []llvm.Value
 | 
				
			||||||
		// when we do we should append to it instead.
 | 
						if used := mod.NamedGlobal(globalName); !used.IsNil() {
 | 
				
			||||||
		panic("todo: append to existing llvm.used")
 | 
							builder := mod.Context().NewBuilder()
 | 
				
			||||||
 | 
							defer builder.Dispose()
 | 
				
			||||||
 | 
							usedInitializer := used.Initializer()
 | 
				
			||||||
 | 
							num := usedInitializer.Type().ArrayLength()
 | 
				
			||||||
 | 
							for i := 0; i < num; i++ {
 | 
				
			||||||
 | 
								usedValues = append(usedValues, builder.CreateExtractValue(usedInitializer, i, ""))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							used.EraseFromParentAsGlobal()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Add the new values.
 | 
				
			||||||
	i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
 | 
						i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
 | 
				
			||||||
	var castValues []llvm.Value
 | 
					 | 
				
			||||||
	for _, value := range values {
 | 
						for _, value := range values {
 | 
				
			||||||
		castValues = append(castValues, llvm.ConstBitCast(value, i8ptrType))
 | 
							usedValues = append(usedValues, llvm.ConstPointerCast(value, i8ptrType))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	usedInitializer := llvm.ConstArray(i8ptrType, castValues)
 | 
					
 | 
				
			||||||
	used := llvm.AddGlobal(mod, usedInitializer.Type(), "llvm.used")
 | 
						// Create a new array (with the old and new values).
 | 
				
			||||||
 | 
						usedInitializer := llvm.ConstArray(i8ptrType, usedValues)
 | 
				
			||||||
 | 
						used := llvm.AddGlobal(mod, usedInitializer.Type(), globalName)
 | 
				
			||||||
	used.SetInitializer(usedInitializer)
 | 
						used.SetInitializer(usedInitializer)
 | 
				
			||||||
	used.SetLinkage(llvm.AppendingLinkage)
 | 
						used.SetLinkage(llvm.AppendingLinkage)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,6 +150,19 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
 | 
				
			||||||
		// that the only thing we'll do is read the pointer.
 | 
							// that the only thing we'll do is read the pointer.
 | 
				
			||||||
		llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
 | 
							llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
 | 
				
			||||||
		llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
 | 
							llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
 | 
				
			||||||
 | 
						case "__mulsi3", "__divmodsi4", "__udivmodsi4":
 | 
				
			||||||
 | 
							if strings.Split(c.Triple, "-")[0] == "avr" {
 | 
				
			||||||
 | 
								// These functions are compiler-rt/libgcc functions that are
 | 
				
			||||||
 | 
								// currently implemented in Go. Assembly versions should appear in
 | 
				
			||||||
 | 
								// LLVM 16 hopefully. Until then, they need to be made available to
 | 
				
			||||||
 | 
								// the linker and the best way to do that is llvm.compiler.used.
 | 
				
			||||||
 | 
								// I considered adding a pragma for this, but the LLVM language
 | 
				
			||||||
 | 
								// reference explicitly says that this feature should not be exposed
 | 
				
			||||||
 | 
								// to source languages:
 | 
				
			||||||
 | 
								// > This is a rare construct that should only be used in rare
 | 
				
			||||||
 | 
								// > circumstances, and should not be exposed to source languages.
 | 
				
			||||||
 | 
								llvmutil.AppendToGlobal(c.mod, "llvm.compiler.used", llvmFn)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// External/exported functions may not retain pointer values.
 | 
						// External/exported functions may not retain pointer values.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,6 +40,8 @@ func procUnpin() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The following functions are workarounds for things missing in compiler-rt.
 | 
					// The following functions are workarounds for things missing in compiler-rt.
 | 
				
			||||||
// They will likely need special assembly implementations.
 | 
					// They will likely need special assembly implementations.
 | 
				
			||||||
 | 
					// They are treated specially: they're added to @llvm.compiler.used so that the
 | 
				
			||||||
 | 
					// linker won't eliminate them.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//export __mulsi3
 | 
					//export __mulsi3
 | 
				
			||||||
func __mulsi3(a, b uint32) uint32 {
 | 
					func __mulsi3(a, b uint32) uint32 {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@ MEMORY
 | 
				
			||||||
    RAM (xrw)       : ORIGIN = 0x800000 + __ram_start, LENGTH = __ram_size
 | 
					    RAM (xrw)       : ORIGIN = 0x800000 + __ram_start, LENGTH = __ram_size
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ENTRY(__vector_RESET)
 | 
					ENTRY(main)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SECTIONS
 | 
					SECTIONS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,7 @@ func CreateStackSizeLoads(mod llvm.Module, config *compileopts.Config) []string
 | 
				
			||||||
	stackSizesGlobal.SetInitializer(llvm.ConstArray(functions[0].Type(), defaultStackSizes))
 | 
						stackSizesGlobal.SetInitializer(llvm.ConstArray(functions[0].Type(), defaultStackSizes))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Add all relevant values to llvm.used (for LTO).
 | 
						// Add all relevant values to llvm.used (for LTO).
 | 
				
			||||||
	llvmutil.AppendToUsedGlobals(mod, append([]llvm.Value{stackSizesGlobal}, functionValues...)...)
 | 
						llvmutil.AppendToGlobal(mod, "llvm.used", append([]llvm.Value{stackSizesGlobal}, functionValues...)...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Replace the calls with loads from the new global with stack sizes.
 | 
						// Replace the calls with loads from the new global with stack sizes.
 | 
				
			||||||
	irbuilder := ctx.NewBuilder()
 | 
						irbuilder := ctx.NewBuilder()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче