1 change: 1 addition & 0 deletions clang/include/clang/CIR/CIRGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class CIRGenerator : public clang::ASTConsumer {
~CIRGenerator() override;
void Initialize(clang::ASTContext &astCtx) override;
bool HandleTopLevelDecl(clang::DeclGroupRef group) override;
mlir::ModuleOp getModule() const;
};

} // namespace cir
Expand Down
21 changes: 21 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRDialect.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,25 @@
#ifndef LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H
#define LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H

#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/Interfaces/CallInterfaces.h"
#include "mlir/Interfaces/ControlFlowInterfaces.h"
#include "mlir/Interfaces/FunctionInterfaces.h"
#include "mlir/Interfaces/InferTypeOpInterface.h"
#include "mlir/Interfaces/LoopLikeInterface.h"
#include "mlir/Interfaces/MemorySlotInterfaces.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"

#include "clang/CIR/Dialect/IR/CIROpsDialect.h.inc"

// TableGen'erated files for MLIR dialects require that a macro be defined when
// they are included. GET_OP_CLASSES tells the file to define the classes for
// the operations of that dialect.
#define GET_OP_CLASSES
#include "clang/CIR/Dialect/IR/CIROps.h.inc"

#endif // LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H
82 changes: 82 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,86 @@

include "clang/CIR/Dialect/IR/CIRDialect.td"

include "mlir/IR/BuiltinAttributeInterfaces.td"
include "mlir/IR/EnumAttr.td"
include "mlir/IR/SymbolInterfaces.td"
include "mlir/IR/CommonAttrConstraints.td"
include "mlir/Interfaces/ControlFlowInterfaces.td"
include "mlir/Interfaces/FunctionInterfaces.td"
include "mlir/Interfaces/InferTypeOpInterface.td"
include "mlir/Interfaces/LoopLikeInterface.td"
include "mlir/Interfaces/MemorySlotInterfaces.td"
include "mlir/Interfaces/SideEffectInterfaces.td"

//===----------------------------------------------------------------------===//
// CIR Ops
//===----------------------------------------------------------------------===//

// LLVMLoweringInfo is used by cir-tablegen to generate LLVM lowering logic
// automatically for CIR operations. The `llvmOp` field gives the name of the
// LLVM IR dialect operation that the CIR operation will be lowered to. The
// input arguments of the CIR operation will be passed in the same order to the
// lowered LLVM IR operation.
//
// Example:
//
// For the following CIR operation definition:
//
// def FooOp : CIR_Op<"foo"> {
// // ...
// let arguments = (ins CIR_AnyType:$arg1, CIR_AnyType:$arg2);
// let llvmOp = "BarOp";
// }
//
// cir-tablegen will generate LLVM lowering code for the FooOp similar to the
// following:
//
// class CIRFooOpLowering
// : public mlir::OpConversionPattern<mlir::cir::FooOp> {
// public:
// using OpConversionPattern<mlir::cir::FooOp>::OpConversionPattern;
//
// mlir::LogicalResult matchAndRewrite(
// mlir::cir::FooOp op,
// OpAdaptor adaptor,
// mlir::ConversionPatternRewriter &rewriter) const override {
// rewriter.replaceOpWithNewOp<mlir::LLVM::BarOp>(
// op, adaptor.getOperands()[0], adaptor.getOperands()[1]);
// return mlir::success();
// }
// }
//
// If you want fully customized LLVM IR lowering logic, simply exclude the
// `llvmOp` field from your CIR operation definition.
class LLVMLoweringInfo {
string llvmOp = "";
}

class CIR_Op<string mnemonic, list<Trait> traits = []> :
Op<CIR_Dialect, mnemonic, traits>, LLVMLoweringInfo;

//===----------------------------------------------------------------------===//
// FuncOp
//===----------------------------------------------------------------------===//

// TODO(CIR): For starters, cir.func has only name, nothing else. The other
// properties of a function will be added over time as more of ClangIR is
// upstreamed.

def FuncOp : CIR_Op<"func"> {
let summary = "Declare or define a function";
let description = [{
... lots of text to be added later ...
}];

let arguments = (ins SymbolNameAttr:$sym_name);

let skipDefaultBuilders = 1;

let builders = [OpBuilder<(ins "StringRef":$name)>];

let hasCustomAssemblyFormat = 1;
let hasVerifier = 1;
}

#endif // LLVM_CLANG_CIR_DIALECT_IR_CIROPS
1 change: 1 addition & 0 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class SemaHLSL : public SemaBase {

// HLSL Type trait implementations
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
bool IsTypedResourceElementCompatible(QualType T1);

bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old);

Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ add_clang_library(clangAST
DeclOpenMP.cpp
DeclPrinter.cpp
DeclTemplate.cpp
DynamicRecursiveASTVisitor.cpp
ParentMapContext.cpp
Expr.cpp
ExprClassification.cpp
Expand Down
452 changes: 452 additions & 0 deletions clang/lib/AST/DynamicRecursiveASTVisitor.cpp

Large diffs are not rendered by default.

136 changes: 132 additions & 4 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/Basic/SourceManager.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"

#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Location.h"
Expand All @@ -24,9 +27,134 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &context,
clang::ASTContext &astctx,
const clang::CodeGenOptions &cgo,
DiagnosticsEngine &diags)
: astCtx(astctx), langOpts(astctx.getLangOpts()),
theModule{mlir::ModuleOp::create(mlir::UnknownLoc())},
target(astCtx.getTargetInfo()) {}
: builder(&context), astCtx(astctx), langOpts(astctx.getLangOpts()),
theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&context))},
diags(diags), target(astCtx.getTargetInfo()) {}

mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) {
assert(cLoc.isValid() && "expected valid source location");
const SourceManager &sm = astCtx.getSourceManager();
PresumedLoc pLoc = sm.getPresumedLoc(cLoc);
StringRef filename = pLoc.getFilename();
return mlir::FileLineColLoc::get(builder.getStringAttr(filename),
pLoc.getLine(), pLoc.getColumn());
}

mlir::Location CIRGenModule::getLoc(SourceRange cRange) {
assert(cRange.isValid() && "expected a valid source range");
mlir::Location begin = getLoc(cRange.getBegin());
mlir::Location end = getLoc(cRange.getEnd());
mlir::Attribute metadata;
return mlir::FusedLoc::get({begin, end}, metadata, builder.getContext());
}

void CIRGenModule::buildGlobal(clang::GlobalDecl gd) {
const auto *global = cast<ValueDecl>(gd.getDecl());

if (const auto *fd = dyn_cast<FunctionDecl>(global)) {
// Update deferred annotations with the latest declaration if the function
// was already used or defined.
if (fd->hasAttr<AnnotateAttr>())
errorNYI(fd->getSourceRange(), "deferredAnnotations");
if (!fd->doesThisDeclarationHaveABody()) {
if (!fd->doesDeclarationForceExternallyVisibleDefinition())
return;

errorNYI(fd->getSourceRange(),
"function declaration that forces code gen");
return;
}
} else {
errorNYI(global->getSourceRange(), "global variable declaration");
}

// TODO(CIR): Defer emitting some global definitions until later
buildGlobalDefinition(gd);
}

void CIRGenModule::buildGlobalFunctionDefinition(clang::GlobalDecl gd,
mlir::Operation *op) {
auto const *funcDecl = cast<FunctionDecl>(gd.getDecl());
auto funcOp = builder.create<mlir::cir::FuncOp>(
getLoc(funcDecl->getSourceRange()), funcDecl->getIdentifier()->getName());
theModule.push_back(funcOp);
}

void CIRGenModule::buildGlobalDefinition(clang::GlobalDecl gd,
mlir::Operation *op) {
const auto *decl = cast<ValueDecl>(gd.getDecl());
if (const auto *fd = dyn_cast<FunctionDecl>(decl)) {
// TODO(CIR): Skip generation of CIR for functions with available_externally
// linkage at -O0.

if (const auto *method = dyn_cast<CXXMethodDecl>(decl)) {
// Make sure to emit the definition(s) before we emit the thunks. This is
// necessary for the generation of certain thunks.
(void)method;
errorNYI(method->getSourceRange(), "member function");
return;
}

if (fd->isMultiVersion())
errorNYI(fd->getSourceRange(), "multiversion functions");
buildGlobalFunctionDefinition(gd, op);
return;
}

llvm_unreachable("Invalid argument to CIRGenModule::buildGlobalDefinition");
}

// Emit code for a single top level declaration.
void CIRGenModule::buildTopLevelDecl(Decl *decl) {}
void CIRGenModule::buildTopLevelDecl(Decl *decl) {

// Ignore dependent declarations.
if (decl->isTemplated())
return;

switch (decl->getKind()) {
default:
errorNYI(decl->getBeginLoc(), "declaration of kind",
decl->getDeclKindName());
break;

case Decl::Function: {
auto *fd = cast<FunctionDecl>(decl);
// Consteval functions shouldn't be emitted.
if (!fd->isConsteval())
buildGlobal(fd);
break;
}
}
}

DiagnosticBuilder CIRGenModule::errorNYI(llvm::StringRef feature) {
unsigned diagID = diags.getCustomDiagID(
DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0");
return diags.Report(diagID) << feature;
}

DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
llvm::StringRef feature) {
unsigned diagID = diags.getCustomDiagID(
DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0");
return diags.Report(loc, diagID) << feature;
}

DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
llvm::StringRef feature,
llvm::StringRef name) {
unsigned diagID = diags.getCustomDiagID(
DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0: %1");
return diags.Report(loc, diagID) << feature << name;
}

DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
llvm::StringRef feature) {
return errorNYI(loc.getBegin(), feature) << loc;
}

DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
llvm::StringRef feature,
llvm::StringRef name) {
return errorNYI(loc.getBegin(), feature, name) << loc;
}
34 changes: 34 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,21 @@

#include "CIRGenTypeCache.h"

#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/MLIRContext.h"
#include "llvm/ADT/StringRef.h"

namespace clang {
class ASTContext;
class CodeGenOptions;
class Decl;
class DiagnosticBuilder;
class DiagnosticsEngine;
class GlobalDecl;
class LangOptions;
class SourceLocation;
class SourceRange;
class TargetInfo;
} // namespace clang

Expand All @@ -44,6 +50,10 @@ class CIRGenModule : public CIRGenTypeCache {
~CIRGenModule() = default;

private:
// TODO(CIR) 'builder' will change to CIRGenBuilderTy once that type is
// defined
mlir::OpBuilder builder;

/// Hold Clang AST information.
clang::ASTContext &astCtx;

Expand All @@ -52,10 +62,34 @@ class CIRGenModule : public CIRGenTypeCache {
/// A "module" matches a c/cpp source file: containing a list of functions.
mlir::ModuleOp theModule;

clang::DiagnosticsEngine &diags;

const clang::TargetInfo &target;

public:
mlir::ModuleOp getModule() const { return theModule; }

/// Helpers to convert the presumed location of Clang's SourceLocation to an
/// MLIR Location.
mlir::Location getLoc(clang::SourceLocation cLoc);
mlir::Location getLoc(clang::SourceRange cRange);

void buildTopLevelDecl(clang::Decl *decl);

/// Emit code for a single global function or variable declaration. Forward
/// declarations are emitted lazily.
void buildGlobal(clang::GlobalDecl gd);

void buildGlobalDefinition(clang::GlobalDecl gd,
mlir::Operation *op = nullptr);
void buildGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op);

/// Helpers to emit "not yet implemented" error diagnostics
DiagnosticBuilder errorNYI(llvm::StringRef);
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef);
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef, llvm::StringRef);
DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef);
DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef, llvm::StringRef);
};
} // namespace cir

Expand Down
10 changes: 9 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@

#include "CIRGenModule.h"

#include "mlir/IR/MLIRContext.h"

#include "clang/AST/DeclGroup.h"
#include "clang/CIR/CIRGenerator.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"

using namespace cir;
using namespace clang;
Expand All @@ -31,9 +34,14 @@ void CIRGenerator::Initialize(ASTContext &astCtx) {

this->astCtx = &astCtx;

cgm = std::make_unique<CIRGenModule>(*mlirCtx, astCtx, codeGenOpts, diags);
mlirCtx = std::make_unique<mlir::MLIRContext>();
mlirCtx->loadDialect<mlir::cir::CIRDialect>();
cgm = std::make_unique<CIRGenModule>(*mlirCtx.get(), astCtx, codeGenOpts,
diags);
}

mlir::ModuleOp CIRGenerator::getModule() const { return cgm->getModule(); }

