Skip to content

[clang] handle fp options in __builtin_convertvector #125522

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 76 additions & 4 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -4579,25 +4579,97 @@ class ShuffleVectorExpr : public Expr {
/// ConvertVectorExpr - Clang builtin function __builtin_convertvector
/// This AST node provides support for converting a vector type to another
/// vector type of the same arity.
class ConvertVectorExpr : public Expr {
class ConvertVectorExpr final
: public Expr,
private llvm::TrailingObjects<ConvertVectorExpr, FPOptionsOverride> {
private:
Stmt *SrcExpr;
TypeSourceInfo *TInfo;
SourceLocation BuiltinLoc, RParenLoc;

friend TrailingObjects;
friend class ASTReader;
friend class ASTStmtReader;
explicit ConvertVectorExpr(EmptyShell Empty) : Expr(ConvertVectorExprClass, Empty) {}
explicit ConvertVectorExpr(bool HasFPFeatures, EmptyShell Empty)
: Expr(ConvertVectorExprClass, Empty) {
ConvertVectorExprBits.HasFPFeatures = HasFPFeatures;
}

public:
ConvertVectorExpr(Expr *SrcExpr, TypeSourceInfo *TI, QualType DstType,
ExprValueKind VK, ExprObjectKind OK,
SourceLocation BuiltinLoc, SourceLocation RParenLoc)
SourceLocation BuiltinLoc, SourceLocation RParenLoc,
FPOptionsOverride FPFeatures)
: Expr(ConvertVectorExprClass, DstType, VK, OK), SrcExpr(SrcExpr),
TInfo(TI), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {
ConvertVectorExprBits.HasFPFeatures = FPFeatures.requiresTrailingStorage();
if (hasStoredFPFeatures())
setStoredFPFeatures(FPFeatures);
setDependence(computeDependence(this));
}

size_t numTrailingObjects(OverloadToken<FPOptionsOverride>) const {
return ConvertVectorExprBits.HasFPFeatures ? 1 : 0;
}

FPOptionsOverride &getTrailingFPFeatures() {
assert(ConvertVectorExprBits.HasFPFeatures);
return *getTrailingObjects<FPOptionsOverride>();
}

const FPOptionsOverride &getTrailingFPFeatures() const {
assert(ConvertVectorExprBits.HasFPFeatures);
return *getTrailingObjects<FPOptionsOverride>();
}

public:
static ConvertVectorExpr *CreateEmpty(const ASTContext &C,
bool hasFPFeatures);

static ConvertVectorExpr *Create(const ASTContext &C, Expr *SrcExpr,
TypeSourceInfo *TI, QualType DstType,
ExprValueKind VK, ExprObjectKind OK,
SourceLocation BuiltinLoc,
SourceLocation RParenLoc,
FPOptionsOverride FPFeatures);

/// Get the FP contractibility status of this operator. Only meaningful for
/// operations on floating point types.
bool isFPContractableWithinStatement(const LangOptions &LO) const {
return getFPFeaturesInEffect(LO).allowFPContractWithinStatement();
}

/// Is FPFeatures in Trailing Storage?
bool hasStoredFPFeatures() const {
return ConvertVectorExprBits.HasFPFeatures;
}

/// Get FPFeatures from trailing storage.
FPOptionsOverride getStoredFPFeatures() const {
return getTrailingFPFeatures();
}

/// Get the store FPOptionsOverride or default if not stored.
FPOptionsOverride getStoredFPFeaturesOrDefault() const {
return hasStoredFPFeatures() ? getStoredFPFeatures() : FPOptionsOverride();
}

/// Set FPFeatures in trailing storage, used by Serialization & ASTImporter.
void setStoredFPFeatures(FPOptionsOverride F) { getTrailingFPFeatures() = F; }

/// Get the FP features status of this operator. Only meaningful for
/// operations on floating point types.
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const {
if (ConvertVectorExprBits.HasFPFeatures)
return getStoredFPFeatures().applyOverrides(LO);
return FPOptions::defaultWithoutTrailingStorage(LO);
}

FPOptionsOverride getFPOptionsOverride() const {
if (ConvertVectorExprBits.HasFPFeatures)
return getStoredFPFeatures();
return FPOptionsOverride();
}

/// getSrcExpr - Return the Expr to be converted.
Expr *getSrcExpr() const { return cast<Expr>(SrcExpr); }

Expand Down
15 changes: 15 additions & 0 deletions clang/include/clang/AST/Stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -1215,6 +1215,20 @@ class alignas(void *) Stmt {
SourceLocation Loc;
};

class ConvertVectorExprBitfields {
friend class ConvertVectorExpr;

LLVM_PREFERRED_TYPE(ExprBitfields)
unsigned : NumExprBits;

//
/// This is only meaningful for operations on floating point
/// types when additional values need to be in trailing storage.
/// It is 0 otherwise.
LLVM_PREFERRED_TYPE(bool)
unsigned HasFPFeatures : 1;
};

union {
// Same order as in StmtNodes.td.
// Statements
Expand Down Expand Up @@ -1293,6 +1307,7 @@ class alignas(void *) Stmt {

// Clang Extensions
OpaqueValueExprBitfields OpaqueValueExprBits;
ConvertVectorExprBitfields ConvertVectorExprBits;
};

public:
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/TextNodeDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ class TextNodeDumper
void VisitOpenACCAsteriskSizeExpr(const OpenACCAsteriskSizeExpr *S);
void VisitEmbedExpr(const EmbedExpr *S);
void VisitAtomicExpr(const AtomicExpr *AE);
void VisitConvertVectorExpr(const ConvertVectorExpr *S);
};

} // namespace clang
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7386,9 +7386,10 @@ ExpectedStmt ASTNodeImporter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
if (Err)
return std::move(Err);

return new (Importer.getToContext())
ConvertVectorExpr(ToSrcExpr, ToTSI, ToType, E->getValueKind(),
E->getObjectKind(), ToBuiltinLoc, ToRParenLoc);
return ConvertVectorExpr::Create(
Importer.getToContext(), ToSrcExpr, ToTSI, ToType, E->getValueKind(),
E->getObjectKind(), ToBuiltinLoc, ToRParenLoc,
E->getStoredFPFeaturesOrDefault());
}

