Skip to content

feat: Add TO_<CHAR,STRING> functions #1355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 20, 2024
Merged

feat: Add TO_<CHAR,STRING> functions #1355

merged 9 commits into from
Nov 20, 2024

Conversation

volsa
Copy link
Member

@volsa volsa commented Nov 12, 2024

This commit introduces the TO_CHAR, TO_WCHAR, TO_STRING and TO_WSTRING functions, all making use of already existing X_TO_Y functions.

EDIT: There's some issue with printf() statements giving incorrect validation errors, which needs to be fixed before this can be merged.

This commit introduces the `TO_CHAR`, `TO_WCHAR`, `TO_STRING` and `TO_WSTRING` functions, all
making use of already existing `X_TO_Y` functions.
@@ -701,12 +702,10 @@ impl AnnotationMapImpl {

/// annotates the given statement (using it's `get_id()`) with the given type-name
pub fn annotate(&mut self, s: &AstNode, annotation: StatementAnnotation) {
log::trace!("Annotation: {annotation:?} @ {s:?}");
Copy link
Member Author

@volsa volsa Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi I've previously introduced these trace statements but in hindsight I have to admit they're not as useful as I imagined (i.e. they're waaaaay too bloaty). A better approach would be a more concise representation but that's something I'll address (or not, who knows) when I have the pleasure to debug resolver bugs again :^)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

soonTM

@volsa volsa marked this pull request as ready for review November 14, 2024 12:02
@volsa volsa requested review from mhasel and ghaith November 14, 2024 12:02
END_FUNCTION

FUNCTION TO_CHAR__STRING : CHAR
VAR_INPUT {ref}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The {ref} here is no longer necessary, since aggregate-type arguments are now always passed as pointers. Not blocking, we should probably change these for all occurances in the `stdlib

Copy link
Member Author

@volsa volsa Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets address this in another PR since I also forgot to remove the code-gen python scripts.

Copy link

@TheColonel2688 TheColonel2688 Nov 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mhasel

I am confused, why would Aggregate types be implicitly pass by reference that isn't how it works in Codesys. They are passed by value unless you explicitly pass by reference or use a Reference to or Pointer type.

Changing this would may break alot of existing code that can be converted over from codesys.

In well written code this should not be an issue since in a single task application because it is a bad practice to modify variables that are passed in by value, but this could cause issues with variables that are used across tasks. Aggregate types are not copied atomically as far as I know but after they are copied they are expected to not be mutated outside the function.

Maybe I am missing somthing?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be an implicit reference that the user would not see. I don't know the codesys internal representation but I strongly suspect they would also do something similar for chars and string.

There are multiple reasons to do this but mainly it's because that's what C and llvm usually expect but also compile time performance since the alternative would cause us to preallocate values on the call stack and we previously had compile issues with that. The effect of this is as mentioned transparent for the user in PLC. The C function would however have an additional parameter.

What we do internally to preserve the by value behavior is to actually allocate a new variable on the stack and pass a pointer to that variable

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh ok, so are you saying there would be a new variables allocated on the heap, and then the value would be copied in to it? Ok I think I am following how that makes sense.

Thank you for the explanation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still on the stack, just allocated at runtime because allocating/returning at compile time was very slow during the optimisation passes / binary generation pass
https://llvm.org/docs/LangRef.html#alloca-instruction

Copy link
Collaborator

@ghaith ghaith Nov 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's some more context on why this is usually needed:
https://stackoverflow.com/questions/11656532/returning-an-array-using-c
Technically it's not required for structs but it made our lives easier there.

Edit: I got something confused here, I gave an example with returns in mind, but these are parameters, the same issues still apply.. we do indeed copy the values before passing them using a memcpy but it's still all on the stack.
https://llvm.org/docs/LangRef.html#llvm-memcpy-intrinsic

This is an equivalant C application with a struct and a string allocated on the stack using this method:

#include<stdio.h>

typedef struct {
	int x;
	int y;
} MyStruct;


void func(MyStruct* str) {
	str->x = 1;
	str->y = 2;
}

void stringExample(char* arg) {
	sprintf(arg, "Hello, World!");
}

int main() {
	MyStruct str;
	printf("Before: x : %d y: %d\n", str.x, str.y);
	func(&str);
	printf("After: x : %d y: %d\n", str.x, str.y);
	char helloWorld[14];
	stringExample(helloWorld);
	printf("%s\n", helloWorld);
	return 0;
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also for context, I think the graph speaks for itself but the big reduction in compile times (oscat) was due to that internal change https://plc-lang.github.io/metrics/

Copy link

@TheColonel2688 TheColonel2688 Nov 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's some more context on why this is usually needed:
https://stackoverflow.com/questions/11656532/returning-an-array-using-c
Technically it's not required for structs but it made our lives easier there.

Edit: I got something confused here, I gave an example with returns in mind, but these are parameters, the same issues still apply.. we do indeed copy the values before passing them using a memcpy but it's still all on the stack.
https://llvm.org/docs/LangRef.html#llvm-memcpy-intrinsic

This is an equivalant C application with a struct and a string allocated on the stack using this method:

#include<stdio.h>

typedef struct {
	int x;
	int y;
} MyStruct;


void func(MyStruct* str) {
	str->x = 1;
	str->y = 2;
}

void stringExample(char* arg) {
	sprintf(arg, "Hello, World!");
}

int main() {
	MyStruct str;
	printf("Before: x : %d y: %d\n", str.x, str.y);
	func(&str);
	printf("After: x : %d y: %d\n", str.x, str.y);
	char helloWorld[14];
	stringExample(helloWorld);
	printf("%s\n", helloWorld);
	return 0;
}

Ooooh I understand now. I never really considered being able to dynamically allocated to the stack. So now that I understand that part. So I am following whar is happing now.

Thank you for the explanation!!! Very much appreciated sorry to derail your PR discussion.

@mhasel mhasel self-requested a review November 20, 2024 12:16
@volsa volsa merged commit db0bf1e into master Nov 20, 2024
19 checks passed
@volsa volsa deleted the volsa/to-string branch November 20, 2024 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants