yonghong-song updated this revision to Diff 221962.
yonghong-song retitled this revision from "[WIP][CLANG][BPF] implement clang 
__builtin_bitfield_info() intrinsic" to "[WIP][CLANG][BPF] do compile-once 
run-everywhere relocation for bitfields".
yonghong-song edited the summary of this revision.
yonghong-song added a comment.
Herald added subscribers: llvm-commits, jdoerfert, hiraditya.
Herald added a project: LLVM.

add BPF backend support


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/Builtins.def
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/Sema/SemaChecking.cpp
  llvm/include/llvm/IR/IRBuilder.h
  llvm/include/llvm/IR/Intrinsics.td
  llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
  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
@@ -254,7 +254,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
@@ -966,14 +966,14 @@
   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,
+  StringRef PatchImmStr = AccessPattern.substr(FirstColon + 1,
       FirstDollar - FirstColon);
 
   BTFOffsetReloc OffsetReloc;
   OffsetReloc.Label = ORSym;
   OffsetReloc.OffsetNameOff = addString(IndexPattern);
   OffsetReloc.TypeID = RootId;
-  AccessOffsets[AccessPattern.str()] = std::stoi(OffsetStr);
+  PatchImms[AccessPattern.str()] = std::stoull(PatchImmStr);
   OffsetRelocTable[SecNameOff].push_back(OffsetReloc);
 }
 
@@ -1157,10 +1157,13 @@
         MDNode *MDN = GVar->getMetadata(LLVMContext::MD_preserve_access_index);
         DIType *Ty = dyn_cast<DIType>(MDN);
         std::string TypeName = Ty->getName();
-        int64_t Imm = AccessOffsets[GVar->getName().str()];
+        uint64_t Imm = PatchImms[GVar->getName().str()];
 
-        // Emit "mov ri, <imm>" for abstract member accesses.
-        OutMI.setOpcode(BPF::MOV_ri);
+        // Emit "mov/ld_imm64 ri, <imm>" for patched immediate.
+        if (Imm > UINT_MAX)
+          OutMI.setOpcode(BPF::LD_imm64);
+        else
+          OutMI.setOpcode(BPF::MOV_ri);
         OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
         OutMI.addOperand(MCOperand::createImm(Imm));
         return true;
Index: llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
===================================================================
--- llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
+++ llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
@@ -50,6 +50,32 @@
 //   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 access. To avoid generating loads which might
+// have side effects with bpf programs, e.g., verifier may reject it,
+// a new clang intrinsic (__builtin_preserve_bitfield_info()) is added
+// to return bitfield member offset, signness and member size, given
+// a bitfield access. For example,
+//   struct s { int a; int b:3; int b2:4; } arg;
+//   uint64_t __builtin_preserve_bitfield_info(arg->b)
+// The application can then use member offset, signness and member size
+// to perform bit field extraction.
+//
+// A new IR intrinsic:
+//   uint64_t preserve_array_access_index(base)
+// is introduced.
+// The above __builtin_preserve_bitfield_info(arg->b) will generate
+// two preserve_*_access_index() calls like
+//   addr = preserve_struct_access_index(base, 1, 1) !struct s
+//   uint64_t preserve_array_access_index(addr)
+// The above two IR intrinsics will be eventually replaced with
+// a relocatable insn:
+//   bitfield_info = 8ULL << 48 /* member offset */ |
+//                   1 << 7 /* signness */ |
+//                   3 /* member size */
+// and bitfield_info can be changed by bpf loader based on the
+// types on the host.
+//
 //===----------------------------------------------------------------------===//
 
 #include "BPF.h"
@@ -95,14 +121,15 @@
     BPFPreserveArrayAI = 1,
     BPFPreserveUnionAI = 2,
     BPFPreserveStructAI = 3,
+    BPFPreserveBitFieldAI = 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.
+  // The base call is an input of something else other than
+  // preserve_*_access_index intrinsics.
   std::map<CallInst *, uint32_t> BaseAICalls;
 
   bool doTransformation(Module &M);
@@ -125,7 +152,7 @@
 
   Value *computeBaseAndAccessKey(CallInst *Call, std::string &AccessKey,
                                  uint32_t Kind, MDNode *&BaseMeta);
-  bool getAccessIndex(const Value *IndexValue, uint64_t &AccessIndex);
+  uint64_t getAccessIndex(const Value *IndexValue);
   bool transformGEPChain(Module &M, CallInst *Call, uint32_t Kind);
 };
 } // End anonymous namespace
@@ -228,6 +255,11 @@
                       ->getZExtValue();
     return true;
   }
+  if (GV->getName().startswith("llvm.preserve.bitfield.access.index")) {
+    Kind = BPFPreserveBitFieldAI;
+    TypeMeta = nullptr;
+    return true;
+  }
 
   return false;
 }
@@ -307,6 +339,9 @@
                                              uint32_t ParentAI,
                                              const MDNode *ChildType) {
   const DIType *PType = stripQualifiers(cast<DIType>(ParentType));
+  if (!ChildType)
+    return true; // Bitfield Parent, 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 +500,11 @@
 }
 
 /// Get access index from the preserve_*_access_index intrinsic calls.
-bool BPFAbstractMemberAccess::getAccessIndex(const Value *IndexValue,
-                                             uint64_t &AccessIndex) {
+uint64_t BPFAbstractMemberAccess::getAccessIndex(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();
 }
 
 /// Compute the base of the whole preserve_*_access_index chains, i.e., the base
@@ -504,7 +536,7 @@
   //    int a[10][20]; ... __builtin_preserve_access_index(&a[2][3]) ...
   // we will skip them.
   uint32_t FirstIndex = 0;
-  uint32_t AccessOffset = 0;
+  uint64_t PatchImm = 0; // AccessOffset or the BitField Info Encoding
   while (CallStack.size()) {
     auto StackElem = CallStack.top();
     Call = StackElem.first;
@@ -519,17 +551,18 @@
       // struct or union type
       TypeName = Ty->getName();
       TypeMeta = Ty;
-      AccessOffset += FirstIndex * Ty->getSizeInBits() >> 3;
+      PatchImm += FirstIndex * Ty->getSizeInBits() >> 3;
       break;
     }
 
+    assert(Kind == BPFPreserveBitFieldAI &&
+           "Reaching preserve_bitfield_access_index 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 = getAccessIndex(Call->getArgOperand(2));
 
     DIType *BaseTy = nullptr;
     bool CheckElemType = false;
@@ -569,7 +602,7 @@
       else
         TypeName = CTy->getName();
       TypeMeta = CTy;
-      AccessOffset += FirstIndex * CTy->getSizeInBits() >> 3;
+      PatchImm += FirstIndex * CTy->getSizeInBits() >> 3;
       break;
     }
   }
@@ -584,11 +617,12 @@
     Kind = StackElem.second;
     CallStack.pop();
 
+    if (Kind == BPFPreserveBitFieldAI)
+      break;
+
     // Access Index
-    uint64_t AccessIndex;
     uint32_t ArgIndex = (Kind == BPFPreserveUnionAI) ? 1 : 2;
-    if (!getAccessIndex(Call->getArgOperand(ArgIndex), AccessIndex))
-      return nullptr;
+    uint64_t AccessIndex = getAccessIndex(Call->getArgOperand(ArgIndex));
     AccessKey += ":" + std::to_string(AccessIndex);
 
     MDNode *MDN = Call->getMetadata(LLVMContext::MD_preserve_access_index);
@@ -597,17 +631,36 @@
     uint32_t Tag = CTy->getTag();
     if (Tag == dwarf::DW_TAG_structure_type) {
       auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]);
