Issue 53371
Summary [LLVM] Inconsistent behavior when setting instruction alignment to 0
Labels
Assignees
Reporter dosisod
    I have noticed some inconsistencies between the C/C++ API's, and the documentation, in regards to what should happen when setting alignment on certain instructions to zero. In [the documentation](https://llvm.org/docs/LangRef.html#store-instruction) for the store instruction, it states:

> A value of 0 or an omitted align argument means that the operation has the ABI alignment for the target.

Which implies that having an explicit `0` is valid (at least in IR), though when you try to do this in the C/C++ API's: it either crashes, or gives weird results. I created some MVP's to explain:

Setting alignment to 1 (works):
```
$ ./main
default alignment: 4
got: "  store i64 1337, i64* %0, align 4"
new alignment: 1
got: "  store i64 1337, i64* %0, align 1"

$ ./main-cpp
default alignment: 4
got: "  store i64 1337, i64* %0, align 4"
new alignment: 1
got: "  store i64 1337, i64* %0, align 1"
```

Setting alignment to 0 (doesn't work):
```
$ ./main
default alignment: 4
got: "  store i64 1337, i64* %0, align 4"
new alignment: 2147483648
got: "  store atomic i64 1337, i64* %0 seq_cst, align 2147483648"

$ ./main-cpp
default alignment: 4
got: "  store i64 1337, i64* %0, align 4"
main-cpp: /usr/include/llvm/Support/Alignment.h:77: llvm::Align::Align(uint64_t): Assertion `Value > 0 && "Value must not be 0"' failed.
Aborted (core dumped)
```

`main` uses the C API, and `main-cpp` uses the C++ API. Source is below.

This behavior seems to stem from https://reviews.llvm.org/D77454. This behavior was not present in LLVM 10, but is in version 11 onward.

```
$ uname -a
Linux archer 5.16.2-arch1-1 #1 SMP PREEMPT Thu, 20 Jan 2022 16:18:29 +0000 x86_64 GNU/Linux

$ pacman -Qs llvm
local/clang 13.0.0-4
    C language family frontend for LLVM
local/lld 13.0.0-1
    Linker from the LLVM project
local/llvm 13.0.0-6
    Collection of modular and reusable compiler and toolchain technologies
local/llvm-libs 13.0.0-6
    LLVM runtime libraries
```

<details>
<summary>C API example</summary>

```c
#include <stdbool.h>
#include <string.h>
#include <stdio.h>

#include <llvm-c/Core.h>

int main(void) {
	LLVMContextRef ctx = LLVMContextCreate();

	LLVMModuleRef module = LLVMModuleCreateWithNameInContext(
		"module",
		ctx
	);

	LLVMTypeRef main_func_type = LLVMFunctionType(
		LLVMInt64TypeInContext(ctx),
		NULL,
		0,
		false
	);

	LLVMValueRef main_func = LLVMAddFunction(
		module,
		"main",
		main_func_type
	);

	LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(
		ctx,
		main_func,
		"entry"
	);

	LLVMBuilderRef builder = LLVMCreateBuilderInContext(ctx);
	LLVMPositionBuilderAtEnd(builder, entry);

	LLVMValueRef num = LLVMConstInt(
		LLVMInt64TypeInContext(ctx),
		(unsigned long long)(1337),
		1
	);

	LLVMValueRef alloca = LLVMBuildAlloca(
		builder,
		LLVMInt64TypeInContext(ctx),
		""
	);

	LLVMValueRef store = LLVMBuildStore(
		builder,
		num,
		alloca
	);
	printf("default alignment: %u\n", LLVMGetAlignment(store));
	char *str = LLVMPrintValueToString(store);
	printf("got: \"%s\"\n", str);

	LLVMSetAlignment(store, 0);
	printf("new alignment: %u\n", LLVMGetAlignment(store));
	str = LLVMPrintValueToString(store);
	printf("got: \"%s\"\n", str);
}
```
</details>

<details>
<summary>C++ API example</summary>

```c++
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"

#include <iostream>
#include <memory>
#include <string>

using namespace llvm;

int main() {
	auto ctx = std::make_unique<LLVMContext>();
	auto mod = std::make_unique<Module>("main", *ctx);
	auto builder = std::make_unique<IRBuilder<>>(*ctx);

	auto *main_func_type = FunctionType::get(
		Type::getInt64Ty(*ctx),
		{},
		false
	);

	auto *main_func = Function::Create(
		main_func_type,
		Function::ExternalLinkage,
		"main",
		mod.get()
	);

	BasicBlock *bb = BasicBlock::Create(*ctx, "entry", main_func);
	builder->SetInsertPoint(bb);

	auto *num = ConstantInt::get(*ctx, APInt(64, 1337));

	auto alloca = new AllocaInst(
		Type::getInt64Ty(*ctx),
		0,
		"",
		bb
	);

	auto store = new StoreInst(
		num,
		alloca,
		bb
	);

	std::string str;
	llvm::raw_string_ostream rso(str);
	store->print(rso, true);

	printf("default alignment: %u\n", store->getAlignment());
	std::cout << "got: \"" << str << "\"\n";

	store->setAlignment(Align(0));

	str = "";
	store->print(rso, true);

	printf("new alignment: %u\n", store->getAlignment());
	std::cout << "got: \"" << str << "\"\n";
}
```
</details>

<details>
<summary>Makefile</summary>

```makefile
#!/bin/sh

CFLAGS += -std=c18 -g3 -O0
CXXFLAGS += -std=c++17 -g3 -O0
CXX = clang++

LLVM_CONFIG = $(shell command -v llvm-config)
LLVM_CFLAGS = $(shell $(LLVM_CONFIG) --cflags)
LLVM_CXXFLAGS = $(shell $(LLVM_CONFIG) --cxxflags)
LLVM_LDFLAGS = $(shell $(LLVM_CONFIG) --libs)


all: main main-cpp

main: main.c
	$(CC) main.c -o main $(CFLAGS) $(LLVM_CFLAGS) $(LLVM_LDFLAGS)

main-cpp: main.cpp
	$(CXX) main.cpp -o main-cpp $(CXXFLAGS) $(LLVM_CXXFLAGS) $(LLVM_LDFLAGS)

clean:
	rm main main-cpp
```
</details>
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to