yonghong-song updated this revision to Diff 222910.
yonghong-song edited the summary of this revision.
yonghong-song added a comment.
use a bpf target builtin __builtin_get_field_info().
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D67980/new/
https://reviews.llvm.org/D67980
Files:
clang/include/clang/Basic/BuiltinsBPF.def
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/TargetBuiltins.h
clang/include/clang/Sema/Sema.h
clang/include/clang/module.modulemap
clang/lib/Basic/Targets/BPF.cpp
clang/lib/Basic/Targets/BPF.h
clang/lib/CodeGen/CGBuiltin.cpp
clang/lib/CodeGen/CGExpr.cpp
clang/lib/CodeGen/CodeGenFunction.h
clang/lib/Sema/SemaChecking.cpp
llvm/include/llvm/IR/IntrinsicsBPF.td
llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
llvm/lib/Target/BPF/BPFCORE.h
llvm/lib/Target/BPF/BTF.h
llvm/lib/Target/BPF/BTFDebug.cpp
llvm/lib/Target/BPF/BTFDebug.h
Index: llvm/lib/Target/BPF/BTFDebug.h
===================================================================
--- llvm/lib/Target/BPF/BTFDebug.h
+++ llvm/lib/Target/BPF/BTFDebug.h
@@ -228,6 +228,7 @@
const MCSymbol *Label; ///< MCSymbol identifying insn for the reloc
uint32_t TypeID; ///< Type ID
uint32_t OffsetNameOff; ///< The string to traverse types
+ uint32_t RelocKind; ///< What to patch the instruction
};
/// Represent one extern relocation.
@@ -254,7 +255,7 @@
StringMap<std::vector<std::string>> FileContent;
std::map<std::string, std::unique_ptr<BTFKindDataSec>> DataSecEntries;
std::vector<BTFTypeStruct *> StructTypes;
- std::map<std::string, int64_t> AccessOffsets;
+ std::map<std::string, uint64_t> PatchImms;
std::map<StringRef, std::pair<bool, std::vector<BTFTypeDerived *>>>
FixupDerivedTypes;
Index: llvm/lib/Target/BPF/BTFDebug.cpp
===================================================================
--- llvm/lib/Target/BPF/BTFDebug.cpp
+++ llvm/lib/Target/BPF/BTFDebug.cpp
@@ -844,6 +844,7 @@
Asm->EmitLabelReference(OffsetRelocInfo.Label, 4);
OS.EmitIntValue(OffsetRelocInfo.TypeID, 4);
OS.EmitIntValue(OffsetRelocInfo.OffsetNameOff, 4);
+ OS.EmitIntValue(OffsetRelocInfo.RelocKind, 4);
}
}
}
@@ -965,15 +966,19 @@
unsigned RootId = populateStructType(RootTy);
size_t FirstDollar = AccessPattern.find_first_of('$');
size_t FirstColon = AccessPattern.find_first_of(':');
+ size_t SecondColon = AccessPattern.find_first_of(':', FirstColon + 1);
StringRef IndexPattern = AccessPattern.substr(FirstDollar + 1);
- StringRef OffsetStr = AccessPattern.substr(FirstColon + 1,
- FirstDollar - FirstColon);
+ StringRef RelocKindStr = AccessPattern.substr(FirstColon + 1,
+ SecondColon - FirstColon);
+ StringRef PatchImmStr = AccessPattern.substr(SecondColon + 1,
+ FirstDollar - SecondColon);
BTFOffsetReloc OffsetReloc;
OffsetReloc.Label = ORSym;
OffsetReloc.OffsetNameOff = addString(IndexPattern);
OffsetReloc.TypeID = RootId;
- AccessOffsets[AccessPattern.str()] = std::stoi(OffsetStr);
+ OffsetReloc.RelocKind = std::stoull(RelocKindStr);
+ PatchImms[AccessPattern.str()] = std::stoull(PatchImmStr);
OffsetRelocTable[SecNameOff].push_back(OffsetReloc);
}
@@ -1154,8 +1159,8 @@
const GlobalValue *GVal = MO.getGlobal();
auto *GVar = dyn_cast<GlobalVariable>(GVal);
if (GVar && GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) {
- // Emit "mov ri, <imm>" for abstract member accesses.
- int64_t Imm = AccessOffsets[GVar->getName().str()];
+ // Emit "mov ri, <imm>" for patched immediate.
+ int64_t Imm = PatchImms[GVar->getName().str()];
OutMI.setOpcode(BPF::MOV_ri);
OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
OutMI.addOperand(MCOperand::createImm(Imm));
Index: llvm/lib/Target/BPF/BTF.h
===================================================================
--- llvm/lib/Target/BPF/BTF.h
+++ llvm/lib/Target/BPF/BTF.h
@@ -76,7 +76,7 @@
SecExternRelocSize = 8,
BPFFuncInfoSize = 8,
BPFLineInfoSize = 16,
- BPFOffsetRelocSize = 12,
+ BPFOffsetRelocSize = 16,
BPFExternRelocSize = 8,
};
@@ -251,6 +251,7 @@
uint32_t InsnOffset; ///< Byte offset in this section
uint32_t TypeID; ///< TypeID for the relocation
uint32_t OffsetNameOff; ///< The string to traverse types
+ uint32_t RelocKind; ///< What to patch the instruction
};
/// Specifying offset relocation's in one section.
Index: llvm/lib/Target/BPF/BPFCORE.h
===================================================================
--- llvm/lib/Target/BPF/BPFCORE.h
+++ llvm/lib/Target/BPF/BPFCORE.h
@@ -13,6 +13,14 @@
class BPFCoreSharedInfo {
public:
+ enum OffsetRelocKind : uint32_t {
+ BTF_FIELD_ACCESS_OFFSET = 0,
+ BTF_FIELD_EXISTENCE,
+ BTF_FIELD_SIGNNESS,
+ BTF_FIELD_BF_BYTE_OFFSET_64BIT_ALIGN,
+ BTF_FIELD_BF_LSHIFT_64BIT_ALIGN,
+ BTF_FIELD_BF_RSHIFT_64BIT_ALIGN,
+ };
/// The attribute attached to globals representing a member offset
static const std::string AmaAttr;
/// The section name to identify a patchable external global
Index: llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
===================================================================
--- llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
+++ llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
@@ -50,6 +50,28 @@
// addr = preserve_struct_access_index(base, gep_index, di_index)
// !llvm.preserve.access.index <struct_ditype>
//
+// Bitfield member access needs special attention. User cannot take the
+// address of a bitfield acceess. To facilitate kernel verifier
+// for easy bitfield code optimization, a new clang intrinsic is introduced:
+// uint32_t __builtin_get_field_info(member_access, info_kind)
+// In IR, a chain with two (or more) intrinsic calls will be generated:
+// ...
+// addr = preserve_struct_access_index(base, 1, 1) !struct s
+// uint32_t result = bpf_get_field_info(addr, info_kind)
+//
+// Suppose the info_kind is BTF_FIELD_SIGNNESS,
+// The above two IR intrinsics will be replaced with
+// a relocatable insn:
+// signness = /* signness of member_access */
+// and signness can be changed by bpf loader based on the
+// types on the host.
+//
+// User can also test whether a field exists or not with
+// uint32_t result = bpf_get_field_info(member_access, BTF_FIELD_EXISTENCE)
+// The field will be always available (result = 1) during initial
+// compilation, but bpf loader can patch with the correct value
+// on the target host where the member_access may or may not be available.
+//
//===----------------------------------------------------------------------===//
#include "BPF.h"
@@ -95,14 +117,16 @@
BPFPreserveArrayAI = 1,
BPFPreserveUnionAI = 2,
BPFPreserveStructAI = 3,
+ BPFGetFieldInfoAI = 4,
};
std::map<std::string, GlobalVariable *> GEPGlobals;
// A map to link preserve_*_access_index instrinsic calls.
std::map<CallInst *, std::pair<CallInst *, uint32_t>> AIChain;
- // A map to hold all the base preserve_*_access_index instrinsic calls.
- // The base call is not an input of any other preserve_*_access_index
- // intrinsics.
+ // A map to hold all the base preserve_*_access_index
+ // and get_field_info instrinsic calls.
+ // The base call is an input of something else other than
+ // these intrinsics.
std::map<CallInst *, uint32_t> BaseAICalls;
bool doTransformation(Module &M);
@@ -122,10 +146,12 @@
bool removePreserveAccessIndexIntrinsic(Module &M);
void replaceWithGEP(std::vector<CallInst *> &CallList,
uint32_t NumOfZerosIndex, uint32_t DIIndex);
+ uint32_t GetFieldInfo(uint32_t InfoKind, DICompositeType *CTy,
+ uint32_t AccessIndex);
Value *computeBaseAndAccessKey(CallInst *Call, std::string &AccessKey,
uint32_t Kind, MDNode *&BaseMeta);
- bool getAccessIndex(const Value *IndexValue, uint64_t &AccessIndex);
+ uint64_t getConstant(const Value *IndexValue);
bool transformGEPChain(Module &M, CallInst *Call, uint32_t Kind);
};
} // End anonymous namespace
@@ -206,8 +232,7 @@
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();
+ AccessIndex = getConstant(Call->getArgOperand(2));
return true;
}
if (GV->getName().startswith("llvm.preserve.union.access.index")) {
@@ -215,8 +240,7 @@
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();
+ AccessIndex = getConstant(Call->getArgOperand(1));
return true;
}
if (GV->getName().startswith("llvm.preserve.struct.access.index")) {
@@ -224,8 +248,13 @@
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();
+ AccessIndex = getConstant(Call->getArgOperand(2));
+ return true;
+ }
+ if (GV->getName().startswith("llvm.bpf.get.field.info")) {
+ Kind = BPFGetFieldInfoAI;
+ TypeMeta = nullptr;
+ AccessIndex = getConstant(Call->getArgOperand(1));
return true;
}
@@ -307,6 +336,9 @@
uint32_t ParentAI,
const MDNode *ChildType) {
const DIType *PType = stripQualifiers(cast<DIType>(ParentType));
+ if (!ChildType)
+ return true; // get_field_info, no type comparison needed.
+
const DIType *CType = stripQualifiers(cast<DIType>(ChildType));
// Child is a derived/pointer type, which is due to type casting.
@@ -465,14 +497,58 @@
}
/// Get access index from the preserve_*_access_index intrinsic calls.
-bool BPFAbstractMemberAccess::getAccessIndex(const Value *IndexValue,
- uint64_t &AccessIndex) {
+uint64_t BPFAbstractMemberAccess::getConstant(const Value *IndexValue) {
const ConstantInt *CV = dyn_cast<ConstantInt>(IndexValue);
- if (!CV)
- return false;
+ assert(CV);
- AccessIndex = CV->getValue().getZExtValue();
- return true;
+ return CV->getValue().getZExtValue();
+}
+
+uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind, DICompositeType *CTy,
+ uint32_t AccessIndex) {
+ if (InfoKind == BPFCoreSharedInfo::BTF_FIELD_EXISTENCE)
+ return 1;
+
+ uint32_t Tag = CTy->getTag();
+ if (InfoKind == BPFCoreSharedInfo::BTF_FIELD_SIGNNESS) {
+ assert(Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type);
+ auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
+ const DIType *BaseTy = stripQualifiers(MemberTy->getBaseType());
+ const auto *BTy = dyn_cast<DIBasicType>(BaseTy);
+ while (!BTy) {
+ const auto *CompTy = dyn_cast<DICompositeType>(BaseTy);
+ assert(CompTy);
+ assert(CompTy->getTag() == dwarf::DW_TAG_enumeration_type);
+ BaseTy = stripQualifiers(CompTy->getBaseType());
+ BTy = dyn_cast<DIBasicType>(BaseTy);
+ }
+ uint32_t Encoding = BTy->getEncoding();
+ return (Encoding == dwarf::DW_ATE_signed || Encoding == dwarf::DW_ATE_signed_char);
+ }
+
+ // BTF_FIELD_BF_*
+ uint32_t PatchImm = 0;
+ assert(Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type);
+ auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
+ assert(MemberTy->isBitField());
+ uint64_t OffsetInBits = MemberTy->getOffsetInBits();
+ uint64_t SizeInBits = MemberTy->getSizeInBits();
+ assert(SizeInBits <= 63);
+ switch (InfoKind) {
+ default:
+ assert("Invalid InfoKind");
+ break;
+ case BPFCoreSharedInfo::BTF_FIELD_BF_BYTE_OFFSET_64BIT_ALIGN:
+ PatchImm = (OffsetInBits & ~0x3f) >> 3;
+ break;
+ case BPFCoreSharedInfo::BTF_FIELD_BF_LSHIFT_64BIT_ALIGN:
+ PatchImm = OffsetInBits & 0x3f;
+ break;
+ case BPFCoreSharedInfo::BTF_FIELD_BF_RSHIFT_64BIT_ALIGN:
+ PatchImm = 64 - SizeInBits;
+ break;
+ }
+ return PatchImm;
}
/// Compute the base of the whole preserve_*_access_index chains, i.e., the base
@@ -504,7 +580,8 @@
// int a[10][20]; ... __builtin_preserve_access_index(&a[2][3]) ...
// we will skip them.
uint32_t FirstIndex = 0;
- uint32_t AccessOffset = 0;
+ uint32_t PatchImm = 0; // AccessOffset or the BitField Info Encoding
+ uint32_t InfoKind = BPFCoreSharedInfo::BTF_FIELD_ACCESS_OFFSET;
while (CallStack.size()) {
auto StackElem = CallStack.top();
Call = StackElem.first;
@@ -519,17 +596,19 @@
// struct or union type
TypeName = Ty->getName();
TypeMeta = Ty;
- AccessOffset += FirstIndex * Ty->getSizeInBits() >> 3;
+
+ PatchImm += FirstIndex * Ty->getSizeInBits() >> 3;
break;
}
+ assert(Kind == BPFGetFieldInfoAI &&
+ "Reaching get_field_info and cannot find top type name");
+
// Array entries will always be consumed for accumulative initial index.
CallStack.pop();
// BPFPreserveArrayAI
- uint64_t AccessIndex;
- if (!getAccessIndex(Call->getArgOperand(2), AccessIndex))
- return nullptr;
+ uint64_t AccessIndex = getConstant(Call->getArgOperand(2));
DIType *BaseTy = nullptr;
bool CheckElemType = false;
@@ -569,7 +648,7 @@
else
TypeName = CTy->getName();
TypeMeta = CTy;
- AccessOffset += FirstIndex * CTy->getSizeInBits() >> 3;
+ PatchImm += FirstIndex * CTy->getSizeInBits() >> 3;
break;
}
}
@@ -584,30 +663,46 @@
Kind = StackElem.second;
CallStack.pop();
+ if (Kind == BPFGetFieldInfoAI)
+ break;
+
+ // Find next element if it exists
+ if (CallStack.size()) {
+ auto StackElem2 = CallStack.top();
+ uint32_t Kind2 = StackElem2.second;
+ if (Kind2 == BPFGetFieldInfoAI) {
+ CallInst *Call2 = StackElem2.first;
+ InfoKind = getConstant(Call2->getArgOperand(1));
+ }
+ }
+
// Access Index
- uint64_t AccessIndex;
uint32_t ArgIndex = (Kind == BPFPreserveUnionAI) ? 1 : 2;
- if (!getAccessIndex(Call->getArgOperand(ArgIndex), AccessIndex))
- return nullptr;
+ uint64_t AccessIndex = getConstant(Call->getArgOperand(ArgIndex));
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;
+ if (InfoKind == BPFCoreSharedInfo::BTF_FIELD_ACCESS_OFFSET) {
+ if (Tag == dwarf::DW_TAG_structure_type) {
+ auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
+ PatchImm += MemberTy->getOffsetInBits() >> 3;
+ } else if (Tag == dwarf::DW_TAG_array_type) {
+ auto *EltTy = stripQualifiers(CTy->getBaseType());
+ PatchImm += AccessIndex * calcArraySize(CTy, 1) *
+ EltTy->getSizeInBits() >> 3;
+ }
+ } else {
+ PatchImm = GetFieldInfo(InfoKind, CTy, AccessIndex);
}
}
- // Access key is the type name + access string, uniquely identifying
+ // Access key is the type name + patch immediate string, uniquely identifying
// one kernel memory access.
- AccessKey = TypeName + ":" + std::to_string(AccessOffset) + "$" + AccessKey;
+ AccessKey = TypeName + ":" + std::to_string(InfoKind) + ":" +
+ std::to_string(PatchImm) + "$" + AccessKey;
return Base;
}
@@ -646,25 +741,36 @@
GV = GEPGlobals[AccessKey];
}
- // Load the global variable.
- auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV);
- BB->getInstList().insert(Call->getIterator(), LDInst);
+ if (Kind == BPFGetFieldInfoAI) {
+ // Load the global variable.
+ auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV);
+ BB->getInstList().insert(Call->getIterator(), LDInst);
+ auto *TcInst = new TruncInst(LDInst, Call->getType());
+ BB->getInstList().insert(Call->getIterator(), TcInst);
- // Generate a BitCast
- auto *BCInst = new BitCastInst(Base, Type::getInt8PtrTy(BB->getContext()));
- BB->getInstList().insert(Call->getIterator(), BCInst);
+ Call->replaceAllUsesWith(TcInst);
+ Call->eraseFromParent();
+ } else {
+ // Load the global variable.
+ auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV);
+ BB->getInstList().insert(Call->getIterator(), LDInst);
- // Generate a GetElementPtr
- auto *GEP = GetElementPtrInst::Create(Type::getInt8Ty(BB->getContext()),
- BCInst, LDInst);
- BB->getInstList().insert(Call->getIterator(), GEP);
+ // Generate a BitCast
+ auto *BCInst = new BitCastInst(Base, Type::getInt8PtrTy(BB->getContext()));
+ BB->getInstList().insert(Call->getIterator(), BCInst);
- // Generate a BitCast
- auto *BCInst2 = new BitCastInst(GEP, Call->getType());
- BB->getInstList().insert(Call->getIterator(), BCInst2);
+ // Generate a GetElementPtr
+ auto *GEP = GetElementPtrInst::Create(Type::getInt8Ty(BB->getContext()),
+ BCInst, LDInst);
+ BB->getInstList().insert(Call->getIterator(), GEP);
- Call->replaceAllUsesWith(BCInst2);
- Call->eraseFromParent();
+ // Generate a BitCast
+ auto *BCInst2 = new BitCastInst(GEP, Call->getType());
+ BB->getInstList().insert(Call->getIterator(), BCInst2);
+
+ Call->replaceAllUsesWith(BCInst2);
+ Call->eraseFromParent();
+ }
return true;
}
Index: llvm/include/llvm/IR/IntrinsicsBPF.td
===================================================================
--- llvm/include/llvm/IR/IntrinsicsBPF.td
+++ llvm/include/llvm/IR/IntrinsicsBPF.td
@@ -20,4 +20,7 @@
Intrinsic<[llvm_i64_ty], [llvm_ptr_ty, llvm_i64_ty], [IntrReadMem]>;
def int_bpf_pseudo : GCCBuiltin<"__builtin_bpf_pseudo">,
Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty]>;
+ def int_bpf_get_field_info : GCCBuiltin<"__builtin_bpf_get_field_info">,
+ Intrinsic<[llvm_i32_ty], [llvm_anyptr_ty, llvm_i32_ty],
+ [IntrNoMem, ImmArg<1>]>;
}
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -1540,6 +1540,11 @@
if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
break;
+ case llvm::Triple::bpfeb:
+ case llvm::Triple::bpfel:
+ if (CheckBPFBuiltinFunctionCall(BuiltinID, TheCall))
+ return ExprError();
+ break;
case llvm::Triple::hexagon:
if (CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
@@ -1940,6 +1945,36 @@
return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);
}
+bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
+ CallExpr *TheCall) {
+ assert(BuiltinID == BPF::BI__builtin_get_field_info &&
+ "unexpected ARM builtin");
+
+ if (checkArgCount(*this, TheCall, 2))
+ return true;
+
+ // The first argument needs to be a record field access
+ Expr *Arg = TheCall->getArg(0);
+ if (Arg->getType()->getAsPlaceholderType() ||
+ (Arg->IgnoreParens()->getObjectKind() != OK_BitField &&
+ !dyn_cast<MemberExpr>(Arg->IgnoreParens()))) {
+ Diag(Arg->getBeginLoc(), diag::err_get_field_info_not_field)
+ << 1 << Arg->getSourceRange();
+ return true;
+ }
+
+ // The second argument needs to be a constant int
+ llvm::APSInt Value;
+ if (!TheCall->getArg(1)->isIntegerConstantExpr(Value, Context)) {
+ Diag(Arg->getBeginLoc(), diag::err_get_field_info_not_const)
+ << 2 << Arg->getSourceRange();
+ return true;
+ }
+
+ TheCall->setType(Context.UnsignedIntTy);
+ return false;
+}
+
bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) {
struct BuiltinAndString {
unsigned BuiltinID;
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -3760,6 +3760,7 @@
llvm::Value *vectorWrapScalar16(llvm::Value *Op);
llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E,
llvm::Triple::ArchType Arch);
+ llvm::Value *EmitBPFBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *BuildVector(ArrayRef<llvm::Value*> Ops);
llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -3990,9 +3990,19 @@
const CGBitFieldInfo &Info = RL.getBitFieldInfo(field);
Address Addr = base.getAddress();
unsigned Idx = RL.getLLVMFieldNo(field);
- if (Idx != 0)
- // For structs, we GEP to the field that the record layout suggests.
- Addr = Builder.CreateStructGEP(Addr, Idx, field->getName());
+ if (!IsInPreservedAIRegion) {
+ if (Idx != 0)
+ // For structs, we GEP to the field that the record layout suggests.
+ Addr = Builder.CreateStructGEP(Addr, Idx, field->getName());
+ } else {
+ const RecordDecl *rec = field->getParent();
+ llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateRecordType(
+ getContext().getRecordType(rec), rec->getLocation());
+ Addr = Builder.CreatePreserveStructAccessIndex(Addr, Idx,
+ getDebugInfoFIndex(rec, field->getFieldIndex()),
+ DbgInfo);
+ }
+
// Get the access type.
llvm::Type *FieldIntTy =
llvm::Type::getIntNTy(getLLVMContext(), Info.StorageSize);
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -4242,6 +4242,9 @@
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
return CGF->EmitAArch64BuiltinExpr(BuiltinID, E, Arch);
+ case llvm::Triple::bpfeb:
+ case llvm::Triple::bpfel:
+ return CGF->EmitBPFBuiltinExpr(BuiltinID, E);
case llvm::Triple::x86:
case llvm::Triple::x86_64:
return CGF->EmitX86BuiltinExpr(BuiltinID, E);
@@ -9300,6 +9303,41 @@
}
}
+Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E) {
+ assert(BuiltinID == BPF::BI__builtin_get_field_info &&
+ "unexpected ARM builtin");
+
+ const Expr *Arg = E->getArg(0);
+ bool IsBitField = Arg->IgnoreParens()->getObjectKind() == OK_BitField;
+ bool IsError = false;
+
+ if (!getDebugInfo()) {
+ CGM.Error(E->getExprLoc(), "using builtin_get_field_info() without -g");
+ IsError = true;
+ }
+
+ if (IsError)
+ return IsBitField ? EmitLValue(Arg).getBitFieldPointer()
+ : EmitLValue(Arg).getPointer();
+
+ // Enable underlying preserve_*_access_index() generation.
+ bool OldIsInPreservedAIRegion = IsInPreservedAIRegion;
+ IsInPreservedAIRegion = true;
+ Value *FieldAddr = IsBitField ? EmitLValue(Arg).getBitFieldPointer()
+ : EmitLValue(Arg).getPointer();
+ IsInPreservedAIRegion = OldIsInPreservedAIRegion;
+
+ ConstantInt *C = cast<ConstantInt>(EmitScalarExpr(E->getArg(1)));
+ Value *InfoKind = ConstantInt::get(Int32Ty, C->getZExtValue());
+
+ // Built the IR for the get_field_info intrinsic.
+ llvm::Function *FnGetFieldInfo = llvm::Intrinsic::getDeclaration(
+ &CGM.getModule(), llvm::Intrinsic::bpf_get_field_info,
+ {FieldAddr->getType()});
+ return Builder.CreateCall(FnGetFieldInfo, {FieldAddr, InfoKind});
+}
+
llvm::Value *CodeGenFunction::
BuildVector(ArrayRef<llvm::Value*> Ops) {
assert((Ops.size() & (Ops.size() - 1)) == 0 &&
Index: clang/lib/Basic/Targets/BPF.h
===================================================================
--- clang/lib/Basic/Targets/BPF.h
+++ clang/lib/Basic/Targets/BPF.h
@@ -22,6 +22,8 @@
namespace targets {
class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo {
+ static const Builtin::Info BuiltinInfo[];
+
public:
BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
: TargetInfo(Triple) {
@@ -54,7 +56,7 @@
Features[Name] = Enabled;
}
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
const char *getClobbers() const override { return ""; }
Index: clang/lib/Basic/Targets/BPF.cpp
===================================================================
--- clang/lib/Basic/Targets/BPF.cpp
+++ clang/lib/Basic/Targets/BPF.cpp
@@ -13,11 +13,20 @@
#include "BPF.h"
#include "Targets.h"
#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
#include "llvm/ADT/StringRef.h"
using namespace clang;
using namespace clang::targets;
+const Builtin::Info BPFTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+#include "clang/Basic/BuiltinsBPF.def"
+};
+
void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
Builder.defineMacro("__bpf__");
@@ -34,3 +43,8 @@
void BPFTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const {
Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames));
}
+
+ArrayRef<Builtin::Info> BPFTargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::BPF::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
Index: clang/include/clang/module.modulemap
===================================================================
--- clang/include/clang/module.modulemap
+++ clang/include/clang/module.modulemap
@@ -35,6 +35,7 @@
textual header "Basic/BuiltinsAArch64.def"
textual header "Basic/BuiltinsAMDGPU.def"
textual header "Basic/BuiltinsARM.def"
+ textual header "Basic/BuiltinsBPF.def"
textual header "Basic/Builtins.def"
textual header "Basic/BuiltinsHexagon.def"
textual header "Basic/BuiltinsLe64.def"
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -11047,6 +11047,7 @@
bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+ bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall);
bool CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall);
Index: clang/include/clang/Basic/TargetBuiltins.h
===================================================================
--- clang/include/clang/Basic/TargetBuiltins.h
+++ clang/include/clang/Basic/TargetBuiltins.h
@@ -52,6 +52,16 @@
};
}
+ /// BPF builtins
+ namespace BPF {
+ enum {
+ LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
+ #define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+ #include "clang/Basic/BuiltinsBPF.def"
+ LastTSBuiltin
+ };
+ }
+
/// PPC builtins
namespace PPC {
enum {
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9947,6 +9947,11 @@
"%select{non-pointer|function pointer|void pointer}0 argument to "
"'__builtin_launder' is not allowed">;
+def err_get_field_info_not_field : Error<
+ "__builtin_get_field_info argument %0 not a field access">;
+def err_get_field_info_not_const: Error<
+ "__builtin_get_field_info argument %0 not a constant">;
+
def err_bit_cast_non_trivially_copyable : Error<
"__builtin_bit_cast %select{source|destination}0 type must be trivially copyable">;
def err_bit_cast_type_size_mismatch : Error<
Index: clang/include/clang/Basic/BuiltinsBPF.def
===================================================================
--- /dev/null
+++ clang/include/clang/Basic/BuiltinsBPF.def
@@ -0,0 +1,24 @@
+//===--- BuiltinsBPF.def - BPF Builtin function database --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the BPF-specific builtin function database. Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+// The format of this database matches clang/Basic/Builtins.def.
+
+#if defined(BUILTIN) && !defined(TARGET_BUILTIN)
+# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS)
+#endif
+
+// Get record field information.
+TARGET_BUILTIN(__builtin_get_field_info, "Ui.", "t", "")
+
+#undef BUILTIN
+#undef TARGET_BUILTIN
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits