MCPcopy
hub / github.com/tinygo-org/tinygo / createSyscalln

Method createSyscalln

compiler/syscall.go:359–474  ·  view source on GitHub ↗

createSyscalln emits instructions for the syscall.syscalln function on Windows. This handles the variadic calling convention used in Go 1.26+: func syscalln(fn, n uintptr, args ...uintptr) (r1, r2 uintptr, err Errno) The function generates a switch on n to dispatch to the correct fixed-argument f

(call *ssa.CallCommon)

Source from the content-addressed store, hash-verified

357// The function generates a switch on n to dispatch to the correct fixed-argument
358// function pointer call with SetLastError(0)/GetLastError() wrapping.
359func (b *builder) createSyscalln(call *ssa.CallCommon) (llvm.Value, error) {
360 const maxArgs = 18 // Windows syscalls support up to 18 args
361
362 isI386 := strings.HasPrefix(b.Triple, "i386-")
363
364 // Get the function pointer (call.Args[0]) and n (call.Args[1]).
365 fn := b.getValue(call.Args[0], getPos(call))
366 fnPtr := b.CreateIntToPtr(fn, b.dataPtrType, "")
367 n := b.getValue(call.Args[1], getPos(call))
368
369 // Get the variadic args slice (call.Args[2]).
370 // In SSA, the variadic slice is the third argument.
371 var argsPtr llvm.Value
372 if len(call.Args) > 2 {
373 argsSlice := b.getValue(call.Args[2], getPos(call))
374 argsPtr = b.CreateExtractValue(argsSlice, 0, "args.data")
375 } else {
376 argsPtr = llvm.ConstNull(b.dataPtrType)
377 }
378
379 // Prepare SetLastError and GetLastError.
380 setLastError := b.mod.NamedFunction("SetLastError")
381 if setLastError.IsNil() {
382 llvmType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.ctx.Int32Type()}, false)
383 setLastError = llvm.AddFunction(b.mod, "SetLastError", llvmType)
384 if isI386 {
385 setLastError.SetFunctionCallConv(llvm.X86StdcallCallConv)
386 }
387 }
388 getLastError := b.mod.NamedFunction("GetLastError")
389 if getLastError.IsNil() {
390 llvmType := llvm.FunctionType(b.ctx.Int32Type(), nil, false)
391 getLastError = llvm.AddFunction(b.mod, "GetLastError", llvmType)
392 if isI386 {
393 getLastError.SetFunctionCallConv(llvm.X86StdcallCallConv)
394 }
395 }
396
397 retType := b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType, b.uintptrType}, false)
398
399 // Create the merge block where all cases converge.
400 mergeBB := b.insertBasicBlock("syscalln.merge")
401
402 // Create the default (panic) block.
403 panicBB := b.insertBasicBlock("syscalln.panic")
404
405 // Create the switch on n.
406 sw := b.CreateSwitch(n, panicBB, maxArgs+1)
407
408 // We'll collect blocks and values for the PHI node.
409 var incomingVals []llvm.Value
410 var incomingBlocks []llvm.BasicBlock
411
412 // Generate a case for each arg count 0..maxArgs.
413 for i := 0; i <= maxArgs; i++ {
414 caseBB := b.insertBasicBlock("syscalln.case" + strconv.Itoa(i))
415 sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), caseBB)
416 b.SetInsertPointAtEnd(caseBB)

Callers 1

createFunctionCallMethod · 0.95

Calls 6

getValueMethod · 0.95
insertBasicBlockMethod · 0.95
readStackPointerMethod · 0.95
writeStackPointerMethod · 0.95
IsNilMethod · 0.80
getPosFunction · 0.70

Tested by

no test coverage detected