Skip to content

[CIR][CIRGen] Add support for abs #1011

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 9 commits into from
Oct 30, 2024
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
20 changes: 20 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -4005,6 +4005,26 @@ def SinOp : UnaryFPToFPBuiltinOp<"sin", "SinOp">;
def SqrtOp : UnaryFPToFPBuiltinOp<"sqrt", "SqrtOp">;
def TruncOp : UnaryFPToFPBuiltinOp<"trunc", "FTruncOp">;

def AbsOp : CIR_Op<"abs", [Pure, SameOperandsAndResultType]> {
let arguments = (ins PrimitiveSInt:$src, UnitAttr:$poison);
let results = (outs PrimitiveSInt:$result);
let summary = [{
libc builtin equivalent abs, labs, llabs

The `poison` argument indicate whether the result value
is a poison value if the first argument is statically or
dynamically an INT_MIN value.

Example:

```mlir
%0 = cir.const #cir.int<-42> : s32i
%1 = cir.abs %0 poison : s32i
```
}];
let assemblyFormat = "$src ( `poison` $poison^ )? `:` type($src) attr-dict";
}

class BinaryFPToFPBuiltinOp<string mnemonic, string llvmOpName>
: CIR_Op<mnemonic, [Pure, SameOperandsAndResultType]> {
let summary = [{
Expand Down
30 changes: 27 additions & 3 deletions clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,9 +855,33 @@ RValue CIRGenFunction::buildBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIllabs:
case Builtin::BI__builtin_abs:
case Builtin::BI__builtin_labs:
case Builtin::BI__builtin_llabs:
llvm_unreachable("Builtin::BIabs like NYI");

case Builtin::BI__builtin_llabs: {
bool SanitizeOverflow = SanOpts.has(SanitizerKind::SignedIntegerOverflow);
auto Arg = buildScalarExpr(E->getArg(0));
mlir::Value Result;
switch (getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined: {
auto Call = getBuilder().create<mlir::cir::AbsOp>(
getLoc(E->getExprLoc()), Arg.getType(), Arg, false);
Result = Call->getResult(0);
break;
}
case LangOptions::SOB_Undefined: {
if (!SanitizeOverflow) {
auto Call = getBuilder().create<mlir::cir::AbsOp>(
getLoc(E->getExprLoc()), Arg.getType(), Arg, true);
Result = Call->getResult(0);
break;
}
llvm_unreachable("BI__builtin_abs with LangOptions::SOB_Undefined when "
"SanitizeOverflow is true");
}
[[fallthrough]];
case LangOptions::SOB_Trapping:
llvm_unreachable("BI__builtin_abs with LangOptions::SOB_Trapping");
}
return RValue::get(Result);
}
case Builtin::BI__builtin_complex: {
mlir::Value Real = buildScalarExpr(E->getArg(0));
mlir::Value Imag = buildScalarExpr(E->getArg(1));
Expand Down
16 changes: 15 additions & 1 deletion clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4155,6 +4155,20 @@ class CIRIsFPClassOpLowering
return mlir::success();
}
};
class CIRAbsOpLowering : public mlir::OpConversionPattern<mlir::cir::AbsOp> {
public:
using OpConversionPattern<mlir::cir::AbsOp>::OpConversionPattern;

mlir::LogicalResult
matchAndRewrite(mlir::cir::AbsOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override {
auto resTy = this->getTypeConverter()->convertType(op.getType());
auto absOp = rewriter.create<mlir::LLVM::AbsOp>(
op.getLoc(), resTy, adaptor.getOperands()[0], adaptor.getPoison());
rewriter.replaceOp(op, absOp);
return mlir::success();
}
};

void populateCIRToLLVMConversionPatterns(
mlir::RewritePatternSet &patterns, mlir::TypeConverter &converter,
Expand Down Expand Up @@ -4193,7 +4207,7 @@ void populateCIRToLLVMConversionPatterns(
CIREhTypeIdOpLowering, CIRCatchParamOpLowering, CIRResumeOpLowering,
CIRAllocExceptionOpLowering, CIRFreeExceptionOpLowering,
CIRThrowOpLowering, CIRIntrinsicCallLowering, CIRBaseClassAddrOpLowering,
CIRVTTAddrPointOpLowering, CIRIsFPClassOpLowering
CIRVTTAddrPointOpLowering, CIRIsFPClassOpLowering, CIRAbsOpLowering
#define GET_BUILTIN_LOWERING_LIST
#include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc"
#undef GET_BUILTIN_LOWERING_LIST
Expand Down
25 changes: 18 additions & 7 deletions clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
#include "mlir/Transforms/DialectConversion.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/LoweringHelpers.h"
#include "clang/CIR/LowerToMLIR.h"
#include "clang/CIR/LoweringHelpers.h"
#include "clang/CIR/Passes.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
Expand Down Expand Up @@ -244,6 +244,17 @@ class CIRFAbsOpLowering : public mlir::OpConversionPattern<mlir::cir::FAbsOp> {
return mlir::LogicalResult::success();
}
};
class CIRAbsOpLowering : public mlir::OpConversionPattern<mlir::cir::AbsOp> {
public:
using mlir::OpConversionPattern<mlir::cir::AbsOp>::OpConversionPattern;

mlir::LogicalResult
matchAndRewrite(mlir::cir::AbsOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override {
rewriter.replaceOpWithNewOp<mlir::math::AbsIOp>(op, adaptor.getSrc());
return mlir::LogicalResult::success();
}
};

class CIRFloorOpLowering
: public mlir::OpConversionPattern<mlir::cir::FloorOp> {
Expand Down Expand Up @@ -1324,12 +1335,12 @@ void populateCIRToMLIRConversionPatterns(mlir::RewritePatternSet &patterns,
CIRCosOpLowering, CIRGlobalOpLowering, CIRGetGlobalOpLowering,
CIRCastOpLowering, CIRPtrStrideOpLowering, CIRSqrtOpLowering,
CIRCeilOpLowering, CIRExp2OpLowering, CIRExpOpLowering, CIRFAbsOpLowering,
CIRFloorOpLowering, CIRLog10OpLowering, CIRLog2OpLowering,
CIRLogOpLowering, CIRRoundOpLowering, CIRPtrStrideOpLowering,
CIRSinOpLowering, CIRShiftOpLowering, CIRBitClzOpLowering,
CIRBitCtzOpLowering, CIRBitPopcountOpLowering, CIRBitClrsbOpLowering,
CIRBitFfsOpLowering, CIRBitParityOpLowering, CIRIfOpLowering,
CIRVectorCreateLowering, CIRVectorInsertLowering,
CIRAbsOpLowering, CIRFloorOpLowering, CIRLog10OpLowering,
CIRLog2OpLowering, CIRLogOpLowering, CIRRoundOpLowering,
CIRPtrStrideOpLowering, CIRSinOpLowering, CIRShiftOpLowering,
CIRBitClzOpLowering, CIRBitCtzOpLowering, CIRBitPopcountOpLowering,
CIRBitClrsbOpLowering, CIRBitFfsOpLowering, CIRBitParityOpLowering,
CIRIfOpLowering, CIRVectorCreateLowering, CIRVectorInsertLowering,
CIRVectorExtractLowering, CIRVectorCmpOpLowering>(converter,
patterns.getContext());
}
Expand Down
34 changes: 34 additions & 0 deletions clang/test/CIR/CodeGen/libc.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s

// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -fwrapv
// RUN: FileCheck --check-prefix=CIR_NO_POSION --input-file=%t.cir %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -fwrapv
// RUN: FileCheck --check-prefix=LLVM_NO_POSION --input-file=%t.ll %s

// Should generate CIR's builtin memcpy op.
void *memcpy(void *, const void *, unsigned long);
Expand All @@ -19,3 +26,30 @@ float testFabsf(float x) {
return fabsf(x);
// CHECK: cir.fabs %{{.+}} : !cir.float
}

int abs(int);
int testAbs(int x) {
return abs(x);
// CHECK: cir.abs %{{.+}} poison : !s32i
// LLVM: %{{.+}} = call i32 @llvm.abs.i32(i32 %{{.+}}, i1 true)
// CIR_NO_POSION: cir.abs %{{.+}} : !s32i
// LLVM_NO_POSION: %{{.+}} = call i32 @llvm.abs.i32(i32 %{{.+}}, i1 false)
}

long labs(long);
long testLabs(long x) {
return labs(x);
// CHECK: cir.abs %{{.+}} poison : !s64i
// LLVM: %{{.+}} = call i64 @llvm.abs.i64(i64 %{{.+}}, i1 true)
// CIR_NO_POSION: cir.abs %{{.+}} : !s64i
// LLVM_NO_POSION: %{{.+}} = call i64 @llvm.abs.i64(i64 %{{.+}}, i1 false)
}

long long llabs(long long);
long long testLlabs(long long x) {
return llabs(x);
// CHECK: cir.abs %{{.+}} poison : !s64i
// LLVM: %{{.+}} = call i64 @llvm.abs.i64(i64 %{{.+}}, i1 true)
// CIR_NO_POSION: cir.abs %{{.+}} : !s64i
// LLVM_NO_POSION: %{{.+}} = call i64 @llvm.abs.i64(i64 %{{.+}}, i1 false)
}
23 changes: 23 additions & 0 deletions clang/test/CIR/Lowering/ThroughMLIR/abs.cir
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: cir-opt %s -cir-to-mlir -o %t.mlir
// RUN: FileCheck %s --input-file %t.mlir
!s32i = !cir.int<s, 32>
!s64i = !cir.int<s, 64>
module {
cir.func @foo() {
%0 = cir.const #cir.int<-1> : !s32i
%1 = cir.const #cir.int<-2> : !s64i
%4 = cir.abs %0 : !s32i
%5 = cir.abs %1 : !s64i
cir.return
}
}

// CHECK: module {
// CHECK-NEXT: func.func @foo() {
// CHECK-NEXT: %[[C0:.+]] = arith.constant -1 : i32
// CHECK-NEXT: %[[C1:.+]] = arith.constant -2 : i64
// CHECK-NEXT: %{{.+}} = math.absi %[[C0]] : i32
// CHECK-NEXT: %{{.+}} = math.absi %[[C1]] : i64
// CHECK-NEXT: return
// CHECK-NEXT: }
// CHECK-NEXT: }