ConstantBuilder proposal

Here’s a sketch of what I am proposing for ConstantBuilder.

I’d like feedback on naming conventions, doc comments, etc.

//===-- llvm/Support/ConstantBuilder.h - Builder for Constants –- C++ --===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the ConstantBuilder class, which is used as a convenient
// way to create LLVM Constants with a consistent and simplified interface.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_CONSTANTBUILDER_H
#define LLVM_SUPPORT_CONSTANTBUILDER_H

#include “llvm/Constants.h”
#include “llvm/DerivedTypes.h”

namespace llvm {

/// ConstantBuilder - This provides a uniform API for creating constants.
class ConstantBuilder {
public:

//===--------------------------------------------------------------------===//
// Constant arrays
//===--------------------------------------------------------------------===//

/// GetArray - return a constant array given an array type and a vector
/// of elements.
static Constant *GetArray(
const ArrayType Ty, ///< The type of the array
const std::vector<Constant
> &V) { ///< The elements of the array
return ConstantArray::get(Ty, V);
}

/// GetArray - return a constant array given an array type and a POD
/// array of elements.
static Constant *GetArray(
const ArrayType *Ty, ///< The type of the array
Constant *const *Vals, ///< The elements of the array
unsigned NumVals) { ///< The length of the array
return ConstantArray::get(Ty, Vals, NumVals);
}

/// GetArray - return a constant array given an array type and an
/// iterator pair
template
static Constant *GetArray(
const ArrayType *Ty, ///< The type of the array
RandomAccessIterator ArgBegin, ///< Iterator for the first element
RandomAccessIterator ArgEnd) { ///< The elements of the array
return GetArray(Ty, &ArgBegin[0], ArgEnd - ArgBegin);
}

/// GetArrayOf - return a constant array given an element type and a vector
/// of elements.
static Constant *GetArrayOf(
const Type ElementTy, ///< The type of the array elements
const std::vector<Constant
> &V) { ///< The elements of the array
return GetArray(ArrayType::get(ElementTy, (uint64_t) V.size()), V);
}

/// GetArrayOf - return a constant array given an element type and a POD
/// array of elements.
static Constant *GetArrayOf(
const Type *ElementTy, ///< The type of the array elements
Constant *const *Vals, ///< The elements of the array
unsigned NumVals) { ///< The length of the array
return GetArray(ArrayType::get(ElementTy, NumVals), Vals, NumVals);
}

/// GetArrayOf - return a constant array given an element type and an
/// iterator pair
template
static Constant *GetArrayOf(
const Type *ElementTy, ///< The type of the array elements
RandomAccessIterator ArgBegin, ///< Iterator for the first element
RandomAccessIterator ArgEnd) { ///< The elements of the array
return GetArray(
ArrayType::get(ElementTy, ArgEnd - ArgBegin), ArgBegin, ArgEnd);
}

//===--------------------------------------------------------------------===//
// Constant structs
//===--------------------------------------------------------------------===//

/// GetStruct - return a constant struct given a struct type and a vector
/// of elements.
static Constant *GetStruct(
const StructType Ty,
const std::vector<Constant
> &V) {
return ConstantStruct::get(Ty, V);
}

/// GetStruct - return a constant struct given a context and a vector
/// of elements.
static Constant GetStruct(
LLVMContext &Context,
const std::vector<Constant
> &V,
bool Packed = false) {
return ConstantStruct::get(Context, V, Packed);
}

/// GetStruct - return a constant struct given a context and a POD
/// array of elements.
static Constant *GetStruct(
LLVMContext &Context,
Constant *const *Vals,
unsigned NumVals,
bool Packed = false) {
return ConstantStruct::get(Context, Vals, NumVals, Packed);
}

/// GetStruct - return a constant struct given a context and an iterator
/// pair.
template
static Constant *GetStruct(
LLVMContext &Context,
RandomAccessIterator ArgBegin, ///< Iterator for the first element
RandomAccessIterator ArgEnd) { ///< The elements of the array
return GetStruct(Context, &ArgBegin[0], ArgEnd - ArgBegin);
}

/// GetStruct - return a constant struct given a variable number of elements,
/// ending with NULL.
static Constant *GetStruct(
LLVMContext &Context,
Constant * Val, …) END_WITH_NULL;

//===--------------------------------------------------------------------===//
// Constant expressions
//===--------------------------------------------------------------------===//

/// GetAlignOf constant expr - computes the alignment of a type in a target
/// independent way (Note: the return type is an i64).
static Constant GetAlignOf(const Type Ty) {
return ConstantExpr::getAlignOf(Ty);
}

/// GetSizeOf constant expr - computes the (alloc) size of a type (in
/// address-units, not bits) in a target independent way (Note: the return
/// type is an i64).
///
static Constant GetSizeOf(const Type Ty) {
return ConstantExpr::getSizeOf(Ty);
}

/// GetOffsetOf constant expr - computes the offset of a struct field in a
/// target independent way (Note: the return type is an i64).
///
static Constant GetOffsetOf(const StructType STy, unsigned FieldNo) {
return ConstantExpr::getOffsetOf(STy, FieldNo);
}

/// GetOffsetOf constant expr - This is a generalized form of GetOffsetOf,
/// which supports any aggregate type, and any Constant index.
///
static Constant GetOffsetOf(const Type Ty, Constant *FieldNo) {
return ConstantExpr::getOffsetOf(Ty, FieldNo);
}

static Constant *GetNeg(Constant *C) {
return ConstantExpr::getNeg(C);
}

static Constant *GetFNeg(Constant *C) {
return ConstantExpr::getFNeg(C);
}

static Constant *GetNot(Constant *C) {
return ConstantExpr::getNot(C);
}

static Constant *GetAdd(Constant *C1, Constant *C2) {
return ConstantExpr::getAdd(C1, C2);
}

static Constant *GetFAdd(Constant *C1, Constant *C2) {
return ConstantExpr::getFAdd(C1, C2);
}

static Constant *GetSub(Constant *C1, Constant *C2) {
return ConstantExpr::getSub(C1, C2);
}

static Constant *GetFSub(Constant *C1, Constant *C2) {
return ConstantExpr::getFSub(C1, C2);
}

static Constant *GetMul(Constant *C1, Constant *C2) {
return ConstantExpr::getMul(C1, C2);
}

static Constant *GetFMul(Constant *C1, Constant *C2) {
return ConstantExpr::getFMul(C1, C2);
}

static Constant *GetUDiv(Constant *C1, Constant *C2) {
return ConstantExpr::getUDiv(C1, C2);
}

static Constant *GetSDiv(Constant *C1, Constant *C2) {
return ConstantExpr::getSDiv(C1, C2);
}

static Constant *GetFDiv(Constant *C1, Constant *C2) {
return ConstantExpr::getFDiv(C1, C2);
}

static Constant *GetURem(Constant *C1, Constant *C2) {
return ConstantExpr::getURem(C1, C2);
}

static Constant *GetSRem(Constant *C1, Constant *C2) {
return ConstantExpr::getSRem(C1, C2);
}

static Constant *GetFRem(Constant *C1, Constant *C2) {
return ConstantExpr::getFRem(C1, C2);
}

static Constant *GetAnd(Constant *C1, Constant *C2) {
return ConstantExpr::getAnd(C1, C2);
}

static Constant *GetOr(Constant *C1, Constant *C2) {
return ConstantExpr::getOr(C1, C2);
}

static Constant *GetXor(Constant *C1, Constant *C2) {
return ConstantExpr::getXor(C1, C2);
}

static Constant *GetShl(Constant *C1, Constant *C2) {
return ConstantExpr::getShl(C1, C2);
}

static Constant *GetLShr(Constant *C1, Constant *C2) {
return ConstantExpr::getLShr(C1, C2);
}

static Constant *GetAShr(Constant *C1, Constant *C2) {
return ConstantExpr::getAShr(C1, C2);
}

static Constant *GetTrunc(Constant *C, const Type *Ty) {
return ConstantExpr::getTrunc(C, Ty);
}

static Constant *GetSExt(Constant *C, const Type *Ty) {
return ConstantExpr::getSExt(C, Ty);
}

static Constant *GetZExt(Constant *C, const Type *Ty) {
return ConstantExpr::getZExt(C, Ty);
}

static Constant *GetFPTrunc(Constant *C, const Type *Ty) {
return ConstantExpr::getFPTrunc(C, Ty);
}

static Constant *GetFPExtend(Constant *C, const Type *Ty) {
return ConstantExpr::getFPExtend(C, Ty);
}

static Constant *GetUIToFP(Constant *C, const Type *Ty) {
return ConstantExpr::getUIToFP(C, Ty);
}

static Constant *GetSIToFP(Constant *C, const Type *Ty) {
return ConstantExpr::getSIToFP(C, Ty);
}

static Constant *GetFPToUI(Constant *C, const Type *Ty) {
return ConstantExpr::getFPToUI(C, Ty);
}

static Constant *GetFPToSI(Constant *C, const Type *Ty) {
return ConstantExpr::getFPToSI(C, Ty);
}

static Constant *GetPtrToInt(Constant *C, const Type *Ty) {
return ConstantExpr::getPtrToInt(C, Ty);
}

static Constant *GetIntToPtr(Constant *C, const Type *Ty) {
return ConstantExpr::getIntToPtr(C, Ty);
}

static Constant *GetBitCast(Constant *C, const Type *Ty) {
return ConstantExpr::getBitCast(C, Ty);
}

static Constant *GetNSWNeg(Constant *C) {
return ConstantExpr::getNSWNeg(C);
}

static Constant *GetNUWNeg(Constant *C) {
return ConstantExpr::getNUWNeg(C);
}

static Constant *GetNSWAdd(Constant *C1, Constant *C2) {
return ConstantExpr::getNSWAdd(C1, C2);
}

static Constant *GetNUWAdd(Constant *C1, Constant *C2) {
return ConstantExpr::getNUWAdd(C1, C2);
}

static Constant *GetNSWSub(Constant *C1, Constant *C2) {
return ConstantExpr::getNSWSub(C1, C2);
}

static Constant *GetNUWSub(Constant *C1, Constant *C2) {
return ConstantExpr::getNUWSub(C1, C2);
}

static Constant *GetNSWMul(Constant *C1, Constant *C2) {
return ConstantExpr::getNSWMul(C1, C2);
}

static Constant *GetNUWMul(Constant *C1, Constant *C2) {
return ConstantExpr::getNUWMul(C1, C2);
}

static Constant *GetExactSDiv(Constant *C1, Constant *C2) {
return ConstantExpr::getExactSDiv(C1, C2);
}

// @brief Convenience function for getting one of the casting operations
// using a CastOps opcode.
static Constant *GetCast(
unsigned ops, ///< The opcode for the conversion
Constant *C, ///< The constant to be converted
const Type *Ty ///< The type to which the constant is converted
) {
return ConstantExpr::getCast(ops, C, Ty);
}

// @brief Create a ZExt or BitCast cast constant expression
static Constant *GetZExtOrBitCast(
Constant *C, ///< The constant to zext or bitcast
const Type *Ty ///< The type to zext or bitcast C to
) {
return ConstantExpr::getZExtOrBitCast(C, Ty);
}

// @brief Create a SExt or BitCast cast constant expression
static Constant *GetSExtOrBitCast(
Constant *C, ///< The constant to sext or bitcast
const Type *Ty ///< The type to sext or bitcast C to
) {
return ConstantExpr::getSExtOrBitCast(C, Ty);
}

// @brief Create a Trunc or BitCast cast constant expression
static Constant *GetTruncOrBitCast(
Constant *C, ///< The constant to trunc or bitcast
const Type *Ty ///< The type to trunc or bitcast C to
) {
return ConstantExpr::getTruncOrBitCast(C, Ty);
}

/// @brief Create a BitCast or a PtrToInt cast constant expression
static Constant *GetPointerCast(
Constant *C, ///< The pointer value to be casted (operand 0)
const Type *Ty ///< The type to which cast should be made
) {
return ConstantExpr::getPointerCast(C, Ty);
}

/// @brief Create a ZExt, Bitcast or Trunc for integer → integer casts
static Constant *GetIntegerCast(
Constant *C, ///< The integer constant to be casted
const Type *Ty, ///< The integer type to cast to
bool isSigned ///< Whether C should be treated as signed or not
) {
return ConstantExpr::getIntegerCast(C, Ty, isSigned);
}

/// @brief Create a FPExt, Bitcast or FPTrunc for fp → fp casts
static Constant *GetFPCast(
Constant *C, ///< The integer constant to be casted
const Type *Ty ///< The integer type to cast to
) {
return ConstantExpr::getFPCast(C, Ty);
}

/// Select constant expr
static Constant *GetSelect(Constant *C, Constant *V1, Constant *V2) {
return ConstantExpr::getSelect(C, V1, V2);
}

/// @brief Return an ICmp or FCmp comparison operator constant expression.
static Constant *GetCompare(unsigned short pred, Constant *C1, Constant *C2) {
return ConstantExpr::getCompare(pred, C1, C2);
}

static Constant *GetICmp(unsigned short pred, Constant *C1, Constant *C2) {
return ConstantExpr::getICmp(pred, C1, C2);
}

static Constant *GetFCmp(unsigned short pred, Constant *C1, Constant *C2) {
return ConstantExpr::getFCmp(pred, C1, C2);
}

//===--------------------------------------------------------------------===//
// Constant GEPs
//===--------------------------------------------------------------------===//

static Constant *GetGEP(
Constant *C, ///< Pointer to item being indexed
Constant *const *IdxList, ///< List of indices
unsigned NumIdx) { ///< Number of indices
return ConstantExpr::getGetElementPtr(C, IdxList, NumIdx);
}

template
static Constant *GetGEP(
Constant *C, ///< Pointer to item being indexed
RandomAccessIterator ArgBegin, ///< Iterator for the first element
RandomAccessIterator ArgEnd) { ///< The elements of the array
return GetGEP(C, &ArgBegin[0], ArgEnd - ArgBegin);
}

static Constant *GetGEP(
Constant *C, ///< Pointer to item being indexed
Constant * Idx, …) END_WITH_NULL; ///< List of indices

static Constant *GetGEP1_32(
Constant *C, ///< Pointer to item being indexed
unsigned Idx0); ///< Index 0 of GEP

static Constant *GetGEP2_32(
Constant *C, ///< Pointer to item being indexed
unsigned Idx0, ///< Index 0 of GEP
unsigned Idx1); ///< Index 1 of GEP

static Constant *GetGEP1_64(
Constant *C, ///< Pointer to item being indexed
uint64_t Idx0); ///< Index 0 of GEP

static Constant *GetGEP2_64(
Constant *C, ///< Pointer to item being indexed
uint64_t Idx0, ///< Index 0 of GEP
uint64_t Idx1); ///< Index 1 of GEP

//===--------------------------------------------------------------------===//
// Constant Inbounds GEPs
//===--------------------------------------------------------------------===//

static Constant *GetInBoundsGEP(
Constant *C, ///< Pointer to item being indexed
Constant *const *IdxList, ///< POD array of indices
unsigned NumIdx) { ///< Number of indices
return ConstantExpr::getGetElementPtr(C, IdxList, NumIdx);
}

template
static Constant *GetInBoundsGEP(
Constant *C, ///< Pointer to item being indexed
RandomAccessIterator ArgBegin, ///< Iterator for the first element
RandomAccessIterator ArgEnd) { ///< The elements of the array
return GetInBoundsGEP(C, &ArgBegin[0], ArgEnd - ArgBegin);
}

static Constant *GetInBoundsGEP(
Constant *C, ///< Pointer to item being indexed
Constant * Idx, …) END_WITH_NULL; ///< List of indices

static Constant *GetInBoundsGEP1_32(
Constant *C, ///< Pointer to item being indexed
unsigned Idx0); ///< Index 0 of GEP

static Constant *GetInBoundsGEP2_32(
Constant *C, ///< Pointer to item being indexed
unsigned Idx0, ///< Index 0 of GEP
unsigned Idx1); ///< Index 1 of GEP

static Constant *GetInBoundsGEP1_64(
Constant *C, ///< Pointer to item being indexed
uint64_t Idx0); ///< Index 0 of GEP

static Constant *GetInBoundsGEP2_64(
Constant *C, ///< Pointer to item being indexed
uint64_t Idx0, ///< Index 0 of GEP
uint64_t Idx1); ///< Index 1 of GEP

static Constant *GetStructGEP(
Constant *C, ///< Pointer to item being indexed
uint64_t Idx) { ///< Index of struct field
return GetInBoundsGEP2_32(C, 0, Idx);
}

//===--------------------------------------------------------------------===//
// Constant Aggregate Ops
//===--------------------------------------------------------------------===//

static Constant *GetExtractElement(Constant *Vec, Constant *Idx) {
return ConstantExpr::getExtractElement(Vec, Idx);
}

static Constant *GetInsertElement(
Constant *Vec,
Constant *Elt,
Constant *Idx) {
return ConstantExpr::getInsertElement(Vec, Elt, Idx);
}

static Constant *GetExtractValue(
Constant *Agg,
const unsigned *IdxList,
unsigned NumIdx) {
return ConstantExpr::getExtractValue(Agg, IdxList, NumIdx);
}

static Constant *GetInsertValue(
Constant *Agg,
Constant *Val,
const unsigned *IdxList,
unsigned NumIdx) {
return ConstantExpr::getInsertValue(Agg, Val, IdxList, NumIdx);
}

static Constant *GetShuffleVector(
Constant *V1,
Constant *V2,
Constant *Mask) {
return ConstantExpr::getShuffleVector(V1, V2, Mask);
}
};

}

