diff --git a/compiler.go b/compiler.go index 3aa70c3c..1c8c2c06 100644 --- a/compiler.go +++ b/compiler.go @@ -3129,6 +3129,17 @@ func (c *Compiler) ApplyFunctionSections() { } } +// Turn all global constants into global variables. This works around a +// limitation on Harvard architectures (e.g. AVR), where constant and +// non-constant pointers point to a different address space. +func (c *Compiler) NonConstGlobals() { + global := c.mod.FirstGlobal() + for !global.IsNil() { + global.SetGlobalConstant(false) + global = llvm.NextGlobal(global) + } +} + func (c *Compiler) Optimize(optLevel, sizeLevel int, inlinerThreshold uint) { builder := llvm.NewPassManagerBuilder() defer builder.Dispose() diff --git a/main.go b/main.go index 99e29414..4312ea4a 100644 --- a/main.go +++ b/main.go @@ -49,6 +49,18 @@ func Compile(pkgName, outpath string, spec *TargetSpec, printIR, dumpSSA bool, a return err } + // On the AVR, pointers can point either to flash or to RAM, but we don't + // know. As a temporary fix, load all global variables in RAM. + // In the future, there should be a compiler pass that determines which + // pointers are flash and which are in RAM so that pointers can have a + // correct address space parameter (address space 1 is for flash). + if strings.HasPrefix(spec.Triple, "avr") { + c.NonConstGlobals() + if err := c.Verify(); err != nil { + return err + } + } + // Generate output. if strings.HasSuffix(outpath, ".o") { return c.EmitObject(outpath)