bool CIRGenerator::HandleTopLevelDecl(DeclGroupRef group) {

for (Decl *decl : group)
Expand Down
38 changes: 38 additions & 0 deletions clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//===- CIRAttrs.cpp - MLIR CIR Attributes ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the attributes in the CIR dialect.
//
//===----------------------------------------------------------------------===//

#include "clang/CIR/Dialect/IR/CIRDialect.h"

using namespace mlir;
using namespace mlir::cir;

//===----------------------------------------------------------------------===//
// General CIR parsing / printing
//===----------------------------------------------------------------------===//

Attribute CIRDialect::parseAttribute(DialectAsmParser &parser,
Type type) const {
// No attributes yet to parse
return Attribute{};
}

void CIRDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const {
// No attributes yet to print
}

//===----------------------------------------------------------------------===//
// CIR Dialect
//===----------------------------------------------------------------------===//

void CIRDialect::registerAttributes() {
// No attributes yet to register
}
55 changes: 54 additions & 1 deletion clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,57 @@
//
//===----------------------------------------------------------------------===//

#include <clang/CIR/Dialect/IR/CIRDialect.h>
#include "clang/CIR/Dialect/IR/CIRDialect.h"

#include "mlir/Support/LogicalResult.h"

#include "clang/CIR/Dialect/IR/CIROpsDialect.cpp.inc"

using namespace mlir;
using namespace mlir::cir;

//===----------------------------------------------------------------------===//
// CIR Dialect
//===----------------------------------------------------------------------===//

void mlir::cir::CIRDialect::initialize() {
registerTypes();
registerAttributes();
addOperations<
#define GET_OP_LIST
#include "clang/CIR/Dialect/IR/CIROps.cpp.inc"
>();
}

//===----------------------------------------------------------------------===//
// FuncOp
//===----------------------------------------------------------------------===//

void mlir::cir::FuncOp::build(OpBuilder &builder, OperationState &result,
StringRef name) {
result.addAttribute(SymbolTable::getSymbolAttrName(),
builder.getStringAttr(name));
}

ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
StringAttr nameAttr;
if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
state.attributes))
return failure();
return success();
}

void cir::FuncOp::print(OpAsmPrinter &p) {
p << ' ';
// For now the only property a function has is its name
p.printSymbolName(getSymName());
}

mlir::LogicalResult mlir::cir::FuncOp::verify() { return success(); }

//===----------------------------------------------------------------------===//
// TableGen'd op method definitions
//===----------------------------------------------------------------------===//

#define GET_OP_CLASSES
#include "clang/CIR/Dialect/IR/CIROps.cpp.inc"
37 changes: 37 additions & 0 deletions clang/lib/CIR/Dialect/IR/CIRTypes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//===- CIRTypes.cpp - MLIR CIR Types --------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the types in the CIR dialect.
//
//===----------------------------------------------------------------------===//

#include "clang/CIR/Dialect/IR/CIRDialect.h"

using namespace mlir;
using namespace mlir::cir;

//===----------------------------------------------------------------------===//
// General CIR parsing / printing
//===----------------------------------------------------------------------===//

Type CIRDialect::parseType(DialectAsmParser &parser) const {
// No types yet to parse
return Type{};
}

void CIRDialect::printType(Type type, DialectAsmPrinter &os) const {
// No types yet to print
}

//===----------------------------------------------------------------------===//
// CIR Dialect
//===----------------------------------------------------------------------===//

void CIRDialect::registerTypes() {
// No types yet to register
}
5 changes: 5 additions & 0 deletions clang/lib/CIR/Dialect/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
add_clang_library(MLIRCIR
CIRAttrs.cpp
CIRDialect.cpp
CIRTypes.cpp

LINK_LIBS PUBLIC
MLIRIR
)
41 changes: 40 additions & 1 deletion clang/lib/CIR/FrontendAction/CIRGenAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ class CIRGenConsumer : public clang::ASTConsumer {

virtual void anchor();

CIRGenAction::OutputType Action;

std::unique_ptr<raw_pwrite_stream> OutputStream;

ASTContext *Context{nullptr};
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
std::unique_ptr<CIRGenerator> Gen;

Expand All @@ -37,14 +40,37 @@ class CIRGenConsumer : public clang::ASTConsumer {
const LangOptions &LangOptions,
const FrontendOptions &FEOptions,
std::unique_ptr<raw_pwrite_stream> OS)
: OutputStream(std::move(OS)), FS(VFS),
: Action(Action), OutputStream(std::move(OS)), FS(VFS),
Gen(std::make_unique<CIRGenerator>(DiagnosticsEngine, std::move(VFS),
CodeGenOptions)) {}

void Initialize(ASTContext &Ctx) override {
assert(!Context && "initialized multiple times");
Context = &Ctx;
Gen->Initialize(Ctx);
}

bool HandleTopLevelDecl(DeclGroupRef D) override {
Gen->HandleTopLevelDecl(D);
return true;
}

void HandleTranslationUnit(ASTContext &C) override {
Gen->HandleTranslationUnit(C);
mlir::ModuleOp MlirModule = Gen->getModule();
switch (Action) {
case CIRGenAction::OutputType::EmitCIR:
if (OutputStream && MlirModule) {
mlir::OpPrintingFlags Flags;
Flags.enableDebugInfo(/*enable=*/true, /*prettyForm=*/false);
MlirModule->print(*OutputStream, Flags);
}
break;
default:
llvm_unreachable("NYI: CIRGenAction other than EmitCIR");
break;
}
}
};
} // namespace cir

Expand All @@ -55,10 +81,23 @@ CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx)

CIRGenAction::~CIRGenAction() { MLIRMod.release(); }

static std::unique_ptr<raw_pwrite_stream>
getOutputStream(CompilerInstance &CI, StringRef InFile,
CIRGenAction::OutputType Action) {
switch (Action) {
case CIRGenAction::OutputType::EmitCIR:
return CI.createDefaultOutputFile(false, InFile, "cir");
}
llvm_unreachable("Invalid CIRGenAction::OutputType");
}

std::unique_ptr<ASTConsumer>
CIRGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
std::unique_ptr<llvm::raw_pwrite_stream> Out = CI.takeOutputStream();

if (!Out)
Out = getOutputStream(CI, InFile, Action);

auto Result = std::make_unique<cir::CIRGenConsumer>(
Action, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
CI.getHeaderSearchOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(),
Expand Down
18 changes: 17 additions & 1 deletion clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18671,6 +18671,12 @@ Value *EmitAMDGPUGridSize(CodeGenFunction &CGF, unsigned Index) {
auto *GEP = CGF.Builder.CreateGEP(CGF.Int8Ty, DP, Offset);
auto *LD = CGF.Builder.CreateLoad(
Address(GEP, CGF.Int32Ty, CharUnits::fromQuantity(4)));

llvm::MDBuilder MDB(CGF.getLLVMContext());

// Known non-zero.
LD->setMetadata(llvm::LLVMContext::MD_range,
MDB.createRange(APInt(32, 1), APInt::getZero(32)));
LD->setMetadata(llvm::LLVMContext::MD_invariant_load,
llvm::MDNode::get(CGF.getLLVMContext(), {}));
return LD;
Expand Down Expand Up @@ -18855,7 +18861,17 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/T0->getScalarType(),
getDotProductIntrinsic(CGM.getHLSLRuntime(), VecTy0->getElementType()),
ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.dot");
} break;
}
case Builtin::BI__builtin_hlsl_dot4add_i8packed: {
Value *A = EmitScalarExpr(E->getArg(0));
Value *B = EmitScalarExpr(E->getArg(1));
Value *C = EmitScalarExpr(E->getArg(2));

Intrinsic::ID ID = CGM.getHLSLRuntime().getDot4AddI8PackedIntrinsic();
return Builder.CreateIntrinsic(
/*ReturnType=*/C->getType(), ID, ArrayRef<Value *>{A, B, C}, nullptr,
"hlsl.dot4add.i8packed");
}
case Builtin::BI__builtin_hlsl_lerp: {
Value *X = EmitScalarExpr(E->getArg(0));
Value *Y = EmitScalarExpr(E->getArg(1));
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class CGHLSLRuntime {
GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot)
GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot)
GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot)
GENERATE_HLSL_INTRINSIC_FUNCTION(Dot4AddI8Packed, dot4add_i8packed)
GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane)
GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane)

Expand Down
36 changes: 29 additions & 7 deletions clang/lib/CodeGen/Targets/NVPTX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "ABIInfoImpl.h"
#include "TargetInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/IntrinsicsNVPTX.h"

using namespace clang;
Expand Down Expand Up @@ -78,7 +79,13 @@ class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo {
// Adds a NamedMDNode with GV, Name, and Operand as operands, and adds the
// resulting MDNode to the nvvm.annotations MDNode.
static void addNVVMMetadata(llvm::GlobalValue *GV, StringRef Name,
int Operand);
int Operand,
const SmallVectorImpl<int> &GridConstantArgs);

static void addNVVMMetadata(llvm::GlobalValue *GV, StringRef Name,
int Operand) {
addNVVMMetadata(GV, Name, Operand, SmallVector<int, 1>(0));
}

private:
static void emitBuiltinSurfTexDeviceCopy(CodeGenFunction &CGF, LValue Dst,
Expand Down Expand Up @@ -240,7 +247,8 @@ void NVPTXTargetCodeGenInfo::setTargetAttributes(
}

const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
if (!FD) return;
if (!FD)
return;

llvm::Function *F = cast<llvm::Function>(GV);

Expand All @@ -263,8 +271,13 @@ void NVPTXTargetCodeGenInfo::setTargetAttributes(
// __global__ functions cannot be called from the device, we do not
// need to set the noinline attribute.
if (FD->hasAttr<CUDAGlobalAttr>()) {
SmallVector<int, 10> GCI;
for (auto IV : llvm::enumerate(FD->parameters()))
if (IV.value()->hasAttr<CUDAGridConstantAttr>())
// For some reason arg indices are 1-based in NVVM
GCI.push_back(IV.index() + 1);
// Create !{<func-ref>, metadata !"kernel", i32 1} node
addNVVMMetadata(F, "kernel", 1);
addNVVMMetadata(F, "kernel", 1, GCI);
}
if (CUDALaunchBoundsAttr *Attr = FD->getAttr<CUDALaunchBoundsAttr>())
M.handleCUDALaunchBoundsAttr(F, Attr);
Expand All @@ -276,18 +289,27 @@ void NVPTXTargetCodeGenInfo::setTargetAttributes(
}
}

void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::GlobalValue *GV,
StringRef Name, int Operand) {
void NVPTXTargetCodeGenInfo::addNVVMMetadata(
llvm::GlobalValue *GV, StringRef Name, int Operand,
const SmallVectorImpl<int> &GridConstantArgs) {
llvm::Module *M = GV->getParent();
llvm::LLVMContext &Ctx = M->getContext();

// Get "nvvm.annotations" metadata node
llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations");

llvm::Metadata *MDVals[] = {
SmallVector<llvm::Metadata *, 5> MDVals = {
llvm::ConstantAsMetadata::get(GV), llvm::MDString::get(Ctx, Name),
llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand))};
if (!GridConstantArgs.empty()) {
SmallVector<llvm::Metadata *, 10> GCM;
for (int I : GridConstantArgs)
GCM.push_back(llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), I)));
MDVals.append({llvm::MDString::get(Ctx, "grid_constant"),
llvm::MDNode::get(Ctx, GCM)});
}
// Append metadata to nvvm.annotations
MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
}
Expand All @@ -309,7 +331,7 @@ NVPTXTargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
return llvm::ConstantExpr::getAddrSpaceCast(
llvm::ConstantPointerNull::get(NPT), PT);
}
}
} // namespace

void CodeGenModule::handleCUDALaunchBoundsAttr(llvm::Function *F,
const CUDALaunchBoundsAttr *Attr,
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5358,6 +5358,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
} else if (JA.getType() == types::TY_RewrittenLegacyObjC) {
CmdArgs.push_back("-rewrite-objc");
rewriteKind = RK_Fragile;
} else if (JA.getType() == types::TY_CIR) {
CmdArgs.push_back("-emit-cir");
} else {
assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!");
}
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/PS4CPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,10 @@ void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-z");
CmdArgs.push_back("start-stop-visibility=hidden");

// DT_DEBUG is not supported on PlayStation.
CmdArgs.push_back("-z");
CmdArgs.push_back("rodynamic");

CmdArgs.push_back("-z");
CmdArgs.push_back("common-page-size=0x4000");

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/XRayArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
case llvm::Triple::systemz:
break;
default:
D.Diag(diag::err_drv_unsupported_opt_for_target)
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,16 @@ uint64_t dot(uint64_t3, uint64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint64_t dot(uint64_t4, uint64_t4);

//===----------------------------------------------------------------------===//
// dot4add builtins
//===----------------------------------------------------------------------===//

/// \fn int dot4add_i8packed(uint A, uint B, int C)

_HLSL_AVAILABILITY(shadermodel, 6.4)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot4add_i8packed)
int dot4add_i8packed(unsigned int, unsigned int, int);

//===----------------------------------------------------------------------===//
// exp builtins
//===----------------------------------------------------------------------===//
Expand Down
11 changes: 10 additions & 1 deletion clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12225,8 +12225,17 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
<< NewFD;
}

if (!Redeclaration && LangOpts.CUDA)
if (!Redeclaration && LangOpts.CUDA) {
bool IsKernel = NewFD->hasAttr<CUDAGlobalAttr>();
for (auto *Parm : NewFD->parameters()) {
if (!Parm->getType()->isDependentType() &&
Parm->hasAttr<CUDAGridConstantAttr>() &&
!(IsKernel && Parm->getType().isConstQualified()))
Diag(Parm->getAttr<CUDAGridConstantAttr>()->getLocation(),
diag::err_cuda_grid_constant_not_allowed);
}
CUDA().checkTargetOverload(NewFD, Previous);
}
}

// Check if the function definition uses any AArch64 SME features without
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4748,6 +4748,15 @@ static void handleManagedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(CUDADeviceAttr::CreateImplicit(S.Context));
}

