I tried to compile some inline assembler for 64-bit iOS application.
Here's an example:
int roundff(float _value) {
int res;
float temp;
asm("vcvtr.s32.f32 %[temp], %[value] \n vmov %[res], %[temp]" : [res] "=r" (res), [temp] "=w" (temp) : [value] "w" (_value));
return res;
}
and I have this errors:
Unrecognized instruction mnemonic.
But this code compiles fine:
__asm__ volatile(
"add %[result], %[b], %[a];"
: [result] "=r" (result)
: [a] "r" (a), [b] "r" (b), [c] "r" (c)
);
Than I founded that in aarch64 I have to use fcvt instead of vcvt. Because
int a = (int)(10.123);
compiles into
fcvtzs w8, s8
but I don't know how to write it in inline assembler. Something like this
int roundff(float _value)
{
int res;
asm("fcvtzs %[res], %[value]" : [res] "=r" (res) : [value] "w" (_value));
return res;
}
also doesn't work and generates this errors:
Instruction 'fcvtz' can not set flags, but 's' suffix specified.
Invalid operand for instruction.
Also I need round instead of trim. (fcvtns)
Any help? Where I can read something more about arm(32/64) asm?
UPDATE
Ok. This: float res = nearbyintf(v) compiles into nice instruction frinti s0 s0. But why my inline assembler does not work on iOS using clang compiler?
Here is how you do it:
-(int) roundff:(float)a {
int y;
__asm__("fcvtzs %w0, %s1\n\t" : "=r"(y) : "w"(a));
return y;
}
Take care,
/A
You can get the rounding you want using standard math.h functions that inline to single ARM instructions. Better yet, the compiler knows what they do, so may be able to optimize better by e.g. proving that the integer can't be negative, if that's the case.
Check godbolt for the compiler output:
#include <math.h>
int truncate_f_to_int(float v)
{
int res = v; // standard C cast: truncate with fcvtzs on ARM64
// AMD64: inlines to cvtTss2si rax, xmm0 // Note the extra T for truncate
return res;
}
int round_f_away_from_zero(float v)
{
int res = roundf(v); // optimizes to fcvtas on ARM64
// AMD64: AND/OR with two constants before converting with truncation
return res;
}
//#define NOT_ON_GODBOLT
// godbolt has a broken setup and gets x86-64 inline asm for lrintf on ARM64
#if defined(NOT_ON_GODBOLT) || defined (__x86_64__) || defined(__i386__)
int round_f_to_even(float v)
{
int res = lrintf(v); // should inline to a convert using the current rounding mode
// AMD64: inlines to cvtss2si rax, xmm0
// nearbyintf(v); // ARM64: calls the math library
// rintf(v); // ARM64: calls the math library
return res;
}
#endif
godbolt has a buggy install of headers for non-x86 architectures: they still uses x86 math headers, including inline asm.
Also, your roundff function with inline asm for fcvtzs compiled just fine on godbolt with gcc 4.8. Maybe you were trying to build for 32bit ARM? But like I said, use the library function that does what you want, then check to make sure it inlines to nice ASM.
Related
I'm writing a binding for a C library with the help of rust-bindgen for which the function signatures are generated automatically into a bindings.rs as:
#[repr(C)]
struct A {
//...
}
struct B {
//...
}
extern "C" {
pub fn foo(x: *mut A, y: *mut B);
//...
}
I'm not very happy with this signature of foo because I know that x is a pointer to a constant struct. Moreover, I want to apply this idea to improve this signature into something like
extern "C" {
pub fn foo(x: &'_ A, y: &'_ mut B);
}
But binding.rs has a bunch functions like foo and rewriting them by hand is a very time consuming task and I think that macros (or something else) should help. For example, there might exist one (or several) magic macro rewrite!
// hide
mod ffi {
include!("binding.rs"); // so bunch of functions: foo, bar
}
// re-exports
extern "C" {
rewrite!(foo); // should expand to: pub fn foo(x: &'_A, y: &'_ mut B)
rewrite!(bar);
}
I'm at a very early stage of this work. I don't even know if such a problem can be solved by a macro or anything else, so I'm looking for any entry point.
I've cross-posted this question to the Rust user forum.
A declarative macro can't accomplish this but a procedural macro might be able to. With proc_macro2, you can modify the token stream of a function declaration by placing your rewrite attribute on it, e.g.
extern "C" {
#[rustify]
pub fn foo(x: *mut A, y: *mut B);
}
And your rustify macro would substitute *mut Typename with Option<&mut Typename>.
I don't know how you'd change the mut borrow offhand without replacing the original declaration with *const.
typedef (void (^blockType)());
I need cast blocks with different argument types into a same type blockType, and invoke it as the original type later. But there is a issue while casting block type.
The following code works well with any argument type, ...
((blockType)^(BOOL b) {
NSLog(#"BOOL: %d", b);
})(YES); // >> BOOL: 1
((blockType)^(int i) {
NSLog(#"int: %d", i);
})(1); // >> int: 1
((blockType)^(double f) {
NSLog(#"double: %f", f);
})(1.0 / 3); // >> double: 0.333333
((blockType)^(NSString *s) {
NSLog(#"NSString *: %#", #"string");
})(1.0 / 3); // >> NSString *: string
except float:
((blockType)^(float f) {
NSLog(#"float: %f", f);
})(1.0f); // >> float: 0.000000
((blockType)^(float f) {
NSLog(#"float: %f", f);
})(1.0f / 3); // >> float: 36893488147419103232.000000
but it is ok without casting:
(^(float f) {
NSLog(#"float without casting: %f", f);
})(1.0 / 3); // >> float without casting: 0.333333
how to explain and resolve it?
It appears to be a taint of the good old C language. Consider the following code (we can say it is kind of 'translation' of your Obj-C block with issues to C as far as blocks are related to function pointers (see here)):
void test()
{
void (*pEmpty)();
pEmpty = functionFloat;
pEmpty(1.0f / 3);
}
void functionFloat(float f)
{
printf("float: %f", f);
}
If you call test you will see the same result as when you invoke your 'sick' block. Compiler will provide just a warning about incompatible pointers and will let you run. But if you change
void (*pEmpty)();
to
void (*pEmpty)(void);
there will be a compile-time error. Same will happen if you add void explicitly to your void-blocks, e.g. (void (^)(void) instead of (void (^)().
The reason for such behavior explained in the C Standard:
The empty list in a function declarator that is not part of a
definition of that function specifies that no information about the number or types of the
parameters is supplied.§6.7.6.3-14 (p.134)
Thus, as it doesn't mean that there are no parameters but rather no info about them, cast passes fine.
The problem with unexpected output is the following:
A pointer to a function of one type may be converted to a pointer to a function of another
type and back again; the result shall compare equal to the original pointer. If a converted
pointer is used to call a function whose type is not compatible with the referenced type,
the behavior is undefined.§6.3.2.3-8 (p.56)
and
If the function is defined with a type that is not compatible with the type (of the
expression) pointed to by the expression that denotes the called function, the behavior is
undefined.§6.5.2.2-9 (p.82)
So, it seems that the solution here is just like #jtbandes said: don't mess block types and re-design this part of code to avoid such casts.
Explain: Calling the block as blockType- (void (^)()), the block is treated as (void (^)(double)).
Resolve: Must cast the block back to (void (^)(float)) when invoking.
I was trying to create a Lex program that does the following:
INPUT
float hey1(int a, int b);
OUTPUT
Function: hey1
it returns: float
Signature:
a - float
b - float
With the current knowledge I have of LEX, I decided to input the test file and output the 1st part to another file, which would become the input for the next part. Kindly guide me forward, as I have come to a dead end, and can't proceed forward.
My attempt :-
%{
FILE *out;
%}
letter [A-Za-z0-9]
%%
("float"|"void"|"int")" "{letter}*"(" fprintf(out,"Function: %s", yytext) ;
%%
int main()
{
yyin = fopen("test.c","r") ;
out=fopen("out.c","w");
yylex() ;
fclose(yyin) ;
}
Thanks
I am working through this Rust tutorial, and I'm trying to solve this problem:
Implement a function, incrementMut that takes as input a vector of integers and modifies the values of the original list by incrementing each value by one.
This seems like a fairly simple problem, yes?
I have been trying to get a solution to compile for a while now, and I'm beginning to lose hope. This is what I have so far:
fn main() {
let mut p = vec![1i, 2i, 3i];
increment_mut(p);
for &x in p.iter() {
print!("{} ", x);
}
println!("");
}
fn increment_mut(mut x: Vec<int>) {
for &mut i in x.iter() {
i += 1;
}
}
This is what the compiler says when I try to compile:
Compiling tut2 v0.0.1 (file:///home/nate/git/rust/tut2)
/home/nate/git/rust/tut2/src/main.rs:5:12: 5:13 error: use of moved value: `p`
/home/nate/git/rust/tut2/src/main.rs:5 for &x in p.iter() {
^
/home/nate/git/rust/tut2/src/main.rs:3:16: 3:17 note: `p` moved here because it has type `collections::vec::Vec<int>`, which is non-copyable
/home/nate/git/rust/tut2/src/main.rs:3 increment_mut(p);
^
error: aborting due to previous error
Could not compile `tut2`.
To learn more, run the command again with --verbose.
I also tried a version with references:
fn main() {
let mut p = vec![1i, 2i, 3i];
increment_mut(&p);
for &x in p.iter() {
print!("{} ", x);
}
println!("");
}
fn increment_mut(x: &mut Vec<int>) {
for &mut i in x.iter() {
i += 1i;
}
}
And the error:
Compiling tut2 v0.0.1 (file:///home/nate/git/rust/tut2)
/home/nate/git/rust/tut2/src/main.rs:3:16: 3:18 error: cannot borrow immutable dereference of `&`-pointer as mutable
/home/nate/git/rust/tut2/src/main.rs:3 increment_mut(&p);
^~
error: aborting due to previous error
Could not compile `tut2`.
To learn more, run the command again with --verbose.
I feel like I'm missing some core idea about memory ownership in Rust, and it's making solving trivial problems like this very difficult, could someone shed some light on this?
There are a few mistakes in your code.
increment_mut(&p), given a p that is Vec<int>, would require the function increment_mut(&Vec<int>); &-references and &mut-references are completely distinct things syntactically, and if you want a &mut-reference you must write &mut p, not &p.
You need to understand patterns and how they operate; for &mut i in x.iter() will not do what you intend it to: what it will do is take the &int that each iteration of x.iter() produces, dereference it (the &), copying the value (because int satisfies Copy, if you tried it with a non-Copy type like String it would not compile), and place it in the mutable variable i (mut i). That is, it is equivalent to for i in x.iter() { let mut i = *i; … }. The effect of this is that i += 1 is actually just incrementing a local variable and has no effect on the vector. You can fix this by using iter_mut, which produces &mut int rather than &int, and changing the &mut i pattern to just i and the i += 1 to *i += 1, meaning “change the int inside the &mut int.
You can also switch from using &mut Vec<int> to using &mut [int] by calling .as_mut_slice() on your vector. This is a better practice; you should practically never need a reference to a vector as that is taking two levels of indirection where only one is needed. Ditto for &String—it’s exceedingly rare, you should in such cases work with &str.
So then:
fn main() {
let mut p = vec![1i, 2i, 3i];
increment_mut(p.as_mut_slice());
for &x in p.iter() {
print!("{} ", x);
}
println!("");
}
fn increment_mut(x: &mut [int]) {
for i in x.iter_mut() {
*i += 1;
}
}
I am writing D2 bindings for Lua. This is in one of the Lua header files.
typedef int (*lua_CFunction) (lua_State *L);
I assume the equivalent D2 statement would be:
extern(C) alias int function( lua_State* L ) lua_CFunction;
Lua also provides an api function:
void lua_pushcfunction( lua_State* L, string name, lua_CFunction func );
If I want to push a D2 function does it have to be extern(C) or can I just use the function?
int dfunc( lua_State* L )
{
std.stdio.writeln("dfunc");
}
extern(C) int cfunc( lua_State* L )
{
std.stdio.writeln("cfunc");
}
lua_State* L = lua_newstate();
lua_pushcfunction(L, "cfunc", &cfunc); //This will definitely work.
lua_pushcfunction(L, "dfunc", &dfunc); //Will this work?
If I can only use cfunc, why? I don't need to do anything like that in C++. I can just pass the address of a C++ function to C and everything just works.
Yes, the function must be declared as extern (C).
The calling convention of functions in C and D are different, so you must tell the compiler to use the C convention with extern (C). I don't know why you don't have to do this in C++.
See here for more information on interfacing with C.
It's also worth noting that you can use the C style for declaring function arguments.
Yes, your typedef translation is correct. OTOH have you looked at the htod tool?