[clang] [CIR] Upstream builtin lowering emitter & FAbs op (PR #151750)
Amr Hesham via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 2 05:34:36 PDT 2025
https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/151750
>From 756f0656c3ad7788ed80ff9ccc091e19d07d63f8 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Fri, 1 Aug 2025 20:48:02 +0200
Subject: [PATCH 1/2] [CIR] Upstream builtin fabs op
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 18 +++
.../clang/CIR/Dialect/IR/CMakeLists.txt | 4 +
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 23 ++++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 7 ++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 4 +
clang/test/CIR/CodeGen/builtins.cpp | 14 +++
clang/utils/TableGen/CIRLoweringEmitter.cpp | 108 ++++++++++++++++++
clang/utils/TableGen/CMakeLists.txt | 1 +
clang/utils/TableGen/TableGen.cpp | 7 ++
clang/utils/TableGen/TableGenBackends.h | 3 +
10 files changed, 189 insertions(+)
create mode 100644 clang/test/CIR/CodeGen/builtins.cpp
create mode 100644 clang/utils/TableGen/CIRLoweringEmitter.cpp
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 5ef5b60ed5a52..975a8d102d800 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3199,4 +3199,22 @@ def CIR_ExpectOp : CIR_Op<"expect", [
}];
}
+//===----------------------------------------------------------------------===//
+// Floating Point Ops
+//===----------------------------------------------------------------------===//
+
+class CIR_UnaryFPToFPBuiltinOp<string mnemonic, string llvmOpName>
+ : CIR_Op<mnemonic, [Pure, SameOperandsAndResultType]>
+{
+ let arguments = (ins CIR_AnyFloatOrVecOfFloatType:$src);
+ let results = (outs CIR_AnyFloatOrVecOfFloatType:$result);
+ let summary = "libc builtin equivalent ignoring "
+ "floating point exceptions and errno";
+ let assemblyFormat = "$src `:` type($src) attr-dict";
+
+ let llvmOp = llvmOpName;
+}
+
+def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp">;
+
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
index 6e7f3da4add3e..3a574b96340e7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
@@ -20,6 +20,10 @@ mlir_tablegen(CIROpsAttributes.h.inc -gen-attrdef-decls)
mlir_tablegen(CIROpsAttributes.cpp.inc -gen-attrdef-defs)
add_public_tablegen_target(MLIRCIREnumsGen)
+clang_tablegen(CIRBuiltinsLowering.inc -gen-cir-builtins-lowering
+ SOURCE CIROps.td
+ TARGET CIRBuiltinsLowering)
+
set(LLVM_TARGET_DEFINITIONS CIRTypeConstraints.td)
mlir_tablegen(CIRTypeConstraints.h.inc -gen-type-constraint-decls)
mlir_tablegen(CIRTypeConstraints.cpp.inc -gen-type-constraint-defs)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 9049a016b2b9b..201c119c1747f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -71,6 +71,19 @@ RValue CIRGenFunction::emitRotate(const CallExpr *e, bool isRotateLeft) {
return RValue::get(r);
}
+template <class Operation>
+static RValue emitUnaryMaybeConstrainedFPBuiltin(CIRGenFunction &cgf,
+ const CallExpr &e) {
+ mlir::Value arg = cgf.emitScalarExpr(e.getArg(0));
+
+ assert(!cir::MissingFeatures::cgFPOptionsRAII());
+ assert(!cir::MissingFeatures::fpConstraints());
+
+ auto call =
+ cgf.getBuilder().create<Operation>(arg.getLoc(), arg.getType(), arg);
+ return RValue::get(call->getResult(0));
+}
+
RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
const CallExpr *e,
ReturnValueSlot returnValue) {
@@ -111,6 +124,16 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
default:
break;
+ case Builtin::BIfabs:
+ case Builtin::BIfabsf:
+ case Builtin::BIfabsl:
+ case Builtin::BI__builtin_fabs:
+ case Builtin::BI__builtin_fabsf:
+ case Builtin::BI__builtin_fabsf16:
+ case Builtin::BI__builtin_fabsl:
+ case Builtin::BI__builtin_fabsf128:
+ return emitUnaryMaybeConstrainedFPBuiltin<cir::FAbsOp>(*this, *e);
+
case Builtin::BI__assume:
case Builtin::BI__builtin_assume: {
if (e->getArg(0)->HasSideEffects(getContext()))
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 957a51ab334aa..8d18176be8218 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2215,6 +2215,9 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMVecShuffleOpLowering,
CIRToLLVMVecSplatOpLowering,
CIRToLLVMVecTernaryOpLowering
+#define GET_BUILTIN_LOWERING_LIST
+#include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc"
+#undef GET_BUILTIN_LOWERING_LIST
// clang-format on
>(converter, patterns.getContext());
@@ -2792,6 +2795,10 @@ mlir::LogicalResult CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(
return mlir::success();
}
+#define GET_BUILTIN_LOWERING_CLASSES_DEF
+#include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc"
+#undef GET_BUILTIN_LOWERING_CLASSES_DEF
+
std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
return std::make_unique<ConvertCIRToLLVMPass>();
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index f339d4310ae0c..486a6b5daa563 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -628,6 +628,10 @@ class CIRToLLVMGetBitfieldOpLowering
mlir::ConversionPatternRewriter &) const override;
};
+#define GET_BUILTIN_LOWERING_CLASSES_DECLARE
+#include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc"
+#undef GET_BUILTIN_LOWERING_CLASSES_DECLARE
+
} // namespace direct
} // namespace cir
diff --git a/clang/test/CIR/CodeGen/builtins.cpp b/clang/test/CIR/CodeGen/builtins.cpp
new file mode 100644
index 0000000000000..3d43821af4e51
--- /dev/null
+++ b/clang/test/CIR/CodeGen/builtins.cpp
@@ -0,0 +1,14 @@
+// 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-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+double fabs(double x) {
+ return __builtin_fabs(x);
+}
+
+// CIR: {{.*}} = cir.fabs {{.*}} : !cir.double
+// LLVM: {{.*}} = call double @llvm.fabs.f64(double {{.*}})
+// OGCG: {{.*}} = call double @llvm.fabs.f64(double {{.*}})
diff --git a/clang/utils/TableGen/CIRLoweringEmitter.cpp b/clang/utils/TableGen/CIRLoweringEmitter.cpp
new file mode 100644
index 0000000000000..e494f38ef5b02
--- /dev/null
+++ b/clang/utils/TableGen/CIRLoweringEmitter.cpp
@@ -0,0 +1,108 @@
+//===- CIRLoweringEmitter.cpp - Generate lowering of builtins --=-*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "TableGenBackends.h"
+#include "llvm/TableGen/TableGenBackend.h"
+
+using namespace llvm;
+
+namespace {
+std::string ClassDeclaration;
+std::string ClassDefinitions;
+std::string ClassList;
+
+// Adapted from mlir/lib/TableGen/Operator.cpp
+// Returns the C++ class name of the operation, which is the name of the
+// operation with the dialect prefix removed and the first underscore removed.
+// If the operation name starts with an underscore, the underscore is considered
+// part of the class name.
+std::string getCppClassName(const Record *Operation) {
+ StringRef Name = Operation->getName();
+ auto [prefix, cppClassName] = Name.split('_');
+ if (prefix.empty()) {
+ // Class name with a leading underscore and without dialect prefix
+ return Name.str();
+ }
+
+ if (cppClassName.empty()) {
+ // Class name without dialect prefix
+ return prefix.str();
+ }
+
+ return cppClassName.str();
+}
+
+void GenerateLowering(const Record *Operation) {
+ using namespace std::string_literals;
+ std::string Name = getCppClassName(Operation);
+ std::string LLVMOp = Operation->getValueAsString("llvmOp").str();
+
+ ClassDeclaration +=
+ "class CIR" + Name +
+ "Lowering : public mlir::OpConversionPattern<cir::" + Name +
+ R"C++(> {
+ public:
+ using OpConversionPattern<cir::)C++" +
+ Name + R"C++(>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::)C++" +
+ Name +
+ " op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) "
+ "const "
+ "override;" +
+ R"C++(
+};
+)C++";
+
+ ClassDefinitions +=
+ R"C++(mlir::LogicalResult
+CIR)C++" +
+ Name + "Lowering::matchAndRewrite(cir::" + Name +
+ R"C++( op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const {)C++";
+
+ auto ResultCount = Operation->getValueAsDag("results")->getNumArgs();
+ if (ResultCount > 0)
+ ClassDefinitions += R"C++(
+ auto resTy = this->getTypeConverter()->convertType(op.getType());)C++";
+
+ ClassDefinitions += R"C++(
+ rewriter.replaceOpWithNewOp<mlir::LLVM::)C++" +
+ LLVMOp + ">(op";
+
+ if (ResultCount > 0)
+ ClassDefinitions += ", resTy";
+
+ size_t ArgCount = Operation->getValueAsDag("arguments")->getNumArgs();
+ for (size_t i = 0; i != ArgCount; ++i)
+ ClassDefinitions += ", adaptor.getOperands()[" + std::to_string(i) + ']';
+
+ ClassDefinitions += R"C++();
+ return mlir::success();
+}
+)C++";
+
+ ClassList += ", CIR" + Name + "Lowering\n";
+}
+} // namespace
+
+void clang::EmitCIRBuiltinsLowering(const RecordKeeper &Records,
+ raw_ostream &OS) {
+ emitSourceFileHeader("Lowering of ClangIR builtins to LLVM IR builtins", OS);
+ for (const auto *Builtin :
+ Records.getAllDerivedDefinitions("LLVMLoweringInfo")) {
+ if (!Builtin->getValueAsString("llvmOp").empty())
+ GenerateLowering(Builtin);
+ }
+
+ OS << "#ifdef GET_BUILTIN_LOWERING_CLASSES_DECLARE\n"
+ << ClassDeclaration << "\n#endif\n";
+ OS << "#ifdef GET_BUILTIN_LOWERING_CLASSES_DEF\n"
+ << ClassDefinitions << "\n#endif\n";
+ OS << "#ifdef GET_BUILTIN_LOWERING_LIST\n" << ClassList << "\n#endif\n";
+}
diff --git a/clang/utils/TableGen/CMakeLists.txt b/clang/utils/TableGen/CMakeLists.txt
index ce759ec8548d9..14f13824e9575 100644
--- a/clang/utils/TableGen/CMakeLists.txt
+++ b/clang/utils/TableGen/CMakeLists.txt
@@ -4,6 +4,7 @@ add_tablegen(clang-tblgen CLANG
DESTINATION "${CLANG_TOOLS_INSTALL_DIR}"
EXPORT Clang
ASTTableGen.cpp
+ CIRLoweringEmitter.cpp
ClangASTNodesEmitter.cpp
ClangASTPropertiesEmitter.cpp
ClangAttrEmitter.cpp
diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp
index 98c4a07a99c42..d4a383e801085 100644
--- a/clang/utils/TableGen/TableGen.cpp
+++ b/clang/utils/TableGen/TableGen.cpp
@@ -25,6 +25,7 @@ using namespace clang;
enum ActionType {
PrintRecords,
DumpJSON,
+ GenCIRBuiltinsLowering,
GenClangAttrClasses,
GenClangAttrParserStringSwitches,
GenClangAttrSubjectMatchRulesParserStringSwitches,
@@ -128,6 +129,9 @@ cl::opt<ActionType> Action(
"Print all records to stdout (default)"),
clEnumValN(DumpJSON, "dump-json",
"Dump all records as machine-readable JSON"),
+ clEnumValN(GenCIRBuiltinsLowering, "gen-cir-builtins-lowering",
+ "Generate lowering of ClangIR builtins to equivalent LLVM "
+ "IR builtins"),
clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes",
"Generate clang attribute clases"),
clEnumValN(GenClangAttrParserStringSwitches,
@@ -354,6 +358,9 @@ bool ClangTableGenMain(raw_ostream &OS, const RecordKeeper &Records) {
case DumpJSON:
EmitJSON(Records, OS);
break;
+ case GenCIRBuiltinsLowering:
+ EmitCIRBuiltinsLowering(Records, OS);
+ break;
case GenClangAttrClasses:
EmitClangAttrClass(Records, OS);
break;
diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h
index 79b1f66d0e49e..26d9e2c611898 100644
--- a/clang/utils/TableGen/TableGenBackends.h
+++ b/clang/utils/TableGen/TableGenBackends.h
@@ -24,6 +24,9 @@ class RecordKeeper;
namespace clang {
+void EmitCIRBuiltinsLowering(const llvm::RecordKeeper &RK,
+ llvm::raw_ostream &OS);
+
void EmitClangDeclContext(const llvm::RecordKeeper &RK, llvm::raw_ostream &OS);
/**
@param PriorizeIfSubclassOf These classes should be prioritized in the output.
>From 834eb5c09bb4cca1aea1697a7a54cfdf208b821e Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Sat, 2 Aug 2025 09:42:09 +0200
Subject: [PATCH 2/2] Address code review comments
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 12 ++++--
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 2 +-
.../TableGen/emit-cir-builtins-lowering.td | 42 +++++++++++++++++++
clang/utils/TableGen/TableGen.cpp | 9 +++-
4 files changed, 60 insertions(+), 5 deletions(-)
create mode 100644 clang/test/TableGen/emit-cir-builtins-lowering.td
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 975a8d102d800..efbe5d84df901 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3208,13 +3208,19 @@ class CIR_UnaryFPToFPBuiltinOp<string mnemonic, string llvmOpName>
{
let arguments = (ins CIR_AnyFloatOrVecOfFloatType:$src);
let results = (outs CIR_AnyFloatOrVecOfFloatType:$result);
- let summary = "libc builtin equivalent ignoring "
- "floating point exceptions and errno";
+
let assemblyFormat = "$src `:` type($src) attr-dict";
let llvmOp = llvmOpName;
}
-def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp">;
+def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp"> {
+ let summary = "Computes the floating-point absolute value";
+ let description = [{
+ `cir.fabs` computes the absolute value of a floating-point operand
+ and returns a result of the same type, ignoring floating-point
+ exceptions. It does not set `errno`.
+ }];
+}
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 201c119c1747f..748fb9d79c102 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -80,7 +80,7 @@ static RValue emitUnaryMaybeConstrainedFPBuiltin(CIRGenFunction &cgf,
assert(!cir::MissingFeatures::fpConstraints());
auto call =
- cgf.getBuilder().create<Operation>(arg.getLoc(), arg.getType(), arg);
+ Operation::create(cgf.getBuilder(), arg.getLoc(), arg.getType(), arg);
return RValue::get(call->getResult(0));
}
diff --git a/clang/test/TableGen/emit-cir-builtins-lowering.td b/clang/test/TableGen/emit-cir-builtins-lowering.td
new file mode 100644
index 0000000000000..bcc0c7450f5d4
--- /dev/null
+++ b/clang/test/TableGen/emit-cir-builtins-lowering.td
@@ -0,0 +1,42 @@
+// RUN: clang-tblgen -gen-cir-builtins-lowering -I%S %s -o - 2>&1 | \
+// RUN: FileCheck --strict-whitespace %s
+
+def ins;
+def outs;
+
+class OpBase {
+ dag arguments = (ins);
+ dag results = (outs);
+}
+
+class LLVMLoweringInfo {
+ string llvmOp = "";
+}
+
+class CIR_Op : LLVMLoweringInfo, OpBase;
+
+def CIR_FAbsOp : CIR_Op {
+ let arguments = (ins);
+ let results = (outs);
+
+ let llvmOp = "FAbsOp";
+}
+
+// CHECK: #ifdef GET_BUILTIN_LOWERING_CLASSES_DECLARE
+// CHECK: class CIRFAbsOpLowering : public mlir::OpConversionPattern<cir::FAbsOp> {
+// CHECK: public:
+// CHECK: using OpConversionPattern<cir::FAbsOp>::OpConversionPattern;
+// CHECK: mlir::LogicalResult
+// CHECK: matchAndRewrite(cir::FAbsOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const override;
+// CHECK: };
+// CHECK: #endif
+// CHECK: #ifdef GET_BUILTIN_LOWERING_CLASSES_DEF
+// CHECK: mlir::LogicalResult
+// CHECK: CIRFAbsOpLowering::matchAndRewrite(cir::FAbsOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const {
+// CHECK: rewriter.replaceOpWithNewOp<mlir::LLVM::FAbsOp>(op);
+// CHECK: return mlir::success();
+// CHECK: }
+// CHECK: #endif
+// CHECK: #ifdef GET_BUILTIN_LOWERING_LIST
+// CHECK: , CIRFAbsOpLowering
+// CHECK: #endif
diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp
index d4a383e801085..74f7b74952d19 100644
--- a/clang/utils/TableGen/TableGen.cpp
+++ b/clang/utils/TableGen/TableGen.cpp
@@ -12,6 +12,7 @@
#include "ASTTableGen.h"
#include "TableGenBackends.h" // Declares all backends.
+#include "clang/Config/config.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
@@ -25,7 +26,9 @@ using namespace clang;
enum ActionType {
PrintRecords,
DumpJSON,
+#if CLANG_ENABLE_CIR
GenCIRBuiltinsLowering,
+#endif // CLANG_ENABLE_CIR
GenClangAttrClasses,
GenClangAttrParserStringSwitches,
GenClangAttrSubjectMatchRulesParserStringSwitches,
@@ -129,9 +132,11 @@ cl::opt<ActionType> Action(
"Print all records to stdout (default)"),
clEnumValN(DumpJSON, "dump-json",
"Dump all records as machine-readable JSON"),
+#if CLANG_ENABLE_CIR
clEnumValN(GenCIRBuiltinsLowering, "gen-cir-builtins-lowering",
"Generate lowering of ClangIR builtins to equivalent LLVM "
"IR builtins"),
+#endif // CLANG_ENABLE_CIR
clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes",
"Generate clang attribute clases"),
clEnumValN(GenClangAttrParserStringSwitches,
@@ -358,9 +363,11 @@ bool ClangTableGenMain(raw_ostream &OS, const RecordKeeper &Records) {
case DumpJSON:
EmitJSON(Records, OS);
break;
+#if CLANG_ENABLE_CIR
case GenCIRBuiltinsLowering:
EmitCIRBuiltinsLowering(Records, OS);
break;
+#endif // CLANG_ENABLE_CIR
case GenClangAttrClasses:
EmitClangAttrClass(Records, OS);
break;
@@ -646,7 +653,7 @@ bool ClangTableGenMain(raw_ostream &OS, const RecordKeeper &Records) {
return false;
}
-}
+} // namespace
int main(int argc, char **argv) {
sys::PrintStackTraceOnErrorSignal(argv[0]);
More information about the cfe-commits
mailing list