#endif

If you remove all the 'static's from the member functions, it'd work
more like IRBuilder.
It would also allow you to take the LLVMContext& as a constructor
parameter, so that methods like this:

/// GetStruct - return a constant struct given a context and a vector
/// of elements.
static Constant *GetStruct(
LLVMContext &Context,
const std::vector<Constant*> &V,
bool Packed = false) {
return ConstantStruct::get(Context, V, Packed);
}

can remove it from their parameter list. It's probably pretty unlikely
a given ConstantBuilder instance would be used with multiple
LLVMContexts.

Making this a class you need an instance of would likely also allow
typing to be reduced a bit because said instance can be given a
shorter name than 'ConstantBuilder'. For example: 'cb.GetStruct(...)'
instead of 'ConstantBuilder::GetStruct(MyContext, ...)'.

If you remove all the 'static’s from the member functions, it’d work
more like IRBuilder.
It would also allow you to take the LLVMContext& as a constructor
parameter, so that methods like this:

/// GetStruct - return a constant struct given a context and a vector
/// of elements.
static Constant GetStruct(
LLVMContext &Context,
const std::vector<Constant
> &V,
bool Packed = false) {
return ConstantStruct::get(Context, V, Packed);
}

can remove it from their parameter list. It’s probably pretty unlikely
a given ConstantBuilder instance would be used with multiple
LLVMContexts.

I thought about that - the only issue is that the only methods that need a context parameter are the ones for building structs, the rest can derive the context from the arguments. (in fact, you could even get the context for the struct-building methods from the arguments except in the case where the struct was empty.)

Making this a class you need an instance of would likely also allow
typing to be reduced a bit because said instance can be given a
shorter name than ‘ConstantBuilder’. For example: ‘cb.GetStruct(…)’
instead of ‘ConstantBuilder::GetStruct(MyContext, …)’.

That would make sense if you were going to keep the builder around for creating more than one constant with the same instance.

In my own code, I have a StructBuilder class that is specialized for building structs:

Constant * foo = StructBuilder(context)
.add(ptr)
.addNullPtr(type)
.addInt32(10)
.build();

Actually, my main question is whether there is even interest in this - I’m happy to write all the docs and unit tests, but only if this is something that people want. I know that it makes my life a lot easier to be able to create constant structs and arrays like this, but I can do that just as easily in my own project.