|
|
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
|
|
|
target triple = "wasm32-unknown-unknown-wasm"
|
|
|
|
|
|
|
|
%runtime.typecodeID = type { %runtime.typecodeID*, i32 }
|
|
|
|
%runtime.funcValueWithSignature = type { i32, %runtime.typecodeID* }
|
|
|
|
|
|
|
|
@"reflect/types.type:func:{basic:uint8}{}" = external constant %runtime.typecodeID
|
|
|
|
@"reflect/types.type:func:{basic:int}{}" = external constant %runtime.typecodeID
|
transform (func-lowering): remove specializations from function value lowering and fix lowering of a function value of an unimplemented type
Previously, the function value lowering pass had special cases for when there were 0 or 1 function implementations.
However, the results of the pass were incorrect in both of these cases.
This change removes the specializations and fixes the transformation.
In the case that there was a single function implementation, the compiler emitted a select instruction to obtain the function pointer.
This selected between null and the implementing function pointer.
While this was technically correct, it failed to eliminate indirect function calls.
This prevented discovery of these calls by the coroutine lowering pass, and caused async function calls to be passed through unlowered.
As a result, the generated code had undefined behavior (usually resulting in a segfault).
In the case of no function implementations, the lowering code was correct.
However, the lowering code was not run.
The discovery of function signatures was accomplished by scanning implementations, and when there were no implementations nothing was discovered or lowered.
For maintainability reasons, I have removed both specializations rather than fixing them.
This substantially simplifies the code, and reduces the amount of variation that we need to worry about for testing purposes.
The IR now generated in the cases of 0 or 1 function implementations can be efficiently simplified by LLVM's optimization passes.
Therefore, there should not be a substantial regression in terms of performance or machine code size.
5 years ago
|
|
|
@"reflect/types.type:func:{}{basic:uint32}" = external constant %runtime.typecodeID
|
|
|
|
@"func1Uint8$withSignature" = constant %runtime.funcValueWithSignature { i32 ptrtoint (void (i8, i8*, i8*)* @func1Uint8 to i32), %runtime.typecodeID* @"reflect/types.type:func:{basic:uint8}{}" }
|
|
|
|
@"func2Uint8$withSignature" = constant %runtime.funcValueWithSignature { i32 ptrtoint (void (i8, i8*, i8*)* @func2Uint8 to i32), %runtime.typecodeID* @"reflect/types.type:func:{basic:uint8}{}" }
|
|
|
|
@"main$withSignature" = constant %runtime.funcValueWithSignature { i32 ptrtoint (void (i32, i8*, i8*)* @"main$1" to i32), %runtime.typecodeID* @"reflect/types.type:func:{basic:int}{}" }
|
|
|
|
@"main$2$withSignature" = constant %runtime.funcValueWithSignature { i32 ptrtoint (void (i32, i8*, i8*)* @"main$2" to i32), %runtime.typecodeID* @"reflect/types.type:func:{basic:int}{}" }
|
|
|
|
|
|
|
|
declare i32 @runtime.getFuncPtr(i8*, i32, %runtime.typecodeID*, i8*, i8*)
|
|
|
|
|
|
|
|
declare void @"internal/task.start"(i32, i8*, i8*, i8*)
|
|
|
|
|
|
|
|
declare void @runtime.nilPanic(i8*, i8*)
|
|
|
|
|
|
|
|
declare void @"main$1"(i32, i8*, i8*)
|
|
|
|
|
|
|
|
declare void @"main$2"(i32, i8*, i8*)
|
|
|
|
|
|
|
|
declare void @func1Uint8(i8, i8*, i8*)
|
|
|
|
|
|
|
|
declare void @func2Uint8(i8, i8*, i8*)
|
|
|
|
|
transform (func-lowering): remove specializations from function value lowering and fix lowering of a function value of an unimplemented type
Previously, the function value lowering pass had special cases for when there were 0 or 1 function implementations.
However, the results of the pass were incorrect in both of these cases.
This change removes the specializations and fixes the transformation.
In the case that there was a single function implementation, the compiler emitted a select instruction to obtain the function pointer.
This selected between null and the implementing function pointer.
While this was technically correct, it failed to eliminate indirect function calls.
This prevented discovery of these calls by the coroutine lowering pass, and caused async function calls to be passed through unlowered.
As a result, the generated code had undefined behavior (usually resulting in a segfault).
In the case of no function implementations, the lowering code was correct.
However, the lowering code was not run.
The discovery of function signatures was accomplished by scanning implementations, and when there were no implementations nothing was discovered or lowered.
For maintainability reasons, I have removed both specializations rather than fixing them.
This substantially simplifies the code, and reduces the amount of variation that we need to worry about for testing purposes.
The IR now generated in the cases of 0 or 1 function implementations can be efficiently simplified by LLVM's optimization passes.
Therefore, there should not be a substantial regression in terms of performance or machine code size.
5 years ago
|
|
|
define i32 @runFuncNone(i8* %0, i32 %1, i8* %context, i8* %parentHandle) {
|
|
|
|
entry:
|
transform (func-lowering): remove specializations from function value lowering and fix lowering of a function value of an unimplemented type
Previously, the function value lowering pass had special cases for when there were 0 or 1 function implementations.
However, the results of the pass were incorrect in both of these cases.
This change removes the specializations and fixes the transformation.
In the case that there was a single function implementation, the compiler emitted a select instruction to obtain the function pointer.
This selected between null and the implementing function pointer.
While this was technically correct, it failed to eliminate indirect function calls.
This prevented discovery of these calls by the coroutine lowering pass, and caused async function calls to be passed through unlowered.
As a result, the generated code had undefined behavior (usually resulting in a segfault).
In the case of no function implementations, the lowering code was correct.
However, the lowering code was not run.
The discovery of function signatures was accomplished by scanning implementations, and when there were no implementations nothing was discovered or lowered.
For maintainability reasons, I have removed both specializations rather than fixing them.
This substantially simplifies the code, and reduces the amount of variation that we need to worry about for testing purposes.
The IR now generated in the cases of 0 or 1 function implementations can be efficiently simplified by LLVM's optimization passes.
Therefore, there should not be a substantial regression in terms of performance or machine code size.
5 years ago
|
|
|
br i1 false, label %fpcall.nil, label %fpcall.next
|
|
|
|
|
|
|
|
fpcall.nil: ; preds = %entry
|
|
|
|
call void @runtime.nilPanic(i8* undef, i8* null)
|
|
|
|
unreachable
|
|
|
|
|
|
|
|
fpcall.next: ; preds = %entry
|
transform (func-lowering): remove specializations from function value lowering and fix lowering of a function value of an unimplemented type
Previously, the function value lowering pass had special cases for when there were 0 or 1 function implementations.
However, the results of the pass were incorrect in both of these cases.
This change removes the specializations and fixes the transformation.
In the case that there was a single function implementation, the compiler emitted a select instruction to obtain the function pointer.
This selected between null and the implementing function pointer.
While this was technically correct, it failed to eliminate indirect function calls.
This prevented discovery of these calls by the coroutine lowering pass, and caused async function calls to be passed through unlowered.
As a result, the generated code had undefined behavior (usually resulting in a segfault).
In the case of no function implementations, the lowering code was correct.
However, the lowering code was not run.
The discovery of function signatures was accomplished by scanning implementations, and when there were no implementations nothing was discovered or lowered.
For maintainability reasons, I have removed both specializations rather than fixing them.
This substantially simplifies the code, and reduces the amount of variation that we need to worry about for testing purposes.
The IR now generated in the cases of 0 or 1 function implementations can be efficiently simplified by LLVM's optimization passes.
Therefore, there should not be a substantial regression in terms of performance or machine code size.
5 years ago
|
|
|
switch i32 %1, label %func.default [
|
|
|
|
i32 0, label %func.nil
|
|
|
|
]
|
|
|
|
|
|
|
|
func.nil: ; preds = %fpcall.next
|
|
|
|
call void @runtime.nilPanic(i8* undef, i8* null)
|
|
|
|
unreachable
|
|
|
|
|
|
|
|
func.next: ; No predecessors!
|
|
|
|
ret i32 undef
|
|
|
|
|
|
|
|
func.default: ; preds = %fpcall.next
|
|
|
|
unreachable
|
|
|
|
}
|
|
|
|
|
|
|
|
define void @runFunc2(i8* %0, i32 %1, i8 %2, i8* %context, i8* %parentHandle) {
|
|
|
|
entry:
|
|
|
|
br i1 false, label %fpcall.nil, label %fpcall.next
|
|
|
|
|
|
|
|
fpcall.nil: ; preds = %entry
|
|
|
|
call void @runtime.nilPanic(i8* undef, i8* null)
|
|
|
|
unreachable
|
|
|
|
|
|
|
|
fpcall.next: ; preds = %entry
|
|
|
|
switch i32 %1, label %func.default [
|
|
|
|
i32 0, label %func.nil
|
|
|
|
i32 1, label %func.call1
|
|
|
|
i32 2, label %func.call2
|
|
|
|
]
|
|
|
|
|
|
|
|
func.nil: ; preds = %fpcall.next
|
|
|
|
call void @runtime.nilPanic(i8* undef, i8* null)
|
|
|
|
unreachable
|
|
|
|
|
|
|
|
func.call1: ; preds = %fpcall.next
|
|
|
|
call void @func1Uint8(i8 %2, i8* %0, i8* undef)
|
|
|
|
br label %func.next
|
|
|
|
|
|
|
|
func.call2: ; preds = %fpcall.next
|
|
|
|
call void @func2Uint8(i8 %2, i8* %0, i8* undef)
|
|
|
|
br label %func.next
|
|
|
|
|
|
|
|
func.next: ; preds = %func.call2, %func.call1
|
|
|
|
ret void
|
|
|
|
|
|
|
|
func.default: ; preds = %fpcall.next
|
|
|
|
unreachable
|
|
|
|
}
|
|
|
|
|
|
|
|
define void @sleepFuncValue(i8* %0, i32 %1, i8* nocapture readnone %context, i8* nocapture readnone %parentHandle) {
|
|
|
|
entry:
|
|
|
|
switch i32 %1, label %func.default [
|
|
|
|
i32 0, label %func.nil
|
|
|
|
i32 1, label %func.call1
|
|
|
|
i32 2, label %func.call2
|
|
|
|
]
|
|
|
|
|
|
|
|
func.nil: ; preds = %entry
|
|
|
|
call void @runtime.nilPanic(i8* undef, i8* null)
|
|
|
|
unreachable
|
|
|
|
|
|
|
|
func.call1: ; preds = %entry
|
|
|
|
call void @"internal/task.start"(i32 ptrtoint (void (i32, i8*, i8*)* @"main$1" to i32), i8* null, i8* undef, i8* null)
|
|
|
|
br label %func.next
|
|
|
|
|
|
|
|
func.call2: ; preds = %entry
|
|
|
|
call void @"internal/task.start"(i32 ptrtoint (void (i32, i8*, i8*)* @"main$2" to i32), i8* null, i8* undef, i8* null)
|
|
|
|
br label %func.next
|
|
|
|
|
|
|
|
func.next: ; preds = %func.call2, %func.call1
|
|
|
|
ret void
|
|
|
|
|
|
|
|
func.default: ; preds = %entry
|
|
|
|
unreachable
|
|
|
|
}
|