aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2021-04-11 00:51:48 +0200
committerRon Evans <[email protected]>2021-04-12 08:11:28 +0200
commite7a05b6e74d0c7f91bc0049ec9bfca0bf65a78f7 (patch)
tree4e94b2594462ff0fae8430dff72039f75041b119
parent2fd8f103ab61b8306025b91a8892c7608330b9e0 (diff)
downloadtinygo-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.go12
-rw-r--r--transform/testdata/allocs.ll10
-rw-r--r--transform/testdata/allocs.out.ll8
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)