Skip to content
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
94 changes: 94 additions & 0 deletions include/warpforth/Dialect/Forth/ForthOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,100 @@ def Forth_ModOp : Forth_Op<"mod", [Pure]> {
}];
}

//===----------------------------------------------------------------------===//
// Bitwise operations.
//===----------------------------------------------------------------------===//

def Forth_AndOp : Forth_Op<"and", [Pure]> {
let summary = "Bitwise AND of top two stack elements";
let description = [{
Pops the top two elements, performs bitwise AND, and pushes the result.
Forth semantics: ( a b -- a&b )
}];

let arguments = (ins Forth_StackType:$input_stack);
let results = (outs Forth_StackType:$output_stack);

let assemblyFormat = [{
$input_stack attr-dict `:` type($input_stack) `->` type($output_stack)
}];
}

def Forth_OrOp : Forth_Op<"or", [Pure]> {
let summary = "Bitwise OR of top two stack elements";
let description = [{
Pops the top two elements, performs bitwise OR, and pushes the result.
Forth semantics: ( a b -- a|b )
}];

let arguments = (ins Forth_StackType:$input_stack);
let results = (outs Forth_StackType:$output_stack);

let assemblyFormat = [{
$input_stack attr-dict `:` type($input_stack) `->` type($output_stack)
}];
}

def Forth_XorOp : Forth_Op<"xor", [Pure]> {
let summary = "Bitwise XOR of top two stack elements";
let description = [{
Pops the top two elements, performs bitwise XOR, and pushes the result.
Forth semantics: ( a b -- a^b )
}];

let arguments = (ins Forth_StackType:$input_stack);
let results = (outs Forth_StackType:$output_stack);

let assemblyFormat = [{
$input_stack attr-dict `:` type($input_stack) `->` type($output_stack)
}];
}

def Forth_NotOp : Forth_Op<"not", [Pure]> {
let summary = "Bitwise NOT of top stack element";
let description = [{
Pops the top element, performs bitwise NOT (complement), and pushes the result.
Forth semantics: ( a -- ~a )
}];

let arguments = (ins Forth_StackType:$input_stack);
let results = (outs Forth_StackType:$output_stack);

let assemblyFormat = [{
$input_stack attr-dict `:` type($input_stack) `->` type($output_stack)
}];
}

def Forth_LshiftOp : Forth_Op<"lshift", [Pure]> {
let summary = "Left shift";
let description = [{
Pops shift amount and value, shifts value left, and pushes the result.
Forth semantics: ( a n -- a<<n )
}];

let arguments = (ins Forth_StackType:$input_stack);
let results = (outs Forth_StackType:$output_stack);

let assemblyFormat = [{
$input_stack attr-dict `:` type($input_stack) `->` type($output_stack)
}];
}

def Forth_RshiftOp : Forth_Op<"rshift", [Pure]> {
let summary = "Logical right shift";
let description = [{
Pops shift amount and value, shifts value right (logical/unsigned), and pushes the result.
Forth semantics: ( a n -- a>>n )
}];

let arguments = (ins Forth_StackType:$input_stack);
let results = (outs Forth_StackType:$output_stack);

let assemblyFormat = [{
$input_stack attr-dict `:` type($input_stack) `->` type($output_stack)
}];
}

//===----------------------------------------------------------------------===//
// Memory operations.
//===----------------------------------------------------------------------===//
Expand Down
58 changes: 49 additions & 9 deletions lib/Conversion/ForthToMemRef/ForthToMemRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,13 @@ using SubOpConversion = BinaryArithOpConversion<forth::SubOp, arith::SubIOp>;
using MulOpConversion = BinaryArithOpConversion<forth::MulOp, arith::MulIOp>;
using DivOpConversion = BinaryArithOpConversion<forth::DivOp, arith::DivSIOp>;
using ModOpConversion = BinaryArithOpConversion<forth::ModOp, arith::RemSIOp>;
using AndOpConversion = BinaryArithOpConversion<forth::AndOp, arith::AndIOp>;
using OrOpConversion = BinaryArithOpConversion<forth::OrOp, arith::OrIOp>;
using XorOpConversion = BinaryArithOpConversion<forth::XorOp, arith::XOrIOp>;
using LshiftOpConversion =
BinaryArithOpConversion<forth::LshiftOp, arith::ShLIOp>;
using RshiftOpConversion =
BinaryArithOpConversion<forth::RshiftOp, arith::ShRUIOp>;

/// Base template for binary comparison operations.
/// Pops two values, compares, pushes -1 (true) or 0 (false): (a b -- flag)
Expand Down Expand Up @@ -348,6 +355,37 @@ using LtOpConversion =
using GtOpConversion =
BinaryCmpOpConversion<forth::GtOp, arith::CmpIPredicate::sgt>;

/// Conversion pattern for forth.not operation (bitwise NOT).
/// Unary: pops one value, XORs with -1 (all bits set), pushes result: (a -- ~a)
struct NotOpConversion : public OpConversionPattern<forth::NotOp> {
NotOpConversion(const TypeConverter &typeConverter, MLIRContext *context)
: OpConversionPattern<forth::NotOp>(typeConverter, context) {}
using OneToNOpAdaptor = OpConversionPattern::OneToNOpAdaptor;

LogicalResult
matchAndRewrite(forth::NotOp op, OneToNOpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
auto loc = op.getLoc();
ValueRange inputStack = adaptor.getOperands()[0];
Value memref = inputStack[0];
Value stackPtr = inputStack[1];

// Load top value
Value a = rewriter.create<memref::LoadOp>(loc, memref, stackPtr);

// XOR with -1 (all bits set) to flip all bits
Value allOnes = rewriter.create<arith::ConstantOp>(
loc, rewriter.getI64Type(), rewriter.getI64IntegerAttr(-1));
Value result = rewriter.create<arith::XOrIOp>(loc, a, allOnes);

// Store result at same position (SP unchanged)
rewriter.create<memref::StoreOp>(loc, result, memref, stackPtr);

rewriter.replaceOpWithMultiple(op, {{memref, stackPtr}});
return success();
}
};

