     }
   }
 
+  /// Perform a GEP (Get Element Pointer) with this value as the base.
+  ///
+  /// - parameter indices: A list of indices that indicate which of the elements
+  ///   of the aggregate object are indexed.
+  ///
+  /// - returns: A value representing the address of a subelement of the given
+  ///   aggregate data structure value.
   public func constGEP(indices: [IRValue]) -> IRValue {
     var idxs = indices.map { $0.asLLVM() as Optional }
     return idxs.withUnsafeMutableBufferPointer { buf in

import cllvm

public protocol IRValue {
  func asLLVM() -> LLVMValueRef
}

public extension IRValue {
  public var type: IRType {
    return convertType(LLVMTypeOf(asLLVM()))
  }

  public var alignment: Int {
    get { return Int(LLVMGetAlignment(asLLVM())) }
    set { LLVMSetAlignment(asLLVM(), UInt32(newValue)) }
  }

  public var isConstant: Bool {
    return LLVMIsConstant(asLLVM()) != 0
  }

  public var isUndef: Bool {
    return LLVMIsUndef(asLLVM()) != 0
  }

  public var name: String {
    get {
      let ptr = LLVMGetValueName(asLLVM())!

    }
  }

  /// Replaces all uses of this value with the specified value.
  ///
  /// - parameter value: The new value to swap in.
  public func replaceAllUses(with value: IRValue) {
    LLVMReplaceAllUsesWith(asLLVM(), value.asLLVM())
  }

  /// Dumps a representation of this value to stderr.
  public func dump() {
    LLVMDumpValue(asLLVM())
  }
}

extension LLVMValueRef: IRValue {
  /// Retrieves the underlying LLVM value object.
  public func asLLVM() -> LLVMValueRef {
    return self
  }
}

extension Int: IRValue {
  /// Retrieves the underlying LLVM value object.
  public func asLLVM() -> LLVMValueRef {
    return IntType(width: MemoryLayout<Int>.size * 8).constant(self).asLLVM()
  }
}

extension Int8: IRValue {
  /// Retrieves the underlying LLVM value object.
  public func asLLVM() -> LLVMValueRef {
    return IntType(width: MemoryLayout<Int8>.size * 8).constant(self).asLLVM()
  }
}

extension Int16: IRValue {
  /// Retrieves the underlying LLVM value object.
  public func asLLVM() -> LLVMValueRef {
    return IntType(width: MemoryLayout<Int16>.size * 8).constant(self).asLLVM()
  }
}

extension Int32: IRValue {
  /// Retrieves the underlying LLVM value object.
  public func asLLVM() -> LLVMValueRef {
    return IntType(width: MemoryLayout<Int32>.size * 8).constant(self).asLLVM()
  }
}

extension Int64: IRValue {
  /// Retrieves the underlying LLVM value object.
  public func asLLVM() -> LLVMValueRef {
    return IntType(width: MemoryLayout<Int64>.size * 8).constant(self).asLLVM()
  }
}

extension UInt: IRValue {
  /// Retrieves the underlying LLVM value object.
  public func asLLVM() -> LLVMValueRef {
    return IntType(width: MemoryLayout<UInt>.size * 8).constant(self).asLLVM()
  }
}

extension UInt8: IRValue {
  /// Retrieves the underlying LLVM value object.
  public func asLLVM() -> LLVMValueRef {
    return IntType(width: MemoryLayout<UInt8>.size * 8).constant(self).asLLVM()
  }
}

extension UInt16: IRValue {
  /// Retrieves the underlying LLVM value object.
  public func asLLVM() -> LLVMValueRef {
    return IntType(width: MemoryLayout<UInt16>.size * 8).constant(self).asLLVM()
  }
}

extension UInt32: IRValue {
  /// Retrieves the underlying LLVM value object.
  public func asLLVM() -> LLVMValueRef {
    return IntType(width: MemoryLayout<UInt32>.size * 8).constant(self).asLLVM()
  }
}

extension UInt64: IRValue {
  /// Retrieves the underlying LLVM value object.
  public func asLLVM() -> LLVMValueRef {
    return IntType(width: MemoryLayout<UInt64>.size * 8).constant(self).asLLVM()
  }
}

extension Bool: IRValue {
  /// Retrieves the underlying LLVM value object.
  public func asLLVM() -> LLVMValueRef {
    return IntType(width: 1).constant(self ? 1 : 0).asLLVM()
  }
}

extension String: IRValue {
  /// Retrieves the underlying LLVM value object.
  public func asLLVM() -> LLVMValueRef {
    return LLVMConstString(self, UInt32(self.utf8.count), 0)
  }