static void handleGridConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (D->isInvalidDecl())
return;
// Whether __grid_constant__ is allowed to be used will be checked in
// Sema::CheckFunctionDeclaration as we need complete function decl to make
// the call.
D->addAttr(::new (S.Context) CUDAGridConstantAttr(S.Context, AL));
}

static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
const auto *Fn = cast<FunctionDecl>(D);
if (!Fn->isInlineSpecified()) {
Expand Down Expand Up @@ -6645,6 +6654,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_CUDADevice:
handleDeviceAttr(S, D, AL);
break;
case ParsedAttr::AT_CUDAGridConstant:
handleGridConstantAttr(S, D, AL);
break;
case ParsedAttr::AT_HIPManaged:
handleManagedAttr(S, D, AL);
break;
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5032,6 +5032,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_IsScalar:
case UTT_IsCompound:
case UTT_IsMemberPointer:
case UTT_IsTypedResourceElementCompatible:
// Fall-through

// These traits are modeled on type predicates in C++0x [meta.unary.prop]
Expand Down Expand Up @@ -5714,6 +5715,15 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
tok::kw___builtin_hlsl_is_intangible))
return false;
return T->isHLSLIntangibleType();

case UTT_IsTypedResourceElementCompatible:
assert(Self.getLangOpts().HLSL &&
"typed resource element compatible types are an HLSL-only feature");
if (Self.RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), T,
diag::err_incomplete_type))
return false;

return Self.HLSL().IsTypedResourceElementCompatible(T);
}
}

Expand Down
44 changes: 44 additions & 0 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2199,6 +2199,50 @@ static void BuildFlattenedTypeList(QualType BaseTy,
}
}

bool SemaHLSL::IsTypedResourceElementCompatible(clang::QualType QT) {
if (QT.isNull())
return false;

// check if the outer type was an array type
if (QT->isArrayType())
return false;

llvm::SmallVector<QualType, 4> QTTypes;
BuildFlattenedTypeList(QT, QTTypes);

assert(QTTypes.size() > 0 &&
"expected at least one constituent type from non-null type");
QualType FirstQT = SemaRef.Context.getCanonicalType(QTTypes[0]);

// element count cannot exceed 4
if (QTTypes.size() > 4)
return false;

for (QualType TempQT : QTTypes) {
// ensure homogeneity
if (!getASTContext().hasSameUnqualifiedType(FirstQT, TempQT))
return false;
}

if (const BuiltinType *BT = FirstQT->getAs<BuiltinType>()) {
if (BT->isBooleanType() || BT->isEnumeralType())
return false;

// Check if it is an array type.
if (FirstQT->isArrayType())
return false;
}

// if the loop above completes without returning, then
// we've guaranteed homogeneity
int TotalSizeInBytes =
(SemaRef.Context.getTypeSize(FirstQT) / 8) * QTTypes.size();
if (TotalSizeInBytes > 16)
return false;

return true;
}

bool SemaHLSL::IsScalarizedLayoutCompatible(QualType T1, QualType T2) const {
if (T1.isNull() || T2.isNull())
return false;
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,12 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}

if (auto *A = dyn_cast<CUDAGridConstantAttr>(TmplAttr)) {
if (!New->hasAttr<CUDAGridConstantAttr>())
New->addAttr(A->clone(Context));
continue;
}

assert(!TmplAttr->isPackExpansion());
if (TmplAttr->isLateParsed() && LateAttrs) {
// Late parsed attributes must be instantiated and attached after the
Expand Down
6 changes: 3 additions & 3 deletions clang/test/CIR/hello.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s | FileCheck --allow-empty %s
// Smoke test for ClangIR code generation
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s

// just confirm that we don't crash
// CHECK-NOT: *
void foo() {}
// CHECK: cir.func @foo
2 changes: 2 additions & 0 deletions clang/test/CodeGenCUDA/Inputs/cuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#define __managed__ __attribute__((managed))
#endif
#define __launch_bounds__(...) __attribute__((launch_bounds(__VA_ARGS__)))
#define __grid_constant__ __attribute__((grid_constant))
#else
#define __constant__
#define __device__
Expand All @@ -20,6 +21,7 @@
#define __shared__
#define __managed__
#define __launch_bounds__(...)
#define __grid_constant__
#endif

struct dim3 {
Expand Down
31 changes: 31 additions & 0 deletions clang/test/CodeGenCUDA/grid-constant.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --version 5
// RUN: %clang_cc1 "-triple" "nvptx64-nvidia-cuda" -emit-llvm -fcuda-is-device -o - %s | FileCheck %s

#include "Inputs/cuda.h"

struct S {};

__global__ void kernel(__grid_constant__ const S gc_arg1, int arg2, __grid_constant__ const int gc_arg3) {}

// dependent arguments get diagnosed after instantiation.
template <typename T>
__global__ void tkernel_const(__grid_constant__ const T arg) {}

template <typename T>
__global__ void tkernel(int dummy, __grid_constant__ T arg) {}

void foo() {
tkernel_const<const S><<<1,1>>>({});
tkernel_const<S><<<1,1>>>({});
tkernel<const S><<<1,1>>>(1, {});
}
//.
//.
// CHECK: [[META0:![0-9]+]] = !{ptr @_Z6kernel1Sii, !"kernel", i32 1, !"grid_constant", [[META1:![0-9]+]]}
// CHECK: [[META1]] = !{i32 1, i32 3}
// CHECK: [[META2:![0-9]+]] = !{ptr @_Z13tkernel_constIK1SEvT_, !"kernel", i32 1, !"grid_constant", [[META3:![0-9]+]]}
// CHECK: [[META3]] = !{i32 1}
// CHECK: [[META4:![0-9]+]] = !{ptr @_Z13tkernel_constI1SEvT_, !"kernel", i32 1, !"grid_constant", [[META3]]}
// CHECK: [[META5:![0-9]+]] = !{ptr @_Z7tkernelIK1SEviT_, !"kernel", i32 1, !"grid_constant", [[META6:![0-9]+]]}
// CHECK: [[META6]] = !{i32 2}
//.
17 changes: 17 additions & 0 deletions clang/test/CodeGenHLSL/builtins/dot4add_i8packed.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// RUN: %clang_cc1 -finclude-default-header -triple \
// RUN: dxil-pc-shadermodel6.3-compute %s -emit-llvm -disable-llvm-passes -o - | \
// RUN: FileCheck %s -DTARGET=dx
// RUN: %clang_cc1 -finclude-default-header -triple \
// RUN: spirv-pc-vulkan-compute %s -emit-llvm -disable-llvm-passes -o - | \
// RUN: FileCheck %s -DTARGET=spv

// Test basic lowering to runtime function call.

// CHECK-LABEL: test
int test(uint a, uint b, int c) {
// CHECK: %[[RET:.*]] = call [[TY:i32]] @llvm.[[TARGET]].dot4add.i8packed([[TY]] %[[#]], [[TY]] %[[#]], [[TY]] %[[#]])
// CHECK: ret [[TY]] %[[RET]]
return dot4add_i8packed(a, b, c);
}

// CHECK: declare [[TY]] @llvm.[[TARGET]].dot4add.i8packed([[TY]], [[TY]], [[TY]])
3 changes: 2 additions & 1 deletion clang/test/CodeGenOpenCL/builtins-amdgcn.cl
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ void test_get_workgroup_size(int d, global int *out)
// CHECK-LABEL: @test_get_grid_size(
// CHECK: {{.*}}call align 4 dereferenceable(64){{.*}} ptr addrspace(4) @llvm.amdgcn.dispatch.ptr()
// CHECK: getelementptr inbounds i8, ptr addrspace(4) %{{.*}}, i64 %{{.+}}
// CHECK: load i32, ptr addrspace(4) %{{.*}}, align 4, !invariant.load
// CHECK: load i32, ptr addrspace(4) %{{.*}}, align 4, !range [[$GRID_RANGE:![0-9]+]], !invariant.load
void test_get_grid_size(int d, global int *out)
{
switch (d) {
Expand Down Expand Up @@ -896,5 +896,6 @@ void test_set_fpenv(unsigned long env) {
__builtin_amdgcn_set_fpenv(env);
}

// CHECK-DAG: [[$GRID_RANGE]] = !{i32 1, i32 0}
// CHECK-DAG: [[$WS_RANGE]] = !{i16 1, i16 1025}
// CHECK-DAG: attributes #[[$NOUNWIND_READONLY]] = { convergent mustprogress nocallback nofree nounwind willreturn memory(none) }
2 changes: 2 additions & 0 deletions clang/test/Driver/XRay/xray-mode-flags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// RUN: | FileCheck --check-prefix=BASIC %s
// RUN: %clang -### --target=aarch64-linux-gnu -fxray-instrument %s 2>&1 \
// RUN: | FileCheck --check-prefixes=FDR,BASIC %s
// RUN: %clang -### --target=s390x-linux-gnu -fxray-instrument -fxray-modes=xray-basic %s 2>&1 \
// RUN: | FileCheck --check-prefix=BASIC %s
// RUN: %clang -### --target=x86_64-linux-gnu -fxray-instrument -fxray-modes=all %s 2>&1 \
// RUN: | FileCheck --check-prefixes=FDR,BASIC %s
// RUN: %clang -### --target=x86_64-linux-gnu -fxray-instrument -fxray-modes=xray-fdr,xray-basic %s 2>&1 \
Expand Down
1 change: 1 addition & 0 deletions clang/test/Driver/ps5-linker.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
// CHECK-EXE-SAME: "--unresolved-symbols=report-all"
// CHECK-EXE-SAME: "-z" "now"
// CHECK-EXE-SAME: "-z" "start-stop-visibility=hidden"
// CHECK-EXE-SAME: "-z" "rodynamic"
// CHECK-EXE-SAME: "-z" "common-page-size=0x4000"
// CHECK-EXE-SAME: "-z" "max-page-size=0x4000"
// CHECK-EXE-SAME: "-z" "dead-reloc-in-nonalloc=.debug_*=0xffffffffffffffff"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
// CHECK-NEXT: CUDADeviceBuiltinSurfaceType (SubjectMatchRule_record)
// CHECK-NEXT: CUDADeviceBuiltinTextureType (SubjectMatchRule_record)
// CHECK-NEXT: CUDAGlobal (SubjectMatchRule_function)
// CHECK-NEXT: CUDAGridConstant (SubjectMatchRule_variable_is_parameter)
// CHECK-NEXT: CUDAHost (SubjectMatchRule_function)
// CHECK-NEXT: CUDALaunchBounds (SubjectMatchRule_objc_method, SubjectMatchRule_hasType_functionType)
// CHECK-NEXT: CUDAShared (SubjectMatchRule_variable)
Expand Down
1 change: 1 addition & 0 deletions clang/test/SemaCUDA/Inputs/cuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define __host__ __attribute__((host))
#define __shared__ __attribute__((shared))
#define __managed__ __attribute__((managed))
#define __grid_constant__ __attribute__((grid_constant))
#define __launch_bounds__(...) __attribute__((launch_bounds(__VA_ARGS__)))

struct dim3 {
Expand Down
33 changes: 33 additions & 0 deletions clang/test/SemaCUDA/grid-constant.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -fcuda-is-device -verify %s
#include "Inputs/cuda.h"

struct S {};

__global__ void kernel_struct(__grid_constant__ const S arg) {}
__global__ void kernel_scalar(__grid_constant__ const int arg) {}

__global__ void gc_kernel_non_const(__grid_constant__ S arg) {} // expected-error {{__grid_constant__ is only allowed on const-qualified kernel parameters}}

void non_kernel(__grid_constant__ S arg) {} // expected-error {{__grid_constant__ is only allowed on const-qualified kernel parameters}}

// templates w/ non-dependent argument types get diagnosed right
// away, without instantiation.
template <typename T>
__global__ void tkernel_nd_const(__grid_constant__ const S arg, T dummy) {}
template <typename T>
__global__ void tkernel_nd_non_const(__grid_constant__ S arg, T dummy) {} // expected-error {{__grid_constant__ is only allowed on const-qualified kernel parameters}}

// dependent arguments get diagnosed after instantiation.
template <typename T>
__global__ void tkernel_const(__grid_constant__ const T arg) {}

template <typename T>
__global__ void tkernel(__grid_constant__ T arg) {} // expected-error {{__grid_constant__ is only allowed on const-qualified kernel parameters}}

void foo() {
tkernel_const<const S><<<1,1>>>({});
tkernel_const<S><<<1,1>>>({});
tkernel<const S><<<1,1>>>({});
tkernel<S><<<1,1>>>({}); // expected-note {{in instantiation of function template specialization 'tkernel<S>' requested here}}
}
28 changes: 28 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/dot4add_i8packed-errors.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only -disable-llvm-passes -verify

int test_too_few_arg0() {
return __builtin_hlsl_dot4add_i8packed();
// expected-error@-1 {{too few arguments to function call, expected 3, have 0}}
}

int test_too_few_arg1(int p0) {
return __builtin_hlsl_dot4add_i8packed(p0);
// expected-error@-1 {{too few arguments to function call, expected 3, have 1}}
}

int test_too_few_arg2(int p0) {
return __builtin_hlsl_dot4add_i8packed(p0, p0);
// expected-error@-1 {{too few arguments to function call, expected 3, have 2}}
}

int test_too_many_arg(int p0) {
return __builtin_hlsl_dot4add_i8packed(p0, p0, p0, p0);
// expected-error@-1 {{too many arguments to function call, expected 3, have 4}}
}

struct S { float f; };

int test_expr_struct_type_check(S p0, int p1) {
return __builtin_hlsl_dot4add_i8packed(p0, p1, p1);
// expected-error@-1 {{no viable conversion from 'S' to 'unsigned int'}}
}
109 changes: 109 additions & 0 deletions clang/test/SemaHLSL/Types/Traits/IsTypedResourceElementCompatible.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
// expected-no-diagnostics

struct oneInt {
int i;
};

struct twoInt {
int aa;
int ab;
};

struct threeInts {
oneInt o;
twoInt t;
};

struct oneFloat {
float f;
};
struct depthDiff {
int i;
oneInt o;
oneFloat f;
};

struct notHomogenous{
int i;
float f;
};

struct EightElements {
twoInt x[2];
twoInt y[2];
};

struct EightHalves {
half x[8];
};

struct intVec {
int2 i;
};

struct oneIntWithVec {
int i;
oneInt i2;
int2 i3;
};

struct weirdStruct {
int i;
intVec iv;
};

_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(int), "");
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(float), "");
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(float4), "");
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(double2), "");
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(oneInt), "");
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(oneFloat), "");
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(twoInt), "");
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(threeInts), "");
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(notHomogenous), "");
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(depthDiff), "");
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(EightElements), "");
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(EightHalves), "");
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(oneIntWithVec), "");
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(weirdStruct), "");
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(RWBuffer<int>), "");


