What does "set" mean in llvm TableGen files? - llvm

I read the llvm backend for AVR. What does "set" mean in llvm TableGen? How do I write the pattern for the instruction "mov"? Like as follows?
(set ACC:$rd,(mov GPR8:$src));
Another code from AVR backend as follows:
def ADDRdRr : FRdRr<0b0000,
0b11,
(outs GPR8:$rd),
(ins GPR8:$src, GPR8:$rr),
"add\t$rd, $rr",
[(set i8:$rd, (add i8:$src, i8:$rr)),
(implicit SREG)]>;

This pattern matches an addition operation and set means that the result of addition should be placed in $rd operand. As you can see, this is exactly the operand marked as "output" - (outs GPR8:$rd).
Regarding mov instruction, in my toy backend I didn't even needed to specify a pattern for it. My mov definition looks like
def MovRR : InstRR<7, (outs IntRegs:$reg2), (ins IntRegs:$reg1),
"mov $reg1, $reg2", []>;
Instead of matching, I implemented MyBackendInstrInfo::copyPhysReg():
void MyBackendInstrInfo::copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
const DebugLoc &DL, unsigned DestReg, unsigned SrcReg,
bool KillSrc) const
{
if (MB::IntRegsRegClass.contains(DestReg, SrcReg))
BuildMI(MBB, MI, DL, get(MB::MovRR), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
else
llvm_unreachable("Impossible reg-to-reg copy");
}

Related

C++ Nullptr vs Null-Object for potential noop function arguments?

TL;DR : Should we use fn(Interface* pMaybeNull) or fn(Interface& maybeNullObject) -- specifically in the case of "optional" function arguments of a virtual/abstract base class?
Our code base contains various forms of the following pattern:
struct CallbackBase {
virtual ~CallbackBase() = default;
virtual void Hello(/*omitted ...*/) = 0;
};
...
void DoTheThing(..., CallbackBase* pOpt) {
...
if (pOpt) { pOpt->Hello(...); }
}
where the usage site would look like:
... {
auto greet = ...;
...
DoTheThing(..., &greet);
// or if no callback is required from call site:
DoTheThing(..., nullptr);
}
It has been proposed that, going forward, we should use a form of the Null-Object-Pattern. like so:
struct NoopCall : public CallbackBase {
virtual void Hello(/*omitted ...*/) { /*noop*/ }
};
void DoTheThing2(..., CallbackBase& opt) {
...
opt.Hello(...);
}
... {
NoopCall noop;
// if no callback is required from call site:
DoTheThing2(..., noop);
}
Note: Search variations yield lots of results regarding Null-Object (many not in the C++ space), a lot of very basic treatment of pointer vs. references and if you include the word "optional", as-in the parameter is optional, you obviously get a lot of hits regarding std::optional which, afaik, is unsuitable for this virtual interface use case.
I couldn't find a decent comparison of the two variants present here, so here goes:
Given C++17/C++20 and a halfway modern compiler, is there any expected difference in the runtime characteristics of the two approaches? (this factor being just a corollary to the overall design choice.)
The "Null Object" approach certainly "seems" more modern and safer to me -- is there anything in favor of the pointer approach?
Note:
I think it is orthogonal to the question posed, whether it stands as posted, or uses a variant of overloading or default arguments.
That is, the question should be valid, regardless of:
//a
void DoTheThing(arg);
// vs b
void DoTheThing(arg=nullthing);
// vs c
void DoTheThing(arg); // overload1
void DoTheThing(); // overload0 (calling 1 internally)
Performance:
I inspected the code on godbolt and while MSVC shows "the obvious", the gcc output is interesting (see below).
// Gist for a MCVE.
"The obvious" is that the version with the Noop object contains an unconditional virtual call to Hello and the pointer version has an additional pointer test, eliding the call if the pointer is null.
So, if the function is "always" called with a valid callback, the pointer version is a pessimization, paying an additional null check.
If the function is "never" called with a valid callback, the NullObject version is a (worse) pessimization, paying a virtual call that does nothing.
However, the object version in the gcc code contains this:
WithObject(int, CallbackBase&):
...
mov rax, QWORD PTR [rsi]
...
mov rax, QWORD PTR [rax+16]
(!) cmp rax, OFFSET FLAT:NoopCaller::Hello(HelloData const&)
jne .L31
.L25:
...
.L31:
mov rdi, rsi
mov rsi, rsp
call rax
jmp .L25
And while my understanding of assembly is certainly near non existent, this looks like gcc is comparing the call pointer to the NoopCaller::Hello function, and eliding the call in this case!
Conclusion
In general, the pointer version should produce more optimal code on the micro-level. However, compiler optimizations might make any difference near non-observable.
Think about using the pointer version if you have a very hot path where the callback is null.
Use the null object version otherwise, as it is arguably safer and more maintainable.

Do branch likelihood hints carry through function calls?

I've come across a few scenarios where I want to say a function's return value is likely inside the body of a function, not the if statement that will call it.
For example, say I want to port code from using a LIKELY macro to using the new [[likely]] annotation. But these go in syntactically different places:
#define LIKELY(...) __builtin_expect(!!(__VA_ARGS__),0)
if(LIKELY(x)) { ... }
vs
if(x) [[likely]] { ... }
There's no easy way to redefine the LIKELY macro to use the annotation. Would defining a function like
inline bool likely(bool x) {
if(x) [[likely]] return true;
else return false;
}
propagate the hint out to an if? Like in
if(likely(x)) { ... }
Similarly, in generic code, it can be difficult to directly express algorithmic likelihood information in the actual if statement, even if this information is known elsewhere. For example, a copy_if where the predicate is almost always false. As far as I know, there is no way to express that using attributes, but if branch weight info can propagate through functions, this is a solved problem.
So far I haven't been able to find documentation about this and I don't know a good setup to test this by looking at the outputted assembly.
The story appears to be mixed for different compilers.
On GCC, I think your inline likely function works, or at least has some effect. Using Compiler Explorer to test differences on this code:
inline bool likely(bool x) {
if(x) [[likely]] return true;
else return false;
}
//#define LIKELY(x) likely(x)
#define LIKELY(x) x
int f(int x) {
if (LIKELY(!x)) {
return -3548;
}
else {
return x + 1;
}
}
This function f adds 1 to x and returns it, unless x is 0, in which case it returns -3548. The LIKELY macro, when it's active, indicates to the compiler that the case where x is zero is more common.
This version, with no change, produces this assembly under GCC 10 -O1:
f(int):
test edi, edi
je .L3
lea eax, [rdi+1]
ret
.L3:
mov eax, -3548
ret
With the #define changed to the inline function with the [[likely]], we get:
f(int):
lea eax, [rdi+1]
test edi, edi
mov edx, -3548
cmove eax, edx
ret
That's a conditional move instead of a conditional jump. A win, I guess, albeit for a simple example.
This indicates that branch weights propagate through inline functions, which makes sense.
On clang, however, there is limited support for the likely and unlikely attributes, and where there is it does not seem to propagate through inline function calls, according to #Peter Cordes 's report.
There is, however, a hacky macro solution that I think also works:
#define EMPTY()
#define LIKELY(x) x) [[likely]] EMPTY(
Then anything like
if ( LIKELY(x) ) {
becomes like
if ( x) [[likely]] EMPTY( ) {
which then becomes
if ( x) [[likely]] {
.
Example: https://godbolt.org/z/nhfehn
Note however that this probably only works in if-statements, or in other cases that the LIKELY is enclosed in parentheses.
gcc 10.2 at least is able to make this deduction (with -O2).
If we consider the following simple program:
void foo();
void bar();
void baz(int x) {
if (x == 0)
foo();
else
bar();
}
then it compiles to:
baz(int):
test edi, edi
jne .L2
jmp foo()
.L2:
jmp bar()
However if we add [[likely]] on the else clause, the generated code changes to
baz(int):
test edi, edi
je .L4
jmp bar()
.L4:
jmp foo()
so that the not-taken case of the conditional branch corresponds to the "likely" case.
Now if we pull the comparison out into an inline function:
void foo();
void bar();
inline bool is_zero(int x) {
if (x == 0)
return true;
else
return false;
}
void baz(int x) {
if (is_zero(x))
foo();
else
bar();
}
we are again back to the original generated code, taking the branch in the bar() case. But if we add [[likely]] on the else clause in is_zero, we see the branch reversed again.
clang 10.0.1 however does not demonstrate this behavior and seems to ignore [[likely]] altogether in all versions of this example.
Yes, it will probably inline, but this is quite pointless.
The __builtin_expect will continue to work even after you upgrade to a compiler that supports those C++ 20 attributes. You can refactor them later, but it will be for purely aesthetic reasons.
Also, your implementation of the LIKELY macro is erroneous (it is actually UNLIKELY), the correct implementations are nelow.
#define LIKELY( x ) __builtin_expect( !! ( x ), 1 )
#define UNLIKELY( x ) __builtin_expect( !! ( x ), 0 )

Ternary operator applies class-expanding macro to the both of operands

I use Microsoft Visual C++ 2010 and Windows 7.
I have the DataDecoder class to decode some data. Here it is:
template< typename T >
class DataDecoder
{
private:
T lpData;
public:
DataDecoder() { lpData = NULL; }
DataDecoder( T lpSource ) { lpData = (T)DecodeStaticData(lpSource); }
~DataDecoder() { if(lpData) free(lpData); }
operator T() { return lpData; }
};
This class works perfectly. Also I have this macro:
#define _STR_A(x) DataDecoder<char*>(x)
It works perfectly too. But there is another construction in my code:
LPVOID lpAdditionalData = NULL;
LPSTR lpTemp = lpAdditionalData ? _STR_A("SOMEDATA") : NULL;
At this point weird things begin to happen. First of all I get NULL parameter in my DecodeStaticData(). But it could not be true: _STR_A() applies to valid parameter only. Then I decided to look at disassembly:
0011843A cmp dword ptr [lpAdditionalData],0
00118441 je WinMain+172h (118462h)
00118443 push offset string "SOMEDATA" (124068h)
00118448 lea ecx,[ebp-0C2Ch]
0011844E call DataDecoder<char *>::DataDecoder<char *> (117770h)
00118453 or dword ptr [ebp-0C14h],1
0011845A mov dword ptr [ebp-0C34h],eax
00118460 jmp WinMain+18Ch (11847Ch)
00118462 push 0
00118464 lea ecx,[ebp-0C28h]
0011846A call DataDecoder<char *>::DataDecoder<char *> (117770h)
As you can see, class constructor is called in BOTH cases, for "SOMEDATA" and for NULL too!
Is it correct behavior? How can I deal with this?
UPDATE: I turned on preprocessing to file and this is what I see:
LPSTR lpTemp = lpAdditionalData ? DataDecoder<char*>("SOMEDATA") : 0;
So, it is not preprocessor problem.
Like any expression, one involving a conditional operator must have a type. An expression c ? a : b can't magically have a type that changes at run-time depending on the value of c - the type of a sometimes, the type of b other times. Instead, if a and b are of different types, there are complicated rules that determine the final type of the overall expression, by trying to coerce one to the type of the other.
In your case, DataDecoder<char*>(x) can't be coerced to the type of NULL, but NULL can be coerced to DataDecoder<char*>, by way of a user-defined conversion DataDecoder<char*>(NULL). This is what you observe.

Accessing C++ class member in inline assembly

Question: How can I access a member variable in assembly from within a non-POD class?
Elaboration:
I have written some inline assembly code for a class member function but what eludes me is how to access class member variables. I've tried the offsetof macro but this is a non-POD class.
The current solution I'm using is to assign a pointer from global scope to the member variable but it's a messy solution and I was hoping there was something better that I dont know about.
note: I'm using the G++ compiler. A solution with Intel syntax Asm would be nice but I'll take anything.
example of what I want to do (intel syntax):
class SomeClass
{
int* var_j;
void set4(void)
{
asm("mov var_j, 4"); // sets pointer SomeClass::var_j to address "4"
}
};
current hackish solution:
int* global_j;
class SomeClass
{
int* var_j;
void set4(void)
{
asm("mov global_j, 4"); // sets pointer global_j to address "4"
var_j = global_j; // copy it back to member variable :(
}
};
Those are crude examples but I think they get the point across.
This is all you need:
__asm__ __volatile__ ("movl $4,%[v]" : [v] "+m" (var_j)) ;
Edited to add: The assembler does accept Intel syntax, but the compiler doesn't know it, so this trick won't work using Intel syntax (not with g++ 4.4.0, anyway).
class SomeClass
{
int* var_j;
void set4(void)
{
__asm__ __volatile__("movl $4, (%0,%1)"
:
: "r"(this), "r"((char*)&var_j-(char*)this)
:
);
}
};
This might work too, saving you one register:
__asm__ __volatile__("movl $4, %1(%0)"
:
: "r"(this), "i"((char*)&var_j-(char*)this)
:
);
In fact, since the offset of var_j wrt. this should be known at compile time, the second option is the way to go, even if it requires some tweaking to get it working. (I don't have access to a g++ system right now, so I'll leave this up to you to investigate.)
And don't ever underestimate the importance of __volatile__. Took more of my time that I'd liked to track down bugs that appeared because I missed the volatile keyword and the compiler took it upon itself to do strange things with my assembly.

Arbitrary pointer to unknown class function - invalid type conversion

I have a hack program; it injects some functions into a target process to control it. The program is written in C++ with inline assembly.
class GameProcMain {
// this just a class
};
GameProcMain* mainproc; // there is no problem I can do =(GameProcMain*)0xC1EA90
Now I want to define a class function (which set ecx to class pointer) instead of writing assembly.
PPLYDATA GetNearblyMob(__Vector3* cordinate) {
__asm {
mov ecx, 0xC1EA90
enter code here
push cordinate
mov edi, 0x4A8010
call edi
}
}
I want to define it and call it like.
PPLYDATA (DLPL::*GetNearblyMob)(__Vector3* cordinate);
mainproc->GetNearblyMob(ADDR_CHRB->kordinat)
When I try GetNearblyMob=(PPLYDATA (DLPL::*)(__Vector3*)) 0x4A8010;
It says something like error: invalid type conversion: "int" to "PPLYDATA (DLPL::*)(int, int)"
but I can do this to set the pointer:
void initializeHack() {
__asm {
LEA edi, GetNearblyMob
MOV eax, 0x4A8010
MOV [edi], eax
}
}
Now I want to learn "how I can set GetNearblyMob without using assembly and legitimately in C++".
The problem is that member functions automatically get an extra parameter for the this pointer. Sometimes you can cast between member and non-member functions, but I don't see the need to cast anything.
Typically it's easier to reverse-engineer into C functions than into C++. C typically has a more straightforward ABI, so you can keep the data structures straight as you work them out.
So, I would recommend
PPLYDATA (*GetNearblyMob)(DLPL *main_obj, __Vector3* cordinate) = 0x12345UL;
and then define your own function
class DLPL {
GetNearblyMob( __Vector3* cordinate ) {
return ::GetNearblyMob( this, cordinate );
}
// ... other program functions
};
I am a bit surprised that it won't you cast like that.
You can try to do something like
GetNearblyMob=reinterpret_cast<PPLYDATA (DLPL::*)(__Vector3*)> (0x4A8010);
If that still does not work, try
*(int*)(&GetNearblyMob) = 0x4A8010;