package ssa

import (
	
	
	

	
)

// 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".
type BasicBlock interface {
	// 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.
	BasicBlockID uint32

	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 {
		return fmt.Sprintf("blk%d", .id)
	}
}

// String implements fmt.Stringer for debugging.
func ( BasicBlockID) () string {
	if  == basicBlockIDReturnBlock {
		return "blk_ret"
	} else {
		return fmt.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 {
	return len(.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) {
	 := .currentInstr
	if  != nil {
		.next = 
		.prev = 
	} else {
		.rootInstr = 
	}
	.currentInstr = 

	switch .opcode {
	case OpcodeJump, OpcodeBrz, OpcodeBrnz:
		 := BasicBlockID(.rValue)
		.basicBlock().addPred(, )
	case OpcodeBrTable:
		for ,  := range .rValues.View() {
			 := BasicBlockID()
			.basicBlock().addPred(, )
		}
	}
}

// NumPreds implements BasicBlock.NumPreds.
func ( *basicBlock) () int {
	return len(.preds)
}

// Preds implements BasicBlock.Preds.
func ( *basicBlock) () int {
	return len(.preds)
}

// Pred implements BasicBlock.Pred.
func ( *basicBlock) ( int) BasicBlock {
	return .preds[].blk
}

// Succs implements BasicBlock.Succs.
func ( *basicBlock) () int {
	return len(.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()
	}

	if len(.preds) > 0 {
		 := make([]string, 0, len(.preds))
		for ,  := range .preds {
			if .blk.invalid {
				continue
			}
			 = append(, fmt.Sprintf("blk%d", .blk.id))

		}
		return fmt.Sprintf("blk%d: (%s) <-- (%s)",
			.id, strings.Join(, ","), strings.Join(, ","))
	} else {
		return fmt.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())
	}
	if len(.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()))
				}
			}

			var  int
			if .ReturnBlock() {
				 = len(.currentSignature.Results)
			} else {
				 = len(.params.View())
			}

			if len(.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 {
	return strconv.Itoa(int(.id))
}

// LoopNestingForestChildren implements BasicBlock.LoopNestingForestChildren.
func ( *basicBlock) () []BasicBlock {
	return .loopNestingForestChildren.View()
}

// LoopHeader implements BasicBlock.LoopHeader.
func ( *basicBlock) () bool {
	return .loopHeader
}