diff --git a/.ci/monolithic-linux.sh b/.ci/monolithic-linux.sh index 4a8418d7baa8c..e6a59a2ae1306 100755 --- a/.ci/monolithic-linux.sh +++ b/.ci/monolithic-linux.sh @@ -64,11 +64,13 @@ cmake -S "${MONOREPO_ROOT}"/llvm -B "${BUILD_DIR}" \ start-group "ninja" -# Targets are not escaped as they are passed as separate arguments. -ninja -C "${BUILD_DIR}" -k 0 ${targets} |& tee ninja.log -cp ${BUILD_DIR}/.ninja_log ninja.ninja_log +if [[ -n "${targets}" ]]; then + # Targets are not escaped as they are passed as separate arguments. + ninja -C "${BUILD_DIR}" -k 0 ${targets} |& tee ninja.log + cp ${BUILD_DIR}/.ninja_log ninja.ninja_log +fi -if [[ "${runtime_targets}" != "" ]]; then +if [[ -n "${runtime_targets}" ]]; then start-group "ninja Runtimes" ninja -C "${BUILD_DIR}" ${runtime_targets} |& tee ninja_runtimes.log @@ -77,7 +79,7 @@ fi # Compiling runtimes with just-built Clang and running their tests # as an additional testing for Clang. -if [[ "${runtime_targets_needs_reconfig}" != "" ]]; then +if [[ -n "${runtime_targets_needs_reconfig}" ]]; then start-group "CMake Runtimes C++26" cmake \ diff --git a/.ci/monolithic-windows.sh b/.ci/monolithic-windows.sh index 7b926b87f3623..36941644c6a6c 100755 --- a/.ci/monolithic-windows.sh +++ b/.ci/monolithic-windows.sh @@ -51,11 +51,13 @@ cmake -S "${MONOREPO_ROOT}"/llvm -B "${BUILD_DIR}" \ start-group "ninja" -# Targets are not escaped as they are passed as separate arguments. -ninja -C "${BUILD_DIR}" -k 0 ${targets} |& tee ninja.log -cp ${BUILD_DIR}/.ninja_log ninja.ninja_log +if [[ -n "${targets}" ]]; then + # Targets are not escaped as they are passed as separate arguments. + ninja -C "${BUILD_DIR}" -k 0 ${targets} |& tee ninja.log + cp ${BUILD_DIR}/.ninja_log ninja.ninja_log +fi -if [[ "${runtimes_targets}" != "" ]]; then +if [[ -n "${runtimes_targets}" ]]; then start-group "ninja runtimes" ninja -C "${BUILD_DIR}" -k 0 ${runtimes_targets} |& tee ninja_runtimes.log diff --git a/.ci/premerge_advisor_explain.py b/.ci/premerge_advisor_explain.py index 269f75cace266..69568895e9030 100644 --- a/.ci/premerge_advisor_explain.py +++ b/.ci/premerge_advisor_explain.py @@ -148,7 +148,7 @@ def main( # Skip looking for results on AArch64 for now because the premerge advisor # service is not available on AWS currently. - if platform.machine() == "arm64": + if platform.machine() == "arm64" or platform.machine() == "aarch64": sys.exit(0) main( diff --git a/.ci/premerge_advisor_upload.py b/.ci/premerge_advisor_upload.py index 9e14743c7cc07..86032a42e179d 100644 --- a/.ci/premerge_advisor_upload.py +++ b/.ci/premerge_advisor_upload.py @@ -59,7 +59,7 @@ def main(commit_sha, workflow_run_number, build_log_files): # Skip uploading results on AArch64 for now because the premerge advisor # service is not available on AWS currently. - if platform.machine() == "arm64": + if platform.machine() == "arm64" or platform.machine() == "aarch64": sys.exit(0) main(args.commit_sha, args.workflow_run_number, args.build_log_files) diff --git a/.ci/utils.sh b/.ci/utils.sh index c364f9395d67b..713a07ba5d898 100644 --- a/.ci/utils.sh +++ b/.ci/utils.sh @@ -33,7 +33,7 @@ function at-exit { # If building fails there will be no results files. shopt -s nullglob - if [[ "$GITHUB_ACTIONS" != "" ]]; then + if [[ -n "$GITHUB_ACTIONS" ]]; then python "${MONOREPO_ROOT}"/.ci/generate_test_report_github.py \ $retcode "${BUILD_DIR}"/test-results.*.xml "${MONOREPO_ROOT}"/ninja*.log \ >> $GITHUB_STEP_SUMMARY @@ -44,7 +44,7 @@ function at-exit { fi if [[ "$retcode" != "0" ]]; then - if [[ "$GITHUB_ACTIONS" != "" ]]; then + if [[ -n "$GITHUB_ACTIONS" ]]; then python "${MONOREPO_ROOT}"/.ci/premerge_advisor_upload.py \ $(git rev-parse HEAD~1) $GITHUB_RUN_NUMBER \ "${BUILD_DIR}"/test-results.*.xml "${MONOREPO_ROOT}"/ninja*.log @@ -59,10 +59,10 @@ trap at-exit EXIT function start-group { groupname=$1 - if [[ "$GITHUB_ACTIONS" != "" ]]; then + if [[ -n "$GITHUB_ACTIONS" ]]; then echo "::endgroup" echo "::group::$groupname" - elif [[ "$POSTCOMMIT_CI" != "" ]]; then + elif [[ -n "$POSTCOMMIT_CI" ]]; then echo "@@@$STEP@@@" else echo "Starting $groupname" @@ -73,6 +73,6 @@ export PIP_BREAK_SYSTEM_PACKAGES=1 pip install -q -r "${MONOREPO_ROOT}"/.ci/all_requirements.txt # The ARM64 builders run on AWS and don't have access to the GCS cache. -if [[ "$GITHUB_ACTIONS" != "" ]] && [[ "$RUNNER_ARCH" != "ARM64" ]]; then +if [[ -n "$GITHUB_ACTIONS" ]] && [[ "$RUNNER_ARCH" != "ARM64" ]]; then python .ci/cache_lit_timing_files.py download fi diff --git a/clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp b/clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp index a7b74944690b4..75693a0c563e9 100644 --- a/clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp @@ -67,6 +67,11 @@ static auto typeWithNameIn(const std::vector &Names) { hasCanonicalType(hasDeclaration(namedDecl(hasAnyName(Names))))); } +static auto functionWithNameIn(const std::vector &Names) { + auto Call = callExpr(callee(functionDecl(hasAnyName(Names)))); + return anyOf(expr(cxxBindTemporaryExpr(has(Call))), expr(Call)); +} + CoroutineHostileRAIICheck::CoroutineHostileRAIICheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), @@ -83,9 +88,8 @@ void CoroutineHostileRAIICheck::registerMatchers(MatchFinder *Finder) { hasAttr(attr::Kind::ScopedLockable))))) .bind("scoped-lockable"); auto OtherRAII = varDecl(typeWithNameIn(RAIITypesList)).bind("raii"); - auto AllowedSuspend = awaitable( - anyOf(typeWithNameIn(AllowedAwaitablesList), - callExpr(callee(functionDecl(hasAnyName(AllowedCallees)))))); + auto AllowedSuspend = awaitable(anyOf(typeWithNameIn(AllowedAwaitablesList), + functionWithNameIn(AllowedCallees))); Finder->addMatcher( expr(anyOf(coawaitExpr(unless(AllowedSuspend)), coyieldExpr()), forEachPrevStmt( @@ -113,9 +117,9 @@ void CoroutineHostileRAIICheck::storeOptions( ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "RAIITypesList", utils::options::serializeStringList(RAIITypesList)); - Options.store(Opts, "SafeAwaitableList", + Options.store(Opts, "AllowedAwaitablesList", utils::options::serializeStringList(AllowedAwaitablesList)); - Options.store(Opts, "SafeCallees", + Options.store(Opts, "AllowedCallees", utils::options::serializeStringList(AllowedCallees)); } } // namespace clang::tidy::misc diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp index ec6ddec56e1f2..dff73aeb7a5ee 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp @@ -2,7 +2,7 @@ // RUN: -config="{CheckOptions: {\ // RUN: misc-coroutine-hostile-raii.RAIITypesList: 'my::Mutex; ::my::other::Mutex', \ // RUN: misc-coroutine-hostile-raii.AllowedAwaitablesList: 'safe::awaitable; ::transformable::awaitable', \ -// RUN: misc-coroutine-hostile-raii.AllowedCallees: 'safe::AwaitFunc; ::safe::Obj::AwaitMethod' \ +// RUN: misc-coroutine-hostile-raii.AllowedCallees: 'safe::AwaitFunc; ::safe::Obj::AwaitMethod; retExemptedAwaitable' \ // RUN: }}" namespace std { @@ -163,7 +163,10 @@ ReturnObject RAIISafeSuspendTest() { // ================================================================================ // Safe transformable awaitable // ================================================================================ -struct transformable { struct awaitable{}; }; +struct transformable { + struct awaitable{}; + struct unsafe_awaitable{}; +}; using alias_transformable_awaitable = transformable::awaitable; struct UseTransformAwaitable { struct promise_type { @@ -172,13 +175,18 @@ struct UseTransformAwaitable { std::suspend_always final_suspend() noexcept { return {}; } void unhandled_exception() {} std::suspend_always await_transform(transformable::awaitable) { return {}; } + std::suspend_always await_transform(transformable::unsafe_awaitable) { + return {}; + } }; }; auto retAwaitable() { return transformable::awaitable{}; } +auto retExemptedAwaitable() { return transformable::unsafe_awaitable{}; } UseTransformAwaitable RAIISafeSuspendTest2() { absl::Mutex a; co_await retAwaitable(); + co_await retExemptedAwaitable(); co_await transformable::awaitable{}; co_await alias_transformable_awaitable{}; } diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 34c2476ffccce..6b5c34d28ce2a 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -29,7 +29,6 @@ struct MissingFeatures { // Unhandled global/linkage information. static bool opGlobalThreadLocal() { return false; } - static bool opGlobalConstant() { return false; } static bool opGlobalWeakRef() { return false; } static bool opGlobalUnnamedAddr() { return false; } static bool opGlobalSection() { return false; } diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 12bf3a3954b1b..74ec986e49ca7 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -21,7 +21,6 @@ #include "clang/AST/ASTLambda.h" #include "clang/AST/Expr.h" #include "clang/Basic/TargetInfo.h" -#include "llvm/Support/SystemZ/zOSSupport.h" using namespace clang; using namespace clang::interp; diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 325875d10d6ea..e0e4f67df87b2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -526,7 +526,8 @@ cir::GlobalOp CIRGenFunction::addInitializerToStaticVarDecl( bool needsDtor = d.needsDestruction(getContext()) == QualType::DK_cxx_destructor; - assert(!cir::MissingFeatures::opGlobalConstant()); + gv.setConstant(d.getType().isConstantStorage( + getContext(), /*ExcludeCtor=*/true, !needsDtor)); gv.setInitialValueAttr(init); emitter.finalize(gv); diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index c1f2581eb96e3..b8e51f87d4045 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -675,7 +675,10 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty, errorNYI(d->getSourceRange(), "OpenMP target global variable"); gv.setAlignmentAttr(getSize(astContext.getDeclAlign(d))); - assert(!cir::MissingFeatures::opGlobalConstant()); + // FIXME: This code is overly simple and should be merged with other global + // handling. + gv.setConstant(d->getType().isConstantStorage( + astContext, /*ExcludeCtor=*/false, /*ExcludeDtor=*/false)); setLinkageForGV(gv, d); @@ -864,7 +867,11 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd, if (emitter) emitter->finalize(gv); - assert(!cir::MissingFeatures::opGlobalConstant()); + // If it is safe to mark the global 'constant', do so now. + gv.setConstant((vd->hasAttr() && langOpts.CUDAIsDevice) || + (!needsGlobalCtor && !needsGlobalDtor && + vd->getType().isConstantStorage( + astContext, /*ExcludeCtor=*/true, /*ExcludeDtor=*/true))); assert(!cir::MissingFeatures::opGlobalSection()); // Set CIR's linkage type as appropriate. @@ -876,8 +883,17 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd, // FIXME(cir): setLinkage should likely set MLIR's visibility automatically. gv.setVisibility(getMLIRVisibilityFromCIRLinkage(linkage)); assert(!cir::MissingFeatures::opGlobalDLLImportExport()); - if (linkage == cir::GlobalLinkageKind::CommonLinkage) - errorNYI(initExpr->getSourceRange(), "common linkage"); + if (linkage == cir::GlobalLinkageKind::CommonLinkage) { + // common vars aren't constant even if declared const. + gv.setConstant(false); + // Tentative definition of global variables may be initialized with + // non-zero null pointers. In this case they should have weak linkage + // since common linkage must have zero initializer and must not have + // explicit section therefore cannot have non-zero initial value. + std::optional initializer = gv.getInitialValue(); + if (initializer && !getBuilder().isNullValue(*initializer)) + gv.setLinkage(cir::GlobalLinkageKind::WeakAnyLinkage); + } setNonAliasAttributes(vd, gv); @@ -1231,10 +1247,8 @@ cir::GlobalLinkageKind CIRGenModule::getCIRLinkageForDeclarator( // linkage. if (!getLangOpts().CPlusPlus && isa(dd) && !isVarDeclStrongDefinition(astContext, *this, cast(dd), - getCodeGenOpts().NoCommon)) { - errorNYI(dd->getBeginLoc(), "common linkage", dd->getDeclKindName()); + getCodeGenOpts().NoCommon)) return cir::GlobalLinkageKind::CommonLinkage; - } // selectany symbols are externally visible, so use weak instead of // linkonce. MSVC optimizes away references to const selectany globals, so diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index d43a462a25092..4912bd197dba4 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1995,7 +1995,6 @@ void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp( // attributes are available on cir.global ops. This duplicates code // in CIRToLLVMGlobalOpLowering::matchAndRewrite() but that will go // away when the placeholders are no longer needed. - assert(!cir::MissingFeatures::opGlobalConstant()); const bool isConst = op.getConstant(); assert(!cir::MissingFeatures::addressSpace()); const unsigned addrSpace = 0; @@ -2055,8 +2054,7 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite( convertTypeForMemory(*getTypeConverter(), dataLayout, cirSymType); // FIXME: These default values are placeholders until the the equivalent // attributes are available on cir.global ops. - assert(!cir::MissingFeatures::opGlobalConstant()); - const bool isConst = false; + const bool isConst = op.getConstant(); assert(!cir::MissingFeatures::addressSpace()); const unsigned addrSpace = 0; const bool isDsoLocal = op.getDsoLocal(); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 13147c4f7d54d..9d2ff97789fb3 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -4641,11 +4641,17 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, LHS.getBaseInfo(), TBAAAccessInfo()); } - // The HLSL runtime handle the subscript expression on global resource arrays. - if (getLangOpts().HLSL && (E->getType()->isHLSLResourceRecord() || - E->getType()->isHLSLResourceRecordArray())) { - std::optional LV = - CGM.getHLSLRuntime().emitResourceArraySubscriptExpr(E, *this); + // The HLSL runtime handles subscript expressions on global resource arrays + // and objects with HLSL buffer layouts. + if (getLangOpts().HLSL) { + std::optional LV; + if (E->getType()->isHLSLResourceRecord() || + E->getType()->isHLSLResourceRecordArray()) { + LV = CGM.getHLSLRuntime().emitResourceArraySubscriptExpr(E, *this); + } else if (E->getType().getAddressSpace() == LangAS::hlsl_constant) { + LV = CGM.getHLSLRuntime().emitBufferArraySubscriptExpr(E, *this, + EmitIdxAfterBase); + } if (LV.has_value()) return *LV; } @@ -5110,6 +5116,11 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { EmitIgnoredExpr(E->getBase()); return EmitDeclRefLValue(DRE); } + if (getLangOpts().HLSL && + E->getType().getAddressSpace() == LangAS::hlsl_constant) { + // We have an HLSL buffer - emit using HLSL's layout rules. + return CGM.getHLSLRuntime().emitBufferMemberExpr(*this, E); + } Expr *BaseExpr = E->getBase(); // Check whether the underlying base pointer is a constant null. diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 4e61a6f61948f..67b5f919d1b2a 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -2278,6 +2278,10 @@ void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty, } } + if (getLangOpts().HLSL && Ty.getAddressSpace() == LangAS::hlsl_constant) + if (CGM.getHLSLRuntime().emitBufferCopy(*this, DestPtr, SrcPtr, Ty)) + return; + // Aggregate assignment turns into llvm.memcpy. This is almost valid per // C99 6.5.16.1p3, which states "If the value being stored in an object is // read from another object that overlaps in anyway the storage of the first diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index ec02096787c7a..208afff24d498 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -13,10 +13,11 @@ //===----------------------------------------------------------------------===// #include "CGHLSLRuntime.h" -#include "Address.h" #include "CGDebugInfo.h" +#include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "HLSLBufferLayoutBuilder.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attrs.inc" @@ -26,6 +27,7 @@ #include "clang/AST/Type.h" #include "clang/Basic/TargetOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Frontend/HLSL/RootSignatureMetadata.h" @@ -278,23 +280,18 @@ llvm::Triple::ArchType CGHLSLRuntime::getArch() { // Emits constant global variables for buffer constants declarations // and creates metadata linking the constant globals with the buffer global. -void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl, - llvm::GlobalVariable *BufGV) { +void CGHLSLRuntime::emitBufferGlobalsAndMetadata( + const HLSLBufferDecl *BufDecl, llvm::GlobalVariable *BufGV, + const CGHLSLOffsetInfo &OffsetInfo) { LLVMContext &Ctx = CGM.getLLVMContext(); // get the layout struct from constant buffer target type llvm::Type *BufType = BufGV->getValueType(); - llvm::Type *BufLayoutType = - cast(BufType)->getTypeParameter(0); llvm::StructType *LayoutStruct = cast( - cast(BufLayoutType)->getTypeParameter(0)); + cast(BufType)->getTypeParameter(0)); - // Start metadata list associating the buffer global variable with its - // constatns - SmallVector BufGlobals; - BufGlobals.push_back(ValueAsMetadata::get(BufGV)); - - const auto *ElemIt = LayoutStruct->element_begin(); + SmallVector> DeclsWithOffset; + size_t OffsetIdx = 0; for (Decl *D : BufDecl->buffer_decls()) { if (isa(D)) // Nothing to do for this declaration. @@ -326,14 +323,28 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl, continue; } + DeclsWithOffset.emplace_back(VD, OffsetInfo[OffsetIdx++]); + } + + if (!OffsetInfo.empty()) + llvm::stable_sort(DeclsWithOffset, [](const auto &LHS, const auto &RHS) { + return CGHLSLOffsetInfo::compareOffsets(LHS.second, RHS.second); + }); + + // Associate the buffer global variable with its constants + SmallVector BufGlobals; + BufGlobals.reserve(DeclsWithOffset.size() + 1); + BufGlobals.push_back(ValueAsMetadata::get(BufGV)); + + auto ElemIt = LayoutStruct->element_begin(); + for (auto &[VD, _] : DeclsWithOffset) { + if (CGM.getTargetCodeGenInfo().isHLSLPadding(*ElemIt)) + ++ElemIt; + assert(ElemIt != LayoutStruct->element_end() && "number of elements in layout struct does not match"); llvm::Type *LayoutType = *ElemIt++; - // FIXME: handle resources inside user defined structs - // (llvm/wg-hlsl#175) - - // create global variable for the constant and to metadata list GlobalVariable *ElemGV = cast(CGM.GetAddrOfGlobalVar(VD, LayoutType)); BufGlobals.push_back(ValueAsMetadata::get(ElemGV)); @@ -410,18 +421,17 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) { // create global variable for the constant buffer CGHLSLOffsetInfo OffsetInfo = CGHLSLOffsetInfo::fromDecl(*BufDecl); - llvm::TargetExtType *TargetTy = cast( - convertHLSLSpecificType(ResHandleTy, OffsetInfo)); + llvm::Type *LayoutTy = convertHLSLSpecificType(ResHandleTy, OffsetInfo); llvm::GlobalVariable *BufGV = new GlobalVariable( - TargetTy, /*isConstant*/ false, - GlobalValue::LinkageTypes::ExternalLinkage, PoisonValue::get(TargetTy), + LayoutTy, /*isConstant*/ false, + GlobalValue::LinkageTypes::ExternalLinkage, PoisonValue::get(LayoutTy), llvm::formatv("{0}{1}", BufDecl->getName(), BufDecl->isCBuffer() ? ".cb" : ".tb"), GlobalValue::NotThreadLocal); CGM.getModule().insertGlobalVariable(BufGV); // Add globals for constant buffer elements and create metadata nodes - emitBufferGlobalsAndMetadata(BufDecl, BufGV); + emitBufferGlobalsAndMetadata(BufDecl, BufGV, OffsetInfo); // Initialize cbuffer from binding (implicit or explicit) initializeBufferFromBinding(BufDecl, BufGV); @@ -440,7 +450,7 @@ void CGHLSLRuntime::addRootSignature( SignatureDecl->getRootElements(), nullptr, M); } -llvm::TargetExtType * +llvm::StructType * CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) { const auto Entry = LayoutTypes.find(StructType); if (Entry != LayoutTypes.end()) @@ -449,7 +459,7 @@ CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) { } void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType, - llvm::TargetExtType *LayoutTy) { + llvm::StructType *LayoutTy) { assert(getHLSLBufferLayoutType(StructType) == nullptr && "layout type for this struct already exist"); LayoutTypes[StructType] = LayoutTy; @@ -1103,3 +1113,236 @@ std::optional CGHLSLRuntime::emitResourceArraySubscriptExpr( } return CGF.MakeAddrLValue(TmpVar, ResultTy, AlignmentSource::Decl); } + +std::optional CGHLSLRuntime::emitBufferArraySubscriptExpr( + const ArraySubscriptExpr *E, CodeGenFunction &CGF, + llvm::function_ref EmitIdxAfterBase) { + // Find the element type to index by first padding the element type per HLSL + // buffer rules, and then padding out to a 16-byte register boundary if + // necessary. + llvm::Type *LayoutTy = + HLSLBufferLayoutBuilder(CGF.CGM).layOutType(E->getType()); + uint64_t LayoutSizeInBits = + CGM.getDataLayout().getTypeSizeInBits(LayoutTy).getFixedValue(); + CharUnits ElementSize = CharUnits::fromQuantity(LayoutSizeInBits / 8); + CharUnits RowAlignedSize = ElementSize.alignTo(CharUnits::fromQuantity(16)); + if (RowAlignedSize > ElementSize) { + llvm::Type *Padding = CGM.getTargetCodeGenInfo().getHLSLPadding( + CGM, RowAlignedSize - ElementSize); + assert(Padding && "No padding type for target?"); + LayoutTy = llvm::StructType::get(CGF.getLLVMContext(), {LayoutTy, Padding}, + /*isPacked=*/true); + } + + // If the layout type doesn't introduce any padding, we don't need to do + // anything special. + llvm::Type *OrigTy = CGF.CGM.getTypes().ConvertTypeForMem(E->getType()); + if (LayoutTy == OrigTy) + return std::nullopt; + + LValueBaseInfo EltBaseInfo; + TBAAAccessInfo EltTBAAInfo; + Address Addr = + CGF.EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo); + llvm::Value *Idx = EmitIdxAfterBase(/*Promote*/ true); + + // Index into the object as-if we have an array of the padded element type, + // and then dereference the element itself to avoid reading padding that may + // be past the end of the in-memory object. + SmallVector Indices; + Indices.push_back(Idx); + Indices.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 0)); + + llvm::Value *GEP = CGF.Builder.CreateGEP(LayoutTy, Addr.emitRawPointer(CGF), + Indices, "cbufferidx"); + Addr = Address(GEP, Addr.getElementType(), RowAlignedSize, KnownNonNull); + + return CGF.MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo); +} + +namespace { +/// Utility for emitting copies following the HLSL buffer layout rules (ie, +/// copying out of a cbuffer). +class HLSLBufferCopyEmitter { + CodeGenFunction &CGF; + Address DestPtr; + Address SrcPtr; + llvm::Type *LayoutTy = nullptr; + + SmallVector CurStoreIndices; + SmallVector CurLoadIndices; + + void emitCopyAtIndices(llvm::Type *FieldTy, llvm::ConstantInt *StoreIndex, + llvm::ConstantInt *LoadIndex) { + CurStoreIndices.push_back(StoreIndex); + CurLoadIndices.push_back(LoadIndex); + auto RestoreIndices = llvm::make_scope_exit([&]() { + CurStoreIndices.pop_back(); + CurLoadIndices.pop_back(); + }); + + // First, see if this is some kind of aggregate and recurse. + if (processArray(FieldTy)) + return; + if (processBufferLayoutArray(FieldTy)) + return; + if (processStruct(FieldTy)) + return; + + // When we have a scalar or vector element we can emit the copy. + CharUnits Align = CharUnits::fromQuantity( + CGF.CGM.getDataLayout().getABITypeAlign(FieldTy)); + Address SrcGEP = RawAddress( + CGF.Builder.CreateInBoundsGEP(LayoutTy, SrcPtr.getBasePointer(), + CurLoadIndices, "cbuf.src"), + FieldTy, Align, SrcPtr.isKnownNonNull()); + Address DestGEP = CGF.Builder.CreateInBoundsGEP( + DestPtr, CurStoreIndices, FieldTy, Align, "cbuf.dest"); + llvm::Value *Load = CGF.Builder.CreateLoad(SrcGEP, "cbuf.load"); + CGF.Builder.CreateStore(Load, DestGEP); + } + + bool processArray(llvm::Type *FieldTy) { + auto *AT = dyn_cast(FieldTy); + if (!AT) + return false; + + // If we have an llvm::ArrayType this is just a regular array with no top + // level padding, so all we need to do is copy each member. + for (unsigned I = 0, E = AT->getNumElements(); I < E; ++I) + emitCopyAtIndices(AT->getElementType(), + llvm::ConstantInt::get(CGF.SizeTy, I), + llvm::ConstantInt::get(CGF.SizeTy, I)); + return true; + } + + bool processBufferLayoutArray(llvm::Type *FieldTy) { + // A buffer layout array is a struct with two elements: the padded array, + // and the last element. That is, is should look something like this: + // + // { [%n x { %type, %padding }], %type } + // + auto *ST = dyn_cast(FieldTy); + if (!ST || ST->getNumElements() != 2) + return false; + + auto *PaddedEltsTy = dyn_cast(ST->getElementType(0)); + if (!PaddedEltsTy) + return false; + + auto *PaddedTy = dyn_cast(PaddedEltsTy->getElementType()); + if (!PaddedTy || PaddedTy->getNumElements() != 2) + return false; + + if (!CGF.CGM.getTargetCodeGenInfo().isHLSLPadding( + PaddedTy->getElementType(1))) + return false; + + llvm::Type *ElementTy = ST->getElementType(1); + if (PaddedTy->getElementType(0) != ElementTy) + return false; + + // All but the last of the logical array elements are in the padded array. + unsigned NumElts = PaddedEltsTy->getNumElements() + 1; + + // Add an extra indirection to the load for the struct and walk the + // array prefix. + CurLoadIndices.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 0)); + for (unsigned I = 0; I < NumElts - 1; ++I) { + // We need to copy the element itself, without the padding. + CurLoadIndices.push_back(llvm::ConstantInt::get(CGF.SizeTy, I)); + emitCopyAtIndices(ElementTy, llvm::ConstantInt::get(CGF.SizeTy, I), + llvm::ConstantInt::get(CGF.Int32Ty, 0)); + CurLoadIndices.pop_back(); + } + CurLoadIndices.pop_back(); + + // Now copy the last element. + emitCopyAtIndices(ElementTy, + llvm::ConstantInt::get(CGF.SizeTy, NumElts - 1), + llvm::ConstantInt::get(CGF.Int32Ty, 1)); + + return true; + } + + bool processStruct(llvm::Type *FieldTy) { + auto *ST = dyn_cast(FieldTy); + if (!ST) + return false; + + // Copy the struct field by field, but skip any explicit padding. + unsigned Skipped = 0; + for (unsigned I = 0, E = ST->getNumElements(); I < E; ++I) { + llvm::Type *ElementTy = ST->getElementType(I); + if (CGF.CGM.getTargetCodeGenInfo().isHLSLPadding(ElementTy)) + ++Skipped; + else + emitCopyAtIndices(ElementTy, llvm::ConstantInt::get(CGF.Int32Ty, I), + llvm::ConstantInt::get(CGF.Int32Ty, I + Skipped)); + } + return true; + } + +public: + HLSLBufferCopyEmitter(CodeGenFunction &CGF, Address DestPtr, Address SrcPtr) + : CGF(CGF), DestPtr(DestPtr), SrcPtr(SrcPtr) {} + + bool emitCopy(QualType CType) { + LayoutTy = HLSLBufferLayoutBuilder(CGF.CGM).layOutType(CType); + + // TODO: We should be able to fall back to a regular memcpy if the layout + // type doesn't have any padding, but that runs into issues in the backend + // currently. + // + // See https://github.com/llvm/wg-hlsl/issues/351 + emitCopyAtIndices(LayoutTy, llvm::ConstantInt::get(CGF.SizeTy, 0), + llvm::ConstantInt::get(CGF.SizeTy, 0)); + return true; + } +}; +} // namespace + +bool CGHLSLRuntime::emitBufferCopy(CodeGenFunction &CGF, Address DestPtr, + Address SrcPtr, QualType CType) { + return HLSLBufferCopyEmitter(CGF, DestPtr, SrcPtr).emitCopy(CType); +} + +LValue CGHLSLRuntime::emitBufferMemberExpr(CodeGenFunction &CGF, + const MemberExpr *E) { + LValue Base = + CGF.EmitCheckedLValue(E->getBase(), CodeGenFunction::TCK_MemberAccess); + auto *Field = dyn_cast(E->getMemberDecl()); + assert(Field && "Unexpected access into HLSL buffer"); + + // Get the field index for the struct. + const RecordDecl *Rec = Field->getParent(); + unsigned FieldIdx = + CGM.getTypes().getCGRecordLayout(Rec).getLLVMFieldNo(Field); + + // Work out the buffer layout type to index into. + QualType RecType = CGM.getContext().getCanonicalTagType(Rec); + assert(RecType->isStructureOrClassType() && "Invalid type in HLSL buffer"); + // Since this is a member of an object in the buffer and not the buffer's + // struct/class itself, we shouldn't have any offsets on the members we need + // to contend with. + CGHLSLOffsetInfo EmptyOffsets; + llvm::StructType *LayoutTy = HLSLBufferLayoutBuilder(CGM).layOutStruct( + RecType->getAsCanonical(), EmptyOffsets); + + // Now index into the struct, making sure that the type we return is the + // buffer layout type rather than the original type in the AST. + QualType FieldType = Field->getType(); + llvm::Type *FieldLLVMTy = CGM.getTypes().ConvertTypeForMem(FieldType); + CharUnits Align = CharUnits::fromQuantity( + CGF.CGM.getDataLayout().getABITypeAlign(FieldLLVMTy)); + Address Addr(CGF.Builder.CreateStructGEP(LayoutTy, Base.getPointer(CGF), + FieldIdx, Field->getName()), + FieldLLVMTy, Align, KnownNonNull); + + LValue LV = LValue::MakeAddr(Addr, FieldType, CGM.getContext(), + LValueBaseInfo(AlignmentSource::Type), + CGM.getTBAAAccessInfo(FieldType)); + LV.getQuals().addCVRQualifiers(Base.getVRQualifiers()); + + return LV; +} diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index e1200c62eccf1..e6f3cc09819bd 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -15,20 +15,19 @@ #ifndef LLVM_CLANG_LIB_CODEGEN_CGHLSLRUNTIME_H #define LLVM_CLANG_LIB_CODEGEN_CGHLSLRUNTIME_H -#include "llvm/ADT/DenseMap.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/IR/IntrinsicsDirectX.h" -#include "llvm/IR/IntrinsicsSPIRV.h" - +#include "Address.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/HLSLRuntime.h" - +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Frontend/HLSL/HLSLResource.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsDirectX.h" +#include "llvm/IR/IntrinsicsSPIRV.h" #include #include @@ -100,12 +99,19 @@ class CGHLSLOffsetInfo { /// of the HLSL buffer after all of the elements with specified offset. static CGHLSLOffsetInfo fromDecl(const HLSLBufferDecl &BufDecl); + /// Comparison function for offsets received from `operator[]` suitable for + /// use in a `stable_sort`. This will order implicit bindings after explicit + /// offsets. + static bool compareOffsets(uint32_t LHS, uint32_t RHS) { return LHS < RHS; } + /// Get the given offset, or `~0U` if there is no offset for the member. uint32_t operator[](size_t I) const { if (Offsets.empty()) return Unspecified; return Offsets[I]; } + + bool empty() const { return Offsets.empty(); } }; class CGHLSLRuntime { @@ -221,19 +227,28 @@ class CGHLSLRuntime { llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB); - llvm::TargetExtType * - getHLSLBufferLayoutType(const RecordType *LayoutStructTy); + llvm::StructType *getHLSLBufferLayoutType(const RecordType *LayoutStructTy); void addHLSLBufferLayoutType(const RecordType *LayoutStructTy, - llvm::TargetExtType *LayoutTy); + llvm::StructType *LayoutTy); void emitInitListOpaqueValues(CodeGenFunction &CGF, InitListExpr *E); std::optional emitResourceArraySubscriptExpr(const ArraySubscriptExpr *E, CodeGenFunction &CGF); + std::optional emitBufferArraySubscriptExpr( + const ArraySubscriptExpr *E, CodeGenFunction &CGF, + llvm::function_ref EmitIdxAfterBase); + + bool emitBufferCopy(CodeGenFunction &CGF, Address DestPtr, Address SrcPtr, + QualType CType); + + LValue emitBufferMemberExpr(CodeGenFunction &CGF, const MemberExpr *E); + private: void emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl, - llvm::GlobalVariable *BufGV); + llvm::GlobalVariable *BufGV, + const CGHLSLOffsetInfo &OffsetInfo); void initializeBufferFromBinding(const HLSLBufferDecl *BufDecl, llvm::GlobalVariable *GV); void initializeBufferFromBinding(const HLSLBufferDecl *BufDecl, @@ -253,7 +268,7 @@ class CGHLSLRuntime { llvm::Triple::ArchType getArch(); - llvm::DenseMap LayoutTypes; + llvm::DenseMap LayoutTypes; unsigned SPIRVLastAssignedInputSemanticLocation = 0; }; diff --git a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp index 4bc6d565fd41f..07cc738882b50 100644 --- a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp +++ b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp @@ -9,6 +9,7 @@ #include "HLSLBufferLayoutBuilder.h" #include "CGHLSLRuntime.h" #include "CodeGenModule.h" +#include "TargetInfo.h" #include "clang/AST/Type.h" #include @@ -19,72 +20,22 @@ using namespace clang; using namespace clang::CodeGen; -using llvm::hlsl::CBufferRowSizeInBytes; -namespace { - -// Creates a new array type with the same dimentions but with the new -// element type. -static llvm::Type * -createArrayWithNewElementType(CodeGenModule &CGM, - const ConstantArrayType *ArrayType, - llvm::Type *NewElemType) { - const clang::Type *ArrayElemType = ArrayType->getArrayElementTypeNoTypeQual(); - if (ArrayElemType->isConstantArrayType()) - NewElemType = createArrayWithNewElementType( - CGM, cast(ArrayElemType), NewElemType); - return llvm::ArrayType::get(NewElemType, ArrayType->getSExtSize()); -} - -// Returns the size of a scalar or vector in bytes -static unsigned getScalarOrVectorSizeInBytes(llvm::Type *Ty) { - assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy()); - if (Ty->isVectorTy()) { - llvm::FixedVectorType *FVT = cast(Ty); - return FVT->getNumElements() * - (FVT->getElementType()->getScalarSizeInBits() / 8); - } - return Ty->getScalarSizeInBits() / 8; -} - -} // namespace +static const CharUnits CBufferRowSize = + CharUnits::fromQuantity(llvm::hlsl::CBufferRowSizeInBytes); namespace clang { namespace CodeGen { -// Creates a layout type for given struct or class with HLSL constant buffer -// layout taking into account PackOffsets, if provided. -// Previously created layout types are cached by CGHLSLRuntime. -// -// The function iterates over all fields of the record type (including base -// classes) and calls layoutField to converts each field to its corresponding -// LLVM type and to calculate its HLSL constant buffer layout. Any embedded -// structs (or arrays of structs) are converted to target layout types as well. -// -// When PackOffsets are specified the elements will be placed based on the -// user-specified offsets. Not all elements must have a packoffset/register(c#) -// annotation though. For those that don't, the PackOffsets array will contain -// -1 value instead. These elements must be placed at the end of the layout -// after all of the elements with specific offset. -llvm::TargetExtType * -HLSLBufferLayoutBuilder::createLayoutType(const RecordType *RT, - const CGHLSLOffsetInfo &OffsetInfo) { +llvm::StructType * +HLSLBufferLayoutBuilder::layOutStruct(const RecordType *RT, + const CGHLSLOffsetInfo &OffsetInfo) { // check if we already have the layout type for this struct - if (llvm::TargetExtType *Ty = - CGM.getHLSLRuntime().getHLSLBufferLayoutType(RT)) + // TODO: Do we need to check for matching OffsetInfo? + if (llvm::StructType *Ty = CGM.getHLSLRuntime().getHLSLBufferLayoutType(RT)) return Ty; - SmallVector Layout; - SmallVector LayoutElements; - unsigned Index = 0; // packoffset index - unsigned EndOffset = 0; - - SmallVector> DelayLayoutFields; - - // reserve first spot in the layout vector for buffer size - Layout.push_back(0); - // iterate over all fields of the record, including fields on base classes llvm::SmallVector RecordDecls; RecordDecls.push_back(RT->castAsCXXRecordDecl()); @@ -95,187 +46,97 @@ HLSLBufferLayoutBuilder::createLayoutType(const RecordType *RT, RecordDecls.push_back(D->bases_begin()->getType()->castAsCXXRecordDecl()); } - unsigned FieldOffset; - llvm::Type *FieldType; - - while (!RecordDecls.empty()) { - const CXXRecordDecl *RD = RecordDecls.pop_back_val(); - - for (const auto *FD : RD->fields()) { - // No PackOffset info at all, or have a valid packoffset/register(c#) - // annotations value -> layout the field. - const uint32_t PO = OffsetInfo[Index++]; - if (PO != CGHLSLOffsetInfo::Unspecified) { - if (!layoutField(FD, EndOffset, FieldOffset, FieldType, PO)) - return nullptr; - Layout.push_back(FieldOffset); - LayoutElements.push_back(FieldType); - continue; - } - // Have PackOffset info, but there is no packoffset/register(cX) - // annotation on this field. Delay the layout until after all of the - // other elements with packoffsets/register(cX) are processed. - DelayLayoutFields.emplace_back(FD, LayoutElements.size()); - // reserve space for this field in the layout vector and elements list - Layout.push_back(UINT_MAX); - LayoutElements.push_back(nullptr); + SmallVector> FieldsWithOffset; + unsigned OffsetIdx = 0; + for (const CXXRecordDecl *RD : llvm::reverse(RecordDecls)) + for (const auto *FD : RD->fields()) + FieldsWithOffset.emplace_back(FD, OffsetInfo[OffsetIdx++]); + + if (!OffsetInfo.empty()) + llvm::stable_sort(FieldsWithOffset, [](const auto &LHS, const auto &RHS) { + return CGHLSLOffsetInfo::compareOffsets(LHS.second, RHS.second); + }); + + SmallVector Layout; + CharUnits CurrentOffset = CharUnits::Zero(); + for (auto &[FD, Offset] : FieldsWithOffset) { + llvm::Type *LayoutType = layOutType(FD->getType()); + + const llvm::DataLayout &DL = CGM.getDataLayout(); + CharUnits Size = + CharUnits::fromQuantity(DL.getTypeSizeInBits(LayoutType) / 8); + CharUnits Align = CharUnits::fromQuantity(DL.getABITypeAlign(LayoutType)); + + if (LayoutType->isAggregateType() || + (CurrentOffset % CBufferRowSize) + Size > CBufferRowSize) + Align = Align.alignTo(CBufferRowSize); + + CharUnits NextOffset = CurrentOffset.alignTo(Align); + + if (Offset != CGHLSLOffsetInfo::Unspecified) { + CharUnits PackOffset = CharUnits::fromQuantity(Offset); + assert(PackOffset >= NextOffset && + "Offset is invalid - would overlap with previous object"); + NextOffset = PackOffset; } - } - - // process delayed layouts - for (auto I : DelayLayoutFields) { - const FieldDecl *FD = I.first; - const unsigned IndexInLayoutElements = I.second; - // the first item in layout vector is size, so we need to offset the index - // by 1 - const unsigned IndexInLayout = IndexInLayoutElements + 1; - assert(Layout[IndexInLayout] == UINT_MAX && - LayoutElements[IndexInLayoutElements] == nullptr); - if (!layoutField(FD, EndOffset, FieldOffset, FieldType)) - return nullptr; - Layout[IndexInLayout] = FieldOffset; - LayoutElements[IndexInLayoutElements] = FieldType; + if (NextOffset > CurrentOffset) { + llvm::Type *Padding = CGM.getTargetCodeGenInfo().getHLSLPadding( + CGM, NextOffset - CurrentOffset); + assert(Padding && "No padding type for target?"); + Layout.emplace_back(Padding); + CurrentOffset = NextOffset; + } + Layout.emplace_back(LayoutType); + CurrentOffset += Size; } - // set the size of the buffer - Layout[0] = EndOffset; - - // create the layout struct type; anonymous struct have empty name but + // Create the layout struct type; anonymous structs have empty name but // non-empty qualified name const auto *Decl = RT->castAsCXXRecordDecl(); std::string Name = Decl->getName().empty() ? "anon" : Decl->getQualifiedNameAsString(); - llvm::StructType *StructTy = - llvm::StructType::create(LayoutElements, Name, true); - // create target layout type - llvm::TargetExtType *NewLayoutTy = llvm::TargetExtType::get( - CGM.getLLVMContext(), LayoutTypeName, {StructTy}, Layout); - if (NewLayoutTy) - CGM.getHLSLRuntime().addHLSLBufferLayoutType(RT, NewLayoutTy); - return NewLayoutTy; + llvm::StructType *NewTy = llvm::StructType::create(Layout, Name, + /*isPacked=*/true); + CGM.getHLSLRuntime().addHLSLBufferLayoutType(RT, NewTy); + return NewTy; } -// The function converts a single field of HLSL Buffer to its corresponding -// LLVM type and calculates it's layout. Any embedded structs (or -// arrays of structs) are converted to target layout types as well. -// The converted type is set to the FieldType parameter, the element -// offset is set to the FieldOffset parameter. The EndOffset (=size of the -// buffer) is also updated accordingly to the offset just after the placed -// element, unless the incoming EndOffset already larger (may happen in case -// of unsorted packoffset annotations). -// Returns true if the conversion was successful. -// The packoffset parameter contains the field's layout offset provided by the -// user or -1 if there was no packoffset (or register(cX)) annotation. -bool HLSLBufferLayoutBuilder::layoutField(const FieldDecl *FD, - unsigned &EndOffset, - unsigned &FieldOffset, - llvm::Type *&FieldType, - uint32_t Packoffset) { - - // Size of element; for arrays this is a size of a single element in the - // array. Total array size of calculated as (ArrayCount-1) * ArrayStride + - // ElemSize. - unsigned ElemSize = 0; - unsigned ElemOffset = 0; - unsigned ArrayCount = 1; - unsigned ArrayStride = 0; - - unsigned NextRowOffset = llvm::alignTo(EndOffset, CBufferRowSizeInBytes); - - llvm::Type *ElemLayoutTy = nullptr; - QualType FieldTy = FD->getType(); +llvm::Type *HLSLBufferLayoutBuilder::layOutArray(const ConstantArrayType *AT) { + llvm::Type *EltTy = layOutType(AT->getElementType()); + uint64_t Count = AT->getZExtSize(); + + CharUnits EltSize = + CharUnits::fromQuantity(CGM.getDataLayout().getTypeSizeInBits(EltTy) / 8); + CharUnits Padding = EltSize.alignTo(CBufferRowSize) - EltSize; + + // If we don't have any padding between elements then we just need the array + // itself. + if (Count < 2 || Padding.isZero()) + return llvm::ArrayType::get(EltTy, Count); + + llvm::LLVMContext &Context = CGM.getLLVMContext(); + llvm::Type *PaddingTy = + CGM.getTargetCodeGenInfo().getHLSLPadding(CGM, Padding); + assert(PaddingTy && "No padding type for target?"); + auto *PaddedEltTy = + llvm::StructType::get(Context, {EltTy, PaddingTy}, /*isPacked=*/true); + return llvm::StructType::get( + Context, {llvm::ArrayType::get(PaddedEltTy, Count - 1), EltTy}, + /*IsPacked=*/true); +} - if (FieldTy->isConstantArrayType()) { - // Unwrap array to find the element type and get combined array size. - QualType Ty = FieldTy; - while (Ty->isConstantArrayType()) { - auto *ArrayTy = CGM.getContext().getAsConstantArrayType(Ty); - ArrayCount *= ArrayTy->getSExtSize(); - Ty = ArrayTy->getElementType(); - } - // For array of structures, create a new array with a layout type - // instead of the structure type. - if (Ty->isStructureOrClassType()) { - CGHLSLOffsetInfo EmptyOffsets; - llvm::Type *NewTy = cast( - createLayoutType(Ty->getAsCanonical(), EmptyOffsets)); - if (!NewTy) - return false; - assert(isa(NewTy) && "expected target type"); - ElemSize = cast(NewTy)->getIntParameter(0); - ElemLayoutTy = createArrayWithNewElementType( - CGM, cast(FieldTy.getTypePtr()), NewTy); - } else { - // Array of vectors or scalars - ElemSize = - getScalarOrVectorSizeInBytes(CGM.getTypes().ConvertTypeForMem(Ty)); - ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy); - } - ArrayStride = llvm::alignTo(ElemSize, CBufferRowSizeInBytes); - ElemOffset = (Packoffset != CGHLSLOffsetInfo::Unspecified) ? Packoffset - : NextRowOffset; +llvm::Type *HLSLBufferLayoutBuilder::layOutType(QualType Ty) { + if (const auto *AT = CGM.getContext().getAsConstantArrayType(Ty)) + return layOutArray(AT); - } else if (FieldTy->isStructureOrClassType()) { - // Create a layout type for the structure + if (Ty->isStructureOrClassType()) { CGHLSLOffsetInfo EmptyOffsets; - ElemLayoutTy = createLayoutType( - cast(FieldTy->getAsCanonical()), EmptyOffsets); - if (!ElemLayoutTy) - return false; - assert(isa(ElemLayoutTy) && "expected target type"); - ElemSize = cast(ElemLayoutTy)->getIntParameter(0); - ElemOffset = (Packoffset != CGHLSLOffsetInfo::Unspecified) ? Packoffset - : NextRowOffset; - - } else { - // scalar or vector - find element size and alignment - unsigned Align = 0; - ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy); - if (ElemLayoutTy->isVectorTy()) { - // align vectors by sub element size - const llvm::FixedVectorType *FVT = - cast(ElemLayoutTy); - unsigned SubElemSize = FVT->getElementType()->getScalarSizeInBits() / 8; - ElemSize = FVT->getNumElements() * SubElemSize; - Align = SubElemSize; - } else { - assert(ElemLayoutTy->isIntegerTy() || ElemLayoutTy->isFloatingPointTy()); - ElemSize = ElemLayoutTy->getScalarSizeInBits() / 8; - Align = ElemSize; - } - - // calculate or get element offset for the vector or scalar - if (Packoffset != CGHLSLOffsetInfo::Unspecified) { - ElemOffset = Packoffset; - } else { - ElemOffset = llvm::alignTo(EndOffset, Align); - // if the element does not fit, move it to the next row - if (ElemOffset + ElemSize > NextRowOffset) - ElemOffset = NextRowOffset; - } + return layOutStruct(Ty->getAsCanonical(), EmptyOffsets); } - // Update end offset of the layout; do not update it if the EndOffset - // is already bigger than the new value (which may happen with unordered - // packoffset annotations) - unsigned NewEndOffset = - ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize; - EndOffset = std::max(EndOffset, NewEndOffset); - - // add the layout element and offset to the lists - FieldOffset = ElemOffset; - FieldType = ElemLayoutTy; - return true; -} - -bool HLSLBufferLayoutBuilder::layoutField(const FieldDecl *FD, - unsigned &EndOffset, - unsigned &FieldOffset, - llvm::Type *&FieldType) { - return layoutField(FD, EndOffset, FieldOffset, FieldType, - CGHLSLOffsetInfo::Unspecified); + return CGM.getTypes().ConvertTypeForMem(Ty); } } // namespace CodeGen diff --git a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h index 916e60e83e2c0..c55f680fe5a98 100644 --- a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h +++ b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h @@ -6,16 +6,15 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/TypeBase.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/DerivedTypes.h" namespace clang { -class RecordType; -class FieldDecl; - namespace CodeGen { class CGHLSLOffsetInfo; class CodeGenModule; +class CGHLSLOffsetInfo; //===----------------------------------------------------------------------===// // Implementation of constant buffer layout common between DirectX and @@ -25,24 +24,30 @@ class CodeGenModule; class HLSLBufferLayoutBuilder { private: CodeGenModule &CGM; - llvm::StringRef LayoutTypeName; public: - HLSLBufferLayoutBuilder(CodeGenModule &CGM, llvm::StringRef LayoutTypeName) - : CGM(CGM), LayoutTypeName(LayoutTypeName) {} - - // Returns LLVM target extension type with the name LayoutTypeName - // for given structure type and layout data. The first number in - // the Layout is the size followed by offsets for each struct element. - llvm::TargetExtType *createLayoutType(const RecordType *StructType, - const CGHLSLOffsetInfo &OffsetInfo); - -private: - bool layoutField(const clang::FieldDecl *FD, unsigned &EndOffset, - unsigned &FieldOffset, llvm::Type *&FieldType, - uint32_t Packoffset); - bool layoutField(const clang::FieldDecl *FD, unsigned &EndOffset, - unsigned &FieldOffset, llvm::Type *&FieldType); + HLSLBufferLayoutBuilder(CodeGenModule &CGM) : CGM(CGM) {} + + /// Lays out a struct type following HLSL buffer rules and considering any + /// explicit offset information. Previously created layout structs are cached + /// by CGHLSLRuntime. + /// + /// The function iterates over all fields of the record type (including base + /// classes) and works out a padded llvm type to represent the buffer layout. + /// + /// If a non-empty OffsetInfo is provided (ie, from `packoffset` annotations + /// in the source), any provided offsets offsets will be respected. If the + /// OffsetInfo is available but has empty entries, those will be layed out at + /// the end of the structure. + llvm::StructType *layOutStruct(const RecordType *StructType, + const CGHLSLOffsetInfo &OffsetInfo); + + /// Lays out an array type following HLSL buffer rules. + llvm::Type *layOutArray(const ConstantArrayType *AT); + + /// Lays out a type following HLSL buffer rules. Arrays and structures will be + /// padded appropriately and nested objects will be converted as appropriate. + llvm::Type *layOutType(QualType Type); }; } // namespace CodeGen diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index 383f52f298d2e..db06584d766bf 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -38,6 +38,7 @@ namespace CodeGen { class ABIInfo; class CallArgList; class CodeGenFunction; +class CGHLSLOffsetInfo; class CGBlockInfo; class CGHLSLOffsetInfo; class SwiftABIInfo; @@ -448,6 +449,15 @@ class TargetCodeGenInfo { return nullptr; } + /// Return an LLVM type that corresponds to padding in HLSL types + virtual llvm::Type *getHLSLPadding(CodeGenModule &CGM, + CharUnits NumBytes) const { + return nullptr; + } + + /// Return true if this is an HLSL padding type. + virtual bool isHLSLPadding(llvm::Type *Ty) const { return false; } + // Set the Branch Protection Attributes of the Function accordingly to the // BPI. Remove attributes that contradict with current BPI. static void diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp index f30b30284cb12..a007c90881ab2 100644 --- a/clang/lib/CodeGen/Targets/DirectX.cpp +++ b/clang/lib/CodeGen/Targets/DirectX.cpp @@ -31,6 +31,19 @@ class DirectXTargetCodeGenInfo : public TargetCodeGenInfo { llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *T, const CGHLSLOffsetInfo &OffsetInfo) const override; + + llvm::Type *getHLSLPadding(CodeGenModule &CGM, + CharUnits NumBytes) const override { + unsigned Size = NumBytes.getQuantity(); + return llvm::TargetExtType::get(CGM.getLLVMContext(), "dx.Padding", {}, + {Size}); + } + + bool isHLSLPadding(llvm::Type *Ty) const override { + if (auto *TET = dyn_cast(Ty)) + return TET->getName() == "dx.Padding"; + return false; + } }; llvm::Type *DirectXTargetCodeGenInfo::getHLSLType( @@ -74,10 +87,9 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType( if (ContainedTy.isNull() || !ContainedTy->isStructureType()) return nullptr; - llvm::Type *BufferLayoutTy = - HLSLBufferLayoutBuilder(CGM, "dx.Layout") - .createLayoutType(ContainedTy->castAsCanonical(), - OffsetInfo); + llvm::StructType *BufferLayoutTy = + HLSLBufferLayoutBuilder(CGM).layOutStruct( + ContainedTy->getAsCanonical(), OffsetInfo); if (!BufferLayoutTy) return nullptr; diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp index be7e9ccecae9f..1a8c85d8871ec 100644 --- a/clang/lib/CodeGen/Targets/SPIR.cpp +++ b/clang/lib/CodeGen/Targets/SPIR.cpp @@ -55,6 +55,20 @@ class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo { llvm::Type *getOpenCLType(CodeGenModule &CGM, const Type *T) const override; llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *Ty, const CGHLSLOffsetInfo &OffsetInfo) const override; + + llvm::Type *getHLSLPadding(CodeGenModule &CGM, + CharUnits NumBytes) const override { + unsigned Size = NumBytes.getQuantity(); + return llvm::TargetExtType::get(CGM.getLLVMContext(), "spirv.Padding", {}, + {Size}); + } + + bool isHLSLPadding(llvm::Type *Ty) const override { + if (auto *TET = dyn_cast(Ty)) + return TET->getName() == "spirv.Padding"; + return false; + } + llvm::Type *getSPIRVImageTypeFromHLSLResource( const HLSLAttributedResourceType::Attributes &attributes, QualType SampledType, CodeGenModule &CGM) const; @@ -563,10 +577,9 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType( if (ContainedTy.isNull() || !ContainedTy->isStructureType()) return nullptr; - llvm::Type *BufferLayoutTy = - HLSLBufferLayoutBuilder(CGM, "spirv.Layout") - .createLayoutType(ContainedTy->castAsCanonical(), - OffsetInfo); + llvm::StructType *BufferLayoutTy = + HLSLBufferLayoutBuilder(CGM).layOutStruct( + ContainedTy->getAsCanonical(), OffsetInfo); uint32_t StorageClass = /* Uniform storage class */ 2; return llvm::TargetExtType::get(Ctx, "spirv.VulkanBuffer", {BufferLayoutTy}, {StorageClass, false}); diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp index 4178d1fd352c3..a3deb907c23ed 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp @@ -358,9 +358,8 @@ void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) { } } // namespace -namespace clang::tooling::dependencies { std::unique_ptr -createDiagOptions(ArrayRef CommandLine) { +dependencies::createDiagOptions(ArrayRef CommandLine) { std::vector CLI; for (const std::string &Arg : CommandLine) CLI.push_back(Arg.c_str()); @@ -382,9 +381,10 @@ DignosticsEngineWithDiagOpts::DignosticsEngineWithDiagOpts( } std::pair, std::unique_ptr> -buildCompilation(ArrayRef ArgStrs, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr FS, - llvm::BumpPtrAllocator &Alloc) { +dependencies::buildCompilation(ArrayRef ArgStrs, + DiagnosticsEngine &Diags, + IntrusiveRefCntPtr FS, + llvm::BumpPtrAllocator &Alloc) { SmallVector Argv; Argv.reserve(ArgStrs.size()); for (const std::string &Arg : ArgStrs) @@ -417,8 +417,8 @@ buildCompilation(ArrayRef ArgStrs, DiagnosticsEngine &Diags, } std::unique_ptr -createCompilerInvocation(ArrayRef CommandLine, - DiagnosticsEngine &Diags) { +dependencies::createCompilerInvocation(ArrayRef CommandLine, + DiagnosticsEngine &Diags) { llvm::opt::ArgStringList Argv; for (const std::string &Str : ArrayRef(CommandLine).drop_front()) Argv.push_back(Str.c_str()); @@ -432,10 +432,10 @@ createCompilerInvocation(ArrayRef CommandLine, } std::pair, std::vector> -initVFSForTUBuferScanning(IntrusiveRefCntPtr BaseFS, - ArrayRef CommandLine, - StringRef WorkingDirectory, - llvm::MemoryBufferRef TUBuffer) { +dependencies::initVFSForTUBuferScanning( + IntrusiveRefCntPtr BaseFS, + ArrayRef CommandLine, StringRef WorkingDirectory, + llvm::MemoryBufferRef TUBuffer) { // Reset what might have been modified in the previous worker invocation. BaseFS->setCurrentWorkingDirectory(WorkingDirectory); @@ -459,9 +459,10 @@ initVFSForTUBuferScanning(IntrusiveRefCntPtr BaseFS, std::pair, std::vector> -initVFSForByNameScanning(IntrusiveRefCntPtr BaseFS, - ArrayRef CommandLine, - StringRef WorkingDirectory, StringRef ModuleName) { +dependencies::initVFSForByNameScanning( + IntrusiveRefCntPtr BaseFS, + ArrayRef CommandLine, StringRef WorkingDirectory, + StringRef ModuleName) { // Reset what might have been modified in the previous worker invocation. BaseFS->setCurrentWorkingDirectory(WorkingDirectory); @@ -486,7 +487,7 @@ initVFSForByNameScanning(IntrusiveRefCntPtr BaseFS, return std::make_pair(OverlayFS, ModifiedCommandLine); } -bool initializeScanCompilerInstance( +bool dependencies::initializeScanCompilerInstance( CompilerInstance &ScanInstance, IntrusiveRefCntPtr FS, DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service, @@ -559,7 +560,7 @@ bool initializeScanCompilerInstance( } llvm::SmallVector -getInitialStableDirs(const CompilerInstance &ScanInstance) { +dependencies::getInitialStableDirs(const CompilerInstance &ScanInstance) { // Create a collection of stable directories derived from the ScanInstance // for determining whether module dependencies would fully resolve from // those directories. @@ -571,8 +572,8 @@ getInitialStableDirs(const CompilerInstance &ScanInstance) { } std::optional -computePrebuiltModulesASTMap(CompilerInstance &ScanInstance, - llvm::SmallVector &StableDirs) { +dependencies::computePrebuiltModulesASTMap( + CompilerInstance &ScanInstance, llvm::SmallVector &StableDirs) { // Store a mapping of prebuilt module files and their properties like header // search options. This will prevent the implicit build to create duplicate // modules and will force reuse of the existing prebuilt module files @@ -590,7 +591,8 @@ computePrebuiltModulesASTMap(CompilerInstance &ScanInstance, } std::unique_ptr -takeAndUpdateDependencyOutputOptionsFrom(CompilerInstance &ScanInstance) { +dependencies::takeAndUpdateDependencyOutputOptionsFrom( + CompilerInstance &ScanInstance) { // This function moves the existing dependency output options from the // invocation to the collector. The options in the invocation are reset, // which ensures that the compiler won't create new dependency collectors, @@ -607,7 +609,8 @@ takeAndUpdateDependencyOutputOptionsFrom(CompilerInstance &ScanInstance) { return Opts; } -std::shared_ptr initializeScanInstanceDependencyCollector( +std::shared_ptr +dependencies::initializeScanInstanceDependencyCollector( CompilerInstance &ScanInstance, std::unique_ptr DepOutputOpts, StringRef WorkingDirectory, DependencyConsumer &Consumer, @@ -633,7 +636,6 @@ std::shared_ptr initializeScanInstanceDependencyCollector( return MDC; } -} // namespace clang::tooling::dependencies bool DependencyScanningAction::runInvocation( std::unique_ptr Invocation, diff --git a/clang/test/CIR/CodeGen/constant-inits.cpp b/clang/test/CIR/CodeGen/constant-inits.cpp index d5a7bb9d57251..ef9802de405c1 100644 --- a/clang/test/CIR/CodeGen/constant-inits.cpp +++ b/clang/test/CIR/CodeGen/constant-inits.cpp @@ -105,57 +105,57 @@ void function() { // CIR-DAG: !rec_anon_struct = !cir.record // CIR-DAG: !rec_anon_struct1 = !cir.record}> -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE1e = #cir.zero : !rec_empty -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE1s = #cir.const_record<{#cir.int<0> : !s32i, #cir.int<-1> : !s32i}> : !rec_simple -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE2p1 = #cir.const_record<{#cir.int<10> : !s32i, #cir.int<20> : !s32i, #cir.const_array<[#cir.int<99> : !s8i, #cir.int<88> : !s8i, #cir.int<77> : !s8i]> : !cir.array, #cir.int<40> : !s32i}> : !rec_Point -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE2p2 = #cir.const_record<{#cir.int<123> : !s8i, #cir.int<456> : !s32i}> : !rec_packed -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE3paa = #cir.const_record<{#cir.int<1> : !s16i, #cir.int<2> : !s8i, #cir.fp<3.000000e+00> : !cir.float, #cir.zero : !u8i}> : !rec_packed_and_aligned +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE1e = #cir.zero : !rec_empty +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE1s = #cir.const_record<{#cir.int<0> : !s32i, #cir.int<-1> : !s32i}> : !rec_simple +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE2p1 = #cir.const_record<{#cir.int<10> : !s32i, #cir.int<20> : !s32i, #cir.const_array<[#cir.int<99> : !s8i, #cir.int<88> : !s8i, #cir.int<77> : !s8i]> : !cir.array, #cir.int<40> : !s32i}> : !rec_Point +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE2p2 = #cir.const_record<{#cir.int<123> : !s8i, #cir.int<456> : !s32i}> : !rec_packed +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE3paa = #cir.const_record<{#cir.int<1> : !s16i, #cir.int<2> : !s8i, #cir.fp<3.000000e+00> : !cir.float, #cir.zero : !u8i}> : !rec_packed_and_aligned -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE5array = #cir.const_array<[ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE5array = #cir.const_array<[ // CIR-DAG-SAME: #cir.const_record<{#cir.int<123> : !s32i, #cir.int<456> : !s32i, #cir.const_array<[#cir.int<11> : !s8i, #cir.int<22> : !s8i, #cir.int<33> : !s8i]> : !cir.array, #cir.int<789> : !s32i}> : !rec_Point // CIR-DAG-SAME: #cir.const_record<{#cir.int<10> : !s32i, #cir.int<20> : !s32i, #cir.zero : !cir.array, #cir.int<40> : !s32i}> : !rec_Point // CIR-DAG-SAME: ]> : !cir.array -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE12simple_array = #cir.const_array<[ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE12simple_array = #cir.const_array<[ // CIR-DAG-SAME: #cir.const_record<{#cir.int<0> : !s32i, #cir.int<-1> : !s32i}> : !rec_simple, // CIR-DAG-SAME: #cir.const_record<{#cir.int<1111> : !s32i, #cir.int<2222> : !s32i}> : !rec_simple, // CIR-DAG-SAME: #cir.const_record<{#cir.int<0> : !s32i, #cir.int<-1> : !s32i}> : !rec_simple // CIR-DAG-SAME: ]> : !cir.array -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE12packed_array = #cir.const_array<[ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE12packed_array = #cir.const_array<[ // CIR-DAG-SAME: #cir.const_record<{#cir.int<123> : !s8i, #cir.int<456> : !s32i}> : !rec_packed, // CIR-DAG-SAME: #cir.const_record<{#cir.int<123> : !s8i, #cir.int<456> : !s32i}> : !rec_packed // CIR-DAG-SAME: ]> : !cir.array -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE9paa_array = #cir.const_array<[ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE9paa_array = #cir.const_array<[ // CIR-DAG-SAME: #cir.const_record<{#cir.int<1> : !s16i, #cir.int<2> : !s8i, #cir.fp<3.000000e+00> : !cir.float, #cir.zero : !u8i}> : !rec_packed_and_aligned, // CIR-DAG-SAME: #cir.zero : !rec_packed_and_aligned // CIR-DAG-SAME: ]> : !cir.array -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE6ba_bf1 = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE6ba_bf1 = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<255> : !u8i, // CIR-DAG-SAME: #cir.int<170> : !u8i, // CIR-DAG-SAME: #cir.int<52> : !u8i, // CIR-DAG-SAME: #cir.int<18> : !u8i // CIR-DAG-SAME: }> : !rec_anon_struct -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE6ba_bf2 = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE6ba_bf2 = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<255> : !u8i, // CIR-DAG-SAME: #cir.int<127> : !u8i, // CIR-DAG-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array // CIR-DAG-SAME: }> : !rec_anon_struct1 -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE6ba_bf3 = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE6ba_bf3 = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<42> : !u8i // CIR-DAG-SAME: }> : !rec_single_byte_bitfield -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE5p_bf1 = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE5p_bf1 = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<17> : !u8i, // CIR-DAG-SAME: #cir.int<3> : !u8i, // CIR-DAG-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array // CIR-DAG-SAME: }> : !rec_anon_struct1 -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE5p_bf2 = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE5p_bf2 = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<127> : !u8i, // CIR-DAG-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array // CIR-DAG-SAME: }> : !rec_signed_partial_bitfields -// CIR-DAG: cir.global "private" internal dso_local @_ZZ8functionvE5p_bf3 = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @_ZZ8functionvE5p_bf3 = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<125> : !u8i // CIR-DAG-SAME: }> : !rec_mixed_partial_bitfields @@ -163,21 +163,21 @@ void function() { // CIR: cir.return -// LLVM-DAG: @_ZZ8functionvE12packed_array = internal global [2 x %struct.packed] [%struct.packed <{ i8 123, i32 456 }>, %struct.packed <{ i8 123, i32 456 }>] -// LLVM-DAG: @_ZZ8functionvE12simple_array = internal global [3 x %struct.simple] [%struct.simple { i32 0, i32 -1 }, %struct.simple { i32 1111, i32 2222 }, %struct.simple { i32 0, i32 -1 }] -// LLVM-DAG: @_ZZ8functionvE1e = internal global %struct.empty zeroinitializer -// LLVM-DAG: @_ZZ8functionvE1s = internal global %struct.simple { i32 0, i32 -1 } -// LLVM-DAG: @_ZZ8functionvE2p1 = internal global %struct.Point { i32 10, i32 20, [3 x i8] c"cXM", i32 40 } -// LLVM-DAG: @_ZZ8functionvE2p2 = internal global %struct.packed <{ i8 123, i32 456 }> -// LLVM-DAG: @_ZZ8functionvE3paa = internal global %struct.packed_and_aligned <{ i16 1, i8 2, float 3.000000e+00, i8 0 }> -// LLVM-DAG: @_ZZ8functionvE5array = internal global [2 x %struct.Point] [%struct.Point { i32 123, i32 456, [3 x i8] c"\0B\16!", i32 789 }, %struct.Point { i32 10, i32 20, [3 x i8] zeroinitializer, i32 40 }] -// LLVM-DAG: @_ZZ8functionvE9paa_array = internal global [2 x %struct.packed_and_aligned] [%struct.packed_and_aligned <{ i16 1, i8 2, float 3.000000e+00, i8 0 }>, %struct.packed_and_aligned zeroinitializer] -// LLVM-DAG: @_ZZ8functionvE6ba_bf1 = internal global { i8, i8, i8, i8 } { i8 -1, i8 -86, i8 52, i8 18 } -// LLVM-DAG: @_ZZ8functionvE6ba_bf2 = internal global { i8, i8, [2 x i8] } { i8 -1, i8 127, [2 x i8] zeroinitializer } -// LLVM-DAG: @_ZZ8functionvE6ba_bf3 = internal global %struct.single_byte_bitfield { i8 42 } -// LLVM-DAG: @_ZZ8functionvE5p_bf1 = internal global { i8, i8, [2 x i8] } { i8 17, i8 3, [2 x i8] zeroinitializer } -// LLVM-DAG: @_ZZ8functionvE5p_bf2 = internal global %struct.signed_partial_bitfields { i8 127, [3 x i8] zeroinitializer } -// LLVM-DAG: @_ZZ8functionvE5p_bf3 = internal global %struct.mixed_partial_bitfields { i8 125 } +// LLVM-DAG: @_ZZ8functionvE12packed_array = internal constant [2 x %struct.packed] [%struct.packed <{ i8 123, i32 456 }>, %struct.packed <{ i8 123, i32 456 }>] +// LLVM-DAG: @_ZZ8functionvE12simple_array = internal constant [3 x %struct.simple] [%struct.simple { i32 0, i32 -1 }, %struct.simple { i32 1111, i32 2222 }, %struct.simple { i32 0, i32 -1 }] +// LLVM-DAG: @_ZZ8functionvE1e = internal constant %struct.empty zeroinitializer +// LLVM-DAG: @_ZZ8functionvE1s = internal constant %struct.simple { i32 0, i32 -1 } +// LLVM-DAG: @_ZZ8functionvE2p1 = internal constant %struct.Point { i32 10, i32 20, [3 x i8] c"cXM", i32 40 } +// LLVM-DAG: @_ZZ8functionvE2p2 = internal constant %struct.packed <{ i8 123, i32 456 }> +// LLVM-DAG: @_ZZ8functionvE3paa = internal constant %struct.packed_and_aligned <{ i16 1, i8 2, float 3.000000e+00, i8 0 }> +// LLVM-DAG: @_ZZ8functionvE5array = internal constant [2 x %struct.Point] [%struct.Point { i32 123, i32 456, [3 x i8] c"\0B\16!", i32 789 }, %struct.Point { i32 10, i32 20, [3 x i8] zeroinitializer, i32 40 }] +// LLVM-DAG: @_ZZ8functionvE9paa_array = internal constant [2 x %struct.packed_and_aligned] [%struct.packed_and_aligned <{ i16 1, i8 2, float 3.000000e+00, i8 0 }>, %struct.packed_and_aligned zeroinitializer] +// LLVM-DAG: @_ZZ8functionvE6ba_bf1 = internal constant { i8, i8, i8, i8 } { i8 -1, i8 -86, i8 52, i8 18 } +// LLVM-DAG: @_ZZ8functionvE6ba_bf2 = internal constant { i8, i8, [2 x i8] } { i8 -1, i8 127, [2 x i8] zeroinitializer } +// LLVM-DAG: @_ZZ8functionvE6ba_bf3 = internal constant %struct.single_byte_bitfield { i8 42 } +// LLVM-DAG: @_ZZ8functionvE5p_bf1 = internal constant { i8, i8, [2 x i8] } { i8 17, i8 3, [2 x i8] zeroinitializer } +// LLVM-DAG: @_ZZ8functionvE5p_bf2 = internal constant %struct.signed_partial_bitfields { i8 127, [3 x i8] zeroinitializer } +// LLVM-DAG: @_ZZ8functionvE5p_bf3 = internal constant %struct.mixed_partial_bitfields { i8 125 } // LLVM-LABEL: define{{.*}} void @_Z8functionv // LLVM: ret void diff --git a/clang/test/CIR/CodeGen/global-constant.c b/clang/test/CIR/CodeGen/global-constant.c new file mode 100644 index 0000000000000..588642c0c3faa --- /dev/null +++ b/clang/test/CIR/CodeGen/global-constant.c @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +const int global_no_use = 12; +// CIR: cir.global constant {{.*}}@global_no_use +// LLVM: @global_no_use = constant +// OGCG: @global_no_use = constant + +const float global_used = 1.2f; +// CIR: cir.global constant {{.*}}@global_used +// LLVM: @global_used = constant +// OGCG: @global_used = constant + +float const * get_float_ptr() { + return &global_used; +} diff --git a/clang/test/CIR/CodeGen/no-common.c b/clang/test/CIR/CodeGen/no-common.c new file mode 100644 index 0000000000000..ce4c5fc0b3a33 --- /dev/null +++ b/clang/test/CIR/CodeGen/no-common.c @@ -0,0 +1,103 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir %s -emit-cir -o %t-default.cir +// RUN: FileCheck --input-file=%t-default.cir %s -check-prefix=CIR-DEFAULT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir %s -fno-common -emit-cir -o %t-no-common.cir +// RUN: FileCheck --input-file=%t-no-common.cir %s -check-prefix=CIR-DEFAULT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir %s -fcommon -emit-cir -o %t-common.cir +// RUN: FileCheck --input-file=%t-common.cir %s -check-prefix=CIR-COMMON + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir %s -emit-llvm -o %t-default-cir.ll +// RUN: FileCheck --input-file=%t-default-cir.ll %s -check-prefix=LLVM-DEFAULT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir %s -fno-common -emit-llvm -o %t-no-common-cir.ll +// RUN: FileCheck --input-file=%t-no-common-cir.ll %s -check-prefix=LLVM-DEFAULT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir %s -fcommon -emit-llvm -o %t-common-cir.ll +// RUN: FileCheck --input-file=%t-common-cir.ll %s -check-prefix=LLVM-COMMON + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o %t-default.ll +// RUN: FileCheck --input-file=%t-default.ll %s -check-prefix=OGCG-DEFAULT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -fno-common -emit-llvm -o %t-no-common.ll +// RUN: FileCheck --input-file=%t-no-common.ll %s -check-prefix=OGCG-DEFAULT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -fcommon -emit-llvm -o %t-common.ll +// RUN: FileCheck --input-file=%t-common.ll %s -check-prefix=OGCG-COMMON + +const int a = 42; +// CIR-DEFAULT: cir.global constant external @a = #cir.int<42> +// LLVM-DEFAULT: @a = constant i32 42 +// OGCG-DEFAULT: @a = constant i32 42 + +// CIR-COMMON: cir.global constant external @a +// LLVM-COMMON: @a = constant i32 42 +// OGCG-COMMON: @a = constant i32 42 + +const int b __attribute__((common)) = 42; +// CIR-DEFAULT: cir.global constant external @b = #cir.int<42> +// LLVM-DEFAULT: @b = constant i32 42 +// OGCG-DEFAULT: @b = constant i32 42 + +// CIR-COMMON: cir.global constant external @b = #cir.int<42> +// LLVM-COMMON: @b = constant i32 42 +// OGCG-COMMON: @b = constant i32 42 + +const int c __attribute__((nocommon)) = 42; +// CIR-DEFAULT: cir.global constant external @c = #cir.int<42> +// LLVM-DEFAULT: @c = constant i32 42 +// OGCG-DEFAULT: @c = constant i32 42 + +// CIR-COMMON: cir.global constant external @c = #cir.int<42> +// LLVM-COMMON: @c = constant i32 42 +// OGCG-COMMON: @c = constant i32 42 + +int d = 11; +// CIR-DEFAULT: cir.global external @d = #cir.int<11> +// LLVM-DEFAULT: @d = global i32 11 +// OGCG-DEFAULT: @d = global i32 11 + +// CIR-COMMON: cir.global external @d = #cir.int<11> +// LLVM-COMMON: @d = global i32 11 +// OGCG-COMMON: @d = global i32 11 + +int e; +// CIR-DEFAULT: cir.global external @e = #cir.int<0> +// LLVM-DEFAULT: @e = global i32 0 +// OGCG-DEFAULT: @e = global i32 0 + +// CIR-COMMON: cir.global common @e = #cir.int<0> +// LLVM-COMMON: @e = common global i32 0 +// OGCG-COMMON: @e = common global i32 0 + + +int f __attribute__((common)); +// CIR-DEFAULT: cir.global common @f = #cir.int<0> +// LLVM-DEFAULT: @f = common global i32 0 +// OGCG-DEFAULT: @f = common global i32 0 + +// CIR-COMMON: cir.global common @f +// LLVM-COMMON: @f = common global i32 0 +// OGCG-COMMON: @f = common global i32 0 + +int g __attribute__((nocommon)); +// CIR-DEFAULT: cir.global external @g = #cir.int<0> +// LLVM-DEFAULT: @g = global i32 +// OGCG-DEFAULT: @g = global i32 0 + +// CIR-COMMON: cir.global external @g = #cir.int<0> +// LLVM-COMMON: @g = global i32 0 +// OGCG-COMMON: @g = global i32 0 + +const int h; +// CIR-DEFAULT: cir.global constant external @h = #cir.int<0> +// LLVM-DEFAULT: @h = constant i32 +// OGCG-DEFAULT: @h = constant i32 0 + +// CIR-COMMON: cir.global common @h = #cir.int<0> +// LLVM-COMMON: @h = common global i32 0 +// OGCG-COMMON: @h = common global i32 0 + +typedef void* (*fn_t)(long a, long b, char *f, int c); +fn_t ABC __attribute__ ((nocommon)); +// CIR-DEFAULT: cir.global external @ABC = #cir.ptr +// LLVM-DEFAULT: @ABC = global ptr null +// OGCG-DEFAULT: @ABC = global ptr null + +// CIR-COMMON: cir.global external @ABC = #cir.ptr +// LLVM-COMMON: @ABC = global ptr null +// OGCG-COMMON: @ABC = global ptr null diff --git a/clang/test/CIR/CodeGen/record-zero-init-padding.c b/clang/test/CIR/CodeGen/record-zero-init-padding.c index f131c9bbd069f..9c8daccb21a53 100644 --- a/clang/test/CIR/CodeGen/record-zero-init-padding.c +++ b/clang/test/CIR/CodeGen/record-zero-init-padding.c @@ -41,28 +41,28 @@ void test_zero_init_padding(void) { // CIR-DAG: !rec_anon_struct3 = !cir.record, !s32i}> // paf: char + 3 bytes padding + int -> uses !rec_anon_struct3 -// CIR-DAG: cir.global "private" internal dso_local @test_zero_init_padding.paf = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @test_zero_init_padding.paf = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<1> : !s8i, // CIR-DAG-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array, // CIR-DAG-SAME: #cir.int<42> : !s32i // CIR-DAG-SAME: }> : !rec_anon_struct3 // bfp: unsigned bitfield byte + 3 bytes padding + int -> uses !rec_anon_struct2 -// CIR-DAG: cir.global "private" internal dso_local @test_zero_init_padding.bfp = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @test_zero_init_padding.bfp = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<17> : !u8i, // CIR-DAG-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array, // CIR-DAG-SAME: #cir.int<99> : !s32i // CIR-DAG-SAME: }> : !rec_anon_struct2 // tp: int + char + 3 bytes tail padding -> uses !rec_anon_struct1 -// CIR-DAG: cir.global "private" internal dso_local @test_zero_init_padding.tp = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @test_zero_init_padding.tp = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<10> : !s32i, // CIR-DAG-SAME: #cir.int<20> : !s8i, // CIR-DAG-SAME: #cir.const_array<[#cir.zero : !u8i, #cir.zero : !u8i, #cir.zero : !u8i]> : !cir.array // CIR-DAG-SAME: }> : !rec_anon_struct1 // mp: char + 1 byte padding + short + 4 bytes padding + long long -> uses !rec_anon_struct -// CIR-DAG: cir.global "private" internal dso_local @test_zero_init_padding.mp = #cir.const_record<{ +// CIR-DAG: cir.global "private" constant internal dso_local @test_zero_init_padding.mp = #cir.const_record<{ // CIR-DAG-SAME: #cir.int<5> : !s8i, // CIR-DAG-SAME: #cir.zero : !u8i, // CIR-DAG-SAME: #cir.int<10> : !s16i, @@ -73,10 +73,10 @@ void test_zero_init_padding(void) { // CIR-LABEL: cir.func {{.*}}@test_zero_init_padding // CIR: cir.return -// LLVM-DAG: @test_zero_init_padding.paf = internal global { i8, [3 x i8], i32 } { i8 1, [3 x i8] zeroinitializer, i32 42 } -// LLVM-DAG: @test_zero_init_padding.bfp = internal global { i8, [3 x i8], i32 } { i8 17, [3 x i8] zeroinitializer, i32 99 } -// LLVM-DAG: @test_zero_init_padding.tp = internal global { i32, i8, [3 x i8] } { i32 10, i8 20, [3 x i8] zeroinitializer } -// LLVM-DAG: @test_zero_init_padding.mp = internal global { i8, i8, i16, [4 x i8], i64 } { i8 5, i8 0, i16 10, [4 x i8] zeroinitializer, i64 100 } +// LLVM-DAG: @test_zero_init_padding.paf = internal constant { i8, [3 x i8], i32 } { i8 1, [3 x i8] zeroinitializer, i32 42 } +// LLVM-DAG: @test_zero_init_padding.bfp = internal constant { i8, [3 x i8], i32 } { i8 17, [3 x i8] zeroinitializer, i32 99 } +// LLVM-DAG: @test_zero_init_padding.tp = internal constant { i32, i8, [3 x i8] } { i32 10, i8 20, [3 x i8] zeroinitializer } +// LLVM-DAG: @test_zero_init_padding.mp = internal constant { i8, i8, i16, [4 x i8], i64 } { i8 5, i8 0, i16 10, [4 x i8] zeroinitializer, i64 100 } // LLVM-LABEL: define{{.*}} void @test_zero_init_padding // LLVM: ret void diff --git a/clang/test/CIR/CodeGen/vtt.cpp b/clang/test/CIR/CodeGen/vtt.cpp index f9a62e37450cf..d0319b7adc126 100644 --- a/clang/test/CIR/CodeGen/vtt.cpp +++ b/clang/test/CIR/CodeGen/vtt.cpp @@ -5,12 +5,12 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-rtti -emit-llvm %s -o %t.ll // RUN: FileCheck --check-prefixes=OGCG-NO-RTTI,OGCG-COMMON --input-file=%t.ll %s -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --check-prefixes=CIR-RTTI,CIR-COMMON --input-file=%t.cir %s -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll -// RUN: FileCheck --check-prefixes=LLVM-RTTI,LLVM-COMMON --input-file=%t-cir.ll %s -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll -// RUN: FileCheck --check-prefixes=OGCG-RTTI,OGCG-COMMON --input-file=%t.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t-rtti.cir +// RUN: FileCheck --check-prefixes=CIR-RTTI,CIR-COMMON --input-file=%t-rtti.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir-rtti.ll +// RUN: FileCheck --check-prefixes=LLVM-RTTI,LLVM-COMMON --input-file=%t-cir-rtti.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t-rtti.ll +// RUN: FileCheck --check-prefixes=OGCG-RTTI,OGCG-COMMON --input-file=%t-rtti.ll %s // Note: This test will be expanded to verify VTT emission and VTT implicit // argument handling. For now, it's just test the record layout. @@ -170,7 +170,7 @@ void D::y() {} // CIR-RTTI: cir.global{{.*}} @_ZTI1B : !cir.ptr -// LLVM-RTTI: @_ZTI1B = external global ptr +// LLVM-RTTI: @_ZTI1B = external constant ptr // OGCG-RTTI: @_ZTI1B = external constant ptr diff --git a/clang/test/ClangScanDeps/module-in-stable-dir-by-name.c b/clang/test/ClangScanDeps/module-in-stable-dir-by-name.c new file mode 100644 index 0000000000000..742bc2e046ceb --- /dev/null +++ b/clang/test/ClangScanDeps/module-in-stable-dir-by-name.c @@ -0,0 +1,43 @@ +// UNSUPPORTED: system-windows +// RUN: rm -rf %t +// RUN: split-file %s %t + +// Verify the stable dir path. +//--- Sysroot/usr/include/SysA/module.modulemap +module SysA { + header "SysA.h" +} + +//--- Sysroot/usr/include/SysA/SysA.h +int SysVal = 42; + +//--- cdb.json.template +[{ + "file": "", + "directory": "DIR", + "command": "clang -fmodules -fmodules-cache-path=DIR/cache -isysroot DIR/Sysroot -IDIR/Sysroot/usr/include -x c" +}] + +// RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json +// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -module-names=SysA > %t/result.json +// RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s + +// CHECK: { +// CHECK-NEXT: "modules": [ +// CHECK-NEXT: { +// CHECK-NEXT: "is-in-stable-directories": true, +// CHECK-NEXT: "clang-module-deps": [], +// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Sysroot/usr/include/SysA/module.modulemap", +// CHECK-NEXT: "command-line": [ +// CHECK: ], +// CHECK-NEXT: "context-hash": "{{.*}}", +// CHECK-NEXT: "file-deps": [ +// CHECK-NEXT: "[[PREFIX]]/Sysroot/usr/include/SysA/module.modulemap", +// CHECK-NEXT: "[[PREFIX]]/Sysroot/usr/include/SysA/SysA.h" +// CHECK-NEXT: ], +// CHECK-NEXT: "link-libraries": [], +// CHECK-NEXT: "name": "SysA" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "translation-units": [] +// CHECK-NEXT: } diff --git a/clang/test/CodeGenHLSL/ArrayAssignable.hlsl b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl index aaa486eff10b7..d1bfc6db8b504 100644 --- a/clang/test/CodeGenHLSL/ArrayAssignable.hlsl +++ b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl @@ -5,18 +5,19 @@ struct S { float f; }; -// CHECK: [[CBLayout:%.*]] = type <{ [2 x float], [2 x <4 x i32>], [2 x [2 x i32]], [1 x target("dx.Layout", %S, 8, 0, 4)] }> -// CHECK: @CBArrays.cb = global target("dx.CBuffer", target("dx.Layout", [[CBLayout]], 136, 0, 32, 64, 128)) -// CHECK: @c1 = external hidden addrspace(2) global [2 x float], align 4 +// CHECK: [[CBLayout:%.*]] = type <{ <{ [1 x <{ float, target("dx.Padding", 12) }>], float }>, target("dx.Padding", 12), [2 x <4 x i32>], <{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>, target("dx.Padding", 12), <{ [1 x <{ %S, target("dx.Padding", 8) }>], %S }> }> + +// CHECK: @CBArrays.cb = global target("dx.CBuffer", [[CBLayout]]) +// CHECK: @c1 = external hidden addrspace(2) global <{ [1 x <{ float, target("dx.Padding", 12) }>], float }>, align 4 // CHECK: @c2 = external hidden addrspace(2) global [2 x <4 x i32>], align 16 -// CHECK: @c3 = external hidden addrspace(2) global [2 x [2 x i32]], align 4 -// CHECK: @c4 = external hidden addrspace(2) global [1 x target("dx.Layout", %S, 8, 0, 4)], align 1 +// CHECK: @c3 = external hidden addrspace(2) global <{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>, align 4 +// CHECK: @c4 = external hidden addrspace(2) global <{ [1 x <{ %S, target("dx.Padding", 8) }>], %S }>, align 1 cbuffer CBArrays : register(b0) { float c1[2]; int4 c2[2]; int c3[2][2]; - S c4[1]; + S c4[2]; } // CHECK-LABEL: define hidden void {{.*}}arr_assign1 @@ -140,40 +141,71 @@ void arr_assign7() { // CHECK-LABEL: define hidden void {{.*}}arr_assign8 // CHECK: [[C:%.*]] = alloca [2 x float], align 4 -// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[C]], ptr align 4 {{.*}}, i32 8, i1 false) -// CHECK-NEXT: call void @llvm.memcpy.p0.p2.i32(ptr align 4 [[C]], ptr addrspace(2) align 4 @c1, i32 8, i1 false) +// CHECK-NEXT: [[V0:%.*]] = getelementptr inbounds [2 x float], ptr [[C]], i32 0 +// CHECK-NEXT: [[L0:%.*]] = load float, ptr addrspace(2) @c1, align 4 +// CHECK-NEXT: store float [[L0]], ptr [[V0]], align 4 +// CHECK-NEXT: [[V1:%.*]] = getelementptr inbounds [2 x float], ptr [[C]], i32 0, i32 1 +// CHECK-NEXT: [[L1:%.*]] = load float, ptr addrspace(2) getelementptr inbounds (<{ [1 x <{ float, target("dx.Padding", 12) }>], float }>, ptr addrspace(2) @c1, i32 0, i32 1), align 4 +// CHECK-NEXT: store float [[L1]], ptr [[V1]], align 4 // CHECK-NEXT: ret void void arr_assign8() { - float C[2] = {1.0, 2.0}; + float C[2]; C = c1; } +// TODO: We should be able to just memcpy here. +// See https://github.com/llvm/wg-hlsl/issues/351 +// // CHECK-LABEL: define hidden void {{.*}}arr_assign9 // CHECK: [[C:%.*]] = alloca [2 x <4 x i32>], align 16 -// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 16 [[C]], ptr align 16 {{.*}}, i32 32, i1 false) -// CHECK-NEXT: call void @llvm.memcpy.p0.p2.i32(ptr align 16 [[C]], ptr addrspace(2) align 16 @c2, i32 32, i1 false) +// CHECK-NEXT: [[V0:%.*]] = getelementptr inbounds [2 x <4 x i32>], ptr [[C]], i32 0 +// CHECK-NEXT: [[L0:%.*]] = load <4 x i32>, ptr addrspace(2) @c2, align 16 +// CHECK-NEXT: store <4 x i32> [[L0]], ptr [[V0]], align 16 +// CHECK-NEXT: [[V1:%.*]] = getelementptr inbounds [2 x <4 x i32>], ptr [[C]], i32 0, i32 1 +// CHECK-NEXT: [[L1:%.*]] = load <4 x i32>, ptr addrspace(2) getelementptr inbounds ([2 x <4 x i32>], ptr addrspace(2) @c2, i32 0, i32 1), align 16 +// CHECK-NEXT: store <4 x i32> [[L1]], ptr [[V1]], align 16 // CHECK-NEXT: ret void void arr_assign9() { - int4 C[2] = {1,2,3,4,5,6,7,8}; + int4 C[2]; C = c2; } // CHECK-LABEL: define hidden void {{.*}}arr_assign10 // CHECK: [[C:%.*]] = alloca [2 x [2 x i32]], align 4 -// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[C]], ptr align 4 {{.*}}, i32 16, i1 false) -// CHECK-NEXT: call void @llvm.memcpy.p0.p2.i32(ptr align 4 [[C]], ptr addrspace(2) align 4 @c3, i32 16, i1 false) +// CHECK-NEXT: [[V0:%.*]] = getelementptr inbounds [2 x [2 x i32]], ptr [[C]], i32 0, i32 0, i32 0 +// CHECK-NEXT: [[L0:%.*]] = load i32, ptr addrspace(2) @c3, align 4 +// CHECK-NEXT: store i32 [[L0]], ptr [[V0]], align 4 +// CHECK-NEXT: [[V1:%.*]] = getelementptr inbounds [2 x [2 x i32]], ptr [[C]], i32 0, i32 0, i32 1 +// CHECK-NEXT: [[L1:%.*]] = load i32, ptr addrspace(2) getelementptr inbounds (<{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>, ptr addrspace(2) @c3, i32 0, i32 0, i32 0, i32 0, i32 1), align 4 +// CHECK-NEXT: store i32 [[L1]], ptr [[V1]], align 4 +// CHECK-NEXT: [[V2:%.*]] = getelementptr inbounds [2 x [2 x i32]], ptr [[C]], i32 0, i32 1, i32 0 +// CHECK-NEXT: [[L2:%.*]] = load i32, ptr addrspace(2) getelementptr inbounds (<{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>, ptr addrspace(2) @c3, i32 0, i32 1, i32 0, i32 0, i32 0), align 4 +// CHECK-NEXT: store i32 [[L2]], ptr [[V2]], align 4 +// CHECK-NEXT: [[V3:%.*]] = getelementptr inbounds [2 x [2 x i32]], ptr [[C]], i32 0, i32 1, i32 1 +// CHECK-NEXT: [[L3:%.*]] = load i32, ptr addrspace(2) getelementptr inbounds (<{ [1 x <{ <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }>, target("dx.Padding", 12) }>], <{ [1 x <{ i32, target("dx.Padding", 12) }>], i32 }> }>, ptr addrspace(2) @c3, i32 0, i32 1, i32 1), align 4 +// CHECK-NEXT: store i32 [[L3]], ptr [[V3]], align 4 // CHECK-NEXT: ret void void arr_assign10() { - int C[2][2] = {1,2,3,4}; + int C[2][2]; C = c3; } // CHECK-LABEL: define hidden void {{.*}}arr_assign11 -// CHECK: [[C:%.*]] = alloca [1 x %struct.S], align 1 -// CHECK: call void @llvm.memcpy.p0.p2.i32(ptr align 1 [[C]], ptr addrspace(2) align 1 @c4, i32 8, i1 false) +// CHECK: [[C:%.*]] = alloca [2 x %struct.S], align 1 +// CHECK-NEXT: [[V0:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[C]], i32 0, i32 0, i32 0 +// CHECK-NEXT: [[L0:%.*]] = load i32, ptr addrspace(2) @c4, align 4 +// CHECK-NEXT: store i32 [[L0]], ptr [[V0]], align 4 +// CHECK-NEXT: [[V1:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[C]], i32 0, i32 0, i32 1 +// CHECK-NEXT: [[L1:%.*]] = load float, ptr addrspace(2) getelementptr inbounds (<{ [1 x <{ %S, target("dx.Padding", 8) }>], %S }>, ptr addrspace(2) @c4, i32 0, i32 0, i32 0, i32 0, i32 1), align 4 +// CHECK-NEXT: store float [[L1]], ptr [[V1]], align 4 +// CHECK-NEXT: [[V2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[C]], i32 0, i32 1, i32 0 +// CHECK-NEXT: [[L2:%.*]] = load i32, ptr addrspace(2) getelementptr inbounds (<{ [1 x <{ %S, target("dx.Padding", 8) }>], %S }>, ptr addrspace(2) @c4, i32 0, i32 1, i32 0), align 4 +// CHECK-NEXT: store i32 [[L2]], ptr [[V2]], align 4 +// CHECK-NEXT: [[V3:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[C]], i32 0, i32 1, i32 1 +// CHECK-NEXT: [[L3:%.*]] = load float, ptr addrspace(2) getelementptr inbounds (<{ [1 x <{ %S, target("dx.Padding", 8) }>], %S }>, ptr addrspace(2) @c4, i32 0, i32 1, i32 1), align 4 +// CHECK-NEXT: store float [[L3]], ptr [[V3]], align 4 // CHECK-NEXT: ret void void arr_assign11() { - S s = {1, 2.0}; - S C[1] = {s}; + S C[2]; C = c4; } diff --git a/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl b/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl index b36682e065b3a..5553f8c17c6c8 100644 --- a/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl +++ b/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl @@ -37,9 +37,8 @@ void main(unsigned GI : SV_GroupIndex) {} // INLINE-NEXT: alloca // INLINE-NEXT: store i32 12 // INLINE-NEXT: store i32 13 -// INLINE-NEXT: %[[HANDLE:.*]] = call target("dx.CBuffer", target("dx.Layout", %"__cblayout_$Globals", 4, 0)) -// INLINE-NEXT-SAME: @"llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_$Globalss_4_0tt"(i32 0, i32 0, i32 1, i32 0, i1 false) -// INLINE-NEXT: store target("dx.CBuffer", target("dx.Layout", %"__cblayout_$Globals", 4, 0)) %[[HANDLE]], ptr @"$Globals.cb", align 4 +// INLINE-NEXT: %[[HANDLE:.*]] = call target("dx.CBuffer", %"__cblayout_$Globals") @"llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_$Globalsst"(i32 0, i32 0, i32 1, i32 0, ptr @"$Globals.str") +// INLINE-NEXT: store target("dx.CBuffer", %"__cblayout_$Globals") %[[HANDLE]], ptr @"$Globals.cb", align 4 // INLINE-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group() // INLINE-NEXT: store i32 % // INLINE-NEXT: store i32 0 diff --git a/clang/test/CodeGenHLSL/resources/cbuffer.hlsl b/clang/test/CodeGenHLSL/resources/cbuffer.hlsl index c8efe0d64c985..b72cf587d0f93 100644 --- a/clang/test/CodeGenHLSL/resources/cbuffer.hlsl +++ b/clang/test/CodeGenHLSL/resources/cbuffer.hlsl @@ -1,37 +1,123 @@ // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute -fnative-half-type -fnative-int16-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -// CHECK: %__cblayout_CBScalars = type <{ float, double, half, i64, i32, i16, i32, i64 }> -// CHECK: %__cblayout_CBVectors = type <{ <3 x float>, <3 x double>, <2 x half>, <3 x i64>, <4 x i32>, <3 x i16>, <3 x i64> }> -// CHECK: %__cblayout_CBArrays = type <{ [3 x float], [2 x <3 x double>], [2 x [2 x half]], [3 x i64], [2 x [3 x [4 x <4 x i32>]]], [1 x i16], [2 x i64], [4 x i32] }> -// CHECK: %__cblayout_CBStructs = type <{ target("dx.Layout", %A, 8, 0), target("dx.Layout", %B, 14, 0, 8), -// CHECK-SAME: target("dx.Layout", %C, 24, 0, 16), [5 x target("dx.Layout", %A, 8, 0)], -// CHECK-SAME: target("dx.Layout", %__cblayout_D, 94, 0), half, <3 x i16> }> +// CHECK: %__cblayout_CBScalars = type <{ +// CHECK-SAME: float, target("dx.Padding", 4), double, +// CHECK-SAME: half, target("dx.Padding", 6), i64, +// CHECK-SAME: i32, i16, target("dx.Padding", 2), i32, target("dx.Padding", 4), +// CHECK-SAME: i64 +// CHECK-SAME: }> + +// CHECK: %__cblayout_CBVectors = type <{ +// CHECK-SAME: <3 x float>, target("dx.Padding", 4), +// CHECK-SAME: <3 x double>, <2 x half>, target("dx.Padding", 4), +// CHECK-SAME: <3 x i64>, target("dx.Padding", 8), +// CHECK-SAME: <4 x i32>, +// CHECK-SAME: <3 x i16>, target("dx.Padding", 10), +// CHECK-SAME: <3 x i64> +// CHECK-SAME: }> + +// CHECK: %__cblayout_CBArrays = type <{ +// CHECK-SAME: <{ [2 x <{ float, target("dx.Padding", 12) }>], float }>, target("dx.Padding", 12), +// CHECK-SAME: <{ [1 x <{ <3 x double>, target("dx.Padding", 8) }>], <3 x double> }>, target("dx.Padding", 8), +// CHECK-SAME: <{ [1 x <{ +// CHECK-SAME: <{ [1 x <{ half, target("dx.Padding", 14) }>], half }>, target("dx.Padding", 14) }>], +// CHECK-SAME: <{ [1 x <{ half, target("dx.Padding", 14) }>], half }> +// CHECK-SAME: }>, target("dx.Padding", 14), +// CHECK-SAME: <{ [2 x <{ i64, target("dx.Padding", 8) }>], i64 }>, target("dx.Padding", 8), +// CHECK-SAME: [2 x [3 x [4 x <4 x i32>]]] +// CHECK-SAME: [1 x i16], target("dx.Padding", 14), +// CHECK-SAME: <{ [1 x <{ i64, target("dx.Padding", 8) }>], i64 }>, target("dx.Padding", 8), +// CHECK-SAME: <{ [3 x <{ i32, target("dx.Padding", 12) }>], i32 }> +// CHECK-SAME: }> + +// CHECK: %__cblayout_CBStructs = type <{ +// CHECK-SAME: %A, target("dx.Padding", 8), + +// TODO: We should have target("dx.Padding", 2) padding after %B, but we don't +// correctly handle 2- and 3-element vectors inside structs yet because of +// DataLayout rules. See https://github.com/llvm/llvm-project/issues/123968. +// +// CHECK-SAME: %B, + +// CHECK-SAME: %C, target("dx.Padding", 8), +// CHECK-SAME: <{ [4 x <{ %A, target("dx.Padding", 8) }>], %A }>, target("dx.Padding", 8), +// CHECK-SAME: %__cblayout_D, half, +// CHECK-SAME: <3 x i16> +// CHECK-SAME: }> // CHECK: %A = type <{ <2 x float> }> // CHECK: %B = type <{ <2 x float>, <3 x i16> }> -// CHECK: %C = type <{ i32, target("dx.Layout", %A, 8, 0) }> -// CHECK: %__cblayout_D = type <{ [2 x [3 x target("dx.Layout", %B, 14, 0, 8)]] }> +// CHECK: %C = type <{ i32, target("dx.Padding", 12), %A }> + +// CHECK: %__cblayout_D = type <{ +// CHECK-SAME: <{ [1 x <{ +// CHECK-SAME: <{ [2 x <{ %B, target("dx.Padding", 2) }>], %B }>, target("dx.Padding", 2) +// CHECK-SAME: }>], +// CHECK-SAME: <{ [2 x <{ %B, target("dx.Padding", 2) }>], %B }> }> +// CHECK-SAME: }> + +// CHECK: %__cblayout_CBClasses = type <{ +// CHECK-SAME: %K, target("dx.Padding", 12), +// CHECK-SAME: %L, target("dx.Padding", 8), +// CHECK-SAME: %M, target("dx.Padding", 12), +// CHECK-SAME: <{ [9 x <{ %K, target("dx.Padding", 12) }>], %K }> +// CHECK-SAME: }> -// CHECK: %__cblayout_CBClasses = type <{ target("dx.Layout", %K, 4, 0), target("dx.Layout", %L, 8, 0, 4), -// CHECK-SAME: target("dx.Layout", %M, 68, 0), [10 x target("dx.Layout", %K, 4, 0)] }> // CHECK: %K = type <{ float }> // CHECK: %L = type <{ float, float }> -// CHECK: %M = type <{ [5 x target("dx.Layout", %K, 4, 0)] }> - -// CHECK: %__cblayout_CBMix = type <{ [2 x target("dx.Layout", %Test, 8, 0, 4)], float, [3 x [2 x <2 x float>]], float, -// CHECK-SAME: target("dx.Layout", %anon, 4, 0), double, target("dx.Layout", %anon.0, 8, 0), float, <1 x double>, i16 }> +// CHECK: %M = type <{ <{ [4 x <{ %K, target("dx.Padding", 12) }>], %K }> }> + +// CHECK: %__cblayout_CBMix = type <{ +// CHECK-SAME: <{ [1 x <{ %Test, target("dx.Padding", 8) }>], %Test }>, float, target("dx.Padding", 4) +// CHECK-SAME: <{ [2 x <{ +// CHECK-SAME: <{ [1 x <{ <2 x float>, target("dx.Padding", 8) }>], <2 x float> }>, target("dx.Padding", 8) }>], +// CHECK-SAME: <{ [1 x <{ <2 x float>, target("dx.Padding", 8) }>], <2 x float> }> +// CHECK-SAME: }>, float, target("dx.Padding", 4), +// CHECK-SAME: %anon, target("dx.Padding", 4), double, +// CHECK-SAME: %anon.0, float, target("dx.Padding", 4), +// CHECK-SAME: <1 x double>, i16 +// CHECK-SAME: }> // CHECK: %Test = type <{ float, float }> // CHECK: %anon = type <{ float }> // CHECK: %anon.0 = type <{ <2 x i32> }> -// CHECK: %__cblayout_CB_A = type <{ [2 x double], [3 x <3 x float>], float, [3 x double], half, [1 x <2 x double>], float, [2 x <3 x half>], <3 x half> }> -// CHECK: %__cblayout_CB_B = type <{ [3 x <3 x double>], <3 x half> }> -// CHECK: %__cblayout_CB_C = type <{ i32, target("dx.Layout", %F, 96, 0, 16, 28, 32, 56, 64, 80, 84, 90), half, target("dx.Layout", %G, 258, 0, 48, 64, 256), double }> - -// CHECK: %F = type <{ double, <3 x float>, float, <3 x double>, half, <2 x double>, float, <3 x half>, <3 x half> }> -// CHECK: %G = type <{ target("dx.Layout", %E, 36, 0, 8, 16, 20, 22, 24, 32), [1 x float], [2 x target("dx.Layout", %F, 96, 0, 16, 28, 32, 56, 64, 80, 84, 90)], half }> -// CHECK: %E = type <{ float, double, float, half, i16, i64, i32 }> +// CHECK: %__cblayout_CB_A = type <{ +// CHECK-SAME: <{ [1 x <{ double, target("dx.Padding", 8) }>], double }>, target("dx.Padding", 8), +// CHECK-SAME: <{ [2 x <{ <3 x float>, target("dx.Padding", 4) }>], <3 x float> }>, float, +// CHECK-SAME: <{ [2 x <{ double, target("dx.Padding", 8) }>], double }>, half, target("dx.Padding", 6), +// CHECK-SAME: [1 x <2 x double>], +// CHECK-SAME: float, target("dx.Padding", 12), +// CHECK-SAME: <{ [1 x <{ <3 x half>, target("dx.Padding", 10) }>], <3 x half> }>, <3 x half> +// CHECK-SAME: }> + +// CHECK: %__cblayout_CB_B = type <{ +// CHECK-SAME: <{ [2 x <{ <3 x double>, target("dx.Padding", 8) }>], <3 x double> }>, <3 x half> +// CHECK-SAME: }> + +// CHECK: %__cblayout_CB_C = type <{ +// CHECK-SAME: i32, target("dx.Padding", 12), +// CHECK-SAME: %F, +// CHECK-SAME: half, target("dx.Padding", 14), +// CHECK-SAME: %G, target("dx.Padding", 6), double +// CHECK-SAME: }> + +// CHECK: %F = type <{ +// CHECK-SAME: double, target("dx.Padding", 8), +// CHECK-SAME: <3 x float>, float, +// CHECK-SAME: <3 x double>, half, target("dx.Padding", 6), +// CHECK-SAME: <2 x double>, +// CHECK-SAME: float, <3 x half>, <3 x half> +// CHECK-SAME: }> + +// CHECK: %G = type <{ +// CHECK-SAME: %E, target("dx.Padding", 12), +// CHECK-SAME: [1 x float], target("dx.Padding", 12), +// CHECK-SAME: [2 x %F], +// CHECK-SAME: half +// CHECK-SAME: }> + +// CHECK: %E = type <{ float, target("dx.Padding", 4), double, float, half, i16, i64, i32 }> cbuffer CBScalars : register(b1, space5) { float a1; @@ -44,8 +130,7 @@ cbuffer CBScalars : register(b1, space5) { int64_t a8; } -// CHECK: @CBScalars.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, -// CHECK-SAME: 56, 0, 8, 16, 24, 32, 36, 40, 48)) +// CHECK: @CBScalars.cb = global target("dx.CBuffer", %__cblayout_CBScalars) // CHECK: @a1 = external hidden addrspace(2) global float, align 4 // CHECK: @a2 = external hidden addrspace(2) global double, align 8 // CHECK: @a3 = external hidden addrspace(2) global half, align 2 @@ -67,8 +152,7 @@ cbuffer CBVectors { // FIXME: add a bool vectors after llvm-project/llvm#91639 is added } -// CHECK: @CBVectors.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBVectors, -// CHECK-SAME: 136, 0, 16, 40, 48, 80, 96, 112)) +// CHECK: @CBVectors.cb = global target("dx.CBuffer", %__cblayout_CBVectors) // CHECK: @b1 = external hidden addrspace(2) global <3 x float>, align 16 // CHECK: @b2 = external hidden addrspace(2) global <3 x double>, align 32 // CHECK: @b3 = external hidden addrspace(2) global <2 x half>, align 4 @@ -89,16 +173,15 @@ cbuffer CBArrays : register(b2) { bool c8[4]; } -// CHECK: @CBArrays.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, -// CHECK-SAME: 708, 0, 48, 112, 176, 224, 608, 624, 656)) -// CHECK: @c1 = external hidden addrspace(2) global [3 x float], align 4 -// CHECK: @c2 = external hidden addrspace(2) global [2 x <3 x double>], align 32 -// CHECK: @c3 = external hidden addrspace(2) global [2 x [2 x half]], align 2 -// CHECK: @c4 = external hidden addrspace(2) global [3 x i64], align 8 +// CHECK: @CBArrays.cb = global target("dx.CBuffer", %__cblayout_CBArrays) +// CHECK: @c1 = external hidden addrspace(2) global <{ [2 x <{ float, target("dx.Padding", 12) }>], float }>, align 4 +// CHECK: @c2 = external hidden addrspace(2) global <{ [1 x <{ <3 x double>, target("dx.Padding", 8) }>], <3 x double> }>, align 32 +// CHECK: @c3 = external hidden addrspace(2) global <{ [1 x <{ <{ [1 x <{ half, target("dx.Padding", 14) }>], half }>, target("dx.Padding", 14) }>], <{ [1 x <{ half, target("dx.Padding", 14) }>], half }> }>, align 2 +// CHECK: @c4 = external hidden addrspace(2) global <{ [2 x <{ i64, target("dx.Padding", 8) }>], i64 }>, align 8 // CHECK: @c5 = external hidden addrspace(2) global [2 x [3 x [4 x <4 x i32>]]], align 16 // CHECK: @c6 = external hidden addrspace(2) global [1 x i16], align 2 -// CHECK: @c7 = external hidden addrspace(2) global [2 x i64], align 8 -// CHECK: @c8 = external hidden addrspace(2) global [4 x i32], align 4 +// CHECK: @c7 = external hidden addrspace(2) global <{ [1 x <{ i64, target("dx.Padding", 8) }>], i64 }>, align 8 +// CHECK: @c8 = external hidden addrspace(2) global <{ [3 x <{ i32, target("dx.Padding", 12) }>], i32 }>, align 4 // CHECK: @CBArrays.str = private unnamed_addr constant [9 x i8] c"CBArrays\00", align 1 typedef uint32_t4 uint32_t8[2]; @@ -110,8 +193,7 @@ cbuffer CBTypedefArray : register(space2) { T2 t2[2]; } -// CHECK: @CBTypedefArray.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBTypedefArray, -// CHECK-SAME: 128, 0, 64)) +// CHECK: @CBTypedefArray.cb = global target("dx.CBuffer", %__cblayout_CBTypedefArray) // CHECK: @t1 = external hidden addrspace(2) global [2 x [2 x <4 x i32>]], align 16 // CHECK: @t2 = external hidden addrspace(2) global [2 x [2 x <4 x i32>]], align 16 // CHECK: @CBTypedefArray.str = private unnamed_addr constant [15 x i8] c"CBTypedefArray\00", align 1 @@ -135,13 +217,12 @@ struct D { Empty es; }; -// CHECK: @CBStructs.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBStructs, -// CHECK-SAME: 246, 0, 16, 32, 64, 144, 238, 240)) -// CHECK: @a = external hidden addrspace(2) global target("dx.Layout", %A, 8, 0), align 1 -// CHECK: @b = external hidden addrspace(2) global target("dx.Layout", %B, 14, 0, 8), align 1 -// CHECK: @c = external hidden addrspace(2) global target("dx.Layout", %C, 24, 0, 16), align 1 -// CHECK: @array_of_A = external hidden addrspace(2) global [5 x target("dx.Layout", %A, 8, 0)], align 1 -// CHECK: @d = external hidden addrspace(2) global target("dx.Layout", %__cblayout_D, 94, 0), align 1 +// CHECK: @CBStructs.cb = global target("dx.CBuffer", %__cblayout_CBStructs) +// CHECK: @a = external hidden addrspace(2) global %A, align 1 +// CHECK: @b = external hidden addrspace(2) global %B, align 1 +// CHECK: @c = external hidden addrspace(2) global %C, align 1 +// CHECK: @array_of_A = external hidden addrspace(2) global <{ [4 x <{ %A, target("dx.Padding", 8) }>], %A }>, align 1 +// CHECK: @d = external hidden addrspace(2) global %__cblayout_D, align 1 // CHECK: @e = external hidden addrspace(2) global half, align 2 // CHECK: @f = external hidden addrspace(2) global <3 x i16>, align 8 // CHECK: @CBStructs.str = private unnamed_addr constant [10 x i8] c"CBStructs\00", align 1 @@ -176,27 +257,25 @@ cbuffer CBClasses { K ka[10]; }; -// CHECK: @CBClasses.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBClasses, -// CHECK-SAME: 260, 0, 16, 32, 112)) -// CHECK: @k = external hidden addrspace(2) global target("dx.Layout", %K, 4, 0), align 1 -// CHECK: @l = external hidden addrspace(2) global target("dx.Layout", %L, 8, 0, 4), align 1 -// CHECK: @m = external hidden addrspace(2) global target("dx.Layout", %M, 68, 0), align 1 -// CHECK: @ka = external hidden addrspace(2) global [10 x target("dx.Layout", %K, 4, 0)], align 1 +// CHECK: @CBClasses.cb = global target("dx.CBuffer", %__cblayout_CBClasses) +// CHECK: @k = external hidden addrspace(2) global %K, align 1 +// CHECK: @l = external hidden addrspace(2) global %L, align 1 +// CHECK: @m = external hidden addrspace(2) global %M, align 1 +// CHECK: @ka = external hidden addrspace(2) global <{ [9 x <{ %K, target("dx.Padding", 12) }>], %K }>, align 1 // CHECK: @CBClasses.str = private unnamed_addr constant [10 x i8] c"CBClasses\00", align 1 struct Test { float a, b; }; -// CHECK: @CBMix.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBMix, -// CHECK-SAME: 170, 0, 24, 32, 120, 128, 136, 144, 152, 160, 168)) -// CHECK: @test = external hidden addrspace(2) global [2 x target("dx.Layout", %Test, 8, 0, 4)], align 1 +// CHECK: @CBMix.cb = global target("dx.CBuffer", %__cblayout_CBMix) +// CHECK: @test = external hidden addrspace(2) global <{ [1 x <{ %Test, target("dx.Padding", 8) }>], %Test }>, align 1 // CHECK: @f1 = external hidden addrspace(2) global float, align 4 -// CHECK: @f2 = external hidden addrspace(2) global [3 x [2 x <2 x float>]], align 8 +// CHECK: @f2 = external hidden addrspace(2) global <{ [2 x <{ <{ [1 x <{ <2 x float>, target("dx.Padding", 8) }>], <2 x float> }>, target("dx.Padding", 8) }>], <{ [1 x <{ <2 x float>, target("dx.Padding", 8) }>], <2 x float> }> }>, align 8 // CHECK: @f3 = external hidden addrspace(2) global float, align 4 -// CHECK: @f4 = external hidden addrspace(2) global target("dx.Layout", %anon, 4, 0), align 1 +// CHECK: @f4 = external hidden addrspace(2) global %anon, align 1 // CHECK: @f5 = external hidden addrspace(2) global double, align 8 -// CHECK: @f6 = external hidden addrspace(2) global target("dx.Layout", %anon.0, 8, 0), align 1 +// CHECK: @f6 = external hidden addrspace(2) global %anon.0, align 1 // CHECK: @f7 = external hidden addrspace(2) global float, align 4 // CHECK: @f8 = external hidden addrspace(2) global <1 x double>, align 8 // CHECK: @f9 = external hidden addrspace(2) global i16, align 2 @@ -215,7 +294,7 @@ cbuffer CBMix { uint16_t f9; }; -// CHECK: @CB_A.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_A, 188, 0, 32, 76, 80, 120, 128, 144, 160, 182)) +// CHECK: @CB_A.cb = global target("dx.CBuffer", %__cblayout_CB_A) cbuffer CB_A { double B0[2]; @@ -229,7 +308,7 @@ cbuffer CB_A { half3 B8; } -// CHECK: @CB_B.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_B, 94, 0, 88)) +// CHECK: @CB_B.cb = global target("dx.CBuffer", %__cblayout_CB_B) cbuffer CB_B { double3 B9[3]; half3 B10; @@ -264,7 +343,7 @@ struct G { half C3; }; -// CHECK: @CB_C.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_C, 400, 0, 16, 112, 128, 392)) +// CHECK: @CB_C.cb = global target("dx.CBuffer", %__cblayout_CB_C) cbuffer CB_C { int D0; F D1; @@ -275,63 +354,63 @@ cbuffer CB_C { // CHECK: define internal void @_init_buffer_CBScalars.cb() // CHECK-NEXT: entry: -// CHECK-NEXT: %CBScalars.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48)) -// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBScalarss_56_0_8_16_24_32_36_40_48tt(i32 5, i32 1, i32 1, i32 0, ptr @CBScalars.str) -// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48)) %CBScalars.cb_h, ptr @CBScalars.cb, align 4 +// CHECK-NEXT: %CBScalars.cb_h = call target("dx.CBuffer", %__cblayout_CBScalars) +// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s___cblayout_CBScalarsst(i32 5, i32 1, i32 1, i32 0, ptr @CBScalars.str) +// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBScalars) %CBScalars.cb_h, ptr @CBScalars.cb, align 4 // CHECK: define internal void @_init_buffer_CBVectors.cb() // CHECK-NEXT: entry: -// CHECK-NEXT: %CBVectors.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBVectors, 136, 0, 16, 40, 48, 80, 96, 112)) -// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBVectorss_136_0_16_40_48_80_96_112tt(i32 0, i32 0, i32 1, i32 0, ptr @CBVectors.str) -// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBVectors, 136, 0, 16, 40, 48, 80, 96, 112)) %CBVectors.cb_h, ptr @CBVectors.cb, align 4 +// CHECK-NEXT: %CBVectors.cb_h = call target("dx.CBuffer", %__cblayout_CBVectors) +// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CBVectorsst(i32 0, i32 0, i32 1, i32 0, ptr @CBVectors.str) +// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBVectors) %CBVectors.cb_h, ptr @CBVectors.cb, align 4 // CHECK: define internal void @_init_buffer_CBArrays.cb() // CHECK-NEXT: entry: -// CHECK-NEXT: %CBArrays.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656)) -// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBArrayss_708_0_48_112_176_224_608_624_656tt(i32 0, i32 2, i32 1, i32 0, ptr @CBArrays.str) -// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656)) %CBArrays.cb_h, ptr @CBArrays.cb, align 4 +// CHECK-NEXT: %CBArrays.cb_h = call target("dx.CBuffer", %__cblayout_CBArrays) +// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s___cblayout_CBArraysst(i32 0, i32 2, i32 1, i32 0, ptr @CBArrays.str) +// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBArrays) %CBArrays.cb_h, ptr @CBArrays.cb, align 4 // CHECK: define internal void @_init_buffer_CBTypedefArray.cb() // CHECK-NEXT: entry: -// CHECK-NEXT: %CBTypedefArray.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBTypedefArray, 128, 0, 64)) -// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBTypedefArrays_128_0_64tt(i32 1, i32 2, i32 1, i32 0, ptr @CBTypedefArray.str) -// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBTypedefArray, 128, 0, 64)) %CBTypedefArray.cb_h, ptr @CBTypedefArray.cb, align 4 +// CHECK-NEXT: %CBTypedefArray.cb_h = call target("dx.CBuffer", %__cblayout_CBTypedefArray) +// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CBTypedefArrayst(i32 1, i32 2, i32 1, i32 0, ptr @CBTypedefArray.str) +// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBTypedefArray) %CBTypedefArray.cb_h, ptr @CBTypedefArray.cb, align 4 // CHECK: define internal void @_init_buffer_CBStructs.cb() // CHECK-NEXT: entry: -// CHECK-NEXT: %CBStructs.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBStructs, 246, 0, 16, 32, 64, 144, 238, 240)) -// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBStructss_246_0_16_32_64_144_238_240tt(i32 2, i32 0, i32 1, i32 0, ptr @CBStructs.str) -// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBStructs, 246, 0, 16, 32, 64, 144, 238, 240)) %CBStructs.cb_h, ptr @CBStructs.cb, align 4 +// CHECK-NEXT: %CBStructs.cb_h = call target("dx.CBuffer", %__cblayout_CBStructs) +// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CBStructsst(i32 2, i32 0, i32 1, i32 0, ptr @CBStructs.str) +// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBStructs) %CBStructs.cb_h, ptr @CBStructs.cb, align 4 // CHECK: define internal void @_init_buffer_CBClasses.cb() // CHECK-NEXT: entry: -// CHECK-NEXT: %CBClasses.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBClasses, 260, 0, 16, 32, 112)) -// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBClassess_260_0_16_32_112tt(i32 3, i32 0, i32 1, i32 0, ptr @CBClasses.str) -// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBClasses, 260, 0, 16, 32, 112)) %CBClasses.cb_h, ptr @CBClasses.cb, align 4 +// CHECK-NEXT: %CBClasses.cb_h = call target("dx.CBuffer", %__cblayout_CBClasses) +// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CBClassesst(i32 3, i32 0, i32 1, i32 0, ptr @CBClasses.str) +// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBClasses) %CBClasses.cb_h, ptr @CBClasses.cb, align 4 // CHECK: define internal void @_init_buffer_CBMix.cb() // CHECK-NEXT: entry: -// CHECK-NEXT: %CBMix.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBMix, 170, 0, 24, 32, 120, 128, 136, 144, 152, 160, 168)) -// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBMixs_170_0_24_32_120_128_136_144_152_160_168tt(i32 4, i32 0, i32 1, i32 0, ptr @CBMix.str) -// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBMix, 170, 0, 24, 32, 120, 128, 136, 144, 152, 160, 168)) %CBMix.cb_h, ptr @CBMix.cb, align 4 +// CHECK-NEXT: %CBMix.cb_h = call target("dx.CBuffer", %__cblayout_CBMix) +// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CBMixst(i32 4, i32 0, i32 1, i32 0, ptr @CBMix.str) +// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBMix) %CBMix.cb_h, ptr @CBMix.cb, align 4 // CHECK: define internal void @_init_buffer_CB_A.cb() // CHECK-NEXT: entry: -// CHECK-NEXT: %CB_A.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_A, 188, 0, 32, 76, 80, 120, 128, 144, 160, 182)) -// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CB_As_188_0_32_76_80_120_128_144_160_182tt(i32 5, i32 0, i32 1, i32 0, ptr @CB_A.str) -// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_A, 188, 0, 32, 76, 80, 120, 128, 144, 160, 182)) %CB_A.cb_h, ptr @CB_A.cb, align 4 +// CHECK-NEXT: %CB_A.cb_h = call target("dx.CBuffer", %__cblayout_CB_A) +// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CB_Ast(i32 5, i32 0, i32 1, i32 0, ptr @CB_A.str) +// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CB_A) %CB_A.cb_h, ptr @CB_A.cb, align 4 // CHECK: define internal void @_init_buffer_CB_B.cb() // CHECK-NEXT: entry: -// CHECK-NEXT: %CB_B.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_B, 94, 0, 88)) -// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CB_Bs_94_0_88tt(i32 6, i32 0, i32 1, i32 0, ptr @CB_B.str) -// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_B, 94, 0, 88)) %CB_B.cb_h, ptr @CB_B.cb, align 4 +// CHECK-NEXT: %CB_B.cb_h = call target("dx.CBuffer", %__cblayout_CB_B) +// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CB_Bst(i32 6, i32 0, i32 1, i32 0, ptr @CB_B.str) +// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CB_B) %CB_B.cb_h, ptr @CB_B.cb, align 4 // CHECK: define internal void @_init_buffer_CB_C.cb() // CHECK-NEXT: entry: -// CHECK-NEXT: %CB_C.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_C, 400, 0, 16, 112, 128, 392)) -// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CB_Cs_400_0_16_112_128_392tt(i32 7, i32 0, i32 1, i32 0, ptr @CB_C.str) -// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_C, 400, 0, 16, 112, 128, 392)) %CB_C.cb_h, ptr @CB_C.cb, align 4 +// CHECK-NEXT: %CB_C.cb_h = call target("dx.CBuffer", %__cblayout_CB_C) +// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CB_Cst(i32 7, i32 0, i32 1, i32 0, ptr @CB_C.str) +// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CB_C) %CB_C.cb_h, ptr @CB_C.cb, align 4 RWBuffer Buf; diff --git a/clang/test/CodeGenHLSL/resources/cbuffer_and_namespaces.hlsl b/clang/test/CodeGenHLSL/resources/cbuffer_and_namespaces.hlsl index b7bdce32e6507..1fe0a68261c94 100644 --- a/clang/test/CodeGenHLSL/resources/cbuffer_and_namespaces.hlsl +++ b/clang/test/CodeGenHLSL/resources/cbuffer_and_namespaces.hlsl @@ -4,18 +4,18 @@ // CHECK: %"n0::n1::__cblayout_A" = type <{ float }> // CHECK: %"n0::__cblayout_B" = type <{ float }> -// CHECK: %"n0::n2::__cblayout_C" = type <{ float, target("dx.Layout", %"n0::Foo", 4, 0) }> +// CHECK: %"n0::n2::__cblayout_C" = type <{ float, target("dx.Padding", 12), %"n0::Foo" }> // CHECK: %"n0::Foo" = type <{ float }> -// CHECK: @A.cb = global target("dx.CBuffer", target("dx.Layout", %"n0::n1::__cblayout_A", 4, 0)) +// CHECK: @A.cb = global target("dx.CBuffer", %"n0::n1::__cblayout_A") // CHECK: @_ZN2n02n11aE = external hidden addrspace(2) global float, align 4 -// CHECK: @B.cb = global target("dx.CBuffer", target("dx.Layout", %"n0::__cblayout_B", 4, 0)) +// CHECK: @B.cb = global target("dx.CBuffer", %"n0::__cblayout_B") // CHECK: @_ZN2n01aE = external hidden addrspace(2) global float, align 4 -// CHECK: @C.cb = global target("dx.CBuffer", target("dx.Layout", %"n0::n2::__cblayout_C", 20, 0, 16)) +// CHECK: @C.cb = global target("dx.CBuffer", %"n0::n2::__cblayout_C") // CHECK: @_ZN2n02n21aE = external hidden addrspace(2) global float, align 4 -// CHECK: external hidden addrspace(2) global target("dx.Layout", %"n0::Foo", 4, 0), align 1 +// CHECK: external hidden addrspace(2) global %"n0::Foo", align 1 namespace n0 { struct Foo { diff --git a/clang/test/CodeGenHLSL/resources/cbuffer_geps.hlsl b/clang/test/CodeGenHLSL/resources/cbuffer_geps.hlsl new file mode 100644 index 0000000000000..7a0b45875faf9 --- /dev/null +++ b/clang/test/CodeGenHLSL/resources/cbuffer_geps.hlsl @@ -0,0 +1,117 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute -fnative-half-type -fnative-int16-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s + +// Capture the anonymous struct types for check lines below. +// CHECK: [[ANON_1:%.*]] = type <{ float, target("dx.Padding", 12), <4 x i32> }> +// CHECK: [[ANON_2:%.*]] = type <{ <2 x i32>, target("dx.Padding", 8), <{ [3 x <{ %ArrayAndScalar, target("dx.Padding", 12) }>], %ArrayAndScalar }> + +template void use(T); + +cbuffer CBArrays : register(b2) { + float c1[30]; + double3 c2[20]; + float16_t c3[10][20]; + uint64_t c4[30]; + int4 c5[20][30][40]; + uint16_t c6[10]; + int64_t c7[20]; + bool c8[40]; +} + +// CHECK-LABEL: define hidden void @_Z8cbarraysv() +void cbarrays() { + // CHECK: load float, ptr addrspace(2) @c1, align 16 + use(c1[0]); + // CHECK: load float, ptr addrspace(2) getelementptr (<{ float, target("dx.Padding", 12) }>, ptr addrspace(2) @c1, i32 7, i32 0), align 16 + use(c1[7]); + // CHECK: load float, ptr addrspace(2) getelementptr (<{ float, target("dx.Padding", 12) }>, ptr addrspace(2) @c1, i32 29, i32 0), align 16 + use(c1[29]); + + // CHECK: load <3 x double>, ptr addrspace(2) getelementptr (<{ <3 x double>, target("dx.Padding", 8) }>, ptr addrspace(2) @c2, i32 8, i32 0), align 32 + use(c2[8]); + // CHECK: load half, ptr addrspace(2) getelementptr (<{ half, target("dx.Padding", 14) }>, ptr addrspace(2) getelementptr (<{ <{ [19 x <{ half, target("dx.Padding", 14) }>], half }>, target("dx.Padding", 14) }>, ptr addrspace(2) @c3, i32 9, i32 0), i32 5, i32 0), align 16 + use(c3[9][5]); + // CHECK: load i64, ptr addrspace(2) getelementptr (<{ i64, target("dx.Padding", 8) }>, ptr addrspace(2) @c4, i32 6, i32 0), align 16 + use(c4[6]); + // CHECK: load <4 x i32>, ptr addrspace(2) getelementptr inbounds ([40 x <4 x i32>], ptr addrspace(2) getelementptr inbounds ([30 x [40 x <4 x i32>]], ptr addrspace(2) getelementptr inbounds ([20 x [30 x [40 x <4 x i32>]]], ptr addrspace(2) @c5, i32 0, i32 1), i32 0, i32 12), i32 0, i32 15), align 16 + use(c5[1][12][15]); + // CHECK: load i16, ptr addrspace(2) getelementptr (<{ i16, target("dx.Padding", 14) }>, ptr addrspace(2) @c6, i32 4, i32 0), align 16 + use(c6[4]); + // CHECK: load i64, ptr addrspace(2) getelementptr (<{ i64, target("dx.Padding", 8) }>, ptr addrspace(2) @c7, i32 17, i32 0), align 16 + use(c7[17]); + // CHECK: load i32, ptr addrspace(2) getelementptr (<{ i32, target("dx.Padding", 12) }>, ptr addrspace(2) @c8, i32 30, i32 0), align 16 + use(c8[30]); +} + +struct A { + float2 a1; +}; + +struct B : A { + uint16_t3 b1; +}; + +struct C { + int c1; + A c2; +}; + +struct D { + B d1[4][6]; +}; + +cbuffer CBStructs { + A s1; + B s2; + C s3; + A s4[5]; + D s5; +}; + +// CHECK-LABEL: define hidden void @_Z9cbstructsv() +void cbstructs() { + // CHECK: load <2 x float>, ptr addrspace(2) @s1, align 8 + use(s1.a1); + // CHECK: load <3 x i16>, ptr addrspace(2) getelementptr inbounds nuw (%B, ptr addrspace(2) @s2, i32 0, i32 1), align 2 + use(s2.b1); + // CHECK: load <2 x float>, ptr addrspace(2) getelementptr inbounds nuw (%C, ptr addrspace(2) @s3, i32 0, i32 1), align 8 + use(s3.c2.a1); + // CHECK: load <2 x float>, ptr addrspace(2) getelementptr (<{ %A, target("dx.Padding", 8) }>, ptr addrspace(2) @s4, i32 2, i32 0), align 8 + use(s4[2].a1); + // CHECK: load <3 x i16>, ptr addrspace(2) getelementptr inbounds nuw (%B, ptr addrspace(2) getelementptr (<{ %B, target("dx.Padding", 2) }>, ptr addrspace(2) getelementptr (<{ <{ [5 x <{ %B, target("dx.Padding", 2) }>], %B }>, target("dx.Padding", 2) }>, ptr addrspace(2) @s5, i32 3, i32 0), i32 5, i32 0), i32 0, i32 1), align 2 + use(s5.d1[3][5].b1); +} + +struct Scalars { + float a, b; +}; + +struct ArrayAndScalar { + uint4 x[5]; + float y; +}; + +cbuffer CBMix { + Scalars m1[3]; + float m2; + ArrayAndScalar m3; + float2 m4[5][4]; + struct { float c; uint4 d; } m5; + struct { int2 i; ArrayAndScalar j[4]; } m6; + vector m7; +}; + +// CHECK-LABEL: define hidden void @_Z5cbmixv() +void cbmix() { + // CHECK: load float, ptr addrspace(2) getelementptr inbounds nuw (%Scalars, ptr addrspace(2) getelementptr (<{ %Scalars, target("dx.Padding", 8) }>, ptr addrspace(2) @m1, i32 2, i32 0), i32 0, i32 1), align 4 + use(m1[2].b); + // CHECK: load float, ptr addrspace(2) getelementptr inbounds nuw (%ArrayAndScalar, ptr addrspace(2) @m3, i32 0, i32 1), align 4 + use(m3.y); + // CHECK: load <2 x float>, ptr addrspace(2) getelementptr (<{ <2 x float>, target("dx.Padding", 8) }>, ptr addrspace(2) getelementptr (<{ <{ [3 x <{ <2 x float>, target("dx.Padding", 8) }>], <2 x float> }>, target("dx.Padding", 8) }>, ptr addrspace(2) @m4, i32 2, i32 0), i32 3, i32 0), align 16 + use(m4[2][3]); + // CHECK: load <4 x i32>, ptr addrspace(2) getelementptr inbounds nuw ([[ANON_1]], ptr addrspace(2) @m5, i32 0, i32 1), align 16 + use(m5.d); + // CHECK: load <4 x i32>, ptr addrspace(2) getelementptr inbounds ([5 x <4 x i32>], ptr addrspace(2) getelementptr (<{ %ArrayAndScalar, target("dx.Padding", 12) }>, ptr addrspace(2) getelementptr inbounds nuw ([[ANON_2]], ptr addrspace(2) @m6, i32 0, i32 1), i32 2, i32 0), i32 0, i32 2), align 16 + use(m6.j[2].x[2]); + // CHECK: load <1 x double>, ptr addrspace(2) @m7, align 8 + use(m7); +} diff --git a/clang/test/CodeGenHLSL/resources/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/resources/cbuffer_with_packoffset.hlsl index 7bedd63c9f65d..68e263b9fc07f 100644 --- a/clang/test/CodeGenHLSL/resources/cbuffer_with_packoffset.hlsl +++ b/clang/test/CodeGenHLSL/resources/cbuffer_with_packoffset.hlsl @@ -2,13 +2,24 @@ // RUN: dxil-pc-shadermodel6.3-compute %s \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s -// CHECK: %__cblayout_CB = type <{ float, double, <2 x i32> }> -// CHECK: %__cblayout_CB_1 = type <{ float, <2 x float> }> - -// CHECK: @CB.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 176, 16, 168, 88)) -// CHECK: @a = external hidden addrspace(2) global float, align 4 -// CHECK: @b = external hidden addrspace(2) global double, align 8 -// CHECK: @c = external hidden addrspace(2) global <2 x i32>, align 8 +// CHECK: %__cblayout_CB = type <{ +// CHECK-SAME: target("dx.Padding", 16), +// CHECK-SAME: float, +// CHECK-SAME: target("dx.Padding", 68), +// CHECK-SAME: <2 x i32>, +// CHECK-SAME target("dx.Padding", 72), +// CHECK-SAME: double +// CHECK-SAME: }> +// CHECK: %__cblayout_CB_1 = type <{ +// CHECK-SAME: target("dx.Padding", 80), +// CHECK-SAME: <2 x float>, +// CHECK-SAME: float +// CHECK-SAME: }> + +// CHECK-DAG: @CB.cb = global target("dx.CBuffer", %__cblayout_CB) +// CHECK-DAG: @a = external hidden addrspace(2) global float, align 4 +// CHECK-DAG: @b = external hidden addrspace(2) global double, align 8 +// CHECK-DAG: @c = external hidden addrspace(2) global <2 x i32>, align 8 // CHECK: @CB.str = private unnamed_addr constant [3 x i8] c"CB\00", align 1 cbuffer CB : register(b1, space3) { @@ -17,9 +28,9 @@ cbuffer CB : register(b1, space3) { int2 c : packoffset(c5.z); } -// CHECK: @CB.cb.1 = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_1, 92, 88, 80)) -// CHECK: @x = external hidden addrspace(2) global float, align 4 -// CHECK: @y = external hidden addrspace(2) global <2 x float>, align 8 +// CHECK-DAG: @CB.cb.1 = global target("dx.CBuffer", %__cblayout_CB_1) +// CHECK-DAG: @x = external hidden addrspace(2) global float, align 4 +// CHECK-DAG: @y = external hidden addrspace(2) global <2 x float>, align 8 // Missing packoffset annotation will produce a warning. // Element x will be placed after the element y that has an explicit packoffset. @@ -30,8 +41,7 @@ cbuffer CB : register(b0) { // CHECK: define internal void @_init_buffer_CB.cb() // CHECK-NEXT: entry: -// CHECK-NEXT: %CB.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 176, 16, 168, 88)) -// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBs_176_16_168_88tt(i32 3, i32 1, i32 1, i32 0, ptr @CB.str) +// CHECK-NEXT: %CB.cb_h = call target("dx.CBuffer", %__cblayout_CB) @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s___cblayout_CBst(i32 3, i32 1, i32 1, i32 0, ptr @CB.str) float foo() { // CHECK: load float, ptr addrspace(2) @a, align 4 @@ -48,5 +58,5 @@ void main() { } // CHECK: !hlsl.cbs = !{![[CB1:[0-9]+]], ![[CB2:[0-9]+]]} -// CHECK: ![[CB1]] = !{ptr @CB.cb, ptr addrspace(2) @a, ptr addrspace(2) @b, ptr addrspace(2) @c} -// CHECK: ![[CB2]] = !{ptr @CB.cb.1, ptr addrspace(2) @x, ptr addrspace(2) @y} +// CHECK: ![[CB1]] = !{ptr @CB.cb, ptr addrspace(2) @a, ptr addrspace(2) @c, ptr addrspace(2) @b} +// CHECK: ![[CB2]] = !{ptr @CB.cb.1, ptr addrspace(2) @y, ptr addrspace(2) @x} diff --git a/clang/test/CodeGenHLSL/resources/cbuffer_with_static_global_and_function.hlsl b/clang/test/CodeGenHLSL/resources/cbuffer_with_static_global_and_function.hlsl index fa3405df9e3d3..b8c7babb8d634 100644 --- a/clang/test/CodeGenHLSL/resources/cbuffer_with_static_global_and_function.hlsl +++ b/clang/test/CodeGenHLSL/resources/cbuffer_with_static_global_and_function.hlsl @@ -2,7 +2,7 @@ // CHECK: %__cblayout_A = type <{ float }> -// CHECK: @A.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_A, 4, 0)) +// CHECK: @A.cb = global target("dx.CBuffer", %__cblayout_A) // CHECK: @a = external hidden addrspace(2) global float, align 4 // CHECK-DAG: @_ZL1b = internal global float 3.000000e+00, align 4 // CHECK-NOT: @B.cb diff --git a/clang/test/CodeGenHLSL/resources/default_cbuffer.hlsl b/clang/test/CodeGenHLSL/resources/default_cbuffer.hlsl index ad4d92f8afc02..5333dad962195 100644 --- a/clang/test/CodeGenHLSL/resources/default_cbuffer.hlsl +++ b/clang/test/CodeGenHLSL/resources/default_cbuffer.hlsl @@ -1,19 +1,18 @@ // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,DXIL // RUN: %clang_cc1 -finclude-default-header -triple spirv-pc-vulkan1.3-compute -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,SPIRV -// DXIL: %"__cblayout_$Globals" = type <{ float, float, target("dx.Layout", %__cblayout_S, 4, 0) }> -// SPIRV: %"__cblayout_$Globals" = type <{ float, float, target("spirv.Layout", %__cblayout_S, 4, 0) }> +// CHECK: %"__cblayout_$Globals" = type <{ float, float, target("{{.*}}.Padding", 8), %__cblayout_S }> // CHECK: %__cblayout_S = type <{ float }> -// DXIL-DAG: @"$Globals.cb" = global target("dx.CBuffer", target("dx.Layout", %"__cblayout_$Globals", 20, 0, 4, 16)) +// DXIL-DAG: @"$Globals.cb" = global target("dx.CBuffer", %"__cblayout_$Globals") // DXIL-DAG: @a = external hidden addrspace(2) global float // DXIL-DAG: @g = external hidden addrspace(2) global float -// DXIL-DAG: @h = external hidden addrspace(2) global target("dx.Layout", %__cblayout_S, 4, 0), align 4 +// DXIL-DAG: @h = external hidden addrspace(2) global %__cblayout_S, align 4 -// SPIRV-DAG: @"$Globals.cb" = global target("spirv.VulkanBuffer", target("spirv.Layout", %"__cblayout_$Globals", 20, 0, 4, 16), 2, 0) +// SPIRV-DAG: @"$Globals.cb" = global target("spirv.VulkanBuffer", %"__cblayout_$Globals", 2, 0) // SPIRV-DAG: @a = external hidden addrspace(12) global float // SPIRV-DAG: @g = external hidden addrspace(12) global float -// SPIRV-DAG: @h = external hidden addrspace(12) global target("spirv.Layout", %__cblayout_S, 4, 0), align 8 +// SPIRV-DAG: @h = external hidden addrspace(12) global %__cblayout_S, align 8 struct EmptyStruct { }; diff --git a/clang/test/CodeGenHLSL/resources/default_cbuffer_with_layout.hlsl b/clang/test/CodeGenHLSL/resources/default_cbuffer_with_layout.hlsl index 1b2cb0e99aa83..7be1f9043042c 100644 --- a/clang/test/CodeGenHLSL/resources/default_cbuffer_with_layout.hlsl +++ b/clang/test/CodeGenHLSL/resources/default_cbuffer_with_layout.hlsl @@ -1,17 +1,26 @@ // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -// CHECK: %"__cblayout_$Globals" = type <{ i32, float, [4 x double], <4 x i32>, <4 x float>, -// CHECK-SAME: target("dx.Layout", %S, 8, 0) }> +// CHECK: %"__cblayout_$Globals" = type <{ +// CHECK-SAME: float, +// CHECK-SAME: target("dx.Padding", 12), +// CHECK-SAME: <{ [3 x <{ double, target("dx.Padding", 8) }>], double }>, +// CHECK-SAME: target("dx.Padding", 8), +// CHECK-SAME: <4 x i32>, +// CHECK-SAME: %S +// CHECK-SAME: i32, +// CHECK-SAME: target("dx.Padding", 4), +// CHECK-SAME: <4 x float> +// CHECK-SAME: }> + // CHECK: %S = type <{ <2 x float> }> +// CHECK-DAG: @"$Globals.cb" = global target("dx.CBuffer", %"__cblayout_$Globals") +// CHECK-DAG: @a = external hidden addrspace(2) global i32, align 4 // CHECK-DAG: @b = external hidden addrspace(2) global float, align 4 +// CHECK-DAG: @c = external hidden addrspace(2) global <{ [3 x <{ double, target("dx.Padding", 8) }>], double }>, align 8 // CHECK-DAG: @d = external hidden addrspace(2) global <4 x i32>, align 16 -// CHECK-DAG: @"$Globals.cb" = global target("dx.CBuffer", -// CHECK-DAG-SAME: target("dx.Layout", %"__cblayout_$Globals", 144, 120, 16, 32, 64, 128, 112)) -// CHECK-DAG: @a = external hidden addrspace(2) global i32, align 4 -// CHECK-DAG: @c = external hidden addrspace(2) global [4 x double], align 8 // CHECK-DAG: @e = external hidden addrspace(2) global <4 x float>, align 16 -// CHECK-DAG: @s = external hidden addrspace(2) global target("dx.Layout", %S, 8, 0), align 1 +// CHECK-DAG: @s = external hidden addrspace(2) global %S, align 1 struct S { float2 v; @@ -19,8 +28,8 @@ struct S { int a; float b : register(c1); +int4 d : register(c6); double c[4] : register(c2); -int4 d : register(c4); float4 e; S s : register(c7); @@ -32,5 +41,4 @@ void main() { } // CHECK: !hlsl.cbs = !{![[CB:.*]]} -// CHECK: ![[CB]] = !{ptr @"$Globals.cb", ptr addrspace(2) @a, ptr addrspace(2) @b, ptr addrspace(2) @c, -// CHECK-SAME: ptr addrspace(2) @d, ptr addrspace(2) @e, ptr addrspace(2) @s} +// CHECK: ![[CB]] = !{ptr @"$Globals.cb", ptr addrspace(2) @b, ptr addrspace(2) @c, ptr addrspace(2) @d, ptr addrspace(2) @s, ptr addrspace(2) @a, ptr addrspace(2) @e} diff --git a/clang/test/Driver/fsanitize-alloc-token.c b/clang/test/Driver/fsanitize-alloc-token.c index 6d8bda16dfb96..0ffe9abad8053 100644 --- a/clang/test/Driver/fsanitize-alloc-token.c +++ b/clang/test/Driver/fsanitize-alloc-token.c @@ -5,6 +5,7 @@ // CHECK-NO-TOKEN-ALLOC-NOT: "-fsanitize=alloc-token" // RUN: %clang --target=x86_64-linux-gnu -flto -fvisibility=hidden -fno-sanitize-ignorelist -fsanitize=alloc-token,undefined,cfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-COMPATIBLE +// RUN: %clang --target=aarch64-linux-android -march=armv8-a+memtag -flto -fvisibility=hidden -fsanitize=alloc-token,kcfi,memtag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-COMPATIBLE // CHECK-COMPATIBLE: "-fsanitize={{.*}}alloc-token" // RUN: %clang --target=x86_64-linux-gnu -fsanitize=alloc-token -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MINIMAL diff --git a/compiler-rt/test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cpp b/compiler-rt/test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cpp index 664471b6987a8..4201d49df4d74 100644 --- a/compiler-rt/test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cpp +++ b/compiler-rt/test/asan/TestCases/Darwin/atos-symbolizer-dyld-root-path.cpp @@ -1,6 +1,7 @@ // Check that when having a DYLD_ROOT_PATH set, the symbolizer still works. // RUN: %clangxx_asan -O0 %s -o %t -// RUN: %env_asan_opts=verbosity=2 DYLD_ROOT_PATH="/" ASAN_SYMBOLIZER_PATH=$(which atos) \ +// RUN: which atos | tr -d '\n' > %t.symbolizer_path +// RUN: %env_asan_opts=verbosity=2 DYLD_ROOT_PATH="/" ASAN_SYMBOLIZER_PATH=%{readfile:%t.symbolizer_path} \ // RUN: not %run %t 2>&1 | FileCheck %s // // Due to a bug in atos, this only works on x86_64. diff --git a/compiler-rt/test/asan/TestCases/Darwin/atos-symbolizer.cpp b/compiler-rt/test/asan/TestCases/Darwin/atos-symbolizer.cpp index bab4e4f3765c2..7487bd4cb40e6 100644 --- a/compiler-rt/test/asan/TestCases/Darwin/atos-symbolizer.cpp +++ b/compiler-rt/test/asan/TestCases/Darwin/atos-symbolizer.cpp @@ -1,7 +1,8 @@ // Check that the `atos` symbolizer works. // RUN: %clangxx_asan -O0 %s -o %t -// RUN: %env_asan_opts=verbosity=2 ASAN_SYMBOLIZER_PATH=$(which atos) not %run %t 2>&1 | FileCheck %s +// RUN: which atos | tr -d '\n' > %t.symbolizer_path +// RUN: %env_asan_opts=verbosity=2 ASAN_SYMBOLIZER_PATH=%{readfile:%t.symbolizer_path} not %run %t 2>&1 | FileCheck %s // Path returned by `which atos` is invalid on iOS. // UNSUPPORTED: ios, i386-darwin diff --git a/compiler-rt/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cpp b/compiler-rt/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cpp index 0fec18b89411a..145e162a21c0e 100644 --- a/compiler-rt/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cpp +++ b/compiler-rt/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cpp @@ -4,7 +4,8 @@ // UNSUPPORTED: ios // RUN: rm -rf %t && mkdir -p %t -// RUN: cp `%clang_asan -print-file-name=lib`/darwin/libclang_rt.asan_osx_dynamic.dylib \ +// RUN: %clang_asan -print-file-name=lib | tr -d '\n' > %t.lib_name +// RUN: cp %{readfile:%t.lib_name}/darwin/libclang_rt.asan_osx_dynamic.dylib \ // RUN: %t/libclang_rt.asan_osx_dynamic.dylib // RUN: %clangxx_asan %s -o %t/a.out diff --git a/compiler-rt/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cpp b/compiler-rt/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cpp index 0672e064a1904..872848d075eaf 100644 --- a/compiler-rt/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cpp +++ b/compiler-rt/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cpp @@ -5,29 +5,27 @@ // UNSUPPORTED: ios // RUN: rm -rf %t && mkdir -p %t -// RUN: cp `%clang_asan -print-file-name=lib`/darwin/libclang_rt.asan_osx_dynamic.dylib \ +// RUN: %clang_asan -print-file-name=lib | tr -d '\n' > %t.lib_name +// RUN: cp %{readfile:%t.lib_name}/darwin/libclang_rt.asan_osx_dynamic.dylib \ // RUN: %t/libclang_rt.asan_osx_dynamic.dylib // RUN: %clangxx_asan %s -o %t/a.out // RUN: %clangxx -DSHARED_LIB %s \ // RUN: -dynamiclib -o %t/dummy-so.dylib -// RUN: ( cd %t && \ -// RUN: DYLD_INSERT_LIBRARIES=@executable_path/libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ -// RUN: %run ./a.out 2>&1 ) | FileCheck %s || exit 1 +// RUN: cd %t +// RUN: env DYLD_INSERT_LIBRARIES=@executable_path/libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ +// RUN: %run ./a.out 2>&1 | FileCheck %s -// RUN: ( cd %t && \ -// RUN: DYLD_INSERT_LIBRARIES=libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ -// RUN: %run ./a.out 2>&1 ) | FileCheck %s || exit 1 +// RUN: env DYLD_INSERT_LIBRARIES=libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ +// RUN: %run ./a.out 2>&1 | FileCheck %s -// RUN: ( cd %t && \ -// RUN: %env_asan_opts=strip_env=0 \ -// RUN: DYLD_INSERT_LIBRARIES=libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ -// RUN: %run ./a.out 2>&1 ) | FileCheck %s --check-prefix=CHECK-KEEP || exit 1 +// RUN: %env_asan_opts=strip_env=0 \ +// RUN: DYLD_INSERT_LIBRARIES=libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ +// RUN: %run ./a.out 2>&1 | FileCheck %s --check-prefix=CHECK-KEEP -// RUN: ( cd %t && \ -// RUN: DYLD_INSERT_LIBRARIES=%t/libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ -// RUN: %run ./a.out 2>&1 ) | FileCheck %s || exit 1 +// RUN: env DYLD_INSERT_LIBRARIES=%t/libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ +// RUN: %run ./a.out 2>&1 | FileCheck %s #if !defined(SHARED_LIB) #include diff --git a/compiler-rt/test/asan/TestCases/Darwin/init_for_dlopen.cpp b/compiler-rt/test/asan/TestCases/Darwin/init_for_dlopen.cpp index 3bf8e99703a08..9bb652cc79438 100644 --- a/compiler-rt/test/asan/TestCases/Darwin/init_for_dlopen.cpp +++ b/compiler-rt/test/asan/TestCases/Darwin/init_for_dlopen.cpp @@ -5,7 +5,7 @@ // - By default the lit config sets this but we don't want this // test to implicitly depend on this. // - It avoids requiring `--crash` to be passed to `not`. -// RUN: APPLE_ASAN_INIT_FOR_DLOPEN=0 %env_asan_opts=abort_on_error=0 not \ +// RUN: %env_asan_opts=abort_on_error=0 APPLE_ASAN_INIT_FOR_DLOPEN=0 not \ // RUN: %run %t %shared_libasan 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-DL-OPEN-FAIL %s // RUN: env -u APPLE_ASAN_INIT_FOR_DLOPEN %env_asan_opts=abort_on_error=0 not \ diff --git a/compiler-rt/test/asan/TestCases/Darwin/malloc_zone-protected.cpp b/compiler-rt/test/asan/TestCases/Darwin/malloc_zone-protected.cpp index 125b544724d3f..ac3c5898f271a 100644 --- a/compiler-rt/test/asan/TestCases/Darwin/malloc_zone-protected.cpp +++ b/compiler-rt/test/asan/TestCases/Darwin/malloc_zone-protected.cpp @@ -3,8 +3,7 @@ #include // RUN: %clangxx_asan %s -o %t -// RUN: ASAN_OPTIONS="abort_on_error=1" not --crash %run %t 2>&1 | FileCheck %s - +// RUN: env ASAN_OPTIONS="abort_on_error=1" not --crash %run %t 2>&1 | FileCheck %s void *pwn(malloc_zone_t *unused_zone, size_t unused_size) { printf("PWNED\n"); diff --git a/compiler-rt/test/asan_abi/TestCases/Darwin/llvm_interface_symbols.cpp b/compiler-rt/test/asan_abi/TestCases/Darwin/llvm_interface_symbols.cpp index 5da18aa971d43..ba7b5e5815bd6 100644 --- a/compiler-rt/test/asan_abi/TestCases/Darwin/llvm_interface_symbols.cpp +++ b/compiler-rt/test/asan_abi/TestCases/Darwin/llvm_interface_symbols.cpp @@ -24,7 +24,8 @@ // RUN: diff %t.imports-sorted %t.exports-sorted // Ensure that there is no dynamic dylib linked. -// RUN: otool -L %t | (! grep -q "dynamic.dylib") +// RUN: otool -L %t > %t.libs +// RUN: not grep -q "dynamic.dylib" < %t.libs // UNSUPPORTED: ios diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h index 8fa4a84aff06d..36556f8dd7f4a 100644 --- a/flang/include/flang/Parser/openmp-utils.h +++ b/flang/include/flang/Parser/openmp-utils.h @@ -137,6 +137,8 @@ const T *GetFirstArgument(const OmpDirectiveSpecification &spec) { const BlockConstruct *GetFortranBlockConstruct( const ExecutionPartConstruct &epc); +const Block &GetInnermostExecPart(const Block &block); +bool IsStrictlyStructuredBlock(const Block &block); const OmpCombinerExpression *GetCombinerExpr( const OmpReductionSpecifier &rspec); diff --git a/flang/include/flang/Semantics/openmp-utils.h b/flang/include/flang/Semantics/openmp-utils.h index 14a4f0e93bda5..f5739ab16d643 100644 --- a/flang/include/flang/Semantics/openmp-utils.h +++ b/flang/include/flang/Semantics/openmp-utils.h @@ -97,8 +97,6 @@ const SomeExpr *HasStorageOverlap( const SomeExpr &base, llvm::ArrayRef exprs); bool IsAssignment(const parser::ActionStmt *x); bool IsPointerAssignment(const evaluate::Assignment &x); -const parser::Block &GetInnermostExecPart(const parser::Block &block); -bool IsStrictlyStructuredBlock(const parser::Block &block); } // namespace omp } // namespace Fortran::semantics diff --git a/flang/lib/Parser/openmp-utils.cpp b/flang/lib/Parser/openmp-utils.cpp index b9d3763cdd06d..2424828293c73 100644 --- a/flang/lib/Parser/openmp-utils.cpp +++ b/flang/lib/Parser/openmp-utils.cpp @@ -93,6 +93,34 @@ const BlockConstruct *GetFortranBlockConstruct( return nullptr; } +/// parser::Block is a list of executable constructs, parser::BlockConstruct +/// is Fortran's BLOCK/ENDBLOCK construct. +/// Strip the outermost BlockConstructs, return the reference to the Block +/// in the executable part of the innermost of the stripped constructs. +/// Specifically, if the given `block` has a single entry (it's a list), and +/// the entry is a BlockConstruct, get the Block contained within. Repeat +/// this step as many times as possible. +const Block &GetInnermostExecPart(const Block &block) { + const Block *iter{&block}; + while (iter->size() == 1) { + const ExecutionPartConstruct &ep{iter->front()}; + if (auto *bc{GetFortranBlockConstruct(ep)}) { + iter = &std::get(bc->t); + } else { + break; + } + } + return *iter; +} + +bool IsStrictlyStructuredBlock(const Block &block) { + if (block.size() == 1) { + return GetFortranBlockConstruct(block.front()) != nullptr; + } else { + return false; + } +} + const OmpCombinerExpression *GetCombinerExpr( const OmpReductionSpecifier &rspec) { return addr_if(std::get>(rspec.t)); diff --git a/flang/lib/Semantics/check-omp-atomic.cpp b/flang/lib/Semantics/check-omp-atomic.cpp index ec03e6fe2d920..b9e34ca6e74df 100644 --- a/flang/lib/Semantics/check-omp-atomic.cpp +++ b/flang/lib/Semantics/check-omp-atomic.cpp @@ -19,6 +19,7 @@ #include "flang/Evaluate/rewrite.h" #include "flang/Evaluate/tools.h" #include "flang/Parser/char-block.h" +#include "flang/Parser/openmp-utils.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/openmp-utils.h" #include "flang/Semantics/symbol.h" @@ -41,6 +42,7 @@ namespace Fortran::semantics { +using namespace Fortran::parser::omp; using namespace Fortran::semantics::omp; namespace operation = Fortran::evaluate::operation; diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp index 4a40d6eec17bb..18a37d64a3b5a 100644 --- a/flang/lib/Semantics/openmp-utils.cpp +++ b/flang/lib/Semantics/openmp-utils.cpp @@ -496,32 +496,4 @@ bool IsPointerAssignment(const evaluate::Assignment &x) { return std::holds_alternative(x.u) || std::holds_alternative(x.u); } - -/// parser::Block is a list of executable constructs, parser::BlockConstruct -/// is Fortran's BLOCK/ENDBLOCK construct. -/// Strip the outermost BlockConstructs, return the reference to the Block -/// in the executable part of the innermost of the stripped constructs. -/// Specifically, if the given `block` has a single entry (it's a list), and -/// the entry is a BlockConstruct, get the Block contained within. Repeat -/// this step as many times as possible. -const parser::Block &GetInnermostExecPart(const parser::Block &block) { - const parser::Block *iter{&block}; - while (iter->size() == 1) { - const parser::ExecutionPartConstruct &ep{iter->front()}; - if (auto *bc{GetFortranBlockConstruct(ep)}) { - iter = &std::get(bc->t); - } else { - break; - } - } - return *iter; -} - -bool IsStrictlyStructuredBlock(const parser::Block &block) { - if (block.size() == 1) { - return GetFortranBlockConstruct(block.front()) != nullptr; - } else { - return false; - } -} } // namespace Fortran::semantics::omp diff --git a/flang/test/Lower/PowerPC/ppc-vec-load-elem-order.f90 b/flang/test/Lower/PowerPC/ppc-vec-load-elem-order.f90 index 355fd6c3a742a..b17c3f1bdc4e7 100644 --- a/flang/test/Lower/PowerPC/ppc-vec-load-elem-order.f90 +++ b/flang/test/Lower/PowerPC/ppc-vec-load-elem-order.f90 @@ -394,7 +394,7 @@ subroutine vec_xl_testi8a(arg1, arg2, res) vector(integer(1)) :: res res = vec_xl(arg1, arg2) - + ! LLVMIR: %[[arg1:.*]] = load i8, ptr %0, align 1 ! LLVMIR: %[[addr:.*]] = getelementptr i8, ptr %1, i8 %[[arg1]] ! LLVMIR: %[[ld:.*]] = load <16 x i8>, ptr %[[addr]], align 1 @@ -481,7 +481,7 @@ subroutine vec_xl_be_testi8a(arg1, arg2, res) vector(integer(1)) :: res res = vec_xl_be(arg1, arg2) - + ! LLVMIR: %4 = load i8, ptr %0, align 1 ! LLVMIR: %5 = getelementptr i8, ptr %1, i8 %4 ! LLVMIR: %6 = load <16 x i8>, ptr %5, align 1 diff --git a/flang/test/Lower/PowerPC/ppc-vec-sel.f90 b/flang/test/Lower/PowerPC/ppc-vec-sel.f90 index c3de8ba9c1444..93641d1461a99 100644 --- a/flang/test/Lower/PowerPC/ppc-vec-sel.f90 +++ b/flang/test/Lower/PowerPC/ppc-vec-sel.f90 @@ -136,7 +136,7 @@ subroutine vec_sel_testu8(arg1, arg2, arg3) vector(unsigned(8)) :: arg1, arg2, r vector(unsigned(8)) :: arg3 r = vec_sel(arg1, arg2, arg3) - + ! LLVMIR: %[[arg1:.*]] = load <2 x i64>, ptr %{{.*}}, align 16 ! LLVMIR: %[[arg2:.*]] = load <2 x i64>, ptr %{{.*}}, align 16 diff --git a/flang/test/Lower/PowerPC/ppc-vec-store-elem-order.f90 b/flang/test/Lower/PowerPC/ppc-vec-store-elem-order.f90 index caf6d5463a833..947c8b1c7eb2c 100644 --- a/flang/test/Lower/PowerPC/ppc-vec-store-elem-order.f90 +++ b/flang/test/Lower/PowerPC/ppc-vec-store-elem-order.f90 @@ -14,7 +14,7 @@ subroutine vec_st_test(arg1, arg2, arg3) ! LLVMIR: %[[arg1:.*]] = load <8 x i16>, ptr %0, align 16 ! LLVMIR: %[[arg2:.*]] = load i32, ptr %1, align 4 ! LLVMIR: %[[addr:.*]] = getelementptr i8, ptr %2, i32 %[[arg2]] -! LLVMIR: %[[bc:.*]] = bitcast <8 x i16> %[[arg1]] to <4 x i32> +! LLVMIR: %[[bc:.*]] = bitcast <8 x i16> %[[arg1]] to <4 x i32> ! LLVMIR: %[[shf:.*]] = shufflevector <4 x i32> %[[bc]], <4 x i32> undef, <4 x i32> ! LLVMIR: call void @llvm.ppc.altivec.stvx(<4 x i32> %[[shf]], ptr %[[addr]]) end subroutine vec_st_test @@ -28,7 +28,7 @@ subroutine vec_ste_test(arg1, arg2, arg3) integer(4) :: arg2 real(4) :: arg3 call vec_ste(arg1, arg2, arg3) - + ! LLVMIR: %[[arg1:.*]] = load <4 x float>, ptr %0, align 16 ! LLVMIR: %[[arg2:.*]] = load i32, ptr %1, align 4 ! LLVMIR: %[[addr]] = getelementptr i8, ptr %2, i32 %[[arg2]] diff --git a/flang/test/Lower/PowerPC/ppc-vec-store.f90 b/flang/test/Lower/PowerPC/ppc-vec-store.f90 index c25cc8b07cf79..1c3ab9638f117 100644 --- a/flang/test/Lower/PowerPC/ppc-vec-store.f90 +++ b/flang/test/Lower/PowerPC/ppc-vec-store.f90 @@ -300,7 +300,7 @@ subroutine vec_xst_test_vr4i2r4(arg1, arg2, arg3) real(4) :: arg3 call vec_xst(arg1, arg2, arg3) - + ! LLVMIR: %[[arg1:.*]] = load <4 x float>, ptr %{{.*}}, align 16 ! LLVMIR: %[[arg2:.*]] = load i16, ptr %{{.*}}, align 2 ! LLVMIR: %[[addr:.*]] = getelementptr i8, ptr %{{.*}}, i16 %[[arg2]] @@ -432,7 +432,7 @@ subroutine vec_xst_be_test_vi4i4vai4(arg1, arg2, arg3, i) ! LLVMIR: %[[iadd:.*]] = add nsw i64 %[[imul2]], 0 ! LLVMIR: %[[gep1:.*]] = getelementptr <4 x i32>, ptr %2, i64 %[[iadd]] ! LLVMIR: %[[arg1:.*]] = load <4 x i32>, ptr %0, align 16 -! LLVMIR: %[[arg2:.*]] = load i32, ptr %1, align 4 +! LLVMIR: %[[arg2:.*]] = load i32, ptr %1, align 4 ! LLVMIR: %[[gep2:.*]] = getelementptr i8, ptr %[[gep1]], i32 %[[arg2]] ! LLVMIR: %[[src:.*]] = shufflevector <4 x i32> %[[arg1]], <4 x i32> undef, <4 x i32> ! LLVMIR: store <4 x i32> %[[src]], ptr %[[gep2]], align 16 @@ -449,7 +449,7 @@ subroutine vec_xstd2_test_vr4i2r4(arg1, arg2, arg3) real(4) :: arg3 call vec_xstd2(arg1, arg2, arg3) - + ! LLVMIR: %[[arg1:.*]] = load <4 x float>, ptr %{{.*}}, align 16 ! LLVMIR: %[[arg2:.*]] = load i16, ptr %{{.*}}, align 2 ! LLVMIR: %[[addr:.*]] = getelementptr i8, ptr %{{.*}}, i16 %[[arg2]] @@ -509,7 +509,7 @@ subroutine vec_xstd2_test_vi4i4vai4(arg1, arg2, arg3, i) ! LLVMIR: %[[iadd:.*]] = add nsw i64 %[[imul2]], 0 ! LLVMIR: %[[gep1:.*]] = getelementptr <4 x i32>, ptr %2, i64 %[[iadd]] ! LLVMIR: %[[arg1:.*]] = load <4 x i32>, ptr %0, align 16 -! LLVMIR: %[[arg2:.*]] = load i32, ptr %1, align 4 +! LLVMIR: %[[arg2:.*]] = load i32, ptr %1, align 4 ! LLVMIR: %[[gep2:.*]] = getelementptr i8, ptr %[[gep1]], i32 %[[arg2]] ! LLVMIR: %[[src:.*]] = bitcast <4 x i32> %[[arg1]] to <2 x i64> ! LLVMIR: store <2 x i64> %[[src]], ptr %[[gep2]], align 16 @@ -526,7 +526,7 @@ subroutine vec_xstw4_test_vr4i2r4(arg1, arg2, arg3) real(4) :: arg3 call vec_xstw4(arg1, arg2, arg3) - + ! LLVMIR: %[[arg1:.*]] = load <4 x float>, ptr %{{.*}}, align 16 ! LLVMIR: %[[arg2:.*]] = load i16, ptr %{{.*}}, align 2 ! LLVMIR: %[[addr:.*]] = getelementptr i8, ptr %{{.*}}, i16 %[[arg2]] @@ -584,7 +584,7 @@ subroutine vec_xstw4_test_vi4i4vai4(arg1, arg2, arg3, i) ! LLVMIR: %[[iadd:.*]] = add nsw i64 %[[imul2]], 0 ! LLVMIR: %[[gep1:.*]] = getelementptr <4 x i32>, ptr %2, i64 %[[iadd]] ! LLVMIR: %[[arg1:.*]] = load <4 x i32>, ptr %0, align 16 -! LLVMIR: %[[arg2:.*]] = load i32, ptr %1, align 4 +! LLVMIR: %[[arg2:.*]] = load i32, ptr %1, align 4 ! LLVMIR: %[[gep2:.*]] = getelementptr i8, ptr %[[gep1]], i32 %[[arg2]] ! LLVMIR: store <4 x i32> %[[arg1]], ptr %[[gep2]], align 16 end subroutine vec_xstw4_test_vi4i4vai4 diff --git a/flang/test/Lower/allocatable-assignment.f90 b/flang/test/Lower/allocatable-assignment.f90 index 3c220232104a5..b6b2f7b6c77b9 100644 --- a/flang/test/Lower/allocatable-assignment.f90 +++ b/flang/test/Lower/allocatable-assignment.f90 @@ -283,14 +283,14 @@ subroutine test_dyn_char(x, n, c) ! CHECK: hlfir.assign %[[VAL_8]]#0 to %[[VAL_14]]#0 realloc keep_lhs_len : !fir.box>>, !fir.ref>>>> subroutine test_derived_with_init(x, y) - type t + type t integer, allocatable :: a(:) - end type - type(t), allocatable :: x - type(t) :: y + end type + type(t), allocatable :: x + type(t) :: y ! The allocatable component of `x` need to be initialized ! during the automatic allocation (setting its rank and allocation - ! status) before it is assigned with the component of `y` + ! status) before it is assigned with the component of `y` x = y end subroutine ! CHECK-LABEL: func.func @_QMalloc_assignPtest_derived_with_init( @@ -357,7 +357,7 @@ end function elt ! real :: y(2, 3) = reshape([1,2,3,4,5,6], [2,3]) ! real, allocatable :: x (:, :) ! allocate(x(2,2)) -! call test_with_lbounds(x, y) +! call test_with_lbounds(x, y) ! print *, x(10, 20) ! print *, x !end diff --git a/flang/test/Lower/allocatable-globals.f90 b/flang/test/Lower/allocatable-globals.f90 index 9d386688f8881..8b7420ab32391 100644 --- a/flang/test/Lower/allocatable-globals.f90 +++ b/flang/test/Lower/allocatable-globals.f90 @@ -12,7 +12,7 @@ module mod_allocatables character(10), allocatable :: c(:) end module - + ! CHECK-LABEL: func @_QPtest_mod_allocatables() subroutine test_mod_allocatables() use mod_allocatables, only: c diff --git a/flang/test/Lower/allocatable-polymorphic.f90 b/flang/test/Lower/allocatable-polymorphic.f90 index ddd5b6bc22a8e..020db19f5bd9a 100644 --- a/flang/test/Lower/allocatable-polymorphic.f90 +++ b/flang/test/Lower/allocatable-polymorphic.f90 @@ -459,7 +459,7 @@ subroutine test_allocate_with_mold() ! CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[X]](%{{.*}}) {uniq_name = "_QMpolyFtest_allocate_with_moldEx"} : (!fir.ref,c:i32}>>>, !fir.shape<1>) -> (!fir.ref,c:i32}>>>, !fir.ref,c:i32}>>>) ! CHECK: %[[EMBOX_X:.*]] = fir.embox %[[X_DECL]]#0(%{{.*}}) : (!fir.ref,c:i32}>>>, !fir.shape<1>) -> !fir.box,c:i32}>>> -! CHECK: %[[RANK:.*]] = arith.constant 1 : i32 +! CHECK: %[[RANK:.*]] = arith.constant 1 : i32 ! CHECK: %[[P_BOX_NONE:.*]] = fir.convert %[[P_DECL]]#0 : (!fir.ref>>>>) -> !fir.ref> ! CHECK: %[[X_BOX_NONE:.*]] = fir.convert %[[EMBOX_X]] : (!fir.box,c:i32}>>>) -> !fir.box ! CHECK: fir.call @_FortranAPointerApplyMold(%[[P_BOX_NONE]], %[[X_BOX_NONE]], %[[RANK]]) {{.*}} : (!fir.ref>, !fir.box, i32) -> () @@ -613,10 +613,10 @@ program test_alloc ! LLVM: %[[TYPE_CODE:.*]] = load i8, ptr %[[TYPE_CODE_GEP]] ! LLVM-NEXT: %[[EXT_TYPE_CODE:.*]] = sext i8 %[[TYPE_CODE]] to i32 ! LLVM: %{{.*}} = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } undef, i64 %[[ELEM_SIZE]], 1 -! LLVM: %[[TRUNC_TYPE_CODE:.*]] = trunc i32 %[[EXT_TYPE_CODE]] to i8 +! LLVM: %[[TRUNC_TYPE_CODE:.*]] = trunc i32 %[[EXT_TYPE_CODE]] to i8 ! LLVM: %{{.*}} = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %{{.*}}, i8 %[[TRUNC_TYPE_CODE]], 4 ! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %{{.*}}, ptr %[[TMP:.*]] -! LLVM: call void %{{.*}}(ptr %{{.*}}) +! LLVM: call void %{{.*}}(ptr %{{.*}}) ! LLVM: call void @llvm.memcpy.p0.p0.i32 ! LLVM: %[[GEP_TDESC_C2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %{{.*}}, i32 0, i32 7 @@ -627,7 +627,7 @@ program test_alloc ! LLVM: %[[TYPE_CODE:.*]] = load i8, ptr %[[TYPE_CODE_GEP]] ! LLVM-NEXT: %[[EXT_TYPE_CODE:.*]] = sext i8 %[[TYPE_CODE]] to i32 ! LLVM: %{{.*}} = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } undef, i64 %[[ELEM_SIZE]], 1 -! LLVM: %[[TRUNC_TYPE_CODE:.*]] = trunc i32 %[[EXT_TYPE_CODE]] to i8 +! LLVM: %[[TRUNC_TYPE_CODE:.*]] = trunc i32 %[[EXT_TYPE_CODE]] to i8 ! LLVM: %{{.*}} = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %{{.*}}, i8 %[[TRUNC_TYPE_CODE]], 4 ! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %{{.*}}, ptr %{{.*}} ! LLVM: call void %{{.*}}(ptr %{{.*}}) diff --git a/flang/test/Lower/allocated.f90 b/flang/test/Lower/allocated.f90 index 6e8420fc7d79a..11e856fd67bad 100644 --- a/flang/test/Lower/allocated.f90 +++ b/flang/test/Lower/allocated.f90 @@ -15,4 +15,3 @@ subroutine allocated_test(scalar, array) ! CHECK: cmpi ne, %[[addrToInt1]], %c0{{.*}} print *, allocated(array) end subroutine - \ No newline at end of file diff --git a/flang/test/Lower/array-elemental-calls-2.f90 b/flang/test/Lower/array-elemental-calls-2.f90 index 2674b07dece17..60c9257a19822 100644 --- a/flang/test/Lower/array-elemental-calls-2.f90 +++ b/flang/test/Lower/array-elemental-calls-2.f90 @@ -172,7 +172,7 @@ subroutine check_parentheses_logical() subroutine check_parentheses_derived(a) type t integer :: i - end type + end type interface integer elemental function elem_func_derived(x) import :: t diff --git a/flang/test/Lower/array-elemental-calls.f90 b/flang/test/Lower/array-elemental-calls.f90 index 853807bcb3e6c..93d2979ec9383 100644 --- a/flang/test/Lower/array-elemental-calls.f90 +++ b/flang/test/Lower/array-elemental-calls.f90 @@ -57,7 +57,7 @@ elemental impure integer function impure_func(j) integer, intent(in) :: j end function end interface - + i = 42 + pure_func(j) i = 42 + impure_func(j) end subroutine diff --git a/flang/test/Lower/array-expression-assumed-size.f90 b/flang/test/Lower/array-expression-assumed-size.f90 index a498148d07fc7..b51dc00c20e28 100644 --- a/flang/test/Lower/array-expression-assumed-size.f90 +++ b/flang/test/Lower/array-expression-assumed-size.f90 @@ -16,8 +16,8 @@ end subroutine assumed_size_forall_test ! CHECK-LABEL: func @_QPassumed_size_test( ! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>{{.*}}) { -! CHECK: %[[VAL_1A:.*]] = fir.convert %c10{{.*}} : (i64) -> index -! CHECK: %[[VAL_1B:.*]] = arith.cmpi sgt, %[[VAL_1A]], %c0{{.*}} : index +! CHECK: %[[VAL_1A:.*]] = fir.convert %c10{{.*}} : (i64) -> index +! CHECK: %[[VAL_1B:.*]] = arith.cmpi sgt, %[[VAL_1A]], %c0{{.*}} : index ! CHECK: %[[VAL_1:.*]] = arith.select %[[VAL_1B]], %[[VAL_1A]], %c0{{.*}} : index ! CHECK: %[[VAL_2:.*]] = fir.assumed_size_extent : index ! CHECK: %[[VAL_3:.*]] = arith.constant 1 : index @@ -79,8 +79,8 @@ end subroutine assumed_size_forall_test ! CHECK-LABEL: func @_QPassumed_size_forall_test( ! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>{{.*}}) { ! CHECK: %[[VAL_1:.*]] = fir.alloca i32 {adapt.valuebyref, bindc_name = "i"} -! CHECK: %[[VAL_2A:.*]] = fir.convert %c10{{.*}} : (i64) -> index -! CHECK: %[[VAL_2B:.*]] = arith.cmpi sgt, %[[VAL_2A]], %c0{{.*}} : index +! CHECK: %[[VAL_2A:.*]] = fir.convert %c10{{.*}} : (i64) -> index +! CHECK: %[[VAL_2B:.*]] = arith.cmpi sgt, %[[VAL_2A]], %c0{{.*}} : index ! CHECK: %[[VAL_2:.*]] = arith.select %[[VAL_2B]], %[[VAL_2A]], %c0{{.*}} : index ! CHECK: %[[VAL_3:.*]] = fir.assumed_size_extent : index ! CHECK: %[[VAL_4:.*]] = arith.constant 2 : i32 diff --git a/flang/test/Lower/array-substring.f90 b/flang/test/Lower/array-substring.f90 index 7544fbb989627..0ede04f0bb2f8 100644 --- a/flang/test/Lower/array-substring.f90 +++ b/flang/test/Lower/array-substring.f90 @@ -46,5 +46,5 @@ function test(C) logical :: test(1) character*12 C(1) - test = C(1:1)(1:8) == (/'ABCDabcd'/) + test = C(1:1)(1:8) == (/'ABCDabcd'/) end function test diff --git a/flang/test/Lower/array-wide-char.f90 b/flang/test/Lower/array-wide-char.f90 index 8bad280d0f056..44fcd45519d85 100644 --- a/flang/test/Lower/array-wide-char.f90 +++ b/flang/test/Lower/array-wide-char.f90 @@ -2,7 +2,7 @@ character(LEN=128, KIND=4), PARAMETER :: conarr(3) = & [ character(128,4) :: "now is the time", "for all good men to come", & - "to the aid of the country" ] + "to the aid of the country" ] character(LEN=10, KIND=4) :: arr(3) = & [ character(10,4) :: "good buddy", "best buddy", " " ] call action_on_char4(conarr) diff --git a/flang/test/Lower/array.f90 b/flang/test/Lower/array.f90 index 710175739b3a8..cd12d7f851e67 100644 --- a/flang/test/Lower/array.f90 +++ b/flang/test/Lower/array.f90 @@ -93,7 +93,7 @@ subroutine s(i,j,k,ii,jj,kk,a1,a2,a3,a4,a5,a6,a7) ! CHECK: fir.coordinate_of %[[a7]], %[[t7]] : ! CHECK-LABEL: EndIoStatement print *, a7(kk, jj, ii) - + end subroutine s ! CHECK-LABEL: range diff --git a/flang/test/Lower/forall-pointer-assignment.f90 b/flang/test/Lower/forall-pointer-assignment.f90 index d89fb3ed5cb57..62184a77addf5 100644 --- a/flang/test/Lower/forall-pointer-assignment.f90 +++ b/flang/test/Lower/forall-pointer-assignment.f90 @@ -1,4 +1,4 @@ -! Test lower of FORALL pointer assignment +! Test lower of FORALL pointer assignment ! RUN: bbc -emit-fir %s -o - | FileCheck %s diff --git a/flang/test/Lower/forall/forall-2.f90 b/flang/test/Lower/forall/forall-2.f90 index cdafb4f3d49e7..c6a20f5859497 100644 --- a/flang/test/Lower/forall/forall-2.f90 +++ b/flang/test/Lower/forall/forall-2.f90 @@ -16,7 +16,7 @@ subroutine implied_iters_allocatable(thing, a1) end type t type(t) :: thing(:) integer :: i - + forall (i=5:13) ! commenting out this test for the moment (hits assert) ! thing(i)%arr = a1 @@ -32,7 +32,7 @@ subroutine conflicting_allocatable(thing, lo, hi) end type t type(t) :: thing(:) integer :: i - + forall (i = lo:hi) ! commenting out this test for the moment (hits assert) ! thing(i)%arr = thing(hi-i)%arr diff --git a/flang/test/Lower/forall/forall-ranked.f90 b/flang/test/Lower/forall/forall-ranked.f90 index 9e56be926e78e..f508c67468212 100644 --- a/flang/test/Lower/forall/forall-ranked.f90 +++ b/flang/test/Lower/forall/forall-ranked.f90 @@ -68,7 +68,7 @@ end function f integer :: arr(11) end type t type(t) :: a(10,10) - + forall (i=1:5) a(i,:)%arr(i+4) = f(i) end forall diff --git a/flang/test/Lower/forall/forall-where-2.f90 b/flang/test/Lower/forall/forall-where-2.f90 index c075508bef561..85aab87559c3c 100644 --- a/flang/test/Lower/forall/forall-where-2.f90 +++ b/flang/test/Lower/forall/forall-where-2.f90 @@ -6,7 +6,7 @@ ! Test a FORALL construct with a nested WHERE construct where the mask ! contains temporary array expressions. -subroutine test_nested_forall_where_with_temp_in_mask(a,b) +subroutine test_nested_forall_where_with_temp_in_mask(a,b) interface function temp_foo(i, j) integer :: i, j @@ -28,10 +28,10 @@ function temp_foo(i, j) ! CHECK: func @_QPtest_nested_forall_where_with_temp_in_mask({{.*}}) { ! CHECK: %[[tempResultBox:.*]] = fir.alloca !fir.box>> {bindc_name = ".result"} - ! Where condition pre-evaluation + ! Where condition pre-evaluation ! CHECK: fir.do_loop {{.*}} { ! CHECK: fir.do_loop {{.*}} { - ! Evaluation of mask for iteration (i,j) into ragged array temp + ! Evaluation of mask for iteration (i,j) into ragged array temp ! CHECK: %[[tempResult:.*]] = fir.call @_QPtemp_foo ! CHECK: fir.save_result %[[tempResult]] to %[[tempResultBox]] : !fir.box>>, !fir.ref>>> ! CHECK: fir.if {{.*}} { @@ -52,7 +52,7 @@ function temp_foo(i, j) ! CHECK: fir.do_loop {{.*}} { ! Array assignment at iteration (i, j) ! CHECK: fir.do_loop {{.*}} { -! CHECK: fir.if {{.*}} { +! CHECK: fir.if {{.*}} { ! CHECK: arith.divf ! CHECK: } else { ! CHECK: } @@ -64,7 +64,7 @@ function temp_foo(i, j) ! CHECK: fir.do_loop {{.*}} { ! Array assignment at iteration (i, j) ! CHECK: fir.do_loop {{.*}} { -! CHECK: fir.if {{.*}} { +! CHECK: fir.if {{.*}} { ! CHECK: } else { ! CHECK: arith.negf ! CHECK: } diff --git a/flang/test/Lower/forall/forall-where.f90 b/flang/test/Lower/forall/forall-where.f90 index 54ff2bd4c3f16..3202edbaec808 100644 --- a/flang/test/Lower/forall/forall-where.f90 +++ b/flang/test/Lower/forall/forall-where.f90 @@ -6,7 +6,7 @@ ! This has both an explicit and implicit iteration space. The WHERE construct ! makes the assignments conditional and the where mask evaluation must happen ! prior to evaluating the array assignment statement. -subroutine test_nested_forall_where(a,b) +subroutine test_nested_forall_where(a,b) type t real data(100) end type t diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index bbff4969cb413..4b6c10917c315 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -264,6 +264,11 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.sys.mman.munlock libc.src.sys.mman.munlockall libc.src.sys.mman.munmap + libc.src.sys.mman.pkey_alloc + libc.src.sys.mman.pkey_free + libc.src.sys.mman.pkey_get + libc.src.sys.mman.pkey_mprotect + libc.src.sys.mman.pkey_set libc.src.sys.mman.remap_file_pages libc.src.sys.mman.posix_madvise libc.src.sys.mman.shm_open diff --git a/libc/include/sys/mman.yaml b/libc/include/sys/mman.yaml index 8c207552f9805..f9ab0c1001c3d 100644 --- a/libc/include/sys/mman.yaml +++ b/libc/include/sys/mman.yaml @@ -101,6 +101,41 @@ functions: arguments: - type: void * - type: size_t + - name: pkey_alloc + standards: + - Linux + return_type: int + arguments: + - type: unsigned int + - type: unsigned int + - name: pkey_free + standards: + - Linux + return_type: int + arguments: + - type: int + - name: pkey_get + standards: + - GNU + return_type: int + arguments: + - type: int + - name: pkey_mprotect + standards: + - Linux + return_type: int + arguments: + - type: void * + - type: size_t + - type: int + - type: int + - name: pkey_set + standards: + - GNU + return_type: int + arguments: + - type: int + - type: unsigned int - name: posix_madvise standards: - POSIX diff --git a/libc/src/sys/mman/CMakeLists.txt b/libc/src/sys/mman/CMakeLists.txt index 4d4c2ad376050..c7be1eddacb5e 100644 --- a/libc/src/sys/mman/CMakeLists.txt +++ b/libc/src/sys/mman/CMakeLists.txt @@ -86,6 +86,41 @@ add_entrypoint_object( .${LIBC_TARGET_OS}.msync ) +add_entrypoint_object( + pkey_alloc + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.pkey_alloc +) + +add_entrypoint_object( + pkey_free + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.pkey_free +) + +add_entrypoint_object( + pkey_get + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.pkey_get +) + +add_entrypoint_object( + pkey_mprotect + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.pkey_mprotect +) + +add_entrypoint_object( + pkey_set + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.pkey_set +) + add_entrypoint_object( remap_file_pages ALIAS diff --git a/libc/src/sys/mman/linux/CMakeLists.txt b/libc/src/sys/mman/linux/CMakeLists.txt index 7181bb98a187f..97c116f1d2e79 100644 --- a/libc/src/sys/mman/linux/CMakeLists.txt +++ b/libc/src/sys/mman/linux/CMakeLists.txt @@ -1,3 +1,10 @@ +add_subdirectory(generic) +set(ARCH_SUBDIRECTORY generic) +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE}) + add_subdirectory(${LIBC_TARGET_ARCHITECTURE}) + set(ARCH_SUBDIRECTORY ${LIBC_TARGET_ARCHITECTURE}) +endif() + add_entrypoint_object( madvise SRCS @@ -50,6 +57,17 @@ add_entrypoint_object( libc.src.errno.errno ) +add_header_library( + mprotect_common + HDRS + mprotect_common.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno + libc.src.__support.error_or +) + add_entrypoint_object( mprotect SRCS @@ -61,6 +79,7 @@ add_entrypoint_object( libc.include.sys_syscall libc.src.__support.OSUtil.osutil libc.src.errno.errno + .mprotect_common ) add_entrypoint_object( @@ -166,6 +185,82 @@ add_entrypoint_object( libc.src.errno.errno ) +add_entrypoint_object( + pkey_alloc + SRCS + pkey_alloc.cpp + HDRS + ../pkey_alloc.h + DEPENDS + libc.include.sys_mman + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + +add_header_library( + pkey_common + HDRS + pkey_common.h + DEPENDS + .${ARCH_SUBDIRECTORY}.pkey_common +) + +add_entrypoint_object( + pkey_free + SRCS + pkey_free.cpp + HDRS + ../pkey_free.h + DEPENDS + libc.include.sys_mman + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + +add_entrypoint_object( + pkey_get + SRCS + pkey_get.cpp + HDRS + ../pkey_get.h + DEPENDS + libc.include.sys_mman + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno + .pkey_common +) + +add_entrypoint_object( + pkey_mprotect + SRCS + pkey_mprotect.cpp + HDRS + ../pkey_mprotect.h + DEPENDS + libc.include.sys_mman + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno + .mprotect_common +) + +add_entrypoint_object( + pkey_set + SRCS + pkey_set.cpp + HDRS + ../pkey_set.h + DEPENDS + libc.include.sys_mman + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno + .pkey_common +) + add_entrypoint_object( remap_file_pages SRCS diff --git a/libc/src/sys/mman/linux/generic/CMakeLists.txt b/libc/src/sys/mman/linux/generic/CMakeLists.txt new file mode 100644 index 0000000000000..42b6d96c8387e --- /dev/null +++ b/libc/src/sys/mman/linux/generic/CMakeLists.txt @@ -0,0 +1,9 @@ +add_header_library( + pkey_common + HDRS + pkey_common.h + DEPENDS + libc.hdr.errno_macros + libc.src.__support.common + libc.src.__support.error_or +) diff --git a/libc/src/sys/mman/linux/generic/pkey_common.h b/libc/src/sys/mman/linux/generic/pkey_common.h new file mode 100644 index 0000000000000..95f9a464fbd4a --- /dev/null +++ b/libc/src/sys/mman/linux/generic/pkey_common.h @@ -0,0 +1,31 @@ +//===---------- Generic stub implementations for pkey functionality. ------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYS_MMAN_LINUX_GENERIC_PKEY_COMMON_H_ +#define LLVM_SYS_MMAN_LINUX_GENERIC_PKEY_COMMON_H_ + +#include "hdr/errno_macros.h" // For ENOSYS +#include "src/__support/common.h" +#include "src/__support/error_or.h" + +namespace LIBC_NAMESPACE_DECL { +namespace pkey_common { + +LIBC_INLINE ErrorOr pkey_get([[maybe_unused]] int pkey) { + return Error(ENOSYS); +} + +LIBC_INLINE ErrorOr pkey_set([[maybe_unused]] int pkey, + [[maybe_unused]] unsigned int access_rights) { + return Error(ENOSYS); +} + +} // namespace pkey_common +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_SYS_MMAN_LINUX_GENERIC_PKEY_COMMON_H_ diff --git a/libc/src/sys/mman/linux/mprotect.cpp b/libc/src/sys/mman/linux/mprotect.cpp index 6b14915b60c94..c891f03a4713c 100644 --- a/libc/src/sys/mman/linux/mprotect.cpp +++ b/libc/src/sys/mman/linux/mprotect.cpp @@ -11,26 +11,22 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/error_or.h" #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" +#include "src/sys/mman/linux/mprotect_common.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { -// This function is currently linux only. It has to be refactored suitably if -// mprotect is to be supported on non-linux operating systems also. LLVM_LIBC_FUNCTION(int, mprotect, (void *addr, size_t size, int prot)) { - int ret = LIBC_NAMESPACE::syscall_impl( - SYS_mprotect, reinterpret_cast(addr), size, prot); - - // A negative return value indicates an error with the magnitude of the - // value being the error code. - if (ret < 0) { - libc_errno = -ret; + ErrorOr result = + LIBC_NAMESPACE::mprotect_common::mprotect_impl(addr, size, prot); + if (!result.has_value()) { + libc_errno = result.error(); return -1; } - - return 0; + return result.value(); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/sys/mman/linux/mprotect_common.h b/libc/src/sys/mman/linux/mprotect_common.h new file mode 100644 index 0000000000000..5cd354f9919dd --- /dev/null +++ b/libc/src/sys/mman/linux/mprotect_common.h @@ -0,0 +1,38 @@ +//===---------- Shared Linux implementation of POSIX mprotect. ------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include // For syscall numbers. + +namespace LIBC_NAMESPACE_DECL { + +namespace mprotect_common { + +// This function is currently linux only. It has to be refactored suitably if +// mprotect is to be supported on non-linux operating systems also. +LIBC_INLINE ErrorOr mprotect_impl(void *addr, size_t size, int prot) { + int ret = LIBC_NAMESPACE::syscall_impl( + SYS_mprotect, reinterpret_cast(addr), size, prot); + + // A negative return value indicates an error with the magnitude of the + // value being the error code. + if (ret < 0) { + return Error(-ret); + } + + return 0; +} + +} // namespace mprotect_common + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/sys/mman/linux/pkey_alloc.cpp b/libc/src/sys/mman/linux/pkey_alloc.cpp new file mode 100644 index 0000000000000..6ad65f342eb5e --- /dev/null +++ b/libc/src/sys/mman/linux/pkey_alloc.cpp @@ -0,0 +1,37 @@ +//===---------- Linux implementation of the Linux pkey_alloc function -----===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/sys/mman/pkey_alloc.h" + +#include "hdr/errno_macros.h" // For ENOSYS +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" + +#include // For syscall numbers. + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, pkey_alloc, + (unsigned int flags, unsigned int access_rights)) { +#if !defined(SYS_pkey_alloc) + libc_errno = ENOSYS; + return -1; +#else + int ret = + LIBC_NAMESPACE::syscall_impl(SYS_pkey_alloc, flags, access_rights); + if (ret < 0) { + libc_errno = -ret; + return -1; + } + return static_cast(ret); +#endif +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/sys/mman/linux/pkey_common.h b/libc/src/sys/mman/linux/pkey_common.h new file mode 100644 index 0000000000000..7ea7b61cdcb75 --- /dev/null +++ b/libc/src/sys/mman/linux/pkey_common.h @@ -0,0 +1,15 @@ +//===---------- Linux implementation of the Linux pkey_mprotect function --===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/__support/macros/properties/architectures.h" + +#if defined(LIBC_TARGET_ARCH_IS_X86_64) +#include "src/sys/mman/linux/x86_64/pkey_common.h" +#else +#include "src/sys/mman/linux/generic/pkey_common.h" +#endif diff --git a/libc/src/sys/mman/linux/pkey_free.cpp b/libc/src/sys/mman/linux/pkey_free.cpp new file mode 100644 index 0000000000000..328ba0468252e --- /dev/null +++ b/libc/src/sys/mman/linux/pkey_free.cpp @@ -0,0 +1,35 @@ +//===---------- Linux implementation of the Linux pkey_free function ------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/sys/mman/pkey_free.h" + +#include "hdr/errno_macros.h" // For ENOSYS +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" + +#include // For syscall numbers. + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, pkey_free, (int pkey)) { +#if !defined(SYS_pkey_free) + libc_errno = ENOSYS; + return -1; +#else + int ret = LIBC_NAMESPACE::syscall_impl(SYS_pkey_free, pkey); + if (ret < 0) { + libc_errno = -ret; + return -1; + } + return 0; +#endif +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/sys/mman/linux/pkey_get.cpp b/libc/src/sys/mman/linux/pkey_get.cpp new file mode 100644 index 0000000000000..fbec5706c918d --- /dev/null +++ b/libc/src/sys/mman/linux/pkey_get.cpp @@ -0,0 +1,29 @@ +//===---------- Linux implementation of the Linux pkey_mprotect function --===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/sys/mman/pkey_get.h" + +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/architectures.h" +#include "src/sys/mman/linux/pkey_common.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, pkey_get, (int pkey)) { + ErrorOr ret = LIBC_NAMESPACE::pkey_common::pkey_get(pkey); + if (!ret.has_value()) { + libc_errno = ret.error(); + return -1; + } + return ret.value(); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/sys/mman/linux/pkey_mprotect.cpp b/libc/src/sys/mman/linux/pkey_mprotect.cpp new file mode 100644 index 0000000000000..daa12fa927f87 --- /dev/null +++ b/libc/src/sys/mman/linux/pkey_mprotect.cpp @@ -0,0 +1,58 @@ +//===---------- Linux implementation of the Linux pkey_mprotect function --===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/sys/mman/pkey_mprotect.h" + +#include "hdr/errno_macros.h" // For ENOSYS +#include "hdr/types/size_t.h" +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/sys/mman/linux/mprotect_common.h" + +#include // For syscall numbers. + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +LIBC_INLINE ErrorOr pkey_mprotect_impl(void *addr, size_t len, int prot, + int pkey) { + // Fall back to mprotect if pkey is -1 + // to maintain compatibility with kernel versions that don't support pkey. + if (pkey == -1) { + return LIBC_NAMESPACE::mprotect_common::mprotect_impl(addr, len, prot); + } + +#if !defined(SYS_pkey_mprotect) + return Error(ENOSYS); +#else + int ret = LIBC_NAMESPACE::syscall_impl(SYS_pkey_mprotect, addr, len, + prot, pkey); + if (ret < 0) { + return Error(-ret); + } + return 0; +#endif +} + +} // namespace internal + +LLVM_LIBC_FUNCTION(int, pkey_mprotect, + (void *addr, size_t len, int prot, int pkey)) { + ErrorOr ret = + LIBC_NAMESPACE::internal::pkey_mprotect_impl(addr, len, prot, pkey); + if (!ret.has_value()) { + libc_errno = ret.error(); + return -1; + } + return ret.value(); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/sys/mman/linux/pkey_set.cpp b/libc/src/sys/mman/linux/pkey_set.cpp new file mode 100644 index 0000000000000..919a6dceeafef --- /dev/null +++ b/libc/src/sys/mman/linux/pkey_set.cpp @@ -0,0 +1,29 @@ +//===---------- Linux implementation of the Linux pkey_mprotect function --===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/sys/mman/pkey_set.h" + +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/sys/mman/linux/pkey_common.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, pkey_set, (int pkey, unsigned int access_rights)) { + ErrorOr ret = LIBC_NAMESPACE::pkey_common::pkey_set(pkey, access_rights); + if (!ret.has_value()) { + libc_errno = ret.error(); + return -1; + } + return ret.value(); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/sys/mman/linux/x86_64/CMakeLists.txt b/libc/src/sys/mman/linux/x86_64/CMakeLists.txt new file mode 100644 index 0000000000000..1ce23af6dbd2a --- /dev/null +++ b/libc/src/sys/mman/linux/x86_64/CMakeLists.txt @@ -0,0 +1,10 @@ +add_header_library( + pkey_common + HDRS + pkey_common.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.stdint_proxy + libc.src.__support.common + libc.src.__support.error_or +) diff --git a/libc/src/sys/mman/linux/x86_64/pkey_common.h b/libc/src/sys/mman/linux/x86_64/pkey_common.h new file mode 100644 index 0000000000000..cb657750112c9 --- /dev/null +++ b/libc/src/sys/mman/linux/x86_64/pkey_common.h @@ -0,0 +1,61 @@ +//===---------- x86_64-specific implementations for pkey_{get,set}. -------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYS_MMAN_LINUX_X86_64_PKEY_COMMON_H_ +#define LLVM_SYS_MMAN_LINUX_X86_64_PKEY_COMMON_H_ + +#include + +#include "hdr/errno_macros.h" // For ENOSYS +#include "hdr/stdint_proxy.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" + +#if !defined(LIBC_TARGET_ARCH_IS_X86_64) +#error "Invalid include" +#endif + +namespace LIBC_NAMESPACE_DECL { +namespace pkey_common { + +constexpr int KEY_COUNT = 16; +constexpr int KEY_MASK = 0x3; +constexpr int BITS_PER_KEY = 2; + +// x86_64 implementation of pkey_get. +// Returns the access rights for the given pkey on success, errno otherwise. +[[gnu::target("pku")]] +LIBC_INLINE ErrorOr pkey_get(int pkey) { + if (pkey < 0 || pkey >= KEY_COUNT) { + return Error(EINVAL); + } + + uint32_t pkru = _rdpkru_u32(); + return (pkru >> (pkey * BITS_PER_KEY)) & KEY_MASK; +} + +// x86_64 implementation of pkey_set. +// Returns 0 on success, errno otherwise. +[[gnu::target("pku")]] +LIBC_INLINE ErrorOr pkey_set(int pkey, unsigned int access_rights) { + if (pkey < 0 || pkey >= KEY_COUNT || access_rights > KEY_MASK) { + return Error(EINVAL); + } + + uint32_t pkru = _rdpkru_u32(); + pkru &= ~(KEY_MASK << (pkey * BITS_PER_KEY)); + pkru |= ((access_rights & KEY_MASK) << (pkey * BITS_PER_KEY)); + _wrpkru(pkru); + + return 0; +} + +} // namespace pkey_common +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_SYS_MMAN_LINUX_X86_64_PKEY_COMMON_H_ diff --git a/libc/src/sys/mman/pkey_alloc.h b/libc/src/sys/mman/pkey_alloc.h new file mode 100644 index 0000000000000..c63c6a36c8021 --- /dev/null +++ b/libc/src/sys/mman/pkey_alloc.h @@ -0,0 +1,20 @@ +//===-- Implementation header for pkey_alloc function -----------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SYS_MMAN_PKEY_ALLOC_H +#define LLVM_LIBC_SRC_SYS_MMAN_PKEY_ALLOC_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int pkey_alloc(unsigned int flags, unsigned int access_rights); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_SYS_MMAN_PKEY_ALLOC_H diff --git a/libc/src/sys/mman/pkey_free.h b/libc/src/sys/mman/pkey_free.h new file mode 100644 index 0000000000000..a357e9b8c847b --- /dev/null +++ b/libc/src/sys/mman/pkey_free.h @@ -0,0 +1,20 @@ +//===-- Implementation header for pkey_free function ------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SYS_MMAN_PKEY_FREE_H +#define LLVM_LIBC_SRC_SYS_MMAN_PKEY_FREE_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int pkey_free(int pkey); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_SYS_MMAN_PKEY_FREE_H diff --git a/libc/src/sys/mman/pkey_get.h b/libc/src/sys/mman/pkey_get.h new file mode 100644 index 0000000000000..d41afe08ae371 --- /dev/null +++ b/libc/src/sys/mman/pkey_get.h @@ -0,0 +1,20 @@ +//===-- Implementation header for pkey_get function -------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SYS_MMAN_PKEY_GET_H +#define LLVM_LIBC_SRC_SYS_MMAN_PKEY_GET_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int pkey_get(int pkey); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_SYS_MMAN_PKEY_GET_H diff --git a/libc/src/sys/mman/pkey_mprotect.h b/libc/src/sys/mman/pkey_mprotect.h new file mode 100644 index 0000000000000..c02c61594ecc6 --- /dev/null +++ b/libc/src/sys/mman/pkey_mprotect.h @@ -0,0 +1,21 @@ +//===-- Implementation header for pkey_mprotect function --------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SYS_MMAN_PKEY_MPROTECT_H +#define LLVM_LIBC_SRC_SYS_MMAN_PKEY_MPROTECT_H + +#include "hdr/types/size_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int pkey_mprotect(void *addr, size_t len, int prot, int pkey); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_SYS_MMAN_PKEY_MPROTECT_H diff --git a/libc/src/sys/mman/pkey_set.h b/libc/src/sys/mman/pkey_set.h new file mode 100644 index 0000000000000..55bafbd11d709 --- /dev/null +++ b/libc/src/sys/mman/pkey_set.h @@ -0,0 +1,20 @@ +//===-- Implementation header for pkey_set function -------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SYS_MMAN_PKEY_SET_H +#define LLVM_LIBC_SRC_SYS_MMAN_PKEY_SET_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int pkey_set(int pkey, unsigned int access_rights); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_SYS_MMAN_PKEY_SET_H diff --git a/libc/test/src/sys/mman/linux/CMakeLists.txt b/libc/test/src/sys/mman/linux/CMakeLists.txt index 32fee920321c0..8a290795e67f5 100644 --- a/libc/test/src/sys/mman/linux/CMakeLists.txt +++ b/libc/test/src/sys/mman/linux/CMakeLists.txt @@ -66,6 +66,31 @@ add_libc_unittest( libc.test.UnitTest.ErrnoSetterMatcher ) +# Disable sanitizers for pkey_test. +# This test intentionally triggers segfaults to verify pkey_mprotect behavior, +# and sanitizers register signal handlers that interfere with death testing. +if (NOT LLVM_USE_SANITIZER) + add_libc_unittest( + pkey_test + SUITE + libc_sys_mman_unittests + SRCS + pkey_test.cpp + DEPENDS + libc.hdr.errno_macros + libc.hdr.signal_macros + libc.hdr.types.size_t + libc.src.sys.mman.mmap + libc.src.sys.mman.munmap + libc.src.sys.mman.pkey_alloc + libc.src.sys.mman.pkey_free + libc.src.sys.mman.pkey_get + libc.src.sys.mman.pkey_mprotect + libc.src.sys.mman.pkey_set + libc.test.UnitTest.ErrnoCheckingTest + libc.test.UnitTest.ErrnoSetterMatcher + ) +endif() add_libc_unittest( posix_madvise_test diff --git a/libc/test/src/sys/mman/linux/pkey_test.cpp b/libc/test/src/sys/mman/linux/pkey_test.cpp new file mode 100644 index 0000000000000..9c6feae2d457b --- /dev/null +++ b/libc/test/src/sys/mman/linux/pkey_test.cpp @@ -0,0 +1,241 @@ +//===-- Unit tests for pkey functions -------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "hdr/errno_macros.h" +#include "hdr/signal_macros.h" +#include "hdr/types/size_t.h" +#include "src/sys/mman/mmap.h" +#include "src/sys/mman/munmap.h" +#include "src/sys/mman/pkey_alloc.h" +#include "src/sys/mman/pkey_free.h" +#include "src/sys/mman/pkey_get.h" +#include "src/sys/mman/pkey_mprotect.h" +#include "src/sys/mman/pkey_set.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" +#include "test/UnitTest/LibcTest.h" +#include "test/UnitTest/TestLogger.h" + +#include // For EXEC_PAGESIZE. + +using LIBC_NAMESPACE::testing::tlog; +using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; +using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; + +using LlvmLibcProtectionKeyTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +constexpr size_t MMAP_SIZE = EXEC_PAGESIZE; + +// Wrapper around a pkey to ensure it is freed. +class PKeyGuard { +public: + int key; + + PKeyGuard() : key(-1) {} + + PKeyGuard(int key) : key(key) {} + + ~PKeyGuard() { + if (key != -1) { + LIBC_NAMESPACE::pkey_free(key); + } + } +}; + +// Wrapper around mmap to ensure munmap is called. +class MMapPageGuard { +public: + void *addr = nullptr; + size_t size = 0; + + static MMapPageGuard mmap(int prot) { + void *addr = LIBC_NAMESPACE::mmap(nullptr, MMAP_SIZE, prot, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (addr == MAP_FAILED) { + return MMapPageGuard(nullptr, 0); + } + return MMapPageGuard(addr, MMAP_SIZE); + } + + MMapPageGuard(void *addr, size_t size) : addr(addr), size(size) {} + + ~MMapPageGuard() { + if (addr != nullptr) { + LIBC_NAMESPACE::munmap(addr, size); + } + } +}; + +bool protection_keys_supported() { + static bool supported = []() { + PKeyGuard pkey(LIBC_NAMESPACE::pkey_alloc(0, 0)); + int err = libc_errno; + libc_errno = 0; + + if (pkey.key < 0 || (err == ENOSPC || err == ENOSYS || err == EINVAL)) { + tlog << "pkey_alloc failed with errno=" << err << "\n"; + return false; + } + + int access_rights = LIBC_NAMESPACE::pkey_get(pkey.key); + err = libc_errno; + libc_errno = 0; + if (access_rights < 0 || err == ENOSYS) { + tlog << "pkey_get failed with errno=" << err << "\n"; + return false; + } + + return true; + }(); + return supported; +} + +TEST_F(LlvmLibcProtectionKeyTest, MProtectWithPKeyDisablesWrite) { + if (!protection_keys_supported()) { + tlog << "Skipping test: pkey is not available\n"; + return; + } + + PKeyGuard pkey(LIBC_NAMESPACE::pkey_alloc(0, PKEY_DISABLE_WRITE)); + ASSERT_NE(pkey.key, -1); + + MMapPageGuard page = MMapPageGuard::mmap(PROT_READ | PROT_WRITE); + ASSERT_NE(page.addr, nullptr); + + volatile char *data = (char *)page.addr; + data[0] = 'a'; + + EXPECT_THAT(LIBC_NAMESPACE::pkey_mprotect(page.addr, page.size, + PROT_READ | PROT_WRITE, pkey.key), + Succeeds()); + + // Read is still allowed. + EXPECT_EQ(data[0], 'a'); + + // Write is not allowed. + EXPECT_DEATH([&data]() { data[0] = 'b'; }, WITH_SIGNAL(SIGSEGV)); +} + +TEST_F(LlvmLibcProtectionKeyTest, PKeySetChangesAccessRights) { + if (!protection_keys_supported()) { + tlog << "Skipping test: pkey is not available\n"; + return; + } + + PKeyGuard pkey(LIBC_NAMESPACE::pkey_alloc(0, 0)); + ASSERT_NE(pkey.key, -1); + + MMapPageGuard page = MMapPageGuard::mmap(PROT_READ | PROT_WRITE); + ASSERT_NE(page.addr, nullptr); + + EXPECT_THAT(LIBC_NAMESPACE::pkey_mprotect(page.addr, page.size, + PROT_READ | PROT_WRITE, pkey.key), + Succeeds()); + + // Write is allowed by default. + volatile char *data = (char *)page.addr; + data[0] = 'a'; + + EXPECT_THAT(LIBC_NAMESPACE::pkey_set(pkey.key, PKEY_DISABLE_WRITE), + Succeeds()); + + // Now read is allowed but write is not. + EXPECT_EQ(data[0], 'a'); + EXPECT_DEATH([&data]() { data[0] = 'b'; }, WITH_SIGNAL(SIGSEGV)); + + // Now neither read nor write is allowed. + EXPECT_THAT(LIBC_NAMESPACE::pkey_set(pkey.key, PKEY_DISABLE_ACCESS | + PKEY_DISABLE_WRITE), + Succeeds()); + EXPECT_DEATH([&data]() { (void)data[0]; }, WITH_SIGNAL(SIGSEGV)); + EXPECT_DEATH([&data]() { data[0] = 'b'; }, WITH_SIGNAL(SIGSEGV)); +} + +TEST_F(LlvmLibcProtectionKeyTest, FallsBackToMProtectForInvalidPKey) { + MMapPageGuard page = MMapPageGuard::mmap(PROT_READ | PROT_WRITE); + ASSERT_NE(page.addr, nullptr); + + volatile char *data = (char *)page.addr; + data[0] = 'a'; + + EXPECT_THAT( + LIBC_NAMESPACE::pkey_mprotect(page.addr, page.size, PROT_READ, -1), + Succeeds()); + + // Read is still allowed. + EXPECT_EQ(data[0], 'a'); + + // Write is not allowed. + EXPECT_DEATH([&data]() { data[0] = 'b'; }, WITH_SIGNAL(SIGSEGV)); +} + +TEST_F(LlvmLibcProtectionKeyTest, ExhaustedKeysFailsWithENOSPC) { + if (!protection_keys_supported()) { + tlog << "Skipping test: pkey is not available\n"; + return; + } + + // Use an unreasonably large limit to ensure test is cross-platform. + // This limit is intended to be much larger than the actual hardware limit. + constexpr int MAX_PKEYS = 64; + PKeyGuard pkeys[MAX_PKEYS]; + for (int i = 0; i < MAX_PKEYS; ++i) { + pkeys[i].key = LIBC_NAMESPACE::pkey_alloc(0, 0); + } + + // pkey allocation should eventually fail with ENOSPC. + PKeyGuard pkey(LIBC_NAMESPACE::pkey_alloc(0, 0)); + EXPECT_THAT(pkey.key, Fails(ENOSPC)); + libc_errno = 0; +} + +TEST_F(LlvmLibcProtectionKeyTest, Accessors) { + if (!protection_keys_supported()) { + tlog << "Skipping test: pkey is not available\n"; + return; + } + + PKeyGuard pkey(LIBC_NAMESPACE::pkey_alloc(0, PKEY_DISABLE_WRITE)); + ASSERT_NE(pkey.key, -1); + + // Check that pkey_alloc sets the access rights. + EXPECT_EQ(LIBC_NAMESPACE::pkey_get(pkey.key), PKEY_DISABLE_WRITE); + + // Check that pkey_set changes the access rights. + EXPECT_THAT(LIBC_NAMESPACE::pkey_set(pkey.key, PKEY_DISABLE_ACCESS), + Succeeds()); + EXPECT_EQ(LIBC_NAMESPACE::pkey_get(pkey.key), PKEY_DISABLE_ACCESS); +} + +TEST_F(LlvmLibcProtectionKeyTest, AccessorsErrorForInvalidValues) { + if (!protection_keys_supported()) { + tlog << "Skipping test: pkey is not available\n"; + return; + } + + PKeyGuard pkey(LIBC_NAMESPACE::pkey_alloc(0, PKEY_DISABLE_WRITE)); + ASSERT_NE(pkey.key, -1); + + // Pkey is out of bounds in pkey_get. + EXPECT_THAT(LIBC_NAMESPACE::pkey_get(100), Fails(EINVAL)); + EXPECT_THAT(LIBC_NAMESPACE::pkey_get(-1234), Fails(EINVAL)); + + // Pkey is out of bounds in pkey_set. + EXPECT_THAT(LIBC_NAMESPACE::pkey_set(100, PKEY_DISABLE_ACCESS), + Fails(EINVAL)); + EXPECT_THAT(LIBC_NAMESPACE::pkey_set(-1234, PKEY_DISABLE_ACCESS), + Fails(EINVAL)); + + // Non-zero flags are not supported in pkey_alloc. + EXPECT_THAT(LIBC_NAMESPACE::pkey_alloc(123, PKEY_DISABLE_WRITE), + Fails(EINVAL)); + + // Access rights are out of bounds. + EXPECT_THAT(LIBC_NAMESPACE::pkey_alloc(0, 1000), Fails(EINVAL)); + EXPECT_THAT(LIBC_NAMESPACE::pkey_set(pkey.key, 1000), Fails(EINVAL)); +} diff --git a/lldb/include/lldb/Utility/LLDBLog.h b/lldb/include/lldb/Utility/LLDBLog.h index 18e4a3ca73507..ac360bfdf8cee 100644 --- a/lldb/include/lldb/Utility/LLDBLog.h +++ b/lldb/include/lldb/Utility/LLDBLog.h @@ -50,7 +50,8 @@ enum class LLDBLog : Log::MaskType { OnDemand = Log::ChannelFlag<31>, Source = Log::ChannelFlag<32>, Disassembler = Log::ChannelFlag<33>, - LLVM_MARK_AS_BITMASK_ENUM(Disassembler), + InstrumentationRuntime = Log::ChannelFlag<34>, + LLVM_MARK_AS_BITMASK_ENUM(InstrumentationRuntime), }; LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); diff --git a/lldb/include/lldb/Utility/RegisterValue.h b/lldb/include/lldb/Utility/RegisterValue.h index 49aaf68be17fc..baf984cbcb052 100644 --- a/lldb/include/lldb/Utility/RegisterValue.h +++ b/lldb/include/lldb/Utility/RegisterValue.h @@ -46,7 +46,8 @@ class RegisterValue { eTypeUInt16, eTypeUInt32, eTypeUInt64, - eTypeUInt128, + eTypeUIntN, /// < This value is used when the (integer) register is larger + /// than 64-bits. eTypeFloat, eTypeDouble, eTypeLongDouble, @@ -69,7 +70,7 @@ class RegisterValue { m_scalar = inst; } - explicit RegisterValue(llvm::APInt inst) : m_type(eTypeUInt128) { + explicit RegisterValue(llvm::APInt inst) : m_type(eTypeUIntN) { m_scalar = llvm::APInt(std::move(inst)); } @@ -178,7 +179,7 @@ class RegisterValue { } void operator=(llvm::APInt uint) { - m_type = eTypeUInt128; + m_type = eTypeUIntN; m_scalar = llvm::APInt(std::move(uint)); } @@ -217,8 +218,8 @@ class RegisterValue { m_scalar = uint; } - void SetUInt128(llvm::APInt uint) { - m_type = eTypeUInt128; + void SetUIntN(llvm::APInt uint) { + m_type = eTypeUIntN; m_scalar = std::move(uint); } diff --git a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp index a8901beda3970..f124424a37f58 100644 --- a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp +++ b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp @@ -346,6 +346,16 @@ EmulateInstructionARM64::GetOpcodeForInstruction(const uint32_t opcode) { &EmulateInstructionARM64::EmulateLDRSTRImm, "LDR , [{, #}]"}, + {0x3f200c00, 0x3c000400, No_VFP, + &EmulateInstructionARM64::EmulateLDRSTRImm, + "LDR|STR , [], #"}, + {0x3f200c00, 0x3c000c00, No_VFP, + &EmulateInstructionARM64::EmulateLDRSTRImm, + "LDR|STR , [, #]!"}, + {0x3f000000, 0x3d000000, No_VFP, + &EmulateInstructionARM64::EmulateLDRSTRImm, + "LDR|STR , [{, #}]"}, + {0xfc000000, 0x14000000, No_VFP, &EmulateInstructionARM64::EmulateB, "B