#include "llvm/IR/Value.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include <stack>
#define DEBUG_TYPE "bpf-abstract-member-access"
bool doTransformation(Module &M);
- void traceAICall(CallInst *Call, uint32_t Kind);
- void traceBitCast(BitCastInst *BitCast, CallInst *Parent, uint32_t Kind);
- void traceGEP(GetElementPtrInst *GEP, CallInst *Parent, uint32_t Kind);
+ void traceAICall(CallInst *Call, uint32_t Kind, const MDNode *ParentMeta,
+ uint32_t ParentAI);
+ void traceBitCast(BitCastInst *BitCast, CallInst *Parent, uint32_t Kind,
+ const MDNode *ParentMeta, uint32_t ParentAI);
+ void traceGEP(GetElementPtrInst *GEP, CallInst *Parent, uint32_t Kind,
+ const MDNode *ParentMeta, uint32_t ParentAI);
void collectAICallChains(Module &M, Function &F);
- bool IsPreserveDIAccessIndexCall(const CallInst *Call, uint32_t &Kind);
+ bool IsPreserveDIAccessIndexCall(const CallInst *Call, uint32_t &Kind,
+ const MDNode *&TypeMeta, uint32_t &AccessIndex);
+ bool IsValidAIChain(const MDNode *ParentMeta, uint32_t ParentAI,
+ const MDNode *ChildMeta);
bool removePreserveAccessIndexIntrinsic(Module &M);
void replaceWithGEP(std::vector<CallInst *> &CallList,
uint32_t NumOfZerosIndex, uint32_t DIIndex);
Value *computeBaseAndAccessKey(CallInst *Call, std::string &AccessKey,
- uint32_t Kind, MDNode *&TypeMeta);
+ uint32_t Kind, MDNode *&BaseMeta);
bool getAccessIndex(const Value *IndexValue, uint64_t &AccessIndex);
bool transformGEPChain(Module &M, CallInst *Call, uint32_t Kind);
};
return doTransformation(M);
}
+static bool SkipDIDerivedTag(unsigned Tag) {
+ if (Tag != dwarf::DW_TAG_typedef && Tag != dwarf::DW_TAG_const_type &&
+ Tag != dwarf::DW_TAG_volatile_type &&
+ Tag != dwarf::DW_TAG_restrict_type &&
+ Tag != dwarf::DW_TAG_member)
+ return false;
+ return true;
+}
+
+static DIType * stripQualifiers(DIType *Ty) {
+ while (auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
+ if (!SkipDIDerivedTag(DTy->getTag()))
+ break;
+ Ty = DTy->getBaseType();
+ }
+ return Ty;
+}
+
+static const DIType * stripQualifiers(const DIType *Ty) {
+ while (auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
+ if (!SkipDIDerivedTag(DTy->getTag()))
+ break;
+ Ty = DTy->getBaseType();
+ }
+ return Ty;
+}
+
+static uint32_t calcArraySize(const DICompositeType *CTy, uint32_t StartDim) {
+ DINodeArray Elements = CTy->getElements();
+ uint32_t DimSize = 1;
+ for (uint32_t I = StartDim; I < Elements.size(); ++I) {
+ if (auto *Element = dyn_cast_or_null<DINode>(Elements[I]))
+ if (Element->getTag() == dwarf::DW_TAG_subrange_type) {
+ const DISubrange *SR = cast<DISubrange>(Element);
+ auto *CI = SR->getCount().dyn_cast<ConstantInt *>();
+ DimSize *= CI->getSExtValue();
+ }
+ }
+
+ return DimSize;
+}
+
/// Check whether a call is a preserve_*_access_index intrinsic call or not.
bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
- uint32_t &Kind) {
+ uint32_t &Kind,
+ const MDNode *&TypeMeta,
+ uint32_t &AccessIndex) {
if (!Call)
return false;
return false;
if (GV->getName().startswith("llvm.preserve.array.access.index")) {
Kind = BPFPreserveArrayAI;
+ TypeMeta = Call->getMetadata(LLVMContext::MD_preserve_access_index);
+ if (!TypeMeta)
+ report_fatal_error("Missing metadata for llvm.preserve.array.access.index intrinsic");
+ AccessIndex = cast<ConstantInt>(Call->getArgOperand(2))
+ ->getZExtValue();
return true;
}
if (GV->getName().startswith("llvm.preserve.union.access.index")) {
Kind = BPFPreserveUnionAI;
+ TypeMeta = Call->getMetadata(LLVMContext::MD_preserve_access_index);
+ if (!TypeMeta)
+ report_fatal_error("Missing metadata for llvm.preserve.union.access.index intrinsic");
+ AccessIndex = cast<ConstantInt>(Call->getArgOperand(1))
+ ->getZExtValue();
return true;
}
if (GV->getName().startswith("llvm.preserve.struct.access.index")) {
Kind = BPFPreserveStructAI;
+ TypeMeta = Call->getMetadata(LLVMContext::MD_preserve_access_index);
+ if (!TypeMeta)
+ report_fatal_error("Missing metadata for llvm.preserve.struct.access.index intrinsic");
+ AccessIndex = cast<ConstantInt>(Call->getArgOperand(2))
+ ->getZExtValue();
return true;
}
for (auto &I : BB) {
auto *Call = dyn_cast<CallInst>(&I);
uint32_t Kind;
- if (!IsPreserveDIAccessIndexCall(Call, Kind))
+ const MDNode *TypeMeta;
+ uint32_t AccessIndex;
+ if (!IsPreserveDIAccessIndexCall(Call, Kind, TypeMeta, AccessIndex))
continue;
Found = true;
return Found;
}
-void BPFAbstractMemberAccess::traceAICall(CallInst *Call, uint32_t Kind) {
+/// Check whether the access index chain is valid. We check
+/// here because there may be type casts between two
+/// access indexes. We want to ensure memory access still valid.
+bool BPFAbstractMemberAccess::IsValidAIChain(const MDNode *ParentType,
+ uint32_t ParentAI,
+ const MDNode *ChildType) {
+ const DIType *PType = stripQualifiers(cast<DIType>(ParentType));
+ const DIType *CType = stripQualifiers(cast<DIType>(ChildType));
+
+ // Child is a derived/pointer type, which is due to type casting.
+ // Pointer type cannot be in the middle of chain.
+ if (const auto *PtrTy = dyn_cast<DIDerivedType>(CType))
+ return false;
+
+ // Parent is a pointer type.
+ if (const auto *PtrTy = dyn_cast<DIDerivedType>(PType)) {
+ if (PtrTy->getTag() != dwarf::DW_TAG_pointer_type)
+ return false;
+ return stripQualifiers(PtrTy->getBaseType()) == CType;
+ }
+
+ // Otherwise, struct/union/array types
+ const auto *PTy = dyn_cast<DICompositeType>(PType);
+ const auto *CTy = dyn_cast<DICompositeType>(CType);
+ assert(PTy && CTy && "ParentType or ChildType is null or not composite");
+
+ uint32_t PTyTag = PTy->getTag();
+ assert(PTyTag == dwarf::DW_TAG_array_type ||
+ PTyTag == dwarf::DW_TAG_structure_type ||
+ PTyTag == dwarf::DW_TAG_union_type);
+
+ uint32_t CTyTag = CTy->getTag();
+ assert(CTyTag == dwarf::DW_TAG_array_type ||
+ CTyTag == dwarf::DW_TAG_structure_type ||
+ CTyTag == dwarf::DW_TAG_union_type);
+
+ // Multi dimensional arrays, base element should be the same
+ if (PTyTag == dwarf::DW_TAG_array_type && PTyTag == CTyTag)
+ return PTy->getBaseType() == CTy->getBaseType();
+
+ DIType *Ty;
+ if (PTyTag == dwarf::DW_TAG_array_type)
+ Ty = PTy->getBaseType();
+ else
+ Ty = dyn_cast<DIType>(PTy->getElements()[ParentAI]);
+
+ return dyn_cast<DICompositeType>(stripQualifiers(Ty)) == CTy;
+}
+
+void BPFAbstractMemberAccess::traceAICall(CallInst *Call, uint32_t Kind,
+ const MDNode *ParentMeta,
+ uint32_t ParentAI) {
for (User *U : Call->users()) {
Instruction *Inst = dyn_cast<Instruction>(U);
if (!Inst)
continue;
if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
- traceBitCast(BI, Call, Kind);
+ traceBitCast(BI, Call, Kind, ParentMeta, ParentAI);
} else if (auto *CI = dyn_cast<CallInst>(Inst)) {
uint32_t CIKind;
- if (IsPreserveDIAccessIndexCall(CI, CIKind)) {
+ const MDNode *ChildMeta;
+ uint32_t ChildAI;
+ if (IsPreserveDIAccessIndexCall(CI, CIKind, ChildMeta, ChildAI) &&
+ IsValidAIChain(ParentMeta, ParentAI, ChildMeta)) {
AIChain[CI] = std::make_pair(Call, Kind);
- traceAICall(CI, CIKind);
+ traceAICall(CI, CIKind, ChildMeta, ChildAI);
} else {
BaseAICalls[Call] = Kind;
}
} else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
if (GI->hasAllZeroIndices())
- traceGEP(GI, Call, Kind);
+ traceGEP(GI, Call, Kind, ParentMeta, ParentAI);
else
BaseAICalls[Call] = Kind;
}
}
void BPFAbstractMemberAccess::traceBitCast(BitCastInst *BitCast,
- CallInst *Parent, uint32_t Kind) {
+ CallInst *Parent, uint32_t Kind,
+ const MDNode *ParentMeta,
+ uint32_t ParentAI) {
for (User *U : BitCast->users()) {
Instruction *Inst = dyn_cast<Instruction>(U);
if (!Inst)
continue;
if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
- traceBitCast(BI, Parent, Kind);
+ traceBitCast(BI, Parent, Kind, ParentMeta, ParentAI);
} else if (auto *CI = dyn_cast<CallInst>(Inst)) {
uint32_t CIKind;
- if (IsPreserveDIAccessIndexCall(CI, CIKind)) {
+ const MDNode *ChildMeta;
+ uint32_t ChildAI;
+ if (IsPreserveDIAccessIndexCall(CI, CIKind, ChildMeta, ChildAI) &&
+ IsValidAIChain(ParentMeta, ParentAI, ChildMeta)) {
AIChain[CI] = std::make_pair(Parent, Kind);
- traceAICall(CI, CIKind);
+ traceAICall(CI, CIKind, ChildMeta, ChildAI);
} else {
BaseAICalls[Parent] = Kind;
}
} else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
if (GI->hasAllZeroIndices())
- traceGEP(GI, Parent, Kind);
+ traceGEP(GI, Parent, Kind, ParentMeta, ParentAI);
else
BaseAICalls[Parent] = Kind;
}
}
void BPFAbstractMemberAccess::traceGEP(GetElementPtrInst *GEP, CallInst *Parent,
- uint32_t Kind) {
+ uint32_t Kind, const MDNode *ParentMeta,
+ uint32_t ParentAI) {
for (User *U : GEP->users()) {
Instruction *Inst = dyn_cast<Instruction>(U);
if (!Inst)
continue;
if (auto *BI = dyn_cast<BitCastInst>(Inst)) {
- traceBitCast(BI, Parent, Kind);
+ traceBitCast(BI, Parent, Kind, ParentMeta, ParentAI);
} else if (auto *CI = dyn_cast<CallInst>(Inst)) {
uint32_t CIKind;
- if (IsPreserveDIAccessIndexCall(CI, CIKind)) {
+ const MDNode *ChildMeta;
+ uint32_t ChildAI;
+ if (IsPreserveDIAccessIndexCall(CI, CIKind, ChildMeta, ChildAI) &&
+ IsValidAIChain(ParentMeta, ParentAI, ChildMeta)) {
AIChain[CI] = std::make_pair(Parent, Kind);
- traceAICall(CI, CIKind);
+ traceAICall(CI, CIKind, ChildMeta, ChildAI);
} else {
BaseAICalls[Parent] = Kind;
}
} else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
if (GI->hasAllZeroIndices())
- traceGEP(GI, Parent, Kind);
+ traceGEP(GI, Parent, Kind, ParentMeta, ParentAI);
else
BaseAICalls[Parent] = Kind;
}
for (auto &BB : F)
for (auto &I : BB) {
uint32_t Kind;
+ const MDNode *TypeMeta;
+ uint32_t AccessIndex;
auto *Call = dyn_cast<CallInst>(&I);
- if (!IsPreserveDIAccessIndexCall(Call, Kind) ||
+ if (!IsPreserveDIAccessIndexCall(Call, Kind, TypeMeta, AccessIndex) ||
AIChain.find(Call) != AIChain.end())
continue;
- traceAICall(Call, Kind);
+ traceAICall(Call, Kind, TypeMeta, AccessIndex);
}
}
uint32_t Kind,
MDNode *&TypeMeta) {
Value *Base = nullptr;
- std::vector<uint64_t> AccessIndices;
- uint64_t TypeNameIndex = 0;
- std::string LastTypeName;
+ std::string TypeName;
+ std::stack<std::pair<CallInst *, uint32_t>> CallStack;
+ // Put the access chain into a stack with the top as the head of the chain.
while (Call) {
- // Base of original corresponding GEP
- Base = Call->getArgOperand(0);
+ CallStack.push(std::make_pair(Call, Kind));
+ Kind = AIChain[Call].second;
+ Call = AIChain[Call].first;
+ }
- // Type Name
- std::string TypeName;
- MDNode *MDN;
+ // The access offset from the base of the head of chain is also
+ // calculated here as all debuginfo types are available.
+
+ // Get type name and calculate the first index.
+ // We only want to get type name from structure or union.
+ // If user wants a relocation like
+ // int *p; ... __builtin_preserve_access_index(&p[4]) ...
+ // or
+ // int a[10][20]; ... __builtin_preserve_access_index(&a[2][3]) ...
+ // we will skip them.
+ uint32_t FirstIndex = 0;
+ uint32_t AccessOffset = 0;
+ while (CallStack.size()) {
+ auto StackElem = CallStack.top();
+ Call = StackElem.first;
+ Kind = StackElem.second;
+
+ if (!Base)
+ Base = Call->getArgOperand(0);
+
+ MDNode *MDN = Call->getMetadata(LLVMContext::MD_preserve_access_index);
+ DIType *Ty = stripQualifiers(cast<DIType>(MDN));
if (Kind == BPFPreserveUnionAI || Kind == BPFPreserveStructAI) {
- MDN = Call->getMetadata(LLVMContext::MD_preserve_access_index);
- if (!MDN)
- return nullptr;
+ // struct or union type
+ TypeName = Ty->getName();
+ TypeMeta = Ty;
+ AccessOffset += FirstIndex * Ty->getSizeInBits() >> 3;
+ break;
+ }
- DIType *Ty = dyn_cast<DIType>(MDN);
- if (!Ty)
+ // Array entries will always be consumed for accumulative initial index.
+ CallStack.pop();
+
+ // BPFPreserveArrayAI
+ uint64_t AccessIndex;
+ if (!getAccessIndex(Call->getArgOperand(2), AccessIndex))
+ return nullptr;
+
+ DIType *BaseTy = nullptr;
+ bool CheckElemType = false;
+ if (const auto *CTy = dyn_cast<DICompositeType>(Ty)) {
+ // array type
+ assert(CTy->getTag() == dwarf::DW_TAG_array_type);
+
+
+ FirstIndex += AccessIndex * calcArraySize(CTy, 1);
+ BaseTy = stripQualifiers(CTy->getBaseType());
+ CheckElemType = CTy->getElements().size() == 1;
+ } else {
+ // pointer type
+ auto *DTy = cast<DIDerivedType>(Ty);
+ assert(DTy->getTag() == dwarf::DW_TAG_pointer_type);
+
+ BaseTy = stripQualifiers(DTy->getBaseType());
+ CTy = dyn_cast<DICompositeType>(BaseTy);
+ if (!CTy) {
+ CheckElemType = true;
+ } else if (CTy->getTag() != dwarf::DW_TAG_array_type) {
+ FirstIndex += AccessIndex;
+ CheckElemType = true;
+ } else {
+ FirstIndex += AccessIndex * calcArraySize(CTy, 0);
+ }
+ }
+
+ if (CheckElemType) {
+ auto *CTy = dyn_cast<DICompositeType>(BaseTy);
+ if (!CTy)
return nullptr;
- TypeName = Ty->getName();
+ unsigned CTag = CTy->getTag();
+ if (CTag != dwarf::DW_TAG_structure_type && CTag != dwarf::DW_TAG_union_type)
+ return nullptr;
+ else
+ TypeName = CTy->getName();
+ TypeMeta = CTy;
+ AccessOffset += FirstIndex * CTy->getSizeInBits() >> 3;
+ break;
}
+ }
+ assert(TypeName.size());
+ AccessKey += std::to_string(FirstIndex);
+
+ // Traverse the rest of access chain to complete offset calculation
+ // and access key construction.
+ while (CallStack.size()) {
+ auto StackElem = CallStack.top();
+ Call = StackElem.first;
+ Kind = StackElem.second;
+ CallStack.pop();
// Access Index
uint64_t AccessIndex;
uint32_t ArgIndex = (Kind == BPFPreserveUnionAI) ? 1 : 2;
if (!getAccessIndex(Call->getArgOperand(ArgIndex), AccessIndex))
return nullptr;
-
- AccessIndices.push_back(AccessIndex);
- if (TypeName.size()) {
- TypeNameIndex = AccessIndices.size() - 1;
- LastTypeName = TypeName;
- TypeMeta = MDN;
+ AccessKey += ":" + std::to_string(AccessIndex);
+
+ MDNode *MDN = Call->getMetadata(LLVMContext::MD_preserve_access_index);
+ // At this stage, it cannot be pointer type.
+ auto *CTy = cast<DICompositeType>(stripQualifiers(cast<DIType>(MDN)));
+ uint32_t Tag = CTy->getTag();
+ if (Tag == dwarf::DW_TAG_structure_type) {
+ auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
+ AccessOffset += MemberTy->getOffsetInBits() >> 3;
+ } else if (Tag == dwarf::DW_TAG_array_type) {
+ auto *EltTy = stripQualifiers(CTy->getBaseType());
+ AccessOffset += AccessIndex * calcArraySize(CTy, 1) *
+ EltTy->getSizeInBits() >> 3;
}
-
- Kind = AIChain[Call].second;
- Call = AIChain[Call].first;
}
- // The intial type name is required.
- // FIXME: if the initial type access is an array index, e.g.,
- // &a[3].b.c, only one dimentional array is supported.
- if (!LastTypeName.size() || AccessIndices.size() > TypeNameIndex + 2)
- return nullptr;
-
- // Construct the type string AccessKey.
- for (unsigned I = 0; I < AccessIndices.size(); ++I)
- AccessKey = std::to_string(AccessIndices[I]) + ":" + AccessKey;
-
- if (TypeNameIndex == AccessIndices.size() - 1)
- AccessKey = "0:" + AccessKey;
-
// Access key is the type name + access string, uniquely identifying
// one kernel memory access.
- AccessKey = LastTypeName + ":" + AccessKey;
+ AccessKey = TypeName + ":" + std::to_string(AccessOffset) + "$" + AccessKey;
return Base;
}
bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call,
uint32_t Kind) {
std::string AccessKey;
- MDNode *TypeMeta = nullptr;
+ MDNode *TypeMeta;
Value *Base =
computeBaseAndAccessKey(Call, AccessKey, Kind, TypeMeta);
if (!Base)
// For any original GEP Call and Base %2 like
// %4 = bitcast %struct.net_device** %dev1 to i64*
// it is transformed to:
- // %6 = load __BTF_0:sk_buff:0:0:2:0:
+ // %6 = load sk_buff:50:$0:0:0:2:0
// %7 = bitcast %struct.sk_buff* %2 to i8*
// %8 = getelementptr i8, i8* %7, %6
// %9 = bitcast i8* %8 to i64*
GV = new GlobalVariable(M, Type::getInt64Ty(BB->getContext()), false,
GlobalVariable::ExternalLinkage, NULL, AccessKey);
GV->addAttribute(BPFCoreSharedInfo::AmaAttr);
- // Set the metadata (debuginfo types) for the global.
- if (TypeMeta)
- GV->setMetadata(LLVMContext::MD_preserve_access_index, TypeMeta);
+ GV->setMetadata(LLVMContext::MD_preserve_access_index, TypeMeta);
GEPGlobals[AccessKey] = GV;
} else {
GV = GEPGlobals[AccessKey];
#include "BTF.def"
};
-static const DIType * stripQualifiers(const DIType *Ty) {
- while (const auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
- unsigned Tag = DTy->getTag();
- if (Tag != dwarf::DW_TAG_typedef && Tag != dwarf::DW_TAG_const_type &&
- Tag != dwarf::DW_TAG_volatile_type && Tag != dwarf::DW_TAG_restrict_type)
- break;
- Ty = DTy->getBaseType();
- }
-
- return Ty;
-}
-
/// Emit a BTF common type.
void BTFTypeBase::emitType(MCStreamer &OS) {
OS.AddComment(std::string(BTFKindStr[Kind]) + "(id = " + std::to_string(Id) +
}
}
-BTFTypeArray::BTFTypeArray(const DIType *Ty, uint32_t ElemTypeId,
- uint32_t ElemSize, uint32_t NumElems)
- : ElemTyNoQual(Ty), ElemSize(ElemSize) {
+BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems) {
Kind = BTF::BTF_KIND_ARRAY;
BTFType.NameOff = 0;
BTFType.Info = Kind << 24;
// created during initial type traversal. Just
// retrieve that type id.
ArrayInfo.IndexType = BDebug.getArrayIndexTypeId();
-
- ElemTypeNoQual = ElemTyNoQual ? BDebug.getTypeId(ElemTyNoQual)
- : ArrayInfo.ElemType;
}
void BTFTypeArray::emitType(MCStreamer &OS) {
OS.EmitIntValue(ArrayInfo.Nelems, 4);
}
-void BTFTypeArray::getLocInfo(uint32_t Loc, uint32_t &LocOffset,
- uint32_t &ElementTypeId) {
- ElementTypeId = ElemTypeNoQual;
- LocOffset = Loc * ElemSize;
-}
-
/// Represent either a struct or a union.
BTFTypeStruct::BTFTypeStruct(const DICompositeType *STy, bool IsStruct,
bool HasBitField, uint32_t Vlen)
}
const auto *BaseTy = DDTy->getBaseType();
BTFMember.Type = BDebug.getTypeId(BaseTy);
- MemberTypeNoQual.push_back(BDebug.getTypeId(stripQualifiers(BaseTy)));
Members.push_back(BTFMember);
}
}
std::string BTFTypeStruct::getName() { return STy->getName(); }
-void BTFTypeStruct::getMemberInfo(uint32_t Loc, uint32_t &MemberOffset,
- uint32_t &MemberType) {
- MemberType = MemberTypeNoQual[Loc];
- MemberOffset =
- HasBitField ? Members[Loc].Offset & 0xffffff : Members[Loc].Offset;
-}
-
-uint32_t BTFTypeStruct::getStructSize() { return STy->getSizeInBits() >> 3; }
-
/// The Func kind represents both subprogram and pointee of function
/// pointers. If the FuncName is empty, it represents a pointee of function
/// pointer. Otherwise, it represents a subprogram. The func arg names
visitTypeEntry(ElemType, ElemTypeId, false, false);
// Strip qualifiers from element type to get accurate element size.
- ElemType = stripQualifiers(ElemType);
ElemSize = ElemType->getSizeInBits() >> 3;
if (!CTy->getSizeInBits()) {
- auto TypeEntry = llvm::make_unique<BTFTypeArray>(ElemType, ElemTypeId, 0, 0);
- ArrayTypes.push_back(TypeEntry.get());
+ auto TypeEntry = llvm::make_unique<BTFTypeArray>(ElemTypeId, 0);
ElemTypeId = addType(std::move(TypeEntry), CTy);
} else {
// Visit array dimensions.
const DISubrange *SR = cast<DISubrange>(Element);
auto *CI = SR->getCount().dyn_cast<ConstantInt *>();
int64_t Count = CI->getSExtValue();
- const DIType *ArrayElemTy = (I == 0) ? ElemType : nullptr;
auto TypeEntry =
- llvm::make_unique<BTFTypeArray>(ArrayElemTy, ElemTypeId,
- ElemSize, Count);
- ArrayTypes.push_back(TypeEntry.get());
+ llvm::make_unique<BTFTypeArray>(ElemTypeId, Count);
if (I == 0)
ElemTypeId = addType(std::move(TypeEntry), CTy);
else
return Id;
}
-// Find struct/array debuginfo types given a type id.
-void BTFDebug::setTypeFromId(uint32_t TypeId, BTFTypeStruct **PrevStructType,
- BTFTypeArray **PrevArrayType) {
- for (const auto &StructType : StructTypes) {
- if (StructType->getId() == TypeId) {
- *PrevStructType = StructType;
- return;
- }
- }
- for (const auto &ArrayType : ArrayTypes) {
- if (ArrayType->getId() == TypeId) {
- *PrevArrayType = ArrayType;
- return;
- }
- }
-}
-
/// Generate a struct member offset relocation.
void BTFDebug::generateOffsetReloc(const MachineInstr *MI,
const MCSymbol *ORSym, DIType *RootTy,
StringRef AccessPattern) {
- BTFTypeStruct *PrevStructType = nullptr;
- BTFTypeArray *PrevArrayType = nullptr;
unsigned RootId = populateStructType(RootTy);
- setTypeFromId(RootId, &PrevStructType, &PrevArrayType);
- unsigned RootTySize = PrevStructType->getStructSize();
- StringRef IndexPattern = AccessPattern.substr(AccessPattern.find_first_of(':') + 1);
+ size_t FirstDollar = AccessPattern.find_first_of('$');
+ size_t FirstColon = AccessPattern.find_first_of(':');
+ StringRef IndexPattern = AccessPattern.substr(FirstDollar + 1);
+ StringRef OffsetStr = AccessPattern.substr(FirstColon + 1,
+ FirstDollar - FirstColon);
BTFOffsetReloc OffsetReloc;
OffsetReloc.Label = ORSym;
- OffsetReloc.OffsetNameOff = addString(IndexPattern.drop_back());
+ OffsetReloc.OffsetNameOff = addString(IndexPattern);
OffsetReloc.TypeID = RootId;
-
- uint32_t Start = 0, End = 0, Offset = 0;
- bool FirstAccess = true;
- for (auto C : IndexPattern) {
- if (C != ':') {
- End++;
- } else {
- std::string SubStr = IndexPattern.substr(Start, End - Start);
- int Loc = std::stoi(SubStr);
-
- if (FirstAccess) {
- Offset = Loc * RootTySize;
- FirstAccess = false;
- } else if (PrevStructType) {
- uint32_t MemberOffset, MemberTypeId;
- PrevStructType->getMemberInfo(Loc, MemberOffset, MemberTypeId);
-
- Offset += MemberOffset >> 3;
- PrevStructType = nullptr;
- setTypeFromId(MemberTypeId, &PrevStructType, &PrevArrayType);
- } else if (PrevArrayType) {
- uint32_t LocOffset, ElementTypeId;
- PrevArrayType->getLocInfo(Loc, LocOffset, ElementTypeId);
-
- Offset += LocOffset;
- PrevArrayType = nullptr;
- setTypeFromId(ElementTypeId, &PrevStructType, &PrevArrayType);
- } else {
- llvm_unreachable("Internal Error: BTF offset relocation type traversal error");
- }
-
- Start = End + 1;
- End = Start;
- }
- }
- AccessOffsets[AccessPattern.str()] = Offset;
+ AccessOffsets[AccessPattern.str()] = std::stoi(OffsetStr);
OffsetRelocTable[SecNameOff].push_back(OffsetReloc);
}
/// Handle array type.
class BTFTypeArray : public BTFTypeBase {
- const DIType *ElemTyNoQual;
- uint32_t ElemSize;
struct BTF::BTFArray ArrayInfo;
- uint32_t ElemTypeNoQual;
public:
- BTFTypeArray(const DIType *Ty, uint32_t ElemTypeId,
- uint32_t ElemSize, uint32_t NumElems);
+ BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems);
uint32_t getSize() { return BTFTypeBase::getSize() + BTF::BTFArraySize; }
void completeType(BTFDebug &BDebug);
void emitType(MCStreamer &OS);
- void getLocInfo(uint32_t Loc, uint32_t &LocOffset, uint32_t &ElementTypeId);
};
/// Handle struct/union type.
const DICompositeType *STy;
bool HasBitField;
std::vector<struct BTF::BTFMember> Members;
- std::vector<uint32_t> MemberTypeNoQual;
public:
BTFTypeStruct(const DICompositeType *STy, bool IsStruct, bool HasBitField,
void completeType(BTFDebug &BDebug);
void emitType(MCStreamer &OS);
std::string getName();
- void getMemberInfo(uint32_t Loc, uint32_t &Offset, uint32_t &MemberType);
- uint32_t getStructSize();
};
/// Handle function pointer.
StringMap<std::vector<std::string>> FileContent;
std::map<std::string, std::unique_ptr<BTFKindDataSec>> DataSecEntries;
std::vector<BTFTypeStruct *> StructTypes;
- std::vector<BTFTypeArray *> ArrayTypes;
std::map<std::string, int64_t> AccessOffsets;
std::map<StringRef, std::pair<bool, std::vector<BTFTypeDerived *>>>
FixupDerivedTypes;
void generateOffsetReloc(const MachineInstr *MI, const MCSymbol *ORSym,
DIType *RootTy, StringRef AccessPattern);
- /// Set the to-be-traversed Struct/Array Type based on TypeId.
- void setTypeFromId(uint32_t TypeId, BTFTypeStruct **PrevStructType,
- BTFTypeArray **PrevArrayType);
-
/// Populating unprocessed struct type.
unsigned populateStructType(const DIType *Ty);
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; struct v1 {int a; int b;};
+; typedef struct v1 __v1;
+; typedef __v1 arr[4];
+; struct v3 { char c; int d[100]; };
+; #define _(x) (__builtin_preserve_access_index(x))
+; #define cast_to_arr(x) ((arr *)(x))
+; int get_value(const int *arg);
+; int test(struct v3 *arg) {
+; return get_value(_(&cast_to_arr(&arg->d[0])[0][2].b));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.v3 = type { i8, [100 x i32] }
+%struct.v1 = type { i32, i32 }
+
+; Function Attrs: nounwind
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !22 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !32, metadata !DIExpression()), !dbg !33
+ %0 = tail call [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3* %arg, i32 1, i32 1), !dbg !34, !llvm.preserve.access.index !26
+ %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]* %0, i32 1, i32 0), !dbg !34, !llvm.preserve.access.index !15
+ %2 = bitcast i32* %1 to [4 x %struct.v1]*, !dbg !34
+ %3 = tail call [4 x %struct.v1]* @llvm.preserve.array.access.index.p0a4s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]* %2, i32 0, i32 0), !dbg !34, !llvm.preserve.access.index !4
+ %4 = tail call %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]* %3, i32 1, i32 2), !dbg !34, !llvm.preserve.access.index !5
+ %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* %4, i32 1, i32 1), !dbg !34, !llvm.preserve.access.index !8
+ %call = tail call i32 @get_value(i32* %5) #4, !dbg !35
+ ret i32 %call, !dbg !36
+}
+
+; CHECK: r2 = 4
+; CHECK: r1 += r2
+; CHECK: r2 = 20
+; CHECK: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 1 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
+; CHECK: .long 100 # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]])
+
+; CHECK: .ascii "v3" # string offset=1
+; CHECK: .ascii ".text" # string offset=46
+; CHECK: .ascii "0:1:0" # string offset=52
+; CHECK: .ascii "2:1" # string offset=107
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 46 # Offset reloc section string offset=46
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID1]]
+; CHECK-NEXT: .long 52
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID2]]
+; CHECK-NEXT: .long 107
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare [4 x %struct.v1]* @llvm.preserve.array.access.index.p0a4s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable willreturn }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!18, !19, !20}
+!llvm.ident = !{!21}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!2 = !{}
+!3 = !{!4, !15, !5}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "arr", file: !1, line: 3, baseType: !6)
+!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 256, elements: !13)
+!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !8)
+!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !9)
+!9 = !{!10, !12}
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !1, line: 1, baseType: !11, size: 32)
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !1, line: 1, baseType: !11, size: 32, offset: 32)
+!13 = !{!14}
+!14 = !DISubrange(count: 4)
+!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 3200, elements: !16)
+!16 = !{!17}
+!17 = !DISubrange(count: 100)
+!18 = !{i32 2, !"Dwarf Version", i32 4}
+!19 = !{i32 2, !"Debug Info Version", i32 3}
+!20 = !{i32 1, !"wchar_size", i32 4}
+!21 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!22 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !23, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !31)
+!23 = !DISubroutineType(types: !24)
+!24 = !{!11, !25}
+!25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !26, size: 64)
+!26 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 4, size: 3232, elements: !27)
+!27 = !{!28, !30}
+!28 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !26, file: !1, line: 4, baseType: !29, size: 8)
+!29 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!30 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !26, file: !1, line: 4, baseType: !15, size: 3200, offset: 32)
+!31 = !{!32}
+!32 = !DILocalVariable(name: "arg", arg: 1, scope: !22, file: !1, line: 8, type: !25)
+!33 = !DILocation(line: 0, scope: !22)
+!34 = !DILocation(line: 9, column: 20, scope: !22)
+!35 = !DILocation(line: 9, column: 10, scope: !22)
+!36 = !DILocation(line: 9, column: 3, scope: !22)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; struct v1 {int a; int b;};
+; typedef struct v1 __v1;
+; typedef __v1 arr[4][4];
+; struct v3 { char c; int d[100]; };
+; #define _(x) (__builtin_preserve_access_index(x))
+; #define cast_to_arr(x) ((arr *)(x))
+; int get_value(const int *arg);
+; int test(struct v3 *arg) {
+; return get_value(_(&cast_to_arr(&arg->d[0])[0][2][3].b));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.v3 = type { i8, [100 x i32] }
+%struct.v1 = type { i32, i32 }
+
+; Function Attrs: nounwind
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !24 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !34, metadata !DIExpression()), !dbg !35
+ %0 = tail call [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3* %arg, i32 1, i32 1), !dbg !36, !llvm.preserve.access.index !28
+ %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]* %0, i32 1, i32 0), !dbg !36, !llvm.preserve.access.index !15
+ %2 = bitcast i32* %1 to [4 x [4 x %struct.v1]]*, !dbg !36
+ %3 = tail call [4 x [4 x %struct.v1]]* @llvm.preserve.array.access.index.p0a4a4s_struct.v1s.p0a4a4s_struct.v1s([4 x [4 x %struct.v1]]* %2, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !4
+ %4 = tail call [4 x %struct.v1]* @llvm.preserve.array.access.index.p0a4s_struct.v1s.p0a4a4s_struct.v1s([4 x [4 x %struct.v1]]* %3, i32 1, i32 2), !dbg !36, !llvm.preserve.access.index !5
+ %5 = tail call %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]* %4, i32 1, i32 3), !dbg !36, !llvm.preserve.access.index !18
+ %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* %5, i32 1, i32 1), !dbg !36, !llvm.preserve.access.index !8
+ %call = tail call i32 @get_value(i32* %6) #4, !dbg !37
+ ret i32 %call, !dbg !38
+}
+
+; CHECK: r2 = 4
+; CHECK: r1 += r2
+; CHECK: r2 = 92
+; CHECK: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 1 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
+; CHECK: .long 100 # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]])
+
+; CHECK: .ascii "v3" # string offset=1
+; CHECK: .ascii ".text" # string offset=46
+; CHECK: .ascii "0:1:0" # string offset=52
+; CHECK: .ascii "v1" # string offset=100
+; CHECK: .ascii "11:1" # string offset=107
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 46 # Offset reloc section string offset=46
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID1]]
+; CHECK-NEXT: .long 52
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID2]]
+; CHECK-NEXT: .long 107
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare [4 x [4 x %struct.v1]]* @llvm.preserve.array.access.index.p0a4a4s_struct.v1s.p0a4a4s_struct.v1s([4 x [4 x %struct.v1]]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare [4 x %struct.v1]* @llvm.preserve.array.access.index.p0a4s_struct.v1s.p0a4a4s_struct.v1s([4 x [4 x %struct.v1]]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable willreturn }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!20, !21, !22}
+!llvm.ident = !{!23}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!2 = !{}
+!3 = !{!4, !15, !5, !18}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "arr", file: !1, line: 3, baseType: !6)
+!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 1024, elements: !13)
+!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !8)
+!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !9)
+!9 = !{!10, !12}
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !1, line: 1, baseType: !11, size: 32)
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !1, line: 1, baseType: !11, size: 32, offset: 32)
+!13 = !{!14, !14}
+!14 = !DISubrange(count: 4)
+!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 3200, elements: !16)
+!16 = !{!17}
+!17 = !DISubrange(count: 100)
+!18 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 256, elements: !19)
+!19 = !{!14}
+!20 = !{i32 2, !"Dwarf Version", i32 4}
+!21 = !{i32 2, !"Debug Info Version", i32 3}
+!22 = !{i32 1, !"wchar_size", i32 4}
+!23 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!24 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !25, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !33)
+!25 = !DISubroutineType(types: !26)
+!26 = !{!11, !27}
+!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !28, size: 64)
+!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 4, size: 3232, elements: !29)
+!29 = !{!30, !32}
+!30 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !28, file: !1, line: 4, baseType: !31, size: 8)
+!31 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!32 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !28, file: !1, line: 4, baseType: !15, size: 3200, offset: 32)
+!33 = !{!34}
+!34 = !DILocalVariable(name: "arg", arg: 1, scope: !24, file: !1, line: 8, type: !27)
+!35 = !DILocation(line: 0, scope: !24)
+!36 = !DILocation(line: 9, column: 20, scope: !24)
+!37 = !DILocation(line: 9, column: 10, scope: !24)
+!38 = !DILocation(line: 9, column: 3, scope: !24)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; struct v1 { int a; int b; };
+; struct v2 { int c; int d; };
+; struct v3 { char c; struct v2 d; };
+; #define _(x) (__builtin_preserve_access_index(x))
+; #define cast_to_v1(x) ((struct v1 *)(x))
+; int get_value(const int *arg);
+; int test(struct v3 *arg) {
+; return get_value(_(&cast_to_v1(&arg->d)->b));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.v3 = type { i8, %struct.v2 }
+%struct.v2 = type { i32, i32 }
+%struct.v1 = type { i32, i32 }
+
+; Function Attrs: nounwind
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !14 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !28, metadata !DIExpression()), !dbg !29
+ %0 = tail call %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3* %arg, i32 1, i32 1), !dbg !30, !llvm.preserve.access.index !18
+ %1 = bitcast %struct.v2* %0 to %struct.v1*, !dbg !30
+ %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* %1, i32 1, i32 1), !dbg !30, !llvm.preserve.access.index !5
+ %call = tail call i32 @get_value(i32* %2) #4, !dbg !31
+ ret i32 %call, !dbg !32
+}
+
+; CHECK: r2 = 4
+; CHECK: r1 += r2
+; CHECK: r2 = 4
+; CHECK: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 1 # BTF_KIND_STRUCT(id = [[V3_TID:[0-9]+]])
+; CHECK: .long 81 # BTF_KIND_STRUCT(id = [[V1_TID:[0-9]+]])
+
+; CHECK: .ascii "v3" # string offset=1
+; CHECK-NEXT: .byte 0
+; CHECK: .ascii ".text" # string offset=[[SEC_STR:[0-9]+]]
+; CHECK-NEXT: .byte 0
+; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]]
+; CHECK-NEXT: .byte 0
+; CHECK: .ascii "v1" # string offset=81
+; CHECK-NEXT: .byte 0
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long [[SEC_STR]] # Offset reloc section string offset=[[SEC_STR]]
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[V3_TID]]
+; CHECK-NEXT: .long [[ACCESS_STR]]
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[V1_TID]]
+; CHECK-NEXT: .long [[ACCESS_STR]]
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable willreturn }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!10, !11, !12}
+!llvm.ident = !{!13}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !6)
+!6 = !{!7, !9}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !5, file: !1, line: 1, baseType: !8, size: 32)
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !5, file: !1, line: 1, baseType: !8, size: 32, offset: 32)
+!10 = !{i32 2, !"Dwarf Version", i32 4}
+!11 = !{i32 2, !"Debug Info Version", i32 3}
+!12 = !{i32 1, !"wchar_size", i32 4}
+!13 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!14 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 7, type: !15, scopeLine: 7, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27)
+!15 = !DISubroutineType(types: !16)
+!16 = !{!8, !17}
+!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64)
+!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 3, size: 96, elements: !19)
+!19 = !{!20, !22}
+!20 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !18, file: !1, line: 3, baseType: !21, size: 8)
+!21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !18, file: !1, line: 3, baseType: !23, size: 64, offset: 32)
+!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v2", file: !1, line: 2, size: 64, elements: !24)
+!24 = !{!25, !26}
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !23, file: !1, line: 2, baseType: !8, size: 32)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !23, file: !1, line: 2, baseType: !8, size: 32, offset: 32)
+!27 = !{!28}
+!28 = !DILocalVariable(name: "arg", arg: 1, scope: !14, file: !1, line: 7, type: !17)
+!29 = !DILocation(line: 0, scope: !14)
+!30 = !DILocation(line: 8, column: 20, scope: !14)
+!31 = !DILocation(line: 8, column: 10, scope: !14)
+!32 = !DILocation(line: 8, column: 3, scope: !14)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; struct v1 { int a; int b; };
+; typedef struct v1 __v1;
+; struct v2 { int c; int d; };
+; typedef struct v2 __v2;
+; struct v3 { char c; volatile const __v2 d; };
+; typedef struct v3 __v3;
+; #define _(x) (__builtin_preserve_access_index(x))
+; #define cast_to_v1(x) ((__v1 *)(x))
+; int get_value(const int *arg);
+; int test(__v3 *arg) {
+; return get_value(_(&cast_to_v1(&arg->d)->b));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.v3 = type { i8, %struct.v2 }
+%struct.v2 = type { i32, i32 }
+%struct.v1 = type { i32, i32 }
+
+; Function Attrs: nounwind
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !15 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !33, metadata !DIExpression()), !dbg !34
+ %0 = tail call %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3* %arg, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !20
+ %1 = bitcast %struct.v2* %0 to %struct.v1*, !dbg !35
+ %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* %1, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !6
+ %call = tail call i32 @get_value(i32* %2) #4, !dbg !36
+ ret i32 %call, !dbg !37
+}
+
+; CHECK: r2 = 4
+; CHECK: r1 += r2
+; CHECK: r2 = 4
+; CHECK: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 6 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
+; CHECK: .long 91 # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]])
+
+; CHECK: .ascii "v3" # string offset=6
+; CHECK: .ascii ".text" # string offset=39
+; CHECK: .ascii "0:1" # string offset=45
+; CHECK: .ascii "v1" # string offset=91
+
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 39 # Offset reloc section string offset=39
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID1]]
+; CHECK-NEXT: .long 45
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID2]]
+; CHECK-NEXT: .long 45
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable willreturn }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!11, !12, !13}
+!llvm.ident = !{!14}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6)
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !7)
+!7 = !{!8, !10}
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32)
+!11 = !{i32 2, !"Dwarf Version", i32 4}
+!12 = !{i32 2, !"Debug Info Version", i32 3}
+!13 = !{i32 1, !"wchar_size", i32 4}
+!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!15 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 10, type: !16, scopeLine: 10, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !32)
+!16 = !DISubroutineType(types: !17)
+!17 = !{!9, !18}
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64)
+!19 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 6, baseType: !20)
+!20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 5, size: 96, elements: !21)
+!21 = !{!22, !24}
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !20, file: !1, line: 5, baseType: !23, size: 8)
+!23 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !20, file: !1, line: 5, baseType: !25, size: 64, offset: 32)
+!25 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !26)
+!26 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !27)
+!27 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v2", file: !1, line: 4, baseType: !28)
+!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v2", file: !1, line: 3, size: 64, elements: !29)
+!29 = !{!30, !31}
+!30 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !28, file: !1, line: 3, baseType: !9, size: 32)
+!31 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !28, file: !1, line: 3, baseType: !9, size: 32, offset: 32)
+!32 = !{!33}
+!33 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 10, type: !18)
+!34 = !DILocation(line: 0, scope: !15)
+!35 = !DILocation(line: 11, column: 20, scope: !15)
+!36 = !DILocation(line: 11, column: 10, scope: !15)
+!37 = !DILocation(line: 11, column: 3, scope: !15)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; struct v1 { int a; int b; };
+; typedef struct v1 __v1;
+; typedef int __int;
+; struct v3 { char c; __int d[40]; };
+; typedef struct v3 __v3;
+; #define _(x) (__builtin_preserve_access_index(x))
+; #define cast_to_v1(x) ((__v1 *)(x))
+; int get_value(const int *arg);
+; int test(__v3 *arg) {
+; return get_value(_(&cast_to_v1(&arg->d[4])->b));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.v3 = type { i8, [40 x i32] }
+%struct.v1 = type { i32, i32 }
+
+; Function Attrs: nounwind
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !19 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !30, metadata !DIExpression()), !dbg !31
+ %0 = tail call [40 x i32]* @llvm.preserve.struct.access.index.p0a40i32.p0s_struct.v3s(%struct.v3* %arg, i32 1, i32 1), !dbg !32, !llvm.preserve.access.index !24
+ %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]* %0, i32 1, i32 4), !dbg !32, !llvm.preserve.access.index !11
+ %2 = bitcast i32* %1 to %struct.v1*, !dbg !32
+ %3 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* %2, i32 1, i32 1), !dbg !32, !llvm.preserve.access.index !6
+ %call = tail call i32 @get_value(i32* %3) #4, !dbg !33
+ ret i32 %call, !dbg !34
+}
+
+; CHECK: r2 = 20
+; CHECK: r1 += r2
+; CHECK: r2 = 4
+; CHECK: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 6 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
+; CHECK: .long 111 # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]])
+
+; CHECK: .ascii "v3" # string offset=6
+; CHECK: .ascii ".text" # string offset=57
+; CHECK: .ascii "0:1:4" # string offset=63
+; CHECK: .ascii "v1" # string offset=111
+; CHECK: .ascii "0:1" # string offset=118
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 57 # Offset reloc section string offset=57
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID1]]
+; CHECK-NEXT: .long 63
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID2]]
+; CHECK-NEXT: .long 118
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare [40 x i32]* @llvm.preserve.struct.access.index.p0a40i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable willreturn }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!15, !16, !17}
+!llvm.ident = !{!18}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!2 = !{}
+!3 = !{!4, !11}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6)
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !7)
+!7 = !{!8, !10}
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32)
+!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 1280, elements: !13)
+!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 3, baseType: !9)
+!13 = !{!14}
+!14 = !DISubrange(count: 40)
+!15 = !{i32 2, !"Dwarf Version", i32 4}
+!16 = !{i32 2, !"Debug Info Version", i32 3}
+!17 = !{i32 1, !"wchar_size", i32 4}
+!18 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!19 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !20, scopeLine: 9, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !29)
+!20 = !DISubroutineType(types: !21)
+!21 = !{!9, !22}
+!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
+!23 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 5, baseType: !24)
+!24 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 4, size: 1312, elements: !25)
+!25 = !{!26, !28}
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !24, file: !1, line: 4, baseType: !27, size: 8)
+!27 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!28 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !24, file: !1, line: 4, baseType: !11, size: 1280, offset: 32)
+!29 = !{!30}
+!30 = !DILocalVariable(name: "arg", arg: 1, scope: !19, file: !1, line: 9, type: !22)
+!31 = !DILocation(line: 0, scope: !19)
+!32 = !DILocation(line: 10, column: 20, scope: !19)
+!33 = !DILocation(line: 10, column: 10, scope: !19)
+!34 = !DILocation(line: 10, column: 3, scope: !19)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; union v1 { int a; int b; };
+; typedef union v1 __v1;
+; union v2 { int c; int d; };
+; typedef union v2 __v2;
+; union v3 { char c; volatile const __v2 d; };
+; typedef union v3 __v3;
+; #define _(x) (__builtin_preserve_access_index(x))
+; #define cast_to_v1(x) ((__v1 *)(x))
+; int get_value(const int *arg);
+; int test(__v3 *arg) {
+; return get_value(_(&cast_to_v1(&arg->d)->b));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.v3 = type { %union.v2 }
+%union.v2 = type { i32 }
+%union.v1 = type { i32 }
+
+; Function Attrs: nounwind
+define dso_local i32 @test(%union.v3* %arg) local_unnamed_addr #0 !dbg !15 {
+entry:
+ call void @llvm.dbg.value(metadata %union.v3* %arg, metadata !33, metadata !DIExpression()), !dbg !34
+ %0 = tail call %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3* %arg, i32 1), !dbg !35, !llvm.preserve.access.index !20
+ %1 = bitcast %union.v3* %0 to %union.v1*, !dbg !35
+ %2 = tail call %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1* %1, i32 1), !dbg !35, !llvm.preserve.access.index !6
+ %b = getelementptr inbounds %union.v1, %union.v1* %2, i64 0, i32 0, !dbg !35
+ %call = tail call i32 @get_value(i32* %b) #4, !dbg !36
+ ret i32 %call, !dbg !37
+}
+
+; CHECK: r2 = 0
+; CHECK: r1 += r2
+; CHECK: r2 = 0
+; CHECK: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 6 # BTF_KIND_UNION(id = [[TID1:[0-9]+]])
+; CHECK: .long 91 # BTF_KIND_UNION(id = [[TID2:[0-9]+]])
+
+; CHECK: .ascii "v3" # string offset=6
+; CHECK: .ascii ".text" # string offset=39
+; CHECK: .ascii "0:1" # string offset=45
+; CHECK: .ascii "v1" # string offset=91
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 39 # Offset reloc section string offset=39
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID1]]
+; CHECK-NEXT: .long 45
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID2]]
+; CHECK-NEXT: .long 45
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3*, i32) #2
+
+; Function Attrs: nounwind readnone
+declare %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1*, i32) #2
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable willreturn }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!11, !12, !13}
+!llvm.ident = !{!14}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6)
+!6 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v1", file: !1, line: 1, size: 32, elements: !7)
+!7 = !{!8, !10}
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
+!11 = !{i32 2, !"Dwarf Version", i32 4}
+!12 = !{i32 2, !"Debug Info Version", i32 3}
+!13 = !{i32 1, !"wchar_size", i32 4}
+!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!15 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 10, type: !16, scopeLine: 10, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !32)
+!16 = !DISubroutineType(types: !17)
+!17 = !{!9, !18}
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64)
+!19 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 6, baseType: !20)
+!20 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v3", file: !1, line: 5, size: 32, elements: !21)
+!21 = !{!22, !24}
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !20, file: !1, line: 5, baseType: !23, size: 8)
+!23 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!24 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !20, file: !1, line: 5, baseType: !25, size: 32)
+!25 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !26)
+!26 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !27)
+!27 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v2", file: !1, line: 4, baseType: !28)
+!28 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v2", file: !1, line: 3, size: 32, elements: !29)
+!29 = !{!30, !31}
+!30 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !28, file: !1, line: 3, baseType: !9, size: 32)
+!31 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !28, file: !1, line: 3, baseType: !9, size: 32)
+!32 = !{!33}
+!33 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 10, type: !18)
+!34 = !DILocation(line: 0, scope: !15)
+!35 = !DILocation(line: 11, column: 20, scope: !15)
+!36 = !DILocation(line: 11, column: 10, scope: !15)
+!37 = !DILocation(line: 11, column: 3, scope: !15)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; union v1 { int a; int b; };
+; typedef union v1 __v1;
+; typedef int __int;
+; union v3 { char c; __int d[40]; };
+; typedef union v3 __v3;
+; #define _(x) (__builtin_preserve_access_index(x))
+; #define cast_to_v1(x) ((__v1 *)(x))
+; int get_value(const int *arg);
+; int test(__v3 *arg) {
+; return get_value(_(&cast_to_v1(&arg->d[4])->b));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%union.v3 = type { [40 x i32] }
+%union.v1 = type { i32 }
+
+; Function Attrs: nounwind
+define dso_local i32 @test(%union.v3* %arg) local_unnamed_addr #0 !dbg !19 {
+entry:
+ call void @llvm.dbg.value(metadata %union.v3* %arg, metadata !30, metadata !DIExpression()), !dbg !31
+ %0 = tail call %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3* %arg, i32 1), !dbg !32, !llvm.preserve.access.index !24
+ %d = getelementptr inbounds %union.v3, %union.v3* %0, i64 0, i32 0, !dbg !32
+ %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]* %d, i32 1, i32 4), !dbg !32, !llvm.preserve.access.index !11
+ %2 = bitcast i32* %1 to %union.v1*, !dbg !32
+ %3 = tail call %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1* %2, i32 1), !dbg !32, !llvm.preserve.access.index !6
+ %b = getelementptr inbounds %union.v1, %union.v1* %3, i64 0, i32 0, !dbg !32
+ %call = tail call i32 @get_value(i32* %b) #4, !dbg !33
+ ret i32 %call, !dbg !34
+}
+
+; CHECK: r2 = 16
+; CHECK: r1 += r2
+; CHECK: r2 = 0
+; CHECK: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 6 # BTF_KIND_UNION(id = [[TID1:[0-9]+]])
+; CHECK: .long 111 # BTF_KIND_UNION(id = [[TID2:[0-9]+]])
+
+; CHECK: .ascii "v3" # string offset=6
+; CHECK: .ascii ".text" # string offset=57
+; CHECK: .ascii "0:1:4" # string offset=63
+; CHECK: .ascii "v1" # string offset=111
+; CHECK: .ascii "0:1" # string offset=118
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 57 # Offset reloc section string offset=57
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID1]]
+; CHECK-NEXT: .long 63
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID2]]
+; CHECK-NEXT: .long 118
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3*, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1*, i32) #2
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable willreturn }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!15, !16, !17}
+!llvm.ident = !{!18}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!2 = !{}
+!3 = !{!4, !11}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6)
+!6 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v1", file: !1, line: 1, size: 32, elements: !7)
+!7 = !{!8, !10}
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
+!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 1280, elements: !13)
+!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 3, baseType: !9)
+!13 = !{!14}
+!14 = !DISubrange(count: 40)
+!15 = !{i32 2, !"Dwarf Version", i32 4}
+!16 = !{i32 2, !"Debug Info Version", i32 3}
+!17 = !{i32 1, !"wchar_size", i32 4}
+!18 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!19 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !20, scopeLine: 9, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !29)
+!20 = !DISubroutineType(types: !21)
+!21 = !{!9, !22}
+!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
+!23 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 5, baseType: !24)
+!24 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v3", file: !1, line: 4, size: 1280, elements: !25)
+!25 = !{!26, !28}
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !24, file: !1, line: 4, baseType: !27, size: 8)
+!27 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!28 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !24, file: !1, line: 4, baseType: !11, size: 1280)
+!29 = !{!30}
+!30 = !DILocalVariable(name: "arg", arg: 1, scope: !19, file: !1, line: 9, type: !22)
+!31 = !DILocation(line: 0, scope: !19)
+!32 = !DILocation(line: 10, column: 20, scope: !19)
+!33 = !DILocation(line: 10, column: 10, scope: !19)
+!34 = !DILocation(line: 10, column: 3, scope: !19)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef struct v3 { int a; int b; } __v3;
+; #define _(x) (__builtin_preserve_access_index(x))
+; int get_value(const int *arg);
+; __v3 g __attribute__((section("stats")));
+; int test() {
+; return get_value(_(&g.b));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.v3 = type { i32, i32 }
+
+@g = dso_local global %struct.v3 zeroinitializer, section "stats", align 4, !dbg !0
+
+; Function Attrs: nounwind
+define dso_local i32 @test() local_unnamed_addr #0 !dbg !16 {
+entry:
+ %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3* nonnull @g, i32 1, i32 1), !dbg !19, !llvm.preserve.access.index !7
+ %call = tail call i32 @get_value(i32* %0) #3, !dbg !20
+ ret i32 %call, !dbg !21
+}
+
+; CHECK: r2 = 4
+; CHECK: r1 = g ll
+; CHECK: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 16 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
+
+; CHECK: .ascii ".text" # string offset=10
+; CHECK: .ascii "v3" # string offset=16
+; CHECK: .ascii "0:1" # string offset=23
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 10 # Offset reloc section string offset=10
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID1]]
+; CHECK-NEXT: .long 23
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13, !14}
+!llvm.ident = !{!15}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None)
+!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!4 = !{}
+!5 = !{!0}
+!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !3, line: 1, baseType: !7)
+!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !3, line: 1, size: 64, elements: !8)
+!8 = !{!9, !11}
+!9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !7, file: !3, line: 1, baseType: !10, size: 32)
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !7, file: !3, line: 1, baseType: !10, size: 32, offset: 32)
+!12 = !{i32 2, !"Dwarf Version", i32 4}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!14 = !{i32 1, !"wchar_size", i32 4}
+!15 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!16 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 5, type: !17, scopeLine: 5, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4)
+!17 = !DISubroutineType(types: !18)
+!18 = !{!10}
+!19 = !DILocation(line: 6, column: 20, scope: !16)
+!20 = !DILocation(line: 6, column: 10, scope: !16)
+!21 = !DILocation(line: 6, column: 3, scope: !16)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef struct v3 { int a; int b; } __v3;
+; #define _(x) (__builtin_preserve_access_index(x))
+; int get_value(const int *arg);
+; __v3 g[4][5] __attribute__((section("stats")));
+; int test() {
+; return get_value(_(&g[1][2].b));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.v3 = type { i32, i32 }
+
+@g = dso_local global [4 x [5 x %struct.v3]] zeroinitializer, section "stats", align 4, !dbg !0
+
+; Function Attrs: nounwind
+define dso_local i32 @test() local_unnamed_addr #0 !dbg !23 {
+entry:
+ %0 = tail call [5 x %struct.v3]* @llvm.preserve.array.access.index.p0a5s_struct.v3s.p0a4a5s_struct.v3s([4 x [5 x %struct.v3]]* nonnull @g, i32 1, i32 1), !dbg !26, !llvm.preserve.access.index !6
+ %1 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0a5s_struct.v3s([5 x %struct.v3]* %0, i32 1, i32 2), !dbg !26, !llvm.preserve.access.index !16
+ %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3* %1, i32 1, i32 1), !dbg !26, !llvm.preserve.access.index !8
+ %call = tail call i32 @get_value(i32* %2) #3, !dbg !27
+ ret i32 %call, !dbg !28
+}
+
+; CHECK: r2 = 60
+; CHECK: r1 = g ll
+; CHECK: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 16 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
+
+; CHECK: .ascii ".text" # string offset=10
+; CHECK: .ascii "v3" # string offset=16
+; CHECK: .ascii "7:1" # string offset=23
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 10 # Offset reloc section string offset=10
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID1]]
+; CHECK-NEXT: .long 23
+
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare [5 x %struct.v3]* @llvm.preserve.array.access.index.p0a5s_struct.v3s.p0a4a5s_struct.v3s([4 x [5 x %struct.v3]]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0a5s_struct.v3s([5 x %struct.v3]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!19, !20, !21}
+!llvm.ident = !{!22}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !18, nameTableKind: None)
+!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!4 = !{}
+!5 = !{!6, !16}
+!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 1280, elements: !13)
+!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !3, line: 1, baseType: !8)
+!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !3, line: 1, size: 64, elements: !9)
+!9 = !{!10, !12}
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !3, line: 1, baseType: !11, size: 32)
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !3, line: 1, baseType: !11, size: 32, offset: 32)
+!13 = !{!14, !15}
+!14 = !DISubrange(count: 4)
+!15 = !DISubrange(count: 5)
+!16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 320, elements: !17)
+!17 = !{!15}
+!18 = !{!0}
+!19 = !{i32 2, !"Dwarf Version", i32 4}
+!20 = !{i32 2, !"Debug Info Version", i32 3}
+!21 = !{i32 1, !"wchar_size", i32 4}
+!22 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!23 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 5, type: !24, scopeLine: 5, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4)
+!24 = !DISubroutineType(types: !25)
+!25 = !{!11}
+!26 = !DILocation(line: 6, column: 20, scope: !23)
+!27 = !DILocation(line: 6, column: 10, scope: !23)
+!28 = !DILocation(line: 6, column: 3, scope: !23)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef struct v3 { int a; int b; } __v3;
+; #define _(x) (__builtin_preserve_access_index(x))
+; int get_value(const int *arg);
+; __v3 *g __attribute__((section("stats")));
+; int test() {
+; return get_value(_(&g->b));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.v3 = type { i32, i32 }
+
+@g = dso_local local_unnamed_addr global %struct.v3* null, section "stats", align 8, !dbg !0
+
+; Function Attrs: nounwind
+define dso_local i32 @test() local_unnamed_addr #0 !dbg !17 {
+entry:
+ %0 = load %struct.v3*, %struct.v3** @g, align 8, !dbg !20, !tbaa !21
+ %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3* %0, i32 1, i32 1), !dbg !20, !llvm.preserve.access.index !8
+ %call = tail call i32 @get_value(i32* %1) #3, !dbg !25
+ ret i32 %call, !dbg !26
+}
+
+; CHECK: r2 = 4
+; CHECK: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 16 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
+
+; CHECK: .ascii ".text" # string offset=10
+; CHECK: .ascii "v3" # string offset=16
+; CHECK: .ascii "0:1" # string offset=23
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 10 # Offset reloc section string offset=10
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID1]]
+; CHECK-NEXT: .long 23
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!13, !14, !15}
+!llvm.ident = !{!16}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None)
+!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!4 = !{}
+!5 = !{!0}
+!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !3, line: 1, baseType: !8)
+!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !3, line: 1, size: 64, elements: !9)
+!9 = !{!10, !12}
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !3, line: 1, baseType: !11, size: 32)
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !3, line: 1, baseType: !11, size: 32, offset: 32)
+!13 = !{i32 2, !"Dwarf Version", i32 4}
+!14 = !{i32 2, !"Debug Info Version", i32 3}
+!15 = !{i32 1, !"wchar_size", i32 4}
+!16 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!17 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 5, type: !18, scopeLine: 5, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4)
+!18 = !DISubroutineType(types: !19)
+!19 = !{!11}
+!20 = !DILocation(line: 6, column: 20, scope: !17)
+!21 = !{!22, !22, i64 0}
+!22 = !{!"any pointer", !23, i64 0}
+!23 = !{!"omnipotent char", !24, i64 0}
+!24 = !{!"Simple C/C++ TBAA"}
+!25 = !DILocation(line: 6, column: 10, scope: !17)
+!26 = !DILocation(line: 6, column: 3, scope: !17)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; #define _(x) (__builtin_preserve_access_index(x))
+; int get_value(const int *arg);
+; int test(int *arg) {
+; return get_value(_(&arg[4]));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+; Function Attrs: nounwind
+define dso_local i32 @test(i32* %arg) local_unnamed_addr #0 !dbg !10 {
+entry:
+ call void @llvm.dbg.value(metadata i32* %arg, metadata !14, metadata !DIExpression()), !dbg !15
+ %0 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0i32(i32* %arg, i32 0, i32 4), !dbg !16, !llvm.preserve.access.index !4
+ %call = tail call i32 @get_value(i32* %0) #4, !dbg !17
+ ret i32 %call, !dbg !18
+}
+
+; CHECK: r1 += 16
+; CHECK: call get_value
+; CHECK: .section .BTF.ext,"",@progbits
+; CHECK-NOT: .long 12 # OffsetReloc
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.array.access.index.p0i32.p0i32(i32*, i32, i32) #2
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable willreturn }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!6 = !{i32 2, !"Dwarf Version", i32 4}
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{i32 1, !"wchar_size", i32 4}
+!9 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!10 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !11, scopeLine: 3, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !13)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!5, !4}
+!13 = !{!14}
+!14 = !DILocalVariable(name: "arg", arg: 1, scope: !10, file: !1, line: 3, type: !4)
+!15 = !DILocation(line: 0, scope: !10)
+!16 = !DILocation(line: 4, column: 20, scope: !10)
+!17 = !DILocation(line: 4, column: 10, scope: !10)
+!18 = !DILocation(line: 4, column: 3, scope: !10)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef int __int;
+; typedef struct v3 { int a; __int b[4][4]; } __v3;
+; #define _(x) (__builtin_preserve_access_index(x))
+; int get_value(const int *arg);
+; int test(__v3 *arg) {
+; return get_value(_(&arg[1].b[2][3]));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.v3 = type { i32, [4 x [4 x i32]] }
+
+; Function Attrs: nounwind
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !21 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !25, metadata !DIExpression()), !dbg !26
+ %0 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3* %arg, i32 0, i32 1), !dbg !27, !llvm.preserve.access.index !4
+ %1 = tail call [4 x [4 x i32]]* @llvm.preserve.struct.access.index.p0a4a4i32.p0s_struct.v3s(%struct.v3* %0, i32 1, i32 1), !dbg !27, !llvm.preserve.access.index !6
+ %2 = tail call [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]* %1, i32 1, i32 2), !dbg !27, !llvm.preserve.access.index !11
+ %3 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]* %2, i32 1, i32 3), !dbg !27, !llvm.preserve.access.index !15
+ %call = tail call i32 @get_value(i32* %3) #4, !dbg !28
+ ret i32 %call, !dbg !29
+}
+
+; CHECK: r2 = 116
+; CHECK: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 6 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
+
+; CHECK: .ascii "v3" # string offset=6
+; CHECK: .ascii ".text" # string offset=52
+; CHECK: .ascii "1:1:2:3" # string offset=58
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 52 # Offset reloc section string offset=52
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID1]]
+; CHECK-NEXT: .long 58
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare [4 x [4 x i32]]* @llvm.preserve.struct.access.index.p0a4a4i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable willreturn }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!17, !18, !19}
+!llvm.ident = !{!20}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!2 = !{}
+!3 = !{!4, !11, !15}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 2, baseType: !6)
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 2, size: 544, elements: !7)
+!7 = !{!8, !10}
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 2, baseType: !9, size: 32)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 2, baseType: !11, size: 512, offset: 32)
+!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 512, elements: !13)
+!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 1, baseType: !9)
+!13 = !{!14, !14}
+!14 = !DISubrange(count: 4)
+!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 128, elements: !16)
+!16 = !{!14}
+!17 = !{i32 2, !"Dwarf Version", i32 4}
+!18 = !{i32 2, !"Debug Info Version", i32 3}
+!19 = !{i32 1, !"wchar_size", i32 4}
+!20 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!21 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !22, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !24)
+!22 = !DISubroutineType(types: !23)
+!23 = !{!9, !4}
+!24 = !{!25}
+!25 = !DILocalVariable(name: "arg", arg: 1, scope: !21, file: !1, line: 5, type: !4)
+!26 = !DILocation(line: 0, scope: !21)
+!27 = !DILocation(line: 6, column: 20, scope: !21)
+!28 = !DILocation(line: 6, column: 10, scope: !21)
+!29 = !DILocation(line: 6, column: 3, scope: !21)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef int __int;
+; typedef struct v3 { int a; __int b[4][4][4]; } __v3;
+; #define _(x) (__builtin_preserve_access_index(x))
+; int get_value(const int *arg);
+; int test(__v3 *arg) {
+; return get_value(_(&arg[1].b[2][3][2]));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.v3 = type { i32, [4 x [4 x [4 x i32]]] }
+
+; Function Attrs: nounwind
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !23 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !27, metadata !DIExpression()), !dbg !28
+ %0 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3* %arg, i32 0, i32 1), !dbg !29, !llvm.preserve.access.index !4
+ %1 = tail call [4 x [4 x [4 x i32]]]* @llvm.preserve.struct.access.index.p0a4a4a4i32.p0s_struct.v3s(%struct.v3* %0, i32 1, i32 1), !dbg !29, !llvm.preserve.access.index !6
+ %2 = tail call [4 x [4 x i32]]* @llvm.preserve.array.access.index.p0a4a4i32.p0a4a4a4i32([4 x [4 x [4 x i32]]]* %1, i32 1, i32 2), !dbg !29, !llvm.preserve.access.index !11
+ %3 = tail call [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]* %2, i32 1, i32 3), !dbg !29, !llvm.preserve.access.index !15
+ %4 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]* %3, i32 1, i32 2), !dbg !29, !llvm.preserve.access.index !17
+ %call = tail call i32 @get_value(i32* %4) #4, !dbg !30
+ ret i32 %call, !dbg !31
+}
+
+; CHECK: r2 = 448
+; CHECK: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 6 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
+
+; CHECK: .ascii "v3" # string offset=6
+; CHECK: .ascii ".text" # string offset=52
+; CHECK: .ascii "1:1:2:3:2" # string offset=58
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 52 # Offset reloc section string offset=52
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID1]]
+; CHECK-NEXT: .long 58
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare [4 x [4 x [4 x i32]]]* @llvm.preserve.struct.access.index.p0a4a4a4i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare [4 x [4 x i32]]* @llvm.preserve.array.access.index.p0a4a4i32.p0a4a4a4i32([4 x [4 x [4 x i32]]]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]*, i32, i32) #2
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable willreturn }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!19, !20, !21}
+!llvm.ident = !{!22}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!2 = !{}
+!3 = !{!4, !11, !15, !17}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 2, baseType: !6)
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 2, size: 2080, elements: !7)
+!7 = !{!8, !10}
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 2, baseType: !9, size: 32)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 2, baseType: !11, size: 2048, offset: 32)
+!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 2048, elements: !13)
+!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 1, baseType: !9)
+!13 = !{!14, !14, !14}
+!14 = !DISubrange(count: 4)
+!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 512, elements: !16)
+!16 = !{!14, !14}
+!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 128, elements: !18)
+!18 = !{!14}
+!19 = !{i32 2, !"Dwarf Version", i32 4}
+!20 = !{i32 2, !"Debug Info Version", i32 3}
+!21 = !{i32 1, !"wchar_size", i32 4}
+!22 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!23 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !24, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26)
+!24 = !DISubroutineType(types: !25)
+!25 = !{!9, !4}
+!26 = !{!27}
+!27 = !DILocalVariable(name: "arg", arg: 1, scope: !23, file: !1, line: 5, type: !4)
+!28 = !DILocation(line: 0, scope: !23)
+!29 = !DILocation(line: 6, column: 20, scope: !23)
+!30 = !DILocation(line: 6, column: 10, scope: !23)
+!31 = !DILocation(line: 6, column: 3, scope: !23)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef struct v3 { int a; int b; } __v3;
+; #define _(x) (__builtin_preserve_access_index(x))
+; int get_value(const int *arg);
+; int test(__v3 *arg) {
+; return get_value(_(&arg[1]));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.v3 = type { i32, i32 }
+
+; Function Attrs: nounwind
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !15 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !19, metadata !DIExpression()), !dbg !20
+ %0 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3* %arg, i32 0, i32 1), !dbg !21, !llvm.preserve.access.index !4
+ %1 = getelementptr inbounds %struct.v3, %struct.v3* %0, i64 0, i32 0, !dbg !21
+ %call = tail call i32 @get_value(i32* %1) #4, !dbg !22
+ ret i32 %call, !dbg !23
+}
+
+; CHECK: r2 = 8
+; CHECK: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 6 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
+
+; CHECK: .ascii "v3" # string offset=6
+; CHECK: .ascii ".text" # string offset=26
+; CHECK: .byte 49 # string offset=32
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 26 # Offset reloc section string offset=26
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID1]]
+; CHECK-NEXT: .long 32
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable willreturn }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!11, !12, !13}
+!llvm.ident = !{!14}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 1, baseType: !6)
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 1, size: 64, elements: !7)
+!7 = !{!8, !10}
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32)
+!11 = !{i32 2, !"Dwarf Version", i32 4}
+!12 = !{i32 2, !"Debug Info Version", i32 3}
+!13 = !{i32 1, !"wchar_size", i32 4}
+!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!15 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !16, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !18)
+!16 = !DISubroutineType(types: !17)
+!17 = !{!9, !4}
+!18 = !{!19}
+!19 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 4, type: !4)
+!20 = !DILocation(line: 0, scope: !15)
+!21 = !DILocation(line: 5, column: 20, scope: !15)
+!22 = !DILocation(line: 5, column: 10, scope: !15)
+!23 = !DILocation(line: 5, column: 3, scope: !15)
--- /dev/null
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; Source code:
+; typedef struct v3 { int a; int b; } __v3;
+; #define _(x) (__builtin_preserve_access_index(x))
+; int get_value(const int *arg);
+; int test(__v3 *arg) {
+; return get_value(_(&arg[1].b));
+; }
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+
+%struct.v3 = type { i32, i32 }
+
+; Function Attrs: nounwind
+define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !15 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !19, metadata !DIExpression()), !dbg !20
+ %0 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3* %arg, i32 0, i32 1), !dbg !21, !llvm.preserve.access.index !4
+ %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3* %0, i32 1, i32 1), !dbg !21, !llvm.preserve.access.index !6
+ %call = tail call i32 @get_value(i32* %1) #4, !dbg !22
+ ret i32 %call, !dbg !23
+}
+
+; CHECK: r2 = 12
+; CHECK-NEXT: r1 += r2
+; CHECK: call get_value
+
+; CHECK: .long 6 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]])
+; CHECK: .ascii "v3" # string offset=6
+; CHECK: .ascii ".text" # string offset=26
+; CHECK: .ascii "1:1" # string offset=32
+
+; CHECK: .long 12 # OffsetReloc
+; CHECK-NEXT: .long 26 # Offset reloc section string offset=26
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .long [[TID1]]
+; CHECK-NEXT: .long 32
+
+declare dso_local i32 @get_value(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+; Function Attrs: nounwind readnone
+declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { nounwind readnone speculatable willreturn }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!11, !12, !13}
+!llvm.ident = !{!14}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 1, baseType: !6)
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 1, size: 64, elements: !7)
+!7 = !{!8, !10}
+!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32)
+!11 = !{i32 2, !"Dwarf Version", i32 4}
+!12 = !{i32 2, !"Debug Info Version", i32 3}
+!13 = !{i32 1, !"wchar_size", i32 4}
+!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"}
+!15 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !16, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !18)
+!16 = !DISubroutineType(types: !17)
+!17 = !{!9, !4}
+!18 = !{!19}
+!19 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 4, type: !4)
+!20 = !DILocation(line: 0, scope: !15)
+!21 = !DILocation(line: 5, column: 20, scope: !15)
+!22 = !DILocation(line: 5, column: 10, scope: !15)
+!23 = !DILocation(line: 5, column: 3, scope: !15)
%3 = bitcast i32* %2 to i8*, !dbg !34
call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !34
%4 = tail call [10 x %struct.anon]* @llvm.preserve.struct.access.index.p0a10s_struct.anons.p0s_struct.sk_buffs(%struct.sk_buff* %0, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !19
- %5 = tail call %struct.anon* @llvm.preserve.array.access.index.p0s_struct.anons.p0a10s_struct.anons([10 x %struct.anon]* %4, i32 1, i32 5), !dbg !35
+ %5 = tail call %struct.anon* @llvm.preserve.array.access.index.p0s_struct.anons.p0a10s_struct.anons([10 x %struct.anon]* %4, i32 1, i32 5), !dbg !35, !llvm.preserve.access.index !23
%6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.anons(%struct.anon* %5, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !24
%7 = bitcast i32* %6 to i8*, !dbg !35
%8 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %7) #4, !dbg !36
%3 = bitcast i32* %2 to i8*, !dbg !34
call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !34
%4 = tail call [10 x %struct.net_device]* @llvm.preserve.struct.access.index.p0a10s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff* %0, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !19
- %5 = tail call %struct.net_device* @llvm.preserve.array.access.index.p0s_struct.net_devices.p0a10s_struct.net_devices([10 x %struct.net_device]* %4, i32 1, i32 5), !dbg !35
+ %5 = tail call %struct.net_device* @llvm.preserve.array.access.index.p0s_struct.net_devices.p0a10s_struct.net_devices([10 x %struct.net_device]* %4, i32 1, i32 5), !dbg !35, !llvm.preserve.access.index !23
%6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.net_devices(%struct.net_device* %5, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !24
%7 = bitcast i32* %6 to i8*, !dbg !35
%8 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %7) #4, !dbg !36
entry:
call void @llvm.dbg.value(metadata %struct.__s* %arg, metadata !24, metadata !DIExpression()), !dbg !25
%0 = tail call [7 x i32]* @llvm.preserve.struct.access.index.p0a7i32.p0s_struct.__ss(%struct.__s* %arg, i32 0, i32 0), !dbg !26, !llvm.preserve.access.index !13
- %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a7i32([7 x i32]* %0, i32 1, i32 1), !dbg !26
+ %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a7i32([7 x i32]* %0, i32 1, i32 1), !dbg !26, !llvm.preserve.access.index !19
%2 = bitcast i32* %1 to i8*, !dbg !26
%call = tail call i32 @get_value(i8* %2) #4, !dbg !27
ret i32 %call, !dbg !28
define dso_local i32 @test([7 x %union.u]* %arg) local_unnamed_addr #0 !dbg !7 {
entry:
call void @llvm.dbg.value(metadata [7 x %union.u]* %arg, metadata !28, metadata !DIExpression()), !dbg !29
- %0 = tail call [7 x %union.u]* @llvm.preserve.array.access.index.p0a7s_union.us.p0a7s_union.us([7 x %union.u]* %arg, i32 0, i32 1), !dbg !30
+ %0 = tail call [7 x %union.u]* @llvm.preserve.array.access.index.p0a7s_union.us.p0a7s_union.us([7 x %union.u]* %arg, i32 0, i32 1), !dbg !30, !llvm.preserve.access.index !14
%arraydecay = getelementptr inbounds [7 x %union.u], [7 x %union.u]* %0, i64 0, i64 0, !dbg !30
%1 = tail call %union.u* @llvm.preserve.union.access.index.p0s_union.us.p0s_union.us(%union.u* %arraydecay, i32 1), !dbg !30, !llvm.preserve.access.index !16
%d = getelementptr inbounds %union.u, %union.u* %1, i64 0, i32 0, !dbg !30