tbaa error: Access type node must be a valid scalar type

Hi

I am upgrading my clang fork from 5.0 to 6.0 and I am hit by this error:

Access type node must be a valid scalar type

   %4 = load %"struct.Foo::p.test1::"*, %"struct.Foo::p.test1::"** %_param.addr, align 8, !tbaa !16
!16 = !{!15, !15, i64 0}
!15 = !{!"p.test1::", !13, i64 0, !13, i64 8}

It looks like !16 is referencing !15, which is a struct. !13 is
!13 = !{!"any pointer", !8, i64 0}

But the %4 instruction just deals with pointers, so why is there a problem ? The code itself is generated using clang CodeGen routines.
(I wouldn't even know how to manipulate !tbaa directly :slight_smile:

If I remove the !tbaa from %4, llc assembles it fine.
My compiler output didn't change.When I use the 5.0 compiler I get the same (wrong ?) tbaa output. But it didn't used to matter.

I looked at https://lists.llvm.org/pipermail/llvm-dev/2017-January/109028.html, but I don't think it's related as there is no root involved.

Ciao
    Nat!

Here is the complete IR. I marked the interesting spots with ****.

; ModuleID = 'expected_reuse.m'
source_filename = "expected_reuse.m"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.13.0"

%struct._mulle_objc_method = type { i32, i8*, i8*, i32, i8* }
%struct._mulle_objc_loadclass = type { i32, i8*, i32, i32, i8*, i32, i32, i32, %struct._mulle_objc_ivarlist*, %struct._mulle_objc_methodlist*, %struct._mulle_objc_methodlist*, %struct._mulle_objc_propertylist*, %struct._mulle_objc_protocollist*, i32*, i8* }
%struct._mulle_objc_ivarlist = type opaque
%struct._mulle_objc_methodlist = type opaque
%struct._mulle_objc_propertylist = type { i32, [0 x %struct._mulle_objc_property] }
%struct._mulle_objc_property = type { i32, i32, i8*, i8*, i32, i32, i32 }
%struct._mulle_objc_protocollist = type { %struct._mulle_objc_protocollist*, i64, [0 x %struct._mulle_objc_protocol] }
%struct._mulle_objc_protocol = type { i32, i8* }
%struct._mulle_objc_loadclasslist = type { i32, %struct._mulle_objc_loadclass** }
%struct._mulle_objc_loadcategorylist = type { i32, %struct._mulle_objc_loadcategory** }
%struct._mulle_objc_loadcategory = type { i32, i8*, i32, i8*, i32, %struct._mulle_objc_methodlist*, %struct._mulle_objc_methodlist*, %struct._mulle_objc_propertylist*, %struct._mulle_objc_protocollist*, i32*, i8* }
%struct._mulle_objc_superlist = type { i32, [0 x %struct._mulle_objc_super] }
%struct._mulle_objc_super = type { i32, i8*, i32, i32 }
%struct._mulle_objc_loadcategorylist.0 = type { i32, %struct._mulle_objc_loadstaticstring** }
%struct._mulle_objc_loadstaticstring = type { i8* }
%struct._mulle_objc_loadhashnamelist = type { i32, %struct._mulle_objc_loadhashname** }
%struct._mulle_objc_loadhashname = type { i32, i8* }
;;; *********************** >
"%struct.Foo::p.test1::" = type { i8*, i8* }
;;; *********************** <
%union._u_args = type { [1 x [5 x i8*]] }
%struct.variadic_expr = type { i8*, i8* }
%struct._mulle_objc_loadinfo = type { i32, i32, i32, i32, i32, %struct._mulle_objc_loadclasslist*, %struct._mulle_objc_loadcategorylist*, %struct._mulle_objc_superlist*, %struct._mulle_objc_loadcategorylist.0*, %struct._mulle_objc_loadhashnamelist* }

@OBJC_METH_VAR_NAME_ = private unnamed_addr constant [8 x i8] c"test1::\00", section "__TEXT,__cstring,cstring_literals", align 1
@OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [16 x i8] c"v32@0:8^v16^v24\00", section "__TEXT,__cstring,cstring_literals", align 1
@OBJC_CLASS_NAME_ = private unnamed_addr constant [4 x i8] c"Foo\00", section "__TEXT,__cstring,cstring_literals", align 1
@OBJC_CLASS_METHODS_Foo = private global { i32, i8*, [1 x %struct._mulle_objc_method] } { i32 1, i8* null, [1 x %struct._mulle_objc_method] [%struct._mulle_objc_method { i32 -106426998, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([16 x i8], [16 x i8]* @OBJC_METH_VAR_TYPE_, i32 0, i32 0), i32 0, i8* bitcast (void (i8*, i32, %"struct.Foo::p.test1::"*)* @"+[Foo test1::]" to i8*) }] }, section "_DATA,__cls_meth,regular,no_dead_strip", align 4
@OBJC_CLASS_Foo = private global %struct._mulle_objc_loadclass { i32 -941529232, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), i32 298441816, i32 0, i8* null, i32 0, i32 -1, i32 0, %struct._mulle_objc_ivarlist* null, %struct._mulle_objc_methodlist* bitcast ({ i32, i8*, [1 x %struct._mulle_objc_method] }* @OBJC_CLASS_METHODS_Foo to %struct._mulle_objc_methodlist*), %struct._mulle_objc_methodlist* null, %struct._mulle_objc_propertylist* null, %struct._mulle_objc_protocollist* null, i32* null, i8* null }, section "__DATA,__class,regular,no_dead_strip", align 4
@OBJC_CLASS_LOADS = private global { i32, [1 x %struct._mulle_objc_loadclass*] } { i32 1, [1 x %struct._mulle_objc_loadclass*] [%struct._mulle_objc_loadclass* @OBJC_CLASS_Foo] }, section "__DATA,_objc_load_info", align 4
@OBJC_LOAD_INFO = private global { i32, i32, i32, i32, i32, %struct._mulle_objc_loadclasslist*, %struct._mulle_objc_loadcategorylist*, %struct._mulle_objc_superlist*, %struct._mulle_objc_loadcategorylist.0*, %struct._mulle_objc_loadhashnamelist* } { i32 12, i32 1048576, i32 0, i32 0, i32 512, %struct._mulle_objc_loadclasslist* bitcast ({ i32, [1 x %struct._mulle_objc_loadclass*] }* @OBJC_CLASS_LOADS to %struct._mulle_objc_loadclasslist*), %struct._mulle_objc_loadcategorylist* null, %struct._mulle_objc_superlist* null, %struct._mulle_objc_loadcategorylist.0* null, %struct._mulle_objc_loadhashnamelist* null }, section "__DATA,_objc_load_info", align 4
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__load_mulle_objc, i8* null }]
@llvm.compiler.used = appending global [7 x i8*] [i8* getelementptr inbounds ([8 x i8], [8 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([16 x i8], [16 x i8]* @OBJC_METH_VAR_TYPE_, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), i8* bitcast ({ i32, i8*, [1 x %struct._mulle_objc_method] }* @OBJC_CLASS_METHODS_Foo to i8*), i8* bitcast (%struct._mulle_objc_loadclass* @OBJC_CLASS_Foo to i8*), i8* bitcast ({ i32, [1 x %struct._mulle_objc_loadclass*] }* @OBJC_CLASS_LOADS to i8*), i8* bitcast ({ i32, i32, i32, i32, i32, %struct._mulle_objc_loadclasslist*, %struct._mulle_objc_loadcategorylist*, %struct._mulle_objc_superlist*, %struct._mulle_objc_loadcategorylist.0*, %struct._mulle_objc_loadhashnamelist* }* @OBJC_LOAD_INFO to i8*)], section "llvm.metadata"

; Function Attrs: nounwind ssp uwtable
define internal void @"+[Foo test1::]"(i8* nonnull %self, i32 zeroext %_cmd, %"struct.Foo::p.test1::"* %_param) #0 {
entry:
   %self.addr = alloca i8*, align 8
   %_cmd.addr = alloca i32, align 4
   %_param.addr = alloca %"struct.Foo::p.test1::"*, align 8
   %_args = alloca %union._u_args, align 8

   store i8* %self, i8** %self.addr, align 8, !tbaa !7
   store i32 %_cmd, i32* %_cmd.addr, align 4, !tbaa !10
   store %"struct.Foo::p.test1::"* %_param, %"struct.Foo::p.test1::"** %_param.addr, align 8, !tbaa !12

   %0 = load i8*, i8** %self.addr, align 8, !tbaa !7
   %1 = bitcast %union._u_args* %_args to i8*
   call void @llvm.lifetime.start.p0i8(i64 40, i8* %1) #3
   %v = bitcast %union._u_args* %_args to %struct.variadic_expr*
   %param_0 = getelementptr inbounds %struct.variadic_expr, %struct.variadic_expr* %v, i32 0, i32 0
   %2 = load %"struct.Foo::p.test1::"*, %"struct.Foo::p.test1::"** %_param.addr, align 8, !tbaa !12
   %a = getelementptr inbounds %"struct.Foo::p.test1::", %"struct.Foo::p.test1::"* %2, i32 0, i32 0
   %3 = load i8*, i8** %a, align 8, !tbaa !14
   store i8* %3, i8** %param_0, align 8, !tbaa !7
   %param_1 = getelementptr inbounds %struct.variadic_expr, %struct.variadic_expr* %v, i32 0, i32 1
   store i8* inttoptr (i64 1 to i8*), i8** %param_1, align 8, !tbaa !7

;;; *********************** >
   %4 = load %"struct.Foo::p.test1::"*, %"struct.Foo::p.test1::"** %_param.addr, align 8, !tbaa !16
;;; *********************** <

   %5 = bitcast %"struct.Foo::p.test1::"* %4 to i8*
   %6 = bitcast %struct.variadic_expr* %v to i8*
   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %5, i8* %6, i64 16, i32 8, i1 false), !tbaa.struct !17
   %7 = bitcast %union._u_args* %_args to i8*
   call void @llvm.lifetime.end.p0i8(i64 40, i8* %7) #3
   %8 = bitcast %"struct.Foo::p.test1::"* %4 to i8*
   %call = call i8* @mulle_objc_object_inline_constant_methodid_call(i8* %0, i32 zeroext -1800165210, i8* %8)
   ret void
}

; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1

; Function Attrs: argmemonly nounwind
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #1

; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1

; Function Attrs: nonlazybind
declare i8* @mulle_objc_object_inline_constant_methodid_call(i8*, i32, i8*) #2

define internal void @__load_mulle_objc() {
entry:
   call void (%struct._mulle_objc_loadinfo*, ...) @mulle_objc_loadinfo_unfailingenqueue(%struct._mulle_objc_loadinfo* bitcast ({ i32, i32, i32, i32, i32, %struct._mulle_objc_loadclasslist*, %struct._mulle_objc_loadcategorylist*, %struct._mulle_objc_superlist*, %struct._mulle_objc_loadcategorylist.0*, %struct._mulle_objc_loadhashnamelist* }* @OBJC_LOAD_INFO to %struct._mulle_objc_loadinfo*))
   ret void
}

declare void @mulle_objc_loadinfo_unfailingenqueue(%struct._mulle_objc_loadinfo*, ...)

attributes #0 = { nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { argmemonly nounwind }
attributes #2 = { nonlazybind }
attributes #3 = { nounwind }

!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
!llvm.ident = !{!6}

!0 = !{i32 1, !"Objective-C Version", i32 1}
!1 = !{i32 1, !"Objective-C Image Info Version", i32 0}
!2 = !{i32 1, !"Objective-C Image Info Section", !"__DATA, __image_info,regular"}
!3 = !{i32 4, !"Objective-C Garbage Collection", i32 0}
!4 = !{i32 1, !"wchar_size", i32 4}
!5 = !{i32 7, !"PIC Level", i32 2}
!6 = !{!"clang version 6.0.0 "}
!7 = !{!8, !8, i64 0}
!8 = !{!"omnipotent char", !9, i64 0}
!9 = !{!"Simple C/C++ TBAA"}
!10 = !{!11, !11, i64 0}
!11 = !{!"SEL", !8, i64 0}
!12 = !{!13, !13, i64 0}
;;; *********************** >
!13 = !{!"any pointer", !8, i64 0}
!14 = !{!15, !13, i64 0}
!15 = !{!"p.test1::", !13, i64 0, !13, i64 8}
!16 = !{!15, !15, i64 0}
;;; *********************** <
!17 = !{i64 0, i64 8, !12, i64 8, i64 8, !12}

