github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/engine/wazevo/backend/isa/arm64/cond.go (about)

     1  package arm64
     2  
     3  import (
     4  	"strconv"
     5  
     6  	"github.com/wasilibs/wazerox/internal/engine/wazevo/backend/regalloc"
     7  	"github.com/wasilibs/wazerox/internal/engine/wazevo/ssa"
     8  )
     9  
    10  type (
    11  	cond     uint64
    12  	condKind byte
    13  )
    14  
    15  const (
    16  	// condKindRegisterZero represents a condition which checks if the register is zero.
    17  	// This indicates that the instruction must be encoded as CBZ:
    18  	// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/CBZ--Compare-and-Branch-on-Zero-
    19  	condKindRegisterZero condKind = iota
    20  	// condKindRegisterNotZero indicates that the instruction must be encoded as CBNZ:
    21  	// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/CBNZ--Compare-and-Branch-on-Nonzero-
    22  	condKindRegisterNotZero
    23  	// condKindCondFlagSet indicates that the instruction must be encoded as B.cond:
    24  	// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/B-cond--Branch-conditionally-
    25  	condKindCondFlagSet
    26  )
    27  
    28  // kind returns the kind of condition which is stored in the first two bits.
    29  func (c cond) kind() condKind {
    30  	return condKind(c & 0b11)
    31  }
    32  
    33  func (c cond) asUint64() uint64 {
    34  	return uint64(c)
    35  }
    36  
    37  // register returns the register for register conditions.
    38  // This panics if the condition is not a register condition (condKindRegisterZero or condKindRegisterNotZero).
    39  func (c cond) register() regalloc.VReg {
    40  	if c.kind() != condKindRegisterZero && c.kind() != condKindRegisterNotZero {
    41  		panic("condition is not a register")
    42  	}
    43  	return regalloc.VReg(c >> 2)
    44  }
    45  
    46  func registerAsRegZeroCond(r regalloc.VReg) cond {
    47  	return cond(r)<<2 | cond(condKindRegisterZero)
    48  }
    49  
    50  func registerAsRegNotZeroCond(r regalloc.VReg) cond {
    51  	return cond(r)<<2 | cond(condKindRegisterNotZero)
    52  }
    53  
    54  func (c cond) flag() condFlag {
    55  	if c.kind() != condKindCondFlagSet {
    56  		panic("condition is not a flag")
    57  	}
    58  	return condFlag(c >> 2)
    59  }
    60  
    61  func (c condFlag) asCond() cond {
    62  	return cond(c)<<2 | cond(condKindCondFlagSet)
    63  }
    64  
    65  // condFlag represents a condition flag for conditional branches.
    66  // The value matches the encoding of condition flags in the ARM64 instruction set.
    67  // https://developer.arm.com/documentation/den0024/a/The-A64-instruction-set/Data-processing-instructions/Conditional-instructions
    68  type condFlag uint8
    69  
    70  const (
    71  	eq condFlag = iota // eq represents "equal"
    72  	ne                 // ne represents "not equal"
    73  	hs                 // hs represents "higher or same"
    74  	lo                 // lo represents "lower"
    75  	mi                 // mi represents "minus or negative result"
    76  	pl                 // pl represents "plus or positive result"
    77  	vs                 // vs represents "overflow set"
    78  	vc                 // vc represents "overflow clear"
    79  	hi                 // hi represents "higher"
    80  	ls                 // ls represents "lower or same"
    81  	ge                 // ge represents "greater or equal"
    82  	lt                 // lt represents "less than"
    83  	gt                 // gt represents "greater than"
    84  	le                 // le represents "less than or equal"
    85  	al                 // al represents "always"
    86  	nv                 // nv represents "never"
    87  )
    88  
    89  // invert returns the inverted condition.
    90  func (c condFlag) invert() condFlag {
    91  	switch c {
    92  	case eq:
    93  		return ne
    94  	case ne:
    95  		return eq
    96  	case hs:
    97  		return lo
    98  	case lo:
    99  		return hs
   100  	case mi:
   101  		return pl
   102  	case pl:
   103  		return mi
   104  	case vs:
   105  		return vc
   106  	case vc:
   107  		return vs
   108  	case hi:
   109  		return ls
   110  	case ls:
   111  		return hi
   112  	case ge:
   113  		return lt
   114  	case lt:
   115  		return ge
   116  	case gt:
   117  		return le
   118  	case le:
   119  		return gt
   120  	case al:
   121  		return nv
   122  	case nv:
   123  		return al
   124  	default:
   125  		panic(c)
   126  	}
   127  }
   128  
   129  // String implements fmt.Stringer.
   130  func (c condFlag) String() string {
   131  	switch c {
   132  	case eq:
   133  		return "eq"
   134  	case ne:
   135  		return "ne"
   136  	case hs:
   137  		return "hs"
   138  	case lo:
   139  		return "lo"
   140  	case mi:
   141  		return "mi"
   142  	case pl:
   143  		return "pl"
   144  	case vs:
   145  		return "vs"
   146  	case vc:
   147  		return "vc"
   148  	case hi:
   149  		return "hi"
   150  	case ls:
   151  		return "ls"
   152  	case ge:
   153  		return "ge"
   154  	case lt:
   155  		return "lt"
   156  	case gt:
   157  		return "gt"
   158  	case le:
   159  		return "le"
   160  	case al:
   161  		return "al"
   162  	case nv:
   163  		return "nv"
   164  	default:
   165  		panic(strconv.Itoa(int(c)))
   166  	}
   167  }
   168  
   169  // condFlagFromSSAIntegerCmpCond returns the condition flag for the given ssa.IntegerCmpCond.
   170  func condFlagFromSSAIntegerCmpCond(c ssa.IntegerCmpCond) condFlag {
   171  	switch c {
   172  	case ssa.IntegerCmpCondEqual:
   173  		return eq
   174  	case ssa.IntegerCmpCondNotEqual:
   175  		return ne
   176  	case ssa.IntegerCmpCondSignedLessThan:
   177  		return lt
   178  	case ssa.IntegerCmpCondSignedGreaterThanOrEqual:
   179  		return ge
   180  	case ssa.IntegerCmpCondSignedGreaterThan:
   181  		return gt
   182  	case ssa.IntegerCmpCondSignedLessThanOrEqual:
   183  		return le
   184  	case ssa.IntegerCmpCondUnsignedLessThan:
   185  		return lo
   186  	case ssa.IntegerCmpCondUnsignedGreaterThanOrEqual:
   187  		return hs
   188  	case ssa.IntegerCmpCondUnsignedGreaterThan:
   189  		return hi
   190  	case ssa.IntegerCmpCondUnsignedLessThanOrEqual:
   191  		return ls
   192  	default:
   193  		panic(c)
   194  	}
   195  }
   196  
   197  // condFlagFromSSAFloatCmpCond returns the condition flag for the given ssa.FloatCmpCond.
   198  func condFlagFromSSAFloatCmpCond(c ssa.FloatCmpCond) condFlag {
   199  	switch c {
   200  	case ssa.FloatCmpCondEqual:
   201  		return eq
   202  	case ssa.FloatCmpCondNotEqual:
   203  		return ne
   204  	case ssa.FloatCmpCondLessThan:
   205  		return mi
   206  	case ssa.FloatCmpCondLessThanOrEqual:
   207  		return ls
   208  	case ssa.FloatCmpCondGreaterThan:
   209  		return gt
   210  	case ssa.FloatCmpCondGreaterThanOrEqual:
   211  		return ge
   212  	default:
   213  		panic(c)
   214  	}
   215  }