Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LLVM and C function with struct as argument

Tags:

llvm

I'm working on a scripting language, and as part of that I'm writing bridge code between my language and C using LLVM. I've been working on a wrapper for LLVM APIs in objective-c that has been working great up until this point.

typedef struct _test_struct {
    int x;
    int y;
} test_struct;

id testLLVMStructFuncCall(test_struct x) {
    NSLog(@"%d %d",x.x,x.y);
    return N(x.x + x.y);
}

-(void) testLLVMStructFuncCall {
    CGKModule* myMod = [CGKModule moduleWithName:@"llvm_structfunccall_test"];
    CGKType* testStructType = [CGKType structTypeWithElementTypes:[NSArray arrayWithObjects:[CGKType intTypeWith32Bits],[CGKType intTypeWith32Bits],nil]];
    CGKFunction* lfunc = [CGKFunction functionWithName:@"testLLVMStructFuncCall" types:[NSArray arrayWithObjects:[CGKType idType],testStructType,nil] intoModule:myMod];
    CGKFunction* rfunc = [CGKBuilder createStandaloneCallForFunction:lfunc withArguments:[NSArray 
                                                                                          arrayWithObjects:
                                                                                      [CGKConstant getStructOfType:testStructType 
                                                                                                        withValues:[NSArray arrayWithObjects:[CGKConstant getIntConstant:N(10) bits:32],
                                                                                                                    [CGKConstant getIntConstant:N(25) bits:32],nil]],nil] 
                                                        inModule:myMod];
    [myMod dump];
    id var = [[CGKRunner runnerForModule:myMod] runCGKFunction:rfunc];
    assertThat(var,is(equalTo(N(35))));
}

The issue I have is seen in the following output from the test:

Test Case '-[SVFunctionTests testLLVMStructFuncCall]' started.
; ModuleID = 'llvm_structfunccall_test'

%0 = type { i32, i32 }

declare i64* @testLLVMStructFuncCall(%0)

define i64* @0() {
entry:
  %0 = call i64* @testLLVMStructFuncCall(%0 { i32 10, i32 25 })
  ret i64* %0
}
2011-06-20 21:25:54.821 otest-x86_64[3369:707] 10 0
/Users/mtindal/Projects/Silver/Tests/SVFunctionTests.m:576: error: -[SVFunctionTests testLLVMStructFuncCall] : Expected <35>, but was <10>
Test Case '-[SVFunctionTests testLLVMStructFuncCall]' failed (0.016 seconds).

The module dump shows that the structure argument is passed as expected, however, the C function only receives the x field set to 10, and y field is left empty. I'm completely clueless how this happening and what I can do to fix it. Thanks in advance for any help you can give me.

like image 771
Michael Tindal Avatar asked Jun 20 '11 18:06

Michael Tindal


1 Answers

You're missing the Platform ABI. I assume you're on x86-64, then your struct (according to the ABI) should be passed in a single register as a whole. However you're passing {10, 25} as two separate 32-bit values. Given that 32-bit operations do implicit zero extension it's clear why you have 0 as the second value.

To be precise: the C code expects to receive 25 in the top 32 bits of the first argument register, but you're passing the value in the low 32 bits of the second argument register.

like image 179
Anton Korobeynikov Avatar answered Sep 22 '22 02:09

Anton Korobeynikov