// arrays not allowed
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(half[4]), "");

template<typename T> struct TemplatedBuffer {
T a;
__hlsl_resource_t h;
};
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(TemplatedBuffer<int>), "");

struct MyStruct1 : TemplatedBuffer<float> {
float x;
};
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(MyStruct1), "");

struct MyStruct2 {
const TemplatedBuffer<float> TB[10];
};
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(MyStruct2), "");

template<typename T> struct SimpleTemplate {
T a;
};

// though the element type is incomplete, the type trait should still technically return true
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(SimpleTemplate<__hlsl_resource_t>), "");

_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(SimpleTemplate<float>), "");


typedef int myInt;

struct TypeDefTest {
int x;
myInt y;
};

_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(TypeDefTest), "");
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s

// types must be complete
_Static_assert(__builtin_hlsl_is_typed_resource_element_compatible(__hlsl_resource_t), "");

// expected-note@+1{{forward declaration of 'notComplete'}}
struct notComplete;
// expected-error@+1{{incomplete type 'notComplete' where a complete type is required}}
_Static_assert(!__builtin_hlsl_is_typed_resource_element_compatible(notComplete), "");

5 changes: 1 addition & 4 deletions clang/tools/clang-refactor/TestSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,7 @@ findTestSelectionRanges(StringRef Filename) {
EndOffset = Offset;
}
TestSelectionRange Range = {Offset, EndOffset};
auto It = GroupedRanges.insert(std::make_pair(
Matches[1].str(), SmallVector<TestSelectionRange, 8>{Range}));
if (!It.second)
It.first->second.push_back(Range);
GroupedRanges[Matches[1].str()].push_back(Range);
}
if (GroupedRanges.empty()) {
llvm::errs() << "error: -selection=test:" << Filename
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ if(APPLE)
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM64})
else()
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64}
powerpc64le ${HEXAGON} ${LOONGARCH64})
powerpc64le ${HEXAGON} ${LOONGARCH64} ${S390X})
endif()
set(ALL_XRAY_DSO_SUPPORTED_ARCH ${X86_64})
set(ALL_SHADOWCALLSTACK_SUPPORTED_ARCH ${ARM64})
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/fuzzer/FuzzerExtFunctionsWindows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "FuzzerExtFunctions.h"
#include "FuzzerIO.h"
#include <stdlib.h>

using namespace fuzzer;

Expand Down
27 changes: 13 additions & 14 deletions compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,14 @@ int setcontext(const ucontext_t *ucp);

