[llvm-dev] Semantics for non-byte-sized stores? (or whenever "store size in bits" is different than "size in bits")

Björn Pettersson A via llvm-dev llvm-dev at lists.llvm.org
Fri May 17 07:33:45 PDT 2019


It is possible to ask DataLayout about getTypeSizeInBits and also getTypeStoreSize.

And there is a table showing an example of what it could look like:

  /// Size examples:
  ///
  /// Type        SizeInBits  StoreSizeInBits  AllocSizeInBits[*]
  /// ----        ----------  ---------------  ---------------
  ///  i1            1           8                8
  ///  i8            8           8                8
  ///  i19          19          24               32
  ///  i32          32          32               32
  ///  i100        100         104              128
  ///  i128        128         128              128
  ///  Float        32          32               32
  ///  Double       64          64               64
  ///  X86_FP80     80          80               96
  ///
  /// [*] The alloc size depends on the alignment, and thus on the target.
  ///     These values are for x86-32 linux.


Assume that I have LLVM IR for a union between two types that are mapped to i32 and i19.
And then I have two overlapping stores to this union such as:

  %u = alloca %union
  %u32 = bitcast %union* %u to i32*
  %u19 = bitcast %union* %u to i19*
  store i32 -1, i32* %u32
  store i19  0, i19* %u19
  %result = load i32, i32* %u32

How many bits are guaranteed to be zero in %result?
How many bits are guaranteed to be one in %result?

To be more specific:

 a) Is the i19 store defined as only writing 19 bits (even if store size is larger, so it will become a load-modify-write after legalization)?

 b) Is the i19 store defined as touching 24 bits, so we get 5 bits that are undefined (or always zero-extended/sign-extended)?

 c) Is this target specific (and nothing that opt should know about)?

I've got a feeling that the I get different results if feeding the above IR directly into llc, or if I pass it through "opt -dse" first.
(and that might be OK if some bits are undefined in %result)

The actual problem that lead me into these questions is that DeadStoreElimination asserts/miscompiles (depending on endianness) when having something like this instead (partial overwrite of a store that isn't byte-sized):

  %u = alloca %union
  %u32 = bitcast %union* %u to i32*
  %u19 = bitcast %union* %u to i19*
  %u16 = bitcast %union* %u to i16*
  store i19  0, i19* %u19
  store i16 -1, i16* %u16
  %result = load i32, i32* %u32

I'm planning to write a PR (and make a bugfix) but got uncertain about what the correct behavior would be here.

Yet another question is if the i19 value is guaranteed to be placed in the least significant end of the 3 bytes that are tainted by the store?

/Björn (bjope)


More information about the llvm-dev mailing list