Skip to content

Commit 996ddac

Browse files
committed
[CIR] Add rotate operation
1 parent 265fb36 commit 996ddac

File tree

6 files changed

+226
-0
lines changed

6 files changed

+226
-0
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2847,6 +2847,45 @@ def ByteSwapOp : CIR_BitOpBase<"byte_swap", CIR_UIntOfWidths<[16, 32, 64]>> {
28472847
}];
28482848
}
28492849

2850+
//===----------------------------------------------------------------------===//
2851+
// RotateOp
2852+
//===----------------------------------------------------------------------===//
2853+
2854+
def RotateOp : CIR_Op<"rotate", [Pure, SameOperandsAndResultType]> {
2855+
let summary = "Rotate the bits in the operand integer";
2856+
let description = [{
2857+
The `cir.rotate` rotates the bits in `input` by the given amount `amount`.
2858+
The rotate direction is specified by the `left` and `right` keyword.
2859+
2860+
`input` must be an unsigned integer and its with must be either 8, 16, 32,
2861+
or 64. The types of `input`, `amount`, and the result must all match.
2862+
2863+
Example:
2864+
2865+
```mlir
2866+
%r = cir.rotate left %0, %1 : !u32i
2867+
%r = cir.rotate right %0, %1 : !u32i
2868+
```
2869+
}];
2870+
2871+
let results = (outs CIR_IntType:$result);
2872+
let arguments = (ins
2873+
CIR_UIntOfWidths<[8, 16, 32, 64]>:$input,
2874+
CIR_IntType:$amount,
2875+
UnitAttr:$rotateLeft
2876+
);
2877+
2878+
let assemblyFormat = [{
2879+
(`left` $rotateLeft^) : (`right`)?
2880+
$input `,` $amount `:` type($result) attr-dict
2881+
}];
2882+
2883+
let extraClassDeclaration = [{
2884+
bool isRotateLeft() { return getRotateLeft(); }
2885+
bool isRotateRight() { return !getRotateLeft(); }
2886+
}];
2887+
}
2888+
28502889
//===----------------------------------------------------------------------===//
28512890
// Assume Operations
28522891
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e,
5757
return RValue::get(result);
5858
}
5959

60+
RValue CIRGenFunction::emitRotate(const CallExpr *e, bool isRotateLeft) {
61+
mlir::Value input = emitScalarExpr(e->getArg(0));
62+
mlir::Value amount = emitScalarExpr(e->getArg(1));
63+
64+
auto r = builder.create<cir::RotateOp>(getLoc(e->getSourceRange()), input,
65+
amount, isRotateLeft);
66+
return RValue::get(r);
67+
}
68+
6069
RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
6170
const CallExpr *e,
6271
ReturnValueSlot returnValue) {
@@ -219,6 +228,18 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
219228
mlir::Value arg = emitScalarExpr(e->getArg(0));
220229
return RValue::get(builder.create<cir::BitReverseOp>(loc, arg));
221230
}
231+
232+
case Builtin::BI__builtin_rotateleft8:
233+
case Builtin::BI__builtin_rotateleft16:
234+
case Builtin::BI__builtin_rotateleft32:
235+
case Builtin::BI__builtin_rotateleft64:
236+
return emitRotate(e, /*isRotateLeft=*/true);
237+
238+
case Builtin::BI__builtin_rotateright8:
239+
case Builtin::BI__builtin_rotateright16:
240+
case Builtin::BI__builtin_rotateright32:
241+
case Builtin::BI__builtin_rotateright64:
242+
return emitRotate(e, /*isRotateLeft=*/false);
222243
}
223244

