Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions llvm/include/llvm-c/BitReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ LLVM_C_ABI LLVMBool LLVMGetBitcodeModule(LLVMMemoryBufferRef MemBuf,
LLVM_C_ABI LLVMBool LLVMGetBitcodeModule2(LLVMMemoryBufferRef MemBuf,
LLVMModuleRef *OutM);

/**
* Reads the producer string from the bitcode header in the given memory
* buffer. Returns 0 on success. The produced string must be disposed with
* LLVMDisposeMessage.
*/
LLVM_C_ABI LLVMBool LLVMGetBitcodeProducerString(LLVMMemoryBufferRef MemBuf,
char **OutProducer,
char **OutMessage);

/**
* @}
*/
Expand Down
21 changes: 21 additions & 0 deletions llvm/lib/Bitcode/Reader/BitReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,24 @@ LLVMBool LLVMGetBitcodeModule2(LLVMMemoryBufferRef MemBuf,
LLVMModuleRef *OutM) {
return LLVMGetBitcodeModuleInContext2(LLVMGetGlobalContext(), MemBuf, OutM);
}

LLVMBool LLVMGetBitcodeProducerString(LLVMMemoryBufferRef MemBuf,
char **OutProducer, char **OutMessage) {
MemoryBufferRef Buf = unwrap(MemBuf)->getMemBufferRef();

Expected<std::string> ProducerOrErr = getBitcodeProducerString(Buf);
if (!ProducerOrErr) {
std::string Message;
handleAllErrors(ProducerOrErr.takeError(),
[&](ErrorInfoBase &EIB) { Message = EIB.message(); });
if (OutMessage)
*OutMessage = strdup(Message.c_str());
if (OutProducer)
*OutProducer = nullptr;
return 1;
}

if (OutProducer)
*OutProducer = strdup(ProducerOrErr->c_str());
return 0;
}
2 changes: 2 additions & 0 deletions llvm/test/Bindings/llvm-c/producer_string.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
; RUN: llvm-as < %s | llvm-c-test --module-get-producer-string | FileCheck %s
; CHECK: LLVM{{[0-9]+.*}}
1 change: 1 addition & 0 deletions llvm/tools/llvm-c-test/llvm-c-test.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ LLVMModuleRef llvm_load_module(LLVMContextRef C, bool Lazy, bool New);
int llvm_module_dump(bool Lazy, bool New);
int llvm_module_list_functions(void);
int llvm_module_list_globals(void);
int llvm_module_get_producer_string(void);

// calc.c
int llvm_calc(void);
Expand Down
6 changes: 6 additions & 0 deletions llvm/tools/llvm-c-test/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ static void print_usage(void) {
" Read bitcode from stdin - list summary of functions\n\n");
fprintf(stderr, " * --module-list-globals\n");
fprintf(stderr, " Read bitcode from stdin - list summary of globals\n\n");
fprintf(stderr, " * --module-get-producer-string\n");
fprintf(
stderr,
" Read bitcode from stdin - print the producer identification\n\n");
fprintf(stderr, " * --targets-list\n");
fprintf(stderr, " List available targets\n\n");
fprintf(stderr, " * --object-list-sections\n");
Expand Down Expand Up @@ -79,6 +83,8 @@ int main(int argc, char **argv) {
return llvm_module_list_functions();
} else if (argc == 2 && !strcmp(argv[1], "--module-list-globals")) {
return llvm_module_list_globals();
} else if (argc == 2 && !strcmp(argv[1], "--module-get-producer-string")) {
return llvm_module_get_producer_string();
} else if (argc == 2 && !strcmp(argv[1], "--targets-list")) {
return llvm_targets_list();
} else if (argc == 2 && !strcmp(argv[1], "--object-list-sections")) {
Expand Down
57 changes: 55 additions & 2 deletions llvm/tools/llvm-c-test/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
|* *|
|*===----------------------------------------------------------------------===*|
|* *|
|* This file implements the --module-dump, --module-list-functions and *|
|* --module-list-globals commands in llvm-c-test. *|
|* This file implements the module-related commands in llvm-c-test. *|
|* *|
\*===----------------------------------------------------------------------===*/

Expand Down Expand Up @@ -135,3 +134,57 @@ int llvm_module_list_globals(void) {

return 0;
}

int llvm_module_get_producer_string(void) {
LLVMMemoryBufferRef MB;
char *Msg = NULL;
if (LLVMCreateMemoryBufferWithSTDIN(&MB, &Msg)) {
fprintf(stderr, "Error reading file: %s\n", Msg);
LLVMDisposeMessage(Msg);
return 1;
}

char *Producer = NULL;
char *Err = NULL;
LLVMBool Res = LLVMGetBitcodeProducerString(MB, &Producer, &Err);
LLVMDisposeMemoryBuffer(MB);

int Ret = 0;
if (Res) {
if (Producer)
fprintf(stderr,
"LLVMGetBitcodeProducerString returned %d, but Producer is not "
"NULL: %s",
Res, Producer);
if (Err)
fprintf(stderr, "LLVMGetBitcodeProducerSring returned %d, error: %s\n",
Res, Err);
Comment on lines +154 to +161
Copy link
Member

Choose a reason for hiding this comment

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

This can just be outside the if (Res), right? you always want to print these if they are non-null. Then you can immediately dispose them, and then you can:

int Ret = 0;
if (Res) {
  fprintf(stderr, "LLVMGetBitcodeProducerString(...) returned %d", Res);
  Ret = 1;
}
if (!Producer) {
  fprintf(...)
  Ret = 1;
}
if (Err) {
  ...
}
return Ret;

by the way, do we need a negative test, for the error case? It is not currently exercised.

else
fprintf(stderr,
"LLVMGetBitcodeProducerString returned %d, but the error is NULL",
Res);
Ret = 1;
} else {
if (!Producer) {
fprintf(stderr,
"LLVMGetBitcodeProducerString returned %d, but Producer is NULL",
Res);
Ret = 1;
}
if (Err) {
fprintf(stderr,
"LLVMGetBitcodeProducerString returned %d, Producer is not NULL: "
"%s, but also returned an error: %s",
Res, Producer, Err);
Ret = 1;
}

printf("%s\n", Producer);
}

if (Err)
LLVMDisposeMessage(Err);
if (Producer)
LLVMDisposeMessage(Producer);
return Ret;
}
Loading