diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Basic/Targets/AArch64.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Basic/Targets/AArch64.h | 1 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGBuiltin.cpp | 78 | ||||
-rw-r--r-- | clang/lib/Headers/arm_acle.h | 10 | ||||
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 164 |
5 files changed, 258 insertions, 0 deletions
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index a0885a69819..3dd94a6a0c3 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -194,6 +194,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasDotProd) Builder.defineMacro("__ARM_FEATURE_DOTPROD", "1"); + if (HasMTE) + Builder.defineMacro("__ARM_FEATURE_MEMORY_TAGGING", "1"); + if ((FPU & NeonMode) && HasFP16FML) Builder.defineMacro("__ARM_FEATURE_FP16FML", "1"); @@ -258,6 +261,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, HasDotProd = 1; if (Feature == "+fp16fml") HasFP16FML = 1; + if (Feature == "+mte") + HasMTE = 1; } setDataLayout(); diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index cb45c8205fb..f843a9ce74b 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -34,6 +34,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { unsigned HasFullFP16; unsigned HasDotProd; unsigned HasFP16FML; + unsigned HasMTE; llvm::AArch64::ArchKind ArchKind; static const Builtin::Info BuiltinInfo[]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index cfdb69c0798..bc5f6cfe43e 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -7077,6 +7077,84 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, return Builder.CreateCall(F, {Arg0, Arg1}); } + // Memory Tagging Extensions (MTE) Intrinsics + Intrinsic::ID MTEIntrinsicID = Intrinsic::not_intrinsic; + switch (BuiltinID) { + case AArch64::BI__builtin_arm_irg: + MTEIntrinsicID = Intrinsic::aarch64_irg; break; + case AArch64::BI__builtin_arm_addg: + MTEIntrinsicID = Intrinsic::aarch64_addg; break; + case AArch64::BI__builtin_arm_gmi: + MTEIntrinsicID = Intrinsic::aarch64_gmi; break; + case AArch64::BI__builtin_arm_ldg: + MTEIntrinsicID = Intrinsic::aarch64_ldg; break; + case AArch64::BI__builtin_arm_stg: + MTEIntrinsicID = Intrinsic::aarch64_stg; break; + case AArch64::BI__builtin_arm_subp: + MTEIntrinsicID = Intrinsic::aarch64_subp; break; + } + + if (MTEIntrinsicID != Intrinsic::not_intrinsic) { + llvm::Type *T = ConvertType(E->getType()); + + if (MTEIntrinsicID == Intrinsic::aarch64_irg) { + Value *Pointer = EmitScalarExpr(E->getArg(0)); + Value *Mask = EmitScalarExpr(E->getArg(1)); + + Pointer = Builder.CreatePointerCast(Pointer, Int8PtrTy); + Mask = Builder.CreateZExt(Mask, Int64Ty); + Value *RV = Builder.CreateCall( + CGM.getIntrinsic(MTEIntrinsicID), {Pointer, Mask}); + return Builder.CreatePointerCast(RV, T); + } + if (MTEIntrinsicID == Intrinsic::aarch64_addg) { + Value *Pointer = EmitScalarExpr(E->getArg(0)); + Value *TagOffset = EmitScalarExpr(E->getArg(1)); + + Pointer = Builder.CreatePointerCast(Pointer, Int8PtrTy); + TagOffset = Builder.CreateZExt(TagOffset, Int64Ty); + Value *RV = Builder.CreateCall( + CGM.getIntrinsic(MTEIntrinsicID), {Pointer, TagOffset}); + return Builder.CreatePointerCast(RV, T); + } + if (MTEIntrinsicID == Intrinsic::aarch64_gmi) { + Value *Pointer = EmitScalarExpr(E->getArg(0)); + Value *ExcludedMask = EmitScalarExpr(E->getArg(1)); + + ExcludedMask = Builder.CreateZExt(ExcludedMask, Int64Ty); + Pointer = Builder.CreatePointerCast(Pointer, Int8PtrTy); + return Builder.CreateCall( + CGM.getIntrinsic(MTEIntrinsicID), {Pointer, ExcludedMask}); + } + // Although it is possible to supply a different return + // address (first arg) to this intrinsic, for now we set + // return address same as input address. + if (MTEIntrinsicID == Intrinsic::aarch64_ldg) { + Value *TagAddress = EmitScalarExpr(E->getArg(0)); + TagAddress = Builder.CreatePointerCast(TagAddress, Int8PtrTy); + Value *RV = Builder.CreateCall( + CGM.getIntrinsic(MTEIntrinsicID), {TagAddress, TagAddress}); + return Builder.CreatePointerCast(RV, T); + } + // Although it is possible to supply a different tag (to set) + // to this intrinsic (as first arg), for now we supply + // the tag that is in input address arg (common use case). + if (MTEIntrinsicID == Intrinsic::aarch64_stg) { + Value *TagAddress = EmitScalarExpr(E->getArg(0)); + TagAddress = Builder.CreatePointerCast(TagAddress, Int8PtrTy); + return Builder.CreateCall( + CGM.getIntrinsic(MTEIntrinsicID), {TagAddress, TagAddress}); + } + if (MTEIntrinsicID == Intrinsic::aarch64_subp) { + Value *PointerA = EmitScalarExpr(E->getArg(0)); + Value *PointerB = EmitScalarExpr(E->getArg(1)); + PointerA = Builder.CreatePointerCast(PointerA, Int8PtrTy); + PointerB = Builder.CreatePointerCast(PointerB, Int8PtrTy); + return Builder.CreateCall( + CGM.getIntrinsic(MTEIntrinsicID), {PointerA, PointerB}); + } + } + if (BuiltinID == AArch64::BI__builtin_arm_rsr || BuiltinID == AArch64::BI__builtin_arm_rsr64 || BuiltinID == AArch64::BI__builtin_arm_rsrp || diff --git a/clang/lib/Headers/arm_acle.h b/clang/lib/Headers/arm_acle.h index 159509076ca..08d65fa0d06 100644 --- a/clang/lib/Headers/arm_acle.h +++ b/clang/lib/Headers/arm_acle.h @@ -605,6 +605,16 @@ __crc32cd(uint32_t __a, uint64_t __b) { #define __arm_wsr64(sysreg, v) __builtin_arm_wsr64(sysreg, v) #define __arm_wsrp(sysreg, v) __builtin_arm_wsrp(sysreg, v) +// Memory Tagging Extensions (MTE) Intrinsics +#if __ARM_FEATURE_MEMORY_TAGGING +#define __arm_mte_create_random_tag(__ptr, __mask) __builtin_arm_irg(__ptr, __mask) +#define __arm_mte_increment_tag(__ptr, __tag_offset) __builtin_arm_addg(__ptr, __tag_offset) +#define __arm_mte_exclude_tag(__ptr, __excluded) __builtin_arm_gmi(__ptr, __excluded) +#define __arm_mte_get_tag(__ptr) __builtin_arm_ldg(__ptr) +#define __arm_mte_set_tag(__ptr) __builtin_arm_stg(__ptr) +#define __arm_mte_ptrdiff(__ptra, __ptrb) __builtin_arm_subp(__ptra, __ptrb) +#endif + #if defined(__cplusplus) } #endif diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index cc66b43d080..4c2d1dc768d 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1875,6 +1875,16 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, BuiltinID == AArch64::BI__builtin_arm_wsr64) return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + // Memory Tagging Extensions (MTE) Intrinsics + if (BuiltinID == AArch64::BI__builtin_arm_irg || + BuiltinID == AArch64::BI__builtin_arm_addg || + BuiltinID == AArch64::BI__builtin_arm_gmi || + BuiltinID == AArch64::BI__builtin_arm_ldg || + BuiltinID == AArch64::BI__builtin_arm_stg || + BuiltinID == AArch64::BI__builtin_arm_subp) { + return SemaBuiltinARMMemoryTaggingCall(BuiltinID, TheCall); + } + if (BuiltinID == AArch64::BI__builtin_arm_rsr || BuiltinID == AArch64::BI__builtin_arm_rsrp || BuiltinID == AArch64::BI__builtin_arm_wsr || @@ -6102,6 +6112,160 @@ bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, return false; } +/// SemaBuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions +bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) { + if (BuiltinID == AArch64::BI__builtin_arm_irg) { + if (checkArgCount(*this, TheCall, 2)) + return true; + Expr *Arg0 = TheCall->getArg(0); + Expr *Arg1 = TheCall->getArg(1); + + ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + TheCall->setArg(0, FirstArg.get()); + + ExprResult SecArg = DefaultLvalueConversion(Arg1); + if (SecArg.isInvalid()) + return true; + QualType SecArgType = SecArg.get()->getType(); + if (!SecArgType->isIntegerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) + << "second" << SecArgType << Arg1->getSourceRange(); + + // Derive the return type from the pointer argument. + TheCall->setType(FirstArgType); + return false; + } + + if (BuiltinID == AArch64::BI__builtin_arm_addg) { + if (checkArgCount(*this, TheCall, 2)) + return true; + + Expr *Arg0 = TheCall->getArg(0); + ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + TheCall->setArg(0, FirstArg.get()); + + // Derive the return type from the pointer argument. + TheCall->setType(FirstArgType); + + // Second arg must be an constant in range [0,15] + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + } + + if (BuiltinID == AArch64::BI__builtin_arm_gmi) { + if (checkArgCount(*this, TheCall, 2)) + return true; + Expr *Arg0 = TheCall->getArg(0); + Expr *Arg1 = TheCall->getArg(1); + + ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + + QualType SecArgType = Arg1->getType(); + if (!SecArgType->isIntegerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) + << "second" << SecArgType << Arg1->getSourceRange(); + TheCall->setType(Context.IntTy); + return false; + } + + if (BuiltinID == AArch64::BI__builtin_arm_ldg || + BuiltinID == AArch64::BI__builtin_arm_stg) { + if (checkArgCount(*this, TheCall, 1)) + return true; + Expr *Arg0 = TheCall->getArg(0); + ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + TheCall->setArg(0, FirstArg.get()); + + // Derive the return type from the pointer argument. + if (BuiltinID == AArch64::BI__builtin_arm_ldg) + TheCall->setType(FirstArgType); + return false; + } + + if (BuiltinID == AArch64::BI__builtin_arm_subp) { + Expr *ArgA = TheCall->getArg(0); + Expr *ArgB = TheCall->getArg(1); + + ExprResult ArgExprA = DefaultFunctionArrayLvalueConversion(ArgA); + ExprResult ArgExprB = DefaultFunctionArrayLvalueConversion(ArgB); + + if (ArgExprA.isInvalid() || ArgExprB.isInvalid()) + return true; + + QualType ArgTypeA = ArgExprA.get()->getType(); + QualType ArgTypeB = ArgExprB.get()->getType(); + + auto isNull = [&] (Expr *E) -> bool { + return E->isNullPointerConstant( + Context, Expr::NPC_ValueDependentIsNotNull); }; + + // argument should be either a pointer or null + if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA)) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) + << "first" << ArgTypeA << ArgA->getSourceRange(); + + if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB)) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) + << "second" << ArgTypeB << ArgB->getSourceRange(); + + // Ensure Pointee types are compatible + if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) && + ArgTypeB->isAnyPointerType() && !isNull(ArgB)) { + QualType pointeeA = ArgTypeA->getPointeeType(); + QualType pointeeB = ArgTypeB->getPointeeType(); + if (!Context.typesAreCompatible( + Context.getCanonicalType(pointeeA).getUnqualifiedType(), + Context.getCanonicalType(pointeeB).getUnqualifiedType())) { + return Diag(TheCall->getBeginLoc(), diag::err_typecheck_sub_ptr_compatible) + << ArgTypeA << ArgTypeB << ArgA->getSourceRange() + << ArgB->getSourceRange(); + } + } + + // at least one argument should be pointer type + if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_any2arg_pointer) + << ArgTypeA << ArgTypeB << ArgA->getSourceRange(); + + if (isNull(ArgA)) // adopt type of the other pointer + ArgExprA = ImpCastExprToType(ArgExprA.get(), ArgTypeB, CK_NullToPointer); + + if (isNull(ArgB)) + ArgExprB = ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer); + + TheCall->setArg(0, ArgExprA.get()); + TheCall->setArg(1, ArgExprB.get()); + TheCall->setType(Context.LongLongTy); + return false; + } + assert(false && "Unhandled ARM MTE intrinsic"); + return true; +} + /// SemaBuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr /// TheCall is an ARM/AArch64 special register string literal. bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, |