224245
// If this is an alias for a lib function (e.g. __builtin_sin), emit

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,8 @@ class CIRGenFunction : public CIRGenTypeCache {
10291029

10301030
mlir::LogicalResult emitReturnStmt(const clang::ReturnStmt &s);
10311031

1032+
RValue emitRotate(const CallExpr *e, bool isRotateLeft);
1033+
10321034
mlir::Value emitScalarConstant(const ConstantEmission &constant, Expr *e);
10331035

10341036
/// Emit a conversion from the specified type to the specified destination

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,21 @@ mlir::LogicalResult CIRToLLVMReturnOpLowering::matchAndRewrite(
872872
return mlir::LogicalResult::success();
873873
}
874874

875+
mlir::LogicalResult CIRToLLVMRotateOpLowering::matchAndRewrite(
876+
cir::RotateOp op, OpAdaptor adaptor,
877+
mlir::ConversionPatternRewriter &rewriter) const {
878+
// Note that LLVM intrinsic calls to @llvm.fsh{r,l}.i* have the same type as
879+
// the operand.
880+
auto input = adaptor.getInput();
881+
if (op.isRotateLeft())
882+
rewriter.replaceOpWithNewOp<mlir::LLVM::FshlOp>(op, input, input,
883+
adaptor.getAmount());
884+
else
885+
rewriter.replaceOpWithNewOp<mlir::LLVM::FshrOp>(op, input, input,
886+
adaptor.getAmount());
887+
return mlir::LogicalResult::success();
888+
}
889+
875890
static mlir::LogicalResult
876891
rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
877892
mlir::ConversionPatternRewriter &rewriter,
@@ -2075,6 +2090,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
20752090
CIRToLLVMGetBitfieldOpLowering,
20762091
CIRToLLVMGetGlobalOpLowering,
20772092
CIRToLLVMGetMemberOpLowering,
2093+
CIRToLLVMRotateOpLowering,
20782094
CIRToLLVMSelectOpLowering,
20792095
CIRToLLVMSetBitfieldOpLowering,
20802096
CIRToLLVMShiftOpLowering,

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,16 @@ class CIRToLLVMReturnOpLowering
160160
mlir::ConversionPatternRewriter &) const override;
161161
};
162162

