///|
pub fn[Inst] TargetInstructionVerifier::scalar_load(
  self : TargetInstructionVerifier[Inst],
  width : @native.AccessWidth,
  extension : @native.LoadExtension,
  result_type : @native.ValueType,
  target~ : String,
) -> Unit raise TargetVCodeVerifyError {
  if !@native.valid_scalar_load(width, extension, result_type) {
    raise InvalidInstruction(
      instruction=self.instruction,
      message="invalid \{target} scalar load type or extension",
    )
  }
  self.shape([Ptr64], [result_type])
}

///|
pub fn[Inst] TargetInstructionVerifier::scalar_store(
  self : TargetInstructionVerifier[Inst],
  width : @native.AccessWidth,
  value_type : @native.ValueType,
  target~ : String,
) -> Unit raise TargetVCodeVerifyError {
  if !@native.valid_scalar_store(width, value_type) {
    raise InvalidInstruction(
      instruction=self.instruction,
      message="invalid \{target} scalar store type or width",
    )
  }
  self.shape([Ptr64, value_type], [])
}

///|
pub fn[Inst] TargetInstructionVerifier::atomic_load(
  self : TargetInstructionVerifier[Inst],
  width : @native.AccessWidth,
  ty : @native.ValueType,
  target~ : String,
) -> Unit raise TargetVCodeVerifyError {
  if !@native.valid_atomic_access(width, ty) {
    raise InvalidInstruction(
      instruction=self.instruction,
      message="invalid \{target} atomic load width or type",
    )
  }
  self.shape([Ptr64], [ty])
}

///|
pub fn[Inst] TargetInstructionVerifier::atomic_store(
  self : TargetInstructionVerifier[Inst],
  width : @native.AccessWidth,
  ty : @native.ValueType,
  target~ : String,
) -> Unit raise TargetVCodeVerifyError {
  if !@native.valid_atomic_access(width, ty) {
    raise InvalidInstruction(
      instruction=self.instruction,
      message="invalid \{target} atomic store width or type",
    )
  }
  self.shape([Ptr64, ty], [])
}

///|
pub fn[Inst] TargetInstructionVerifier::atomic_rmw(
  self : TargetInstructionVerifier[Inst],
  width : @native.AccessWidth,
  ty : @native.ValueType,
  target~ : String,
) -> Unit raise TargetVCodeVerifyError {
  if !@native.valid_atomic_access(width, ty) {
    raise InvalidInstruction(
      instruction=self.instruction,
      message="invalid \{target} atomic RMW width or type",
    )
  }
  self.shape([Ptr64, ty], [ty])
}

///|
pub fn[Inst] TargetInstructionVerifier::atomic_compare_exchange(
  self : TargetInstructionVerifier[Inst],
  width : @native.AccessWidth,
  ty : @native.ValueType,
  target~ : String,
) -> Unit raise TargetVCodeVerifyError {
  if !@native.valid_atomic_access(width, ty) {
    raise InvalidInstruction(
      instruction=self.instruction,
      message="invalid \{target} atomic compare-exchange width or type",
    )
  }
  self.shape([Ptr64, ty, ty], [ty])
  self.atomic_early_def(
    "atomic compare-exchange result must be an early definition",
  )
}

///|
pub fn[Inst] TargetInstructionVerifier::atomic_early_def(
  self : TargetInstructionVerifier[Inst],
  message : String,
) -> Unit raise TargetVCodeVerifyError {
  let result = self.function
    .instruction_operands(self.instruction)
    .filter(operand => operand.role == Def)[0]
  if result.timing != Early {
    raise InvalidInstruction(instruction=self.instruction, message~)
  }
}

///|
pub fn[Inst] TargetInstructionVerifier::store_repeated64(
  self : TargetInstructionVerifier[Inst],
  offset : UInt64,
  count : UInt32,
) -> Unit raise TargetVCodeVerifyError {
  if count == 0U || offset > 0xFFFFFFFFFFFFFFFFUL - count.to_uint64() * 8UL {
    raise InvalidInstruction(
      instruction=self.instruction,
      message="invalid repeated word range",
    )
  }
  self.shape([Ptr64], [Ptr64, I64, I64])
  for index, operand in self.function.instruction_operands(self.instruction) {
    if operand.timing != (if index == 0 { Late } else { Early }) ||
      operand.tie_id >= 0 ||
      !(operand.constraint is AnyReg || operand.constraint is FixedReg(_)) {
      raise InvalidInstruction(
        instruction=self.instruction,
        message="word fill requires a late address and three independent early register temporaries",
      )
    }
  }
}