ExpectedStmt ASTNodeImporter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3900,6 +3900,8 @@ FPOptions Expr::getFPFeaturesInEffect(const LangOptions &LO) const {
return BO->getFPFeaturesInEffect(LO);
if (auto Cast = dyn_cast<CastExpr>(this))
return Cast->getFPFeaturesInEffect(LO);
if (auto ConvertVector = dyn_cast<ConvertVectorExpr>(this))
return ConvertVector->getFPFeaturesInEffect(LO);
return FPOptions::defaultWithoutTrailingStorage(LO);
}

Expand Down Expand Up @@ -5440,3 +5442,21 @@ OpenACCAsteriskSizeExpr *
OpenACCAsteriskSizeExpr::CreateEmpty(const ASTContext &C) {
return new (C) OpenACCAsteriskSizeExpr({}, C.IntTy);
}

ConvertVectorExpr *ConvertVectorExpr::CreateEmpty(const ASTContext &C,
bool hasFPFeatures) {
void *Mem = C.Allocate(totalSizeToAlloc<FPOptionsOverride>(hasFPFeatures),
alignof(ConvertVectorExpr));
return new (Mem) ConvertVectorExpr(hasFPFeatures, EmptyShell());
}

ConvertVectorExpr *ConvertVectorExpr::Create(
const ASTContext &C, Expr *SrcExpr, TypeSourceInfo *TI, QualType DstType,
ExprValueKind VK, ExprObjectKind OK, SourceLocation BuiltinLoc,
SourceLocation RParenLoc, FPOptionsOverride FPFeatures) {
bool HasFPFeatures = FPFeatures.requiresTrailingStorage();
unsigned Size = totalSizeToAlloc<FPOptionsOverride>(HasFPFeatures);
void *Mem = C.Allocate(Size, alignof(ConvertVectorExpr));
return new (Mem) ConvertVectorExpr(SrcExpr, TI, DstType, VK, OK, BuiltinLoc,
RParenLoc, FPFeatures);
}
6 changes: 6 additions & 0 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3058,3 +3058,9 @@ void TextNodeDumper::VisitEmbedExpr(const EmbedExpr *S) {
void TextNodeDumper::VisitAtomicExpr(const AtomicExpr *AE) {
OS << ' ' << AE->getOpAsString();
}

void TextNodeDumper::VisitConvertVectorExpr(const ConvertVectorExpr *S) {
VisitStmt(S);
if (S->hasStoredFPFeatures())
printFPOptions(S->getStoredFPFeatures());
}
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1949,6 +1949,7 @@ Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) {

llvm::Value *Zero = llvm::Constant::getNullValue(SrcTy);
if (SrcEltTy->isFloatingPointTy()) {
CodeGenFunction::CGFPOptionsRAII FPOptions(CGF, E);
return Builder.CreateFCmpUNE(Src, Zero, "tobool");
} else {
return Builder.CreateICmpNE(Src, Zero, "tobool");
Expand All @@ -1975,6 +1976,7 @@ Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
} else {
assert(SrcEltTy->isFloatingPointTy() && DstEltTy->isFloatingPointTy() &&
"Unknown real conversion");
CodeGenFunction::CGFPOptionsRAII FPOptions(CGF, E);
if (DstEltTy->getTypeID() < SrcEltTy->getTypeID())
Res = Builder.CreateFPTrunc(Src, DstTy, "conv");
else
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5262,8 +5262,8 @@ ExprResult Sema::ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
<< E->getSourceRange());
}