163+
class CIRToLLVMRotateOpLowering
164+
: public mlir::OpConversionPattern<cir::RotateOp> {
165+
public:
166+
using mlir::OpConversionPattern<cir::RotateOp>::OpConversionPattern;
167+
168+
mlir::LogicalResult
169+
matchAndRewrite(cir::RotateOp op, OpAdaptor,
170+
mlir::ConversionPatternRewriter &) const override;
171+
};
172+
163173
class CIRToLLVMCallOpLowering : public mlir::OpConversionPattern<cir::CallOp> {
164174
public:
165175
using mlir::OpConversionPattern<cir::CallOp>::OpConversionPattern;

clang/test/CIR/CodeGen/builtin_bit.cpp

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,3 +416,141 @@ unsigned long long test_builtin_bswap64(unsigned long long x) {
416416

417417
// OGCG-LABEL: @_Z20test_builtin_bswap64y
418418
// OGCG: %{{.+}} = call i64 @llvm.bswap.i64(i64 %{{.+}})
419+
420+
unsigned char test_builtin_rotateleft8(unsigned char x, unsigned char y) {
421+
return __builtin_rotateleft8(x, y);
422+
}
423+
424+
// CIR-LABEL: @_Z24test_builtin_rotateleft8hh
425+
// CIR: %{{.+}} = cir.rotate left %{{.+}}, %{{.+}} : !u8i
426+
427+
// LLVM-LABEL: @_Z24test_builtin_rotateleft8hh
428+
// LLVM: %[[INPUT:.+]] = load i8, ptr %{{.+}}, align 1
429+
// LLVM-NEXT: %[[AMOUNT:.+]] = load i8, ptr %{{.+}}, align 1
430+
// LLVM-NEXT: %{{.+}} = call i8 @llvm.fshl.i8(i8 %[[INPUT]], i8 %[[INPUT]], i8 %[[AMOUNT]])
431+
432+
// OGCG-LABEL: @_Z24test_builtin_rotateleft8hh
433+
// OGCG: %[[INPUT:.+]] = load i8, ptr %{{.+}}, align 1
434+
// OGCG-NEXT: %[[AMOUNT:.+]] = load i8, ptr %{{.+}}, align 1
435+
// OGCG-NEXT: %{{.+}} = call i8 @llvm.fshl.i8(i8 %[[INPUT]], i8 %[[INPUT]], i8 %[[AMOUNT]])
436+
437+
unsigned short test_builtin_rotateleft16(unsigned short x, unsigned short y) {
438+
return __builtin_rotateleft16(x, y);
439+
}
440+
441+
// CIR-LABEL: @_Z25test_builtin_rotateleft16tt
442+
// CIR: %{{.+}} = cir.rotate left %{{.+}}, %{{.+}} : !u16i
443+
444+
// LLVM-LABEL: @_Z25test_builtin_rotateleft16tt
445+
// LLVM: %[[INPUT:.+]] = load i16, ptr %{{.+}}, align 2
446+
// LLVM-NEXT: %[[AMOUNT:.+]] = load i16, ptr %{{.+}}, align 2
447+
// LLVM-NEXT: %{{.+}} = call i16 @llvm.fshl.i16(i16 %[[INPUT]], i16 %[[INPUT]], i16 %[[AMOUNT]])
448+
449+
// OGCG-LABEL: @_Z25test_builtin_rotateleft16tt
450+
// OGCG: %[[INPUT:.+]] = load i16, ptr %{{.+}}, align 2
451+
// OGCG-NEXT: %[[AMOUNT:.+]] = load i16, ptr %{{.+}}, align 2
452+
// OGCG-NEXT: %{{.+}} = call i16 @llvm.fshl.i16(i16 %[[INPUT]], i16 %[[INPUT]], i16 %[[AMOUNT]])
453+
454+
unsigned test_builtin_rotateleft32(unsigned x, unsigned y) {
455+
return __builtin_rotateleft32(x, y);
456+
}
457+
458+
// CIR-LABEL: @_Z25test_builtin_rotateleft32jj
459+
// CIR: %{{.+}} = cir.rotate left %{{.+}}, %{{.+}} : !u32i
460+
461+
// LLVM-LABEL: @_Z25test_builtin_rotateleft32jj
462+
// LLVM: %[[INPUT:.+]] = load i32, ptr %{{.+}}, align 4
463+
// LLVM-NEXT: %[[AMOUNT:.+]] = load i32, ptr %{{.+}}, align 4
464+
// LLVM-NEXT: %{{.+}} = call i32 @llvm.fshl.i32(i32 %[[INPUT]], i32 %[[INPUT]], i32 %[[AMOUNT]])
465+
466+
// OGCG-LABEL: @_Z25test_builtin_rotateleft32jj
467+
// OGCG: %[[INPUT:.+]] = load i32, ptr %{{.+}}, align 4
468+
// OGCG-NEXT: %[[AMOUNT:.+]] = load i32, ptr %{{.+}}, align 4
469+
// OGCG-NEXT: %{{.+}} = call i32 @llvm.fshl.i32(i32 %[[INPUT]], i32 %[[INPUT]], i32 %[[AMOUNT]])
470+
471+
unsigned long long test_builtin_rotateleft64(unsigned long long x,
472+
unsigned long long y) {
473+
return __builtin_rotateleft64(x, y);
474+
}
475+
476+
// CIR-LABEL: @_Z25test_builtin_rotateleft64yy
477+
// CIR: %{{.+}} = cir.rotate left %{{.+}}, %{{.+}} : !u64i
478+
479+
// LLVM-LABEL: @_Z25test_builtin_rotateleft64yy
480+
// LLVM: %[[INPUT:.+]] = load i64, ptr %{{.+}}, align 8
481+
// LLVM-NEXT: %[[AMOUNT:.+]] = load i64, ptr %{{.+}}, align 8
482+
// LLVM-NEXT: %{{.+}} = call i64 @llvm.fshl.i64(i64 %[[INPUT]], i64 %[[INPUT]], i64 %[[AMOUNT]])
483+
484+
// OGCG-LABEL: @_Z25test_builtin_rotateleft64yy
485+
// OGCG: %[[INPUT:.+]] = load i64, ptr %{{.+}}, align 8
486+
// OGCG-NEXT: %[[AMOUNT:.+]] = load i64, ptr %{{.+}}, align 8
487+
// OGCG-NEXT: %{{.+}} = call i64 @llvm.fshl.i64(i64 %[[INPUT]], i64 %[[INPUT]], i64 %[[AMOUNT]])
488+
489+
unsigned char test_builtin_rotateright8(unsigned char x, unsigned char y) {
490+
return __builtin_rotateright8(x, y);
491+
}
492+
493+
// CIR-LABEL: @_Z25test_builtin_rotateright8hh
494+
// CIR: %{{.+}} = cir.rotate right %{{.+}}, %{{.+}} : !u8i
495+
496+
// LLVM-LABEL: @_Z25test_builtin_rotateright8hh
497+
// LLVM: %[[INPUT:.+]] = load i8, ptr %{{.+}}, align 1
498+
// LLVM-NEXT: %[[AMOUNT:.+]] = load i8, ptr %{{.+}}, align 1
499+
// LLVM-NEXT: %{{.+}} = call i8 @llvm.fshr.i8(i8 %[[INPUT]], i8 %[[INPUT]], i8 %[[AMOUNT]])
500+
501+
// OGCG-LABEL: @_Z25test_builtin_rotateright8hh
502+
// OGCG: %[[INPUT:.+]] = load i8, ptr %{{.+}}, align 1
503+
// OGCG-NEXT: %[[AMOUNT:.+]] = load i8, ptr %{{.+}}, align 1
504+
// OGCG-NEXT: %{{.+}} = call i8 @llvm.fshr.i8(i8 %[[INPUT]], i8 %[[INPUT]], i8 %[[AMOUNT]])
505+
506+
unsigned short test_builtin_rotateright16(unsigned short x, unsigned short y) {
507+
return __builtin_rotateright16(x, y);
508+
}
509+
510+
// CIR-LABEL: @_Z26test_builtin_rotateright16tt
511+
// CIR: %{{.+}} = cir.rotate right %{{.+}}, %{{.+}} : !u16i
512+
513+
// LLVM-LABEL: @_Z26test_builtin_rotateright16tt
514+
// LLVM: %[[INPUT:.+]] = load i16, ptr %{{.+}}, align 2
515+
// LLVM-NEXT: %[[AMOUNT:.+]] = load i16, ptr %{{.+}}, align 2
516+
// LLVM-NEXT: %{{.+}} = call i16 @llvm.fshr.i16(i16 %[[INPUT]], i16 %[[INPUT]], i16 %[[AMOUNT]])
517+
518+
// OGCG-LABEL: @_Z26test_builtin_rotateright16tt
519+
// OGCG: %[[INPUT:.+]] = load i16, ptr %{{.+}}, align 2
520+
// OGCG-NEXT: %[[AMOUNT:.+]] = load i16, ptr %{{.+}}, align 2
521+
// OGCG-NEXT: %{{.+}} = call i16 @llvm.fshr.i16(i16 %[[INPUT]], i16 %[[INPUT]], i16 %[[AMOUNT]])
522+
523+
unsigned test_builtin_rotateright32(unsigned x, unsigned y) {
524+
return __builtin_rotateright32(x, y);
525+
}
526+
527+
// CIR-LABEL: @_Z26test_builtin_rotateright32jj
528+
// CIR: %{{.+}} = cir.rotate right %{{.+}}, %{{.+}} : !u32i
529+
530+
// LLVM-LABEL: @_Z26test_builtin_rotateright32jj
531+
// LLVM: %[[INPUT:.+]] = load i32, ptr %{{.+}}, align 4
532+
// LLVM-NEXT: %[[AMOUNT:.+]] = load i32, ptr %{{.+}}, align 4
533+
// LLVM-NEXT: %{{.+}} = call i32 @llvm.fshr.i32(i32 %[[INPUT]], i32 %[[INPUT]], i32 %[[AMOUNT]])
534+
535+
// OGCG-LABEL: @_Z26test_builtin_rotateright32jj
536+
// OGCG: %[[INPUT:.+]] = load i32, ptr %{{.+}}, align 4
537+
// OGCG-NEXT: %[[AMOUNT:.+]] = load i32, ptr %{{.+}}, align 4
538+
// OGCG-NEXT: %{{.+}} = call i32 @llvm.fshr.i32(i32 %[[INPUT]], i32 %[[INPUT]], i32 %[[AMOUNT]])
539+
540+
unsigned long long test_builtin_rotateright64(unsigned long long x,
541+
unsigned long long y) {
542+
return __builtin_rotateright64(x, y);
543+
}
544+
545+
// CIR-LABEL: @_Z26test_builtin_rotateright64yy
546+
// CIR: %{{.+}} = cir.rotate right %{{.+}}, %{{.+}} : !u64i
547+
548+
// LLVM-LABEL: @_Z26test_builtin_rotateright64yy
549+
// LLVM: %[[INPUT:.+]] = load i64, ptr %{{.+}}, align 8
550+
// LLVM-NEXT: %[[AMOUNT:.+]] = load i64, ptr %{{.+}}, align 8
551+
// LLVM-NEXT: %{{.+}} = call i64 @llvm.fshr.i64(i64 %[[INPUT]], i64 %[[INPUT]], i64 %[[AMOUNT]])
552+
553+
// OGCG-LABEL: @_Z26test_builtin_rotateright64yy
554+
// OGCG: %[[INPUT:.+]] = load i64, ptr %{{.+}}, align 8
555+
// OGCG-NEXT: %[[AMOUNT:.+]] = load i64, ptr %{{.+}}, align 8
556+
// OGCG-NEXT: %{{.+}} = call i64 @llvm.fshr.i64(i64 %[[INPUT]], i64 %[[INPUT]], i64 %[[AMOUNT]])

0 commit comments

Comments
 (0)