Skip to content

Commit

Permalink
[SOL] Implement syscall instruction (#121)
Browse files Browse the repository at this point in the history
* Implement static syscalls

* Rename syscall and return

* Remove external call from v3 and use pointer value directly
  • Loading branch information
LucasSte authored Dec 19, 2024
1 parent 0e7ed1d commit 26f146b
Show file tree
Hide file tree
Showing 12 changed files with 143 additions and 30 deletions.
4 changes: 3 additions & 1 deletion llvm/lib/Target/SBF/Disassembler/SBFDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class SBFDisassembler : public MCDisassembler {
uint8_t getInstMode(uint64_t Inst) const { return (Inst >> 61) & 0x7; };
bool isMov32(uint64_t Inst) const { return (Inst >> 56) == 0xb4; }
bool isNewMem(uint64_t Inst) const;
bool isSyscallOrExit(uint64_t Inst) const { return (Inst >> 56) == 0x95; }
};

} // end anonymous namespace
Expand Down Expand Up @@ -202,7 +203,8 @@ DecodeStatus SBFDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
Result =
decodeInstruction(DecoderTableSBFALU32MEMv264,
Instr, Insn, Address, this, STI);
else if (isNewMem(Insn) && STI.hasFeature(SBF::FeatureNewMemEncoding))
else if ((isNewMem(Insn) && STI.hasFeature(SBF::FeatureNewMemEncoding)) ||
(isSyscallOrExit(Insn) && STI.hasFeature(SBF::FeatureStaticSyscalls)))
Result =
decodeInstruction(DecoderTableSBFv264,
Instr, Insn, Address, this, STI);
Expand Down
11 changes: 9 additions & 2 deletions llvm/lib/Target/SBF/SBFISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,11 +592,16 @@ SDValue SBFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// If the callee is a GlobalAddress node (quite common, every direct call is)
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
// Likewise ExternalSymbol -> TargetExternalSymbol.
unsigned NodeCode = SBFISD::CALL;
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), CLI.DL, PtrVT,
G->getOffset(), 0);
} else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) {
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT, 0);
} else if (isa<ConstantSDNode>(Callee) && Subtarget->getHasStaticSyscalls()) {
// When static syscalls are enabled and we have a constant operand for call,
// we emit a syscall.
NodeCode = SBFISD::SYSCALL;
}

// Returns a chain & a flag for retval copy to use.
Expand All @@ -610,14 +615,14 @@ SDValue SBFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
for (auto &Reg : RegsToPass)
Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));

if (HasStackArgs) {
if (HasStackArgs && !Subtarget->getHasDynamicFrames()) {
Ops.push_back(DAG.getRegister(SBF::R5, MVT::i64));
}

if (InGlue.getNode())
Ops.push_back(InGlue);

Chain = DAG.getNode(SBFISD::CALL, CLI.DL, NodeTys, Ops);
Chain = DAG.getNode(NodeCode, CLI.DL, NodeTys, Ops);
InGlue = Chain.getValue(1);

DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
Expand Down Expand Up @@ -919,6 +924,8 @@ const char *SBFTargetLowering::getTargetNodeName(unsigned Opcode) const {
return "SBFISD::Wrapper";
case SBFISD::MEMCPY:
return "SBFISD::MEMCPY";
case SBFISD::SYSCALL:
return "SBFISD::SYSCALL";
}
return nullptr;
}
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/SBF/SBFISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ enum NodeType : unsigned {
SELECT_CC,
BR_CC,
Wrapper,
MEMCPY
MEMCPY,
SYSCALL,
};
}

Expand Down
27 changes: 14 additions & 13 deletions llvm/lib/Target/SBF/SBFInstrFormats.td
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,20 @@ class SBFJumpOp<bits<4> val> {
bits<4> Value = val;
}

def SBF_JA : SBFJumpOp<0x0>;
def SBF_JEQ : SBFJumpOp<0x1>;
def SBF_JGT : SBFJumpOp<0x2>;
def SBF_JGE : SBFJumpOp<0x3>;
def SBF_JNE : SBFJumpOp<0x5>;
def SBF_JSGT : SBFJumpOp<0x6>;
def SBF_JSGE : SBFJumpOp<0x7>;
def SBF_CALL : SBFJumpOp<0x8>;
def SBF_EXIT : SBFJumpOp<0x9>;
def SBF_JLT : SBFJumpOp<0xa>;
def SBF_JLE : SBFJumpOp<0xb>;
def SBF_JSLT : SBFJumpOp<0xc>;
def SBF_JSLE : SBFJumpOp<0xd>;
def SBF_JA : SBFJumpOp<0x0>;
def SBF_JEQ : SBFJumpOp<0x1>;
def SBF_JGT : SBFJumpOp<0x2>;
def SBF_JGE : SBFJumpOp<0x3>;
def SBF_JNE : SBFJumpOp<0x5>;
def SBF_JSGT : SBFJumpOp<0x6>;
def SBF_JSGE : SBFJumpOp<0x7>;
def SBF_CALL : SBFJumpOp<0x8>;
def SBF_EXIT : SBFJumpOp<0x9>;
def SBF_JLT : SBFJumpOp<0xa>;
def SBF_JLE : SBFJumpOp<0xb>;
def SBF_JSLT : SBFJumpOp<0xc>;
def SBF_JSLE : SBFJumpOp<0xd>;
def SBF_SYSCALL : SBFJumpOp<0x9>;

class SBFWidthModifer<bits<2> val> {
bits<2> Value = val;
Expand Down
22 changes: 20 additions & 2 deletions llvm/lib/Target/SBF/SBFInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@ def SDT_SBFMEMCPY : SDTypeProfile<0, 4, [SDTCisVT<0, i64>,
SDTCisVT<1, i64>,
SDTCisVT<2, i64>,
SDTCisVT<3, i64>]>;
def SDT_SBFSyscall : SDTypeProfile<0, 1, [SDTCisVT<0, i64>]>;

def SBFcall : SDNode<"SBFISD::CALL", SDT_SBFCall,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
SDNPVariadic]>;
def SBFSyscall : SDNode<"SBFISD::SYSCALL", SDT_SBFSyscall,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
def SBFretglue : SDNode<"SBFISD::RET_GLUE", SDTNone,
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
def SBFcallseq_start: SDNode<"ISD::CALLSEQ_START", SDT_SBFCallSeqStart,
Expand Down Expand Up @@ -801,6 +804,19 @@ class CALL<string OpcodeStr>
let SBFClass = SBF_JMP;
}

class SYSCALL<string OpcodeStr>
: TYPE_ALU_JMP<SBF_SYSCALL.Value, SBF_K.Value,
(outs),
(ins i64imm:$imm),
!strconcat(OpcodeStr, " $imm"),
[]> {
bits<32> imm;

let Inst{31-0} = imm;
let SBFClass = SBF_JMP;
}


class CALLX<string OpcodeStr>
: TYPE_ALU_JMP<SBF_CALL.Value, SBF_X.Value,
(outs),
Expand Down Expand Up @@ -838,6 +854,7 @@ let isCall=1, hasDelaySlot=0, Uses = [R10],
def JALX : CALLX<"callx">, Requires<[SBFNoCallxSrc]>;
let DecoderNamespace = "SBFv2" in {
def JALX_v2 : CALLX_SRC_REG<"callx">, Requires<[SBFCallxSrc]>;
def SYSCALL_v3 : SYSCALL<"syscall">, Requires<[SBFHasStaticSyscalls]>;
}
}

Expand Down Expand Up @@ -883,7 +900,7 @@ class RETURN<string OpcodeStr>

let isReturn = 1, isTerminator = 1, hasDelaySlot=0, isBarrier = 1,
isNotDuplicable = 1, Predicates = [SBFHasStaticSyscalls] in {
def RETURN : RETURN<"return">;
def RETURN_v3 : RETURN<"return">;
}

// ADJCALLSTACKDOWN/UP pseudo insns
Expand Down Expand Up @@ -946,9 +963,10 @@ def : Pat<(i64 (and (i64 GPR:$src), 0xffffFFFF)),
// Calls
def : Pat<(SBFcall tglobaladdr:$dst), (JAL tglobaladdr:$dst)>;
def : Pat<(SBFcall texternalsym:$dst), (JAL texternalsym:$dst)>;
def : Pat<(SBFcall imm:$dst), (JAL imm:$dst)>;
def : Pat<(SBFcall imm:$dst), (JAL imm:$dst)>, Requires<[SBFNoStaticSyscalls]>;
def : Pat<(SBFcall GPR:$dst), (JALX GPR:$dst)>, Requires<[SBFNoCallxSrc]>;
def : Pat<(SBFcall GPR:$dst), (JALX_v2 GPR:$dst)>, Requires<[SBFCallxSrc]>;
def : Pat<(SBFSyscall imm:$imm), (SYSCALL_v3 imm:$imm)>, Requires<[SBFHasStaticSyscalls]>;

// Loads
let Predicates = [SBFNoALU32, SBFOldMemEncoding] in {
Expand Down
15 changes: 9 additions & 6 deletions llvm/test/CodeGen/SBF/call_internal.ll
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
; RUN: llc < %s -march=sbf --show-mc-encoding | FileCheck --check-prefix=CHECK-ASM %s
; RUN: llc -march=sbf --filetype=obj -o - %s | llvm-objdump -d - | FileCheck --check-prefix=CHECK-OBJ %s
; RUN: llc < %s -march=sbf -mcpu=sbfv2 --show-mc-encoding | FileCheck --check-prefix=CHECK-ASM %s
; RUN: llc < %s -march=sbf --show-mc-encoding | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-V0 %s
; RUN: llc -march=sbf --filetype=obj -o - %s | llvm-objdump -d - | FileCheck --check-prefixes=CHECK-OBJ,CHECK-OBJ-V0 %s
; RUN: llc < %s -march=sbf -mcpu=sbfv2 --show-mc-encoding | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-V3 %s
; RUN: llc -march=sbf -mcpu=sbfv2 --filetype=obj -o - %s | llvm-objdump -d -
; | FileCheck --check-prefix=CHECK-OBJ %s
; | FileCheck --check-prefixes=CHECK-OBJ,CHECK-OBJ-V3 %s

@.str = private unnamed_addr constant [5 x i8] c"foo\0A\00", align 1

Expand All @@ -16,8 +16,11 @@ entry:
; Function Attrs: nounwind
define dso_local i64 @entrypoint(ptr noundef %input) local_unnamed_addr #1 {
entry:
; CHECK-ASM: call 1811268606 # encoding: [0x85,0x00,0x00,0x00,0xfe,0xc3,0xf5,0x6b]
; CHECK-OBJ: 85 00 00 00 fe c3 f5 6b call 0x6bf5c3fe
; CHECK-ASM-V0: call 1811268606 # encoding: [0x85,0x00,0x00,0x00,0xfe,0xc3,0xf5,0x6b]
; CHECK-ASM-V3: syscall 1811268606 # encoding: [0x95,0x00,0x00,0x00,0xfe,0xc3,0xf5,0x6b]

; CHECK-OBJ-V0: 85 00 00 00 fe c3 f5 6b call 0x6bf5c3fe
; CHECK-OBJ-V3: 95 00 00 00 fe c3 f5 6b syscall 0x6bf5c3fe

tail call void inttoptr (i64 1811268606 to ptr)(ptr noundef nonnull @.str, i64 noundef 4) #3
%add.ptr = getelementptr inbounds i8, ptr %input, i64 4
Expand Down
25 changes: 25 additions & 0 deletions llvm/test/CodeGen/SBF/static_syscall.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
; RUN: llc -march=sbf < %s | FileCheck --check-prefix=CHECK-V0 %s
; RUN: llc -march=sbf -mattr=+static-syscalls -show-mc-encoding < %s | FileCheck --check-prefix=CHECK-V3 %s


; Function Attrs: nounwind
define dso_local i32 @test(i32 noundef %a, i32 noundef %b) {
entry:
; CHECK-LABEL: test

; CHECK-V0: call 2
; CHECK-V3 syscall 2 # encoding: [0x95,0x00,0x00,0x00,0x01,0x00,0x00,0x00]
%syscall_1 = tail call i32 inttoptr (i64 2 to ptr)(i32 noundef %a, i32 noundef %b)

; CHECK-V0: call 11
; CHECK-V3: syscall 11 # encoding: [0x95,0x00,0x00,0x00,0x0b,0x00,0x00,0x00]
%syscall_2 = tail call i32 inttoptr (i64 11 to ptr)(i32 noundef %a, i32 noundef %b)

; CHECK-V0: call 112
; CHECK-V3: syscall 112
%syscall_3 = tail call i32 inttoptr (i64 112 to ptr)(i32 noundef %a, i32 noundef %b)

%add_1 = add i32 %syscall_1, %syscall_2
%add_2 = add i32 %add_1, %syscall_3
ret i32 %add_1
}
50 changes: 50 additions & 0 deletions llvm/test/CodeGen/SBF/static_syscall_2.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
; RUN: llc -march=sbf -mattr=+static-syscalls < %s | FileCheck --check-prefix=CHECK %s

; Syscall declaration in C:
;
; int c_declaration(int a, int b) {
; int (*const syscall)(int a, int b) = (void*)50;
; return syscall(a, b);
; }
; The following is the unoptimized output from clang:

define dso_local i32 @c_declaration(i32 noundef %a, i32 noundef %b) #0 {
entry:
%a.addr = alloca i32, align 4
%b.addr = alloca i32, align 4
%syscall = alloca ptr, align 8
store i32 %a, ptr %a.addr, align 4
store i32 %b, ptr %b.addr, align 4
store ptr inttoptr (i64 50 to ptr), ptr %syscall, align 8
%0 = load i32, ptr %a.addr, align 4
%1 = load i32, ptr %b.addr, align 4

; Ensure the syscall instruction is emitted
; CHECK: syscall 50

%call = call i32 inttoptr (i64 50 to ptr)(i32 noundef %0, i32 noundef %1)
ret i32 %call
}

; Syscall declaration in Rust:
;
; #[no_mangle]
; pub unsafe fn rust_declaration(b: u64) -> u32 {
; let syscall : extern "C" fn(b: u64) -> u32 = core::mem::transmute(60u64);
; return syscall(b);
; }
; The following is the unoptimized output from rustc:

define i32 @rust_declaration(i64 %b) unnamed_addr {
start:
%syscall.dbg.spill = alloca [8 x i8], align 8
%b.dbg.spill = alloca [8 x i8], align 8
store i64 %b, ptr %b.dbg.spill, align 8
store ptr getelementptr (i8, ptr null, i64 60), ptr %syscall.dbg.spill, align 8

; Ensure the syscall instruction is emitted
; CHECK: syscall 60

%_0 = call i32 getelementptr (i8, ptr null, i64 60)(i64 %b)
ret i32 %_0
}
6 changes: 6 additions & 0 deletions llvm/test/MC/Disassembler/SBF/sbf-jmp.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# RUN: llvm-mc --disassemble %s -triple=sbf-solana-solana \
# RUN: | FileCheck %s --check-prefix=CHECK-NEW
# RUN: llvm-mc --disassemble %s -triple=sbf-solana-solana -mattr=+static-syscalls \
# RUN: | FileCheck %s --check-prefix=CHECK-V2

# TODO: Test immediate field ranges.

Expand Down Expand Up @@ -109,5 +111,9 @@
# CHECK-NEW: exit
0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00

# CHECK-V2: syscall 5
0x95,0x00,0x00,0x00,0x05,0x00,0x00,0x00


# CHECK-NEW: return
0x9d,0x00,0x00,0x00,0x00,0x00,0x00,0x00
4 changes: 1 addition & 3 deletions llvm/test/MC/SBF/insn-unit.s
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,8 @@
// ======== BPF_JMP Class ========
ja Llabel0 // BPF_JA
call 1 // BPF_CALL
exit // BPF_EXIT
// CHECK: 05 00 1a 00 00 00 00 00 ja +0x1a
// CHECK: 05 00 19 00 00 00 00 00 ja +0x19
// CHECK: 85 00 00 00 01 00 00 00 call 0x1
// CHECK: 95 00 00 00 00 00 00 00 exit

jeq r0, r1, Llabel0 // BPF_JEQ | BPF_X
jne r3, r4, Llabel0 // BPF_JNE | BPF_X
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/MC/SBF/sbf-jmp.s
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,6 @@ call 8
# CHECK-ASM-OLD: encoding: [0x8d,0x00,0x00,0x00,0x04,0x00,0x00,0x00]
callx r4

# CHECK-OBJ-NEW: exit
# CHECK-ASM-NEW: encoding: [0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
# CHECK-OBJ-OLD: exit
# CHECK-ASM-OLD: encoding: [0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
exit
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# RUN: llvm-mc -triple=sbf-solana-solana --mcpu=sbfv2 -filetype=obj -o %t %s
# RUN: llvm-objdump -d -r %t | FileCheck --check-prefix=CHECK %s

syscall 9
return

// CHECK: 95 00 00 00 09 00 00 00 syscall 0x9
// CHECK: 9d 00 00 00 00 00 00 00 return

0 comments on commit 26f146b

Please sign in to comment.