[RFC] Add TBAA metadata to returned aggregates (original) (raw)

November 28, 2025, 5:20pm 1

Problem

In LLVM IR, when we store an aggregate value returned from a function, Clang does not emit TBAA metadata. Compiling the following c++ code with -S -emit-llvm -fsanitize=type -Xclang -disable-llvm-passes to get the ir with tbaa

struct S{
  int i;
  float f;
};

S get_S(){ return {0, 0.f};}
int get_int(){ return 0;}

int main(){
  S s = get_S();
  int i = get_int();
}

the IR for main is the following

define dso_local noundef i32 @main() #1 {
entry:
  %s = alloca %struct.S, align 4
  %i = alloca i32, align 4
  %call = call i64 @_Z5get_Sv()
  store i64 %call, ptr %s, align 4  ; No tbaa on this store
  %call1 = call noundef i32 @_Z7get_intv()
  store i32 %call1, ptr %i, align 4, !tbaa !6 ; tbaa on this store
  ret i32 0
}

Note that we get the tbaa metadata for the returned int, but we don’t get metadata for the returned struct S.
As an aside, S is returned as an i64 here as an optimization, but this remains a (less readable) problem for larger aggregate types too.

Proposal

Patch clang so that when we return a known aggregate type, the resulting stores are tagged with the correct tbaa metadata for the type. For example

%call = call i64 @_Z5get_Sv()
  store i64 %call, ptr %s, align 4, !tbaa !(correct data)

See [Clang] Introduce TBAA metadata for some returned structs by BStott6 · Pull Request #171173 · llvm/llvm-project · GitHub , which looks like the implementation of this.

This looks like a straightforward extension of TBAA to a place where it naturally makes sense. That said, extending TBAA always carries some risk of causing issues for code which isn’t correctly following TBAA rules. Do you expect this will be a significant performance improvement? Or is there some other motivation for this?

jyknight December 11, 2025, 9:27pm 3

That said, extending TBAA always carries some risk of causing issues for code which isn’t correctly following TBAA rules

Any new TBAA-based optimization added also has the risk of breaking additional code that is correctly following the language rules, since LLVM’s TBAA implementation is fundamentally broken vs what’s permitted according to the language standards.

(I wish we’d just disable TBAA by default until someone gets around to redoing it.)

Ref:

gbMattN December 15, 2025, 11:23am 4

Using @BStott’s patch to compile LLVM’s single source benchmarks into IR with -O3, there were no changes. The patch only emits metadata for one subcase, but I wouldn’t expect a significant performance improvement even for all cases (I think this also implies a lower risk of issues for strict alias violating code)

The main motivation of this was to reduce some of TypeSanitizer’s blindspots. So far, all of its instrumentation is generated through TBAA metadata, and I felt it would be better to add the metadata to blindspots then introduce some TySan specific type data. This is so TySan accurately sanitizes the types as llvm would see them.

This means that if it does cause issues in code which isn’t correctly following TBAA rules, then TypeSanitizer would now be able to find the issue.