-      AccessOffset += MemberTy->getOffsetInBits() >> 3;
+      if (!MemberTy->isBitField()) {
+        PatchImm += MemberTy->getOffsetInBits() >> 3;
+      } else {
+        // BitField, PatchImm will be an encoding for bitfield information.
+        PatchImm = (MemberTy->getOffsetInBits() << 16) | MemberTy->getSizeInBits();
+        const DIType *BaseTy = stripQualifiers(MemberTy->getBaseType());
+        // Base Type can be integer type or enum
+        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();
+        if (Encoding == dwarf::DW_ATE_signed || Encoding == dwarf::DW_ATE_signed_char)
+          PatchImm |= 1 << 15;
+      }
     } else if (Tag == dwarf::DW_TAG_array_type) {
       auto *EltTy = stripQualifiers(CTy->getBaseType());
-      AccessOffset += AccessIndex * calcArraySize(CTy, 1) *
+      PatchImm += AccessIndex * calcArraySize(CTy, 1) *
                       EltTy->getSizeInBits() >> 3;
     }
   }
 
-  // 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(PatchImm) + "$" + AccessKey;
 
   return Base;
 }
@@ -646,25 +699,34 @@
     GV = GEPGlobals[AccessKey];
   }
 
-  // Load the global variable.
-  auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV);
-  BB->getInstList().insert(Call->getIterator(), LDInst);
+  if (Kind == BPFPreserveBitFieldAI) {
+    // Load the global variable.
+    auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV);
+    BB->getInstList().insert(Call->getIterator(), LDInst);
+
+    Call->replaceAllUsesWith(LDInst);
+    Call->eraseFromParent();
+  } else {
+    // Load the global variable.
+    auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV);
+    BB->getInstList().insert(Call->getIterator(), LDInst);
 
-  // Generate a BitCast
-  auto *BCInst = new BitCastInst(Base, Type::getInt8PtrTy(BB->getContext()));
-  BB->getInstList().insert(Call->getIterator(), BCInst);
+    // Generate a BitCast
+    auto *BCInst = new BitCastInst(Base, Type::getInt8PtrTy(BB->getContext()));
+    BB->getInstList().insert(Call->getIterator(), BCInst);
 
-  // Generate a GetElementPtr
-  auto *GEP = GetElementPtrInst::Create(Type::getInt8Ty(BB->getContext()),
-                                        BCInst, LDInst);
-  BB->getInstList().insert(Call->getIterator(), GEP);
+    // Generate a GetElementPtr
+    auto *GEP = GetElementPtrInst::Create(Type::getInt8Ty(BB->getContext()),
+                                          BCInst, LDInst);
+    BB->getInstList().insert(Call->getIterator(), GEP);
 
-  // Generate a BitCast
-  auto *BCInst2 = new BitCastInst(GEP, Call->getType());
-  BB->getInstList().insert(Call->getIterator(), BCInst2);
+    // Generate a BitCast
+    auto *BCInst2 = new BitCastInst(GEP, Call->getType());
+    BB->getInstList().insert(Call->getIterator(), BCInst2);
 
-  Call->replaceAllUsesWith(BCInst2);
-  Call->eraseFromParent();
+    Call->replaceAllUsesWith(BCInst2);
+    Call->eraseFromParent();
+  }
 
   return true;
 }
Index: llvm/include/llvm/IR/Intrinsics.td
===================================================================
--- llvm/include/llvm/IR/Intrinsics.td
+++ llvm/include/llvm/IR/Intrinsics.td
@@ -1258,6 +1258,9 @@
                                                   llvm_i32_ty],
                                                  [IntrNoMem, ImmArg<1>,
                                                   ImmArg<2>]>;
+def int_preserve_bitfield_access_index : Intrinsic<[llvm_i64_ty],
+                                                   [llvm_anyptr_ty],
+                                                   [IntrNoMem]>;
 
 //===----------------------------------------------------------------------===//
 // Target-specific intrinsics
Index: llvm/include/llvm/IR/IRBuilder.h
===================================================================
--- llvm/include/llvm/IR/IRBuilder.h
+++ llvm/include/llvm/IR/IRBuilder.h
@@ -2572,6 +2572,20 @@
     return Fn;
   }
 
