Skip to content

Range types always uses signed integer as a base type #13646

@mratsim

Description

@mratsim

Range always use signed integer as the base type in the codegen.

Example:

type
  BaseUint* = SomeUnsignedInt or byte
  Ct*[T: BaseUint] = distinct T
    ## Constant-Time wrapper
    ## Only constant-time operations in particular the ternary operator equivalent
    ##   condition: if true: a else: b
    ## are allowed

  CTBool*[T: Ct] = distinct range[T(0)..T(1)]
    ## Constant-Time boolean wrapper

var x: array[8, CTBool[Ct[uint32]]]
x[0] = (CTBool[Ct[uint32]])(1)
echo x.repr

C code

// [...]
typedef NI tyArray__tvxsR2G9chmuUgp9afapiQkg[8];
// [...]
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
{
	tyArray__nHXaesL0DJZHyVS07ARPRA T1_;
	nimfr_("range_unsigned", "/home/beta/Programming/Nim/constantine/build/range_unsigned.nim");
	nimln_(13, "/home/beta/Programming/Nim/constantine/build/range_unsigned.nim");
	x__C3MQJCEokeOV37kXufP37g[(((NI) 0))- 0] = ((NI) 1);
	nimln_(14, "/home/beta/Programming/Nim/constantine/build/range_unsigned.nim");
	nimZeroMem((void*)T1_, sizeof(tyArray__nHXaesL0DJZHyVS07ARPRA));
	T1_[0] = reprAny(x__C3MQJCEokeOV37kXufP37g, (&NTI__tvxsR2G9chmuUgp9afapiQkg_));
	echoBinSafe(T1_, 1);
	popFrame();
}
}
// [...]

This causes the following issues, note that this is used in a cryptographic library for BigInt

  • The CTBool should be the same size as the base word, if the base word is uint32 on a x86-64 CPU they are not.
  • This causes issues for inline assembly, as with 32-bit word we expect testl + cmovl to work
    but they only work on 32-bit width operand.
    func mux*[T](ctl: CTBool[T], x, y: T): T {.inline.}=
      ## Multiplexer / selector
      ## Returns x if ctl is true
      ## else returns y
      ## So equivalent to ctl? x: y
      when defined(amd64) or defined(i386):
        when sizeof(T) == 8:
          var muxed = x
          asm """
            testq %[ctl], %[ctl]
            cmovzq %[y], %[muxed]
            : [muxed] "+r" (`muxed`)
            : [ctl] "r" (`ctl`), [y] "r" (`y`)
            : "cc"
          """
          muxed
        elif sizeof(T) == 4:
          var muxed = x
          asm """
            testl %[ctl], %[ctl]
            cmovzl %[y], %[muxed]
            : [muxed] "+r" (`muxed`)
            : [ctl] "r" (`ctl`), [y] "r" (`y`)
            : "cc"
          """
          muxed
        else:
          {.error: "Unsupported word size".}
      else:
        y xor (-T(ctl) and (x xor y))
  • C compilers use the undefined behavior of signed int for optimization. As mentioned in
  • Functions that return or accept this CTBool will use 8 bytes instead of 4 bytes

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions