mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 12:43:36 +01:00
5dd6dcdb6a
The current implementation assumes there is an instruction associated with the transform, but this is not the case for timm/TargetConstant/immarg values. These transforms should directly operate on a specific MachineOperand in the source instruction. TableGen would assert if you attempted to define an equivalent GISDNodeXFormEquiv using timm when it failed to find the instruction matcher. Specially recognize SDNodeXForms on timm, and pass the operand index to the render function. Ideally this would be a separate render function type that looks like void renderFoo(MachineInstrBuilder, const MachineOperand&), but this proved to be somewhat mechanically painful. Add an optional operand index which will only be passed if the transform should only look at the one source operand. Theoretically it would also be possible to only ever pass the MachineOperand, and the existing renderers would check the parent. I think that would be somewhat ugly for the standard usage which may want to inspect other operands, and I also think MachineOperand should eventually not carry a pointer to the parent instruction. Use it in one sample pattern. This isn't a great example, since the transform exists to satisfy DAG type constraints. This could also be avoided by just changing the MachineInstr's arbitrary choice of operand type from i16 to i32. Other patterns have nontrivial uses, but this serves as the simplest example. One flaw this still has is if you try to use an SDNodeXForm defined for imm, but the source pattern uses timm, you still see the "Failed to lookup instruction" assert. However, there is now a way to avoid it.
38 lines
1.5 KiB
TableGen
38 lines
1.5 KiB
TableGen
// RUN: llvm-tblgen -gen-global-isel -warn-on-skipped-patterns -optimize-match-table=false -I %p/../../include -I %p/Common %s -o - | FileCheck -check-prefix=GISEL %s
|
|
|
|
include "llvm/Target/Target.td"
|
|
include "GlobalISelEmitterCommon.td"
|
|
|
|
def shiftl_1 : SDNodeXForm<timm, [{
|
|
return CurDAG->getTargetConstant(N->getZExtValue() << 1, SDLoc(N), MVT::i32);
|
|
}]>;
|
|
|
|
def gi_shiftl_1 : GICustomOperandRenderer<"renderShiftImml1">,
|
|
GISDNodeXFormEquiv<shiftl_1>;
|
|
|
|
|
|
def int_mytarget_sleep : Intrinsic<[], [llvm_i32_ty], [ImmArg<0>]>;
|
|
def int_mytarget_foo : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [ImmArg<1>, IntrNoMem]>;
|
|
|
|
|
|
def SLEEP : I<(outs), (ins i32imm:$src0), []>;
|
|
def FOO : I<(outs GPR32:$dst), (ins GPR32:$src0, i32imm:$src1), []>;
|
|
|
|
// GISEL: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INTRINSIC,
|
|
// GISEL: GIM_CheckIntrinsicID, /*MI*/0, /*Op*/1, Intrinsic::mytarget_foo,
|
|
// GISEL: GIM_CheckIsImm, /*MI*/0, /*Op*/3,
|
|
// GISEL: GIR_CustomOperandRenderer, /*InsnID*/0, /*OldInsnID*/0, /*OpIdx*/3, /*OperandRenderer*/GICR_renderShiftImml1, // src1
|
|
def : Pat<
|
|
(int_mytarget_foo i32:$src0, (i32 timm:$src1)),
|
|
(FOO GPR32:$src0, (shiftl_1 $src1))
|
|
>;
|
|
|
|
// GISEL: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS,
|
|
// GISEL: GIM_CheckIntrinsicID, /*MI*/0, /*Op*/0, Intrinsic::mytarget_sleep,
|
|
// GISEL: GIM_CheckIsImm, /*MI*/0, /*Op*/1,
|
|
// GISEL: GIR_CustomOperandRenderer, /*InsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, /*OperandRenderer*/GICR_renderShiftImml1, // src0
|
|
def : Pat<
|
|
(int_mytarget_sleep (i32 timm:$src0)),
|
|
(SLEEP (shiftl_1 $src0))
|
|
>;
|