diff options
author | Ayke van Laethem <[email protected]> | 2021-04-11 00:51:48 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2021-04-12 08:11:28 +0200 |
commit | e7a05b6e74d0c7f91bc0049ec9bfca0bf65a78f7 (patch) | |
tree | 4e94b2594462ff0fae8430dff72039f75041b119 | |
parent | 2fd8f103ab61b8306025b91a8892c7608330b9e0 (diff) | |
download | tinygo-e7a05b6e74d0c7f91bc0049ec9bfca0bf65a78f7.tar.gz tinygo-e7a05b6e74d0c7f91bc0049ec9bfca0bf65a78f7.zip |
transform: do not lower zero-sized alloc to alloca
The LLVM CoroFrame pass appears to be tripping over this zero-sized
alloca. Therefore, do what the runtime would do: return a pointer to
runtime.zeroSizedAlloc. Or just don't deal with this case. But don't
emit a zero sized alloca to avoid this LLVM bug.
More information: https://bugs.llvm.org/show_bug.cgi?id=49916
-rw-r--r-- | transform/allocs.go | 12 | ||||
-rw-r--r-- | transform/testdata/allocs.ll | 10 | ||||
-rw-r--r-- | transform/testdata/allocs.out.ll | 8 |
3 files changed, 30 insertions, 0 deletions
diff --git a/transform/allocs.go b/transform/allocs.go index f21dde123..9cf15a1dc 100644 --- a/transform/allocs.go +++ b/transform/allocs.go @@ -43,6 +43,18 @@ func OptimizeAllocs(mod llvm.Module) { continue } + if size == 0 { + // If the size is 0, the pointer is allowed to alias other + // zero-sized pointers. Use the pointer to the global that would + // also be returned by runtime.alloc. + zeroSizedAlloc := mod.NamedGlobal("runtime.zeroSizedAlloc") + if !zeroSizedAlloc.IsNil() { + heapalloc.ReplaceAllUsesWith(zeroSizedAlloc) + heapalloc.EraseFromParentAsInstruction() + } + continue + } + // In general the pattern is: // %0 = call i8* @runtime.alloc(i32 %size) // %1 = bitcast i8* %0 to type* diff --git a/transform/testdata/allocs.ll b/transform/testdata/allocs.ll index 0511d79df..42932f4fe 100644 --- a/transform/testdata/allocs.ll +++ b/transform/testdata/allocs.ll @@ -1,6 +1,8 @@ target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" target triple = "armv7m-none-eabi" [email protected] = internal global i8 0, align 1 + declare nonnull i8* @runtime.alloc(i32) ; Test allocating a single int (i32) that should be allocated on the stack. @@ -68,6 +70,14 @@ end: ret void } +; Test a zero-sized allocation. +define void @testZeroSizedAlloc() { + %1 = call i8* @runtime.alloc(i32 0) + %2 = bitcast i8* %1 to i32* + %3 = call i32* @noescapeIntPtr(i32* %2) + ret void +} + declare i32* @escapeIntPtr(i32*) declare i32* @noescapeIntPtr(i32* nocapture) diff --git a/transform/testdata/allocs.out.ll b/transform/testdata/allocs.out.ll index eacf62b24..eaddd4645 100644 --- a/transform/testdata/allocs.out.ll +++ b/transform/testdata/allocs.out.ll @@ -1,6 +1,8 @@ target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" target triple = "armv7m-none-eabi" [email protected] = internal global i8 0, align 1 + declare nonnull i8* @runtime.alloc(i32) define void @testInt() { @@ -66,6 +68,12 @@ end: ; preds = %loop ret void } +define void @testZeroSizedAlloc() { + %1 = bitcast i8* @runtime.zeroSizedAlloc to i32* + %2 = call i32* @noescapeIntPtr(i32* %1) + ret void +} + declare i32* @escapeIntPtr(i32*) declare i32* @noescapeIntPtr(i32* nocapture) |