/// Conversion pattern for forth.zero_eq operation (0=).
/// Unary: pops one value, pushes -1 if zero, 0 otherwise: (a -- flag)
struct ZeroEqOpConversion : public OpConversionPattern<forth::ZeroEqOp> {
Expand Down Expand Up @@ -891,15 +929,17 @@ struct ConvertForthToMemRefPass
RewritePatternSet patterns(context);

// Add Forth operation conversion patterns
patterns.add<StackOpConversion, LiteralOpConversion, DupOpConversion,
DropOpConversion, SwapOpConversion, OverOpConversion,
RotOpConversion, AddOpConversion, SubOpConversion,
MulOpConversion, DivOpConversion, ModOpConversion,
EqOpConversion, LtOpConversion, GtOpConversion,
ZeroEqOpConversion, ParamRefOpConversion, LoadOpConversion,
StoreOpConversion, IfOpConversion, BeginUntilOpConversion,
DoLoopOpConversion, LoopIndexOpConversion, YieldOpConversion>(
typeConverter, context);
patterns
.add<StackOpConversion, LiteralOpConversion, DupOpConversion,
DropOpConversion, SwapOpConversion, OverOpConversion,
RotOpConversion, AddOpConversion, SubOpConversion, MulOpConversion,
DivOpConversion, ModOpConversion, AndOpConversion, OrOpConversion,
XorOpConversion, NotOpConversion, LshiftOpConversion,
RshiftOpConversion, EqOpConversion, LtOpConversion, GtOpConversion,
ZeroEqOpConversion, ParamRefOpConversion, LoadOpConversion,
StoreOpConversion, IfOpConversion, BeginUntilOpConversion,
DoLoopOpConversion, LoopIndexOpConversion, YieldOpConversion>(
typeConverter, context);

// Add GPU indexing op conversion patterns
patterns.add<IntrinsicOpConversion<forth::ThreadIdXOp>>(typeConverter,
Expand Down
14 changes: 14 additions & 0 deletions lib/Translation/ForthToMLIR/ForthToMLIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,20 @@ Value ForthParser::emitOperation(StringRef word, Value inputStack,
return builder.create<forth::DivOp>(loc, stackType, inputStack).getResult();
} else if (word == "MOD") {
return builder.create<forth::ModOp>(loc, stackType, inputStack).getResult();
} else if (word == "AND") {
return builder.create<forth::AndOp>(loc, stackType, inputStack).getResult();
} else if (word == "OR") {
return builder.create<forth::OrOp>(loc, stackType, inputStack).getResult();
} else if (word == "XOR") {
return builder.create<forth::XorOp>(loc, stackType, inputStack).getResult();
} else if (word == "NOT") {
return builder.create<forth::NotOp>(loc, stackType, inputStack).getResult();
} else if (word == "LSHIFT") {
return builder.create<forth::LshiftOp>(loc, stackType, inputStack)
.getResult();
} else if (word == "RSHIFT") {
return builder.create<forth::RshiftOp>(loc, stackType, inputStack)
.getResult();
} else if (word == "@") {
return builder.create<forth::LoadOp>(loc, stackType, inputStack)
.getResult();
Expand Down
64 changes: 64 additions & 0 deletions test/Conversion/ForthToMemRef/bitwise.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// RUN: %warpforth-opt --convert-forth-to-memref %s | %FileCheck %s

// CHECK-LABEL: func.func private @main

// and: pop two, arith.andi, store result
// CHECK: memref.load
// CHECK: arith.subi
// CHECK: memref.load
// CHECK: arith.andi %{{.*}}, %{{.*}} : i64
// CHECK: memref.store

// or: pop two, arith.ori, store result
// CHECK: memref.load
// CHECK: memref.load
// CHECK: arith.ori %{{.*}}, %{{.*}} : i64
// CHECK: memref.store

// xor: pop two, arith.xori, store result
// CHECK: memref.load
// CHECK: memref.load
// CHECK: arith.xori %{{.*}}, %{{.*}} : i64
// CHECK: memref.store

// not: load one value, xori with -1, store at same SP
// CHECK: memref.load
// CHECK: arith.constant -1 : i64
// CHECK: arith.xori %{{.*}}, %{{.*}} : i64
// CHECK: memref.store

// lshift: pop two, arith.shli, store result
// CHECK: memref.load
// CHECK: memref.load
// CHECK: arith.shli %{{.*}}, %{{.*}} : i64
// CHECK: memref.store

// rshift: pop two, arith.shrui, store result
// CHECK: memref.load
// CHECK: memref.load
// CHECK: arith.shrui %{{.*}}, %{{.*}} : i64
// CHECK: memref.store

module {
func.func private @main() {
%0 = forth.stack !forth.stack
%1 = forth.literal %0 3 : !forth.stack -> !forth.stack
%2 = forth.literal %1 5 : !forth.stack -> !forth.stack
%3 = forth.and %2 : !forth.stack -> !forth.stack
%4 = forth.literal %3 7 : !forth.stack -> !forth.stack
%5 = forth.literal %4 8 : !forth.stack -> !forth.stack
%6 = forth.or %5 : !forth.stack -> !forth.stack
%7 = forth.literal %6 15 : !forth.stack -> !forth.stack
%8 = forth.literal %7 3 : !forth.stack -> !forth.stack
%9 = forth.xor %8 : !forth.stack -> !forth.stack
%10 = forth.literal %9 42 : !forth.stack -> !forth.stack
%11 = forth.not %10 : !forth.stack -> !forth.stack
%12 = forth.literal %11 1 : !forth.stack -> !forth.stack
%13 = forth.literal %12 4 : !forth.stack -> !forth.stack
%14 = forth.lshift %13 : !forth.stack -> !forth.stack
%15 = forth.literal %14 256 : !forth.stack -> !forth.stack
%16 = forth.literal %15 2 : !forth.stack -> !forth.stack
%17 = forth.rshift %16 : !forth.stack -> !forth.stack
return
}
}
22 changes: 22 additions & 0 deletions test/Translation/Forth/bitwise-ops.forth
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
\ RUN: %warpforth-translate --forth-to-mlir %s | %FileCheck %s

\ Verify bitwise operations parse correctly with SSA chaining
\ CHECK: %[[S0:.*]] = forth.stack
\ CHECK: %[[S1:.*]] = forth.literal %[[S0]]
\ CHECK: %[[S2:.*]] = forth.literal %[[S1]]
\ CHECK: %[[S3:.*]] = forth.and %[[S2]]
\ CHECK: %[[S4:.*]] = forth.literal %[[S3]]
\ CHECK: %[[S5:.*]] = forth.literal %[[S4]]
\ CHECK: %[[S6:.*]] = forth.or %[[S5]]
\ CHECK: %[[S7:.*]] = forth.literal %[[S6]]
\ CHECK: %[[S8:.*]] = forth.literal %[[S7]]
\ CHECK: %[[S9:.*]] = forth.xor %[[S8]]
\ CHECK: %[[S10:.*]] = forth.literal %[[S9]]
\ CHECK: %[[S11:.*]] = forth.not %[[S10]]
\ CHECK: %[[S12:.*]] = forth.literal %[[S11]]
\ CHECK: %[[S13:.*]] = forth.literal %[[S12]]
\ CHECK: %[[S14:.*]] = forth.lshift %[[S13]]
\ CHECK: %[[S15:.*]] = forth.literal %[[S14]]
\ CHECK: %[[S16:.*]] = forth.literal %[[S15]]
\ CHECK: %{{.*}} = forth.rshift %[[S16]]
3 5 AND 7 8 OR 15 3 XOR 42 NOT 1 4 LSHIFT 256 2 RSHIFT