Hi Nat,

I am upgrading my clang fork from 5.0 to 6.0 and I am hit by this error:

Access type node must be a valid scalar type

  %4 = load %"struct.Foo::p.test1::"*, %"struct.Foo::p.test1::"**
%_param.addr, align 8, !tbaa !16
!16 = !{!15, !15, i64 0}
!15 = !{!"p.test1::", !13, i64 0, !13, i64 8}

It looks like !16 is referencing !15, which is a struct. !13 is
!13 = !{!"any pointer", !8, i64 0}

But the %4 instruction just deals with pointers, so why is there a problem ?
The code itself is generated using clang CodeGen routines.
(I wouldn't even know how to manipulate !tbaa directly :slight_smile:

The TBAA scheme is described in more detail here
https://llvm.org/docs/LangRef.html#id918 but I suspect the correct
TBAA metadata is "!16 = !{!15, !13, i64 0}"

Right now the "!tbaa !16" with "!16 = !{!15, !15, i64 0}" tag is
roughly saying "this loads a scalar of type !15 from a pointer of type
!15" which isn't quite right -- it is loading a scalar of type !13 ==
(any pointer) from a pointer of type !15.

If I remove the !tbaa from %4, llc assembles it fine.
My compiler output didn't change.When I use the 5.0 compiler I get the same
(wrong ?) tbaa output. But it didn't used to matter.

It probably did matter, in that before LLVM would silently infer bogus
aliasing information :slight_smile:

For a quick fix, you can consider dropping TBAA metadata that does not
verify. See how TBAAVerifier is used in BitcodeReader.

-- Sanjoy

Hello Nat,

As Sanjoy said, the verifier correctly complains about the tag !16 as its access type is a structure, and not a scalar. If it used to work with v5.0, that means somehow the verifier didn't catch the issue, and then any transformations relying on alias analysis may result in incorrect code. Furthermore, if you get the same IR output with recent versions, then that suggests that the root problem is in the code invoking the clang's codegen functions. Specifically, at some point we seem to create a TBAAAccessInfo object with an aggregate type specified as both the base and access types. Here's how you can use the verifier to catch the moment:

// CodeGenModule.cpp
void CodeGenModule::DecorateInstructionWithTBAA(llvm::Instruction *Inst,
TBAAAccessInfo TBAAInfo) {
- if (llvm::MDNode *Tag = getTBAAAccessTagInfo(TBAAInfo))
+ if (llvm::MDNode *Tag = getTBAAAccessTagInfo(TBAAInfo)) {
Inst->setMetadata(llvm::LLVMContext::MD_tbaa, Tag);