-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[CIR] Upstream support for emitting ignored statements #130869
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
Conversation
This adds support for emitting ClangIR for statements whose value is ignored. The test case being added (CIR/CodeGen/basic.c) tests a few more things. The "f1" test case is the only part that's immediately relevant to this change, but the other cases were part of the same test in the incubator and they are supported so I brought in the entire test.
@llvm/pr-subscribers-clangir Author: Andy Kaylor (andykaylor) ChangesThis adds support for emitting ClangIR for statements whose value is ignored. The test case being added (CIR/CodeGen/basic.c) tests a few more things. The "f1" test case is the only part that's immediately relevant to this change, but the other cases were part of the same test in the incubator and they are supported so I brought in the entire test. Full diff: https://github.com/llvm/llvm-project/pull/130869.diff 5 Files Affected:
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index ddfe654009644..e8d3eff79d0b2 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -83,6 +83,7 @@ struct MissingFeatures {
static bool emitNullabilityCheck() { return false; }
static bool astVarDeclInterface() { return false; }
static bool stackSaveOp() { return false; }
+ static bool aggValueSlot() { return false; }
};
} // namespace cir
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 07fb4cf8f1513..a33aa45f8a4fc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -165,6 +165,33 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
return LValue();
}
+/// Emit code to compute the specified expression which
+/// can have any type. The result is returned as an RValue struct.
+RValue CIRGenFunction::emitAnyExpr(const Expr *e, bool ignoreResult) {
+ switch (CIRGenFunction::getEvaluationKind(e->getType())) {
+ case cir::TEK_Scalar:
+ return RValue::get(emitScalarExpr(e));
+ case cir::TEK_Complex:
+ cgm.errorNYI(e->getSourceRange(), "emitAnyExpr: complex type");
+ return RValue::get(nullptr);
+ case cir::TEK_Aggregate:
+ cgm.errorNYI(e->getSourceRange(), "emitAnyExpr: aggregate type");
+ return RValue::get(nullptr);
+ }
+ llvm_unreachable("bad evaluation kind");
+}
+
+/// Emit code to compute the specified expression, ignoring the result.
+void CIRGenFunction::emitIgnoredExpr(const Expr *e) {
+ if (e->isPRValue()) {
+ assert(!cir::MissingFeatures::aggValueSlot());
+ return (void)emitAnyExpr(e, true);
+ }
+
+ // Just emit it as an l-value and drop the result.
+ emitLValue(e);
+}
+
mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty,
mlir::Location loc,
CharUnits alignment) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 72445f62232a4..ddb1c1c5dd229 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -154,6 +154,12 @@ class CIRGenFunction : public CIRGenTypeCache {
const clang::LangOptions &getLangOpts() const { return cgm.getLangOpts(); }
+ /// Emit code to compute the specified expression which can have any type. The
+ /// result is returned as an RValue struct. If this is an aggregate
+ /// expression, the aggloc/agglocvolatile arguments indicate where the result
+ /// should be returned.
+ RValue emitAnyExpr(const clang::Expr *e, bool ignoreResult = false);
+
void finishFunction(SourceLocation endLoc);
mlir::LogicalResult emitFunctionBody(const clang::Stmt *body);
@@ -170,6 +176,10 @@ class CIRGenFunction : public CIRGenTypeCache {
void emitCompoundStmtWithoutScope(const clang::CompoundStmt &s);
+ /// Emit code to compute the specified expression,
+ /// ignoring the result.
+ void emitIgnoredExpr(const clang::Expr *e);
+
mlir::LogicalResult emitDeclStmt(const clang::DeclStmt &s);
mlir::LogicalResult emitReturnStmt(const clang::ReturnStmt &s);
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index ed5d87a39704a..91627d5d5985a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -55,10 +55,154 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
if (mlir::succeeded(emitSimpleStmt(s, useCurrentScope)))
return mlir::success();
- // Only a subset of simple statements are supported at the moment. When more
- // kinds of statements are supported, a
- // switch (s->getStmtClass()) {
- // will be added here.
+ switch (s->getStmtClass()) {
+
+#define STMT(Type, Base)
+#define ABSTRACT_STMT(Op)
+#define EXPR(Type, Base) case Stmt::Type##Class:
+#include "clang/AST/StmtNodes.inc"
+ {
+ // Remember the block we came in on.
+ mlir::Block *incoming = builder.getInsertionBlock();
+ assert(incoming && "expression emission must have an insertion point");
+
+ emitIgnoredExpr(cast<Expr>(s));
+
+ mlir::Block *outgoing = builder.getInsertionBlock();
+ assert(outgoing && "expression emission cleared block!");
+ return mlir::success();
+ }
+
+ case Stmt::OMPScopeDirectiveClass:
+ case Stmt::OMPErrorDirectiveClass:
+ case Stmt::NoStmtClass:
+ case Stmt::CXXCatchStmtClass:
+ case Stmt::SEHExceptStmtClass:
+ case Stmt::SEHFinallyStmtClass:
+ case Stmt::MSDependentExistsStmtClass:
+ case Stmt::NullStmtClass:
+ case Stmt::CompoundStmtClass:
+ case Stmt::DeclStmtClass:
+ case Stmt::LabelStmtClass:
+ case Stmt::AttributedStmtClass:
+ case Stmt::GotoStmtClass:
+ case Stmt::BreakStmtClass:
+ case Stmt::ContinueStmtClass:
+ case Stmt::DefaultStmtClass:
+ case Stmt::CaseStmtClass:
+ case Stmt::SEHLeaveStmtClass:
+ case Stmt::SYCLKernelCallStmtClass:
+ case Stmt::IfStmtClass:
+ case Stmt::SwitchStmtClass:
+ case Stmt::ForStmtClass:
+ case Stmt::WhileStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::CoroutineBodyStmtClass:
+ case Stmt::CoreturnStmtClass:
+ case Stmt::CXXTryStmtClass:
+ case Stmt::CXXForRangeStmtClass:
+ case Stmt::IndirectGotoStmtClass:
+ case Stmt::ReturnStmtClass:
+ case Stmt::GCCAsmStmtClass:
+ case Stmt::MSAsmStmtClass:
+ case Stmt::OMPParallelDirectiveClass:
+ case Stmt::OMPTaskwaitDirectiveClass:
+ case Stmt::OMPTaskyieldDirectiveClass:
+ case Stmt::OMPBarrierDirectiveClass:
+ case Stmt::CapturedStmtClass:
+ case Stmt::ObjCAtTryStmtClass:
+ case Stmt::ObjCAtThrowStmtClass:
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ case Stmt::ObjCForCollectionStmtClass:
+ case Stmt::ObjCAutoreleasePoolStmtClass:
+ case Stmt::SEHTryStmtClass:
+ case Stmt::OMPMetaDirectiveClass:
+ case Stmt::OMPCanonicalLoopClass:
+ case Stmt::OMPSimdDirectiveClass:
+ case Stmt::OMPTileDirectiveClass:
+ case Stmt::OMPUnrollDirectiveClass:
+ case Stmt::OMPForDirectiveClass:
+ case Stmt::OMPForSimdDirectiveClass:
+ case Stmt::OMPSectionsDirectiveClass:
+ case Stmt::OMPSectionDirectiveClass:
+ case Stmt::OMPSingleDirectiveClass:
+ case Stmt::OMPMasterDirectiveClass:
+ case Stmt::OMPCriticalDirectiveClass:
+ case Stmt::OMPParallelForDirectiveClass:
+ case Stmt::OMPParallelForSimdDirectiveClass:
+ case Stmt::OMPParallelMasterDirectiveClass:
+ case Stmt::OMPParallelSectionsDirectiveClass:
+ case Stmt::OMPTaskDirectiveClass:
+ case Stmt::OMPTaskgroupDirectiveClass:
+ case Stmt::OMPFlushDirectiveClass:
+ case Stmt::OMPDepobjDirectiveClass:
+ case Stmt::OMPScanDirectiveClass:
+ case Stmt::OMPOrderedDirectiveClass:
+ case Stmt::OMPAtomicDirectiveClass:
+ case Stmt::OMPTargetDirectiveClass:
+ case Stmt::OMPTeamsDirectiveClass:
+ case Stmt::OMPCancellationPointDirectiveClass:
+ case Stmt::OMPCancelDirectiveClass:
+ case Stmt::OMPTargetDataDirectiveClass:
+ case Stmt::OMPTargetEnterDataDirectiveClass:
+ case Stmt::OMPTargetExitDataDirectiveClass:
+ case Stmt::OMPTargetParallelDirectiveClass:
+ case Stmt::OMPTargetParallelForDirectiveClass:
+ case Stmt::OMPTaskLoopDirectiveClass:
+ case Stmt::OMPTaskLoopSimdDirectiveClass:
+ case Stmt::OMPMaskedTaskLoopDirectiveClass:
+ case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
+ case Stmt::OMPMasterTaskLoopDirectiveClass:
+ case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
+ case Stmt::OMPParallelGenericLoopDirectiveClass:
+ case Stmt::OMPParallelMaskedDirectiveClass:
+ case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
+ case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
+ case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
+ case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
+ case Stmt::OMPDistributeDirectiveClass:
+ case Stmt::OMPDistributeParallelForDirectiveClass:
+ case Stmt::OMPDistributeParallelForSimdDirectiveClass:
+ case Stmt::OMPDistributeSimdDirectiveClass:
+ case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
+ case Stmt::OMPTargetParallelForSimdDirectiveClass:
+ case Stmt::OMPTargetSimdDirectiveClass:
+ case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
+ case Stmt::OMPTargetUpdateDirectiveClass:
+ case Stmt::OMPTeamsDistributeDirectiveClass:
+ case Stmt::OMPTeamsDistributeSimdDirectiveClass:
+ case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
+ case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
+ case Stmt::OMPTeamsGenericLoopDirectiveClass:
+ case Stmt::OMPTargetTeamsDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
+ case Stmt::OMPInteropDirectiveClass:
+ case Stmt::OMPDispatchDirectiveClass:
+ case Stmt::OMPGenericLoopDirectiveClass:
+ case Stmt::OMPReverseDirectiveClass:
+ case Stmt::OMPInterchangeDirectiveClass:
+ case Stmt::OMPAssumeDirectiveClass:
+ case Stmt::OMPMaskedDirectiveClass:
+ case Stmt::OpenACCComputeConstructClass:
+ case Stmt::OpenACCLoopConstructClass:
+ case Stmt::OpenACCCombinedConstructClass:
+ case Stmt::OpenACCDataConstructClass:
+ case Stmt::OpenACCEnterDataConstructClass:
+ case Stmt::OpenACCExitDataConstructClass:
+ case Stmt::OpenACCHostDataConstructClass:
+ case Stmt::OpenACCWaitConstructClass:
+ case Stmt::OpenACCInitConstructClass:
+ case Stmt::OpenACCShutdownConstructClass:
+ case Stmt::OpenACCSetConstructClass:
+ case Stmt::OpenACCUpdateConstructClass:
+ case Stmt::ObjCAtCatchStmtClass:
+ case Stmt::ObjCAtFinallyStmtClass:
+ cgm.errorNYI(s->getSourceRange(),
+ std::string("emitStmt: ") + s->getStmtClassName());
+ }
return mlir::failure();
}
diff --git a/clang/test/CIR/CodeGen/basic.c b/clang/test/CIR/CodeGen/basic.c
new file mode 100644
index 0000000000000..8d067aefded66
--- /dev/null
+++ b/clang/test/CIR/CodeGen/basic.c
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+
+int f1(int i);
+
+int f1(int i) {
+ i;
+ return i;
+}
+
+// CIR: module
+// CIR-NEXT: cir.func @f1(%arg0: !cir.int<s, 32> loc({{.*}})) -> !cir.int<s, 32>
+// CIR-NEXT: %[[I_PTR:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 32>>, ["i", init] {alignment = 4 : i64}
+// CIR-NEXT: cir.store %arg0, %[[I_PTR]] : !cir.int<s, 32>, !cir.ptr<!cir.int<s, 32>>
+// CIR-NEXT: %[[I_IGNORED:.*]] = cir.load %[[I_PTR]] : !cir.ptr<!cir.int<s, 32>>, !cir.int<s, 32>
+// CIR-NEXT: %[[I:.*]] = cir.load %[[I_PTR]] : !cir.ptr<!cir.int<s, 32>>, !cir.int<s, 32>
+// CIR-NEXT: cir.return %[[I]] : !cir.int<s, 32>
+
+// LLVM: define i32 @f1(i32 %[[I:.*]])
+// LLVM-NEXT: %[[I_PTR:.*]] = alloca i32, i64 1, align 4
+// LLVM-NEXT: store i32 %[[I]], ptr %[[I_PTR]], align 4
+// LLVM-NEXT: %[[I_IGNORED:.*]] = load i32, ptr %[[I_PTR]], align 4
+// LLVM-NEXT: %[[I:.*]] = load i32, ptr %[[I_PTR]], align 4
+// LLVM-NEXT: ret i32 %[[I]]
+
+int f2(void) { return 3; }
+
+// CIR: cir.func @f2() -> !cir.int<s, 32>
+// CIR-NEXT: %[[THREE:.*]] = cir.const #cir.int<3> : !cir.int<s, 32>
+// CIR-NEXT: cir.return %[[THREE]] : !cir.int<s, 32>
+
+// LLVM: define i32 @f2()
+// LLVM-NEXT: ret i32 3
+
+int f3(void) {
+ int i = 3;
+ return i;
+}
+
+// CIR: cir.func @f3() -> !cir.int<s, 32>
+// CIR-NEXT: %[[I_PTR:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 32>>, ["i", init] {alignment = 4 : i64}
+// CIR-NEXT: %[[THREE:.*]] = cir.const #cir.int<3> : !cir.int<s, 32>
+// CIR-NEXT: cir.store %[[THREE]], %[[I_PTR]] : !cir.int<s, 32>, !cir.ptr<!cir.int<s, 32>>
+// CIR-NEXT: %[[I:.*]] = cir.load %[[I_PTR]] : !cir.ptr<!cir.int<s, 32>>, !cir.int<s, 32>
+// CIR-NEXT: cir.return %[[I]] : !cir.int<s, 32>
+
+// LLVM: define i32 @f3()
+// LLVM-NEXT: %[[I_PTR:.*]] = alloca i32, i64 1, align 4
+// LLVM-NEXT: store i32 3, ptr %[[I_PTR]], align 4
+// LLVM-NEXT: %[[I:.*]] = load i32, ptr %[[I_PTR]], align 4
+// LLVM-NEXT: ret i32 %[[I]]
|
@llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) ChangesThis adds support for emitting ClangIR for statements whose value is ignored. The test case being added (CIR/CodeGen/basic.c) tests a few more things. The "f1" test case is the only part that's immediately relevant to this change, but the other cases were part of the same test in the incubator and they are supported so I brought in the entire test. Full diff: https://github.com/llvm/llvm-project/pull/130869.diff 5 Files Affected:
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index ddfe654009644..e8d3eff79d0b2 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -83,6 +83,7 @@ struct MissingFeatures {
static bool emitNullabilityCheck() { return false; }
static bool astVarDeclInterface() { return false; }
static bool stackSaveOp() { return false; }
+ static bool aggValueSlot() { return false; }
};
} // namespace cir
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 07fb4cf8f1513..a33aa45f8a4fc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -165,6 +165,33 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
return LValue();
}
+/// Emit code to compute the specified expression which
+/// can have any type. The result is returned as an RValue struct.
+RValue CIRGenFunction::emitAnyExpr(const Expr *e, bool ignoreResult) {
+ switch (CIRGenFunction::getEvaluationKind(e->getType())) {
+ case cir::TEK_Scalar:
+ return RValue::get(emitScalarExpr(e));
+ case cir::TEK_Complex:
+ cgm.errorNYI(e->getSourceRange(), "emitAnyExpr: complex type");
+ return RValue::get(nullptr);
+ case cir::TEK_Aggregate:
+ cgm.errorNYI(e->getSourceRange(), "emitAnyExpr: aggregate type");
+ return RValue::get(nullptr);
+ }
+ llvm_unreachable("bad evaluation kind");
+}
+
+/// Emit code to compute the specified expression, ignoring the result.
+void CIRGenFunction::emitIgnoredExpr(const Expr *e) {
+ if (e->isPRValue()) {
+ assert(!cir::MissingFeatures::aggValueSlot());
+ return (void)emitAnyExpr(e, true);
+ }
+
+ // Just emit it as an l-value and drop the result.
+ emitLValue(e);
+}
+
mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty,
mlir::Location loc,
CharUnits alignment) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 72445f62232a4..ddb1c1c5dd229 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -154,6 +154,12 @@ class CIRGenFunction : public CIRGenTypeCache {
const clang::LangOptions &getLangOpts() const { return cgm.getLangOpts(); }
+ /// Emit code to compute the specified expression which can have any type. The
+ /// result is returned as an RValue struct. If this is an aggregate
+ /// expression, the aggloc/agglocvolatile arguments indicate where the result
+ /// should be returned.
+ RValue emitAnyExpr(const clang::Expr *e, bool ignoreResult = false);
+
void finishFunction(SourceLocation endLoc);
mlir::LogicalResult emitFunctionBody(const clang::Stmt *body);
@@ -170,6 +176,10 @@ class CIRGenFunction : public CIRGenTypeCache {
void emitCompoundStmtWithoutScope(const clang::CompoundStmt &s);
+ /// Emit code to compute the specified expression,
+ /// ignoring the result.
+ void emitIgnoredExpr(const clang::Expr *e);
+
mlir::LogicalResult emitDeclStmt(const clang::DeclStmt &s);
mlir::LogicalResult emitReturnStmt(const clang::ReturnStmt &s);
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index ed5d87a39704a..91627d5d5985a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -55,10 +55,154 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
if (mlir::succeeded(emitSimpleStmt(s, useCurrentScope)))
return mlir::success();
- // Only a subset of simple statements are supported at the moment. When more
- // kinds of statements are supported, a
- // switch (s->getStmtClass()) {
- // will be added here.
+ switch (s->getStmtClass()) {
+
+#define STMT(Type, Base)
+#define ABSTRACT_STMT(Op)
+#define EXPR(Type, Base) case Stmt::Type##Class:
+#include "clang/AST/StmtNodes.inc"
+ {
+ // Remember the block we came in on.
+ mlir::Block *incoming = builder.getInsertionBlock();
+ assert(incoming && "expression emission must have an insertion point");
+
+ emitIgnoredExpr(cast<Expr>(s));
+
+ mlir::Block *outgoing = builder.getInsertionBlock();
+ assert(outgoing && "expression emission cleared block!");
+ return mlir::success();
+ }
+
+ case Stmt::OMPScopeDirectiveClass:
+ case Stmt::OMPErrorDirectiveClass:
+ case Stmt::NoStmtClass:
+ case Stmt::CXXCatchStmtClass:
+ case Stmt::SEHExceptStmtClass:
+ case Stmt::SEHFinallyStmtClass:
+ case Stmt::MSDependentExistsStmtClass:
+ case Stmt::NullStmtClass:
+ case Stmt::CompoundStmtClass:
+ case Stmt::DeclStmtClass:
+ case Stmt::LabelStmtClass:
+ case Stmt::AttributedStmtClass:
+ case Stmt::GotoStmtClass:
+ case Stmt::BreakStmtClass:
+ case Stmt::ContinueStmtClass:
+ case Stmt::DefaultStmtClass:
+ case Stmt::CaseStmtClass:
+ case Stmt::SEHLeaveStmtClass:
+ case Stmt::SYCLKernelCallStmtClass:
+ case Stmt::IfStmtClass:
+ case Stmt::SwitchStmtClass:
+ case Stmt::ForStmtClass:
+ case Stmt::WhileStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::CoroutineBodyStmtClass:
+ case Stmt::CoreturnStmtClass:
+ case Stmt::CXXTryStmtClass:
+ case Stmt::CXXForRangeStmtClass:
+ case Stmt::IndirectGotoStmtClass:
+ case Stmt::ReturnStmtClass:
+ case Stmt::GCCAsmStmtClass:
+ case Stmt::MSAsmStmtClass:
+ case Stmt::OMPParallelDirectiveClass:
+ case Stmt::OMPTaskwaitDirectiveClass:
+ case Stmt::OMPTaskyieldDirectiveClass:
+ case Stmt::OMPBarrierDirectiveClass:
+ case Stmt::CapturedStmtClass:
+ case Stmt::ObjCAtTryStmtClass:
+ case Stmt::ObjCAtThrowStmtClass:
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ case Stmt::ObjCForCollectionStmtClass:
+ case Stmt::ObjCAutoreleasePoolStmtClass:
+ case Stmt::SEHTryStmtClass:
+ case Stmt::OMPMetaDirectiveClass:
+ case Stmt::OMPCanonicalLoopClass:
+ case Stmt::OMPSimdDirectiveClass:
+ case Stmt::OMPTileDirectiveClass:
+ case Stmt::OMPUnrollDirectiveClass:
+ case Stmt::OMPForDirectiveClass:
+ case Stmt::OMPForSimdDirectiveClass:
+ case Stmt::OMPSectionsDirectiveClass:
+ case Stmt::OMPSectionDirectiveClass:
+ case Stmt::OMPSingleDirectiveClass:
+ case Stmt::OMPMasterDirectiveClass:
+ case Stmt::OMPCriticalDirectiveClass:
+ case Stmt::OMPParallelForDirectiveClass:
+ case Stmt::OMPParallelForSimdDirectiveClass:
+ case Stmt::OMPParallelMasterDirectiveClass:
+ case Stmt::OMPParallelSectionsDirectiveClass:
+ case Stmt::OMPTaskDirectiveClass:
+ case Stmt::OMPTaskgroupDirectiveClass:
+ case Stmt::OMPFlushDirectiveClass:
+ case Stmt::OMPDepobjDirectiveClass:
+ case Stmt::OMPScanDirectiveClass:
+ case Stmt::OMPOrderedDirectiveClass:
+ case Stmt::OMPAtomicDirectiveClass:
+ case Stmt::OMPTargetDirectiveClass:
+ case Stmt::OMPTeamsDirectiveClass:
+ case Stmt::OMPCancellationPointDirectiveClass:
+ case Stmt::OMPCancelDirectiveClass:
+ case Stmt::OMPTargetDataDirectiveClass:
+ case Stmt::OMPTargetEnterDataDirectiveClass:
+ case Stmt::OMPTargetExitDataDirectiveClass:
+ case Stmt::OMPTargetParallelDirectiveClass:
+ case Stmt::OMPTargetParallelForDirectiveClass:
+ case Stmt::OMPTaskLoopDirectiveClass:
+ case Stmt::OMPTaskLoopSimdDirectiveClass:
+ case Stmt::OMPMaskedTaskLoopDirectiveClass:
+ case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
+ case Stmt::OMPMasterTaskLoopDirectiveClass:
+ case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
+ case Stmt::OMPParallelGenericLoopDirectiveClass:
+ case Stmt::OMPParallelMaskedDirectiveClass:
+ case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
+ case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
+ case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
+ case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
+ case Stmt::OMPDistributeDirectiveClass:
+ case Stmt::OMPDistributeParallelForDirectiveClass:
+ case Stmt::OMPDistributeParallelForSimdDirectiveClass:
+ case Stmt::OMPDistributeSimdDirectiveClass:
+ case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
+ case Stmt::OMPTargetParallelForSimdDirectiveClass:
+ case Stmt::OMPTargetSimdDirectiveClass:
+ case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
+ case Stmt::OMPTargetUpdateDirectiveClass:
+ case Stmt::OMPTeamsDistributeDirectiveClass:
+ case Stmt::OMPTeamsDistributeSimdDirectiveClass:
+ case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
+ case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
+ case Stmt::OMPTeamsGenericLoopDirectiveClass:
+ case Stmt::OMPTargetTeamsDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
+ case Stmt::OMPInteropDirectiveClass:
+ case Stmt::OMPDispatchDirectiveClass:
+ case Stmt::OMPGenericLoopDirectiveClass:
+ case Stmt::OMPReverseDirectiveClass:
+ case Stmt::OMPInterchangeDirectiveClass:
+ case Stmt::OMPAssumeDirectiveClass:
+ case Stmt::OMPMaskedDirectiveClass:
+ case Stmt::OpenACCComputeConstructClass:
+ case Stmt::OpenACCLoopConstructClass:
+ case Stmt::OpenACCCombinedConstructClass:
+ case Stmt::OpenACCDataConstructClass:
+ case Stmt::OpenACCEnterDataConstructClass:
+ case Stmt::OpenACCExitDataConstructClass:
+ case Stmt::OpenACCHostDataConstructClass:
+ case Stmt::OpenACCWaitConstructClass:
+ case Stmt::OpenACCInitConstructClass:
+ case Stmt::OpenACCShutdownConstructClass:
+ case Stmt::OpenACCSetConstructClass:
+ case Stmt::OpenACCUpdateConstructClass:
+ case Stmt::ObjCAtCatchStmtClass:
+ case Stmt::ObjCAtFinallyStmtClass:
+ cgm.errorNYI(s->getSourceRange(),
+ std::string("emitStmt: ") + s->getStmtClassName());
+ }
return mlir::failure();
}
diff --git a/clang/test/CIR/CodeGen/basic.c b/clang/test/CIR/CodeGen/basic.c
new file mode 100644
index 0000000000000..8d067aefded66
--- /dev/null
+++ b/clang/test/CIR/CodeGen/basic.c
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+
+int f1(int i);
+
+int f1(int i) {
+ i;
+ return i;
+}
+
+// CIR: module
+// CIR-NEXT: cir.func @f1(%arg0: !cir.int<s, 32> loc({{.*}})) -> !cir.int<s, 32>
+// CIR-NEXT: %[[I_PTR:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 32>>, ["i", init] {alignment = 4 : i64}
+// CIR-NEXT: cir.store %arg0, %[[I_PTR]] : !cir.int<s, 32>, !cir.ptr<!cir.int<s, 32>>
+// CIR-NEXT: %[[I_IGNORED:.*]] = cir.load %[[I_PTR]] : !cir.ptr<!cir.int<s, 32>>, !cir.int<s, 32>
+// CIR-NEXT: %[[I:.*]] = cir.load %[[I_PTR]] : !cir.ptr<!cir.int<s, 32>>, !cir.int<s, 32>
+// CIR-NEXT: cir.return %[[I]] : !cir.int<s, 32>
+
+// LLVM: define i32 @f1(i32 %[[I:.*]])
+// LLVM-NEXT: %[[I_PTR:.*]] = alloca i32, i64 1, align 4
+// LLVM-NEXT: store i32 %[[I]], ptr %[[I_PTR]], align 4
+// LLVM-NEXT: %[[I_IGNORED:.*]] = load i32, ptr %[[I_PTR]], align 4
+// LLVM-NEXT: %[[I:.*]] = load i32, ptr %[[I_PTR]], align 4
+// LLVM-NEXT: ret i32 %[[I]]
+
+int f2(void) { return 3; }
+
+// CIR: cir.func @f2() -> !cir.int<s, 32>
+// CIR-NEXT: %[[THREE:.*]] = cir.const #cir.int<3> : !cir.int<s, 32>
+// CIR-NEXT: cir.return %[[THREE]] : !cir.int<s, 32>
+
+// LLVM: define i32 @f2()
+// LLVM-NEXT: ret i32 3
+
+int f3(void) {
+ int i = 3;
+ return i;
+}
+
+// CIR: cir.func @f3() -> !cir.int<s, 32>
+// CIR-NEXT: %[[I_PTR:.*]] = cir.alloca !cir.int<s, 32>, !cir.ptr<!cir.int<s, 32>>, ["i", init] {alignment = 4 : i64}
+// CIR-NEXT: %[[THREE:.*]] = cir.const #cir.int<3> : !cir.int<s, 32>
+// CIR-NEXT: cir.store %[[THREE]], %[[I_PTR]] : !cir.int<s, 32>, !cir.ptr<!cir.int<s, 32>>
+// CIR-NEXT: %[[I:.*]] = cir.load %[[I_PTR]] : !cir.ptr<!cir.int<s, 32>>, !cir.int<s, 32>
+// CIR-NEXT: cir.return %[[I]] : !cir.int<s, 32>
+
+// LLVM: define i32 @f3()
+// LLVM-NEXT: %[[I_PTR:.*]] = alloca i32, i64 1, align 4
+// LLVM-NEXT: store i32 3, ptr %[[I_PTR]], align 4
+// LLVM-NEXT: %[[I:.*]] = load i32, ptr %[[I_PTR]], align 4
+// LLVM-NEXT: ret i32 %[[I]]
|
clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Outdated
void CIRGenFunction::emitIgnoredExpr(const Expr *e) { | ||
if (e->isPRValue()) { | ||
assert(!cir::MissingFeatures::aggValueSlot()); | ||
return (void)emitAnyExpr(e, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hah, this line is perhaps overly cute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, yeah. I meant to split this out into separate call and return statements. I was actually a bit surprised that this even works.
// CIR-NEXT: %[[I:.*]] = cir.load %[[I_PTR]] : !cir.ptr<!cir.int<s, 32>>, !cir.int<s, 32> | ||
// CIR-NEXT: cir.return %[[I]] : !cir.int<s, 32> | ||
|
||
// LLVM: define i32 @f1(i32 %[[I:.*]]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this llvm from clang itself, or via lowering from CIR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's lowering through clangir to llvm ir.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be neat if we had all 3? WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Recording our discussion here for the benefit of those who weren't present, we agreed that although this will require a bit of extra work for each test, it will have at least two significant benefits: (1) it will allow reviewers to easily compare the LLVM IR generated via CIR to that generated by classic codegen, and (2) it will alert us via a failed test when something changes in the classic codegen that we might also want to consider in the CIR path.
Conclusion: yes, this is worth doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The more the merrier :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be neat if the IR test was:
->CIR
->CIR->LLVM
AND
->LLVM
it sets the precedent for our 'future' and makes it easier to have a test form of the "converted" tests later, and makes it easier to review for correctness, but I'm willing ot let the group discuss it.
Else, I'm good with this.
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t.ll | ||
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM | ||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll | ||
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually curious why these use an intermediary file instead of just a pipe? IIRC this ends up slowing the test down slightly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I don't see any reason for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason we've been doing that is solely making our lives to develop more efficiently. I guess YMMV but whenever I'm investigating a test failure, it's very convenient not to have to pipe the output myself in a file and open in the editor, output is already there and gets updated automatically, etc - in VSCode it's specially handy, cause you click the output file name in the terminal and voila.
Our idea is that whenever we hit a certain maturity state we'll probably bulk change those to use pipes instead, but they are still extremely useful on a daily basis.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the intermediate files got automatically deleted. I can put this back to using the intermediate files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 nits, else LGTM.
clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Outdated
@@ -165,6 +165,34 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) { | |||
return LValue(); | |||
} | |||
|
|||
/// Emit code to compute the specified expression which | |||
/// can have any type. The result is returned as an RValue struct. | |||
RValue CIRGenFunction::emitAnyExpr(const Expr *e, bool ignoreResult) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is ignoreResult
used anywhere? Might need a cast-to-void here to prevent diagnostics.
/// result is returned as an RValue struct. If this is an aggregate | ||
/// expression, the aggloc/agglocvolatile arguments indicate where the result | ||
/// should be returned. | ||
RValue emitAnyExpr(const clang::Expr *e, bool ignoreResult = false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd vastly prefer this not have a default argument
This adds support for emitting ClangIR for statements whose value is ignored. The test case being added (CIR/CodeGen/basic.c) tests a few more things. The "f1" test case is the only part that's immediately relevant to this change, but the other cases were part of the same test in the incubator and they are supported so I brought in the entire test.
This adds support for emitting ClangIR for statements whose value is ignored. The test case being added (CIR/CodeGen/basic.c) tests a few more things. The "f1" test case is the only part that's immediately relevant to this change, but the other cases were part of the same test in the incubator and they are supported so I brought in the entire test.