+  Value *CreatePreserveBitFieldAccessIndex(Value *Base) {
+    assert(isa<PointerType>(Base->getType()) &&
+           "Invalid Base ptr type for preserve.bitfield.access.index.");
+    auto *BaseType = Base->getType();
+
+    Module *M = BB->getParent()->getParent();
+    Function *FnPreserveBitFieldAccessIndex = Intrinsic::getDeclaration(
+        M, Intrinsic::preserve_bitfield_access_index, {BaseType});
+
+    CallInst *Fn = CreateCall(FnPreserveBitFieldAccessIndex, {Base});
+
+    return Fn;
+  }
+
 private:
   /// Helper function that creates an assume intrinsic call that
   /// represents an alignment assumption on the provided Ptr, Mask, Type
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -1429,6 +1429,21 @@
     if (SemaBuiltinPreserveAI(*this, TheCall))
       return ExprError();
     break;
+  case Builtin::BI__builtin_preserve_bitfield_info: {
+    if (checkArgCount(*this, TheCall, 1))
+      return ExprError();
+
+    Expr *Arg = TheCall->getArg(0);
+    if (Arg->getType()->getAsPlaceholderType() ||
+        Arg->IgnoreParens()->getObjectKind() != OK_BitField) {
+      Diag(Arg->getBeginLoc(), diag::err_preserve_bitfield_info_not_bitfield)
+          << Arg->getSourceRange();
+      return ExprError();
+    }
+
+    TheCall->setType(Context.UnsignedLongLongTy);
+    break;
+  }
   case Builtin::BI__builtin_call_with_static_chain:
     if (SemaBuiltinCallWithStaticChain(*this, TheCall))
       return ExprError();
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -484,6 +484,10 @@
   /// region.
   bool IsInPreservedAIRegion = false;
 
+  /// True if CodeGen currently emits code inside presereved bitfield index
+  /// region.
+  bool IsInPreservedBFRegion = false;
+
   const CodeGen::CGBlockInfo *BlockInfo = nullptr;
   llvm::Value *BlockPointer = nullptr;
 
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 (!IsInPreservedBFRegion) {
+      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
@@ -1882,6 +1882,24 @@
     IsInPreservedAIRegion = false;
     return RValue::get(Res);
   }
+  case Builtin::BI__builtin_preserve_bitfield_info: {
+    if (!getDebugInfo()) {
+      CGM.Error(E->getExprLoc(), "using builtin_preserve_bitfield_info() without -g");
+      return RValue::get(EmitLValue(E->getArg(0)).getBitFieldPointer());
+    }
+
+    // Nested builtin_preserve_bitfield_info() not supported
+    if (IsInPreservedBFRegion) {
+      CGM.Error(E->getExprLoc(), "nested builtin_preserve_bitfield_info() not supported");
+      return RValue::get(EmitLValue(E->getArg(0)).getBitFieldPointer());
+    }
+
+    IsInPreservedBFRegion = true;
+    Value *Res = EmitLValue(E->getArg(0)).getBitFieldPointer();
+    IsInPreservedBFRegion = false;
+
+    return RValue::get(Builder.CreatePreserveBitFieldAccessIndex(Res));
+  }
 
   case Builtin::BI__builtin_cimag:
   case Builtin::BI__builtin_cimagf:
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9938,6 +9938,9 @@
   "%select{non-pointer|function pointer|void pointer}0 argument to "
   "'__builtin_launder' is not allowed">;
 
+def err_preserve_bitfield_info_not_bitfield : Error<
+  "__builtin_preserve_bitfield_info argument not a bitfield access">;
+
 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/Builtins.def
===================================================================
--- clang/include/clang/Basic/Builtins.def
+++ clang/include/clang/Basic/Builtins.def
@@ -1469,6 +1469,7 @@
 BUILTIN(__builtin_char_memchr, "c*cC*iz", "n")
 BUILTIN(__builtin_dump_struct, "ivC*v*", "tn")
 BUILTIN(__builtin_preserve_access_index, "v.", "t")
+BUILTIN(__builtin_preserve_bitfield_info, "LLUi.", "t")
 
 // Safestack builtins
 BUILTIN(__builtin___get_unsafe_stack_start, "v*", "Fn")
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to