package ssaimport ()// BasicBlock represents the Basic Block of an SSA function.// Each BasicBlock always ends with branching instructions (e.g. Branch, Return, etc.),// and at most two branches are allowed. If there's two branches, these two are placed together at the end of the block.// In other words, there's no branching instruction in the middle of the block.//// Note: we use the "block argument" variant of SSA, instead of PHI functions. See the package level doc comments.//// Note: we use "parameter/param" as a placeholder which represents a variant of PHI, and "argument/arg" as an actual// Value passed to that "parameter/param".typeBasicBlockinterface {// ID returns the unique ID of this block.ID() BasicBlockID// Name returns the unique string ID of this block. e.g. blk0, blk1, ...Name() string// AddParam adds the parameter to the block whose type specified by `t`.AddParam(b Builder, t Type) Value// Params returns the number of parameters to this block.Params() int// Param returns (Variable, Value) which corresponds to the i-th parameter of this block. // The returned Value is the definition of the param in this block.Param(i int) Value// Root returns the root instruction of this block.Root() *Instruction// Tail returns the tail instruction of this block.Tail() *Instruction// EntryBlock returns true if this block represents the function entry.EntryBlock() bool// ReturnBlock returns ture if this block represents the function return.ReturnBlock() bool// Valid is true if this block is still valid even after optimizations.Valid() bool// Sealed is true if this block has been sealed.Sealed() bool// Preds returns the number of predecessors of this block.Preds() int// Pred returns the i-th predecessor of this block.Pred(i int) BasicBlock// Succs returns the number of successors of this block.Succs() int// Succ returns the i-th successor of this block.Succ(i int) BasicBlock// LoopHeader returns true if this block is a loop header.LoopHeader() bool// LoopNestingForestChildren returns the children of this block in the loop nesting forest.LoopNestingForestChildren() []BasicBlock}type (// basicBlock is a basic block in a SSA-transformed function. basicBlock struct { id BasicBlockID rootInstr, currentInstr *Instruction// params are Values that represent parameters to a basicBlock. // Each parameter can be considered as an output of PHI instruction in traditional SSA. params Values preds []basicBlockPredecessorInfo success []*basicBlock// singlePred is the alias to preds[0] for fast lookup, and only set after Seal is called. singlePred *basicBlock// lastDefinitions maps Variable to its last definition in this block. lastDefinitions map[Variable]Value// unknownsValues are used in builder.findValue. The usage is well-described in the paper. unknownValues []unknownValue// invalid is true if this block is made invalid during optimizations. invalid bool// sealed is true if this is sealed (all the predecessors are known). sealed bool// loopHeader is true if this block is a loop header: // // > A loop header (sometimes called the entry point of the loop) is a dominator that is the target // > of a loop-forming back edge. The loop header dominates all blocks in the loop body. // > A block may be a loop header for more than one loop. A loop may have multiple entry points, // > in which case it has no "loop header". // // See https://en.wikipedia.org/wiki/Control-flow_graph for more details. // // This is modified during the subPassLoopDetection pass. loopHeader bool// loopNestingForestChildren holds the children of this block in the loop nesting forest. // Non-empty if and only if this block is a loop header (i.e. loopHeader=true) loopNestingForestChildren wazevoapi.VarLength[BasicBlock]// reversePostOrder is used to sort all the blocks in the function in reverse post order. // This is used in builder.LayoutBlocks. reversePostOrder int32// visited is used during various traversals. visited int32// child and sibling are the ones in the dominator tree. child, sibling *basicBlock }// BasicBlockID is the unique ID of a basicBlock.BasicBlockIDuint32 unknownValue struct {// variable is the variable that this unknownValue represents. variable Variable// value is the value that this unknownValue represents. value Value })// basicBlockVarLengthNil is the default nil value for basicBlock.loopNestingForestChildren.var basicBlockVarLengthNil = wazevoapi.NewNilVarLength[BasicBlock]()const basicBlockIDReturnBlock = 0xffffffff// Name implements BasicBlock.Name.func ( *basicBlock) () string {if .id == basicBlockIDReturnBlock {return"blk_ret" } else {returnfmt.Sprintf("blk%d", .id) }}// String implements fmt.Stringer for debugging.func ( BasicBlockID) () string {if == basicBlockIDReturnBlock {return"blk_ret" } else {returnfmt.Sprintf("blk%d", ) }}// ID implements BasicBlock.ID.func ( *basicBlock) () BasicBlockID {return .id}// basicBlockPredecessorInfo is the information of a predecessor of a basicBlock.// predecessor is determined by a pair of block and the branch instruction used to jump to the successor.type basicBlockPredecessorInfo struct { blk *basicBlock branch *Instruction}// EntryBlock implements BasicBlock.EntryBlock.func ( *basicBlock) () bool {return .id == 0}// ReturnBlock implements BasicBlock.ReturnBlock.func ( *basicBlock) () bool {return .id == basicBlockIDReturnBlock}// AddParam implements BasicBlock.AddParam.func ( *basicBlock) ( Builder, Type) Value { := .allocateValue() .params = .params.Append(&.(*builder).varLengthPool, )return}// addParamOn adds a parameter to this block whose value is already allocated.func ( *basicBlock) ( *builder, Value) { .params = .params.Append(&.varLengthPool, )}// Params implements BasicBlock.Params.func ( *basicBlock) () int {returnlen(.params.View())}// Param implements BasicBlock.Param.func ( *basicBlock) ( int) Value {return .params.View()[]}// Valid implements BasicBlock.Valid.func ( *basicBlock) () bool {return !.invalid}// Sealed implements BasicBlock.Sealed.func ( *basicBlock) () bool {return .sealed}// insertInstruction implements BasicBlock.InsertInstruction.func ( *basicBlock) ( *builder, *Instruction) { := .currentInstrif != nil { .next = .prev = } else { .rootInstr = } .currentInstr = switch .opcode {caseOpcodeJump, OpcodeBrz, OpcodeBrnz: := BasicBlockID(.rValue) .basicBlock().addPred(, )caseOpcodeBrTable:for , := range .rValues.View() { := BasicBlockID() .basicBlock().addPred(, ) } }}// NumPreds implements BasicBlock.NumPreds.func ( *basicBlock) () int {returnlen(.preds)}// Preds implements BasicBlock.Preds.func ( *basicBlock) () int {returnlen(.preds)}// Pred implements BasicBlock.Pred.func ( *basicBlock) ( int) BasicBlock {return .preds[].blk}// Succs implements BasicBlock.Succs.func ( *basicBlock) () int {returnlen(.success)}// Succ implements BasicBlock.Succ.func ( *basicBlock) ( int) BasicBlock {return .success[]}// Root implements BasicBlock.Root.func ( *basicBlock) () *Instruction {return .rootInstr}// Tail implements BasicBlock.Tail.func ( *basicBlock) () *Instruction {return .currentInstr}// reset resets the basicBlock to its initial state so that it can be reused for another function.func resetBasicBlock( *basicBlock) { .params = ValuesNil .rootInstr, .currentInstr = nil, nil .preds = .preds[:0] .success = .success[:0] .invalid, .sealed = false, false .singlePred = nil .unknownValues = .unknownValues[:0] .lastDefinitions = wazevoapi.ResetMap(.lastDefinitions) .reversePostOrder = -1 .visited = 0 .loopNestingForestChildren = basicBlockVarLengthNil .loopHeader = false .sibling = nil .child = nil}// addPred adds a predecessor to this block specified by the branch instruction.func ( *basicBlock) ( BasicBlock, *Instruction) {if .sealed {panic("BUG: trying to add predecessor to a sealed block: " + .Name()) } := .(*basicBlock)for := range .preds { := &.preds[]if .blk == && .branch != {// If the target is already added, then this must come from the same BrTable, // otherwise such redundant branch should be eliminated by the frontend. (which should be simpler).panic(fmt.Sprintf("BUG: redundant non BrTable jumps in %s whose targes are the same", .Name())) } } .preds = append(.preds, basicBlockPredecessorInfo{blk: ,branch: , }) .success = append(.success, )}// formatHeader returns the string representation of the header of the basicBlock.func ( *basicBlock) ( Builder) string { := make([]string, len(.params.View()))for , := range .params.View() { [] = .formatWithType() }iflen(.preds) > 0 { := make([]string, 0, len(.preds))for , := range .preds {if .blk.invalid {continue } = append(, fmt.Sprintf("blk%d", .blk.id)) }returnfmt.Sprintf("blk%d: (%s) <-- (%s)", .id, strings.Join(, ","), strings.Join(, ",")) } else {returnfmt.Sprintf("blk%d: (%s)", .id, strings.Join(, ", ")) }}// validates validates the basicBlock for debugging purpose.func ( *basicBlock) ( *builder) {if .invalid {panic("BUG: trying to validate an invalid block: " + .Name()) }iflen(.preds) > 0 {for , := range .preds {if .branch.opcode != OpcodeBrTable { := int(.branch.rValue) := .basicBlocksPool.View()if != {panic(fmt.Sprintf("BUG: '%s' is not branch to %s, but to %s", .branch.Format(), .Name(), .Name())) } }varintif .ReturnBlock() { = len(.currentSignature.Results) } else { = len(.params.View()) }iflen(.branch.vs.View()) != {panic(fmt.Sprintf("BUG: len(argument at %s) != len(params at %s): %d != %d: %s", .blk.Name(), .Name(),len(.branch.vs.View()), len(.params.View()), .branch.Format(), )) } } }}// String implements fmt.Stringer for debugging purpose only.func ( *basicBlock) () string {returnstrconv.Itoa(int(.id))}// LoopNestingForestChildren implements BasicBlock.LoopNestingForestChildren.func ( *basicBlock) () []BasicBlock {return .loopNestingForestChildren.View()}// LoopHeader implements BasicBlock.LoopHeader.func ( *basicBlock) () bool {return .loopHeader}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.