namespace __tsan {

// The non-barrier versions of OSAtomic* functions are semantically
// morder::relaxed, but the two variants (e.g. OSAtomicAdd32 and
// OSAtomicAdd32Barrier) are actually aliases of each other, and we cannot have
// different interceptors for them, because they're actually the same function.
// Thus, we have to stay conservative and treat the non-barrier versions as
// morder::acq_rel.
static constexpr morder kMacOrderBarrier = morder::acq_rel;
static constexpr morder kMacOrderNonBarrier = morder::acq_rel;
static constexpr morder kMacFailureOrder = morder::relaxed;
// The non-barrier versions of OSAtomic* functions are semantically mo_relaxed,
// but the two variants (e.g. OSAtomicAdd32 and OSAtomicAdd32Barrier) are
// actually aliases of each other, and we cannot have different interceptors for
// them, because they're actually the same function. Thus, we have to stay
// conservative and treat the non-barrier versions as mo_acq_rel.
static constexpr morder kMacOrderBarrier = mo_acq_rel;
static constexpr morder kMacOrderNonBarrier = mo_acq_rel;
static constexpr morder kMacFailureOrder = mo_relaxed;

# define OSATOMIC_INTERCEPTOR(return_t, t, tsan_t, f, tsan_atomic_f, mo) \
TSAN_INTERCEPTOR(return_t, f, t x, volatile t *ptr) { \
Expand Down Expand Up @@ -465,7 +464,7 @@ struct fake_shared_weak_count {
// Shared and weak pointers in C++ maintain reference counts via atomics in
// libc++.dylib, which are TSan-invisible, and this leads to false positives in
// destructor code. These interceptors re-implements the whole functions so that
// the morder::acq_rel semantics of the atomic decrement are visible.
// the mo_acq_rel semantics of the atomic decrement are visible.
//
// Unfortunately, the interceptors cannot simply Acquire/Release some sync
// object and call the original function, because it would have a race between
Expand All @@ -480,11 +479,11 @@ STDCXX_INTERCEPTOR(void, _ZNSt3__119__shared_weak_count16__release_sharedEv,

SCOPED_TSAN_INTERCEPTOR(_ZNSt3__119__shared_weak_count16__release_sharedEv,
o);
if (__tsan_atomic64_fetch_add(&o->shared_owners, -1, morder::release) == 0) {
if (__tsan_atomic64_fetch_add(&o->shared_owners, -1, mo_release) == 0) {
Acquire(thr, pc, (uptr)&o->shared_owners);
o->on_zero_shared();
if (__tsan_atomic64_fetch_add(&o->shared_weak_owners, -1,
morder::release) == 0) {
if (__tsan_atomic64_fetch_add(&o->shared_weak_owners, -1, mo_release) ==
0) {
Acquire(thr, pc, (uptr)&o->shared_weak_owners);
o->on_zero_shared_weak();
}
Expand All @@ -497,7 +496,7 @@ STDCXX_INTERCEPTOR(bool, _ZNSt3__114__shared_count16__release_sharedEv,
return REAL(_ZNSt3__114__shared_count16__release_sharedEv)(o);

SCOPED_TSAN_INTERCEPTOR(_ZNSt3__114__shared_count16__release_sharedEv, o);
if (__tsan_atomic64_fetch_add(&o->shared_owners, -1, morder::release) == 0) {
if (__tsan_atomic64_fetch_add(&o->shared_owners, -1, mo_release) == 0) {
Acquire(thr, pc, (uptr)&o->shared_owners);
o->on_zero_shared();
return true;
Expand Down
16 changes: 8 additions & 8 deletions compiler-rt/lib/tsan/rtl/tsan_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,14 @@ __extension__ typedef __int128 a128;

// Part of ABI, do not change.
// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic
enum class morder : int {
relaxed,
consume,
acquire,
release,
acq_rel,
seq_cst
};
typedef enum {
mo_relaxed,
mo_consume,
mo_acquire,
mo_release,
mo_acq_rel,
mo_seq_cst
} morder;

struct ThreadState;

Expand Down
214 changes: 99 additions & 115 deletions compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cpp

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions compiler-rt/lib/xray/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ set(hexagon_SOURCES
xray_trampoline_hexagon.S
)

set(s390x_SOURCES
xray_s390x.cpp
xray_trampoline_s390x.S
)
# Enable vector instructions in the assembly file.
set_source_files_properties(xray_trampoline_s390x.S PROPERTIES COMPILE_FLAGS -mvx)

set(XRAY_SOURCE_ARCHS
arm
armhf
Expand All @@ -102,6 +109,7 @@ set(XRAY_SOURCE_ARCHS
mips64
mips64el
powerpc64le
s390x
x86_64
)

Expand Down Expand Up @@ -152,6 +160,7 @@ set(XRAY_ALL_SOURCE_FILES
${mips64_SOURCES}
${mips64el_SOURCES}
${powerpc64le_SOURCES}
${s390x_SOURCES}
${XRAY_IMPL_HEADERS}
)
list(REMOVE_DUPLICATES XRAY_ALL_SOURCE_FILES)
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/xray/xray_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ static const int16_t cSledLength = 64;
static const int16_t cSledLength = 8;
#elif defined(__hexagon__)
static const int16_t cSledLength = 20;
#elif defined(__s390x__)
static const int16_t cSledLength = 18;
#else
#error "Unsupported CPU Architecture"
#endif /* CPU architecture */
Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/lib/xray/xray_interface_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ extern void __xray_FunctionTailExit();
extern void __xray_ArgLoggerEntry();
extern void __xray_CustomEvent();
extern void __xray_TypedEvent();
#if defined(__s390x__)
extern void __xray_FunctionEntryVec();
extern void __xray_FunctionExitVec();
#endif
}

extern "C" {
Expand Down
88 changes: 88 additions & 0 deletions compiler-rt/lib/xray/xray_s390x.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//===-- xray_s390x.cpp ------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of XRay, a dynamic runtime instrumentation system.
//
// Implementation of s390x routines.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_common.h"
#include "xray_defs.h"
#include "xray_interface_internal.h"
#include <cassert>
#include <cstring>

bool __xray::patchFunctionEntry(const bool Enable, uint32_t FuncId,
const XRaySledEntry &Sled,
void (*Trampoline)()) XRAY_NEVER_INSTRUMENT {
uint32_t *Address = reinterpret_cast<uint32_t *>(Sled.address());
if (Enable) {
// The resulting code is:
// stmg %r2, %r15, 16(%r15)
// llilf %2, FuncID
// brasl %r14, __xray_FunctionEntry@GOT
// The FuncId and the stmg instruction must be written.

// Write FuncId into llilf.
Address[2] = FuncId;
// Write last part of stmg.
reinterpret_cast<uint16_t *>(Address)[2] = 0x24;
// Write first part of stmg.
Address[0] = 0xeb2ff010;
} else {
// j +16 instructions.
Address[0] = 0xa7f4000b;
}
return true;
}

bool __xray::patchFunctionExit(const bool Enable, uint32_t FuncId,
const XRaySledEntry &Sled)
XRAY_NEVER_INSTRUMENT {
uint32_t *Address = reinterpret_cast<uint32_t *>(Sled.address());
if (Enable) {
// The resulting code is:
// stmg %r2, %r15, 24(%r15)
// llilf %2,FuncID
// j __xray_FunctionEntry@GOT
// The FuncId and the stmg instruction must be written.

// Write FuncId into llilf.
Address[2] = FuncId;
// Write last part of of stmg.
reinterpret_cast<uint16_t *>(Address)[2] = 0x24;
// Write first part of stmg.
Address[0] = 0xeb2ff010;
} else {
// br %14 instruction.
reinterpret_cast<uint16_t *>(Address)[0] = 0x07fe;
}
return true;
}

bool __xray::patchFunctionTailExit(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled)
XRAY_NEVER_INSTRUMENT {
return patchFunctionExit(Enable, FuncId, Sled);
}

bool __xray::patchCustomEvent(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
// TODO Implement.
return false;
}

bool __xray::patchTypedEvent(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
// TODO Implement.
return false;
}

extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT {
// TODO this will have to be implemented in the trampoline assembly file.
}
176 changes: 176 additions & 0 deletions compiler-rt/lib/xray/xray_trampoline_s390x.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
//===-- xray_trampoline_s390x.s ---------------------------------*- ASM -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of XRay, a dynamic runtime instrumentation system.
//
// This implements the s390x-specific assembler for the trampolines.
// 2 versions of the functions are provided: one which does not store the
// vector registers, and one which does store them. The compiler decides
// which to call based on the availability of the vector extension.
//
//===----------------------------------------------------------------------===//

.text

// Minimal stack frame size
#define STACKSZ 160

// Minimal stack frame size (160) plus space for 8 vector registers a 16 bytes.
#define STACKSZ_VEC 288

//===----------------------------------------------------------------------===//

.globl __xray_FunctionEntry
.p2align 4
.type __xray_FunctionEntry,@function
__xray_FunctionEntry:
# The registers r2-15 of the instrumented function are already saved in the
# stack frame. On entry, r2 contains the function id, and %r14 the address
# of the first instruction of the instrumented function.
# Register r14 will be stored in the slot reserved for compiler use.
stg %r14, 8(%r15)
std %f0, 128(%r15)
std %f2, 136(%r15)
std %f4, 144(%r15)
std %f6, 152(%r15)
aghi %r15, -STACKSZ

lgrl %r1, _ZN6__xray19XRayPatchedFunctionE@GOT
ltg %r1, 0(%r1)
je .Lrestore0

# Set r3 to XRayEntryType::ENTRY = 0.
# The FuncId is still stored in r2.
lghi %r3, 0
basr %r14, %r1

.Lrestore0:
ld %f6, STACKSZ+152(%r15)
ld %f4, STACKSZ+144(%r15)
ld %f2, STACKSZ+136(%r15)
ld %f0, STACKSZ+128(%r15)
lmg %r1, %r15, STACKSZ+8(%r15)
br %r1
.Lfunc_end0:
.size __xray_FunctionEntry, .Lfunc_end0-__xray_FunctionEntry

//===----------------------------------------------------------------------===//

.globl __xray_FunctionEntryVec
.p2align 4
.type __xray_FunctionEntryVec,@function
__xray_FunctionEntryVec:
# The registers r2-15 of the instrumented function are already saved in the
# stack frame. On entry, r2 contains the function id, and %r14 the address
# of the first instruction of the instrumented function.
# Register r14 will be stored in the slot reserved for compiler use.
stg %r14, 8(%r15)
std %f0, 128(%r15)
std %f2, 136(%r15)
std %f4, 144(%r15)
std %f6, 152(%r15)
aghi %r15, -STACKSZ_VEC
vstm %v24, %v31, 160(%r15)

lgrl %r1, _ZN6__xray19XRayPatchedFunctionE@GOT
ltg %r1, 0(%r1)
je .Lrestore1

# Set r3 to XRayEntryType::ENTRY = 0.
# The FuncId is still stored in r2.
lghi %r3, 0
basr %r14, %r1

.Lrestore1:
vlm %v24, %v31, 160(%r15)
ld %f6, STACKSZ_VEC+152(%r15)
ld %f4, STACKSZ_VEC+144(%r15)
ld %f2, STACKSZ_VEC+136(%r15)
ld %f0, STACKSZ_VEC+128(%r15)
lmg %r1, %r15, STACKSZ_VEC+8(%r15)
br %r1
.Lfunc_end1:
.size __xray_FunctionEntryVec, .Lfunc_end1-__xray_FunctionEntryVec

//===----------------------------------------------------------------------===//

.globl __xray_FunctionExit
.p2align 4
.type __xray_FunctionExit,@function
__xray_FunctionExit:
# The registers r2-15 of the instrumented function are already saved in the
# stack frame. On entry, the register r2 contains the function id.
# At the end, the function jumps to the address saved in the slot for r14,
# which contains the return address into the caller of the instrumented
# function.
std %f0, 128(%r15)
std %f2, 136(%r15)
std %f4, 144(%r15)
std %f6, 152(%r15)
aghi %r15, -STACKSZ

lgrl %r1, _ZN6__xray19XRayPatchedFunctionE@GOT
ltg %r1, 0(%r1)
je .Lrestore2

# Set r3 to XRayEntryType::EXIT = 1.
# The FuncId is still stored in r2.
lghi %r3, 1
basr %r14, %r1

.Lrestore2:
ld %f6, STACKSZ+152(%r15)
ld %f4, STACKSZ+144(%r15)
ld %f2, STACKSZ+136(%r15)
ld %f0, STACKSZ+128(%r15)
lmg %r2, %r15, STACKSZ+16(%r15)
br %r14
.Lfunc_end2:
.size __xray_FunctionExit, .Lfunc_end2-__xray_FunctionExit

//===----------------------------------------------------------------------===//

.globl __xray_FunctionExitVec
.p2align 4
.type __xray_FunctionExitVec,@function
__xray_FunctionExitVec:
# The registers r2-15 of the instrumented function are already saved in the
# stack frame. On entry, the register r2 contains the function id.
# At the end, the function jumps to the address saved in the slot for r14,
# which contains the return address into the caller of the instrumented
# function.
std %f0, 128(%r15)
std %f2, 136(%r15)
std %f4, 144(%r15)
std %f6, 152(%r15)
aghi %r15, -STACKSZ_VEC
vstm %v24, %v31, 160(%r15)

lgrl %r1, _ZN6__xray19XRayPatchedFunctionE@GOT
ltg %r1, 0(%r1)
je .Lrestore3

# Set r3 to XRayEntryType::EXIT = 1.
# The FuncId is still stored in r2.
lghi %r3, 1
basr %r14, %r1

.Lrestore3:
vlm %v24, %v31, 160(%r15)
ld %f6, STACKSZ_VEC+152(%r15)
ld %f4, STACKSZ_VEC+144(%r15)
ld %f2, STACKSZ_VEC+136(%r15)
ld %f0, STACKSZ_VEC+128(%r15)
lmg %r2, %r15, STACKSZ_VEC+16(%r15)
br %r14
.Lfunc_end3:
.size __xray_FunctionExit, .Lfunc_end3-__xray_FunctionExit

//===----------------------------------------------------------------------===//

.section ".note.GNU-stack","",@progbits
22 changes: 22 additions & 0 deletions compiler-rt/lib/xray/xray_tsc.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,28 @@ inline uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT {

} // namespace __xray

#elif defined(__s390x__)
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "xray_defs.h"
#include <cerrno>
#include <cstdint>
#include <time.h>

namespace __xray {

inline bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; }

ALWAYS_INLINE uint64_t readTSC(uint8_t &CPU) XRAY_NEVER_INSTRUMENT {
return __builtin_readcyclecounter();
}

inline uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT {
return NanosecondsPerSecond;
}

} // namespace __xray

#else
#error Target architecture is not supported.
#endif // CPU architecture
Expand Down
9 changes: 6 additions & 3 deletions flang/include/flang/Parser/preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class Definition {

bool set_isDisabled(bool disable);

TokenSequence Apply(const std::vector<TokenSequence> &args, Prescanner &);
TokenSequence Apply(const std::vector<TokenSequence> &args, Prescanner &,
bool inIfExpression = false);

void Print(llvm::raw_ostream &out, const char *macroName = "") const;

Expand Down Expand Up @@ -93,7 +94,8 @@ class Preprocessor {
// behavior.
std::optional<TokenSequence> MacroReplacement(const TokenSequence &,
Prescanner &,
std::optional<std::size_t> *partialFunctionLikeMacro = nullptr);
std::optional<std::size_t> *partialFunctionLikeMacro = nullptr,
bool inIfExpression = false);

// Implements a preprocessor directive.
void Directive(const TokenSequence &, Prescanner &);
Expand All @@ -106,7 +108,8 @@ class Preprocessor {

CharBlock SaveTokenAsName(const CharBlock &);
TokenSequence ReplaceMacros(const TokenSequence &, Prescanner &,
std::optional<std::size_t> *partialFunctionLikeMacro = nullptr);
std::optional<std::size_t> *partialFunctionLikeMacro = nullptr,
bool inIfExpression = false);
void SkipDisabledConditionalCode(
const std::string &, IsElseActive, Prescanner &, ProvenanceRange);
bool IsIfPredicateTrue(const TokenSequence &expr, std::size_t first,
Expand Down
1 change: 1 addition & 0 deletions flang/include/flang/Parser/token-sequence.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class TokenSequence {
}

std::size_t SkipBlanks(std::size_t) const;
std::optional<std::size_t> SkipBlanksBackwards(std::size_t) const;

// True if anything remains in the sequence at & after the given offset
// except blanks and line-ending C++ and Fortran free-form comments.
Expand Down
4 changes: 4 additions & 0 deletions flang/include/flang/Runtime/CUDA/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ void RTDECL(CUFDataTransferPtrDesc)(void *dst, Descriptor *src,
void RTDECL(CUFDataTransferDescDesc)(Descriptor *dst, Descriptor *src,
unsigned mode, const char *sourceFile = nullptr, int sourceLine = 0);

/// Data transfer from a descriptor to a descriptor.
void RTDECL(CUFDataTransferDescDescNoRealloc)(Descriptor *dst, Descriptor *src,
unsigned mode, const char *sourceFile = nullptr, int sourceLine = 0);

/// Data transfer from a descriptor to a global descriptor.
void RTDECL(CUFDataTransferGlobalDescDesc)(Descriptor *dst, Descriptor *src,
unsigned mode, const char *sourceFile = nullptr, int sourceLine = 0);
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Evaluate/fold-real.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
common::UsageWarning::FoldingException)) {
context.messages().Say(
common::UsageWarning::FoldingException,
"SCALE intrinsic folding overflow"_warn_en_US);
"SCALE/IEEE_SCALB intrinsic folding overflow"_warn_en_US);
}
return result.value;
}));
Expand Down
51 changes: 14 additions & 37 deletions flang/lib/Optimizer/Transforms/CUFOpConversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,50 +581,27 @@ struct CUFDataTransferOpConversion
builder.create<fir::CallOp>(loc, func, args);
rewriter.eraseOp(op);
} else {
// Type used to compute the width.
mlir::Type computeType = dstTy;
auto seqTy = mlir::dyn_cast<fir::SequenceType>(dstTy);
if (mlir::isa<fir::BaseBoxType>(dstTy)) {
computeType = srcTy;
seqTy = mlir::dyn_cast<fir::SequenceType>(srcTy);
}
int width = computeWidth(loc, computeType, kindMap);
// Transfer from a descriptor.

mlir::Value nbElement;
mlir::Type idxTy = rewriter.getIndexType();
if (!op.getShape()) {
nbElement = rewriter.create<mlir::arith::ConstantOp>(
loc, idxTy,
rewriter.getIntegerAttr(idxTy, seqTy.getConstantArraySize()));
} else {
auto shapeOp =
mlir::dyn_cast<fir::ShapeOp>(op.getShape().getDefiningOp());
nbElement =
createConvertOp(rewriter, loc, idxTy, shapeOp.getExtents()[0]);
for (unsigned i = 1; i < shapeOp.getExtents().size(); ++i) {
auto operand =
createConvertOp(rewriter, loc, idxTy, shapeOp.getExtents()[i]);
nbElement =
rewriter.create<mlir::arith::MulIOp>(loc, nbElement, operand);
}
}
mlir::Value addr = getDeviceAddress(rewriter, op.getDstMutable(), symtab);
mlir::Type boxTy = fir::BoxType::get(dstTy);
llvm::SmallVector<mlir::Value> lenParams;
mlir::Value box =
builder.createBox(loc, boxTy, addr, getShapeFromDecl(op.getDst()),
/*slice=*/nullptr, lenParams,
/*tdesc=*/nullptr);
mlir::Value memBox = builder.createTemporary(loc, box.getType());
builder.create<fir::StoreOp>(loc, box, memBox);

mlir::Value widthValue = rewriter.create<mlir::arith::ConstantOp>(
loc, idxTy, rewriter.getIntegerAttr(idxTy, width));
mlir::Value bytes =
rewriter.create<mlir::arith::MulIOp>(loc, nbElement, widthValue);
mlir::func::FuncOp func = fir::runtime::getRuntimeFunc<mkRTKey(
CUFDataTransferDescDescNoRealloc)>(loc, builder);

mlir::func::FuncOp func =
fir::runtime::getRuntimeFunc<mkRTKey(CUFDataTransferPtrDesc)>(
loc, builder);
auto fTy = func.getFunctionType();
mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
mlir::Value sourceLine =
fir::factory::locationToLineNo(builder, loc, fTy.getInput(5));
mlir::Value dst = op.getDst();
mlir::Value src = op.getSrc();
fir::factory::locationToLineNo(builder, loc, fTy.getInput(4));
llvm::SmallVector<mlir::Value> args{
fir::runtime::createArguments(builder, loc, fTy, dst, src, bytes,
fir::runtime::createArguments(builder, loc, fTy, memBox, op.getSrc(),
modeValue, sourceFile, sourceLine)};
builder.create<fir::CallOp>(loc, func, args);
rewriter.eraseOp(op);
Expand Down
65 changes: 58 additions & 7 deletions flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,17 @@ DebugTypeGenerator::DebugTypeGenerator(mlir::ModuleOp m,
mlir::Type llvmDimsType = getDescFieldTypeModel<kDimsPosInBox>()(context);
mlir::Type llvmPtrType = getDescFieldTypeModel<kAddrPosInBox>()(context);
mlir::Type llvmLenType = getDescFieldTypeModel<kElemLenPosInBox>()(context);
mlir::Type llvmRankType = getDescFieldTypeModel<kRankPosInBox>()(context);

dimsOffset =
getComponentOffset<kDimsPosInBox>(*dataLayout, context, llvmDimsType);
dimsSize = dataLayout->getTypeSize(llvmDimsType);
ptrSize = dataLayout->getTypeSize(llvmPtrType);
rankSize = dataLayout->getTypeSize(llvmRankType);
lenOffset =
getComponentOffset<kElemLenPosInBox>(*dataLayout, context, llvmLenType);
rankOffset =
getComponentOffset<kRankPosInBox>(*dataLayout, context, llvmRankType);
}

static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context,
Expand Down Expand Up @@ -114,10 +119,7 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType(
bool genAllocated, bool genAssociated) {

mlir::MLIRContext *context = module.getContext();
// FIXME: Assumed rank arrays not supported yet
if (seqTy.hasUnknownShape())
return genPlaceholderType(context);

llvm::SmallVector<mlir::LLVM::DINodeAttr> elements;
llvm::SmallVector<mlir::LLVM::DIExpressionElemAttr> ops;
auto addOp = [&](unsigned opc, llvm::ArrayRef<uint64_t> vals) {
ops.push_back(mlir::LLVM::DIExpressionElemAttr::get(context, opc, vals));
Expand All @@ -129,6 +131,58 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType(
// dataLocation = *base_addr
mlir::LLVM::DIExpressionAttr dataLocation =
mlir::LLVM::DIExpressionAttr::get(context, ops);
ops.clear();

mlir::LLVM::DITypeAttr elemTy =
convertType(seqTy.getEleTy(), fileAttr, scope, declOp);

// Assumed-rank arrays
if (seqTy.hasUnknownShape()) {
addOp(llvm::dwarf::DW_OP_push_object_address, {});
addOp(llvm::dwarf::DW_OP_plus_uconst, {rankOffset});
addOp(llvm::dwarf::DW_OP_deref_size, {rankSize});
mlir::LLVM::DIExpressionAttr rank =
mlir::LLVM::DIExpressionAttr::get(context, ops);
ops.clear();

auto genSubrangeOp = [&](unsigned field) -> mlir::LLVM::DIExpressionAttr {
// The dwarf expression for generic subrange assumes that dimension for
// which it is being generated is already pushed on the stack. Here is the
// formula we will use to calculate count for example.
// *(base_addr + offset_count_0 + (dimsSize x dimension_number)).
// where offset_count_0 is offset of the count field for the 0th dimension
addOp(llvm::dwarf::DW_OP_push_object_address, {});
addOp(llvm::dwarf::DW_OP_over, {});
addOp(llvm::dwarf::DW_OP_constu, {dimsSize});
addOp(llvm::dwarf::DW_OP_mul, {});
addOp(llvm::dwarf::DW_OP_plus_uconst,
{dimsOffset + ((dimsSize / 3) * field)});
addOp(llvm::dwarf::DW_OP_plus, {});
addOp(llvm::dwarf::DW_OP_deref, {});
mlir::LLVM::DIExpressionAttr attr =
mlir::LLVM::DIExpressionAttr::get(context, ops);
ops.clear();
return attr;
};

mlir::LLVM::DIExpressionAttr lowerAttr = genSubrangeOp(kDimLowerBoundPos);
mlir::LLVM::DIExpressionAttr countAttr = genSubrangeOp(kDimExtentPos);
mlir::LLVM::DIExpressionAttr strideAttr = genSubrangeOp(kDimStridePos);

auto subrangeTy = mlir::LLVM::DIGenericSubrangeAttr::get(
context, countAttr, lowerAttr, /*upperBound=*/nullptr, strideAttr);
elements.push_back(subrangeTy);

return mlir::LLVM::DICompositeTypeAttr::get(
context, llvm::dwarf::DW_TAG_array_type, /*name=*/nullptr,
/*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy,
mlir::LLVM::DIFlags::Zero, /*sizeInBits=*/0, /*alignInBits=*/0,
elements, dataLocation, rank, /*allocated=*/nullptr,
/*associated=*/nullptr);
}

addOp(llvm::dwarf::DW_OP_push_object_address, {});
addOp(llvm::dwarf::DW_OP_deref, {});
addOp(llvm::dwarf::DW_OP_lit0, {});
addOp(llvm::dwarf::DW_OP_ne, {});

Expand All @@ -139,9 +193,6 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType(
mlir::LLVM::DIExpressionAttr associated = genAssociated ? valid : nullptr;
ops.clear();

llvm::SmallVector<mlir::LLVM::DINodeAttr> elements;
mlir::LLVM::DITypeAttr elemTy =
convertType(seqTy.getEleTy(), fileAttr, scope, declOp);
unsigned offset = dimsOffset;
unsigned index = 0;
mlir::IntegerType intTy = mlir::IntegerType::get(context, 64);
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/Optimizer/Transforms/DebugTypeGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ class DebugTypeGenerator {
std::uint64_t dimsOffset;
std::uint64_t ptrSize;
std::uint64_t lenOffset;
std::uint64_t rankOffset;
std::uint64_t rankSize;
llvm::DenseMap<mlir::Type, mlir::LLVM::DITypeAttr> typeCache;
};

Expand Down
116 changes: 61 additions & 55 deletions flang/lib/Parser/preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,13 @@ static TokenSequence TokenPasting(TokenSequence &&text) {
return result;
}

TokenSequence Definition::Apply(
const std::vector<TokenSequence> &args, Prescanner &prescanner) {
constexpr bool IsDefinedKeyword(CharBlock token) {
return token.size() == 7 && (token[0] == 'd' || token[0] == 'D') &&
ToLowerCaseLetters(token.ToString()) == "defined";
}

TokenSequence Definition::Apply(const std::vector<TokenSequence> &args,
Prescanner &prescanner, bool inIfExpression) {
TokenSequence result;
bool skipping{false};
int parenthesesNesting{0};
Expand Down Expand Up @@ -223,13 +228,16 @@ TokenSequence Definition::Apply(
const TokenSequence *arg{&args[index]};
std::optional<TokenSequence> replaced;
// Don't replace macros in the actual argument if it is preceded or
// followed by the token-pasting operator ## in the replacement text.
if (prev == 0 || !IsTokenPasting(replacement_.TokenAt(prev - 1))) {
// followed by the token-pasting operator ## in the replacement text,
// or if we have to worry about "defined(X)"/"defined X" in an
// #if/#elif expression.
if (!inIfExpression &&
(prev == 0 || !IsTokenPasting(replacement_.TokenAt(prev - 1)))) {
auto next{replacement_.SkipBlanks(j + 1)};
if (next >= tokens || !IsTokenPasting(replacement_.TokenAt(next))) {
// Apply macro replacement to the actual argument
replaced =
prescanner.preprocessor().MacroReplacement(*arg, prescanner);
replaced = prescanner.preprocessor().MacroReplacement(
*arg, prescanner, nullptr, inIfExpression);
if (replaced) {
arg = &*replaced;
}
Expand Down Expand Up @@ -301,7 +309,7 @@ void Preprocessor::Undefine(std::string macro) { definitions_.erase(macro); }

std::optional<TokenSequence> Preprocessor::MacroReplacement(
const TokenSequence &input, Prescanner &prescanner,
std::optional<std::size_t> *partialFunctionLikeMacro) {
std::optional<std::size_t> *partialFunctionLikeMacro, bool inIfExpression) {
// Do quick scan for any use of a defined name.
if (definitions_.empty()) {
return std::nullopt;
Expand All @@ -311,7 +319,7 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
for (; j < tokens; ++j) {
CharBlock token{input.TokenAt(j)};
if (!token.empty() && IsLegalIdentifierStart(token[0]) &&
IsNameDefined(token)) {
(IsNameDefined(token) || (inIfExpression && IsDefinedKeyword(token)))) {
break;
}
}
Expand All @@ -326,17 +334,17 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
// replacement text and attempt to proceed. Otherwise, return, so that
// the caller may try again with remaining tokens in its input.
auto CompleteFunctionLikeMacro{
[this, &input, &prescanner, &result, &partialFunctionLikeMacro](
std::size_t after, const TokenSequence &replacement,
[this, &input, &prescanner, &result, &partialFunctionLikeMacro,
inIfExpression](std::size_t after, const TokenSequence &replacement,
std::size_t pFLMOffset) {
if (after < input.SizeInTokens()) {
result.Put(replacement, 0, pFLMOffset);
TokenSequence suffix;
suffix.Put(
replacement, pFLMOffset, replacement.SizeInTokens() - pFLMOffset);
suffix.Put(input, after, input.SizeInTokens() - after);
auto further{
ReplaceMacros(suffix, prescanner, partialFunctionLikeMacro)};
auto further{ReplaceMacros(
suffix, prescanner, partialFunctionLikeMacro, inIfExpression)};
if (partialFunctionLikeMacro && *partialFunctionLikeMacro) {
// still not closed
**partialFunctionLikeMacro += result.SizeInTokens();
Expand All @@ -357,7 +365,28 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
result.Put(input, j);
continue;
}
// Process identifier in replacement text.
auto it{definitions_.find(token)};
// Is in the X in "defined(X)" or "defined X" in an #if/#elif expression?
if (inIfExpression) {
if (auto prev{result.SkipBlanksBackwards(result.SizeInTokens())}) {
bool ok{true};
std::optional<std::size_t> rightParenthesis;
if (result.TokenAt(*prev).OnlyNonBlank() == '(') {
prev = result.SkipBlanksBackwards(*prev);
rightParenthesis = input.SkipBlanks(j + 1);
ok = *rightParenthesis < tokens &&
input.TokenAt(*rightParenthesis).OnlyNonBlank() == ')';
}
if (ok && prev && IsDefinedKeyword(result.TokenAt(*prev))) {
result = TokenSequence{result, 0, *prev}; // trims off "defined ("
char truth{it != definitions_.end() ? '1' : '0'};
result.Put(&truth, 1, allSources_.CompilerInsertionProvenance(truth));
j = rightParenthesis.value_or(j);
continue;
}
}
}
if (it == definitions_.end()) {
result.Put(input, j);
continue;
Expand Down Expand Up @@ -403,8 +432,8 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
}
std::optional<std::size_t> partialFLM;
def->set_isDisabled(true);
TokenSequence replaced{TokenPasting(
ReplaceMacros(def->replacement(), prescanner, &partialFLM))};
TokenSequence replaced{TokenPasting(ReplaceMacros(
def->replacement(), prescanner, &partialFLM, inIfExpression))};
def->set_isDisabled(false);
if (partialFLM &&
CompleteFunctionLikeMacro(j + 1, replaced, *partialFLM)) {
Expand Down Expand Up @@ -476,11 +505,11 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
(n + 1 == argStart.size() ? k : argStart[n + 1] - 1) - at};
args.emplace_back(TokenSequence(input, at, count));
}
TokenSequence applied{def->Apply(args, prescanner)};
TokenSequence applied{def->Apply(args, prescanner, inIfExpression)};
std::optional<std::size_t> partialFLM;
def->set_isDisabled(true);
TokenSequence replaced{
ReplaceMacros(std::move(applied), prescanner, &partialFLM)};
TokenSequence replaced{ReplaceMacros(
std::move(applied), prescanner, &partialFLM, inIfExpression)};
def->set_isDisabled(false);
if (partialFLM &&
CompleteFunctionLikeMacro(k + 1, replaced, *partialFLM)) {
Expand All @@ -501,9 +530,9 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(

TokenSequence Preprocessor::ReplaceMacros(const TokenSequence &tokens,
Prescanner &prescanner,
std::optional<std::size_t> *partialFunctionLikeMacro) {
if (std::optional<TokenSequence> repl{
MacroReplacement(tokens, prescanner, partialFunctionLikeMacro)}) {
std::optional<std::size_t> *partialFunctionLikeMacro, bool inIfExpression) {
if (std::optional<TokenSequence> repl{MacroReplacement(
tokens, prescanner, partialFunctionLikeMacro, inIfExpression)}) {
return std::move(*repl);
}
return tokens;
Expand Down Expand Up @@ -1215,50 +1244,27 @@ static std::int64_t ExpressionValue(const TokenSequence &token,
return left;
}

bool Preprocessor::IsIfPredicateTrue(const TokenSequence &expr,
bool Preprocessor::IsIfPredicateTrue(const TokenSequence &directive,
std::size_t first, std::size_t exprTokens, Prescanner &prescanner) {
TokenSequence expr1{expr, first, exprTokens};
if (expr1.HasBlanks()) {
expr1.RemoveBlanks();
}
TokenSequence expr2;
for (std::size_t j{0}; j < expr1.SizeInTokens(); ++j) {
if (ToLowerCaseLetters(expr1.TokenAt(j).ToString()) == "defined") {
CharBlock name;
if (j + 3 < expr1.SizeInTokens() &&
expr1.TokenAt(j + 1).OnlyNonBlank() == '(' &&
expr1.TokenAt(j + 3).OnlyNonBlank() == ')') {
name = expr1.TokenAt(j + 2);
j += 3;
} else if (j + 1 < expr1.SizeInTokens() &&
IsLegalIdentifierStart(expr1.TokenAt(j + 1))) {
name = expr1.TokenAt(++j);
}
if (!name.empty()) {
char truth{IsNameDefined(name) ? '1' : '0'};
expr2.Put(&truth, 1, allSources_.CompilerInsertionProvenance(truth));
continue;
}
}
expr2.Put(expr1, j);
}
TokenSequence expr3{ReplaceMacros(expr2, prescanner)};
if (expr3.HasBlanks()) {
expr3.RemoveBlanks();
TokenSequence expr{directive, first, exprTokens};
TokenSequence replaced{
ReplaceMacros(expr, prescanner, nullptr, /*inIfExpression=*/true)};
if (replaced.HasBlanks()) {
replaced.RemoveBlanks();
}
if (expr3.empty()) {
if (replaced.empty()) {
prescanner.Say(expr.GetProvenanceRange(), "empty expression"_err_en_US);
return false;
}
std::size_t atToken{0};
std::optional<Message> error;
bool result{ExpressionValue(expr3, 0, &atToken, &error) != 0};
bool result{ExpressionValue(replaced, 0, &atToken, &error) != 0};
if (error) {
prescanner.Say(std::move(*error));
} else if (atToken < expr3.SizeInTokens() &&
expr3.TokenAt(atToken).ToString() != "!") {
prescanner.Say(expr3.GetIntervalProvenanceRange(
atToken, expr3.SizeInTokens() - atToken),
} else if (atToken < replaced.SizeInTokens() &&
replaced.TokenAt(atToken).ToString() != "!") {
prescanner.Say(replaced.GetIntervalProvenanceRange(
atToken, replaced.SizeInTokens() - atToken),
atToken == 0 ? "could not parse any expression"_err_en_US
: "excess characters after expression"_err_en_US);
}
Expand Down
10 changes: 10 additions & 0 deletions flang/lib/Parser/token-sequence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ std::size_t TokenSequence::SkipBlanks(std::size_t at) const {
return tokens; // even if at > tokens
}

std::optional<std::size_t> TokenSequence::SkipBlanksBackwards(
std::size_t at) const {
while (at-- > 0) {
if (!TokenAt(at).IsBlank()) {
return at;
}
}
return std::nullopt;
}

// C-style /*comments*/ are removed from preprocessing directive
// token sequences by the prescanner, but not C++ or Fortran
// free-form line-ending comments (//... and !...) because
Expand Down
18 changes: 13 additions & 5 deletions flang/lib/Semantics/check-omp-structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2687,11 +2687,19 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Destroy &x) {
llvm::omp::Directive dir{GetContext().directive};
unsigned version{context_.langOptions().OpenMPVersion};
if (dir == llvm::omp::Directive::OMPD_depobj) {
if (version < 52) {
context_.Say(GetContext().clauseSource,
"The object parameter in DESTROY clause in DEPOPJ construct "
"was introduced in %s"_port_en_US,
ThisVersion(52));
unsigned argSince{52}, noargDeprecatedIn{52};
if (x.v) {
if (version < argSince) {
context_.Say(GetContext().clauseSource,
"The object parameter in DESTROY clause on DEPOPJ construct is not allowed in %s, %s"_warn_en_US,
ThisVersion(version), TryVersion(argSince));
}
} else {
if (version >= noargDeprecatedIn) {
context_.Say(GetContext().clauseSource,
"The DESTROY clause without argument on DEPOBJ construct is deprecated in %s"_warn_en_US,
ThisVersion(noargDeprecatedIn));
}
}
}
}
Expand Down
78 changes: 53 additions & 25 deletions flang/lib/Semantics/rewrite-parse-tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,11 @@ class RewriteMutator {
template <typename T> void Post(T &) {}

void Post(parser::Name &);
void Post(parser::SpecificationPart &);
bool Pre(parser::ExecutionPart &);
bool Pre(parser::MainProgram &);
bool Pre(parser::FunctionSubprogram &);
bool Pre(parser::SubroutineSubprogram &);
bool Pre(parser::SeparateModuleSubprogram &);
bool Pre(parser::BlockConstruct &);
bool Pre(parser::ActionStmt &);
void Post(parser::ReadStmt &);
void Post(parser::WriteStmt &);
Expand All @@ -65,12 +68,11 @@ class RewriteMutator {
bool Pre(parser::EndTypeStmt &) { return false; }

private:
using stmtFuncType =
parser::Statement<common::Indirection<parser::StmtFunctionStmt>>;
void FixMisparsedStmtFuncs(parser::SpecificationPart &, parser::Block &);

SemanticsContext &context_;
bool errorOnUnresolvedName_{true};
parser::Messages &messages_;
std::list<stmtFuncType> stmtFuncsToConvert_;
};

// Check that name has been resolved to a symbol
Expand All @@ -94,41 +96,67 @@ static bool ReturnsDataPointer(const Symbol &symbol) {
return false;
}

// Find mis-parsed statement functions and move to stmtFuncsToConvert_ list.
void RewriteMutator::Post(parser::SpecificationPart &x) {
auto &list{std::get<std::list<parser::DeclarationConstruct>>(x.t)};
// Finds misparsed statement functions in a specification part, rewrites
// them into array element assignment statements, and moves them into the
// beginning of the corresponding (execution part's) block.
void RewriteMutator::FixMisparsedStmtFuncs(
parser::SpecificationPart &specPart, parser::Block &block) {
auto &list{std::get<std::list<parser::DeclarationConstruct>>(specPart.t)};
auto origFirst{block.begin()}; // insert each elem before origFirst
for (auto it{list.begin()}; it != list.end();) {
bool isAssignment{false};
if (auto *stmt{std::get_if<stmtFuncType>(&it->u)}) {
bool convert{false};
if (auto *stmt{std::get_if<
parser::Statement<common::Indirection<parser::StmtFunctionStmt>>>(
&it->u)}) {
if (const Symbol *
symbol{std::get<parser::Name>(stmt->statement.value().t).symbol}) {
const Symbol &ultimate{symbol->GetUltimate()};
isAssignment =
convert =
ultimate.has<ObjectEntityDetails>() || ReturnsDataPointer(ultimate);
if (isAssignment) {
stmtFuncsToConvert_.emplace_back(std::move(*stmt));
if (convert) {
auto newStmt{stmt->statement.value().ConvertToAssignment()};
newStmt.source = stmt->source;
block.insert(origFirst,
parser::ExecutionPartConstruct{
parser::ExecutableConstruct{std::move(newStmt)}});
}
}
}
if (isAssignment) {
if (convert) {
it = list.erase(it);
} else {
++it;
}
}
}

// Insert converted assignments at start of ExecutionPart.
bool RewriteMutator::Pre(parser::ExecutionPart &x) {
auto origFirst{x.v.begin()}; // insert each elem before origFirst
for (stmtFuncType &sf : stmtFuncsToConvert_) {
auto stmt{sf.statement.value().ConvertToAssignment()};
stmt.source = sf.source;
x.v.insert(origFirst,
parser::ExecutionPartConstruct{
parser::ExecutableConstruct{std::move(stmt)}});
}
stmtFuncsToConvert_.clear();
bool RewriteMutator::Pre(parser::MainProgram &program) {
FixMisparsedStmtFuncs(std::get<parser::SpecificationPart>(program.t),
std::get<parser::ExecutionPart>(program.t).v);
return true;
}

bool RewriteMutator::Pre(parser::FunctionSubprogram &func) {
FixMisparsedStmtFuncs(std::get<parser::SpecificationPart>(func.t),
std::get<parser::ExecutionPart>(func.t).v);
return true;
}

bool RewriteMutator::Pre(parser::SubroutineSubprogram &subr) {
FixMisparsedStmtFuncs(std::get<parser::SpecificationPart>(subr.t),
std::get<parser::ExecutionPart>(subr.t).v);
return true;
}

bool RewriteMutator::Pre(parser::SeparateModuleSubprogram &subp) {
FixMisparsedStmtFuncs(std::get<parser::SpecificationPart>(subp.t),
std::get<parser::ExecutionPart>(subp.t).v);
return true;
}

bool RewriteMutator::Pre(parser::BlockConstruct &block) {
FixMisparsedStmtFuncs(std::get<parser::BlockSpecificationPart>(block.t).v,
std::get<parser::Block>(block.t));
return true;
}

Expand Down
18 changes: 18 additions & 0 deletions flang/runtime/CUDA/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,24 @@ void RTDECL(CUFDataTransferDescDesc)(Descriptor *dstDesc, Descriptor *srcDesc,
*dstDesc, *srcDesc, terminator, MaybeReallocate, memmoveFct);
}

void RTDECL(CUFDataTransferDescDescNoRealloc)(Descriptor *dstDesc,
Descriptor *srcDesc, unsigned mode, const char *sourceFile,
int sourceLine) {
MemmoveFct memmoveFct;
Terminator terminator{sourceFile, sourceLine};
if (mode == kHostToDevice) {
memmoveFct = &MemmoveHostToDevice;
} else if (mode == kDeviceToHost) {
memmoveFct = &MemmoveDeviceToHost;
} else if (mode == kDeviceToDevice) {
memmoveFct = &MemmoveDeviceToDevice;
} else {
terminator.Crash("host to host copy not supported");
}
Fortran::runtime::Assign(
*dstDesc, *srcDesc, terminator, NoAssignFlags, memmoveFct);
}

void RTDECL(CUFDataTransferGlobalDescDesc)(Descriptor *dstDesc,
Descriptor *srcDesc, unsigned mode, const char *sourceFile,
int sourceLine) {
Expand Down
8 changes: 3 additions & 5 deletions flang/runtime/assign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ static RT_API_ATTRS bool MayAlias(const Descriptor &x, const Descriptor &y) {
return false; // not both allocated
}
const char *xDesc{reinterpret_cast<const char *>(&x)};
const char *xDescLast{xDesc + x.SizeInBytes()};
const char *xDescLast{xDesc + x.SizeInBytes() - 1};
const char *yDesc{reinterpret_cast<const char *>(&y)};
const char *yDescLast{yDesc + y.SizeInBytes()};
const char *yDescLast{yDesc + y.SizeInBytes() - 1};
std::int64_t xLeast, xMost, yLeast, yMost;
MaximalByteOffsetRange(x, xLeast, xMost);
MaximalByteOffsetRange(y, yLeast, yMost);
Expand Down Expand Up @@ -307,10 +307,8 @@ RT_API_ATTRS void Assign(Descriptor &to, const Descriptor &from,
if (mustDeallocateLHS) {
if (deferDeallocation) {
if ((flags & NeedFinalization) && toDerived) {
Finalize(to, *toDerived, &terminator);
Finalize(*deferDeallocation, *toDerived, &terminator);
flags &= ~NeedFinalization;
} else if (toDerived && !toDerived->noDestructionNeeded()) {
Destroy(to, /*finalize=*/false, *toDerived, &terminator);
}
} else {
to.Destroy((flags & NeedFinalization) != 0, /*destroyPointers=*/false,
Expand Down
5 changes: 4 additions & 1 deletion flang/test/Evaluate/errors01.f90
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,13 @@ subroutine s14(n)
print *, ibits(0, 33, n)
end
subroutine warnings
use ieee_arithmetic, only: ieee_scalb
real, parameter :: ok1 = scale(0.0, 99999) ! 0.0
real, parameter :: ok2 = scale(1.0, -99999) ! 0.0
!CHECK: SCALE intrinsic folding overflow
!CHECK: SCALE/IEEE_SCALB intrinsic folding overflow
real, parameter :: bad1 = scale(1.0, 99999)
!CHECK: SCALE/IEEE_SCALB intrinsic folding overflow
real, parameter :: bad1a = ieee_scalb(1.0, 99999)
!CHECK: complex ABS intrinsic folding overflow
real, parameter :: bad2 = abs(cmplx(huge(0.),huge(0.)))
!CHECK: warning: DIM intrinsic folding overflow
Expand Down
22 changes: 10 additions & 12 deletions flang/test/Fir/CUDA/cuda-data-transfer.fir
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func.func @_QPsub4() {
return
}
// CHECK-LABEL: func.func @_QPsub4()
// CHECK: %[[TEMP_BOX1:.*]] = fir.alloca !fir.box<!fir.array<10xi32>>
// CHECK: %[[TEMP_BOX:.*]] = fir.alloca !fir.box<!fir.array<10xi32>>
// CHECK: %[[ADEV:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub4Eadev"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
// CHECK: %[[AHOST:.*]]:2 = hlfir.declare %{{.*}}(%[[AHOST_SHAPE:.*]]) {uniq_name = "_QFsub4Eahost"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
Expand All @@ -81,13 +82,11 @@ func.func @_QPsub4() {
// CHECK: %[[ADEV_BOX:.*]] = fir.convert %[[ADEV]]#0 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
// CHECK: %[[AHOST_BOX:.*]] = fir.convert %[[TEMP_BOX]] : (!fir.ref<!fir.box<!fir.array<10xi32>>>) -> !fir.ref<!fir.box<none>>
// CHECK: fir.call @_FortranACUFDataTransferDescDesc(%[[ADEV_BOX]], %[[AHOST_BOX]], %c0{{.*}}, %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.ref<!fir.box<none>>, i32, !fir.ref<i8>, i32) -> none
// CHECK: %[[NBELEM:.*]] = arith.constant 10 : index
// CHECK: %[[WIDTH:.*]] = arith.constant 4 : index
// CHECK: %[[BYTES:.*]] = arith.muli %[[NBELEM]], %[[WIDTH]] : index
// CHECK: %[[AHOST_PTR:.*]] = fir.convert %[[AHOST]]#0 : (!fir.ref<!fir.array<10xi32>>) -> !fir.llvm_ptr<i8>
// CHECK: %[[EMBOX:.*]] = fir.embox %[[AHOST]]#0(%[[AHOST_SHAPE]]) : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>>
// CHECK: fir.store %[[EMBOX]] to %[[TEMP_BOX1]] : !fir.ref<!fir.box<!fir.array<10xi32>>>
// CHECK: %[[AHOST_BOX:.*]] = fir.convert %[[TEMP_BOX1]] : (!fir.ref<!fir.box<!fir.array<10xi32>>>) -> !fir.ref<!fir.box<none>>
// CHECK: %[[ADEV_BOX:.*]] = fir.convert %[[ADEV]]#0 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
// CHECK: %[[BYTES_CONV:.*]] = fir.convert %[[BYTES]] : (index) -> i64
// CHECK: fir.call @_FortranACUFDataTransferPtrDesc(%[[AHOST_PTR]], %[[ADEV_BOX]], %[[BYTES_CONV]], %c1{{.*}}, %{{.*}}, %{{.*}}) : (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i64, i32, !fir.ref<i8>, i32) -> none
// CHECK: fir.call @_FortranACUFDataTransferDescDescNoRealloc(%[[AHOST_BOX]], %[[ADEV_BOX]], %c1{{.*}}, %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.ref<!fir.box<none>>, i32, !fir.ref<i8>, i32) -> none

func.func @_QPsub5(%arg0: !fir.ref<i32> {fir.bindc_name = "n"}) {
%0 = fir.dummy_scope : !fir.dscope
Expand Down Expand Up @@ -115,6 +114,7 @@ func.func @_QPsub5(%arg0: !fir.ref<i32> {fir.bindc_name = "n"}) {
}

// CHECK-LABEL: func.func @_QPsub5
// CHECK: %[[TEMP_BOX1:.*]] = fir.alloca !fir.box<!fir.array<?x?xi32>>
// CHECK: %[[TEMP_BOX:.*]] = fir.alloca !fir.box<!fir.array<?x?xi32>>
// CHECK: %[[ADEV:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub5Eadev"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi32>>>>)
// CHECK: %[[SHAPE:.*]] = fir.shape %[[I1:.*]], %[[I2:.*]] : (index, index) -> !fir.shape<2>
Expand All @@ -124,13 +124,11 @@ func.func @_QPsub5(%arg0: !fir.ref<i32> {fir.bindc_name = "n"}) {
// CHECK: %[[ADEV_BOX:.*]] = fir.convert %[[ADEV]]#0 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi32>>>>) -> !fir.ref<!fir.box<none>>
// CHECK: %[[AHOST_BOX:.*]] = fir.convert %[[TEMP_BOX]] : (!fir.ref<!fir.box<!fir.array<?x?xi32>>>) -> !fir.ref<!fir.box<none>>
// CHECK: fir.call @_FortranACUFDataTransferDescDesc(%[[ADEV_BOX]], %[[AHOST_BOX]], %c0{{.*}}, %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.ref<!fir.box<none>>, i32, !fir.ref<i8>, i32) -> none
// CHECK: %[[NBELEM:.*]] = arith.muli %[[I1]], %[[I2]] : index
// CHECK: %[[WIDTH:.*]] = arith.constant 4 : index
// CHECK: %[[BYTES:.*]] = arith.muli %[[NBELEM]], %[[WIDTH]] : index
// CHECK: %[[AHOST_PTR:.*]] = fir.convert %[[AHOST]]#1 : (!fir.ref<!fir.array<?x?xi32>>) -> !fir.llvm_ptr<i8>
// CHECK: %[[EMBOX:.*]] = fir.embox %[[AHOST]]#1(%[[SHAPE]]) : (!fir.ref<!fir.array<?x?xi32>>, !fir.shape<2>) -> !fir.box<!fir.array<?x?xi32>>
// CHECK: fir.store %[[EMBOX]] to %[[TEMP_BOX1]] : !fir.ref<!fir.box<!fir.array<?x?xi32>>>
// CHECK: %[[AHOST_BOX:.*]] = fir.convert %[[TEMP_BOX1]] : (!fir.ref<!fir.box<!fir.array<?x?xi32>>>) -> !fir.ref<!fir.box<none>>
// CHECK: %[[ADEV_BOX:.*]] = fir.convert %[[ADEV]]#0 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi32>>>>) -> !fir.ref<!fir.box<none>>
// CHECK: %[[BYTES_CONV:.*]] = fir.convert %[[BYTES]] : (index) -> i64
// CHECK: fir.call @_FortranACUFDataTransferPtrDesc(%[[AHOST_PTR]], %[[ADEV_BOX]], %[[BYTES_CONV]], %c1{{.*}}, %{{.*}}, %{{.*}}) : (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i64, i32, !fir.ref<i8>, i32) -> none
// CHECK: fir.call @_FortranACUFDataTransferDescDescNoRealloc(%[[AHOST_BOX]], %[[ADEV_BOX]], %c1{{.*}}, %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.ref<!fir.box<none>>, i32, !fir.ref<i8>, i32) -> none

func.func @_QPsub6() {
%0 = cuf.alloc i32 {bindc_name = "idev", data_attr = #cuf.cuda<device>, uniq_name = "_QFsub6Eidev"} -> !fir.ref<i32>
Expand Down
117 changes: 117 additions & 0 deletions flang/test/Preprocessing/defined-in-macro.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
! RUN: %flang -E %s 2>&1 | FileCheck %s

! CHECK: print *, 'pass 1'
#define IS_DEFINED
#define M1 defined(IS_DEFINED)
#if M1
print *, 'pass 1'
#else
print *, 'fail 1'
#endif

! CHECK: print *, 'pass 2'
#define M2 defined IS_DEFINED
#if M2
print *, 'pass 2'
#else
print *, 'fail 2'
#endif

! CHECK: print *, 'pass 3'
#define M3 defined(IS_UNDEFINED)
#if M3
print *, 'fail 3'
#else
print *, 'pass 3'
#endif

! CHECK: print *, 'pass 4'
#define M4 defined IS_UNDEFINED
#if M4
print *, 'fail 4'
#else
print *, 'pass 4'
#endif

! CHECK: print *, 'pass 5'
#define DEFINED_KEYWORD defined
#define M5(x) DEFINED_KEYWORD(x)
#define KWM1 1
#if M5(KWM1)
print *, 'pass 5'
#else
print *, 'fail 5'
#endif

! CHECK: print *, 'pass 6'
#define KWM2 KWM1
#if M5(KWM2)
print *, 'pass 6'
#else
print *, 'fail 6'
#endif

! CHECK: print *, 'pass 7'
#if M5(IS_UNDEFINED)
print *, 'fail 7'
#else
print *, 'pass 7'
#endif

! CHECK: print *, 'pass 8'
#define KWM3 IS_UNDEFINED
#if M5(KWM3)
print *, 'pass 8'
#else
print *, 'fail 8'
#endif

! CHECK: print *, 'pass 9'
#define M6(x) defined(x)
#if M6(KWM1)
print *, 'pass 9'
#else
print *, 'fail 9'
#endif

! CHECK: print *, 'pass 10'
#if M6(KWM2)
print *, 'pass 10'
#else
print *, 'fail 10'
#endif

! CHECK: print *, 'pass 11'
#if M6(IS_UNDEFINED)
print *, 'fail 11'
#else
print *, 'pass 11'
#endif

! CHECK: print *, 'pass 12'
#if M6(KWM3)
print *, 'pass 12'
#else
print *, 'fail 12'
#endif

! CHECK: print *, 'pass 13'
#define M7(A, B) ((A) * 10000 + (B) * 100)
#define M8(A, B, C, AA, BB) ( \
(defined(AA) && defined(BB)) && \
(M7(A, B) C M7(AA, BB)))
#if M8(9, 5, >, BAZ, FUX)
print *, 'fail 13'
#else
print *, 'pass 13'
#endif

! CHECK: print *, 'pass 14'
#define M9() (defined(IS_UNDEFINED))
#if M9()
print *, 'fail 14'
#else
print *, 'pass 14'
#endif

end
2 changes: 1 addition & 1 deletion flang/test/Semantics/OpenMP/depobj-construct-v50.f90
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ subroutine f02
subroutine f03
integer :: obj, jbo
!ERROR: The DESTROY clause must refer to the same object as the DEPOBJ construct
!PORTABILITY: The object parameter in DESTROY clause in DEPOPJ construct was introduced in OpenMP v5.2
!WARNING: The object parameter in DESTROY clause on DEPOPJ construct is not allowed in OpenMP v5.0, try -fopenmp-version=52
!$omp depobj(obj) destroy(jbo)
end
6 changes: 6 additions & 0 deletions flang/test/Semantics/OpenMP/depobj-construct-v52.f90
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ subroutine f03
!ERROR: The DESTROY clause must refer to the same object as the DEPOBJ construct
!$omp depobj(obj) destroy(jbo)
end

subroutine f06
integer :: obj
!WARNING: The DESTROY clause without argument on DEPOBJ construct is deprecated in OpenMP v5.2
!$omp depobj(obj) destroy
end
50 changes: 50 additions & 0 deletions flang/test/Semantics/rewrite03.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
!RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
!Test rewriting of misparsed statement function definitions
!into array element assignment statements.

program main
real sf(1)
integer :: j = 1
!CHECK: sf(int(j,kind=8))=1._4
sf(j) = 1.
end

function func
real sf(1)
integer :: j = 1
!CHECK: sf(int(j,kind=8))=2._4
sf(j) = 2.
func = 0.
end

subroutine subr
real sf(1)
integer :: j = 1
!CHECK: sf(int(j,kind=8))=3._4
sf(j) = 3.
end

module m
interface
module subroutine smp
end
end interface
end
submodule(m) sm
contains
module procedure smp
real sf(1)
integer :: j = 1
!CHECK: sf(int(j,kind=8))=4._4
sf(j) = 4.
end
end

subroutine block
block
real sf(1)
integer :: j = 1
!CHECK: sf(int(j,kind=8))=5._4
sf(j) = 5.
end block
end
14 changes: 14 additions & 0 deletions flang/test/Transforms/debug-assumed-rank-array.fir
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s

module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
func.func @_QFPfn(%arg0: !fir.box<!fir.array<*:i32>> ) {
%1 = fir.undefined !fir.dscope
%2 = fircg.ext_declare %arg0 dummy_scope %1 {uniq_name = "_QFFfnEx"} : (!fir.box<!fir.array<*:i32>>, !fir.dscope) -> !fir.box<!fir.array<*:i32>> loc(#loc2)
return
} loc(#loc1)
}
#loc1 = loc("test1.f90":1:1)
#loc2 = loc("test1.f90":3:16)

// CHECK: #[[TY:.*]] = #llvm.di_composite_type<tag = DW_TAG_array_type{{.*}}elements = #llvm.di_generic_subrange<count = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_over, DW_OP_constu(24), DW_OP_mul, DW_OP_plus_uconst(32), DW_OP_plus, DW_OP_deref]>, lowerBound = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_over, DW_OP_constu(24), DW_OP_mul, DW_OP_plus_uconst(24), DW_OP_plus, DW_OP_deref]>, stride = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_over, DW_OP_constu(24), DW_OP_mul, DW_OP_plus_uconst(40), DW_OP_plus, DW_OP_deref]>>, dataLocation = <[DW_OP_push_object_address, DW_OP_deref]>, rank = <[DW_OP_push_object_address, DW_OP_plus_uconst(20), DW_OP_deref_size(1)]>>
// CHECK: #llvm.di_local_variable<{{.*}}name = "x"{{.*}}type = #[[TY]]{{.*}}>
7 changes: 4 additions & 3 deletions libc/src/sys/socket/linux/recvmsg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@

namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(ssize_t, recvmsg,
(int sockfd, struct msghdr *msg, int flags)) {
LLVM_LIBC_FUNCTION(ssize_t, recvmsg, (int sockfd, msghdr *msg, int flags)) {
#ifdef SYS_recvmsg
ssize_t ret =
LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_recvmsg, sockfd, msg, flags);
Expand All @@ -40,9 +39,11 @@ LLVM_LIBC_FUNCTION(ssize_t, recvmsg,
}

// Unpoison the msghdr, as well as all its components.
MSAN_UNPOISON(msg, sizeof(msghdr));
MSAN_UNPOISON(msg->msg_name, msg->msg_namelen);

for (size_t i = 0; i < msg->msg_iovlen; ++i) {
MSAN_UNPOISON(msg->msg_iov->iov_base, msg->msg_iov->iov_len);
MSAN_UNPOISON(msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
}
MSAN_UNPOISON(msg->msg_control, msg->msg_controllen);

Expand Down
1 change: 0 additions & 1 deletion libc/test/src/__support/OSUtil/linux/vdso_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include "src/signal/raise.h"
#include "src/signal/sigaction.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/LibcTest.h"
#include "test/UnitTest/Test.h"
#include <linux/time_types.h>
#include <sys/syscall.h>
Expand Down
1 change: 0 additions & 1 deletion libc/test/src/__support/integer_literals_test.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

//===-- Unittests for user defined integer literals -----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
Expand Down
8 changes: 8 additions & 0 deletions libc/test/src/__support/str_to_double_test.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
//===-- Unittests for str_to_float<double> --------------------------------===//
//
// 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/config.h"
#include "str_to_fp_test.h"

Expand Down
8 changes: 8 additions & 0 deletions libc/test/src/__support/str_to_float_test.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
//===-- Unittests for str_to_float<float> ---------------------------------===//
//
// 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/config.h"
#include "str_to_fp_test.h"

Expand Down
8 changes: 8 additions & 0 deletions libc/test/src/__support/str_to_long_double_test.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
//===-- Unittests for str_to_float<long double> ---------------------------===//
//
// 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/config.h"
#include "str_to_fp_test.h"

Expand Down
Loading