diff --git a/builder/build.go b/builder/build.go index f728cde79d..5f11803122 100644 --- a/builder/build.go +++ b/builder/build.go @@ -747,6 +747,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe } ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU()) ldflags = append(ldflags, "-mllvm", "-mattr="+config.Features()) // needed for MIPS softfloat + ldflags = append(ldflags, "-mllvm", "-wasm-enable-eh") if config.GOOS() == "windows" { // Options for the MinGW wrapper for the lld COFF linker. ldflags = append(ldflags, diff --git a/compiler/calls.go b/compiler/calls.go index f4b76a5135..3b03f39755 100644 --- a/compiler/calls.go +++ b/compiler/calls.go @@ -70,21 +70,25 @@ func (b *builder) createRuntimeInvoke(fnName string, args []llvm.Value, name str // createCall creates a call to the given function with the arguments possibly // expanded. func (b *builder) createCall(fnType llvm.Type, fn llvm.Value, args []llvm.Value, name string) llvm.Value { - expanded := make([]llvm.Value, 0, len(args)) - for _, arg := range args { - fragments := b.expandFormalParam(arg) - expanded = append(expanded, fragments...) - } - return b.CreateCall(fnType, fn, expanded, name) + return b.CreateCall(fnType, fn, b.expandFormalParams(args), name) } // createInvoke is like createCall but continues execution at the landing pad if // the call resulted in a panic. func (b *builder) createInvoke(fnType llvm.Type, fn llvm.Value, args []llvm.Value, name string) llvm.Value { - if b.hasDeferFrame() { + switch b.deferFrameType() { + case recoverInlineAsm: b.createInvokeCheckpoint() + return b.createCall(fnType, fn, args, name) + case recoverWasmEH: + continueBB := b.insertBasicBlock("invoke.cont") + call := b.CreateInvoke(fnType, fn, b.expandFormalParams(args), continueBB, b.landingpad, name) + b.SetInsertPointAtEnd(continueBB) + b.blockExits[b.currentBlock] = continueBB + return call + default: + return b.createCall(fnType, fn, args, name) } - return b.createCall(fnType, fn, args, name) } // Expand an argument type to a list that can be used in a function call @@ -123,6 +127,17 @@ func (b *builder) expandFormalParamOffsets(t llvm.Type) []uint64 { } } +// expandFormalParams expands every param in the params slice like +// expandFormalParam. +func (b *builder) expandFormalParams(params []llvm.Value) []llvm.Value { + expanded := make([]llvm.Value, 0, len(params)) + for _, arg := range params { + fragments := b.expandFormalParam(arg) + expanded = append(expanded, fragments...) + } + return expanded +} + // expandFormalParam splits a formal param value into pieces, so it can be // passed directly as part of a function call. For example, it splits up small // structs into individual fields. It is the equivalent of expandFormalParamType diff --git a/compiler/compiler.go b/compiler/compiler.go index bc17250d99..dcf4c1a832 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -355,7 +355,10 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package, } func (c *compilerContext) getRuntimeType(name string) types.Type { - return c.runtimePkg.Scope().Lookup(name).(*types.TypeName).Type() + if typ, ok := c.runtimePkg.Scope().Lookup(name).(*types.TypeName); ok { + return typ.Type() + } + panic("runtime type not found: " + name) } // getLLVMRuntimeType obtains a named type from the runtime package and returns @@ -1350,7 +1353,7 @@ func (b *builder) createFunction() { b.CreateBr(b.afterDefersBlock[i]) } - if b.hasDeferFrame() { + if b.deferFrameType() != recoverNone { // Create the landing pad block, where execution continues after a // panic. b.createLandingPad() @@ -1487,8 +1490,11 @@ func (b *builder) createInstruction(instr ssa.Instruction) { b.createRuntimeInvoke("_panic", []llvm.Value{value}, "") b.CreateUnreachable() case *ssa.Return: - if b.hasDeferFrame() { - b.createRuntimeCall("destroyDeferFrame", []llvm.Value{b.deferFrame}, "") + switch b.deferFrameType() { + case recoverInlineAsm: + b.createRuntimeCall("destroyDeferFrameInlineAsm", []llvm.Value{b.deferFrame}, "") + case recoverWasmEH: + b.createRuntimeCall("destroyDeferFrameWasmEH", []llvm.Value{b.deferFrame}, "") } if len(instr.Results) == 0 { b.CreateRetVoid() @@ -1741,7 +1747,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c return b.CreateExtractValue(cplx, 0, "real"), nil case "recover": useParentFrame := uint64(0) - if b.hasDeferFrame() { + if b.fn.Recover != nil { // recover() should return the panic value of the parent function, // not of the current function. useParentFrame = 1 @@ -1851,11 +1857,8 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error) case strings.HasPrefix(name, "syscall.rawSyscallNoError") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscallNoError"): return b.createRawSyscallNoError(instr) case name == "runtime.supportsRecover": - supportsRecover := uint64(0) - if b.supportsRecover() { - supportsRecover = 1 - } - return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil + supportsRecover := uint64(b.supportsRecover()) + return llvm.ConstInt(b.ctx.Int8Type(), supportsRecover, false), nil case name == "runtime.panicStrategy": // These constants are defined in src/runtime/panic.go. panicStrategy := map[string]uint64{ diff --git a/compiler/compiler_test.go b/compiler/compiler_test.go index 2e5094875c..c27cd9db09 100644 --- a/compiler/compiler_test.go +++ b/compiler/compiler_test.go @@ -44,6 +44,7 @@ func TestCompiler(t *testing.T) { {"interface.go", "", ""}, {"func.go", "", ""}, {"defer.go", "cortex-m-qemu", ""}, + {"defer.go", "wasm", "none"}, {"pragma.go", "", ""}, {"goroutine.go", "wasm", "asyncify"}, {"goroutine.go", "cortex-m-qemu", "tasks"}, diff --git a/compiler/defer.go b/compiler/defer.go index df8686957a..f71a92644c 100644 --- a/compiler/defer.go +++ b/compiler/defer.go @@ -16,34 +16,54 @@ package compiler import ( "go/types" "strconv" + "strings" "github.com/tinygo-org/tinygo/compiler/llvmutil" "golang.org/x/tools/go/ssa" "tinygo.org/x/go-llvm" ) +type recoverType uint8 + +const ( + // Note: this matches recoverSupport in src/runtime/panic.go + recoverNone recoverType = iota + recoverInlineAsm + recoverWasmEH // WebAssembly exception handling +) + // supportsRecover returns whether the compiler supports the recover() builtin // for the current architecture. -func (b *builder) supportsRecover() bool { - switch b.archFamily() { +func (c *compilerContext) supportsRecover() recoverType { + switch c.archFamily() { case "wasm32": - // Probably needs to be implemented using the exception handling - // proposal of WebAssembly: - // https://github.com/WebAssembly/exception-handling - return false + if !strings.Contains(c.Features, "+exception-handling") { + // No support for the exception handling proposal. + return recoverNone + } + if c.Scheduler == "asyncify" { + // Asyncify does not support WebAssembly exception handling. + // It exits with the following message: + // unexpected expression type + // UNREACHABLE executed at $TINYGOROOT/lib/binaryen/src/passes/Asyncify.cpp:1142! + // See: https://github.com/WebAssembly/binaryen/issues/4470 + return recoverNone + } + // Use WebAssembly exception handling. + return recoverWasmEH case "riscv64", "xtensa": // TODO: add support for these architectures - return false + return recoverNone default: - return true + return recoverInlineAsm } } -// hasDeferFrame returns whether the current function needs to catch panics and -// run defers. -func (b *builder) hasDeferFrame() bool { +// deferFrameType returns the defer type for this function. It is always +// recoverNone for functions without defer. +func (b *builder) deferFrameType() recoverType { if b.fn.Recover == nil { - return false + return recoverNone } return b.supportsRecover() } @@ -63,21 +83,40 @@ func (b *builder) deferInitFunc() { b.deferPtr = b.CreateAlloca(b.dataPtrType, "deferPtr") b.CreateStore(llvm.ConstPointerNull(b.dataPtrType), b.deferPtr) - if b.hasDeferFrame() { + switch b.deferFrameType() { + case recoverInlineAsm: // Set up the defer frame with the current stack pointer. // This assumes that the stack pointer doesn't move outside of the // function prologue/epilogue (an invariant maintained by TinyGo but // possibly broken by the C alloca function). // The frame pointer is _not_ saved, because it is marked as clobbered // in the setjmp-like inline assembly. - deferFrameType := b.getLLVMRuntimeType("deferFrame") + deferFrameType := b.getLLVMRuntimeType("deferFrameInlineAsm") b.deferFrame = b.CreateAlloca(deferFrameType, "deferframe.buf") stackPointer := b.readStackPointer() - b.createRuntimeCall("setupDeferFrame", []llvm.Value{b.deferFrame, stackPointer}, "") + b.createRuntimeCall("setupDeferFrameInlineAsm", []llvm.Value{b.deferFrame, stackPointer}, "") // Create the landing pad block, which is where control transfers after // a panic. b.landingpad = b.ctx.AddBasicBlock(b.llvmFn, "lpad") + case recoverWasmEH: + // Set a personality function, which is required by LLVM but not + // actually called. __gxx_wasm_personality_v0 is the only one that is + // acceptable to the WebAssembly backend it seems. + personality := b.mod.NamedFunction("__gxx_wasm_personality_v0") + if personality.IsNil() { + fnType := llvm.FunctionType(b.ctx.Int32Type(), nil, true) + personality = llvm.AddFunction(b.mod, "__gxx_wasm_personality_v0", fnType) + } + b.llvmFn.SetPersonality(personality) + + // Set up the defer frame. + deferFrameType := b.getLLVMRuntimeType("deferFrameWasmEH") + b.deferFrame = b.CreateAlloca(deferFrameType, "deferframe.buf") + b.createRuntimeCall("setupDeferFrameWasmEH", []llvm.Value{b.deferFrame}, "") + + // Create the landing pad where the 'throw' instruction will jump to. + b.landingpad = b.ctx.AddBasicBlock(b.llvmFn, "catch.dispatch") } } @@ -95,6 +134,43 @@ func (b *builder) createLandingPad() { b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{}) } + if b.supportsRecover() == recoverWasmEH { + // Insert exception handling instructions. + // This emulates C++ exceptions, as if every function is wrapped like + // this: + // + // try { + // function body + // } catch (...) { + // run all defers + // } + // if deferFrame.Panicking { + // // re-raise the same panic message + // panic(previousPanic) + // } + // + // This means that if there is a C++ exception in the program, it will + // get eaten by the Go code. This is fixable if needed (by checking + // whether it's actually a TinyGo exception and re-raising the same + // exception if it isn't after running deferred functions). + // For more information about C++ exception support in WebAssembly: + // https://github.com/WebAssembly/tool-conventions/blob/main/EHScheme.md + + // basic block: catch.dispatch + catchStartBB := b.insertBasicBlock("catch.start") + catchswitch := b.CreateCatchSwitch(llvm.Value{}, llvm.BasicBlock{}, 1, "") + catchswitch.AddHandler(catchStartBB) + + // basic block: catch.start + b.SetInsertPointAtEnd(catchStartBB) + catchpad := b.CreateCatchPad(catchswitch, []llvm.Value{llvm.ConstNull(b.dataPtrType)}, "") + rundefersBB := b.insertBasicBlock("rundefers") + b.CreateCatchRet(catchpad, rundefersBB) + + // basic block: rundefers + b.SetInsertPointAtEnd(rundefersBB) + } + b.createRunDefers() // Continue at the 'recover' block, which returns to the parent in an @@ -432,11 +508,25 @@ func (b *builder) createRunDefers() { // } // } - // Create loop, in the order: loophead, loop, callback0, callback1, ..., unreachable, end. + // Create loop, in the order: + // - loophead + // - loop + // - callback0 + // - callback1 + // - callback* + // - unreachable + // - catch.dispatch (if wasm EH) + // - catch.start (if wasm EH) + // - end + var catchDispatch, catchStart llvm.BasicBlock end := b.insertBasicBlock("rundefers.end") unreachable := b.ctx.InsertBasicBlock(end, "rundefers.default") loop := b.ctx.InsertBasicBlock(unreachable, "rundefers.loop") loophead := b.ctx.InsertBasicBlock(loop, "rundefers.loophead") + if b.supportsRecover() == recoverWasmEH { + catchDispatch = b.ctx.InsertBasicBlock(end, "rundefers.catch.dispatch") + catchStart = b.ctx.InsertBasicBlock(end, "rundefers.catch.start") + } b.CreateBr(loophead) // Create loop head: @@ -471,6 +561,9 @@ func (b *builder) createRunDefers() { block := b.insertBasicBlock("rundefers.callback" + strconv.Itoa(i)) sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), block) b.SetInsertPointAtEnd(block) + var fnType llvm.Type + var llvmFn llvm.Value + var forwardParams []llvm.Value switch callback := callback.(type) { case *ssa.CallCommon: // Call on an value or interface value. @@ -491,7 +584,6 @@ func (b *builder) createRunDefers() { } // Extract the params from the struct (including receiver). - forwardParams := []llvm.Value{} zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false) deferredCallType := b.ctx.StructType(valueTypes, false) for i := 2; i < len(valueTypes); i++ { @@ -500,9 +592,6 @@ func (b *builder) createRunDefers() { forwardParams = append(forwardParams, forwardParam) } - var fnPtr llvm.Value - var fnType llvm.Type - if !callback.IsInvoke() { // Isolate the func value. funcValue := forwardParams[0] @@ -510,7 +599,7 @@ func (b *builder) createRunDefers() { //Get function pointer and context var context llvm.Value - fnPtr, context = b.decodeFuncValue(funcValue) + llvmFn, context = b.decodeFuncValue(funcValue) fnType = b.getLLVMFunctionType(callback.Signature()) //Pass context @@ -519,8 +608,8 @@ func (b *builder) createRunDefers() { // Move typecode from the start to the end of the list of // parameters. forwardParams = append(forwardParams[1:], forwardParams[0]) - fnPtr = b.getInvokeFunction(callback) - fnType = fnPtr.GlobalValueType() + llvmFn = b.getInvokeFunction(callback) + fnType = llvmFn.GlobalValueType() // Add the context parameter. An interface call cannot also be a // closure but we have to supply the parameter anyway for platforms @@ -528,8 +617,6 @@ func (b *builder) createRunDefers() { forwardParams = append(forwardParams, llvm.Undef(b.dataPtrType)) } - b.createCall(fnType, fnPtr, forwardParams, "") - case *ssa.Function: // Direct call. @@ -541,7 +628,6 @@ func (b *builder) createRunDefers() { deferredCallType := b.ctx.StructType(valueTypes, false) // Extract the params from the struct. - forwardParams := []llvm.Value{} zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false) for i := range getParams(callback.Signature) { gep := b.CreateInBoundsGEP(deferredCallType, deferData, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep") @@ -557,9 +643,7 @@ func (b *builder) createRunDefers() { forwardParams = append(forwardParams, llvm.Undef(b.dataPtrType)) } - // Call real function. - fnType, fn := b.getFunction(callback) - b.createInvoke(fnType, fn, forwardParams, "") + fnType, llvmFn = b.getFunction(callback) case *ssa.MakeClosure: // Get the real defer struct type and cast to it. @@ -573,7 +657,6 @@ func (b *builder) createRunDefers() { deferredCallType := b.ctx.StructType(valueTypes, false) // Extract the params from the struct. - forwardParams := []llvm.Value{} zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false) for i := 2; i < len(valueTypes); i++ { gep := b.CreateInBoundsGEP(deferredCallType, deferData, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)}, "") @@ -582,8 +665,7 @@ func (b *builder) createRunDefers() { } // Call deferred function. - fnType, llvmFn := b.getFunction(fn) - b.createCall(fnType, llvmFn, forwardParams, "") + fnType, llvmFn = b.getFunction(fn) case *ssa.Builtin: db := b.deferBuiltinFuncs[callback] @@ -611,12 +693,20 @@ func (b *builder) createRunDefers() { if err != nil { b.diagnostics = append(b.diagnostics, err) } + b.CreateBr(loophead) + continue default: panic("unknown deferred function type") } - // Branch back to the start of the loop. - b.CreateBr(loophead) + // Call the deferred function. + if b.supportsRecover() == recoverWasmEH { + b.CreateInvoke(fnType, llvmFn, b.expandFormalParams(forwardParams), loophead, catchDispatch, "") + } else { + b.createInvoke(fnType, llvmFn, forwardParams, "") + // Branch back to the start of the loop. + b.CreateBr(loophead) + } } // Create default unreachable block: @@ -626,6 +716,19 @@ func (b *builder) createRunDefers() { b.SetInsertPointAtEnd(unreachable) b.CreateUnreachable() + // Ignore any exception that might have occured while running the deferred + // functions. The compiler will insert a check whether the function is still + // panicking before return, so no panic gets lost. + if b.supportsRecover() == recoverWasmEH { + b.SetInsertPointAtEnd(catchDispatch) + catchswitch := b.CreateCatchSwitch(llvm.Value{}, llvm.BasicBlock{}, 1, "") + catchswitch.AddHandler(catchStart) + + b.SetInsertPointAtEnd(catchStart) + catchpad := b.CreateCatchPad(catchswitch, []llvm.Value{llvm.ConstNull(b.dataPtrType)}, "") + b.CreateCatchRet(catchpad, loophead) + } + // End of loop. b.SetInsertPointAtEnd(end) } diff --git a/compiler/symbol.go b/compiler/symbol.go index 5ebdee1471..d2a722d23b 100644 --- a/compiler/symbol.go +++ b/compiler/symbol.go @@ -174,6 +174,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value) // 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("readonly"), 0)) + llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nounwind"), 0)) case "__mulsi3", "__divmodsi4", "__udivmodsi4": if strings.Split(c.Triple, "-")[0] == "avr" { // These functions are compiler-rt/libgcc functions that are @@ -470,7 +471,9 @@ func (c *compilerContext) addStandardDefinedAttributes(llvmFn llvm.Value) { // This behavior matches Clang when compiling C source files. // It reduces binary size on Linux a little bit on non-x86_64 targets by // eliminating exception tables for these functions. - llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nounwind"), 0)) + if c.supportsRecover() != recoverWasmEH { + llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nounwind"), 0)) + } if strings.Split(c.Triple, "-")[0] == "x86_64" { // Required by the ABI. // The uwtable has two possible values: sync (1) or async (2). We use diff --git a/compiler/testdata/basic.ll b/compiler/testdata/basic.ll index e81d5f2a6a..7d30554074 100644 --- a/compiler/testdata/basic.ll +++ b/compiler/testdata/basic.ll @@ -13,30 +13,31 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 { +define hidden i32 @main.addInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 { entry: %0 = add i32 %x, %y ret i32 %0 } ; Function Attrs: nounwind -define hidden i1 @main.equalInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 { +define hidden i1 @main.equalInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 { entry: %0 = icmp eq i32 %x, %y ret i1 %0 } ; Function Attrs: nounwind -define hidden i32 @main.divInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 { +define hidden i32 @main.divInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 { entry: %0 = icmp eq i32 %y, 0 br i1 %0, label %divbyzero.throw, label %divbyzero.next @@ -54,10 +55,10 @@ divbyzero.throw: ; preds = %entry unreachable } -declare void @runtime.divideByZeroPanic(ptr) #1 +declare void @runtime.divideByZeroPanic(ptr) #2 ; Function Attrs: nounwind -define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 { +define hidden i32 @main.divUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 { entry: %0 = icmp eq i32 %y, 0 br i1 %0, label %divbyzero.throw, label %divbyzero.next @@ -72,7 +73,7 @@ divbyzero.throw: ; preds = %entry } ; Function Attrs: nounwind -define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #2 { +define hidden i32 @main.remInt(i32 %x, i32 %y, ptr %context) unnamed_addr #1 { entry: %0 = icmp eq i32 %y, 0 br i1 %0, label %divbyzero.throw, label %divbyzero.next @@ -91,7 +92,7 @@ divbyzero.throw: ; preds = %entry } ; Function Attrs: nounwind -define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #2 { +define hidden i32 @main.remUint(i32 %x, i32 %y, ptr %context) unnamed_addr #1 { entry: %0 = icmp eq i32 %y, 0 br i1 %0, label %divbyzero.throw, label %divbyzero.next @@ -106,61 +107,61 @@ divbyzero.throw: ; preds = %entry } ; Function Attrs: nounwind -define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #2 { +define hidden i1 @main.floatEQ(float %x, float %y, ptr %context) unnamed_addr #1 { entry: %0 = fcmp oeq float %x, %y ret i1 %0 } ; Function Attrs: nounwind -define hidden i1 @main.floatNE(float %x, float %y, ptr %context) unnamed_addr #2 { +define hidden i1 @main.floatNE(float %x, float %y, ptr %context) unnamed_addr #1 { entry: %0 = fcmp une float %x, %y ret i1 %0 } ; Function Attrs: nounwind -define hidden i1 @main.floatLower(float %x, float %y, ptr %context) unnamed_addr #2 { +define hidden i1 @main.floatLower(float %x, float %y, ptr %context) unnamed_addr #1 { entry: %0 = fcmp olt float %x, %y ret i1 %0 } ; Function Attrs: nounwind -define hidden i1 @main.floatLowerEqual(float %x, float %y, ptr %context) unnamed_addr #2 { +define hidden i1 @main.floatLowerEqual(float %x, float %y, ptr %context) unnamed_addr #1 { entry: %0 = fcmp ole float %x, %y ret i1 %0 } ; Function Attrs: nounwind -define hidden i1 @main.floatGreater(float %x, float %y, ptr %context) unnamed_addr #2 { +define hidden i1 @main.floatGreater(float %x, float %y, ptr %context) unnamed_addr #1 { entry: %0 = fcmp ogt float %x, %y ret i1 %0 } ; Function Attrs: nounwind -define hidden i1 @main.floatGreaterEqual(float %x, float %y, ptr %context) unnamed_addr #2 { +define hidden i1 @main.floatGreaterEqual(float %x, float %y, ptr %context) unnamed_addr #1 { entry: %0 = fcmp oge float %x, %y ret i1 %0 } ; Function Attrs: nounwind -define hidden float @main.complexReal(float %x.r, float %x.i, ptr %context) unnamed_addr #2 { +define hidden float @main.complexReal(float %x.r, float %x.i, ptr %context) unnamed_addr #1 { entry: ret float %x.r } ; Function Attrs: nounwind -define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #2 { +define hidden float @main.complexImag(float %x.r, float %x.i, ptr %context) unnamed_addr #1 { entry: ret float %x.i } ; Function Attrs: nounwind -define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 { +define hidden { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 { entry: %0 = fadd float %x.r, %y.r %1 = fadd float %x.i, %y.i @@ -170,7 +171,7 @@ entry: } ; Function Attrs: nounwind -define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 { +define hidden { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 { entry: %0 = fsub float %x.r, %y.r %1 = fsub float %x.i, %y.i @@ -180,7 +181,7 @@ entry: } ; Function Attrs: nounwind -define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #2 { +define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 { entry: %0 = fmul float %x.r, %y.r %1 = fmul float %x.i, %y.i @@ -194,19 +195,19 @@ entry: } ; Function Attrs: nounwind -define hidden void @main.foo(ptr %context) unnamed_addr #2 { +define hidden void @main.foo(ptr %context) unnamed_addr #1 { entry: call void @"main.foo$1"(%main.kv.0 zeroinitializer, ptr undef) ret void } ; Function Attrs: nounwind -define internal void @"main.foo$1"(%main.kv.0 %b, ptr %context) unnamed_addr #2 { +define internal void @"main.foo$1"(%main.kv.0 %b, ptr %context) unnamed_addr #1 { entry: ret void } -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } attributes #3 = { nounwind } diff --git a/compiler/testdata/channel.ll b/compiler/testdata/channel.ll index 65e18dea85..3333ef6239 100644 --- a/compiler/testdata/channel.ll +++ b/compiler/testdata/channel.ll @@ -9,16 +9,17 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden void @main.chanIntSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 { +define hidden void @main.chanIntSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 { entry: %chan.blockedList = alloca %runtime.channelBlockedList, align 8 %chan.value = alloca i32, align 4 @@ -32,15 +33,15 @@ entry: } ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) -declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3 +declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #2 -declare void @runtime.chanSend(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #1 +declare void @runtime.chanSend(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #3 ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) -declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3 +declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #2 ; Function Attrs: nounwind -define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 { +define hidden void @main.chanIntRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 { entry: %chan.blockedList = alloca %runtime.channelBlockedList, align 8 %chan.value = alloca i32, align 4 @@ -52,10 +53,10 @@ entry: ret void } -declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #1 +declare i1 @runtime.chanRecv(ptr dereferenceable_or_null(32), ptr, ptr dereferenceable_or_null(24), ptr) #3 ; Function Attrs: nounwind -define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 { +define hidden void @main.chanZeroSend(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 { entry: %chan.blockedList = alloca %runtime.channelBlockedList, align 8 call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList) @@ -65,7 +66,7 @@ entry: } ; Function Attrs: nounwind -define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 { +define hidden void @main.chanZeroRecv(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 { entry: %chan.blockedList = alloca %runtime.channelBlockedList, align 8 call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %chan.blockedList) @@ -75,7 +76,7 @@ entry: } ; Function Attrs: nounwind -define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(32) %ch1, ptr dereferenceable_or_null(32) %ch2, ptr %context) unnamed_addr #2 { +define hidden void @main.selectZeroRecv(ptr dereferenceable_or_null(32) %ch1, ptr dereferenceable_or_null(32) %ch2, ptr %context) unnamed_addr #1 { entry: %select.states.alloca = alloca [2 x %runtime.chanSelectState], align 8 %select.send.value = alloca i32, align 4 @@ -105,10 +106,10 @@ select.body: ; preds = %select.next br label %select.done } -declare { i32, i1 } @runtime.tryChanSelect(ptr, ptr, i32, i32, ptr) #1 +declare { i32, i1 } @runtime.tryChanSelect(ptr, ptr, i32, i32, ptr) #3 -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +attributes #3 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } attributes #4 = { nounwind } diff --git a/compiler/testdata/defer-cortex-m-qemu.ll b/compiler/testdata/defer-cortex-m-qemu.ll index 52a3bfbabf..076edd6431 100644 --- a/compiler/testdata/defer-cortex-m-qemu.ll +++ b/compiler/testdata/defer-cortex-m-qemu.ll @@ -3,7 +3,7 @@ source_filename = "defer.go" target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" target triple = "thumbv7m-unknown-unknown-eabi" -%runtime.deferFrame = type { ptr, ptr, [0 x ptr], ptr, i1, %runtime._interface } +%runtime.deferFrameInlineAsm = type { ptr, ptr, [0 x ptr], ptr, i1, %runtime._interface } %runtime._interface = type { ptr, ptr } %runtime._defer = type { i32, ptr } @@ -24,9 +24,9 @@ entry: %defer.alloca = alloca { i32, ptr }, align 4 %deferPtr = alloca ptr, align 4 store ptr null, ptr %deferPtr, align 4 - %deferframe.buf = alloca %runtime.deferFrame, align 4 + %deferframe.buf = alloca %runtime.deferFrameInlineAsm, align 4 %0 = call ptr @llvm.stacksave.p0() - call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4 + call void @runtime.setupDeferFrameInlineAsm(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4 store i32 0, ptr %defer.alloca, align 4 %defer.alloca.repack15 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1 store ptr null, ptr %defer.alloca.repack15, align 4 @@ -40,7 +40,7 @@ entry: br label %rundefers.block rundefers.after: ; preds = %rundefers.end - call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4 + call void @runtime.destroyDeferFrameInlineAsm(ptr nonnull %deferframe.buf, ptr undef) #4 ret void rundefers.block: ; preds = %1 @@ -76,7 +76,7 @@ rundefers.end: ; preds = %rundefers.loophead br label %rundefers.after recover: ; preds = %rundefers.end3 - call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4 + call void @runtime.destroyDeferFrameInlineAsm(ptr nonnull %deferframe.buf, ptr undef) #4 ret void lpad: ; preds = %rundefers.callback012, %rundefers.callback0, %entry @@ -115,9 +115,9 @@ rundefers.end3: ; preds = %rundefers.loophead6 ; Function Attrs: nocallback nofree nosync nounwind willreturn declare ptr @llvm.stacksave.p0() #3 -declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #2 +declare void @runtime.setupDeferFrameInlineAsm(ptr dereferenceable_or_null(24), ptr, ptr) #2 -declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #2 +declare void @runtime.destroyDeferFrameInlineAsm(ptr dereferenceable_or_null(24), ptr) #2 ; Function Attrs: nounwind define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #1 { @@ -135,9 +135,9 @@ entry: %defer.alloca = alloca { i32, ptr }, align 4 %deferPtr = alloca ptr, align 4 store ptr null, ptr %deferPtr, align 4 - %deferframe.buf = alloca %runtime.deferFrame, align 4 + %deferframe.buf = alloca %runtime.deferFrameInlineAsm, align 4 %0 = call ptr @llvm.stacksave.p0() - call void @runtime.setupDeferFrame(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4 + call void @runtime.setupDeferFrameInlineAsm(ptr nonnull %deferframe.buf, ptr %0, ptr undef) #4 store i32 0, ptr %defer.alloca, align 4 %defer.alloca.repack22 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1 store ptr null, ptr %defer.alloca.repack22, align 4 @@ -155,7 +155,7 @@ entry: br label %rundefers.block rundefers.after: ; preds = %rundefers.end - call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4 + call void @runtime.destroyDeferFrameInlineAsm(ptr nonnull %deferframe.buf, ptr undef) #4 ret void rundefers.block: ; preds = %1 @@ -201,7 +201,7 @@ rundefers.end: ; preds = %rundefers.loophead br label %rundefers.after recover: ; preds = %rundefers.end7 - call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4 + call void @runtime.destroyDeferFrameInlineAsm(ptr nonnull %deferframe.buf, ptr undef) #4 ret void lpad: ; preds = %rundefers.callback119, %rundefers.callback016, %rundefers.callback1, %rundefers.callback0, %entry diff --git a/compiler/testdata/defer-wasm-none.ll b/compiler/testdata/defer-wasm-none.ll new file mode 100644 index 0000000000..e5987d3675 --- /dev/null +++ b/compiler/testdata/defer-wasm-none.ll @@ -0,0 +1,273 @@ +; ModuleID = 'defer.go' +source_filename = "defer.go" +target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20" +target triple = "wasm32-unknown-wasi" + +%runtime.deferFrameWasmEH = type { ptr, i1, %runtime._interface } +%runtime._interface = type { ptr, ptr } +%runtime._defer = type { i32, ptr } + +; Function Attrs: allockind("alloc,zeroed") allocsize(0) +declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 + +; Function Attrs: nounwind +declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 + +define hidden void @main.init(ptr %context) unnamed_addr #2 { +entry: + ret void +} + +declare void @main.external(ptr) #2 + +define hidden void @main.deferSimple(ptr %context) unnamed_addr #2 personality ptr @__gxx_wasm_personality_v0 { +entry: + %defer.alloca = alloca { i32, ptr }, align 8 + %deferPtr = alloca ptr, align 4 + store ptr null, ptr %deferPtr, align 4 + %deferframe.buf = alloca %runtime.deferFrameWasmEH, align 8 + call void @runtime.setupDeferFrameWasmEH(ptr nonnull %deferframe.buf, ptr undef) + %stackalloc = alloca i8, align 1 + call void @runtime.trackPointer(ptr nonnull %defer.alloca, ptr nonnull %stackalloc, ptr undef) + store i32 0, ptr %defer.alloca, align 4 + %defer.alloca.repack13 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1 + store ptr null, ptr %defer.alloca.repack13, align 4 + store ptr %defer.alloca, ptr %deferPtr, align 4 + invoke void @main.external(ptr undef) + to label %invoke.cont unwind label %catch.dispatch + +invoke.cont: ; preds = %entry + br label %rundefers.block + +rundefers.after: ; preds = %rundefers.end + call void @runtime.destroyDeferFrameWasmEH(ptr nonnull %deferframe.buf, ptr undef) + ret void + +rundefers.block: ; preds = %invoke.cont + br label %rundefers.loophead + +rundefers.loophead: ; preds = %rundefers.catch.start, %rundefers.callback0, %rundefers.block + %0 = load ptr, ptr %deferPtr, align 4 + %stackIsNil = icmp eq ptr %0, null + br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop + +rundefers.loop: ; preds = %rundefers.loophead + %stack.next.gep = getelementptr inbounds %runtime._defer, ptr %0, i32 0, i32 1 + %stack.next = load ptr, ptr %stack.next.gep, align 4 + store ptr %stack.next, ptr %deferPtr, align 4 + %callback = load i32, ptr %0, align 4 + switch i32 %callback, label %rundefers.default [ + i32 0, label %rundefers.callback0 + ] + +rundefers.callback0: ; preds = %rundefers.loop + invoke void @"main.deferSimple$1"(ptr undef) + to label %rundefers.loophead unwind label %rundefers.catch.dispatch + +rundefers.default: ; preds = %rundefers.loop + unreachable + +rundefers.catch.dispatch: ; preds = %rundefers.callback0 + %1 = catchswitch within none [label %rundefers.catch.start] unwind to caller + +rundefers.catch.start: ; preds = %rundefers.catch.dispatch + %2 = catchpad within %1 [ptr null] + catchret from %2 to label %rundefers.loophead + +rundefers.end: ; preds = %rundefers.loophead + br label %rundefers.after + +recover: ; preds = %rundefers.end1 + call void @runtime.destroyDeferFrameWasmEH(ptr nonnull %deferframe.buf, ptr undef) + ret void + +catch.dispatch: ; preds = %entry + %3 = catchswitch within none [label %catch.start] unwind to caller + +catch.start: ; preds = %catch.dispatch + %4 = catchpad within %3 [ptr null] + catchret from %4 to label %rundefers + +rundefers: ; preds = %catch.start + br label %rundefers.loophead4 + +rundefers.loophead4: ; preds = %rundefers.catch.start6, %rundefers.callback012, %rundefers + %5 = load ptr, ptr %deferPtr, align 4 + %stackIsNil7 = icmp eq ptr %5, null + br i1 %stackIsNil7, label %rundefers.end1, label %rundefers.loop3 + +rundefers.loop3: ; preds = %rundefers.loophead4 + %stack.next.gep8 = getelementptr inbounds %runtime._defer, ptr %5, i32 0, i32 1 + %stack.next9 = load ptr, ptr %stack.next.gep8, align 4 + store ptr %stack.next9, ptr %deferPtr, align 4 + %callback11 = load i32, ptr %5, align 4 + switch i32 %callback11, label %rundefers.default2 [ + i32 0, label %rundefers.callback012 + ] + +rundefers.callback012: ; preds = %rundefers.loop3 + invoke void @"main.deferSimple$1"(ptr undef) + to label %rundefers.loophead4 unwind label %rundefers.catch.dispatch5 + +rundefers.default2: ; preds = %rundefers.loop3 + unreachable + +rundefers.catch.dispatch5: ; preds = %rundefers.callback012 + %6 = catchswitch within none [label %rundefers.catch.start6] unwind to caller + +rundefers.catch.start6: ; preds = %rundefers.catch.dispatch5 + %7 = catchpad within %6 [ptr null] + catchret from %7 to label %rundefers.loophead4 + +rundefers.end1: ; preds = %rundefers.loophead4 + br label %recover +} + +declare i32 @__gxx_wasm_personality_v0(...) + +declare void @runtime.setupDeferFrameWasmEH(ptr dereferenceable_or_null(16), ptr) #2 + +declare void @runtime.destroyDeferFrameWasmEH(ptr dereferenceable_or_null(16), ptr) #2 + +define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #2 { +entry: + call void @runtime.printint32(i32 3, ptr undef) + ret void +} + +declare void @runtime.printint32(i32, ptr) #2 + +define hidden void @main.deferMultiple(ptr %context) unnamed_addr #2 personality ptr @__gxx_wasm_personality_v0 { +entry: + %defer.alloca2 = alloca { i32, ptr }, align 8 + %defer.alloca = alloca { i32, ptr }, align 8 + %deferPtr = alloca ptr, align 4 + store ptr null, ptr %deferPtr, align 4 + %deferframe.buf = alloca %runtime.deferFrameWasmEH, align 8 + call void @runtime.setupDeferFrameWasmEH(ptr nonnull %deferframe.buf, ptr undef) + %stackalloc = alloca i8, align 1 + call void @runtime.trackPointer(ptr nonnull %defer.alloca, ptr nonnull %stackalloc, ptr undef) + store i32 0, ptr %defer.alloca, align 4 + %defer.alloca.repack16 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca, i32 0, i32 1 + store ptr null, ptr %defer.alloca.repack16, align 4 + store ptr %defer.alloca, ptr %deferPtr, align 4 + call void @runtime.trackPointer(ptr nonnull %defer.alloca2, ptr nonnull %stackalloc, ptr undef) + store i32 1, ptr %defer.alloca2, align 4 + %defer.alloca2.repack17 = getelementptr inbounds { i32, ptr }, ptr %defer.alloca2, i32 0, i32 1 + store ptr %defer.alloca, ptr %defer.alloca2.repack17, align 4 + store ptr %defer.alloca2, ptr %deferPtr, align 4 + invoke void @main.external(ptr undef) + to label %invoke.cont unwind label %catch.dispatch + +invoke.cont: ; preds = %entry + br label %rundefers.block + +rundefers.after: ; preds = %rundefers.end + call void @runtime.destroyDeferFrameWasmEH(ptr nonnull %deferframe.buf, ptr undef) + ret void + +rundefers.block: ; preds = %invoke.cont + br label %rundefers.loophead + +rundefers.loophead: ; preds = %rundefers.catch.start, %rundefers.callback1, %rundefers.callback0, %rundefers.block + %0 = load ptr, ptr %deferPtr, align 4 + %stackIsNil = icmp eq ptr %0, null + br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop + +rundefers.loop: ; preds = %rundefers.loophead + %stack.next.gep = getelementptr inbounds %runtime._defer, ptr %0, i32 0, i32 1 + %stack.next = load ptr, ptr %stack.next.gep, align 4 + store ptr %stack.next, ptr %deferPtr, align 4 + %callback = load i32, ptr %0, align 4 + switch i32 %callback, label %rundefers.default [ + i32 0, label %rundefers.callback0 + i32 1, label %rundefers.callback1 + ] + +rundefers.callback0: ; preds = %rundefers.loop + invoke void @"main.deferMultiple$1"(ptr undef) + to label %rundefers.loophead unwind label %rundefers.catch.dispatch + +rundefers.callback1: ; preds = %rundefers.loop + invoke void @"main.deferMultiple$2"(ptr undef) + to label %rundefers.loophead unwind label %rundefers.catch.dispatch + +rundefers.default: ; preds = %rundefers.loop + unreachable + +rundefers.catch.dispatch: ; preds = %rundefers.callback1, %rundefers.callback0 + %1 = catchswitch within none [label %rundefers.catch.start] unwind to caller + +rundefers.catch.start: ; preds = %rundefers.catch.dispatch + %2 = catchpad within %1 [ptr null] + catchret from %2 to label %rundefers.loophead + +rundefers.end: ; preds = %rundefers.loophead + br label %rundefers.after + +recover: ; preds = %rundefers.end3 + call void @runtime.destroyDeferFrameWasmEH(ptr nonnull %deferframe.buf, ptr undef) + ret void + +catch.dispatch: ; preds = %entry + %3 = catchswitch within none [label %catch.start] unwind to caller + +catch.start: ; preds = %catch.dispatch + %4 = catchpad within %3 [ptr null] + catchret from %4 to label %rundefers + +rundefers: ; preds = %catch.start + br label %rundefers.loophead6 + +rundefers.loophead6: ; preds = %rundefers.catch.start8, %rundefers.callback115, %rundefers.callback014, %rundefers + %5 = load ptr, ptr %deferPtr, align 4 + %stackIsNil9 = icmp eq ptr %5, null + br i1 %stackIsNil9, label %rundefers.end3, label %rundefers.loop5 + +rundefers.loop5: ; preds = %rundefers.loophead6 + %stack.next.gep10 = getelementptr inbounds %runtime._defer, ptr %5, i32 0, i32 1 + %stack.next11 = load ptr, ptr %stack.next.gep10, align 4 + store ptr %stack.next11, ptr %deferPtr, align 4 + %callback13 = load i32, ptr %5, align 4 + switch i32 %callback13, label %rundefers.default4 [ + i32 0, label %rundefers.callback014 + i32 1, label %rundefers.callback115 + ] + +rundefers.callback014: ; preds = %rundefers.loop5 + invoke void @"main.deferMultiple$1"(ptr undef) + to label %rundefers.loophead6 unwind label %rundefers.catch.dispatch7 + +rundefers.callback115: ; preds = %rundefers.loop5 + invoke void @"main.deferMultiple$2"(ptr undef) + to label %rundefers.loophead6 unwind label %rundefers.catch.dispatch7 + +rundefers.default4: ; preds = %rundefers.loop5 + unreachable + +rundefers.catch.dispatch7: ; preds = %rundefers.callback115, %rundefers.callback014 + %6 = catchswitch within none [label %rundefers.catch.start8] unwind to caller + +rundefers.catch.start8: ; preds = %rundefers.catch.dispatch7 + %7 = catchpad within %6 [ptr null] + catchret from %7 to label %rundefers.loophead6 + +rundefers.end3: ; preds = %rundefers.loophead6 + br label %recover +} + +define internal void @"main.deferMultiple$1"(ptr %context) unnamed_addr #2 { +entry: + call void @runtime.printint32(i32 3, ptr undef) + ret void +} + +define internal void @"main.deferMultiple$2"(ptr %context) unnamed_addr #2 { +entry: + call void @runtime.printint32(i32 5, ptr undef) + ret void +} + +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } diff --git a/compiler/testdata/float.ll b/compiler/testdata/float.ll index 735ab19768..c778e70751 100644 --- a/compiler/testdata/float.ll +++ b/compiler/testdata/float.ll @@ -6,16 +6,17 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #2 { +define hidden i32 @main.f32tou32(float %v, ptr %context) unnamed_addr #1 { entry: %positive = fcmp oge float %v, 0.000000e+00 %withinmax = fcmp ole float %v, 0x41EFFFFFC0000000 @@ -27,25 +28,25 @@ entry: } ; Function Attrs: nounwind -define hidden float @main.maxu32f(ptr %context) unnamed_addr #2 { +define hidden float @main.maxu32f(ptr %context) unnamed_addr #1 { entry: ret float 0x41F0000000000000 } ; Function Attrs: nounwind -define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #2 { +define hidden i32 @main.maxu32tof32(ptr %context) unnamed_addr #1 { entry: ret i32 -1 } ; Function Attrs: nounwind -define hidden { i32, i32, i32, i32 } @main.inftoi32(ptr %context) unnamed_addr #2 { +define hidden { i32, i32, i32, i32 } @main.inftoi32(ptr %context) unnamed_addr #1 { entry: ret { i32, i32, i32, i32 } { i32 -1, i32 0, i32 2147483647, i32 -2147483648 } } ; Function Attrs: nounwind -define hidden i32 @main.u32tof32tou32(i32 %v, ptr %context) unnamed_addr #2 { +define hidden i32 @main.u32tof32tou32(i32 %v, ptr %context) unnamed_addr #1 { entry: %0 = uitofp i32 %v to float %withinmax = fcmp ole float %0, 0x41EFFFFFC0000000 @@ -55,7 +56,7 @@ entry: } ; Function Attrs: nounwind -define hidden float @main.f32tou32tof32(float %v, ptr %context) unnamed_addr #2 { +define hidden float @main.f32tou32tof32(float %v, ptr %context) unnamed_addr #1 { entry: %positive = fcmp oge float %v, 0.000000e+00 %withinmax = fcmp ole float %v, 0x41EFFFFFC0000000 @@ -68,7 +69,7 @@ entry: } ; Function Attrs: nounwind -define hidden i8 @main.f32tou8(float %v, ptr %context) unnamed_addr #2 { +define hidden i8 @main.f32tou8(float %v, ptr %context) unnamed_addr #1 { entry: %positive = fcmp oge float %v, 0.000000e+00 %withinmax = fcmp ole float %v, 2.550000e+02 @@ -80,7 +81,7 @@ entry: } ; Function Attrs: nounwind -define hidden i8 @main.f32toi8(float %v, ptr %context) unnamed_addr #2 { +define hidden i8 @main.f32toi8(float %v, ptr %context) unnamed_addr #1 { entry: %abovemin = fcmp oge float %v, -1.280000e+02 %belowmax = fcmp ole float %v, 1.270000e+02 @@ -93,6 +94,5 @@ entry: ret i8 %0 } -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } diff --git a/compiler/testdata/func.ll b/compiler/testdata/func.ll index bec79bffc5..7591546440 100644 --- a/compiler/testdata/func.ll +++ b/compiler/testdata/func.ll @@ -6,16 +6,17 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #2 { +define hidden void @main.foo(ptr %callback.context, ptr %callback.funcptr, ptr %context) unnamed_addr #1 { entry: %0 = icmp eq ptr %callback.funcptr, null br i1 %0, label %fpcall.throw, label %fpcall.next @@ -29,22 +30,22 @@ fpcall.throw: ; preds = %entry unreachable } -declare void @runtime.nilPanic(ptr) #1 +declare void @runtime.nilPanic(ptr) #2 ; Function Attrs: nounwind -define hidden void @main.bar(ptr %context) unnamed_addr #2 { +define hidden void @main.bar(ptr %context) unnamed_addr #1 { entry: call void @main.foo(ptr undef, ptr nonnull @main.someFunc, ptr undef) ret void } ; Function Attrs: nounwind -define hidden void @main.someFunc(i32 %arg0, ptr %context) unnamed_addr #2 { +define hidden void @main.someFunc(i32 %arg0, ptr %context) unnamed_addr #1 { entry: ret void } -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } attributes #3 = { nounwind } diff --git a/compiler/testdata/gc.ll b/compiler/testdata/gc.ll index 82260fbf45..988fc3d6f5 100644 --- a/compiler/testdata/gc.ll +++ b/compiler/testdata/gc.ll @@ -27,93 +27,94 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden void @main.newScalar(ptr %context) unnamed_addr #2 { +define hidden void @main.newScalar(ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - %new = call align 1 dereferenceable(1) ptr @runtime.alloc(i32 1, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3 + %new = call align 1 dereferenceable(1) ptr @runtime.alloc(i32 1, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) store ptr %new, ptr @main.scalar1, align 4 - %new1 = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3 + %new1 = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) store ptr %new1, ptr @main.scalar2, align 4 - %new2 = call align 8 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3 + %new2 = call align 8 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) store ptr %new2, ptr @main.scalar3, align 4 - %new3 = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #3 + %new3 = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) store ptr %new3, ptr @main.scalar4, align 4 ret void } ; Function Attrs: nounwind -define hidden void @main.newArray(ptr %context) unnamed_addr #2 { +define hidden void @main.newArray(ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - %new = call align 1 dereferenceable(3) ptr @runtime.alloc(i32 3, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3 + %new = call align 1 dereferenceable(3) ptr @runtime.alloc(i32 3, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) store ptr %new, ptr @main.array1, align 4 - %new1 = call align 1 dereferenceable(71) ptr @runtime.alloc(i32 71, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3 + %new1 = call align 1 dereferenceable(71) ptr @runtime.alloc(i32 71, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) store ptr %new1, ptr @main.array2, align 4 - %new2 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3 + %new2 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) store ptr %new2, ptr @main.array3, align 4 ret void } ; Function Attrs: nounwind -define hidden void @main.newStruct(ptr %context) unnamed_addr #2 { +define hidden void @main.newStruct(ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - %new = call align 1 ptr @runtime.alloc(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3 + %new = call align 1 ptr @runtime.alloc(i32 0, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) store ptr %new, ptr @main.struct1, align 4 - %new1 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3 + %new1 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) store ptr %new1, ptr @main.struct2, align 4 - %new2 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-2000000000000001", ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3 + %new2 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-2000000000000001", ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) store ptr %new2, ptr @main.struct3, align 4 - %new3 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0001", ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #3 + %new3 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0001", ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) store ptr %new3, ptr @main.struct4, align 4 ret void } ; Function Attrs: nounwind -define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #2 { +define hidden ptr @main.newFuncValue(ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - %new = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 197 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) #3 + %new = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 197 to ptr), ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %new, ptr nonnull %stackalloc, ptr undef) ret ptr %new } ; Function Attrs: nounwind -define hidden void @main.makeSlice(ptr %context) unnamed_addr #2 { +define hidden void @main.makeSlice(ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - %makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3 + %makeslice = call align 1 dereferenceable(5) ptr @runtime.alloc(i32 5, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) store ptr %makeslice, ptr @main.slice1, align 4 store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 1), align 4 store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice1, i32 0, i32 2), align 4 - %makeslice1 = call align 4 dereferenceable(20) ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) #3 + %makeslice1 = call align 4 dereferenceable(20) ptr @runtime.alloc(i32 20, ptr nonnull inttoptr (i32 67 to ptr), ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %makeslice1, ptr nonnull %stackalloc, ptr undef) store ptr %makeslice1, ptr @main.slice2, align 4 store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 1), align 4 store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice2, i32 0, i32 2), align 4 - %makeslice3 = call align 4 dereferenceable(60) ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) #3 + %makeslice3 = call align 4 dereferenceable(60) ptr @runtime.alloc(i32 60, ptr nonnull inttoptr (i32 71 to ptr), ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %makeslice3, ptr nonnull %stackalloc, ptr undef) store ptr %makeslice3, ptr @main.slice3, align 4 store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 1), align 4 store i32 5, ptr getelementptr inbounds ({ ptr, i32, i32 }, ptr @main.slice3, i32 0, i32 2), align 4 @@ -121,21 +122,20 @@ entry: } ; Function Attrs: nounwind -define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #2 { +define hidden %runtime._interface @main.makeInterface(double %v.r, double %v.i, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - %0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #3 + %0 = call align 8 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #2 + call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) store double %v.r, ptr %0, align 8 %.repack1 = getelementptr inbounds { double, double }, ptr %0, i32 0, i32 1 store double %v.i, ptr %.repack1, align 8 %1 = insertvalue %runtime._interface { ptr @"reflect/types.type:basic:complex128", ptr undef }, ptr %0, 1 - call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:complex128", ptr nonnull %stackalloc, ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:complex128", ptr nonnull %stackalloc, ptr undef) + call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) ret %runtime._interface %1 } -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #3 = { nounwind } +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #2 = { nounwind } diff --git a/compiler/testdata/go1.20.ll b/compiler/testdata/go1.20.ll index 6ef13fb4a8..583e87f018 100644 --- a/compiler/testdata/go1.20.ll +++ b/compiler/testdata/go1.20.ll @@ -8,24 +8,25 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 { +define hidden ptr @main.unsafeSliceData(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) ret ptr %s.data } ; Function Attrs: nounwind -define hidden %runtime._string @main.unsafeString(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #2 { +define hidden %runtime._string @main.unsafeString(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %0 = icmp slt i16 %len, 0 @@ -39,7 +40,7 @@ unsafe.String.next: ; preds = %entry %5 = zext i16 %len to i32 %6 = insertvalue %runtime._string undef, ptr %ptr, 0 %7 = insertvalue %runtime._string %6, i32 %5, 1 - call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) ret %runtime._string %7 unsafe.String.throw: ; preds = %entry @@ -47,17 +48,17 @@ unsafe.String.throw: ; preds = %entry unreachable } -declare void @runtime.unsafeSlicePanic(ptr) #1 +declare void @runtime.unsafeSlicePanic(ptr) #2 ; Function Attrs: nounwind -define hidden ptr @main.unsafeStringData(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 { +define hidden ptr @main.unsafeStringData(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %s.data, ptr nonnull %stackalloc, ptr undef) ret ptr %s.data } -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } attributes #3 = { nounwind } diff --git a/compiler/testdata/go1.21.ll b/compiler/testdata/go1.21.ll index d76ec6212c..89a5a4d170 100644 --- a/compiler/testdata/go1.21.ll +++ b/compiler/testdata/go1.21.ll @@ -8,29 +8,30 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #2 { +define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #1 { entry: ret i32 %a } ; Function Attrs: nounwind -define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #2 { +define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #1 { entry: %0 = call i32 @llvm.smin.i32(i32 %a, i32 %b) ret i32 %0 } ; Function Attrs: nounwind -define hidden i32 @main.min3(i32 %a, i32 %b, i32 %c, ptr %context) unnamed_addr #2 { +define hidden i32 @main.min3(i32 %a, i32 %b, i32 %c, ptr %context) unnamed_addr #1 { entry: %0 = call i32 @llvm.smin.i32(i32 %a, i32 %b) %1 = call i32 @llvm.smin.i32(i32 %0, i32 %c) @@ -38,7 +39,7 @@ entry: } ; Function Attrs: nounwind -define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #2 { +define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #1 { entry: %0 = call i32 @llvm.smin.i32(i32 %a, i32 %b) %1 = call i32 @llvm.smin.i32(i32 %0, i32 %c) @@ -47,21 +48,21 @@ entry: } ; Function Attrs: nounwind -define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #2 { +define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #1 { entry: %0 = call i8 @llvm.umin.i8(i8 %a, i8 %b) ret i8 %0 } ; Function Attrs: nounwind -define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #2 { +define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #1 { entry: %0 = call i32 @llvm.umin.i32(i32 %a, i32 %b) ret i32 %0 } ; Function Attrs: nounwind -define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #2 { +define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #1 { entry: %0 = fcmp olt float %a, %b %1 = select i1 %0, float %a, float %b @@ -69,7 +70,7 @@ entry: } ; Function Attrs: nounwind -define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #2 { +define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #1 { entry: %0 = fcmp olt double %a, %b %1 = select i1 %0, double %a, double %b @@ -77,7 +78,7 @@ entry: } ; Function Attrs: nounwind -define hidden %runtime._string @main.minString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 { +define hidden %runtime._string @main.minString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #1 { entry: %0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0 %1 = insertvalue %runtime._string %0, i32 %a.len, 1 @@ -87,28 +88,28 @@ entry: %4 = call i1 @runtime.stringLess(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr undef) #5 %5 = select i1 %4, %runtime._string %1, %runtime._string %3 %6 = extractvalue %runtime._string %5, 0 - call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5 + call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) ret %runtime._string %5 } -declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1 +declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #2 ; Function Attrs: nounwind -define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #2 { +define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #1 { entry: %0 = call i32 @llvm.smax.i32(i32 %a, i32 %b) ret i32 %0 } ; Function Attrs: nounwind -define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #2 { +define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #1 { entry: %0 = call i32 @llvm.umax.i32(i32 %a, i32 %b) ret i32 %0 } ; Function Attrs: nounwind -define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #2 { +define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #1 { entry: %0 = fcmp ogt float %a, %b %1 = select i1 %0, float %a, float %b @@ -116,7 +117,7 @@ entry: } ; Function Attrs: nounwind -define hidden %runtime._string @main.maxString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 { +define hidden %runtime._string @main.maxString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #1 { entry: %0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0 %1 = insertvalue %runtime._string %0, i32 %a.len, 1 @@ -126,12 +127,12 @@ entry: %4 = call i1 @runtime.stringLess(ptr %b.data, i32 %b.len, ptr %a.data, i32 %a.len, ptr undef) #5 %5 = select i1 %4, %runtime._string %1, %runtime._string %3 %6 = extractvalue %runtime._string %5, 0 - call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5 + call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) ret %runtime._string %5 } ; Function Attrs: nounwind -define hidden void @main.clearSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 { +define hidden void @main.clearSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 { entry: %0 = shl i32 %s.len, 2 call void @llvm.memset.p0.i32(ptr align 4 %s.data, i8 0, i32 %0, i1 false) @@ -142,19 +143,19 @@ entry: declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) #3 ; Function Attrs: nounwind -define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 { +define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden void @main.clearMap(ptr dereferenceable_or_null(40) %m, ptr %context) unnamed_addr #2 { +define hidden void @main.clearMap(ptr dereferenceable_or_null(40) %m, ptr %context) unnamed_addr #1 { entry: call void @runtime.hashmapClear(ptr %m, ptr undef) #5 ret void } -declare void @runtime.hashmapClear(ptr dereferenceable_or_null(40), ptr) #1 +declare void @runtime.hashmapClear(ptr dereferenceable_or_null(40), ptr) #2 ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) declare i32 @llvm.smin.i32(i32, i32) #4 @@ -171,9 +172,9 @@ declare i32 @llvm.smax.i32(i32, i32) #4 ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) declare i32 @llvm.umax.i32(i32, i32) #4 -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) } attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } attributes #5 = { nounwind } diff --git a/compiler/testdata/goroutine-wasm-asyncify.ll b/compiler/testdata/goroutine-wasm-asyncify.ll index 1281857d31..ae8e54f939 100644 --- a/compiler/testdata/goroutine-wasm-asyncify.ll +++ b/compiler/testdata/goroutine-wasm-asyncify.ll @@ -10,24 +10,25 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #2 { +define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #1 { entry: call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #9 ret void } -declare void @main.regularFunction(i32, ptr) #1 +declare void @main.regularFunction(i32, ptr) #2 -declare void @runtime.deadlock(ptr) #1 +declare void @runtime.deadlock(ptr) #2 ; Function Attrs: nounwind define linkonce_odr void @"main.regularFunction$gowrapper"(ptr %0) unnamed_addr #3 { @@ -38,17 +39,17 @@ entry: unreachable } -declare void @"internal/task.start"(i32, ptr, i32, ptr) #1 +declare void @"internal/task.start"(i32, ptr, i32, ptr) #2 ; Function Attrs: nounwind -define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #2 { +define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #1 { entry: call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #9 ret void } ; Function Attrs: nounwind -define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #2 { +define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 { entry: ret void } @@ -63,16 +64,16 @@ entry: } ; Function Attrs: nounwind -define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #2 { +define hidden void @main.closureFunctionGoroutine(ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %n = call align 4 dereferenceable(4) ptr @runtime.alloc(i32 4, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #9 - call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9 + call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) store i32 3, ptr %n, align 4 - call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) #9 - call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) #9 + call void @runtime.trackPointer(ptr nonnull %n, ptr nonnull %stackalloc, ptr undef) + call void @runtime.trackPointer(ptr nonnull @"main.closureFunctionGoroutine$1", ptr nonnull %stackalloc, ptr undef) %0 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr null, ptr undef) #9 - call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9 + call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) store i32 5, ptr %0, align 4 %1 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1 store ptr %n, ptr %1, align 4 @@ -83,7 +84,7 @@ entry: } ; Function Attrs: nounwind -define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #2 { +define internal void @"main.closureFunctionGoroutine$1"(i32 %x, ptr %context) unnamed_addr #1 { entry: store i32 7, ptr %context, align 4 ret void @@ -100,14 +101,14 @@ entry: unreachable } -declare void @runtime.printint32(i32, ptr) #1 +declare void @runtime.printint32(i32, ptr) #2 ; Function Attrs: nounwind -define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #2 { +define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %0 = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr null, ptr undef) #9 - call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9 + call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) store i32 5, ptr %0, align 4 %1 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 1 store ptr %fn.context, ptr %1, align 4 @@ -131,35 +132,35 @@ entry: } ; Function Attrs: nounwind -define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #2 { +define hidden void @main.recoverBuiltinGoroutine(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #2 { +define hidden void @main.copyBuiltinGoroutine(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 { entry: %copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 1, ptr undef) #9 ret void } -declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1 +declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #2 ; Function Attrs: nounwind -define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #2 { +define hidden void @main.closeBuiltinGoroutine(ptr dereferenceable_or_null(32) %ch, ptr %context) unnamed_addr #1 { entry: call void @runtime.chanClose(ptr %ch, ptr undef) #9 ret void } -declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #1 +declare void @runtime.chanClose(ptr dereferenceable_or_null(32), ptr) #2 ; Function Attrs: nounwind -define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 { +define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9 - call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9 + call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) store ptr %itf.value, ptr %0, align 4 %1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1 store ptr @"main$string", ptr %1, align 4 @@ -188,13 +189,13 @@ entry: unreachable } -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #3 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.regularFunction" } -attributes #4 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" } -attributes #5 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" } -attributes #6 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper" } -attributes #7 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" } -attributes #8 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" } +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #3 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.regularFunction" } +attributes #4 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.inlineFunctionGoroutine$1" } +attributes #5 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="main.closureFunctionGoroutine$1" } +attributes #6 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper" } +attributes #7 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Print(string)" "tinygo-methods"="reflect/methods.Print(string)" } +attributes #8 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-gowrapper"="interface:{Print:func:{basic:string}{}}.Print$invoke" } attributes #9 = { nounwind } diff --git a/compiler/testdata/interface.ll b/compiler/testdata/interface.ll index 801f370d58..632306a76b 100644 --- a/compiler/testdata/interface.ll +++ b/compiler/testdata/interface.ll @@ -20,52 +20,53 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #2 { +define hidden %runtime._interface @main.simpleType(ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef) #7 - call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7 + call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:basic:int", ptr nonnull %stackalloc, ptr undef) + call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) ret %runtime._interface { ptr @"reflect/types.type:basic:int", ptr null } } ; Function Attrs: nounwind -define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #2 { +define hidden %runtime._interface @main.pointerType(ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef) #7 - call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7 + call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:basic:int", ptr nonnull %stackalloc, ptr undef) + call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) ret %runtime._interface { ptr @"reflect/types.type:pointer:basic:int", ptr null } } ; Function Attrs: nounwind -define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #2 { +define hidden %runtime._interface @main.interfaceType(ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef) #7 - call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7 + call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:named:error", ptr nonnull %stackalloc, ptr undef) + call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) ret %runtime._interface { ptr @"reflect/types.type:pointer:named:error", ptr null } } ; Function Attrs: nounwind -define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #2 { +define hidden %runtime._interface @main.anonymousInterfaceType(ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr nonnull %stackalloc, ptr undef) #7 - call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) #7 + call void @runtime.trackPointer(ptr nonnull @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr nonnull %stackalloc, ptr undef) + call void @runtime.trackPointer(ptr null, ptr nonnull %stackalloc, ptr undef) ret %runtime._interface { ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", ptr null } } ; Function Attrs: nounwind -define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 { +define hidden i1 @main.isInt(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { entry: %typecode = call i1 @runtime.typeAssert(ptr %itf.typecode, ptr nonnull @"reflect/types.typeid:basic:int", ptr undef) #7 br i1 %typecode, label %typeassert.ok, label %typeassert.next @@ -77,10 +78,10 @@ typeassert.ok: ; preds = %entry br label %typeassert.next } -declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #1 +declare i1 @runtime.typeAssert(ptr, ptr dereferenceable_or_null(1), ptr) #2 ; Function Attrs: nounwind -define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 { +define hidden i1 @main.isError(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { entry: %0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7 br i1 %0, label %typeassert.ok, label %typeassert.next @@ -95,7 +96,7 @@ typeassert.ok: ; preds = %entry declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(ptr) #3 ; Function Attrs: nounwind -define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 { +define hidden i1 @main.isStringer(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { entry: %0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr %itf.typecode) #7 br i1 %0, label %typeassert.ok, label %typeassert.next @@ -110,7 +111,7 @@ typeassert.ok: ; preds = %entry declare i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(ptr) #4 ; Function Attrs: nounwind -define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 { +define hidden i8 @main.callFooMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { entry: %0 = call i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr %itf.value, i32 3, ptr %itf.typecode, ptr undef) #7 ret i8 %0 @@ -119,22 +120,22 @@ entry: declare i8 @"interface:{String:func:{}{basic:string},main.foo:func:{basic:int}{basic:uint8}}.foo$invoke"(ptr, i32, ptr, ptr) #5 ; Function Attrs: nounwind -define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #2 { +define hidden %runtime._string @main.callErrorMethod(ptr %itf.typecode, ptr %itf.value, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %0 = call %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr %itf.value, ptr %itf.typecode, ptr undef) #7 %1 = extractvalue %runtime._string %0, 0 - call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #7 + call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) ret %runtime._string %0 } declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"(ptr, ptr, ptr) #6 -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #3 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.Error() string" } -attributes #4 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.String() string" } -attributes #5 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" } -attributes #6 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" } +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #3 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.Error() string" } +attributes #4 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-methods"="reflect/methods.String() string" } +attributes #5 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" } +attributes #6 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" } attributes #7 = { nounwind } diff --git a/compiler/testdata/pointer.ll b/compiler/testdata/pointer.ll index a659b21744..0816cf50fe 100644 --- a/compiler/testdata/pointer.ll +++ b/compiler/testdata/pointer.ll @@ -6,45 +6,44 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #2 { +define hidden [0 x i32] @main.pointerDerefZero(ptr %x, ptr %context) unnamed_addr #1 { entry: ret [0 x i32] zeroinitializer } ; Function Attrs: nounwind -define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #2 { +define hidden ptr @main.pointerCastFromUnsafe(ptr %x, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) ret ptr %x } ; Function Attrs: nounwind -define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #2 { +define hidden ptr @main.pointerCastToUnsafe(ptr dereferenceable_or_null(4) %x, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) ret ptr %x } ; Function Attrs: nounwind -define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #2 { +define hidden ptr @main.pointerCastToUnsafeNoop(ptr dereferenceable_or_null(1) %x, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 - call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %x, ptr nonnull %stackalloc, ptr undef) ret ptr %x } -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #3 = { nounwind } +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } diff --git a/compiler/testdata/pragma.ll b/compiler/testdata/pragma.ll index 3ee4078f1a..57e2298527 100644 --- a/compiler/testdata/pragma.ll +++ b/compiler/testdata/pragma.ll @@ -14,27 +14,28 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define void @extern_func() #3 { +define void @extern_func() #2 { entry: ret void } ; Function Attrs: nounwind -define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #2 { +define hidden void @somepkg.someFunction1(ptr %context) unnamed_addr #1 { entry: ret void } -declare void @somepkg.someFunction2(ptr) #1 +declare void @somepkg.someFunction2(ptr) #3 ; Function Attrs: inlinehint nounwind define hidden void @main.inlineFunc(ptr %context) unnamed_addr #4 { @@ -70,15 +71,15 @@ entry: ret void } -declare void @main.undefinedFunctionNotInSection(ptr) #1 - -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #3 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" } -attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" } -attributes #7 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="modulename" "wasm-import-name"="import1" } -attributes #8 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="foobar" "wasm-import-name"="imported" } -attributes #9 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exported" } +declare void @main.undefinedFunctionNotInSection(ptr) #3 + +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #2 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" } +attributes #3 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" } +attributes #7 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="modulename" "wasm-import-name"="import1" } +attributes #8 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="foobar" "wasm-import-name"="imported" } +attributes #9 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exported" } diff --git a/compiler/testdata/slice.ll b/compiler/testdata/slice.ll index 092dabbff4..b19486c81a 100644 --- a/compiler/testdata/slice.ll +++ b/compiler/testdata/slice.ll @@ -6,28 +6,29 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 { +define hidden i32 @main.sliceLen(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 { entry: ret i32 %ints.len } ; Function Attrs: nounwind -define hidden i32 @main.sliceCap(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 { +define hidden i32 @main.sliceCap(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 { entry: ret i32 %ints.cap } ; Function Attrs: nounwind -define hidden i32 @main.sliceElement(ptr %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, ptr %context) unnamed_addr #2 { +define hidden i32 @main.sliceElement(ptr %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, ptr %context) unnamed_addr #1 { entry: %.not = icmp ult i32 %index, %ints.len br i1 %.not, label %lookup.next, label %lookup.throw @@ -42,14 +43,14 @@ lookup.throw: ; preds = %entry unreachable } -declare void @runtime.lookupPanic(ptr) #1 +declare void @runtime.lookupPanic(ptr) #2 ; Function Attrs: nounwind -define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #2 { +define hidden { ptr, i32, i32 } @main.sliceAppendValues(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %varargs = call align 4 dereferenceable(12) ptr @runtime.alloc(i32 12, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr nonnull %varargs, ptr nonnull %stackalloc, ptr undef) store i32 1, ptr %varargs, align 4 %0 = getelementptr inbounds [3 x i32], ptr %varargs, i32 0, i32 1 store i32 2, ptr %0, align 4 @@ -62,14 +63,14 @@ entry: %2 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0 %3 = insertvalue { ptr, i32, i32 } %2, i32 %append.newLen, 1 %4 = insertvalue { ptr, i32, i32 } %3, i32 %append.newCap, 2 - call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) ret { ptr, i32, i32 } %4 } -declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr) #1 +declare { ptr, i32, i32 } @runtime.sliceAppend(ptr, ptr nocapture readonly, i32, i32, i32, i32, ptr) #2 ; Function Attrs: nounwind -define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #2 { +define hidden { ptr, i32, i32 } @main.sliceAppendSlice(ptr %ints.data, i32 %ints.len, i32 %ints.cap, ptr %added.data, i32 %added.len, i32 %added.cap, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %append.new = call { ptr, i32, i32 } @runtime.sliceAppend(ptr %ints.data, ptr %added.data, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, ptr undef) #3 @@ -79,21 +80,21 @@ entry: %0 = insertvalue { ptr, i32, i32 } undef, ptr %append.newPtr, 0 %1 = insertvalue { ptr, i32, i32 } %0, i32 %append.newLen, 1 %2 = insertvalue { ptr, i32, i32 } %1, i32 %append.newCap, 2 - call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %append.newPtr, ptr nonnull %stackalloc, ptr undef) ret { ptr, i32, i32 } %2 } ; Function Attrs: nounwind -define hidden i32 @main.sliceCopy(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #2 { +define hidden i32 @main.sliceCopy(ptr %dst.data, i32 %dst.len, i32 %dst.cap, ptr %src.data, i32 %src.len, i32 %src.cap, ptr %context) unnamed_addr #1 { entry: %copy.n = call i32 @runtime.sliceCopy(ptr %dst.data, ptr %src.data, i32 %dst.len, i32 %src.len, i32 4, ptr undef) #3 ret i32 %copy.n } -declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #1 +declare i32 @runtime.sliceCopy(ptr nocapture writeonly, ptr nocapture readonly, i32, i32, i32, ptr) #2 ; Function Attrs: nounwind -define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #2 { +define hidden { ptr, i32, i32 } @main.makeByteSlice(i32 %len, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %slice.maxcap = icmp slt i32 %len, 0 @@ -104,7 +105,7 @@ slice.next: ; preds = %entry %0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0 %1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1 %2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2 - call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) ret { ptr, i32, i32 } %2 slice.throw: ; preds = %entry @@ -112,10 +113,10 @@ slice.throw: ; preds = %entry unreachable } -declare void @runtime.slicePanic(ptr) #1 +declare void @runtime.slicePanic(ptr) #2 ; Function Attrs: nounwind -define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #2 { +define hidden { ptr, i32, i32 } @main.makeInt16Slice(i32 %len, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %slice.maxcap = icmp slt i32 %len, 0 @@ -127,7 +128,7 @@ slice.next: ; preds = %entry %0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0 %1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1 %2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2 - call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) ret { ptr, i32, i32 } %2 slice.throw: ; preds = %entry @@ -136,7 +137,7 @@ slice.throw: ; preds = %entry } ; Function Attrs: nounwind -define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #2 { +define hidden { ptr, i32, i32 } @main.makeArraySlice(i32 %len, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %slice.maxcap = icmp ugt i32 %len, 1431655765 @@ -148,7 +149,7 @@ slice.next: ; preds = %entry %0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0 %1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1 %2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2 - call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) ret { ptr, i32, i32 } %2 slice.throw: ; preds = %entry @@ -157,7 +158,7 @@ slice.throw: ; preds = %entry } ; Function Attrs: nounwind -define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #2 { +define hidden { ptr, i32, i32 } @main.makeInt32Slice(i32 %len, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %slice.maxcap = icmp ugt i32 %len, 1073741823 @@ -169,7 +170,7 @@ slice.next: ; preds = %entry %0 = insertvalue { ptr, i32, i32 } undef, ptr %makeslice.buf, 0 %1 = insertvalue { ptr, i32, i32 } %0, i32 %len, 1 %2 = insertvalue { ptr, i32, i32 } %1, i32 %len, 2 - call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr nonnull %makeslice.buf, ptr nonnull %stackalloc, ptr undef) ret { ptr, i32, i32 } %2 slice.throw: ; preds = %entry @@ -178,26 +179,26 @@ slice.throw: ; preds = %entry } ; Function Attrs: nounwind -define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #2 { +define hidden ptr @main.Add32(ptr %p, i32 %len, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %0 = getelementptr i8, ptr %p, i32 %len - call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %0, ptr nonnull %stackalloc, ptr undef) ret ptr %0 } ; Function Attrs: nounwind -define hidden ptr @main.Add64(ptr %p, i64 %len, ptr %context) unnamed_addr #2 { +define hidden ptr @main.Add64(ptr %p, i64 %len, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %0 = trunc i64 %len to i32 %1 = getelementptr i8, ptr %p, i32 %0 - call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %1, ptr nonnull %stackalloc, ptr undef) ret ptr %1 } ; Function Attrs: nounwind -define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 { +define hidden ptr @main.SliceToArray(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #1 { entry: %0 = icmp ult i32 %s.len, 4 br i1 %0, label %slicetoarray.throw, label %slicetoarray.next @@ -210,14 +211,14 @@ slicetoarray.throw: ; preds = %entry unreachable } -declare void @runtime.sliceToArrayPointerPanic(ptr) #1 +declare void @runtime.sliceToArrayPointerPanic(ptr) #2 ; Function Attrs: nounwind -define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #2 { +define hidden ptr @main.SliceToArrayConst(ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %makeslice = call align 4 dereferenceable(24) ptr @runtime.alloc(i32 24, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3 - call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr nonnull %makeslice, ptr nonnull %stackalloc, ptr undef) br i1 false, label %slicetoarray.throw, label %slicetoarray.next slicetoarray.next: ; preds = %entry @@ -228,7 +229,7 @@ slicetoarray.throw: ; preds = %entry } ; Function Attrs: nounwind -define hidden { ptr, i32, i32 } @main.SliceInt(ptr dereferenceable_or_null(4) %ptr, i32 %len, ptr %context) unnamed_addr #2 { +define hidden { ptr, i32, i32 } @main.SliceInt(ptr dereferenceable_or_null(4) %ptr, i32 %len, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %0 = icmp ugt i32 %len, 1073741823 @@ -242,7 +243,7 @@ unsafe.Slice.next: ; preds = %entry %5 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0 %6 = insertvalue { ptr, i32, i32 } %5, i32 %len, 1 %7 = insertvalue { ptr, i32, i32 } %6, i32 %len, 2 - call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) ret { ptr, i32, i32 } %7 unsafe.Slice.throw: ; preds = %entry @@ -250,10 +251,10 @@ unsafe.Slice.throw: ; preds = %entry unreachable } -declare void @runtime.unsafeSlicePanic(ptr) #1 +declare void @runtime.unsafeSlicePanic(ptr) #2 ; Function Attrs: nounwind -define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #2 { +define hidden { ptr, i32, i32 } @main.SliceUint16(ptr dereferenceable_or_null(1) %ptr, i16 %len, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %0 = icmp eq ptr %ptr, null @@ -266,7 +267,7 @@ unsafe.Slice.next: ; preds = %entry %4 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0 %5 = insertvalue { ptr, i32, i32 } %4, i32 %3, 1 %6 = insertvalue { ptr, i32, i32 } %5, i32 %3, 2 - call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) ret { ptr, i32, i32 } %6 unsafe.Slice.throw: ; preds = %entry @@ -275,7 +276,7 @@ unsafe.Slice.throw: ; preds = %entry } ; Function Attrs: nounwind -define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 { +define hidden { ptr, i32, i32 } @main.SliceUint64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %0 = icmp ugt i64 %len, 1073741823 @@ -290,7 +291,7 @@ unsafe.Slice.next: ; preds = %entry %6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0 %7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1 %8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2 - call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) ret { ptr, i32, i32 } %8 unsafe.Slice.throw: ; preds = %entry @@ -299,7 +300,7 @@ unsafe.Slice.throw: ; preds = %entry } ; Function Attrs: nounwind -define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #2 { +define hidden { ptr, i32, i32 } @main.SliceInt64(ptr dereferenceable_or_null(4) %ptr, i64 %len, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %0 = icmp ugt i64 %len, 1073741823 @@ -314,7 +315,7 @@ unsafe.Slice.next: ; preds = %entry %6 = insertvalue { ptr, i32, i32 } undef, ptr %ptr, 0 %7 = insertvalue { ptr, i32, i32 } %6, i32 %5, 1 %8 = insertvalue { ptr, i32, i32 } %7, i32 %5, 2 - call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) #3 + call void @runtime.trackPointer(ptr %ptr, ptr nonnull %stackalloc, ptr undef) ret { ptr, i32, i32 } %8 unsafe.Slice.throw: ; preds = %entry @@ -322,7 +323,7 @@ unsafe.Slice.throw: ; preds = %entry unreachable } -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } attributes #3 = { nounwind } diff --git a/compiler/testdata/string.ll b/compiler/testdata/string.ll index 64582dd961..ebb7916fcd 100644 --- a/compiler/testdata/string.ll +++ b/compiler/testdata/string.ll @@ -10,34 +10,35 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: nounwind -define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #2 { +define hidden %runtime._string @main.someString(ptr %context) unnamed_addr #1 { entry: ret %runtime._string { ptr @"main$string", i32 3 } } ; Function Attrs: nounwind -define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #2 { +define hidden %runtime._string @main.zeroLengthString(ptr %context) unnamed_addr #1 { entry: ret %runtime._string zeroinitializer } ; Function Attrs: nounwind -define hidden i32 @main.stringLen(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #2 { +define hidden i32 @main.stringLen(ptr %s.data, i32 %s.len, ptr %context) unnamed_addr #1 { entry: ret i32 %s.len } ; Function Attrs: nounwind -define hidden i8 @main.stringIndex(ptr %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #2 { +define hidden i8 @main.stringIndex(ptr %s.data, i32 %s.len, i32 %index, ptr %context) unnamed_addr #1 { entry: %.not = icmp ult i32 %index, %s.len br i1 %.not, label %lookup.next, label %lookup.throw @@ -52,19 +53,19 @@ lookup.throw: ; preds = %entry unreachable } -declare void @runtime.lookupPanic(ptr) #1 +declare void @runtime.lookupPanic(ptr) #2 ; Function Attrs: nounwind -define hidden i1 @main.stringCompareEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 { +define hidden i1 @main.stringCompareEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 { entry: %0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #3 ret i1 %0 } -declare i1 @runtime.stringEqual(ptr, i32, ptr, i32, ptr) #1 +declare i1 @runtime.stringEqual(ptr, i32, ptr, i32, ptr) #2 ; Function Attrs: nounwind -define hidden i1 @main.stringCompareUnequal(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 { +define hidden i1 @main.stringCompareUnequal(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 { entry: %0 = call i1 @runtime.stringEqual(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr undef) #3 %1 = xor i1 %0, true @@ -72,16 +73,16 @@ entry: } ; Function Attrs: nounwind -define hidden i1 @main.stringCompareLarger(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #2 { +define hidden i1 @main.stringCompareLarger(ptr %s1.data, i32 %s1.len, ptr %s2.data, i32 %s2.len, ptr %context) unnamed_addr #1 { entry: %0 = call i1 @runtime.stringLess(ptr %s2.data, i32 %s2.len, ptr %s1.data, i32 %s1.len, ptr undef) #3 ret i1 %0 } -declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1 +declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #2 ; Function Attrs: nounwind -define hidden i8 @main.stringLookup(ptr %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #2 { +define hidden i8 @main.stringLookup(ptr %s.data, i32 %s.len, i8 %x, ptr %context) unnamed_addr #1 { entry: %0 = zext i8 %x to i32 %.not = icmp ult i32 %0, %s.len @@ -97,7 +98,7 @@ lookup.throw: ; preds = %entry unreachable } -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #2 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } attributes #3 = { nounwind } diff --git a/compiler/testdata/zeromap.ll b/compiler/testdata/zeromap.ll index 4ad263130a..036823b228 100644 --- a/compiler/testdata/zeromap.ll +++ b/compiler/testdata/zeromap.ll @@ -8,16 +8,17 @@ target triple = "wasm32-unknown-wasi" ; Function Attrs: allockind("alloc,zeroed") allocsize(0) declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0 +; Function Attrs: nounwind declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1 ; Function Attrs: nounwind -define hidden void @main.init(ptr %context) unnamed_addr #2 { +define hidden void @main.init(ptr %context) unnamed_addr #1 { entry: ret void } ; Function Attrs: noinline nounwind -define hidden i32 @main.testZeroGet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #3 { +define hidden i32 @main.testZeroGet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #2 { entry: %hashmap.key = alloca %main.hasPadding, align 8 %hashmap.value = alloca i32, align 4 @@ -39,17 +40,17 @@ entry: } ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) -declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #4 +declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3 -declare void @runtime.memzero(ptr, i32, ptr) #1 +declare void @runtime.memzero(ptr, i32, ptr) #4 -declare i1 @runtime.hashmapBinaryGet(ptr dereferenceable_or_null(40), ptr, ptr, i32, ptr) #1 +declare i1 @runtime.hashmapBinaryGet(ptr dereferenceable_or_null(40), ptr, ptr, i32, ptr) #4 ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) -declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #4 +declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3 ; Function Attrs: noinline nounwind -define hidden void @main.testZeroSet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #3 { +define hidden void @main.testZeroSet(ptr dereferenceable_or_null(40) %m, i1 %s.b1, i32 %s.i, i1 %s.b2, ptr %context) unnamed_addr #2 { entry: %hashmap.key = alloca %main.hasPadding, align 8 %hashmap.value = alloca i32, align 4 @@ -70,10 +71,10 @@ entry: ret void } -declare void @runtime.hashmapBinarySet(ptr dereferenceable_or_null(40), ptr, ptr, ptr) #1 +declare void @runtime.hashmapBinarySet(ptr dereferenceable_or_null(40), ptr, ptr, ptr) #4 ; Function Attrs: noinline nounwind -define hidden i32 @main.testZeroArrayGet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #3 { +define hidden i32 @main.testZeroArrayGet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #2 { entry: %hashmap.key = alloca [2 x %main.hasPadding], align 8 %hashmap.value = alloca i32, align 4 @@ -100,7 +101,7 @@ entry: } ; Function Attrs: noinline nounwind -define hidden void @main.testZeroArraySet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #3 { +define hidden void @main.testZeroArraySet(ptr dereferenceable_or_null(40) %m, [2 x %main.hasPadding] %s, ptr %context) unnamed_addr #2 { entry: %hashmap.key = alloca [2 x %main.hasPadding], align 8 %hashmap.value = alloca i32, align 4 @@ -127,14 +128,14 @@ entry: } ; Function Attrs: nounwind -define hidden void @main.main(ptr %context) unnamed_addr #2 { +define hidden void @main.main(ptr %context) unnamed_addr #1 { entry: ret void } -attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #1 = { "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #3 = { noinline nounwind "target-features"="+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext" } -attributes #4 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #1 = { nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #2 = { noinline nounwind "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } +attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +attributes #4 = { "target-features"="+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext" } attributes #5 = { nounwind } diff --git a/go.mod b/go.mod index bf85ef3ad1..81e972bd6e 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/sys v0.21.0 golang.org/x/tools v0.22.1-0.20240621165957-db513b091504 gopkg.in/yaml.v2 v2.4.0 - tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8 + tinygo.org/x/go-llvm v0.0.0-20240804145059-aaff3eb751f0 ) require ( diff --git a/go.sum b/go.sum index 7a6d1f4a97..4900ef1ac4 100644 --- a/go.sum +++ b/go.sum @@ -77,5 +77,5 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8 h1:bLsZXRUBavt++CJlMN7sppNziqu3LyamESLhFJcpqFQ= -tinygo.org/x/go-llvm v0.0.0-20240627184919-3b50c76783a8/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0= +tinygo.org/x/go-llvm v0.0.0-20240804145059-aaff3eb751f0 h1:aN9rSxvVWmipB13yVAFOmRj3LX4Kkfiq/fSl5EAilDA= +tinygo.org/x/go-llvm v0.0.0-20240804145059-aaff3eb751f0/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0= diff --git a/main_test.go b/main_test.go index 4c11f7b18d..9421612b79 100644 --- a/main_test.go +++ b/main_test.go @@ -286,10 +286,18 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) { runTest("rand.go", options, t, nil, nil) }) } - if !isWebAssembly { - // The recover() builtin isn't supported yet on WebAssembly and Windows. + if !isWASI { + // On WebAssembly, recover() needs the exception handling proposal which + // isn't (as of 2024) implemented in wasmtime so this test is skipped on + // WASI. t.Run("recover.go", func(t *testing.T) { t.Parallel() + options := options + if isWebAssembly { + // Hack: Asyncify doesn't support exception handling + // instructions. + options.Scheduler = "none" + } runTest("recover.go", options, t, nil, nil) }) } diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 062305f15c..7a5d6605ad 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -15,11 +15,20 @@ func trap() // purposes of TinyGo. It restores the stack pointer and jumps to the given pc. // //export tinygo_longjmp -func tinygo_longjmp(frame *deferFrame) +func tinygo_longjmp(frame *deferFrameInlineAsm) // Compiler intrinsic. // Returns whether recover is supported on the current architecture. -func supportsRecover() bool +func supportsRecover() recoverType + +type recoverType uint8 + +const ( + // Note: these contants match recoverSupport in compiler/defer.go + recoverNone recoverType = iota + recoverInlineAsm + recoverWasmEH +) const ( panicStrategyPrint = 1 @@ -31,33 +40,55 @@ const ( // using the -panic= compiler flag. func panicStrategy() uint8 -// DeferFrame is a stack allocated object that stores information for the -// current "defer frame", which is used in functions that use the `defer` +// LLVM compiler intrinsic: this inserts a wasm 'throw' instruction. +// +//export llvm.wasm.throw +func wasm_throw(uint32, unsafe.Pointer) + +// DeferFrameInlineAsm is a stack allocated object that stores information for +// the current "defer frame", which is used in functions that use the `defer` // keyword. // The compiler knows about the JumpPC struct offset, so it should not be moved // without also updating compiler/defer.go. -type deferFrame struct { +type deferFrameInlineAsm struct { JumpSP unsafe.Pointer // stack pointer to return to JumpPC unsafe.Pointer // pc to return to ExtraRegs [deferExtraRegs]unsafe.Pointer // extra registers (depending on the architecture) - Previous *deferFrame // previous recover buffer pointer + Previous *deferFrameInlineAsm // previous recover buffer pointer Panicking bool // true iff this defer frame is panicking PanicValue interface{} // panic value, might be nil for panic(nil) for example } +// DeferFrameWasmEH is like deferFrameInlineAsm but for WebAssembly exception +// handling. +type deferFrameWasmEH struct { + Previous *deferFrameWasmEH // previous recover buffer pointer + Panicking bool // true iff this defer frame is panicking + PanicValue interface{} // panic value, might be nil for panic(nil) for example +} + // Builtin function panic(msg), used as a compiler intrinsic. func _panic(message interface{}) { if panicStrategy() == panicStrategyTrap { trap() } - if supportsRecover() { - frame := (*deferFrame)(task.Current().DeferFrame) + switch supportsRecover() { + case recoverInlineAsm: + frame := (*deferFrameInlineAsm)(task.Current().DeferFrame) if frame != nil { frame.PanicValue = message frame.Panicking = true tinygo_longjmp(frame) // unreachable } + case recoverWasmEH: + frame := (*deferFrameWasmEH)(task.Current().DeferFrame) + if frame != nil { + frame.PanicValue = message + frame.Panicking = true + wasm_throw(0, nil) + // unreachable + } } printstring("panic: ") printitf(message) @@ -94,21 +125,43 @@ func runtimePanicAt(addr unsafe.Pointer, msg string) { // //go:inline //go:nobounds -func setupDeferFrame(frame *deferFrame, jumpSP unsafe.Pointer) { +func setupDeferFrameInlineAsm(frame *deferFrameInlineAsm, jumpSP unsafe.Pointer) { currentTask := task.Current() - frame.Previous = (*deferFrame)(currentTask.DeferFrame) + frame.Previous = (*deferFrameInlineAsm)(currentTask.DeferFrame) frame.JumpSP = jumpSP frame.Panicking = false currentTask.DeferFrame = unsafe.Pointer(frame) } +//go:inline +//go:nobounds +func setupDeferFrameWasmEH(frame *deferFrameWasmEH) { + currentTask := task.Current() + frame.Previous = (*deferFrameWasmEH)(currentTask.DeferFrame) + frame.Panicking = false + currentTask.DeferFrame = unsafe.Pointer(frame) +} + // Called right before the return instruction. It pops the defer frame from the // linked list of defer frames. It also re-raises a panic if the goroutine is // still panicking. // //go:inline //go:nobounds -func destroyDeferFrame(frame *deferFrame) { +func destroyDeferFrameInlineAsm(frame *deferFrameInlineAsm) { + task.Current().DeferFrame = unsafe.Pointer(frame.Previous) + if frame.Panicking { + // We're still panicking! + // Re-raise the panic now. + _panic(frame.PanicValue) + } +} + +// Like destroyDeferFrameInlineAsm but for wasm. +// +//go:inline +//go:nobounds +func destroyDeferFrameWasmEH(frame *deferFrameWasmEH) { task.Current().DeferFrame = unsafe.Pointer(frame.Previous) if frame.Panicking { // We're still panicking! @@ -122,27 +175,44 @@ func destroyDeferFrame(frame *deferFrame) { // useParentFrame is set when the caller of runtime._recover has a defer frame // itself. In that case, recover() shouldn't check that frame but one frame up. func _recover(useParentFrame bool) interface{} { - if !supportsRecover() { - // Compiling without stack unwinding support, so make this a no-op. - return nil - } // TODO: somehow check that recover() is called directly by a deferred // function in a panicking goroutine. Maybe this can be done by comparing // the frame pointer? - frame := (*deferFrame)(task.Current().DeferFrame) - if useParentFrame { - // Don't recover panic from the current frame (which can't be panicking - // already), but instead from the previous frame. - frame = frame.Previous - } - if frame != nil && frame.Panicking { - // Only the first call to recover returns the panic value. It also stops - // the panicking sequence, hence setting panicking to false. - frame.Panicking = false - return frame.PanicValue + switch supportsRecover() { + case recoverInlineAsm: + frame := (*deferFrameInlineAsm)(task.Current().DeferFrame) + if useParentFrame { + // Don't recover panic from the current frame (which can't be + // panicking already), but instead from the previous frame. + frame = frame.Previous + } + if frame != nil && frame.Panicking { + // Only the first call to recover returns the panic value. It also + // stops the panicking sequence, hence setting panicking to false. + frame.Panicking = false + return frame.PanicValue + } + // Not panicking, so return a nil interface. + return nil + case recoverWasmEH: + frame := (*deferFrameWasmEH)(task.Current().DeferFrame) + if useParentFrame { + // Don't recover panic from the current frame (which can't be + // panicking already), but instead from the previous frame. + frame = frame.Previous + } + if frame != nil && frame.Panicking { + // Only the first call to recover returns the panic value. It also + // stops the panicking sequence, hence setting panicking to false. + frame.Panicking = false + return frame.PanicValue + } + // Not panicking, so return a nil interface. + return nil + default: + // Compiling without stack unwinding support, so make this a no-op. + return nil } - // Not panicking, so return a nil interface. - return nil } // Panic when trying to dereference a nil pointer. diff --git a/targets/wasm.json b/targets/wasm.json index 050ee105e0..6f9138aac8 100644 --- a/targets/wasm.json +++ b/targets/wasm.json @@ -1,7 +1,7 @@ { "llvm-target": "wasm32-unknown-wasi", "cpu": "generic", - "features": "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext", + "features": "+bulk-memory,+exception-handling,+mutable-globals,+nontrapping-fptoint,+sign-ext", "build-tags": ["tinygo.wasm"], "goos": "js", "goarch": "wasm", @@ -12,6 +12,7 @@ "default-stack-size": 65536, "cflags": [ "-mbulk-memory", + "-mexception-handling", "-mnontrapping-fptoint", "-msign-ext" ], diff --git a/testdata/recover.go b/testdata/recover.go index ced90cfaee..725821bfa9 100644 --- a/testdata/recover.go +++ b/testdata/recover.go @@ -17,6 +17,12 @@ func main() { println("\n# panic inside defer") panicInsideDefer() + println("\n# panic inside indirect defer") + panicInsideIndirectDefer(callPanic) + + println("\n# panic inside closure") + panicInsideClosure() + println("\n# panic replace") panicReplace() } @@ -77,6 +83,27 @@ func panicInsideDefer() { }() } +func panicInsideIndirectDefer(callback func()) { + defer func() { + printitf("recovered:", recover()) + }() + defer callback() +} + +func callPanic() { + panic("panic") +} + +func panicInsideClosure() { + msg := "panic" + defer func() { + printitf("recovered:", recover()) + }() + defer func() { + panic(msg) + }() +} + func panicReplace() { defer func() { printitf("recovered:", recover()) diff --git a/testdata/recover.txt b/testdata/recover.txt index d276498550..9faf8619e6 100644 --- a/testdata/recover.txt +++ b/testdata/recover.txt @@ -19,6 +19,12 @@ recovered 2: foo # panic inside defer recovered: panic +# panic inside indirect defer +recovered: panic + +# panic inside closure +recovered: panic + # panic replace panic 1 panic 2 diff --git a/transform/gc.go b/transform/gc.go index 9d1d8f3fbb..4fe585d3da 100644 --- a/transform/gc.go +++ b/transform/gc.go @@ -177,7 +177,7 @@ func MakeGCStackSlots(mod llvm.Module) bool { // now. // With more analysis, it should be possible to optimize a // significant chunk of these away. - case llvm.Call, llvm.Load, llvm.IntToPtr: + case llvm.Call, llvm.Invoke, llvm.Load, llvm.IntToPtr: // These create new values so must be stored locally. But // perhaps some of these can be fused when they actually refer // to the same value.