return new (Context) class ConvertVectorExpr(E, TInfo, DstTy, VK, OK,
BuiltinLoc, RParenLoc);
return ConvertVectorExpr::Create(Context, E, TInfo, DstTy, VK, OK, BuiltinLoc,
RParenLoc, CurFPFeatureOverrides());
}

bool Sema::BuiltinPrefetch(CallExpr *TheCall) {
Expand Down
13 changes: 11 additions & 2 deletions clang/lib/Serialization/ASTReaderStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1387,10 +1387,15 @@ void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {

void ASTStmtReader::VisitConvertVectorExpr(ConvertVectorExpr *E) {
VisitExpr(E);
bool HasFPFeatures = CurrentUnpackingBits->getNextBit();
assert(HasFPFeatures == E->hasStoredFPFeatures());
E->BuiltinLoc = readSourceLocation();
E->RParenLoc = readSourceLocation();
E->TInfo = readTypeSourceInfo();
E->SrcExpr = Record.readSubExpr();
if (HasFPFeatures)
E->setStoredFPFeatures(
FPOptionsOverride::getFromOpaqueInt(Record.readInt()));
}

void ASTStmtReader::VisitBlockExpr(BlockExpr *E) {
Expand Down Expand Up @@ -3391,9 +3396,13 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) ShuffleVectorExpr(Empty);
break;

case EXPR_CONVERT_VECTOR:
S = new (Context) ConvertVectorExpr(Empty);
case EXPR_CONVERT_VECTOR: {
BitsUnpacker ConvertVectorExprBits(Record[ASTStmtReader::NumStmtFields]);
ConvertVectorExprBits.advance(ASTStmtReader::NumExprBits);
bool HasFPFeatures = ConvertVectorExprBits.getNextBit();
S = ConvertVectorExpr::CreateEmpty(Context, HasFPFeatures);
break;
}

case EXPR_BLOCK:
S = new (Context) BlockExpr(Empty);
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Serialization/ASTWriterStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1335,11 +1335,15 @@ void ASTStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {

void ASTStmtWriter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
VisitExpr(E);
bool HasFPFeatures = E->hasStoredFPFeatures();
CurrentPackingBits.addBit(HasFPFeatures);
Record.AddSourceLocation(E->getBuiltinLoc());
Record.AddSourceLocation(E->getRParenLoc());
Record.AddTypeSourceInfo(E->getTypeSourceInfo());
Record.AddStmt(E->getSrcExpr());
Code = serialization::EXPR_CONVERT_VECTOR;
if (HasFPFeatures)
Record.push_back(E->getStoredFPFeatures().getAsOpaqueInt());
}

void ASTStmtWriter::VisitBlockExpr(BlockExpr *E) {
Expand Down
23 changes: 22 additions & 1 deletion clang/test/AST/ast-dump-fpfeatures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@
// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
// RUN: | FileCheck --strict-whitespace %s

// CHECK-LABEL: FunctionDecl {{.*}} no_fpfeatures_func_01 'vector2float (vector2double)'
// CHECK: CompoundStmt {{.*\>$}}
// CHECK: ReturnStmt
// CHECK: ConvertVectorExpr {{.*}} 'vector2float':'__attribute__((__vector_size__(2 * sizeof(float)))) float'{{$}}

typedef double vector2double __attribute__((__vector_size__(16)));
typedef float vector2float __attribute__((__vector_size__(8)));
vector2float no_fpfeatures_func_01(vector2double x) {
return __builtin_convertvector(x, vector2float);
}

float func_01(float x);

template <typename T>
Expand Down Expand Up @@ -248,4 +259,14 @@ __attribute__((optnone)) T func_22(T x, T y) {

float func_23(float x, float y) {
return func_22(x, y);
}
}

// CHECK-LABEL: FunctionDecl {{.*}} func_24 'vector2float (vector2double)'
// CHECK: CompoundStmt {{.*}} FPContractMode=2 ConstRoundingMode=towardzero
// CHECK: ReturnStmt
// CHECK: ConvertVectorExpr {{.*}} FPContractMode=2 ConstRoundingMode=towardzero

#pragma STDC FENV_ROUND FE_TOWARDZERO
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see other tests doing this but we should test also the absence of FP options in the AST as well when nothing is set. This would test that we are not incorrectly identifying that hasStoredFPFeatures() is true and that we don't get garbage values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added in f517b49. I moved it to the beginning of the file due to FP pragmas outside function scopes.

vector2float func_24(vector2double x) {
return __builtin_convertvector(x, vector2float);
}
11 changes: 11 additions & 0 deletions clang/test/AST/const-fpfeatures.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ float _Complex C1u = C0;
float FLu = 0.1F;
// CHECK: @FLu = {{.*}} float 0x3FB99999A0000000

typedef float vector2float __attribute__((__vector_size__(8)));
typedef double vector2double __attribute__((__vector_size__(16)));
const vector2float V2Fu = {1.0F + 0x0.000001p0F, 1.0F + 0x0.000002p0F};
vector2double V2Du = __builtin_convertvector(V2Fu, vector2double);
// CHECK: @V2Fu = {{.*}} <2 x float> splat (float 0x3FF0000020000000)
// CHECK: @V2Du = {{.*}} <2 x double> splat (double 0x3FF0000020000000)

#pragma STDC FENV_ROUND FE_DOWNWARD

Expand All @@ -41,3 +47,8 @@ float _Complex C1d = C0;

float FLd = 0.1F;
// CHECK: @FLd = {{.*}} float 0x3FB9999980000000

const vector2float V2Fd = {1.0F + 0x0.000001p0F, 1.0F + 0x0.000002p0F};
vector2double V2Dd = __builtin_convertvector(V2Fd, vector2double);
// CHECK: @V2Fd = {{.*}} <2 x float> <float 1.000000e+00, float 0x3FF0000020000000>
// CHECK: @V2Dd = {{.*}} <2 x double> <double 1.000000e+00, double 0x3FF0000020000000>
9 changes: 9 additions & 0 deletions clang/test/CodeGen/pragma-fenv_access.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,3 +242,12 @@ float func_20(float x, float y) {
// CHECK-LABEL: @func_20
// STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
// DEFAULT: fadd float

typedef double vector4double __attribute__((__vector_size__(32)));
typedef float vector4float __attribute__((__vector_size__(16)));
vector4float func_21(vector4double x) {
#pragma STDC FENV_ROUND FE_UPWARD
return __builtin_convertvector(x, vector4float);
}
// CHECK-LABEL: @func_21
// STRICT: call <4 x float> @llvm.experimental.constrained.fptrunc.v4f32.v4f64(<4 x double> {{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")